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