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