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