1 | // Class filesystem::path -*- C++ -*- |
2 | |
3 | // Copyright (C) 2014-2022 Free Software Foundation, Inc. |
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 | |
35 | #include <type_traits> |
36 | #include <locale> |
37 | #include <iosfwd> |
38 | #include <iomanip> |
39 | #include <codecvt> |
40 | #include <string_view> |
41 | #include <system_error> |
42 | #include <bits/stl_algobase.h> |
43 | #include <bits/stl_pair.h> |
44 | #include <bits/locale_conv.h> |
45 | #include <ext/concurrence.h> |
46 | #include <bits/shared_ptr.h> |
47 | #include <bits/unique_ptr.h> |
48 | |
49 | #if __cplusplus > 201703L |
50 | # include <compare> |
51 | #endif |
52 | |
53 | #if defined(_WIN32) && !defined(__CYGWIN__) |
54 | # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 |
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 | |
65 | class path; |
66 | |
67 | /// @cond undocumented |
68 | namespace __detail |
69 | { |
70 | /// @addtogroup filesystem |
71 | /// @{ |
72 | template<typename _CharT> |
73 | inline constexpr bool __is_encoded_char = false; |
74 | template<> |
75 | inline constexpr bool __is_encoded_char<char> = true; |
76 | #ifdef _GLIBCXX_USE_CHAR8_T |
77 | template<> |
78 | inline constexpr bool __is_encoded_char<char8_t> = true; |
79 | #endif |
80 | #if _GLIBCXX_USE_WCHAR_T |
81 | template<> |
82 | inline constexpr bool __is_encoded_char<wchar_t> = true; |
83 | #endif |
84 | template<> |
85 | inline constexpr bool __is_encoded_char<char16_t> = true; |
86 | template<> |
87 | inline constexpr bool __is_encoded_char<char32_t> = true; |
88 | |
89 | #if __cpp_concepts >= 201907L |
90 | template<typename _Iter> |
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 | { }; |
96 | |
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 |
103 | |
104 | template<typename _Iter_traits, typename = void> |
105 | struct __is_path_iter_src |
106 | : false_type |
107 | { }; |
108 | |
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>> |
113 | { }; |
114 | |
115 | template<typename _Source> |
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>; |
150 | |
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>; |
154 | |
155 | #if __cpp_lib_concepts |
156 | template<typename _Iter> |
157 | constexpr bool __is_contiguous = std::contiguous_iterator<_Iter>; |
158 | #else |
159 | template<typename _Iter> |
160 | constexpr bool __is_contiguous = false; |
161 | #endif |
162 | |
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 | |
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 | |
180 | // The __effective_range overloads convert a Source parameter into |
181 | // either a basic_string_view<C> or basic_string<C> containing the |
182 | // effective range of the Source, as defined in [fs.path.req]. |
183 | |
184 | template<typename _CharT, typename _Traits, typename _Alloc> |
185 | inline basic_string_view<_CharT> |
186 | __effective_range(const basic_string<_CharT, _Traits, _Alloc>& __source) |
187 | noexcept |
188 | { return __source; } |
189 | |
190 | template<typename _CharT, typename _Traits> |
191 | inline basic_string_view<_CharT> |
192 | __effective_range(const basic_string_view<_CharT, _Traits>& __source) |
193 | noexcept |
194 | { return __source; } |
195 | |
196 | // Return the effective range of an NTCTS. |
197 | template<typename _Source> |
198 | auto |
199 | __effective_range(const _Source& __source) |
200 | { |
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}; |
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. |
211 | basic_string<__unified_u8_t<value_type>> __str; |
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. |
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; |
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>. |
246 | template<typename _Tp, typename _Val = __source_value_t<_Tp>> |
247 | using __value_type_is_char |
248 | = std::enable_if_t<std::is_same_v<_Val, char>, _Val>; |
249 | |
250 | // As above, but also allows char8_t, as required by u8path |
251 | // C++20 [depr.fs.path.factory] |
252 | template<typename _Tp, typename _Val = __source_value_t<_Tp>> |
253 | using __value_type_is_char_or_char8_t |
254 | = std::enable_if_t<std::is_same_v<_Val, char> |
255 | #ifdef _GLIBCXX_USE_CHAR8_T |
256 | || std::is_same_v<_Val, char8_t> |
257 | #endif |
258 | , _Val>; |
259 | |
260 | // Create a basic_string<C> or basic_string_view<C> from an iterator range. |
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; |
267 | static_assert(__is_encoded_char<_EcharT>); // C++17 [fs.req]/3 |
268 | |
269 | if constexpr (__is_contiguous<_InputIterator>) |
270 | { |
271 | // For contiguous iterators we can just return a string view. |
272 | if (auto __len = __last - __first) [[__likely__]] |
273 | return basic_string_view<_EcharT>(&*__first, __len); |
274 | return basic_string_view<_EcharT>(); |
275 | } |
276 | else |
277 | { |
278 | // Conversion requires contiguous characters, so create a string. |
279 | return basic_string<__unified_u8_t<_EcharT>>(__first, __last); |
280 | } |
281 | } |
282 | |
283 | /// @} group filesystem |
284 | } // namespace __detail |
285 | /// @endcond |
286 | |
287 | /// @addtogroup filesystem |
288 | /// @{ |
289 | |
290 | /// A filesystem path |
291 | /// @ingroup filesystem |
292 | class path |
293 | { |
294 | public: |
295 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
296 | using value_type = wchar_t; |
297 | static constexpr value_type preferred_separator = L'\\'; |
298 | #else |
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 = '/'; |
306 | #endif |
307 | using string_type = std::basic_string<value_type>; |
308 | |
309 | /// path::format is ignored in this implementation |
310 | enum format : unsigned char { native_format, generic_format, auto_format }; |
311 | |
312 | // constructors and destructor |
313 | |
314 | path() noexcept { } |
315 | |
316 | path(const path& __p) = default; |
317 | |
318 | path(path&& __p) noexcept |
319 | : _M_pathname(std::move(__p._M_pathname)), |
320 | _M_cmpts(std::move(__p._M_cmpts)) |
321 | { __p.clear(); } |
322 | |
323 | path(string_type&& __source, format = auto_format) |
324 | : _M_pathname(std::move(__source)) |
325 | { _M_split_cmpts(); } |
326 | |
327 | template<typename _Source, |
328 | typename _Require = __detail::_Path<_Source>> |
329 | path(_Source const& __source, format = auto_format) |
330 | : _M_pathname(_S_convert(__detail::__effective_range(__source))) |
331 | { _M_split_cmpts(); } |
332 | |
333 | template<typename _InputIterator, |
334 | typename _Require = __detail::_Path2<_InputIterator>> |
335 | path(_InputIterator __first, _InputIterator __last, format = auto_format) |
336 | : _M_pathname(_S_convert(__detail::__string_from_range(__first, __last))) |
337 | { _M_split_cmpts(); } |
338 | |
339 | template<typename _Source, |
340 | typename _Require = __detail::_Path<_Source>, |
341 | typename _Require2 = __detail::__value_type_is_char<_Source>> |
342 | path(_Source const& __src, const locale& __loc, format = auto_format) |
343 | : _M_pathname(_S_convert_loc(__detail::__effective_range(__src), __loc)) |
344 | { _M_split_cmpts(); } |
345 | |
346 | template<typename _InputIterator, |
347 | typename _Require = __detail::_Path2<_InputIterator>, |
348 | typename _Req2 = __detail::__value_type_is_char<_InputIterator>> |
349 | path(_InputIterator __first, _InputIterator __last, const locale& __loc, |
350 | format = auto_format) |
351 | : _M_pathname(_S_convert_loc(__first, __last, __loc)) |
352 | { _M_split_cmpts(); } |
353 | |
354 | ~path() = default; |
355 | |
356 | // assignments |
357 | |
358 | path& operator=(const path&); |
359 | path& operator=(path&&) noexcept; |
360 | path& operator=(string_type&& __source); |
361 | path& assign(string_type&& __source); |
362 | |
363 | template<typename _Source> |
364 | __detail::_Path<_Source>& |
365 | operator=(_Source const& __source) |
366 | { return *this = path(__source); } |
367 | |
368 | template<typename _Source> |
369 | __detail::_Path<_Source>& |
370 | assign(_Source const& __source) |
371 | { return *this = path(__source); } |
372 | |
373 | template<typename _InputIterator> |
374 | __detail::_Path2<_InputIterator>& |
375 | assign(_InputIterator __first, _InputIterator __last) |
376 | { return *this = path(__first, __last); } |
377 | |
378 | // appends |
379 | |
380 | path& operator/=(const path& __p); |
381 | |
382 | template<typename _Source> |
383 | __detail::_Path<_Source>& |
384 | operator/=(_Source const& __source) |
385 | { |
386 | _M_append(_S_convert(__detail::__effective_range(__source))); |
387 | return *this; |
388 | } |
389 | |
390 | template<typename _Source> |
391 | __detail::_Path<_Source>& |
392 | append(_Source const& __source) |
393 | { |
394 | _M_append(_S_convert(__detail::__effective_range(__source))); |
395 | return *this; |
396 | } |
397 | |
398 | template<typename _InputIterator> |
399 | __detail::_Path2<_InputIterator>& |
400 | append(_InputIterator __first, _InputIterator __last) |
401 | { |
402 | _M_append(_S_convert(__detail::__string_from_range(__first, __last))); |
403 | return *this; |
404 | } |
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> |
415 | __detail::_Path<_Source>& |
416 | operator+=(_Source const& __x) { return concat(__x); } |
417 | |
418 | template<typename _CharT> |
419 | __detail::_Path2<_CharT*>& |
420 | operator+=(_CharT __x); |
421 | |
422 | template<typename _Source> |
423 | __detail::_Path<_Source>& |
424 | concat(_Source const& __x) |
425 | { |
426 | _M_concat(_S_convert(__detail::__effective_range(__x))); |
427 | return *this; |
428 | } |
429 | |
430 | template<typename _InputIterator> |
431 | __detail::_Path2<_InputIterator>& |
432 | concat(_InputIterator __first, _InputIterator __last) |
433 | { |
434 | _M_concat(_S_convert(__detail::__string_from_range(__first, __last))); |
435 | return *this; |
436 | } |
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 |
464 | #ifdef _GLIBCXX_USE_CHAR8_T |
465 | __attribute__((__abi_tag__("__u8" ))) |
466 | std::u8string u8string() const; |
467 | #else |
468 | std::string u8string() const; |
469 | #endif // _GLIBCXX_USE_CHAR8_T |
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 |
483 | #ifdef _GLIBCXX_USE_CHAR8_T |
484 | __attribute__((__abi_tag__("__u8" ))) |
485 | std::u8string generic_u8string() const; |
486 | #else |
487 | std::string generic_u8string() const; |
488 | #endif // _GLIBCXX_USE_CHAR8_T |
489 | std::u16string generic_u16string() const; |
490 | std::u32string generic_u32string() const; |
491 | |
492 | // compare |
493 | |
494 | int compare(const path& __p) const noexcept; |
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; |
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 | |
512 | [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); } |
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(); } |
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; |
531 | using const_iterator = iterator; |
532 | |
533 | iterator begin() const noexcept; |
534 | iterator end() const noexcept; |
535 | |
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 | |
556 | // non-member operators |
557 | |
558 | /// Compare paths |
559 | friend bool operator==(const path& __lhs, const path& __rhs) noexcept |
560 | { return path::_S_compare(__lhs, __rhs) == 0; } |
561 | |
562 | #if __cpp_lib_three_way_comparison |
563 | /// Compare paths |
564 | friend strong_ordering |
565 | operator<=>(const path& __lhs, const path& __rhs) noexcept |
566 | { return path::_S_compare(__lhs, __rhs) <=> 0; } |
567 | #else |
568 | /// Compare paths |
569 | friend bool operator!=(const path& __lhs, const path& __rhs) noexcept |
570 | { return !(__lhs == __rhs); } |
571 | |
572 | /// Compare paths |
573 | friend bool operator<(const path& __lhs, const path& __rhs) noexcept |
574 | { return __lhs.compare(p: __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); } |
587 | #endif |
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 | |
597 | private: |
598 | enum class _Type : unsigned char { |
599 | _Multi = 0, _Root_name, _Root_dir, _Filename |
600 | }; |
601 | |
602 | path(basic_string_view<value_type> __str, _Type __type); |
603 | |
604 | enum class _Split { _Stem, _Extension }; |
605 | |
606 | void _M_append(basic_string_view<value_type>); |
607 | void _M_concat(basic_string_view<value_type>); |
608 | |
609 | pair<const string_type*, size_t> _M_find_extension() const noexcept; |
610 | |
611 | // path::_S_convert creates a basic_string<value_type> or |
612 | // basic_string_view<value_type> from a basic_string<C> or |
613 | // basic_string_view<C>, for an encoded character type C, |
614 | // performing the conversions required by [fs.path.type.cvt]. |
615 | template<typename _Tp> |
616 | static auto |
617 | _S_convert(_Tp __str) |
618 | noexcept(is_same_v<typename _Tp::value_type, value_type>) |
619 | { |
620 | if constexpr (is_same_v<typename _Tp::value_type, value_type>) |
621 | return __str; // No conversion needed. |
622 | #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T |
623 | else if constexpr (is_same_v<_Tp, std::u8string>) |
624 | // Calling _S_convert<char8_t> will return a u8string_view that |
625 | // refers to __str and would dangle after this function returns. |
626 | // Return a string_type instead, to avoid dangling. |
627 | return string_type(_S_convert(__str.data(), |
628 | __str.data() + __str.size())); |
629 | #endif |
630 | else |
631 | return _S_convert(__str.data(), __str.data() + __str.size()); |
632 | } |
633 | |
634 | template<typename _EcharT> |
635 | static auto |
636 | _S_convert(const _EcharT* __first, const _EcharT* __last); |
637 | |
638 | // _S_convert_loc converts a range of char to string_type, using the |
639 | // supplied locale for encoding conversions. |
640 | |
641 | static string_type |
642 | _S_convert_loc(const char* __first, const char* __last, |
643 | const std::locale& __loc); |
644 | |
645 | template<typename _Iter> |
646 | static string_type |
647 | _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) |
648 | { |
649 | const auto __s = __detail::__string_from_range(__first, __last); |
650 | return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); |
651 | } |
652 | |
653 | template<typename _Tp> |
654 | static string_type |
655 | _S_convert_loc(const _Tp& __s, const std::locale& __loc) |
656 | { |
657 | return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); |
658 | } |
659 | |
660 | template<typename _CharT, typename _Traits, typename _Allocator> |
661 | static basic_string<_CharT, _Traits, _Allocator> |
662 | _S_str_convert(basic_string_view<value_type>, const _Allocator&); |
663 | |
664 | // Returns lhs.compare(rhs), but defined after path::iterator is complete. |
665 | __attribute__((__always_inline__)) |
666 | static int |
667 | _S_compare(const path& __lhs, const path& __rhs) noexcept; |
668 | |
669 | void _M_split_cmpts(); |
670 | |
671 | _Type _M_type() const noexcept { return _M_cmpts.type(); } |
672 | |
673 | string_type _M_pathname; |
674 | |
675 | struct _Cmpt; |
676 | |
677 | struct _List |
678 | { |
679 | using value_type = _Cmpt; |
680 | using iterator = value_type*; |
681 | using const_iterator = const value_type*; |
682 | |
683 | _List(); |
684 | _List(const _List&); |
685 | _List(_List&&) = default; |
686 | _List& operator=(const _List&); |
687 | _List& operator=(_List&&) = default; |
688 | ~_List() = default; |
689 | |
690 | _Type type() const noexcept |
691 | { return _Type(reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3); } |
692 | |
693 | void type(_Type) noexcept; |
694 | |
695 | int size() const noexcept; // zero unless type() == _Type::_Multi |
696 | bool empty() const noexcept; // true unless type() == _Type::_Multi |
697 | void clear(); |
698 | void swap(_List& __l) noexcept { _M_impl.swap(u&: __l._M_impl); } |
699 | int capacity() const noexcept; |
700 | void reserve(int, bool); ///< @pre type() == _Type::_Multi |
701 | |
702 | // All the member functions below here have a precondition !empty() |
703 | // (and they should only be called from within the library). |
704 | |
705 | iterator begin() noexcept; |
706 | iterator end() noexcept; |
707 | const_iterator begin() const noexcept; |
708 | const_iterator end() const noexcept; |
709 | |
710 | value_type& front() noexcept; |
711 | value_type& back() noexcept; |
712 | const value_type& front() const noexcept; |
713 | const value_type& back() const noexcept; |
714 | |
715 | void pop_back(); |
716 | void _M_erase_from(const_iterator __pos); // erases [__pos,end()) |
717 | |
718 | struct _Impl; |
719 | struct _Impl_deleter |
720 | { |
721 | void operator()(_Impl*) const noexcept; |
722 | }; |
723 | unique_ptr<_Impl, _Impl_deleter> _M_impl; |
724 | }; |
725 | _List _M_cmpts; |
726 | |
727 | struct _Parser; |
728 | |
729 | template<typename _EcharT> struct _Codecvt; |
730 | }; |
731 | |
732 | /// @{ |
733 | /// @relates std::filesystem::path |
734 | |
735 | #if __cpp_concepts >= 201907L |
736 | // Workaround for PR libstdc++/106201 |
737 | inline void |
738 | swap(same_as<path> auto& __lhs, same_as<path> auto& __rhs) noexcept |
739 | { __lhs.swap(__rhs); } |
740 | #else |
741 | inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } |
742 | #endif |
743 | |
744 | size_t hash_value(const path& __p) noexcept; |
745 | |
746 | /// @} |
747 | |
748 | /// Exception type thrown by the Filesystem library |
749 | class filesystem_error : public std::system_error |
750 | { |
751 | public: |
752 | filesystem_error(const string& __what_arg, error_code __ec); |
753 | |
754 | filesystem_error(const string& __what_arg, const path& __p1, |
755 | error_code __ec); |
756 | |
757 | filesystem_error(const string& __what_arg, const path& __p1, |
758 | const path& __p2, error_code __ec); |
759 | |
760 | filesystem_error(const filesystem_error&) = default; |
761 | filesystem_error& operator=(const filesystem_error&) = default; |
762 | |
763 | // No move constructor or assignment operator. |
764 | // Copy rvalues instead, so that _M_impl is not left empty. |
765 | |
766 | ~filesystem_error(); |
767 | |
768 | const path& path1() const noexcept; |
769 | const path& path2() const noexcept; |
770 | const char* what() const noexcept; |
771 | |
772 | private: |
773 | struct _Impl; |
774 | std::__shared_ptr<const _Impl> _M_impl; |
775 | }; |
776 | |
777 | /// @cond undocumented |
778 | namespace __detail |
779 | { |
780 | [[noreturn]] inline void |
781 | __throw_conversion_error() |
782 | { |
783 | _GLIBCXX_THROW_OR_ABORT(filesystem_error( |
784 | "Cannot convert character sequence" , |
785 | std::make_error_code(errc::illegal_byte_sequence))); |
786 | } |
787 | |
788 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
789 | template<typename _Tp> |
790 | inline std::wstring |
791 | __wstr_from_utf8(const _Tp& __str) |
792 | { |
793 | static_assert(std::is_same_v<typename _Tp::value_type, char>); |
794 | std::wstring __wstr; |
795 | // XXX This assumes native wide encoding is UTF-16. |
796 | std::codecvt_utf8_utf16<wchar_t> __wcvt; |
797 | const auto __p = __str.data(); |
798 | if (!__str_codecvt_in_all(__p, __p + __str.size(), __wstr, __wcvt)) |
799 | __detail::__throw_conversion_error(); |
800 | return __wstr; |
801 | } |
802 | #endif |
803 | |
804 | } // namespace __detail |
805 | /// @endcond |
806 | |
807 | |
808 | /** Create a path from a UTF-8-encoded sequence of char |
809 | * |
810 | * @relates std::filesystem::path |
811 | */ |
812 | template<typename _InputIterator, |
813 | typename _Require = __detail::_Path2<_InputIterator>, |
814 | typename _CharT |
815 | = __detail::__value_type_is_char_or_char8_t<_InputIterator>> |
816 | inline path |
817 | u8path(_InputIterator __first, _InputIterator __last) |
818 | { |
819 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
820 | if constexpr (is_same_v<_CharT, char>) |
821 | return path{ __detail::__wstr_from_utf8( |
822 | __detail::__string_from_range(__first, __last)) }; |
823 | else |
824 | return path{ __first, __last }; // constructor handles char8_t |
825 | #else |
826 | // This assumes native normal encoding is UTF-8. |
827 | return path{ __first, __last }; |
828 | #endif |
829 | } |
830 | |
831 | /** Create a path from a UTF-8-encoded sequence of char |
832 | * |
833 | * @relates std::filesystem::path |
834 | */ |
835 | template<typename _Source, |
836 | typename _Require = __detail::_Path<_Source>, |
837 | typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>> |
838 | inline path |
839 | u8path(const _Source& __source) |
840 | { |
841 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
842 | if constexpr (is_same_v<_CharT, char>) |
843 | return path{ __detail::__wstr_from_utf8( |
844 | __detail::__effective_range(__source)) }; |
845 | else |
846 | return path{ __source }; // constructor handles char8_t |
847 | #else |
848 | // This assumes native normal encoding is UTF-8. |
849 | return path{ __source }; |
850 | #endif |
851 | } |
852 | |
853 | /// @cond undocumented |
854 | |
855 | struct path::_Cmpt : path |
856 | { |
857 | _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos); |
858 | |
859 | _Cmpt() : _M_pos(-1) { } |
860 | |
861 | size_t _M_pos; |
862 | }; |
863 | |
864 | // path::_Codecvt<C> Performs conversions between C and path::string_type. |
865 | // The native encoding of char strings is the OS-dependent current |
866 | // encoding for pathnames. FIXME: We assume this is UTF-8 everywhere, |
867 | // but should use a Windows API to query it. |
868 | |
869 | // Converts between native pathname encoding and char16_t or char32_t. |
870 | template<typename _EcharT> |
871 | struct path::_Codecvt |
872 | // Need derived class here because std::codecvt has protected destructor. |
873 | : std::codecvt<_EcharT, char, mbstate_t> |
874 | { }; |
875 | |
876 | // Converts between native pathname encoding and native wide encoding. |
877 | // The native encoding for wide strings is the execution wide-character |
878 | // set encoding. FIXME: We assume that this is either UTF-32 or UTF-16 |
879 | // (depending on the width of wchar_t). That matches GCC's default, |
880 | // but can be changed with -fwide-exec-charset. |
881 | // We need a custom codecvt converting the native pathname encoding |
882 | // to/from the native wide encoding. |
883 | template<> |
884 | struct path::_Codecvt<wchar_t> |
885 | : __conditional_t<sizeof(wchar_t) == sizeof(char32_t), |
886 | std::codecvt_utf8<wchar_t>, // UTF-8 <-> UTF-32 |
887 | std::codecvt_utf8_utf16<wchar_t>> // UTF-8 <-> UTF-16 |
888 | { }; |
889 | |
890 | template<typename _EcharT> |
891 | auto |
892 | path::_S_convert(const _EcharT* __f, const _EcharT* __l) |
893 | { |
894 | static_assert(__detail::__is_encoded_char<_EcharT>); |
895 | |
896 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
897 | # define _GLIBCXX_CONV_FROM_UTF8(S) __detail::__wstr_from_utf8(S) |
898 | #else |
899 | # define _GLIBCXX_CONV_FROM_UTF8(S) S |
900 | #endif |
901 | |
902 | if constexpr (is_same_v<_EcharT, value_type>) |
903 | return basic_string_view<value_type>(__f, __l - __f); |
904 | #ifdef _GLIBCXX_USE_CHAR8_T |
905 | else if constexpr (is_same_v<_EcharT, char8_t>) |
906 | { |
907 | string_view __str(reinterpret_cast<const char*>(__f), __l - __f); |
908 | return _GLIBCXX_CONV_FROM_UTF8(__str); |
909 | } |
910 | #endif |
911 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
912 | else if constexpr (is_same_v<_EcharT, char>) |
913 | { |
914 | std::wstring __wstr; |
915 | path::_Codecvt<wchar_t> __cvt; |
916 | if (__str_codecvt_in_all(__f, __l, __wstr, __cvt)) |
917 | return __wstr; |
918 | } |
919 | #endif |
920 | else |
921 | { |
922 | path::_Codecvt<_EcharT> __cvt; |
923 | std::string __str; |
924 | if (__str_codecvt_out_all(__f, __l, __str, __cvt)) |
925 | return _GLIBCXX_CONV_FROM_UTF8(__str); |
926 | } |
927 | __detail::__throw_conversion_error(); |
928 | } |
929 | #undef _GLIBCXX_CONV_FROM_UTF8 |
930 | |
931 | /// @endcond |
932 | |
933 | /// An iterator for the components of a path |
934 | class path::iterator |
935 | { |
936 | public: |
937 | using difference_type = std::ptrdiff_t; |
938 | using value_type = path; |
939 | using reference = const path&; |
940 | using pointer = const path*; |
941 | using iterator_category = std::bidirectional_iterator_tag; |
942 | |
943 | iterator() noexcept : _M_path(nullptr), _M_cur(), _M_at_end() { } |
944 | |
945 | iterator(const iterator&) = default; |
946 | iterator& operator=(const iterator&) = default; |
947 | |
948 | reference operator*() const noexcept; |
949 | pointer operator->() const noexcept { return std::__addressof(r: **this); } |
950 | |
951 | iterator& operator++() noexcept; |
952 | |
953 | iterator operator++(int) noexcept |
954 | { auto __tmp = *this; ++*this; return __tmp; } |
955 | |
956 | iterator& operator--() noexcept; |
957 | |
958 | iterator operator--(int) noexcept |
959 | { auto __tmp = *this; --*this; return __tmp; } |
960 | |
961 | friend bool |
962 | operator==(const iterator& __lhs, const iterator& __rhs) noexcept |
963 | { return __lhs._M_equals(__rhs); } |
964 | |
965 | friend bool |
966 | operator!=(const iterator& __lhs, const iterator& __rhs) noexcept |
967 | { return !__lhs._M_equals(__rhs); } |
968 | |
969 | private: |
970 | friend class path; |
971 | |
972 | bool |
973 | _M_is_multi() const noexcept |
974 | { return _M_path->_M_type() == _Type::_Multi; } |
975 | |
976 | friend difference_type |
977 | __path_iter_distance(const iterator& __first, const iterator& __last) |
978 | noexcept |
979 | { |
980 | __glibcxx_assert(__first._M_path != nullptr); |
981 | __glibcxx_assert(__first._M_path == __last._M_path); |
982 | if (__first._M_is_multi()) |
983 | return std::distance(first: __first._M_cur, last: __last._M_cur); |
984 | else if (__first._M_at_end == __last._M_at_end) |
985 | return 0; |
986 | else |
987 | return __first._M_at_end ? -1 : 1; |
988 | } |
989 | |
990 | friend void |
991 | __path_iter_advance(iterator& __i, difference_type __n) noexcept |
992 | { |
993 | if (__n == 1) |
994 | ++__i; |
995 | else if (__n == -1) |
996 | --__i; |
997 | else if (__n != 0) |
998 | { |
999 | __glibcxx_assert(__i._M_path != nullptr); |
1000 | __glibcxx_assert(__i._M_is_multi()); |
1001 | // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n); |
1002 | __i._M_cur += __n; |
1003 | } |
1004 | } |
1005 | |
1006 | iterator(const path* __path, path::_List::const_iterator __iter) noexcept |
1007 | : _M_path(__path), _M_cur(__iter), _M_at_end() |
1008 | { } |
1009 | |
1010 | iterator(const path* __path, bool __at_end) noexcept |
1011 | : _M_path(__path), _M_cur(), _M_at_end(__at_end) |
1012 | { } |
1013 | |
1014 | bool _M_equals(iterator) const noexcept; |
1015 | |
1016 | const path* _M_path; |
1017 | path::_List::const_iterator _M_cur; |
1018 | bool _M_at_end; // only used when type != _Multi |
1019 | }; |
1020 | |
1021 | |
1022 | inline path& |
1023 | path::operator=(path&& __p) noexcept |
1024 | { |
1025 | if (&__p == this) [[__unlikely__]] |
1026 | return *this; |
1027 | |
1028 | _M_pathname = std::move(__p._M_pathname); |
1029 | _M_cmpts = std::move(__p._M_cmpts); |
1030 | __p.clear(); |
1031 | return *this; |
1032 | } |
1033 | |
1034 | inline path& |
1035 | path::operator=(string_type&& __source) |
1036 | { return *this = path(std::move(__source)); } |
1037 | |
1038 | inline path& |
1039 | path::assign(string_type&& __source) |
1040 | { return *this = path(std::move(__source)); } |
1041 | |
1042 | inline path& |
1043 | path::operator+=(const string_type& __x) |
1044 | { |
1045 | _M_concat(__x); |
1046 | return *this; |
1047 | } |
1048 | |
1049 | inline path& |
1050 | path::operator+=(const value_type* __x) |
1051 | { |
1052 | _M_concat(__x); |
1053 | return *this; |
1054 | } |
1055 | |
1056 | inline path& |
1057 | path::operator+=(value_type __x) |
1058 | { |
1059 | _M_concat(basic_string_view<value_type>(&__x, 1)); |
1060 | return *this; |
1061 | } |
1062 | |
1063 | inline path& |
1064 | path::operator+=(basic_string_view<value_type> __x) |
1065 | { |
1066 | _M_concat(__x); |
1067 | return *this; |
1068 | } |
1069 | |
1070 | template<typename _CharT> |
1071 | inline __detail::_Path2<_CharT*>& |
1072 | path::operator+=(const _CharT __x) |
1073 | { |
1074 | _M_concat(_S_convert(&__x, &__x + 1)); |
1075 | return *this; |
1076 | } |
1077 | |
1078 | inline path& |
1079 | path::make_preferred() |
1080 | { |
1081 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1082 | auto __pos = _M_pathname.find(L'/'); |
1083 | while (__pos != _M_pathname.npos) |
1084 | { |
1085 | _M_pathname[__pos] = preferred_separator; |
1086 | __pos = _M_pathname.find(L'/', __pos); |
1087 | } |
1088 | #endif |
1089 | return *this; |
1090 | } |
1091 | |
1092 | inline void path::swap(path& __rhs) noexcept |
1093 | { |
1094 | _M_pathname.swap(s&: __rhs._M_pathname); |
1095 | _M_cmpts.swap(l&: __rhs._M_cmpts); |
1096 | } |
1097 | |
1098 | /// @cond undocumented |
1099 | template<typename _CharT, typename _Traits, typename _Allocator> |
1100 | std::basic_string<_CharT, _Traits, _Allocator> |
1101 | path::_S_str_convert(basic_string_view<value_type> __str, |
1102 | const _Allocator& __a) |
1103 | { |
1104 | static_assert(!is_same_v<_CharT, value_type>); |
1105 | |
1106 | using _WString = basic_string<_CharT, _Traits, _Allocator>; |
1107 | |
1108 | if (__str.size() == 0) |
1109 | return _WString(__a); |
1110 | |
1111 | #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1112 | string_view __u8str = __str; |
1113 | #else |
1114 | // First convert native string from UTF-16 to to UTF-8. |
1115 | // XXX This assumes that the execution wide-character set is UTF-16. |
1116 | std::codecvt_utf8_utf16<value_type> __cvt; |
1117 | |
1118 | using _CharAlloc = __alloc_rebind<_Allocator, char>; |
1119 | using _String = basic_string<char, char_traits<char>, _CharAlloc>; |
1120 | _String __u8str{_CharAlloc{__a}}; |
1121 | const value_type* __wfirst = __str.data(); |
1122 | const value_type* __wlast = __wfirst + __str.size(); |
1123 | if (!__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) |
1124 | __detail::__throw_conversion_error(); |
1125 | if constexpr (is_same_v<_CharT, char>) |
1126 | return __u8str; // XXX assumes native ordinary encoding is UTF-8. |
1127 | else |
1128 | #endif |
1129 | { |
1130 | const char* __first = __u8str.data(); |
1131 | const char* __last = __first + __u8str.size(); |
1132 | |
1133 | // Convert UTF-8 string to requested format. |
1134 | #ifdef _GLIBCXX_USE_CHAR8_T |
1135 | if constexpr (is_same_v<_CharT, char8_t>) |
1136 | return _WString(__first, __last, __a); |
1137 | else |
1138 | #endif |
1139 | { |
1140 | // Convert UTF-8 to wide string. |
1141 | _WString __wstr(__a); |
1142 | path::_Codecvt<_CharT> __cvt; |
1143 | if (__str_codecvt_in_all(__first, __last, __wstr, __cvt)) |
1144 | return __wstr; |
1145 | } |
1146 | } |
1147 | __detail::__throw_conversion_error(); |
1148 | } |
1149 | /// @endcond |
1150 | |
1151 | template<typename _CharT, typename _Traits, typename _Allocator> |
1152 | inline basic_string<_CharT, _Traits, _Allocator> |
1153 | path::string(const _Allocator& __a) const |
1154 | { |
1155 | if constexpr (is_same_v<_CharT, value_type>) |
1156 | return { _M_pathname.c_str(), _M_pathname.length(), __a }; |
1157 | else |
1158 | return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); |
1159 | } |
1160 | |
1161 | inline std::string |
1162 | path::string() const { return string<char>(); } |
1163 | |
1164 | #if _GLIBCXX_USE_WCHAR_T |
1165 | inline std::wstring |
1166 | path::wstring() const { return string<wchar_t>(); } |
1167 | #endif |
1168 | |
1169 | #ifdef _GLIBCXX_USE_CHAR8_T |
1170 | inline std::u8string |
1171 | path::u8string() const { return string<char8_t>(); } |
1172 | #else |
1173 | inline std::string |
1174 | path::u8string() const |
1175 | { |
1176 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1177 | std::string __str; |
1178 | // convert from native wide encoding (assumed to be UTF-16) to UTF-8 |
1179 | std::codecvt_utf8_utf16<value_type> __cvt; |
1180 | const value_type* __first = _M_pathname.data(); |
1181 | const value_type* __last = __first + _M_pathname.size(); |
1182 | if (__str_codecvt_out_all(__first, __last, __str, __cvt)) |
1183 | return __str; |
1184 | __detail::__throw_conversion_error(); |
1185 | #else |
1186 | return _M_pathname; |
1187 | #endif |
1188 | } |
1189 | #endif // _GLIBCXX_USE_CHAR8_T |
1190 | |
1191 | inline std::u16string |
1192 | path::u16string() const { return string<char16_t>(); } |
1193 | |
1194 | inline std::u32string |
1195 | path::u32string() const { return string<char32_t>(); } |
1196 | |
1197 | template<typename _CharT, typename _Traits, typename _Allocator> |
1198 | inline std::basic_string<_CharT, _Traits, _Allocator> |
1199 | path::generic_string(const _Allocator& __a) const |
1200 | { |
1201 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1202 | const value_type __slash = L'/'; |
1203 | #else |
1204 | const value_type __slash = '/'; |
1205 | #endif |
1206 | using _Alloc2 = typename allocator_traits<_Allocator>::template |
1207 | rebind_alloc<value_type>; |
1208 | basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a); |
1209 | |
1210 | if (_M_type() == _Type::_Root_dir) |
1211 | __str.assign(1, __slash); |
1212 | else |
1213 | { |
1214 | __str.reserve(_M_pathname.size()); |
1215 | bool __add_slash = false; |
1216 | for (auto& __elem : *this) |
1217 | { |
1218 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1219 | if (__elem._M_type() == _Type::_Root_dir) |
1220 | { |
1221 | __str += __slash; |
1222 | continue; |
1223 | } |
1224 | #endif |
1225 | if (__add_slash) |
1226 | __str += __slash; |
1227 | __str += basic_string_view<value_type>(__elem._M_pathname); |
1228 | __add_slash = __elem._M_type() == _Type::_Filename; |
1229 | } |
1230 | } |
1231 | |
1232 | if constexpr (is_same_v<_CharT, value_type>) |
1233 | return __str; |
1234 | else |
1235 | return _S_str_convert<_CharT, _Traits>(__str, __a); |
1236 | } |
1237 | |
1238 | inline std::string |
1239 | path::generic_string() const |
1240 | { return generic_string<char>(); } |
1241 | |
1242 | #if _GLIBCXX_USE_WCHAR_T |
1243 | inline std::wstring |
1244 | path::generic_wstring() const |
1245 | { return generic_string<wchar_t>(); } |
1246 | #endif |
1247 | |
1248 | #ifdef _GLIBCXX_USE_CHAR8_T |
1249 | inline std::u8string |
1250 | path::generic_u8string() const |
1251 | { return generic_string<char8_t>(); } |
1252 | #else |
1253 | inline std::string |
1254 | path::generic_u8string() const |
1255 | { return generic_string(); } |
1256 | #endif |
1257 | |
1258 | inline std::u16string |
1259 | path::generic_u16string() const |
1260 | { return generic_string<char16_t>(); } |
1261 | |
1262 | inline std::u32string |
1263 | path::generic_u32string() const |
1264 | { return generic_string<char32_t>(); } |
1265 | |
1266 | inline int |
1267 | path::compare(const string_type& __s) const noexcept |
1268 | { return compare(s: basic_string_view<value_type>(__s)); } |
1269 | |
1270 | inline int |
1271 | path::compare(const value_type* __s) const noexcept |
1272 | { return compare(s: basic_string_view<value_type>(__s)); } |
1273 | |
1274 | inline path |
1275 | path::filename() const |
1276 | { |
1277 | if (empty()) |
1278 | return {}; |
1279 | else if (_M_type() == _Type::_Filename) |
1280 | return *this; |
1281 | else if (_M_type() == _Type::_Multi) |
1282 | { |
1283 | if (_M_pathname.back() == preferred_separator) |
1284 | return {}; |
1285 | auto __last = --end(); |
1286 | if (__last->_M_type() == _Type::_Filename) |
1287 | return *__last; |
1288 | } |
1289 | return {}; |
1290 | } |
1291 | |
1292 | inline path |
1293 | path::stem() const |
1294 | { |
1295 | auto ext = _M_find_extension(); |
1296 | if (ext.first && ext.second != 0) |
1297 | return path{ext.first->substr(pos: 0, n: ext.second)}; |
1298 | return {}; |
1299 | } |
1300 | |
1301 | inline path |
1302 | path::extension() const |
1303 | { |
1304 | auto ext = _M_find_extension(); |
1305 | if (ext.first && ext.second != string_type::npos) |
1306 | return path{ext.first->substr(pos: ext.second)}; |
1307 | return {}; |
1308 | } |
1309 | |
1310 | inline bool |
1311 | path::has_stem() const noexcept |
1312 | { |
1313 | auto ext = _M_find_extension(); |
1314 | return ext.first && ext.second != 0; |
1315 | } |
1316 | |
1317 | inline bool |
1318 | path::has_extension() const noexcept |
1319 | { |
1320 | auto ext = _M_find_extension(); |
1321 | return ext.first && ext.second != string_type::npos; |
1322 | } |
1323 | |
1324 | inline bool |
1325 | path::is_absolute() const noexcept |
1326 | { |
1327 | #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS |
1328 | return has_root_name() && has_root_directory(); |
1329 | #else |
1330 | return has_root_directory(); |
1331 | #endif |
1332 | } |
1333 | |
1334 | inline path::iterator |
1335 | path::begin() const noexcept |
1336 | { |
1337 | if (_M_type() == _Type::_Multi) |
1338 | return iterator(this, _M_cmpts.begin()); |
1339 | return iterator(this, empty()); |
1340 | } |
1341 | |
1342 | inline path::iterator |
1343 | path::end() const noexcept |
1344 | { |
1345 | if (_M_type() == _Type::_Multi) |
1346 | return iterator(this, _M_cmpts.end()); |
1347 | return iterator(this, true); |
1348 | } |
1349 | |
1350 | inline path::iterator& |
1351 | path::iterator::operator++() noexcept |
1352 | { |
1353 | __glibcxx_assert(_M_path != nullptr); |
1354 | if (_M_is_multi()) |
1355 | { |
1356 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); |
1357 | ++_M_cur; |
1358 | } |
1359 | else |
1360 | { |
1361 | __glibcxx_assert(!_M_at_end); |
1362 | _M_at_end = true; |
1363 | } |
1364 | return *this; |
1365 | } |
1366 | |
1367 | inline path::iterator& |
1368 | path::iterator::operator--() noexcept |
1369 | { |
1370 | __glibcxx_assert(_M_path != nullptr); |
1371 | if (_M_is_multi()) |
1372 | { |
1373 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); |
1374 | --_M_cur; |
1375 | } |
1376 | else |
1377 | { |
1378 | __glibcxx_assert(_M_at_end); |
1379 | _M_at_end = false; |
1380 | } |
1381 | return *this; |
1382 | } |
1383 | |
1384 | inline path::iterator::reference |
1385 | path::iterator::operator*() const noexcept |
1386 | { |
1387 | __glibcxx_assert(_M_path != nullptr); |
1388 | if (_M_is_multi()) |
1389 | { |
1390 | __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); |
1391 | return *_M_cur; |
1392 | } |
1393 | return *_M_path; |
1394 | } |
1395 | |
1396 | inline bool |
1397 | path::iterator::_M_equals(iterator __rhs) const noexcept |
1398 | { |
1399 | if (_M_path != __rhs._M_path) |
1400 | return false; |
1401 | if (_M_path == nullptr) |
1402 | return true; |
1403 | if (_M_is_multi()) |
1404 | return _M_cur == __rhs._M_cur; |
1405 | return _M_at_end == __rhs._M_at_end; |
1406 | } |
1407 | |
1408 | // Define this now that path and path::iterator are complete. |
1409 | // It needs to consider the string_view(Range&&) constructor during |
1410 | // overload resolution, which depends on whether range<path> is satisfied, |
1411 | // which depends on whether path::iterator is complete. |
1412 | inline int |
1413 | path::_S_compare(const path& __lhs, const path& __rhs) noexcept |
1414 | { return __lhs.compare(p: __rhs); } |
1415 | |
1416 | /// @} group filesystem |
1417 | _GLIBCXX_END_NAMESPACE_CXX11 |
1418 | } // namespace filesystem |
1419 | |
1420 | /// @cond undocumented |
1421 | |
1422 | inline ptrdiff_t |
1423 | distance(filesystem::path::iterator __first, filesystem::path::iterator __last) |
1424 | noexcept |
1425 | { return __path_iter_distance(__first, __last); } |
1426 | |
1427 | template<typename _Distance> |
1428 | inline void |
1429 | advance(filesystem::path::iterator& __i, _Distance __n) noexcept |
1430 | { __path_iter_advance(__i, n: static_cast<ptrdiff_t>(__n)); } |
1431 | |
1432 | extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>; |
1433 | |
1434 | /// @endcond |
1435 | |
1436 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
1437 | // 3657. std::hash<std::filesystem::path> is not enabled |
1438 | template<> |
1439 | struct hash<filesystem::path> |
1440 | { |
1441 | size_t |
1442 | operator()(const filesystem::path& __p) const noexcept |
1443 | { return filesystem::hash_value(__p); } |
1444 | }; |
1445 | |
1446 | _GLIBCXX_END_NAMESPACE_VERSION |
1447 | } // namespace std |
1448 | |
1449 | #endif // C++17 |
1450 | |
1451 | #endif // _GLIBCXX_FS_PATH_H |
1452 | |