]>
Commit | Line | Data |
---|---|---|
641cb5a6 JW |
1 | // Class filesystem::path -*- C++ -*- |
2 | ||
7adcbafe | 3 | // Copyright (C) 2014-2022 Free Software Foundation, Inc. |
641cb5a6 JW |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file include/bits/fs_path.h | |
26 | * This is an internal header file, included by other library headers. | |
27 | * Do not attempt to use it directly. @headername{filesystem} | |
28 | */ | |
29 | ||
30 | #ifndef _GLIBCXX_FS_PATH_H | |
31 | #define _GLIBCXX_FS_PATH_H 1 | |
32 | ||
33 | #if __cplusplus >= 201703L | |
34 | ||
641cb5a6 | 35 | #include <type_traits> |
641cb5a6 JW |
36 | #include <locale> |
37 | #include <iosfwd> | |
9534a5e6 | 38 | #include <iomanip> |
641cb5a6 JW |
39 | #include <codecvt> |
40 | #include <string_view> | |
41 | #include <system_error> | |
42 | #include <bits/stl_algobase.h> | |
16158c96 | 43 | #include <bits/stl_pair.h> |
641cb5a6 | 44 | #include <bits/locale_conv.h> |
24d9b090 JW |
45 | #include <ext/concurrence.h> |
46 | #include <bits/shared_ptr.h> | |
4f87bb8d | 47 | #include <bits/unique_ptr.h> |
641cb5a6 | 48 | |
d43919bf JW |
49 | #if __cplusplus > 201703L |
50 | # include <compare> | |
51 | #endif | |
52 | ||
641cb5a6 JW |
53 | #if defined(_WIN32) && !defined(__CYGWIN__) |
54 | # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 | |
641cb5a6 JW |
55 | #endif |
56 | ||
57 | namespace std _GLIBCXX_VISIBILITY(default) | |
58 | { | |
59 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
60 | ||
61 | namespace filesystem | |
62 | { | |
63 | _GLIBCXX_BEGIN_NAMESPACE_CXX11 | |
64 | ||
a1e7d33b TH |
65 | class path; |
66 | ||
67 | /// @cond undocumented | |
68 | namespace __detail | |
69 | { | |
f2ce64b5 JW |
70 | /// @addtogroup filesystem |
71 | /// @{ | |
a1e7d33b | 72 | template<typename _CharT> |
988b853f JW |
73 | inline constexpr bool __is_encoded_char = false; |
74 | template<> | |
75 | inline constexpr bool __is_encoded_char<char> = true; | |
c124af93 | 76 | #ifdef _GLIBCXX_USE_CHAR8_T |
988b853f JW |
77 | template<> |
78 | inline constexpr bool __is_encoded_char<char8_t> = true; | |
c124af93 | 79 | #endif |
47f79054 | 80 | #if _GLIBCXX_USE_WCHAR_T |
988b853f JW |
81 | template<> |
82 | inline constexpr bool __is_encoded_char<wchar_t> = true; | |
47f79054 | 83 | #endif |
988b853f JW |
84 | template<> |
85 | inline constexpr bool __is_encoded_char<char16_t> = true; | |
86 | template<> | |
87 | inline constexpr bool __is_encoded_char<char32_t> = true; | |
641cb5a6 | 88 | |
988b853f | 89 | #if __cpp_concepts >= 201907L |
a1e7d33b | 90 | template<typename _Iter> |
988b853f JW |
91 | using __safe_iterator_traits = std::iterator_traits<_Iter>; |
92 | #else | |
93 | template<typename _Iter> | |
94 | struct __safe_iterator_traits : std::iterator_traits<_Iter> | |
95 | { }; | |
641cb5a6 | 96 | |
988b853f JW |
97 | // Protect against ill-formed iterator_traits specializations in C++17 |
98 | template<> struct __safe_iterator_traits<void*> { }; | |
99 | template<> struct __safe_iterator_traits<const void*> { }; | |
100 | template<> struct __safe_iterator_traits<volatile void*> { }; | |
101 | template<> struct __safe_iterator_traits<const volatile void*> { }; | |
102 | #endif | |
641cb5a6 | 103 | |
988b853f JW |
104 | template<typename _Iter_traits, typename = void> |
105 | struct __is_path_iter_src | |
106 | : false_type | |
107 | { }; | |
641cb5a6 | 108 | |
988b853f JW |
109 | template<typename _Iter_traits> |
110 | struct __is_path_iter_src<_Iter_traits, | |
111 | void_t<typename _Iter_traits::value_type>> | |
112 | : bool_constant<__is_encoded_char<typename _Iter_traits::value_type>> | |
a1e7d33b | 113 | { }; |
641cb5a6 | 114 | |
a1e7d33b | 115 | template<typename _Source> |
988b853f JW |
116 | inline constexpr bool __is_path_src |
117 | = __is_path_iter_src<iterator_traits<decay_t<_Source>>>::value; | |
118 | ||
119 | template<> | |
120 | inline constexpr bool __is_path_src<path> = false; | |
121 | ||
122 | template<> | |
123 | inline constexpr bool __is_path_src<volatile path> = false; | |
124 | ||
125 | template<> | |
126 | inline constexpr bool __is_path_src<void*> = false; | |
127 | ||
128 | template<> | |
129 | inline constexpr bool __is_path_src<const void*> = false; | |
130 | ||
131 | template<> | |
132 | inline constexpr bool __is_path_src<volatile void*> = false; | |
133 | ||
134 | template<> | |
135 | inline constexpr bool __is_path_src<const volatile void*> = false; | |
136 | ||
137 | template<typename _CharT, typename _Traits, typename _Alloc> | |
138 | inline constexpr bool | |
139 | __is_path_src<basic_string<_CharT, _Traits, _Alloc>> | |
140 | = __is_encoded_char<_CharT>; | |
141 | ||
142 | template<typename _CharT, typename _Traits> | |
143 | inline constexpr bool | |
144 | __is_path_src<basic_string_view<_CharT, _Traits>> | |
145 | = __is_encoded_char<_CharT>; | |
146 | ||
147 | // SFINAE constraint for Source parameters as required by [fs.path.req]. | |
148 | template<typename _Tp> | |
149 | using _Path = enable_if_t<__is_path_src<_Tp>, path>; | |
641cb5a6 | 150 | |
988b853f JW |
151 | // SFINAE constraint for InputIterator parameters as required by [fs.req]. |
152 | template<typename _Iter, typename _Tr = __safe_iterator_traits<_Iter>> | |
153 | using _Path2 = enable_if_t<__is_path_iter_src<_Tr>::value, path>; | |
641cb5a6 | 154 | |
b83b810a JW |
155 | #if __cpp_lib_concepts |
156 | template<typename _Iter> | |
157 | constexpr bool __is_contiguous = std::contiguous_iterator<_Iter>; | |
158 | #else | |
159 | template<typename _Iter> | |
f874a13c | 160 | constexpr bool __is_contiguous = false; |
b83b810a JW |
161 | #endif |
162 | ||
f874a13c JW |
163 | template<typename _Tp> |
164 | constexpr bool __is_contiguous<_Tp*> = true; | |
165 | ||
166 | template<typename _Tp, typename _Seq> | |
167 | constexpr bool | |
168 | __is_contiguous<__gnu_cxx::__normal_iterator<_Tp*, _Seq>> = true; | |
169 | ||
b83b810a JW |
170 | #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T |
171 | // For POSIX treat char8_t sequences as char without encoding conversions. | |
172 | template<typename _EcharT> | |
173 | using __unified_u8_t | |
174 | = __conditional_t<is_same_v<_EcharT, char8_t>, char, _EcharT>; | |
175 | #else | |
176 | template<typename _EcharT> | |
177 | using __unified_u8_t = _EcharT; | |
178 | #endif | |
179 | ||
584d52b0 | 180 | // The __effective_range overloads convert a Source parameter into |
b83b810a | 181 | // either a basic_string_view<C> or basic_string<C> containing the |
584d52b0 | 182 | // effective range of the Source, as defined in [fs.path.req]. |
a1e7d33b TH |
183 | |
184 | template<typename _CharT, typename _Traits, typename _Alloc> | |
b83b810a | 185 | inline basic_string_view<_CharT> |
584d52b0 | 186 | __effective_range(const basic_string<_CharT, _Traits, _Alloc>& __source) |
b83b810a | 187 | noexcept |
584d52b0 | 188 | { return __source; } |
a1e7d33b TH |
189 | |
190 | template<typename _CharT, typename _Traits> | |
b83b810a | 191 | inline basic_string_view<_CharT> |
584d52b0 | 192 | __effective_range(const basic_string_view<_CharT, _Traits>& __source) |
b83b810a | 193 | noexcept |
584d52b0 | 194 | { return __source; } |
a1e7d33b | 195 | |
b83b810a | 196 | // Return the effective range of an NTCTS. |
584d52b0 | 197 | template<typename _Source> |
b83b810a | 198 | auto |
584d52b0 JW |
199 | __effective_range(const _Source& __source) |
200 | { | |
b83b810a JW |
201 | // Remove a level of normal/safe iterator indirection, or decay an array. |
202 | using _Iter = decltype(std::__niter_base(__source)); | |
203 | using value_type = typename iterator_traits<_Iter>::value_type; | |
204 | ||
205 | if constexpr (__is_contiguous<_Iter>) | |
206 | return basic_string_view<value_type>{&*__source}; | |
584d52b0 JW |
207 | else |
208 | { | |
209 | // _Source is an input iterator that iterates over an NTCTS. | |
210 | // Create a basic_string by reading until the null character. | |
b83b810a | 211 | basic_string<__unified_u8_t<value_type>> __str; |
584d52b0 JW |
212 | _Source __it = __source; |
213 | for (value_type __ch = *__it; __ch != value_type(); __ch = *++__it) | |
214 | __str.push_back(__ch); | |
215 | return __str; | |
216 | } | |
217 | } | |
218 | ||
219 | // The value type of a Source parameter's effective range. | |
b83b810a JW |
220 | template<typename _Source> |
221 | struct __source_value_type_impl | |
222 | { | |
223 | using type | |
224 | = typename __safe_iterator_traits<decay_t<_Source>>::value_type; | |
225 | }; | |
226 | ||
227 | template<typename _CharT, typename _Traits, typename _Alloc> | |
228 | struct __source_value_type_impl<basic_string<_CharT, _Traits, _Alloc>> | |
229 | { | |
230 | using type = _CharT; | |
231 | }; | |
232 | ||
233 | template<typename _CharT, typename _Traits> | |
234 | struct __source_value_type_impl<basic_string_view<_CharT, _Traits>> | |
235 | { | |
236 | using type = _CharT; | |
237 | }; | |
238 | ||
239 | // The value type of a Source parameter's effective range. | |
240 | template<typename _Source> | |
241 | using __source_value_t = typename __source_value_type_impl<_Source>::type; | |
584d52b0 JW |
242 | |
243 | // SFINAE helper to check that an effective range has value_type char, | |
244 | // as required by path constructors taking a std::locale parameter. | |
245 | // The type _Tp must have already been checked by _Path<Tp> or _Path2<_Tp>. | |
b83b810a | 246 | template<typename _Tp, typename _Val = __source_value_t<_Tp>> |
a1e7d33b | 247 | using __value_type_is_char |
584d52b0 | 248 | = std::enable_if_t<std::is_same_v<_Val, char>, _Val>; |
2b4e2c93 | 249 | |
584d52b0 JW |
250 | // As above, but also allows char8_t, as required by u8path |
251 | // C++20 [depr.fs.path.factory] | |
b83b810a | 252 | template<typename _Tp, typename _Val = __source_value_t<_Tp>> |
2b4e2c93 | 253 | using __value_type_is_char_or_char8_t |
584d52b0 | 254 | = std::enable_if_t<std::is_same_v<_Val, char> |
2b4e2c93 | 255 | #ifdef _GLIBCXX_USE_CHAR8_T |
584d52b0 | 256 | || std::is_same_v<_Val, char8_t> |
2b4e2c93 | 257 | #endif |
584d52b0 | 258 | , _Val>; |
a1e7d33b | 259 | |
b83b810a | 260 | // Create a basic_string<C> or basic_string_view<C> from an iterator range. |
cd3f067b JW |
261 | template<typename _InputIterator> |
262 | inline auto | |
263 | __string_from_range(_InputIterator __first, _InputIterator __last) | |
264 | { | |
265 | using _EcharT | |
266 | = typename std::iterator_traits<_InputIterator>::value_type; | |
b83b810a | 267 | static_assert(__is_encoded_char<_EcharT>); // C++17 [fs.req]/3 |
cd3f067b | 268 | |
b83b810a | 269 | if constexpr (__is_contiguous<_InputIterator>) |
cd3f067b JW |
270 | { |
271 | // For contiguous iterators we can just return a string view. | |
b83b810a JW |
272 | if (auto __len = __last - __first) [[__likely__]] |
273 | return basic_string_view<_EcharT>(&*__first, __len); | |
274 | return basic_string_view<_EcharT>(); | |
cd3f067b JW |
275 | } |
276 | else | |
b83b810a JW |
277 | { |
278 | // Conversion requires contiguous characters, so create a string. | |
279 | return basic_string<__unified_u8_t<_EcharT>>(__first, __last); | |
280 | } | |
cd3f067b JW |
281 | } |
282 | ||
f2ce64b5 | 283 | /// @} group filesystem |
a1e7d33b TH |
284 | } // namespace __detail |
285 | /// @endcond | |
641cb5a6 | 286 | |
f2ce64b5 JW |
287 | /// @addtogroup filesystem |
288 | /// @{ | |
289 | ||
290 | /// A filesystem path | |
291 | /// @ingroup filesystem | |
a1e7d33b TH |
292 | class path |
293 | { | |
641cb5a6 JW |
294 | public: |
295 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
d727fdc4 JW |
296 | using value_type = wchar_t; |
297 | static constexpr value_type preferred_separator = L'\\'; | |
641cb5a6 | 298 | #else |
d727fdc4 JW |
299 | # ifdef _GLIBCXX_DOXYGEN |
300 | /// Windows uses wchar_t for path::value_type, POSIX uses char. | |
301 | using value_type = __os_dependent__; | |
302 | # else | |
303 | using value_type = char; | |
304 | # endif | |
305 | static constexpr value_type preferred_separator = '/'; | |
641cb5a6 | 306 | #endif |
d727fdc4 | 307 | using string_type = std::basic_string<value_type>; |
641cb5a6 | 308 | |
d727fdc4 | 309 | /// path::format is ignored in this implementation |
43aaf5ab | 310 | enum format : unsigned char { native_format, generic_format, auto_format }; |
0348dd00 | 311 | |
641cb5a6 JW |
312 | // constructors and destructor |
313 | ||
314 | path() noexcept { } | |
315 | ||
316 | path(const path& __p) = default; | |
317 | ||
373acac1 | 318 | path(path&& __p) noexcept |
4f87bb8d JW |
319 | : _M_pathname(std::move(__p._M_pathname)), |
320 | _M_cmpts(std::move(__p._M_cmpts)) | |
321 | { __p.clear(); } | |
641cb5a6 | 322 | |
0348dd00 | 323 | path(string_type&& __source, format = auto_format) |
641cb5a6 JW |
324 | : _M_pathname(std::move(__source)) |
325 | { _M_split_cmpts(); } | |
326 | ||
327 | template<typename _Source, | |
a1e7d33b | 328 | typename _Require = __detail::_Path<_Source>> |
0348dd00 | 329 | path(_Source const& __source, format = auto_format) |
584d52b0 | 330 | : _M_pathname(_S_convert(__detail::__effective_range(__source))) |
641cb5a6 JW |
331 | { _M_split_cmpts(); } |
332 | ||
333 | template<typename _InputIterator, | |
988b853f | 334 | typename _Require = __detail::_Path2<_InputIterator>> |
0348dd00 | 335 | path(_InputIterator __first, _InputIterator __last, format = auto_format) |
85b24e32 | 336 | : _M_pathname(_S_convert(__detail::__string_from_range(__first, __last))) |
641cb5a6 JW |
337 | { _M_split_cmpts(); } |
338 | ||
339 | template<typename _Source, | |
a1e7d33b TH |
340 | typename _Require = __detail::_Path<_Source>, |
341 | typename _Require2 = __detail::__value_type_is_char<_Source>> | |
584d52b0 JW |
342 | path(_Source const& __src, const locale& __loc, format = auto_format) |
343 | : _M_pathname(_S_convert_loc(__detail::__effective_range(__src), __loc)) | |
641cb5a6 JW |
344 | { _M_split_cmpts(); } |
345 | ||
346 | template<typename _InputIterator, | |
988b853f JW |
347 | typename _Require = __detail::_Path2<_InputIterator>, |
348 | typename _Req2 = __detail::__value_type_is_char<_InputIterator>> | |
0348dd00 JW |
349 | path(_InputIterator __first, _InputIterator __last, const locale& __loc, |
350 | format = auto_format) | |
641cb5a6 JW |
351 | : _M_pathname(_S_convert_loc(__first, __last, __loc)) |
352 | { _M_split_cmpts(); } | |
353 | ||
354 | ~path() = default; | |
355 | ||
356 | // assignments | |
357 | ||
4f87bb8d JW |
358 | path& operator=(const path&); |
359 | path& operator=(path&&) noexcept; | |
641cb5a6 JW |
360 | path& operator=(string_type&& __source); |
361 | path& assign(string_type&& __source); | |
362 | ||
363 | template<typename _Source> | |
a1e7d33b | 364 | __detail::_Path<_Source>& |
641cb5a6 JW |
365 | operator=(_Source const& __source) |
366 | { return *this = path(__source); } | |
367 | ||
368 | template<typename _Source> | |
a1e7d33b | 369 | __detail::_Path<_Source>& |
641cb5a6 JW |
370 | assign(_Source const& __source) |
371 | { return *this = path(__source); } | |
372 | ||
373 | template<typename _InputIterator> | |
988b853f | 374 | __detail::_Path2<_InputIterator>& |
641cb5a6 JW |
375 | assign(_InputIterator __first, _InputIterator __last) |
376 | { return *this = path(__first, __last); } | |
377 | ||
378 | // appends | |
379 | ||
9534a5e6 | 380 | path& operator/=(const path& __p); |
641cb5a6 | 381 | |
24cc0de9 | 382 | template<typename _Source> |
a1e7d33b | 383 | __detail::_Path<_Source>& |
641cb5a6 | 384 | operator/=(_Source const& __source) |
4f87bb8d | 385 | { |
584d52b0 | 386 | _M_append(_S_convert(__detail::__effective_range(__source))); |
4f87bb8d JW |
387 | return *this; |
388 | } | |
641cb5a6 JW |
389 | |
390 | template<typename _Source> | |
a1e7d33b | 391 | __detail::_Path<_Source>& |
641cb5a6 | 392 | append(_Source const& __source) |
4f87bb8d | 393 | { |
584d52b0 | 394 | _M_append(_S_convert(__detail::__effective_range(__source))); |
4f87bb8d JW |
395 | return *this; |
396 | } | |
641cb5a6 JW |
397 | |
398 | template<typename _InputIterator> | |
988b853f | 399 | __detail::_Path2<_InputIterator>& |
641cb5a6 | 400 | append(_InputIterator __first, _InputIterator __last) |
4f87bb8d | 401 | { |
85b24e32 | 402 | _M_append(_S_convert(__detail::__string_from_range(__first, __last))); |
4f87bb8d JW |
403 | return *this; |
404 | } | |
641cb5a6 JW |
405 | |
406 | // concatenation | |
407 | ||
408 | path& operator+=(const path& __x); | |
409 | path& operator+=(const string_type& __x); | |
410 | path& operator+=(const value_type* __x); | |
411 | path& operator+=(value_type __x); | |
412 | path& operator+=(basic_string_view<value_type> __x); | |
413 | ||
414 | template<typename _Source> | |
a1e7d33b | 415 | __detail::_Path<_Source>& |
641cb5a6 JW |
416 | operator+=(_Source const& __x) { return concat(__x); } |
417 | ||
418 | template<typename _CharT> | |
988b853f | 419 | __detail::_Path2<_CharT*>& |
641cb5a6 JW |
420 | operator+=(_CharT __x); |
421 | ||
422 | template<typename _Source> | |
a1e7d33b | 423 | __detail::_Path<_Source>& |
641cb5a6 | 424 | concat(_Source const& __x) |
4f87bb8d | 425 | { |
584d52b0 | 426 | _M_concat(_S_convert(__detail::__effective_range(__x))); |
4f87bb8d JW |
427 | return *this; |
428 | } | |
641cb5a6 JW |
429 | |
430 | template<typename _InputIterator> | |
988b853f | 431 | __detail::_Path2<_InputIterator>& |
641cb5a6 | 432 | concat(_InputIterator __first, _InputIterator __last) |
4f87bb8d | 433 | { |
85b24e32 | 434 | _M_concat(_S_convert(__detail::__string_from_range(__first, __last))); |
4f87bb8d JW |
435 | return *this; |
436 | } | |
641cb5a6 JW |
437 | |
438 | // modifiers | |
439 | ||
440 | void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } | |
441 | ||
442 | path& make_preferred(); | |
443 | path& remove_filename(); | |
444 | path& replace_filename(const path& __replacement); | |
445 | path& replace_extension(const path& __replacement = path()); | |
446 | ||
447 | void swap(path& __rhs) noexcept; | |
448 | ||
449 | // native format observers | |
450 | ||
451 | const string_type& native() const noexcept { return _M_pathname; } | |
452 | const value_type* c_str() const noexcept { return _M_pathname.c_str(); } | |
453 | operator string_type() const { return _M_pathname; } | |
454 | ||
455 | template<typename _CharT, typename _Traits = std::char_traits<_CharT>, | |
456 | typename _Allocator = std::allocator<_CharT>> | |
457 | std::basic_string<_CharT, _Traits, _Allocator> | |
458 | string(const _Allocator& __a = _Allocator()) const; | |
459 | ||
460 | std::string string() const; | |
461 | #if _GLIBCXX_USE_WCHAR_T | |
462 | std::wstring wstring() const; | |
463 | #endif | |
c124af93 TH |
464 | #ifdef _GLIBCXX_USE_CHAR8_T |
465 | __attribute__((__abi_tag__("__u8"))) | |
466 | std::u8string u8string() const; | |
467 | #else | |
641cb5a6 | 468 | std::string u8string() const; |
c124af93 | 469 | #endif // _GLIBCXX_USE_CHAR8_T |
641cb5a6 JW |
470 | std::u16string u16string() const; |
471 | std::u32string u32string() const; | |
472 | ||
473 | // generic format observers | |
474 | template<typename _CharT, typename _Traits = std::char_traits<_CharT>, | |
475 | typename _Allocator = std::allocator<_CharT>> | |
476 | std::basic_string<_CharT, _Traits, _Allocator> | |
477 | generic_string(const _Allocator& __a = _Allocator()) const; | |
478 | ||
479 | std::string generic_string() const; | |
480 | #if _GLIBCXX_USE_WCHAR_T | |
481 | std::wstring generic_wstring() const; | |
482 | #endif | |
c124af93 TH |
483 | #ifdef _GLIBCXX_USE_CHAR8_T |
484 | __attribute__((__abi_tag__("__u8"))) | |
485 | std::u8string generic_u8string() const; | |
486 | #else | |
641cb5a6 | 487 | std::string generic_u8string() const; |
c124af93 | 488 | #endif // _GLIBCXX_USE_CHAR8_T |
641cb5a6 JW |
489 | std::u16string generic_u16string() const; |
490 | std::u32string generic_u32string() const; | |
491 | ||
492 | // compare | |
493 | ||
494 | int compare(const path& __p) const noexcept; | |
36313a6b JW |
495 | int compare(const string_type& __s) const noexcept; |
496 | int compare(const value_type* __s) const noexcept; | |
497 | int compare(basic_string_view<value_type> __s) const noexcept; | |
641cb5a6 JW |
498 | |
499 | // decomposition | |
500 | ||
501 | path root_name() const; | |
502 | path root_directory() const; | |
503 | path root_path() const; | |
504 | path relative_path() const; | |
505 | path parent_path() const; | |
506 | path filename() const; | |
507 | path stem() const; | |
508 | path extension() const; | |
509 | ||
510 | // query | |
511 | ||
d69f1ec7 | 512 | [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); } |
4fe5c8c7 JW |
513 | bool has_root_name() const noexcept; |
514 | bool has_root_directory() const noexcept; | |
515 | bool has_root_path() const noexcept; | |
516 | bool has_relative_path() const noexcept; | |
517 | bool has_parent_path() const noexcept; | |
518 | bool has_filename() const noexcept; | |
519 | bool has_stem() const noexcept; | |
520 | bool has_extension() const noexcept; | |
521 | bool is_absolute() const noexcept; | |
522 | bool is_relative() const noexcept { return !is_absolute(); } | |
641cb5a6 JW |
523 | |
524 | // generation | |
525 | path lexically_normal() const; | |
526 | path lexically_relative(const path& base) const; | |
527 | path lexically_proximate(const path& base) const; | |
528 | ||
529 | // iterators | |
530 | class iterator; | |
d727fdc4 | 531 | using const_iterator = iterator; |
641cb5a6 | 532 | |
f2b7f56a JW |
533 | iterator begin() const noexcept; |
534 | iterator end() const noexcept; | |
641cb5a6 | 535 | |
b0874c66 JW |
536 | /// Write a path to a stream |
537 | template<typename _CharT, typename _Traits> | |
538 | friend std::basic_ostream<_CharT, _Traits>& | |
539 | operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p) | |
540 | { | |
541 | __os << std::quoted(__p.string<_CharT, _Traits>()); | |
542 | return __os; | |
543 | } | |
544 | ||
545 | /// Read a path from a stream | |
546 | template<typename _CharT, typename _Traits> | |
547 | friend std::basic_istream<_CharT, _Traits>& | |
548 | operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p) | |
549 | { | |
550 | std::basic_string<_CharT, _Traits> __tmp; | |
551 | if (__is >> std::quoted(__tmp)) | |
552 | __p = std::move(__tmp); | |
553 | return __is; | |
554 | } | |
555 | ||
f90b16c4 JW |
556 | // non-member operators |
557 | ||
d43919bf JW |
558 | /// Compare paths |
559 | friend bool operator==(const path& __lhs, const path& __rhs) noexcept | |
1e690757 | 560 | { return path::_S_compare(__lhs, __rhs) == 0; } |
d43919bf JW |
561 | |
562 | #if __cpp_lib_three_way_comparison | |
563 | /// Compare paths | |
564 | friend strong_ordering | |
565 | operator<=>(const path& __lhs, const path& __rhs) noexcept | |
1e690757 | 566 | { return path::_S_compare(__lhs, __rhs) <=> 0; } |
d43919bf JW |
567 | #else |
568 | /// Compare paths | |
569 | friend bool operator!=(const path& __lhs, const path& __rhs) noexcept | |
570 | { return !(__lhs == __rhs); } | |
571 | ||
f90b16c4 JW |
572 | /// Compare paths |
573 | friend bool operator<(const path& __lhs, const path& __rhs) noexcept | |
574 | { return __lhs.compare(__rhs) < 0; } | |
575 | ||
576 | /// Compare paths | |
577 | friend bool operator<=(const path& __lhs, const path& __rhs) noexcept | |
578 | { return !(__rhs < __lhs); } | |
579 | ||
580 | /// Compare paths | |
581 | friend bool operator>(const path& __lhs, const path& __rhs) noexcept | |
582 | { return __rhs < __lhs; } | |
583 | ||
584 | /// Compare paths | |
585 | friend bool operator>=(const path& __lhs, const path& __rhs) noexcept | |
586 | { return !(__lhs < __rhs); } | |
d43919bf | 587 | #endif |
f90b16c4 JW |
588 | |
589 | /// Append one path to another | |
590 | friend path operator/(const path& __lhs, const path& __rhs) | |
591 | { | |
592 | path __result(__lhs); | |
593 | __result /= __rhs; | |
594 | return __result; | |
595 | } | |
596 | ||
641cb5a6 JW |
597 | private: |
598 | enum class _Type : unsigned char { | |
4f87bb8d | 599 | _Multi = 0, _Root_name, _Root_dir, _Filename |
641cb5a6 JW |
600 | }; |
601 | ||
4f87bb8d JW |
602 | path(basic_string_view<value_type> __str, _Type __type) |
603 | : _M_pathname(__str) | |
641cb5a6 | 604 | { |
4f87bb8d JW |
605 | __glibcxx_assert(__type != _Type::_Multi); |
606 | _M_cmpts.type(__type); | |
641cb5a6 JW |
607 | } |
608 | ||
609 | enum class _Split { _Stem, _Extension }; | |
610 | ||
4f87bb8d JW |
611 | void _M_append(basic_string_view<value_type>); |
612 | void _M_concat(basic_string_view<value_type>); | |
641cb5a6 | 613 | |
4fe5c8c7 | 614 | pair<const string_type*, size_t> _M_find_extension() const noexcept; |
641cb5a6 | 615 | |
584d52b0 | 616 | // path::_S_convert creates a basic_string<value_type> or |
b83b810a JW |
617 | // basic_string_view<value_type> from a basic_string<C> or |
618 | // basic_string_view<C>, for an encoded character type C, | |
584d52b0 | 619 | // performing the conversions required by [fs.path.type.cvt]. |
584d52b0 JW |
620 | template<typename _Tp> |
621 | static auto | |
b83b810a | 622 | _S_convert(_Tp __str) |
373acac1 | 623 | noexcept(is_same_v<typename _Tp::value_type, value_type>) |
641cb5a6 | 624 | { |
5e3f8883 | 625 | if constexpr (is_same_v<typename _Tp::value_type, value_type>) |
b83b810a JW |
626 | return __str; // No conversion needed. |
627 | #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T | |
628 | else if constexpr (is_same_v<_Tp, std::u8string>) | |
629 | // Calling _S_convert<char8_t> will return a u8string_view that | |
630 | // refers to __str and would dangle after this function returns. | |
631 | // Return a string_type instead, to avoid dangling. | |
e547d134 JW |
632 | return string_type(_S_convert(__str.data(), |
633 | __str.data() + __str.size())); | |
b83b810a | 634 | #endif |
584d52b0 JW |
635 | else |
636 | return _S_convert(__str.data(), __str.data() + __str.size()); | |
641cb5a6 JW |
637 | } |
638 | ||
584d52b0 JW |
639 | template<typename _EcharT> |
640 | static auto | |
641 | _S_convert(const _EcharT* __first, const _EcharT* __last); | |
642 | ||
b83b810a JW |
643 | // _S_convert_loc converts a range of char to string_type, using the |
644 | // supplied locale for encoding conversions. | |
645 | ||
641cb5a6 JW |
646 | static string_type |
647 | _S_convert_loc(const char* __first, const char* __last, | |
648 | const std::locale& __loc); | |
649 | ||
650 | template<typename _Iter> | |
651 | static string_type | |
652 | _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) | |
653 | { | |
cd3f067b | 654 | const auto __s = __detail::__string_from_range(__first, __last); |
584d52b0 | 655 | return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); |
641cb5a6 JW |
656 | } |
657 | ||
584d52b0 | 658 | template<typename _Tp> |
641cb5a6 | 659 | static string_type |
584d52b0 | 660 | _S_convert_loc(const _Tp& __s, const std::locale& __loc) |
641cb5a6 | 661 | { |
49d729ea | 662 | return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); |
641cb5a6 JW |
663 | } |
664 | ||
665 | template<typename _CharT, typename _Traits, typename _Allocator> | |
666 | static basic_string<_CharT, _Traits, _Allocator> | |
9fc98511 | 667 | _S_str_convert(basic_string_view<value_type>, const _Allocator&); |
641cb5a6 | 668 | |
1e690757 JW |
669 | // Returns lhs.compare(rhs), but defined after path::iterator is complete. |
670 | __attribute__((__always_inline__)) | |
671 | static int | |
672 | _S_compare(const path& __lhs, const path& __rhs) noexcept; | |
673 | ||
641cb5a6 | 674 | void _M_split_cmpts(); |
4f87bb8d JW |
675 | |
676 | _Type _M_type() const noexcept { return _M_cmpts.type(); } | |
641cb5a6 JW |
677 | |
678 | string_type _M_pathname; | |
679 | ||
680 | struct _Cmpt; | |
4f87bb8d JW |
681 | |
682 | struct _List | |
683 | { | |
684 | using value_type = _Cmpt; | |
685 | using iterator = value_type*; | |
686 | using const_iterator = const value_type*; | |
687 | ||
688 | _List(); | |
689 | _List(const _List&); | |
690 | _List(_List&&) = default; | |
691 | _List& operator=(const _List&); | |
692 | _List& operator=(_List&&) = default; | |
693 | ~_List() = default; | |
694 | ||
695 | _Type type() const noexcept | |
b6b9fd4a | 696 | { return _Type(reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3); } |
4f87bb8d JW |
697 | |
698 | void type(_Type) noexcept; | |
699 | ||
700 | int size() const noexcept; // zero unless type() == _Type::_Multi | |
701 | bool empty() const noexcept; // true unless type() == _Type::_Multi | |
702 | void clear(); | |
703 | void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); } | |
704 | int capacity() const noexcept; | |
705 | void reserve(int, bool); ///< @pre type() == _Type::_Multi | |
706 | ||
707 | // All the member functions below here have a precondition !empty() | |
708 | // (and they should only be called from within the library). | |
709 | ||
fe9d058c JW |
710 | iterator begin() noexcept; |
711 | iterator end() noexcept; | |
712 | const_iterator begin() const noexcept; | |
713 | const_iterator end() const noexcept; | |
4f87bb8d JW |
714 | |
715 | value_type& front() noexcept; | |
716 | value_type& back() noexcept; | |
717 | const value_type& front() const noexcept; | |
718 | const value_type& back() const noexcept; | |
719 | ||
73d968d9 JW |
720 | void pop_back(); |
721 | void _M_erase_from(const_iterator __pos); // erases [__pos,end()) | |
4f87bb8d JW |
722 | |
723 | struct _Impl; | |
724 | struct _Impl_deleter | |
725 | { | |
726 | void operator()(_Impl*) const noexcept; | |
727 | }; | |
728 | unique_ptr<_Impl, _Impl_deleter> _M_impl; | |
729 | }; | |
730 | _List _M_cmpts; | |
731 | ||
732 | struct _Parser; | |
641cb5a6 JW |
733 | }; |
734 | ||
f2ce64b5 JW |
735 | /// @{ |
736 | /// @relates std::filesystem::path | |
d727fdc4 | 737 | |
641cb5a6 JW |
738 | inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } |
739 | ||
740 | size_t hash_value(const path& __p) noexcept; | |
741 | ||
d6039f5c JW |
742 | /// @} |
743 | ||
744 | /// Exception type thrown by the Filesystem library | |
745 | class filesystem_error : public std::system_error | |
746 | { | |
747 | public: | |
748 | filesystem_error(const string& __what_arg, error_code __ec); | |
749 | ||
750 | filesystem_error(const string& __what_arg, const path& __p1, | |
751 | error_code __ec); | |
752 | ||
753 | filesystem_error(const string& __what_arg, const path& __p1, | |
754 | const path& __p2, error_code __ec); | |
755 | ||
756 | filesystem_error(const filesystem_error&) = default; | |
757 | filesystem_error& operator=(const filesystem_error&) = default; | |
758 | ||
759 | // No move constructor or assignment operator. | |
760 | // Copy rvalues instead, so that _M_impl is not left empty. | |
761 | ||
762 | ~filesystem_error(); | |
763 | ||
764 | const path& path1() const noexcept; | |
765 | const path& path2() const noexcept; | |
766 | const char* what() const noexcept; | |
767 | ||
768 | private: | |
769 | struct _Impl; | |
770 | std::__shared_ptr<const _Impl> _M_impl; | |
771 | }; | |
772 | ||
57a4f5e4 JW |
773 | /// @cond undocumented |
774 | namespace __detail | |
775 | { | |
776 | [[noreturn]] inline void | |
777 | __throw_conversion_error() | |
778 | { | |
779 | _GLIBCXX_THROW_OR_ABORT(filesystem_error( | |
780 | "Cannot convert character sequence", | |
781 | std::make_error_code(errc::illegal_byte_sequence))); | |
782 | } | |
783 | ||
784 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
785 | template<typename _Tp> | |
786 | inline std::wstring | |
787 | __wstr_from_utf8(const _Tp& __str) | |
788 | { | |
789 | static_assert(std::is_same_v<typename _Tp::value_type, char>); | |
790 | std::wstring __wstr; | |
791 | // XXX This assumes native wide encoding is UTF-16. | |
792 | std::codecvt_utf8_utf16<wchar_t> __wcvt; | |
793 | const auto __p = __str.data(); | |
794 | if (!__str_codecvt_in_all(__p, __p + __str.size(), __wstr, __wcvt)) | |
795 | __detail::__throw_conversion_error(); | |
796 | return __wstr; | |
797 | } | |
798 | #endif | |
799 | ||
800 | } // namespace __detail | |
801 | /// @endcond | |
802 | ||
803 | ||
d6039f5c JW |
804 | /** Create a path from a UTF-8-encoded sequence of char |
805 | * | |
806 | * @relates std::filesystem::path | |
807 | */ | |
a1e7d33b | 808 | template<typename _InputIterator, |
988b853f | 809 | typename _Require = __detail::_Path2<_InputIterator>, |
2b4e2c93 TH |
810 | typename _CharT |
811 | = __detail::__value_type_is_char_or_char8_t<_InputIterator>> | |
a1e7d33b | 812 | inline path |
9534a5e6 | 813 | u8path(_InputIterator __first, _InputIterator __last) |
641cb5a6 JW |
814 | { |
815 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
3eda32cb | 816 | if constexpr (is_same_v<_CharT, char>) |
cd3f067b JW |
817 | return path{ __detail::__wstr_from_utf8( |
818 | __detail::__string_from_range(__first, __last)) }; | |
3eda32cb | 819 | else |
cd3f067b | 820 | return path{ __first, __last }; // constructor handles char8_t |
641cb5a6 | 821 | #else |
26b1320e | 822 | // This assumes native normal encoding is UTF-8. |
9534a5e6 | 823 | return path{ __first, __last }; |
641cb5a6 JW |
824 | #endif |
825 | } | |
826 | ||
d6039f5c JW |
827 | /** Create a path from a UTF-8-encoded sequence of char |
828 | * | |
829 | * @relates std::filesystem::path | |
830 | */ | |
a1e7d33b TH |
831 | template<typename _Source, |
832 | typename _Require = __detail::_Path<_Source>, | |
2b4e2c93 | 833 | typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>> |
a1e7d33b | 834 | inline path |
9534a5e6 | 835 | u8path(const _Source& __source) |
641cb5a6 JW |
836 | { |
837 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
3eda32cb | 838 | if constexpr (is_same_v<_CharT, char>) |
cd3f067b JW |
839 | return path{ __detail::__wstr_from_utf8( |
840 | __detail::__effective_range(__source)) }; | |
3eda32cb | 841 | else |
cd3f067b | 842 | return path{ __source }; // constructor handles char8_t |
641cb5a6 | 843 | #else |
cd3f067b | 844 | // This assumes native normal encoding is UTF-8. |
9534a5e6 | 845 | return path{ __source }; |
641cb5a6 JW |
846 | #endif |
847 | } | |
848 | ||
d727fdc4 JW |
849 | /// @cond undocumented |
850 | ||
641cb5a6 JW |
851 | struct path::_Cmpt : path |
852 | { | |
4f87bb8d JW |
853 | _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos) |
854 | : path(__s, __t), _M_pos(__pos) { } | |
641cb5a6 JW |
855 | |
856 | _Cmpt() : _M_pos(-1) { } | |
857 | ||
858 | size_t _M_pos; | |
859 | }; | |
860 | ||
584d52b0 JW |
861 | template<typename _EcharT> |
862 | auto | |
863 | path::_S_convert(const _EcharT* __f, const _EcharT* __l) | |
641cb5a6 | 864 | { |
584d52b0 JW |
865 | static_assert(__detail::__is_encoded_char<_EcharT>); |
866 | ||
867 | if constexpr (is_same_v<_EcharT, value_type>) | |
868 | return basic_string_view<value_type>(__f, __l - __f); | |
869 | #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T | |
870 | else if constexpr (is_same_v<_EcharT, char8_t>) | |
871 | // For POSIX converting from char8_t to char is also 'noconv' | |
872 | return string_view(reinterpret_cast<const char*>(__f), __l - __f); | |
26b1320e | 873 | #endif |
584d52b0 JW |
874 | else |
875 | { | |
26b1320e | 876 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
584d52b0 JW |
877 | std::wstring __wstr; |
878 | if constexpr (is_same_v<_EcharT, char>) | |
879 | { | |
880 | struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t> | |
881 | { } __cvt; | |
882 | if (__str_codecvt_in_all(__f, __l, __wstr, __cvt)) | |
883 | return __wstr; | |
884 | } | |
c124af93 | 885 | #ifdef _GLIBCXX_USE_CHAR8_T |
584d52b0 JW |
886 | else if constexpr (is_same_v<_EcharT, char8_t>) |
887 | { | |
cd3f067b JW |
888 | const auto __f2 = reinterpret_cast<const char*>(__f); |
889 | return __detail::__wstr_from_utf8(string_view(__f2, __l - __f)); | |
584d52b0 | 890 | } |
c124af93 | 891 | #endif |
584d52b0 JW |
892 | else // char16_t or char32_t |
893 | { | |
894 | struct _UCvt : std::codecvt<_EcharT, char, std::mbstate_t> | |
895 | { } __cvt; | |
896 | std::string __str; | |
897 | if (__str_codecvt_out_all(__f, __l, __str, __cvt)) | |
cd3f067b | 898 | return __detail::__wstr_from_utf8(__str); |
584d52b0 | 899 | } |
26b1320e | 900 | #else // ! windows |
584d52b0 JW |
901 | struct _UCvt : std::codecvt<_EcharT, char, std::mbstate_t> |
902 | { } __cvt; | |
903 | std::string __str; | |
904 | if (__str_codecvt_out_all(__f, __l, __str, __cvt)) | |
905 | return __str; | |
c124af93 | 906 | #endif |
57a4f5e4 | 907 | __detail::__throw_conversion_error(); |
641cb5a6 | 908 | } |
584d52b0 | 909 | } |
641cb5a6 | 910 | |
d727fdc4 JW |
911 | /// @endcond |
912 | ||
641cb5a6 JW |
913 | /// An iterator for the components of a path |
914 | class path::iterator | |
915 | { | |
916 | public: | |
917 | using difference_type = std::ptrdiff_t; | |
918 | using value_type = path; | |
919 | using reference = const path&; | |
920 | using pointer = const path*; | |
921 | using iterator_category = std::bidirectional_iterator_tag; | |
922 | ||
42eff613 | 923 | iterator() noexcept : _M_path(nullptr), _M_cur(), _M_at_end() { } |
641cb5a6 JW |
924 | |
925 | iterator(const iterator&) = default; | |
926 | iterator& operator=(const iterator&) = default; | |
927 | ||
42eff613 JW |
928 | reference operator*() const noexcept; |
929 | pointer operator->() const noexcept { return std::__addressof(**this); } | |
641cb5a6 | 930 | |
42eff613 | 931 | iterator& operator++() noexcept; |
641cb5a6 | 932 | |
42eff613 JW |
933 | iterator operator++(int) noexcept |
934 | { auto __tmp = *this; ++*this; return __tmp; } | |
641cb5a6 | 935 | |
42eff613 JW |
936 | iterator& operator--() noexcept; |
937 | ||
938 | iterator operator--(int) noexcept | |
939 | { auto __tmp = *this; --*this; return __tmp; } | |
940 | ||
941 | friend bool | |
942 | operator==(const iterator& __lhs, const iterator& __rhs) noexcept | |
641cb5a6 JW |
943 | { return __lhs._M_equals(__rhs); } |
944 | ||
42eff613 JW |
945 | friend bool |
946 | operator!=(const iterator& __lhs, const iterator& __rhs) noexcept | |
641cb5a6 JW |
947 | { return !__lhs._M_equals(__rhs); } |
948 | ||
949 | private: | |
950 | friend class path; | |
951 | ||
42eff613 JW |
952 | bool |
953 | _M_is_multi() const noexcept | |
954 | { return _M_path->_M_type() == _Type::_Multi; } | |
9e160526 JW |
955 | |
956 | friend difference_type | |
957 | __path_iter_distance(const iterator& __first, const iterator& __last) | |
42eff613 | 958 | noexcept |
9e160526 JW |
959 | { |
960 | __glibcxx_assert(__first._M_path != nullptr); | |
961 | __glibcxx_assert(__first._M_path == __last._M_path); | |
962 | if (__first._M_is_multi()) | |
963 | return std::distance(__first._M_cur, __last._M_cur); | |
964 | else if (__first._M_at_end == __last._M_at_end) | |
965 | return 0; | |
966 | else | |
967 | return __first._M_at_end ? -1 : 1; | |
968 | } | |
969 | ||
970 | friend void | |
42eff613 | 971 | __path_iter_advance(iterator& __i, difference_type __n) noexcept |
9e160526 JW |
972 | { |
973 | if (__n == 1) | |
974 | ++__i; | |
975 | else if (__n == -1) | |
976 | --__i; | |
977 | else if (__n != 0) | |
978 | { | |
979 | __glibcxx_assert(__i._M_path != nullptr); | |
980 | __glibcxx_assert(__i._M_is_multi()); | |
981 | // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n); | |
982 | __i._M_cur += __n; | |
983 | } | |
984 | } | |
985 | ||
42eff613 | 986 | iterator(const path* __path, path::_List::const_iterator __iter) noexcept |
641cb5a6 JW |
987 | : _M_path(__path), _M_cur(__iter), _M_at_end() |
988 | { } | |
989 | ||
42eff613 | 990 | iterator(const path* __path, bool __at_end) noexcept |
641cb5a6 JW |
991 | : _M_path(__path), _M_cur(), _M_at_end(__at_end) |
992 | { } | |
993 | ||
42eff613 | 994 | bool _M_equals(iterator) const noexcept; |
641cb5a6 JW |
995 | |
996 | const path* _M_path; | |
997 | path::_List::const_iterator _M_cur; | |
998 | bool _M_at_end; // only used when type != _Multi | |
999 | }; | |
1000 | ||
1001 | ||
1002 | inline path& | |
1003 | path::operator=(path&& __p) noexcept | |
1004 | { | |
d96f11a2 JW |
1005 | if (&__p == this) [[__unlikely__]] |
1006 | return *this; | |
1007 | ||
641cb5a6 JW |
1008 | _M_pathname = std::move(__p._M_pathname); |
1009 | _M_cmpts = std::move(__p._M_cmpts); | |
641cb5a6 JW |
1010 | __p.clear(); |
1011 | return *this; | |
1012 | } | |
1013 | ||
1014 | inline path& | |
1015 | path::operator=(string_type&& __source) | |
1016 | { return *this = path(std::move(__source)); } | |
1017 | ||
1018 | inline path& | |
1019 | path::assign(string_type&& __source) | |
1020 | { return *this = path(std::move(__source)); } | |
1021 | ||
641cb5a6 JW |
1022 | inline path& |
1023 | path::operator+=(const string_type& __x) | |
1024 | { | |
4f87bb8d | 1025 | _M_concat(__x); |
641cb5a6 JW |
1026 | return *this; |
1027 | } | |
1028 | ||
1029 | inline path& | |
1030 | path::operator+=(const value_type* __x) | |
1031 | { | |
4f87bb8d | 1032 | _M_concat(__x); |
641cb5a6 JW |
1033 | return *this; |
1034 | } | |
1035 | ||
1036 | inline path& | |
1037 | path::operator+=(value_type __x) | |
1038 | { | |
4f87bb8d | 1039 | _M_concat(basic_string_view<value_type>(&__x, 1)); |
641cb5a6 JW |
1040 | return *this; |
1041 | } | |
1042 | ||
1043 | inline path& | |
1044 | path::operator+=(basic_string_view<value_type> __x) | |
1045 | { | |
4f87bb8d | 1046 | _M_concat(__x); |
641cb5a6 JW |
1047 | return *this; |
1048 | } | |
1049 | ||
1050 | template<typename _CharT> | |
988b853f | 1051 | inline __detail::_Path2<_CharT*>& |
584d52b0 | 1052 | path::operator+=(const _CharT __x) |
641cb5a6 | 1053 | { |
584d52b0 JW |
1054 | _M_concat(_S_convert(&__x, &__x + 1)); |
1055 | return *this; | |
641cb5a6 JW |
1056 | } |
1057 | ||
1058 | inline path& | |
1059 | path::make_preferred() | |
1060 | { | |
1061 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
00df7ee4 JW |
1062 | auto __pos = _M_pathname.find(L'/'); |
1063 | while (__pos != _M_pathname.npos) | |
1064 | { | |
1065 | _M_pathname[__pos] = preferred_separator; | |
1066 | __pos = _M_pathname.find(L'/', __pos); | |
1067 | } | |
641cb5a6 JW |
1068 | #endif |
1069 | return *this; | |
1070 | } | |
1071 | ||
1072 | inline void path::swap(path& __rhs) noexcept | |
1073 | { | |
1074 | _M_pathname.swap(__rhs._M_pathname); | |
1075 | _M_cmpts.swap(__rhs._M_cmpts); | |
641cb5a6 JW |
1076 | } |
1077 | ||
d727fdc4 | 1078 | /// @cond undocumented |
641cb5a6 JW |
1079 | template<typename _CharT, typename _Traits, typename _Allocator> |
1080 | std::basic_string<_CharT, _Traits, _Allocator> | |
9fc98511 JW |
1081 | path::_S_str_convert(basic_string_view<value_type> __str, |
1082 | const _Allocator& __a) | |
641cb5a6 | 1083 | { |
26b1320e | 1084 | static_assert(!is_same_v<_CharT, value_type>); |
641cb5a6 | 1085 | |
26b1320e JW |
1086 | using _WString = basic_string<_CharT, _Traits, _Allocator>; |
1087 | ||
1088 | if (__str.size() == 0) | |
1089 | return _WString(__a); | |
641cb5a6 JW |
1090 | |
1091 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
26b1320e JW |
1092 | // First convert native string from UTF-16 to to UTF-8. |
1093 | // XXX This assumes that the execution wide-character set is UTF-16. | |
1094 | std::codecvt_utf8_utf16<value_type> __cvt; | |
1095 | ||
641cb5a6 JW |
1096 | using _CharAlloc = __alloc_rebind<_Allocator, char>; |
1097 | using _String = basic_string<char, char_traits<char>, _CharAlloc>; | |
641cb5a6 | 1098 | _String __u8str{_CharAlloc{__a}}; |
26b1320e JW |
1099 | const value_type* __wfirst = __str.data(); |
1100 | const value_type* __wlast = __wfirst + __str.size(); | |
1101 | if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) { | |
1102 | if constexpr (is_same_v<_CharT, char>) | |
1103 | return __u8str; // XXX assumes native ordinary encoding is UTF-8. | |
1104 | else { | |
1105 | ||
1106 | const char* __first = __u8str.data(); | |
1107 | const char* __last = __first + __u8str.size(); | |
641cb5a6 | 1108 | #else |
26b1320e JW |
1109 | const value_type* __first = __str.data(); |
1110 | const value_type* __last = __first + __str.size(); | |
1111 | #endif | |
1112 | ||
1113 | // Convert UTF-8 string to requested format. | |
c124af93 TH |
1114 | #ifdef _GLIBCXX_USE_CHAR8_T |
1115 | if constexpr (is_same_v<_CharT, char8_t>) | |
26b1320e | 1116 | return _WString(__first, __last, __a); |
c124af93 | 1117 | else |
c124af93 | 1118 | #endif |
26b1320e JW |
1119 | { |
1120 | // Convert UTF-8 to wide string. | |
1121 | _WString __wstr(__a); | |
1122 | struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt; | |
1123 | if (__str_codecvt_in_all(__first, __last, __wstr, __cvt)) | |
c124af93 | 1124 | return __wstr; |
c124af93 | 1125 | } |
26b1320e JW |
1126 | |
1127 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
1128 | } } | |
641cb5a6 | 1129 | #endif |
57a4f5e4 | 1130 | __detail::__throw_conversion_error(); |
641cb5a6 | 1131 | } |
d727fdc4 | 1132 | /// @endcond |
641cb5a6 JW |
1133 | |
1134 | template<typename _CharT, typename _Traits, typename _Allocator> | |
1135 | inline basic_string<_CharT, _Traits, _Allocator> | |
1136 | path::string(const _Allocator& __a) const | |
1137 | { | |
1138 | if constexpr (is_same_v<_CharT, value_type>) | |
26b1320e | 1139 | return { _M_pathname.c_str(), _M_pathname.length(), __a }; |
641cb5a6 JW |
1140 | else |
1141 | return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); | |
1142 | } | |
1143 | ||
1144 | inline std::string | |
1145 | path::string() const { return string<char>(); } | |
1146 | ||
1147 | #if _GLIBCXX_USE_WCHAR_T | |
1148 | inline std::wstring | |
1149 | path::wstring() const { return string<wchar_t>(); } | |
1150 | #endif | |
1151 | ||
c124af93 TH |
1152 | #ifdef _GLIBCXX_USE_CHAR8_T |
1153 | inline std::u8string | |
1154 | path::u8string() const { return string<char8_t>(); } | |
1155 | #else | |
641cb5a6 JW |
1156 | inline std::string |
1157 | path::u8string() const | |
1158 | { | |
1159 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
1160 | std::string __str; | |
26b1320e JW |
1161 | // convert from native wide encoding (assumed to be UTF-16) to UTF-8 |
1162 | std::codecvt_utf8_utf16<value_type> __cvt; | |
641cb5a6 JW |
1163 | const value_type* __first = _M_pathname.data(); |
1164 | const value_type* __last = __first + _M_pathname.size(); | |
26b1320e | 1165 | if (__str_codecvt_out_all(__first, __last, __str, __cvt)) |
641cb5a6 | 1166 | return __str; |
57a4f5e4 | 1167 | __detail::__throw_conversion_error(); |
641cb5a6 JW |
1168 | #else |
1169 | return _M_pathname; | |
1170 | #endif | |
1171 | } | |
c124af93 | 1172 | #endif // _GLIBCXX_USE_CHAR8_T |
641cb5a6 JW |
1173 | |
1174 | inline std::u16string | |
1175 | path::u16string() const { return string<char16_t>(); } | |
1176 | ||
1177 | inline std::u32string | |
1178 | path::u32string() const { return string<char32_t>(); } | |
1179 | ||
1180 | template<typename _CharT, typename _Traits, typename _Allocator> | |
1181 | inline std::basic_string<_CharT, _Traits, _Allocator> | |
1182 | path::generic_string(const _Allocator& __a) const | |
1183 | { | |
1184 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
1185 | const value_type __slash = L'/'; | |
1186 | #else | |
1187 | const value_type __slash = '/'; | |
1188 | #endif | |
9fc98511 JW |
1189 | using _Alloc2 = typename allocator_traits<_Allocator>::template |
1190 | rebind_alloc<value_type>; | |
1191 | basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a); | |
641cb5a6 | 1192 | |
4f87bb8d | 1193 | if (_M_type() == _Type::_Root_dir) |
641cb5a6 JW |
1194 | __str.assign(1, __slash); |
1195 | else | |
1196 | { | |
1197 | __str.reserve(_M_pathname.size()); | |
1198 | bool __add_slash = false; | |
1199 | for (auto& __elem : *this) | |
1200 | { | |
fe7cc34f JW |
1201 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1202 | if (__elem._M_type() == _Type::_Root_dir) | |
1203 | { | |
1204 | __str += __slash; | |
1205 | continue; | |
1206 | } | |
1207 | #endif | |
641cb5a6 JW |
1208 | if (__add_slash) |
1209 | __str += __slash; | |
9fc98511 | 1210 | __str += basic_string_view<value_type>(__elem._M_pathname); |
4f87bb8d | 1211 | __add_slash = __elem._M_type() == _Type::_Filename; |
641cb5a6 JW |
1212 | } |
1213 | } | |
1214 | ||
1215 | if constexpr (is_same_v<_CharT, value_type>) | |
1216 | return __str; | |
1217 | else | |
1218 | return _S_str_convert<_CharT, _Traits>(__str, __a); | |
1219 | } | |
1220 | ||
1221 | inline std::string | |
1222 | path::generic_string() const | |
1223 | { return generic_string<char>(); } | |
1224 | ||
1225 | #if _GLIBCXX_USE_WCHAR_T | |
1226 | inline std::wstring | |
1227 | path::generic_wstring() const | |
1228 | { return generic_string<wchar_t>(); } | |
1229 | #endif | |
1230 | ||
c124af93 TH |
1231 | #ifdef _GLIBCXX_USE_CHAR8_T |
1232 | inline std::u8string | |
1233 | path::generic_u8string() const | |
1234 | { return generic_string<char8_t>(); } | |
1235 | #else | |
641cb5a6 JW |
1236 | inline std::string |
1237 | path::generic_u8string() const | |
1238 | { return generic_string(); } | |
c124af93 | 1239 | #endif |
641cb5a6 JW |
1240 | |
1241 | inline std::u16string | |
1242 | path::generic_u16string() const | |
1243 | { return generic_string<char16_t>(); } | |
1244 | ||
1245 | inline std::u32string | |
1246 | path::generic_u32string() const | |
1247 | { return generic_string<char32_t>(); } | |
1248 | ||
1249 | inline int | |
36313a6b JW |
1250 | path::compare(const string_type& __s) const noexcept |
1251 | { return compare(basic_string_view<value_type>(__s)); } | |
641cb5a6 JW |
1252 | |
1253 | inline int | |
36313a6b JW |
1254 | path::compare(const value_type* __s) const noexcept |
1255 | { return compare(basic_string_view<value_type>(__s)); } | |
641cb5a6 JW |
1256 | |
1257 | inline path | |
1258 | path::filename() const | |
1259 | { | |
1260 | if (empty()) | |
1261 | return {}; | |
4f87bb8d | 1262 | else if (_M_type() == _Type::_Filename) |
641cb5a6 | 1263 | return *this; |
4f87bb8d | 1264 | else if (_M_type() == _Type::_Multi) |
641cb5a6 JW |
1265 | { |
1266 | if (_M_pathname.back() == preferred_separator) | |
1267 | return {}; | |
1268 | auto& __last = *--end(); | |
4f87bb8d | 1269 | if (__last._M_type() == _Type::_Filename) |
641cb5a6 JW |
1270 | return __last; |
1271 | } | |
1272 | return {}; | |
1273 | } | |
1274 | ||
1275 | inline path | |
1276 | path::stem() const | |
1277 | { | |
1278 | auto ext = _M_find_extension(); | |
1279 | if (ext.first && ext.second != 0) | |
1280 | return path{ext.first->substr(0, ext.second)}; | |
1281 | return {}; | |
1282 | } | |
1283 | ||
1284 | inline path | |
1285 | path::extension() const | |
1286 | { | |
1287 | auto ext = _M_find_extension(); | |
1288 | if (ext.first && ext.second != string_type::npos) | |
1289 | return path{ext.first->substr(ext.second)}; | |
1290 | return {}; | |
1291 | } | |
1292 | ||
1293 | inline bool | |
4fe5c8c7 | 1294 | path::has_stem() const noexcept |
641cb5a6 JW |
1295 | { |
1296 | auto ext = _M_find_extension(); | |
1297 | return ext.first && ext.second != 0; | |
1298 | } | |
1299 | ||
1300 | inline bool | |
4fe5c8c7 | 1301 | path::has_extension() const noexcept |
641cb5a6 JW |
1302 | { |
1303 | auto ext = _M_find_extension(); | |
1304 | return ext.first && ext.second != string_type::npos; | |
1305 | } | |
1306 | ||
9534a5e6 | 1307 | inline bool |
4fe5c8c7 | 1308 | path::is_absolute() const noexcept |
9534a5e6 JW |
1309 | { |
1310 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS | |
1311 | return has_root_name() && has_root_directory(); | |
1312 | #else | |
1313 | return has_root_directory(); | |
1314 | #endif | |
1315 | } | |
1316 | ||
641cb5a6 | 1317 | inline path::iterator |
42eff613 | 1318 | path::begin() const noexcept |
641cb5a6 | 1319 | { |
4f87bb8d | 1320 | if (_M_type() == _Type::_Multi) |
641cb5a6 | 1321 | return iterator(this, _M_cmpts.begin()); |
cf290ea3 | 1322 | return iterator(this, empty()); |
641cb5a6 JW |
1323 | } |
1324 | ||
1325 | inline path::iterator | |
42eff613 | 1326 | path::end() const noexcept |
641cb5a6 | 1327 | { |
4f87bb8d | 1328 | if (_M_type() == _Type::_Multi) |
641cb5a6 JW |
1329 | return iterator(this, _M_cmpts.end()); |
1330 | return iterator(this, true); | |
1331 | } | |
1332 | ||
1333 | inline path::iterator& | |
42eff613 | 1334 | path::iterator::operator++() noexcept |
641cb5a6 JW |
1335 | { |
1336 | __glibcxx_assert(_M_path != nullptr); | |
42eff613 | 1337 | if (_M_is_multi()) |
641cb5a6 JW |
1338 | { |
1339 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); | |
1340 | ++_M_cur; | |
1341 | } | |
1342 | else | |
1343 | { | |
1344 | __glibcxx_assert(!_M_at_end); | |
1345 | _M_at_end = true; | |
1346 | } | |
1347 | return *this; | |
1348 | } | |
1349 | ||
1350 | inline path::iterator& | |
42eff613 | 1351 | path::iterator::operator--() noexcept |
641cb5a6 JW |
1352 | { |
1353 | __glibcxx_assert(_M_path != nullptr); | |
42eff613 | 1354 | if (_M_is_multi()) |
641cb5a6 JW |
1355 | { |
1356 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); | |
1357 | --_M_cur; | |
1358 | } | |
1359 | else | |
1360 | { | |
1361 | __glibcxx_assert(_M_at_end); | |
1362 | _M_at_end = false; | |
1363 | } | |
1364 | return *this; | |
1365 | } | |
1366 | ||
1367 | inline path::iterator::reference | |
42eff613 | 1368 | path::iterator::operator*() const noexcept |
641cb5a6 JW |
1369 | { |
1370 | __glibcxx_assert(_M_path != nullptr); | |
42eff613 | 1371 | if (_M_is_multi()) |
641cb5a6 JW |
1372 | { |
1373 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); | |
1374 | return *_M_cur; | |
1375 | } | |
1376 | return *_M_path; | |
1377 | } | |
1378 | ||
1379 | inline bool | |
42eff613 | 1380 | path::iterator::_M_equals(iterator __rhs) const noexcept |
641cb5a6 JW |
1381 | { |
1382 | if (_M_path != __rhs._M_path) | |
1383 | return false; | |
1384 | if (_M_path == nullptr) | |
1385 | return true; | |
42eff613 | 1386 | if (_M_is_multi()) |
641cb5a6 JW |
1387 | return _M_cur == __rhs._M_cur; |
1388 | return _M_at_end == __rhs._M_at_end; | |
1389 | } | |
1390 | ||
1e690757 JW |
1391 | // Define this now that path and path::iterator are complete. |
1392 | // It needs to consider the string_view(Range&&) constructor during | |
1393 | // overload resolution, which depends on whether range<path> is satisfied, | |
1394 | // which depends on whether path::iterator is complete. | |
1395 | inline int | |
1396 | path::_S_compare(const path& __lhs, const path& __rhs) noexcept | |
1397 | { return __lhs.compare(__rhs); } | |
1398 | ||
f0b88346 | 1399 | /// @} group filesystem |
641cb5a6 JW |
1400 | _GLIBCXX_END_NAMESPACE_CXX11 |
1401 | } // namespace filesystem | |
1402 | ||
f2ce64b5 JW |
1403 | /// @cond undocumented |
1404 | ||
9e160526 JW |
1405 | inline ptrdiff_t |
1406 | distance(filesystem::path::iterator __first, filesystem::path::iterator __last) | |
42eff613 | 1407 | noexcept |
9e160526 JW |
1408 | { return __path_iter_distance(__first, __last); } |
1409 | ||
21c76051 | 1410 | template<typename _Distance> |
42eff613 JW |
1411 | inline void |
1412 | advance(filesystem::path::iterator& __i, _Distance __n) noexcept | |
9e160526 JW |
1413 | { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); } |
1414 | ||
24d9b090 JW |
1415 | extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>; |
1416 | ||
f2ce64b5 JW |
1417 | /// @endcond |
1418 | ||
e3c5e836 JW |
1419 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1420 | // 3657. std::hash<std::filesystem::path> is not enabled | |
1421 | template<> | |
1422 | struct hash<filesystem::path> | |
1423 | { | |
1424 | size_t | |
1425 | operator()(const filesystem::path& __p) const noexcept | |
1426 | { return filesystem::hash_value(__p); } | |
1427 | }; | |
1428 | ||
641cb5a6 JW |
1429 | _GLIBCXX_END_NAMESPACE_VERSION |
1430 | } // namespace std | |
1431 | ||
1432 | #endif // C++17 | |
1433 | ||
1434 | #endif // _GLIBCXX_FS_PATH_H |