xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/bits/fs_path.h (revision 4ac76180e904e771b9d522c7e57296d371f06499)
1 // Class filesystem::path -*- C++ -*-
2 
3 // Copyright (C) 2014-2020 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 <utility>
36 #include <type_traits>
37 #include <locale>
38 #include <iosfwd>
39 #include <iomanip>
40 #include <codecvt>
41 #include <string_view>
42 #include <system_error>
43 #include <bits/stl_algobase.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 # include <algorithm>
56 #endif
57 
_GLIBCXX_VISIBILITY(default)58 namespace std _GLIBCXX_VISIBILITY(default)
59 {
60 _GLIBCXX_BEGIN_NAMESPACE_VERSION
61 
62 namespace filesystem
63 {
64 _GLIBCXX_BEGIN_NAMESPACE_CXX11
65 
66   /** @addtogroup filesystem
67    *  @{
68    */
69 
70   class path;
71 
72   /// @cond undocumented
73 namespace __detail
74 {
75   template<typename _CharT>
76     using __is_encoded_char = __is_one_of<remove_const_t<_CharT>,
77 	  char,
78 #ifdef _GLIBCXX_USE_CHAR8_T
79 	  char8_t,
80 #endif
81 #if _GLIBCXX_USE_WCHAR_T
82 	  wchar_t,
83 #endif
84 	  char16_t, char32_t>;
85 
86   template<typename _Iter,
87 	   typename _Iter_traits = std::iterator_traits<_Iter>>
88     using __is_path_iter_src
89       = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
90 	       std::is_base_of<std::input_iterator_tag,
91 			       typename _Iter_traits::iterator_category>>;
92 
93   template<typename _Iter>
94     static __is_path_iter_src<_Iter>
95     __is_path_src(_Iter, int);
96 
97   template<typename _CharT, typename _Traits, typename _Alloc>
98     static __is_encoded_char<_CharT>
99     __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
100 
101   template<typename _CharT, typename _Traits>
102     static __is_encoded_char<_CharT>
103     __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
104 
105   template<typename _Unknown>
106     static std::false_type
107     __is_path_src(const _Unknown&, ...);
108 
109   template<typename _Tp1, typename _Tp2>
110     struct __constructible_from;
111 
112   template<typename _Iter>
113     struct __constructible_from<_Iter, _Iter>
114     : __is_path_iter_src<_Iter>
115     { };
116 
117   template<typename _Source>
118     struct __constructible_from<_Source, void>
119     : decltype(__is_path_src(std::declval<const _Source&>(), 0))
120     { };
121 
122   template<typename _Tp1, typename _Tp2 = void>
123     using _Path = typename
124       std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
125 			    __not_<is_void<remove_pointer_t<_Tp1>>>,
126 			    __constructible_from<_Tp1, _Tp2>>::value,
127 		     path>::type;
128 
129   template<typename _Source>
130     _Source
131     _S_range_begin(_Source __begin) { return __begin; }
132 
133   struct __nul_terminated { };
134 
135   template<typename _Source>
136     __nul_terminated
137     _S_range_end(_Source) { return {}; }
138 
139   template<typename _CharT, typename _Traits, typename _Alloc>
140     inline const _CharT*
141     _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
142     { return __str.data(); }
143 
144   template<typename _CharT, typename _Traits, typename _Alloc>
145     inline const _CharT*
146     _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
147     { return __str.data() + __str.size(); }
148 
149   template<typename _CharT, typename _Traits>
150     inline const _CharT*
151     _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
152     { return __str.data(); }
153 
154   template<typename _CharT, typename _Traits>
155     inline const _CharT*
156     _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
157     { return __str.data() + __str.size(); }
158 
159   template<typename _Tp,
160 	   typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
161 	   typename _Val = typename std::iterator_traits<_Iter>::value_type,
162 	   typename _UnqualVal = std::remove_const_t<_Val>>
163     using __value_type_is_char
164       = std::enable_if_t<std::is_same_v<_UnqualVal, char>,
165 			 _UnqualVal>;
166 
167   template<typename _Tp,
168 	   typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
169 	   typename _Val = typename std::iterator_traits<_Iter>::value_type,
170 	   typename _UnqualVal = std::remove_const_t<_Val>>
171     using __value_type_is_char_or_char8_t
172       = std::enable_if_t<__or_v<
173 			   std::is_same<_UnqualVal, char>
174 #ifdef _GLIBCXX_USE_CHAR8_T
175 			   , std::is_same<_UnqualVal, char8_t>
176 #endif
177 			   >,
178 			 _UnqualVal>;
179 
180 } // namespace __detail
181   /// @endcond
182 
183   /// A filesystem path.
184   class path
185   {
186   public:
187 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
188     using value_type = wchar_t;
189     static constexpr value_type preferred_separator = L'\\';
190 #else
191 # ifdef _GLIBCXX_DOXYGEN
192     /// Windows uses wchar_t for path::value_type, POSIX uses char.
193     using value_type = __os_dependent__;
194 # else
195     using value_type =  char;
196 # endif
197     static constexpr value_type preferred_separator = '/';
198 #endif
199     using string_type = std::basic_string<value_type>;
200 
201     /// path::format is ignored in this implementation
202     enum format : unsigned char { native_format, generic_format, auto_format };
203 
204     // constructors and destructor
205 
206     path() noexcept { }
207 
208     path(const path& __p) = default;
209 
210     path(path&& __p)
211 #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_FULLY_DYNAMIC_STRING == 0
212       noexcept
213 #endif
214     : _M_pathname(std::move(__p._M_pathname)),
215       _M_cmpts(std::move(__p._M_cmpts))
216     { __p.clear(); }
217 
218     path(string_type&& __source, format = auto_format)
219     : _M_pathname(std::move(__source))
220     { _M_split_cmpts(); }
221 
222     template<typename _Source,
223 	     typename _Require = __detail::_Path<_Source>>
224       path(_Source const& __source, format = auto_format)
225       : _M_pathname(_S_convert(__detail::_S_range_begin(__source),
226 			       __detail::_S_range_end(__source)))
227       { _M_split_cmpts(); }
228 
229     template<typename _InputIterator,
230 	     typename _Require = __detail::_Path<_InputIterator, _InputIterator>>
231       path(_InputIterator __first, _InputIterator __last, format = auto_format)
232       : _M_pathname(_S_convert(__first, __last))
233       { _M_split_cmpts(); }
234 
235     template<typename _Source,
236 	     typename _Require = __detail::_Path<_Source>,
237 	     typename _Require2 = __detail::__value_type_is_char<_Source>>
238       path(_Source const& __source, const locale& __loc, format = auto_format)
239       : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source),
240 				   __detail::_S_range_end(__source), __loc))
241       { _M_split_cmpts(); }
242 
243     template<typename _InputIterator,
244 	     typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
245 	     typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
246       path(_InputIterator __first, _InputIterator __last, const locale& __loc,
247 	   format = auto_format)
248       : _M_pathname(_S_convert_loc(__first, __last, __loc))
249       { _M_split_cmpts(); }
250 
251     ~path() = default;
252 
253     // assignments
254 
255     path& operator=(const path&);
256     path& operator=(path&&) noexcept;
257     path& operator=(string_type&& __source);
258     path& assign(string_type&& __source);
259 
260     template<typename _Source>
261       __detail::_Path<_Source>&
262       operator=(_Source const& __source)
263       { return *this = path(__source); }
264 
265     template<typename _Source>
266       __detail::_Path<_Source>&
267       assign(_Source const& __source)
268       { return *this = path(__source); }
269 
270     template<typename _InputIterator>
271       __detail::_Path<_InputIterator, _InputIterator>&
272       assign(_InputIterator __first, _InputIterator __last)
273       { return *this = path(__first, __last); }
274 
275     // appends
276 
277     path& operator/=(const path& __p);
278 
279     template<typename _Source>
280       __detail::_Path<_Source>&
281       operator/=(_Source const& __source)
282       {
283 	_M_append(_S_convert(__detail::_S_range_begin(__source),
284 			     __detail::_S_range_end(__source)));
285 	return *this;
286       }
287 
288     template<typename _Source>
289       __detail::_Path<_Source>&
290       append(_Source const& __source)
291       {
292 	_M_append(_S_convert(__detail::_S_range_begin(__source),
293 			     __detail::_S_range_end(__source)));
294 	return *this;
295       }
296 
297     template<typename _InputIterator>
298       __detail::_Path<_InputIterator, _InputIterator>&
299       append(_InputIterator __first, _InputIterator __last)
300       {
301 	_M_append(_S_convert(__first, __last));
302 	return *this;
303       }
304 
305     // concatenation
306 
307     path& operator+=(const path& __x);
308     path& operator+=(const string_type& __x);
309     path& operator+=(const value_type* __x);
310     path& operator+=(value_type __x);
311     path& operator+=(basic_string_view<value_type> __x);
312 
313     template<typename _Source>
314       __detail::_Path<_Source>&
315       operator+=(_Source const& __x) { return concat(__x); }
316 
317     template<typename _CharT>
318       __detail::_Path<_CharT*, _CharT*>&
319       operator+=(_CharT __x);
320 
321     template<typename _Source>
322       __detail::_Path<_Source>&
323       concat(_Source const& __x)
324       {
325 	_M_concat(_S_convert(__detail::_S_range_begin(__x),
326 			     __detail::_S_range_end(__x)));
327 	return *this;
328       }
329 
330     template<typename _InputIterator>
331       __detail::_Path<_InputIterator, _InputIterator>&
332       concat(_InputIterator __first, _InputIterator __last)
333       {
334 	_M_concat(_S_convert(__first, __last));
335 	return *this;
336       }
337 
338     // modifiers
339 
340     void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
341 
342     path& make_preferred();
343     path& remove_filename();
344     path& replace_filename(const path& __replacement);
345     path& replace_extension(const path& __replacement = path());
346 
347     void swap(path& __rhs) noexcept;
348 
349     // native format observers
350 
351     const string_type&  native() const noexcept { return _M_pathname; }
352     const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
353     operator string_type() const { return _M_pathname; }
354 
355     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
356 	     typename _Allocator = std::allocator<_CharT>>
357       std::basic_string<_CharT, _Traits, _Allocator>
358       string(const _Allocator& __a = _Allocator()) const;
359 
360     std::string    string() const;
361 #if _GLIBCXX_USE_WCHAR_T
362     std::wstring   wstring() const;
363 #endif
364 #ifdef _GLIBCXX_USE_CHAR8_T
365     __attribute__((__abi_tag__("__u8")))
366     std::u8string  u8string() const;
367 #else
368     std::string    u8string() const;
369 #endif // _GLIBCXX_USE_CHAR8_T
370     std::u16string u16string() const;
371     std::u32string u32string() const;
372 
373     // generic format observers
374     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
375 	     typename _Allocator = std::allocator<_CharT>>
376       std::basic_string<_CharT, _Traits, _Allocator>
377       generic_string(const _Allocator& __a = _Allocator()) const;
378 
379     std::string    generic_string() const;
380 #if _GLIBCXX_USE_WCHAR_T
381     std::wstring   generic_wstring() const;
382 #endif
383 #ifdef _GLIBCXX_USE_CHAR8_T
384     __attribute__((__abi_tag__("__u8")))
385     std::u8string  generic_u8string() const;
386 #else
387     std::string    generic_u8string() const;
388 #endif // _GLIBCXX_USE_CHAR8_T
389     std::u16string generic_u16string() const;
390     std::u32string generic_u32string() const;
391 
392     // compare
393 
394     int compare(const path& __p) const noexcept;
395     int compare(const string_type& __s) const noexcept;
396     int compare(const value_type* __s) const noexcept;
397     int compare(basic_string_view<value_type> __s) const noexcept;
398 
399     // decomposition
400 
401     path root_name() const;
402     path root_directory() const;
403     path root_path() const;
404     path relative_path() const;
405     path parent_path() const;
406     path filename() const;
407     path stem() const;
408     path extension() const;
409 
410     // query
411 
412     [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); }
413     bool has_root_name() const noexcept;
414     bool has_root_directory() const noexcept;
415     bool has_root_path() const noexcept;
416     bool has_relative_path() const noexcept;
417     bool has_parent_path() const noexcept;
418     bool has_filename() const noexcept;
419     bool has_stem() const noexcept;
420     bool has_extension() const noexcept;
421     bool is_absolute() const noexcept;
422     bool is_relative() const noexcept { return !is_absolute(); }
423 
424     // generation
425     path lexically_normal() const;
426     path lexically_relative(const path& base) const;
427     path lexically_proximate(const path& base) const;
428 
429     // iterators
430     class iterator;
431     using const_iterator = iterator;
432 
433     iterator begin() const;
434     iterator end() const;
435 
436     /// Write a path to a stream
437     template<typename _CharT, typename _Traits>
438       friend std::basic_ostream<_CharT, _Traits>&
439       operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p)
440       {
441 	__os << std::quoted(__p.string<_CharT, _Traits>());
442 	return __os;
443       }
444 
445     /// Read a path from a stream
446     template<typename _CharT, typename _Traits>
447       friend std::basic_istream<_CharT, _Traits>&
448       operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p)
449       {
450 	std::basic_string<_CharT, _Traits> __tmp;
451 	if (__is >> std::quoted(__tmp))
452 	  __p = std::move(__tmp);
453 	return __is;
454       }
455 
456     // non-member operators
457 
458     /// Compare paths
459     friend bool operator==(const path& __lhs, const path& __rhs) noexcept
460     { return __lhs.compare(__rhs) == 0; }
461 
462 #if __cpp_lib_three_way_comparison
463     /// Compare paths
464     friend strong_ordering
465     operator<=>(const path& __lhs, const path& __rhs) noexcept
466     { return __lhs.compare(__rhs) <=> 0; }
467 #else
468     /// Compare paths
469     friend bool operator!=(const path& __lhs, const path& __rhs) noexcept
470     { return !(__lhs == __rhs); }
471 
472     /// Compare paths
473     friend bool operator<(const path& __lhs, const path& __rhs) noexcept
474     { return __lhs.compare(__rhs) < 0; }
475 
476     /// Compare paths
477     friend bool operator<=(const path& __lhs, const path& __rhs) noexcept
478     { return !(__rhs < __lhs); }
479 
480     /// Compare paths
481     friend bool operator>(const path& __lhs, const path& __rhs) noexcept
482     { return __rhs < __lhs; }
483 
484     /// Compare paths
485     friend bool operator>=(const path& __lhs, const path& __rhs) noexcept
486     { return !(__lhs < __rhs); }
487 #endif
488 
489     /// Append one path to another
490     friend path operator/(const path& __lhs, const path& __rhs)
491     {
492       path __result(__lhs);
493       __result /= __rhs;
494       return __result;
495     }
496 
497     /// @cond undocumented
498     // Create a basic_string by reading until a null character.
499     template<typename _InputIterator,
500 	     typename _Traits = std::iterator_traits<_InputIterator>,
501 	     typename _CharT
502 	       = typename std::remove_cv_t<typename _Traits::value_type>>
503       static std::basic_string<_CharT>
504       _S_string_from_iter(_InputIterator __source)
505       {
506 	std::basic_string<_CharT> __str;
507 	for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
508 	  __str.push_back(__ch);
509 	return __str;
510       }
511     /// @endcond
512 
513   private:
514     enum class _Type : unsigned char {
515       _Multi = 0, _Root_name, _Root_dir, _Filename
516     };
517 
518     path(basic_string_view<value_type> __str, _Type __type);
519 
520     enum class _Split { _Stem, _Extension };
521 
522     void _M_append(basic_string_view<value_type>);
523     void _M_concat(basic_string_view<value_type>);
524 
525     pair<const string_type*, size_t> _M_find_extension() const noexcept;
526 
527     template<typename _CharT>
528       struct _Cvt;
529 
530     static basic_string_view<value_type>
531     _S_convert(value_type* __src, __detail::__nul_terminated)
532     { return __src; }
533 
534     static basic_string_view<value_type>
535     _S_convert(const value_type* __src, __detail::__nul_terminated)
536     { return __src; }
537 
538     static basic_string_view<value_type>
539     _S_convert(value_type* __first, value_type* __last)
540     { return {__first, __last - __first}; }
541 
542     static basic_string_view<value_type>
543     _S_convert(const value_type* __first, const value_type* __last)
544     { return {__first, __last - __first}; }
545 
546     template<typename _Iter>
547       static string_type
548       _S_convert(_Iter __first, _Iter __last)
549       {
550 	using __value_type = typename std::iterator_traits<_Iter>::value_type;
551 	return _Cvt<typename remove_cv<__value_type>::type>::
552 	  _S_convert(__first, __last);
553       }
554 
555     template<typename _InputIterator>
556       static string_type
557       _S_convert(_InputIterator __src, __detail::__nul_terminated)
558       {
559 	// Read from iterator into basic_string until a null value is seen:
560 	auto __s = _S_string_from_iter(__src);
561 	// Convert (if needed) from iterator's value type to path::value_type:
562 	return string_type(_S_convert(__s.data(), __s.data() + __s.size()));
563       }
564 
565     static string_type
566     _S_convert_loc(const char* __first, const char* __last,
567 		   const std::locale& __loc);
568 
569     template<typename _Iter>
570       static string_type
571       _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
572       {
573 	const std::string __str(__first, __last);
574 	return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
575       }
576 
577     template<typename _InputIterator>
578       static string_type
579       _S_convert_loc(_InputIterator __src, __detail::__nul_terminated,
580 		     const std::locale& __loc)
581       {
582 	const std::string __s = _S_string_from_iter(__src);
583 	return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
584       }
585 
586     template<typename _CharT, typename _Traits, typename _Allocator>
587       static basic_string<_CharT, _Traits, _Allocator>
588       _S_str_convert(basic_string_view<value_type>, const _Allocator&);
589 
590     void _M_split_cmpts();
591 
592     _Type _M_type() const noexcept { return _M_cmpts.type(); }
593 
594     string_type _M_pathname;
595 
596     struct _Cmpt;
597 
598     struct _List
599     {
600       using value_type = _Cmpt;
601       using iterator = value_type*;
602       using const_iterator = const value_type*;
603 
604       _List();
605       _List(const _List&);
606       _List(_List&&) = default;
607       _List& operator=(const _List&);
608       _List& operator=(_List&&) = default;
609       ~_List() = default;
610 
611       _Type type() const noexcept
612       { return _Type(reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3); }
613 
614       void type(_Type) noexcept;
615 
616       int size() const noexcept; // zero unless type() == _Type::_Multi
617       bool empty() const noexcept; // true unless type() == _Type::_Multi
618       void clear();
619       void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); }
620       int capacity() const noexcept;
621       void reserve(int, bool); ///< @pre type() == _Type::_Multi
622 
623       // All the member functions below here have a precondition !empty()
624       // (and they should only be called from within the library).
625 
626       iterator begin() noexcept;
627       iterator end() noexcept;
628       const_iterator begin() const noexcept;
629       const_iterator end() const noexcept;
630 
631       value_type& front() noexcept;
632       value_type& back() noexcept;
633       const value_type& front() const noexcept;
634       const value_type& back() const noexcept;
635 
636       void pop_back();
637       void _M_erase_from(const_iterator __pos); // erases [__pos,end())
638 
639       struct _Impl;
640       struct _Impl_deleter
641       {
642 	void operator()(_Impl*) const noexcept;
643       };
644       unique_ptr<_Impl, _Impl_deleter> _M_impl;
645     };
646     _List _M_cmpts;
647 
648     struct _Parser;
649   };
650 
651   /// @relates std::filesystem::path @{
652 
653   inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
654 
655   size_t hash_value(const path& __p) noexcept;
656 
657   /// @}
658 
659   /// Exception type thrown by the Filesystem library
660   class filesystem_error : public std::system_error
661   {
662   public:
663     filesystem_error(const string& __what_arg, error_code __ec);
664 
665     filesystem_error(const string& __what_arg, const path& __p1,
666 		     error_code __ec);
667 
668     filesystem_error(const string& __what_arg, const path& __p1,
669 		     const path& __p2, error_code __ec);
670 
671     filesystem_error(const filesystem_error&) = default;
672     filesystem_error& operator=(const filesystem_error&) = default;
673 
674     // No move constructor or assignment operator.
675     // Copy rvalues instead, so that _M_impl is not left empty.
676 
677     ~filesystem_error();
678 
679     const path& path1() const noexcept;
680     const path& path2() const noexcept;
681     const char* what() const noexcept;
682 
683   private:
684     struct _Impl;
685     std::__shared_ptr<const _Impl> _M_impl;
686   };
687 
688   /** Create a path from a UTF-8-encoded sequence of char
689    *
690    * @relates std::filesystem::path
691    */
692   template<typename _InputIterator,
693 	   typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
694 	   typename _CharT
695 	     = __detail::__value_type_is_char_or_char8_t<_InputIterator>>
696     inline path
697     u8path(_InputIterator __first, _InputIterator __last)
698     {
699 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
700       if constexpr (is_same_v<_CharT, char>)
701 	{
702 	  // XXX This assumes native wide encoding is UTF-16.
703 	  std::codecvt_utf8_utf16<path::value_type> __cvt;
704 	  path::string_type __tmp;
705 	  if constexpr (is_pointer_v<_InputIterator>)
706 	    {
707 	      if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
708 		return path{ __tmp };
709 	    }
710 	  else
711 	    {
712 	      const std::string __u8str{__first, __last};
713 	      const char* const __p = __u8str.data();
714 	      if (__str_codecvt_in_all(__p, __p + __u8str.size(), __tmp, __cvt))
715 		return path{ __tmp };
716 	    }
717 	  _GLIBCXX_THROW_OR_ABORT(filesystem_error(
718 	      "Cannot convert character sequence",
719 	      std::make_error_code(errc::illegal_byte_sequence)));
720 	}
721       else
722 	return path{ __first, __last };
723 #else
724       // This assumes native normal encoding is UTF-8.
725       return path{ __first, __last };
726 #endif
727     }
728 
729   /** Create a path from a UTF-8-encoded sequence of char
730    *
731    * @relates std::filesystem::path
732    */
733   template<typename _Source,
734 	   typename _Require = __detail::_Path<_Source>,
735 	   typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>>
736     inline path
737     u8path(const _Source& __source)
738     {
739 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
740       if constexpr (is_same_v<_CharT, char>)
741 	{
742 	  if constexpr (is_convertible_v<const _Source&, std::string_view>)
743 	    {
744 	      const std::string_view __s = __source;
745 	      return filesystem::u8path(__s.data(), __s.data() + __s.size());
746 	    }
747 	  else
748 	    {
749 	      std::string __s = path::_S_string_from_iter(__source);
750 	      return filesystem::u8path(__s.data(), __s.data() + __s.size());
751 	    }
752 	}
753       else
754 	return path{ __source };
755 #else
756       return path{ __source };
757 #endif
758     }
759 
760   /// @cond undocumented
761 
762   struct path::_Cmpt : path
763   {
764     _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos);
765 
766     _Cmpt() : _M_pos(-1) { }
767 
768     size_t _M_pos;
769   };
770 
771   // specialize _Cvt for degenerate 'noconv' case
772   template<>
773     struct path::_Cvt<path::value_type>
774     {
775       template<typename _Iter>
776 	static string_type
777 	_S_convert(_Iter __first, _Iter __last)
778 	{ return string_type{__first, __last}; }
779     };
780 
781 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS  && defined _GLIBCXX_USE_CHAR8_T
782   // For POSIX converting from char8_t to char is also 'noconv'
783   template<>
784     struct path::_Cvt<char8_t>
785     {
786       template<typename _Iter>
787 	static string_type
788 	_S_convert(_Iter __first, _Iter __last)
789 	{ return string_type(__first, __last); }
790     };
791 #endif
792 
793   template<typename _CharT>
794     struct path::_Cvt
795     {
796       static string_type
797       _S_convert(const _CharT* __f, const _CharT* __l)
798       {
799 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
800 	std::wstring __wstr;
801 	if constexpr (is_same_v<_CharT, char>)
802 	  {
803 	    struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
804 	    { } __cvt;
805 	    if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
806 	      return __wstr;
807 	  }
808 #ifdef _GLIBCXX_USE_CHAR8_T
809 	else if constexpr (is_same_v<_CharT, char8_t>)
810 	  {
811 	    const char* __f2 = (const char*)__f;
812 	    const char* __l2 = (const char*)__l;
813 	    std::codecvt_utf8_utf16<wchar_t> __wcvt;
814 	    if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
815 	      return __wstr;
816 	  }
817 #endif
818 	else // char16_t or char32_t
819 	  {
820 	    struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
821 	    { } __cvt;
822 	    std::string __str;
823 	    if (__str_codecvt_out_all(__f, __l, __str, __cvt))
824 	      {
825 		const char* __f2 = __str.data();
826 		const char* __l2 = __f2 + __str.size();
827 		std::codecvt_utf8_utf16<wchar_t> __wcvt;
828 		if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
829 		  return __wstr;
830 	      }
831 	  }
832 #else // ! windows
833 	struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
834 	{ } __cvt;
835 	std::string __str;
836 	if (__str_codecvt_out_all(__f, __l, __str, __cvt))
837 	  return __str;
838 #endif
839 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
840 	      "Cannot convert character sequence",
841 	      std::make_error_code(errc::illegal_byte_sequence)));
842       }
843 
844       static string_type
845       _S_convert(_CharT* __f, _CharT* __l)
846       {
847 	return _S_convert(const_cast<const _CharT*>(__f),
848 			  const_cast<const _CharT*>(__l));
849       }
850 
851       template<typename _Iter>
852 	static string_type
853 	_S_convert(_Iter __first, _Iter __last)
854 	{
855 	  const std::basic_string<_CharT> __str(__first, __last);
856 	  return _S_convert(__str.data(), __str.data() + __str.size());
857 	}
858 
859       template<typename _Iter, typename _Cont>
860 	static string_type
861 	_S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
862 		  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
863 	{ return _S_convert(__first.base(), __last.base()); }
864     };
865 
866   /// @endcond
867 
868   /// An iterator for the components of a path
869   class path::iterator
870   {
871   public:
872     using difference_type	= std::ptrdiff_t;
873     using value_type		= path;
874     using reference		= const path&;
875     using pointer		= const path*;
876     using iterator_category	= std::bidirectional_iterator_tag;
877 
878     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
879 
880     iterator(const iterator&) = default;
881     iterator& operator=(const iterator&) = default;
882 
883     reference operator*() const;
884     pointer   operator->() const { return std::__addressof(**this); }
885 
886     iterator& operator++();
887     iterator  operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
888 
889     iterator& operator--();
890     iterator  operator--(int) { auto __tmp = *this; --*this; return __tmp; }
891 
892     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
893     { return __lhs._M_equals(__rhs); }
894 
895     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
896     { return !__lhs._M_equals(__rhs); }
897 
898   private:
899     friend class path;
900 
901     bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
902 
903     friend difference_type
904     __path_iter_distance(const iterator& __first, const iterator& __last)
905     {
906       __glibcxx_assert(__first._M_path != nullptr);
907       __glibcxx_assert(__first._M_path == __last._M_path);
908       if (__first._M_is_multi())
909 	return std::distance(__first._M_cur, __last._M_cur);
910       else if (__first._M_at_end == __last._M_at_end)
911 	return 0;
912       else
913 	return __first._M_at_end ? -1 : 1;
914     }
915 
916     friend void
917     __path_iter_advance(iterator& __i, difference_type __n)
918     {
919       if (__n == 1)
920 	++__i;
921       else if (__n == -1)
922 	--__i;
923       else if (__n != 0)
924 	{
925 	  __glibcxx_assert(__i._M_path != nullptr);
926 	  __glibcxx_assert(__i._M_is_multi());
927 	  // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
928 	  __i._M_cur += __n;
929 	}
930     }
931 
932     iterator(const path* __path, path::_List::const_iterator __iter)
933     : _M_path(__path), _M_cur(__iter), _M_at_end()
934     { }
935 
936     iterator(const path* __path, bool __at_end)
937     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
938     { }
939 
940     bool _M_equals(iterator) const;
941 
942     const path* 		_M_path;
943     path::_List::const_iterator _M_cur;
944     bool			_M_at_end;  // only used when type != _Multi
945   };
946 
947 
948   inline path&
949   path::operator=(path&& __p) noexcept
950   {
951     if (&__p == this) [[__unlikely__]]
952       return *this;
953 
954     _M_pathname = std::move(__p._M_pathname);
955     _M_cmpts = std::move(__p._M_cmpts);
956     __p.clear();
957     return *this;
958   }
959 
960   inline path&
961   path::operator=(string_type&& __source)
962   { return *this = path(std::move(__source)); }
963 
964   inline path&
965   path::assign(string_type&& __source)
966   { return *this = path(std::move(__source)); }
967 
968   inline path&
969   path::operator+=(const string_type& __x)
970   {
971     _M_concat(__x);
972     return *this;
973   }
974 
975   inline path&
976   path::operator+=(const value_type* __x)
977   {
978     _M_concat(__x);
979     return *this;
980   }
981 
982   inline path&
983   path::operator+=(value_type __x)
984   {
985     _M_concat(basic_string_view<value_type>(&__x, 1));
986     return *this;
987   }
988 
989   inline path&
990   path::operator+=(basic_string_view<value_type> __x)
991   {
992     _M_concat(__x);
993     return *this;
994   }
995 
996   template<typename _CharT>
997     inline __detail::_Path<_CharT*, _CharT*>&
998     path::operator+=(_CharT __x)
999     {
1000       auto* __addr = std::__addressof(__x);
1001       return concat(__addr, __addr + 1);
1002     }
1003 
1004   inline path&
1005   path::make_preferred()
1006   {
1007 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1008     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
1009 		 preferred_separator);
1010 #endif
1011     return *this;
1012   }
1013 
1014   inline void path::swap(path& __rhs) noexcept
1015   {
1016     _M_pathname.swap(__rhs._M_pathname);
1017     _M_cmpts.swap(__rhs._M_cmpts);
1018   }
1019 
1020   /// @cond undocumented
1021   template<typename _CharT, typename _Traits, typename _Allocator>
1022     std::basic_string<_CharT, _Traits, _Allocator>
1023     path::_S_str_convert(basic_string_view<value_type> __str,
1024 			 const _Allocator& __a)
1025     {
1026       static_assert(!is_same_v<_CharT, value_type>);
1027 
1028       using _WString = basic_string<_CharT, _Traits, _Allocator>;
1029 
1030       if (__str.size() == 0)
1031 	return _WString(__a);
1032 
1033 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1034       // First convert native string from UTF-16 to to UTF-8.
1035       // XXX This assumes that the execution wide-character set is UTF-16.
1036       std::codecvt_utf8_utf16<value_type> __cvt;
1037 
1038       using _CharAlloc = __alloc_rebind<_Allocator, char>;
1039       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
1040       _String __u8str{_CharAlloc{__a}};
1041       const value_type* __wfirst = __str.data();
1042       const value_type* __wlast = __wfirst + __str.size();
1043       if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
1044       if constexpr (is_same_v<_CharT, char>)
1045 	return __u8str; // XXX assumes native ordinary encoding is UTF-8.
1046       else {
1047 
1048       const char* __first = __u8str.data();
1049       const char* __last = __first + __u8str.size();
1050 #else
1051       const value_type* __first = __str.data();
1052       const value_type* __last = __first + __str.size();
1053 #endif
1054 
1055       // Convert UTF-8 string to requested format.
1056 #ifdef _GLIBCXX_USE_CHAR8_T
1057       if constexpr (is_same_v<_CharT, char8_t>)
1058 	return _WString(__first, __last, __a);
1059       else
1060 #endif
1061 	{
1062 	  // Convert UTF-8 to wide string.
1063 	  _WString __wstr(__a);
1064 	  struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
1065 	  if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
1066 	    return __wstr;
1067 	}
1068 
1069 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1070       } }
1071 #endif
1072       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1073 	    "Cannot convert character sequence",
1074 	    std::make_error_code(errc::illegal_byte_sequence)));
1075     }
1076   /// @endcond
1077 
1078   template<typename _CharT, typename _Traits, typename _Allocator>
1079     inline basic_string<_CharT, _Traits, _Allocator>
1080     path::string(const _Allocator& __a) const
1081     {
1082       if constexpr (is_same_v<_CharT, value_type>)
1083 	return { _M_pathname.c_str(), _M_pathname.length(), __a };
1084       else
1085 	return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1086     }
1087 
1088   inline std::string
1089   path::string() const { return string<char>(); }
1090 
1091 #if _GLIBCXX_USE_WCHAR_T
1092   inline std::wstring
1093   path::wstring() const { return string<wchar_t>(); }
1094 #endif
1095 
1096 #ifdef _GLIBCXX_USE_CHAR8_T
1097   inline std::u8string
1098   path::u8string() const { return string<char8_t>(); }
1099 #else
1100   inline std::string
1101   path::u8string() const
1102   {
1103 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1104     std::string __str;
1105     // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1106     std::codecvt_utf8_utf16<value_type> __cvt;
1107     const value_type* __first = _M_pathname.data();
1108     const value_type* __last = __first + _M_pathname.size();
1109     if (__str_codecvt_out_all(__first, __last, __str, __cvt))
1110       return __str;
1111     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1112 	  "Cannot convert character sequence",
1113 	  std::make_error_code(errc::illegal_byte_sequence)));
1114 #else
1115     return _M_pathname;
1116 #endif
1117   }
1118 #endif // _GLIBCXX_USE_CHAR8_T
1119 
1120   inline std::u16string
1121   path::u16string() const { return string<char16_t>(); }
1122 
1123   inline std::u32string
1124   path::u32string() const { return string<char32_t>(); }
1125 
1126   template<typename _CharT, typename _Traits, typename _Allocator>
1127     inline std::basic_string<_CharT, _Traits, _Allocator>
1128     path::generic_string(const _Allocator& __a) const
1129     {
1130 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1131       const value_type __slash = L'/';
1132 #else
1133       const value_type __slash = '/';
1134 #endif
1135       using _Alloc2 = typename allocator_traits<_Allocator>::template
1136 	rebind_alloc<value_type>;
1137       basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a);
1138 
1139       if (_M_type() == _Type::_Root_dir)
1140 	__str.assign(1, __slash);
1141       else
1142 	{
1143 	  __str.reserve(_M_pathname.size());
1144 	  bool __add_slash = false;
1145 	  for (auto& __elem : *this)
1146 	    {
1147 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1148 	      if (__elem._M_type() == _Type::_Root_dir)
1149 		{
1150 		  __str += __slash;
1151 		  continue;
1152 		}
1153 #endif
1154 	      if (__add_slash)
1155 		__str += __slash;
1156 	      __str += basic_string_view<value_type>(__elem._M_pathname);
1157 	      __add_slash = __elem._M_type() == _Type::_Filename;
1158 	    }
1159 	}
1160 
1161       if constexpr (is_same_v<_CharT, value_type>)
1162 	return __str;
1163       else
1164 	return _S_str_convert<_CharT, _Traits>(__str, __a);
1165     }
1166 
1167   inline std::string
1168   path::generic_string() const
1169   { return generic_string<char>(); }
1170 
1171 #if _GLIBCXX_USE_WCHAR_T
1172   inline std::wstring
1173   path::generic_wstring() const
1174   { return generic_string<wchar_t>(); }
1175 #endif
1176 
1177 #ifdef _GLIBCXX_USE_CHAR8_T
1178   inline std::u8string
1179   path::generic_u8string() const
1180   { return generic_string<char8_t>(); }
1181 #else
1182   inline std::string
1183   path::generic_u8string() const
1184   { return generic_string(); }
1185 #endif
1186 
1187   inline std::u16string
1188   path::generic_u16string() const
1189   { return generic_string<char16_t>(); }
1190 
1191   inline std::u32string
1192   path::generic_u32string() const
1193   { return generic_string<char32_t>(); }
1194 
1195   inline int
1196   path::compare(const string_type& __s) const noexcept
1197   { return compare(basic_string_view<value_type>(__s)); }
1198 
1199   inline int
1200   path::compare(const value_type* __s) const noexcept
1201   { return compare(basic_string_view<value_type>(__s)); }
1202 
1203   inline path
1204   path::filename() const
1205   {
1206     if (empty())
1207       return {};
1208     else if (_M_type() == _Type::_Filename)
1209       return *this;
1210     else if (_M_type() == _Type::_Multi)
1211       {
1212 	if (_M_pathname.back() == preferred_separator)
1213 	  return {};
1214 	auto __last = --end();
1215 	if (__last->_M_type() == _Type::_Filename)
1216 	  return *__last;
1217       }
1218     return {};
1219   }
1220 
1221   inline path
1222   path::stem() const
1223   {
1224     auto ext = _M_find_extension();
1225     if (ext.first && ext.second != 0)
1226       return path{ext.first->substr(0, ext.second)};
1227     return {};
1228   }
1229 
1230   inline path
1231   path::extension() const
1232   {
1233     auto ext = _M_find_extension();
1234     if (ext.first && ext.second != string_type::npos)
1235       return path{ext.first->substr(ext.second)};
1236     return {};
1237   }
1238 
1239   inline bool
1240   path::has_stem() const noexcept
1241   {
1242     auto ext = _M_find_extension();
1243     return ext.first && ext.second != 0;
1244   }
1245 
1246   inline bool
1247   path::has_extension() const noexcept
1248   {
1249     auto ext = _M_find_extension();
1250     return ext.first && ext.second != string_type::npos;
1251   }
1252 
1253   inline bool
1254   path::is_absolute() const noexcept
1255   {
1256 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1257     return has_root_name() && has_root_directory();
1258 #else
1259     return has_root_directory();
1260 #endif
1261   }
1262 
1263   inline path::iterator
1264   path::begin() const
1265   {
1266     if (_M_type() == _Type::_Multi)
1267       return iterator(this, _M_cmpts.begin());
1268     return iterator(this, empty());
1269   }
1270 
1271   inline path::iterator
1272   path::end() const
1273   {
1274     if (_M_type() == _Type::_Multi)
1275       return iterator(this, _M_cmpts.end());
1276     return iterator(this, true);
1277   }
1278 
1279   inline path::iterator&
1280   path::iterator::operator++()
1281   {
1282     __glibcxx_assert(_M_path != nullptr);
1283     if (_M_path->_M_type() == _Type::_Multi)
1284       {
1285 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1286 	++_M_cur;
1287       }
1288     else
1289       {
1290 	__glibcxx_assert(!_M_at_end);
1291 	_M_at_end = true;
1292       }
1293     return *this;
1294   }
1295 
1296   inline path::iterator&
1297   path::iterator::operator--()
1298   {
1299     __glibcxx_assert(_M_path != nullptr);
1300     if (_M_path->_M_type() == _Type::_Multi)
1301       {
1302 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1303 	--_M_cur;
1304       }
1305     else
1306       {
1307 	__glibcxx_assert(_M_at_end);
1308 	_M_at_end = false;
1309       }
1310     return *this;
1311   }
1312 
1313   inline path::iterator::reference
1314   path::iterator::operator*() const
1315   {
1316     __glibcxx_assert(_M_path != nullptr);
1317     if (_M_path->_M_type() == _Type::_Multi)
1318       {
1319 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1320 	return *_M_cur;
1321       }
1322     return *_M_path;
1323   }
1324 
1325   inline bool
1326   path::iterator::_M_equals(iterator __rhs) const
1327   {
1328     if (_M_path != __rhs._M_path)
1329       return false;
1330     if (_M_path == nullptr)
1331       return true;
1332     if (_M_path->_M_type() == path::_Type::_Multi)
1333       return _M_cur == __rhs._M_cur;
1334     return _M_at_end == __rhs._M_at_end;
1335   }
1336 
1337   /// @} group filesystem
1338 _GLIBCXX_END_NAMESPACE_CXX11
1339 } // namespace filesystem
1340 
1341 inline ptrdiff_t
1342 distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1343 { return __path_iter_distance(__first, __last); }
1344 
1345 template<typename _Distance>
1346   void
1347   advance(filesystem::path::iterator& __i, _Distance __n)
1348   { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1349 
1350 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1351 
1352 _GLIBCXX_END_NAMESPACE_VERSION
1353 } // namespace std
1354 
1355 #endif // C++17
1356 
1357 #endif // _GLIBCXX_FS_PATH_H
1358