xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/experimental/bits/fs_path.h (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 // Class filesystem::path -*- C++ -*-
2 
3 // Copyright (C) 2014-2019 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 
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   /**
75    * @ingroup filesystem-ts
76    * @{
77    */
78 
79   /// A filesystem path.
80   class path
81   {
82     template<typename _CharT,
83 	     typename _Ch = typename remove_const<_CharT>::type>
84       using __is_encoded_char
85 	= __or_<is_same<_Ch, char>,
86 		is_same<_Ch, wchar_t>,
87 #ifdef _GLIBCXX_USE_CHAR8_T
88 		is_same<_Ch, char8_t>,
89 #endif
90 		is_same<_Ch, char16_t>,
91 		is_same<_Ch, char32_t>>;
92 
93     template<typename _Iter,
94 	     typename _Iter_traits = std::iterator_traits<_Iter>>
95       using __is_path_iter_src
96 	= __and_<__is_encoded_char<typename _Iter_traits::value_type>,
97 		 std::is_base_of<std::input_iterator_tag,
98 				 typename _Iter_traits::iterator_category>>;
99 
100     template<typename _Iter>
101       static __is_path_iter_src<_Iter>
102       __is_path_src(_Iter, int);
103 
104     template<typename _CharT, typename _Traits, typename _Alloc>
105       static __is_encoded_char<_CharT>
106       __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
107 
108 #if __cplusplus >= 201402L
109     template<typename _CharT, typename _Traits>
110       static __is_encoded_char<_CharT>
111       __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
112 #endif
113 
114     template<typename _Unknown>
115       static std::false_type
116       __is_path_src(const _Unknown&, ...);
117 
118     template<typename _Tp1, typename _Tp2>
119       struct __constructible_from;
120 
121     template<typename _Iter>
122       struct __constructible_from<_Iter, _Iter>
123       : __is_path_iter_src<_Iter>
124       { };
125 
126     template<typename _Source>
127       struct __constructible_from<_Source, void>
128       : decltype(__is_path_src(std::declval<_Source>(), 0))
129       { };
130 
131     template<typename _Tp1, typename _Tp2 = void,
132 	     typename _Tp1_nocv = typename remove_cv<_Tp1>::type,
133 	     typename _Tp1_noptr = typename remove_pointer<_Tp1>::type>
134       using _Path = typename
135 	std::enable_if<__and_<__not_<is_same<_Tp1_nocv, path>>,
136 			      __not_<is_void<_Tp1_noptr>>,
137 			      __constructible_from<_Tp1, _Tp2>>::value,
138 		       path>::type;
139 
140     template<typename _Source>
141       static _Source
142       _S_range_begin(_Source __begin) { return __begin; }
143 
144     struct __null_terminated { };
145 
146     template<typename _Source>
147       static __null_terminated
148       _S_range_end(_Source) { return {}; }
149 
150     template<typename _CharT, typename _Traits, typename _Alloc>
151       static const _CharT*
152       _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
153       { return __str.data(); }
154 
155     template<typename _CharT, typename _Traits, typename _Alloc>
156       static const _CharT*
157       _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
158       { return __str.data() + __str.size(); }
159 
160 #if __cplusplus >= 201402L
161     template<typename _CharT, typename _Traits>
162       static const _CharT*
163       _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
164       { return __str.data(); }
165 
166     template<typename _CharT, typename _Traits>
167       static const _CharT*
168       _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
169       { return __str.data() + __str.size(); }
170 #endif
171 
172     template<typename _Tp,
173 	     typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
174 	     typename _Val = typename std::iterator_traits<_Iter>::value_type>
175       using __value_type_is_char = typename std::enable_if<
176 	std::is_same<typename std::remove_const<_Val>::type, char>::value
177 	>::type;
178 
179   public:
180 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
181     typedef wchar_t				value_type;
182     static constexpr value_type			preferred_separator = L'\\';
183 #else
184     typedef char				value_type;
185     static constexpr value_type			preferred_separator = '/';
186 #endif
187     typedef std::basic_string<value_type>	string_type;
188 
189     // constructors and destructor
190 
191     path() noexcept { }
192 
193     path(const path& __p) = default;
194 
195     path(path&& __p) noexcept
196     : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
197     {
198       if (_M_type == _Type::_Multi)
199 	_M_split_cmpts();
200       __p.clear();
201     }
202 
203     path(string_type&& __source)
204     : _M_pathname(std::move(__source))
205     { _M_split_cmpts(); }
206 
207     template<typename _Source,
208 	     typename _Require = _Path<_Source>>
209       path(_Source const& __source)
210       : _M_pathname(_S_convert(_S_range_begin(__source),
211 			       _S_range_end(__source)))
212       { _M_split_cmpts(); }
213 
214     template<typename _InputIterator,
215 	     typename _Require = _Path<_InputIterator, _InputIterator>>
216       path(_InputIterator __first, _InputIterator __last)
217       : _M_pathname(_S_convert(__first, __last))
218       { _M_split_cmpts(); }
219 
220     template<typename _Source,
221 	     typename _Require = _Path<_Source>,
222 	     typename _Require2 = __value_type_is_char<_Source>>
223       path(_Source const& __source, const locale& __loc)
224       : _M_pathname(_S_convert_loc(_S_range_begin(__source),
225 				   _S_range_end(__source), __loc))
226       { _M_split_cmpts(); }
227 
228     template<typename _InputIterator,
229 	     typename _Require = _Path<_InputIterator, _InputIterator>,
230 	     typename _Require2 = __value_type_is_char<_InputIterator>>
231       path(_InputIterator __first, _InputIterator __last, const locale& __loc)
232       : _M_pathname(_S_convert_loc(__first, __last, __loc))
233       { _M_split_cmpts(); }
234 
235     ~path() = default;
236 
237     // assignments
238 
239     path& operator=(const path& __p) = default;
240     path& operator=(path&& __p) noexcept;
241     path& operator=(string_type&& __source);
242     path& assign(string_type&& __source);
243 
244     template<typename _Source>
245       _Path<_Source>&
246       operator=(_Source const& __source)
247       { return *this = path(__source); }
248 
249     template<typename _Source>
250       _Path<_Source>&
251       assign(_Source const& __source)
252       { return *this = path(__source); }
253 
254     template<typename _InputIterator>
255       _Path<_InputIterator, _InputIterator>&
256       assign(_InputIterator __first, _InputIterator __last)
257       { return *this = path(__first, __last); }
258 
259     // appends
260 
261     path& operator/=(const path& __p) { return _M_append(__p._M_pathname); }
262 
263     template <class _Source>
264       _Path<_Source>&
265       operator/=(_Source const& __source)
266       { return append(__source); }
267 
268     template<typename _Source>
269       _Path<_Source>&
270       append(_Source const& __source)
271       {
272 	return _M_append(_S_convert(_S_range_begin(__source),
273 				    _S_range_end(__source)));
274       }
275 
276     template<typename _InputIterator>
277       _Path<_InputIterator, _InputIterator>&
278       append(_InputIterator __first, _InputIterator __last)
279       { return _M_append(_S_convert(__first, __last)); }
280 
281     // concatenation
282 
283     path& operator+=(const path& __x);
284     path& operator+=(const string_type& __x);
285     path& operator+=(const value_type* __x);
286     path& operator+=(value_type __x);
287 #if __cplusplus >= 201402L
288     path& operator+=(basic_string_view<value_type> __x);
289 #endif
290 
291     template<typename _Source>
292       _Path<_Source>&
293       operator+=(_Source const& __x) { return concat(__x); }
294 
295     template<typename _CharT>
296       _Path<_CharT*, _CharT*>&
297       operator+=(_CharT __x);
298 
299     template<typename _Source>
300       _Path<_Source>&
301       concat(_Source const& __x)
302       { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
303 
304     template<typename _InputIterator>
305       _Path<_InputIterator, _InputIterator>&
306       concat(_InputIterator __first, _InputIterator __last)
307       { return *this += _S_convert(__first, __last); }
308 
309     // modifiers
310 
311     void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
312 
313     path& make_preferred();
314     path& remove_filename();
315     path& replace_filename(const path& __replacement);
316     path& replace_extension(const path& __replacement = path());
317 
318     void swap(path& __rhs) noexcept;
319 
320     // native format observers
321 
322     const string_type&  native() const noexcept { return _M_pathname; }
323     const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
324     operator string_type() const { return _M_pathname; }
325 
326     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
327 	     typename _Allocator = std::allocator<_CharT>>
328       std::basic_string<_CharT, _Traits, _Allocator>
329       string(const _Allocator& __a = _Allocator()) const;
330 
331     std::string    string() const;
332 #if _GLIBCXX_USE_WCHAR_T
333     std::wstring   wstring() const;
334 #endif
335 #ifdef _GLIBCXX_USE_CHAR8_T
336     __attribute__((__abi_tag__("__u8")))
337     std::u8string  u8string() const;
338 #else
339     std::string    u8string() const;
340 #endif // _GLIBCXX_USE_CHAR8_T
341     std::u16string u16string() const;
342     std::u32string u32string() const;
343 
344     // generic format observers
345     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
346 	     typename _Allocator = std::allocator<_CharT>>
347       std::basic_string<_CharT, _Traits, _Allocator>
348       generic_string(const _Allocator& __a = _Allocator()) const;
349 
350     std::string    generic_string() const;
351 #if _GLIBCXX_USE_WCHAR_T
352     std::wstring   generic_wstring() const;
353 #endif
354 #ifdef _GLIBCXX_USE_CHAR8_T
355     __attribute__((__abi_tag__("__u8")))
356     std::u8string  generic_u8string() const;
357 #else
358     std::string    generic_u8string() const;
359 #endif // _GLIBCXX_USE_CHAR8_T
360     std::u16string generic_u16string() const;
361     std::u32string generic_u32string() const;
362 
363     // compare
364 
365     int compare(const path& __p) const noexcept;
366     int compare(const string_type& __s) const;
367     int compare(const value_type* __s) const;
368 #if __cplusplus >= 201402L
369     int compare(const basic_string_view<value_type> __s) const;
370 #endif
371 
372     // decomposition
373 
374     path root_name() const;
375     path root_directory() const;
376     path root_path() const;
377     path relative_path() const;
378     path parent_path() const;
379     path filename() const;
380     path stem() const;
381     path extension() const;
382 
383     // query
384 
385     _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_pathname.empty(); }
386     bool has_root_name() const;
387     bool has_root_directory() const;
388     bool has_root_path() const;
389     bool has_relative_path() const;
390     bool has_parent_path() const;
391     bool has_filename() const;
392     bool has_stem() const;
393     bool has_extension() const;
394     bool is_absolute() const;
395     bool is_relative() const { return !is_absolute(); }
396 
397     // iterators
398     class iterator;
399     typedef iterator const_iterator;
400 
401     iterator begin() const;
402     iterator end() const;
403 
404     // Create a basic_string by reading until a null character.
405     template<typename _InputIterator,
406 	     typename _Traits = std::iterator_traits<_InputIterator>,
407 	     typename _CharT
408 	       = typename std::remove_cv<typename _Traits::value_type>::type>
409       static std::basic_string<_CharT>
410       _S_string_from_iter(_InputIterator __source)
411       {
412 	std::basic_string<_CharT> __str;
413 	for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
414 	  __str.push_back(__ch);
415 	return __str;
416       }
417 
418   private:
419     enum class _Type : unsigned char {
420 	_Multi, _Root_name, _Root_dir, _Filename
421     };
422 
423     path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
424     {
425       __glibcxx_assert(!empty());
426       __glibcxx_assert(_M_type != _Type::_Multi);
427     }
428 
429     enum class _Split { _Stem, _Extension };
430 
431     path& _M_append(const string_type& __str)
432     {
433       if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
434 	  && !__str.empty() && !_S_is_dir_sep(__str.front()))
435 	_M_pathname += preferred_separator;
436       _M_pathname += __str;
437       _M_split_cmpts();
438       return *this;
439     }
440 
441     pair<const string_type*, size_t> _M_find_extension() const;
442 
443     template<typename _CharT>
444       struct _Cvt;
445 
446     static string_type
447     _S_convert(value_type* __src, __null_terminated)
448     { return string_type(__src); }
449 
450     static string_type
451     _S_convert(const value_type* __src, __null_terminated)
452     { return string_type(__src); }
453 
454     template<typename _Iter>
455       static string_type
456       _S_convert(_Iter __first, _Iter __last)
457       {
458 	using __value_type = typename std::iterator_traits<_Iter>::value_type;
459 	return _Cvt<typename remove_cv<__value_type>::type>::
460 	  _S_convert(__first, __last);
461       }
462 
463     template<typename _InputIterator>
464       static string_type
465       _S_convert(_InputIterator __src, __null_terminated)
466       {
467 	auto __s = _S_string_from_iter(__src);
468 	return _S_convert(__s.c_str(), __s.c_str() + __s.size());
469       }
470 
471     static string_type
472     _S_convert_loc(const char* __first, const char* __last,
473 		   const std::locale& __loc);
474 
475     template<typename _Iter>
476       static string_type
477       _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
478       {
479 	const std::string __str(__first, __last);
480 	return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
481       }
482 
483     template<typename _InputIterator>
484       static string_type
485       _S_convert_loc(_InputIterator __src, __null_terminated,
486 		     const std::locale& __loc)
487       {
488 	const std::string __s = _S_string_from_iter(__src);
489 	return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
490       }
491 
492     static bool _S_is_dir_sep(value_type __ch)
493     {
494 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
495       return __ch == L'/' || __ch == preferred_separator;
496 #else
497       return __ch == '/';
498 #endif
499     }
500 
501     void _M_split_cmpts();
502     void _M_trim();
503     void _M_add_root_name(size_t __n);
504     void _M_add_root_dir(size_t __pos);
505     void _M_add_filename(size_t __pos, size_t __n);
506 
507     string_type _M_pathname;
508 
509     struct _Cmpt;
510     using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
511     _List _M_cmpts; // empty unless _M_type == _Type::_Multi
512     _Type _M_type = _Type::_Multi;
513   };
514 
515   inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
516 
517   size_t hash_value(const path& __p) noexcept;
518 
519   /// Compare paths
520   inline bool operator<(const path& __lhs, const path& __rhs) noexcept
521   { return __lhs.compare(__rhs) < 0; }
522 
523   /// Compare paths
524   inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
525   { return !(__rhs < __lhs); }
526 
527   /// Compare paths
528   inline bool operator>(const path& __lhs, const path& __rhs) noexcept
529   { return __rhs < __lhs; }
530 
531   /// Compare paths
532   inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
533   { return !(__lhs < __rhs); }
534 
535   /// Compare paths
536   inline bool operator==(const path& __lhs, const path& __rhs) noexcept
537   { return __lhs.compare(__rhs) == 0; }
538 
539   /// Compare paths
540   inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
541   { return !(__lhs == __rhs); }
542 
543   /// Append one path to another
544   inline path operator/(const path& __lhs, const path& __rhs)
545   {
546     path __result(__lhs);
547     __result /= __rhs;
548     return __result;
549   }
550 
551   /// Write a path to a stream
552   template<typename _CharT, typename _Traits>
553     basic_ostream<_CharT, _Traits>&
554     operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
555     {
556       auto __tmp = __p.string<_CharT, _Traits>();
557       using __quoted_string
558 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
559       __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')};
560       return __os;
561     }
562 
563   /// Read a path from a stream
564   template<typename _CharT, typename _Traits>
565     basic_istream<_CharT, _Traits>&
566     operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
567     {
568       basic_string<_CharT, _Traits> __tmp;
569       using __quoted_string
570 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
571       if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') })
572 	__p = std::move(__tmp);
573       return __is;
574     }
575 
576   /// Create a path from a UTF-8-encoded sequence of char
577   // TODO constrain with _Path<InputIterator, InputIterator> and __value_type_is_char
578   template<typename _InputIterator>
579     inline path
580     u8path(_InputIterator __first, _InputIterator __last)
581     {
582 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
583       // XXX This assumes native wide encoding is UTF-16.
584       std::codecvt_utf8_utf16<path::value_type> __cvt;
585       path::string_type __tmp;
586       const std::string __u8str{__first, __last};
587       const char* const __ptr = __u8str.data();
588       if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
589 	return path{ __tmp };
590       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
591 	    "Cannot convert character sequence",
592 	    std::make_error_code(errc::illegal_byte_sequence)));
593 #else
594       return path{ __first, __last };
595 #endif
596     }
597 
598   /// Create a path from a UTF-8-encoded sequence of char
599   // TODO constrain with _Path<Source> and __value_type_is_char
600   template<typename _Source>
601     inline path
602     u8path(const _Source& __source)
603     {
604 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
605       std::string __s = path::_S_string_from_iter(__source);
606       return filesystem::u8path(__s.data(), __s.data() + __s.size());
607 #else
608       return path{ __source };
609 #endif
610     }
611 
612   class filesystem_error : public std::system_error
613   {
614   public:
615     filesystem_error(const string& __what_arg, error_code __ec)
616     : system_error(__ec, __what_arg) { }
617 
618     filesystem_error(const string& __what_arg, const path& __p1,
619 		     error_code __ec)
620     : system_error(__ec, __what_arg), _M_path1(__p1) { }
621 
622     filesystem_error(const string& __what_arg, const path& __p1,
623 		     const path& __p2, error_code __ec)
624     : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
625     { }
626 
627     ~filesystem_error();
628 
629     const path& path1() const noexcept { return _M_path1; }
630     const path& path2() const noexcept { return _M_path2; }
631     const char* what() const noexcept { return _M_what.c_str(); }
632 
633   private:
634     std::string _M_gen_what();
635 
636     path _M_path1;
637     path _M_path2;
638     std::string _M_what = _M_gen_what();
639   };
640 
641   struct path::_Cmpt : path
642   {
643     _Cmpt(string_type __s, _Type __t, size_t __pos)
644       : path(std::move(__s), __t), _M_pos(__pos) { }
645 
646     _Cmpt() : _M_pos(-1) { }
647 
648     size_t _M_pos;
649   };
650 
651   // specialize _Cvt for degenerate 'noconv' case
652   template<>
653     struct path::_Cvt<path::value_type>
654     {
655       template<typename _Iter>
656 	static string_type
657 	_S_convert(_Iter __first, _Iter __last)
658 	{ return string_type{__first, __last}; }
659     };
660 
661   template<typename _CharT>
662     struct path::_Cvt
663     {
664 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
665       static string_type
666       _S_wconvert(const char* __f, const char* __l, true_type)
667       {
668 	using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
669 	const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
670 	std::wstring __wstr;
671 	if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
672 	    return __wstr;
673 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
674 	      "Cannot convert character sequence",
675 	      std::make_error_code(errc::illegal_byte_sequence)));
676       }
677 
678       static string_type
679       _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
680       {
681 #ifdef _GLIBCXX_USE_CHAR8_T
682 	if constexpr (is_same<_CharT, char8_t>::value)
683 	  return _S_wconvert((const char*)__f, (const char*)__l, true_type());
684 	else
685 #endif
686 	  {
687 	    struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
688 	    { } __cvt;
689 	    std::string __str;
690 	    if (__str_codecvt_out_all(__f, __l, __str, __cvt))
691 	      {
692 		const char* __f2 = __str.data();
693 		const char* __l2 = __f2 + __str.size();
694 		std::codecvt_utf8_utf16<wchar_t> __wcvt;
695 		std::wstring __wstr;
696 		if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
697 		  return __wstr;
698 	      }
699 	    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
700 		  "Cannot convert character sequence",
701 		  std::make_error_code(errc::illegal_byte_sequence)));
702 	  }
703       }
704 
705       static string_type
706       _S_convert(const _CharT* __f, const _CharT* __l)
707       {
708 	return _S_wconvert(__f, __l, is_same<_CharT, char>{});
709       }
710 #else
711       static string_type
712       _S_convert(const _CharT* __f, const _CharT* __l)
713       {
714 #ifdef _GLIBCXX_USE_CHAR8_T
715 	if constexpr (is_same<_CharT, char8_t>::value)
716 	  return string_type(__f, __l);
717 	else
718 	  {
719 #endif
720 	    struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
721 	    { } __cvt;
722 	    std::string __str;
723 	    if (__str_codecvt_out_all(__f, __l, __str, __cvt))
724 	      return __str;
725 #ifdef _GLIBCXX_USE_CHAR8_T
726 	  }
727 #endif
728 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
729 	      "Cannot convert character sequence",
730 	      std::make_error_code(errc::illegal_byte_sequence)));
731       }
732 #endif
733 
734       static string_type
735       _S_convert(_CharT* __f, _CharT* __l)
736       {
737 	return _S_convert(const_cast<const _CharT*>(__f),
738 			  const_cast<const _CharT*>(__l));
739       }
740 
741       template<typename _Iter>
742 	static string_type
743 	_S_convert(_Iter __first, _Iter __last)
744 	{
745 	  const std::basic_string<_CharT> __str(__first, __last);
746 	  return _S_convert(__str.data(), __str.data() + __str.size());
747 	}
748 
749       template<typename _Iter, typename _Cont>
750 	static string_type
751 	_S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
752 		  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
753 	{ return _S_convert(__first.base(), __last.base()); }
754     };
755 
756   /// An iterator for the components of a path
757   class path::iterator
758   {
759   public:
760     using difference_type	= std::ptrdiff_t;
761     using value_type		= path;
762     using reference		= const path&;
763     using pointer		= const path*;
764     using iterator_category	= std::bidirectional_iterator_tag;
765 
766     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
767 
768     iterator(const iterator&) = default;
769     iterator& operator=(const iterator&) = default;
770 
771     reference operator*() const;
772     pointer   operator->() const { return std::__addressof(**this); }
773 
774     iterator& operator++();
775     iterator  operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
776 
777     iterator& operator--();
778     iterator  operator--(int) { auto __tmp = *this; --*this; return __tmp; }
779 
780     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
781     { return __lhs._M_equals(__rhs); }
782 
783     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
784     { return !__lhs._M_equals(__rhs); }
785 
786   private:
787     friend class path;
788 
789     iterator(const path* __path, path::_List::const_iterator __iter)
790     : _M_path(__path), _M_cur(__iter), _M_at_end()
791     { }
792 
793     iterator(const path* __path, bool __at_end)
794     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
795     { }
796 
797     bool _M_equals(iterator) const;
798 
799     const path* 		_M_path;
800     path::_List::const_iterator _M_cur;
801     bool			_M_at_end;  // only used when type != _Multi
802   };
803 
804 
805   inline path&
806   path::operator=(path&& __p) noexcept
807   {
808     _M_pathname = std::move(__p._M_pathname);
809     _M_cmpts = std::move(__p._M_cmpts);
810     _M_type = __p._M_type;
811     __p.clear();
812     return *this;
813   }
814 
815   inline path&
816   path::operator=(string_type&& __source)
817   { return *this = path(std::move(__source)); }
818 
819   inline path&
820   path::assign(string_type&& __source)
821   { return *this = path(std::move(__source)); }
822 
823   inline path&
824   path::operator+=(const path& __p)
825   {
826     return operator+=(__p.native());
827   }
828 
829   inline path&
830   path::operator+=(const string_type& __x)
831   {
832     _M_pathname += __x;
833     _M_split_cmpts();
834     return *this;
835   }
836 
837   inline path&
838   path::operator+=(const value_type* __x)
839   {
840     _M_pathname += __x;
841     _M_split_cmpts();
842     return *this;
843   }
844 
845   inline path&
846   path::operator+=(value_type __x)
847   {
848     _M_pathname += __x;
849     _M_split_cmpts();
850     return *this;
851   }
852 
853 #if __cplusplus >= 201402L
854   inline path&
855   path::operator+=(basic_string_view<value_type> __x)
856   {
857     _M_pathname.append(__x.data(), __x.size());
858     _M_split_cmpts();
859     return *this;
860   }
861 #endif
862 
863   template<typename _CharT>
864     inline path::_Path<_CharT*, _CharT*>&
865     path::operator+=(_CharT __x)
866     {
867       auto* __addr = std::__addressof(__x);
868       return concat(__addr, __addr + 1);
869     }
870 
871   inline path&
872   path::make_preferred()
873   {
874 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
875     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
876 		 preferred_separator);
877 #endif
878     return *this;
879   }
880 
881   inline void path::swap(path& __rhs) noexcept
882   {
883     _M_pathname.swap(__rhs._M_pathname);
884     _M_cmpts.swap(__rhs._M_cmpts);
885     std::swap(_M_type, __rhs._M_type);
886   }
887 
888   template<typename _CharT, typename _Traits, typename _Allocator>
889     inline std::basic_string<_CharT, _Traits, _Allocator>
890     path::string(const _Allocator& __a) const
891     {
892       if (is_same<_CharT, value_type>::value)
893 	return { _M_pathname.begin(), _M_pathname.end(), __a };
894 
895       using _WString = basic_string<_CharT, _Traits, _Allocator>;
896 
897       const value_type* __first = _M_pathname.data();
898       const value_type* __last = __first + _M_pathname.size();
899 
900 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
901       using _CharAlloc = __alloc_rebind<_Allocator, char>;
902       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
903 
904       // First convert native string from UTF-16 to to UTF-8.
905       // XXX This assumes that the execution wide-character set is UTF-16.
906       codecvt_utf8_utf16<value_type> __cvt;
907       _String __u8str{_CharAlloc{__a}};
908       if (__str_codecvt_out_all(__first, __last, __u8str, __cvt))
909 	{
910 	  struct
911 	  {
912 	    const _String*
913 	    operator()(const _String& __from, _String&, true_type)
914 	    { return std::__addressof(__from); }
915 
916 	    _WString*
917 	    operator()(const _String& __from, _WString& __to, false_type)
918 	    {
919 #ifdef _GLIBCXX_USE_CHAR8_T
920 	      if constexpr (is_same<_CharT, char8_t>::value)
921 	        {
922 	          __to.assign(__from.begin(), __from.end());
923 	          return std::__addressof(__to);
924 	        }
925 	      else
926 #endif
927 	        {
928 	          // Convert UTF-8 to wide string.
929 	          struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
930 		  { } __cvt;
931 	          const char* __f = __from.data();
932 	          const char* __l = __f + __from.size();
933 	          if (__str_codecvt_in_all(__f, __l, __to, __cvt))
934 		    return std::__addressof(__to);
935 	        }
936 	      return nullptr;
937 	    }
938 	  } __dispatch;
939 	  _WString __wstr(__a);
940 	  if (auto* __p = __dispatch(__u8str, __wstr, is_same<_CharT, char>{}))
941 	    return *__p;
942 	}
943 #else
944 #ifdef _GLIBCXX_USE_CHAR8_T
945       if constexpr (is_same<_CharT, char8_t>::value)
946           return _WString(__first, __last, __a);
947       else
948 #endif
949         {
950           struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
951           _WString __wstr(__a);
952           if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
953 	    return __wstr;
954         }
955 #endif
956       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
957 	    "Cannot convert character sequence",
958 	    std::make_error_code(errc::illegal_byte_sequence)));
959     }
960 
961   inline std::string
962   path::string() const { return string<char>(); }
963 
964 #if _GLIBCXX_USE_WCHAR_T
965   inline std::wstring
966   path::wstring() const { return string<wchar_t>(); }
967 #endif
968 
969 #ifdef _GLIBCXX_USE_CHAR8_T
970   inline std::u8string
971   path::u8string() const { return string<char8_t>(); }
972 #else
973   inline std::string
974   path::u8string() const
975   {
976 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
977     std::string __str;
978     // convert from native wide encoding (assumed to be UTF-16) to UTF-8
979     std::codecvt_utf8_utf16<value_type> __cvt;
980     const value_type* __first = _M_pathname.data();
981     const value_type* __last = __first + _M_pathname.size();
982     if (__str_codecvt_out_all(__first, __last, __str, __cvt))
983       return __str;
984     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
985 	  "Cannot convert character sequence",
986 	  std::make_error_code(errc::illegal_byte_sequence)));
987 #else
988     return _M_pathname;
989 #endif
990   }
991 #endif // _GLIBCXX_USE_CHAR8_T
992 
993   inline std::u16string
994   path::u16string() const { return string<char16_t>(); }
995 
996   inline std::u32string
997   path::u32string() const { return string<char32_t>(); }
998 
999 #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1000   template<typename _CharT, typename _Traits, typename _Allocator>
1001     inline std::basic_string<_CharT, _Traits, _Allocator>
1002     path::generic_string(const _Allocator& __a) const
1003     { return string<_CharT, _Traits, _Allocator>(__a); }
1004 
1005   inline std::string
1006   path::generic_string() const { return string(); }
1007 
1008 #if _GLIBCXX_USE_WCHAR_T
1009   inline std::wstring
1010   path::generic_wstring() const { return wstring(); }
1011 #endif
1012 
1013 #ifdef _GLIBCXX_USE_CHAR8_T
1014   inline std::u8string
1015   path::generic_u8string() const { return u8string(); }
1016 #else
1017   inline std::string
1018   path::generic_u8string() const { return u8string(); }
1019 #endif
1020 
1021   inline std::u16string
1022   path::generic_u16string() const { return u16string(); }
1023 
1024   inline std::u32string
1025   path::generic_u32string() const { return u32string(); }
1026 #endif
1027 
1028   inline int
1029   path::compare(const string_type& __s) const { return compare(path(__s)); }
1030 
1031   inline int
1032   path::compare(const value_type* __s) const { return compare(path(__s)); }
1033 
1034 #if __cplusplus >= 201402L
1035   inline int
1036   path::compare(basic_string_view<value_type> __s) const
1037   { return compare(path(__s)); }
1038 #endif
1039 
1040   inline path
1041   path::filename() const { return empty() ? path() : *--end(); }
1042 
1043   inline path
1044   path::stem() const
1045   {
1046     auto ext = _M_find_extension();
1047     if (ext.first && ext.second != 0)
1048       return path{ext.first->substr(0, ext.second)};
1049     return {};
1050   }
1051 
1052   inline path
1053   path::extension() const
1054   {
1055     auto ext = _M_find_extension();
1056     if (ext.first && ext.second != string_type::npos)
1057       return path{ext.first->substr(ext.second)};
1058     return {};
1059   }
1060 
1061   inline bool
1062   path::has_stem() const
1063   {
1064     auto ext = _M_find_extension();
1065     return ext.first && ext.second != 0;
1066   }
1067 
1068   inline bool
1069   path::has_extension() const
1070   {
1071     auto ext = _M_find_extension();
1072     return ext.first && ext.second != string_type::npos;
1073   }
1074 
1075   inline bool
1076   path::is_absolute() const
1077   {
1078 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1079     return has_root_name() && has_root_directory();
1080 #else
1081     return has_root_directory();
1082 #endif
1083   }
1084 
1085   inline path::iterator
1086   path::begin() const
1087   {
1088     if (_M_type == _Type::_Multi)
1089       return iterator(this, _M_cmpts.begin());
1090     return iterator(this, false);
1091   }
1092 
1093   inline path::iterator
1094   path::end() const
1095   {
1096     if (_M_type == _Type::_Multi)
1097       return iterator(this, _M_cmpts.end());
1098     return iterator(this, true);
1099   }
1100 
1101   inline path::iterator&
1102   path::iterator::operator++()
1103   {
1104     __glibcxx_assert(_M_path != nullptr);
1105     if (_M_path->_M_type == _Type::_Multi)
1106       {
1107 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1108 	++_M_cur;
1109       }
1110     else
1111       {
1112 	__glibcxx_assert(!_M_at_end);
1113 	_M_at_end = true;
1114       }
1115     return *this;
1116   }
1117 
1118   inline path::iterator&
1119   path::iterator::operator--()
1120   {
1121     __glibcxx_assert(_M_path != nullptr);
1122     if (_M_path->_M_type == _Type::_Multi)
1123       {
1124 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1125 	--_M_cur;
1126       }
1127     else
1128       {
1129 	__glibcxx_assert(_M_at_end);
1130 	_M_at_end = false;
1131       }
1132     return *this;
1133   }
1134 
1135   inline path::iterator::reference
1136   path::iterator::operator*() const
1137   {
1138     __glibcxx_assert(_M_path != nullptr);
1139     if (_M_path->_M_type == _Type::_Multi)
1140       {
1141 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1142 	return *_M_cur;
1143       }
1144     return *_M_path;
1145   }
1146 
1147   inline bool
1148   path::iterator::_M_equals(iterator __rhs) const
1149   {
1150     if (_M_path != __rhs._M_path)
1151       return false;
1152     if (_M_path == nullptr)
1153       return true;
1154     if (_M_path->_M_type == path::_Type::_Multi)
1155       return _M_cur == __rhs._M_cur;
1156     return _M_at_end == __rhs._M_at_end;
1157   }
1158 
1159   // @} group filesystem-ts
1160 _GLIBCXX_END_NAMESPACE_CXX11
1161 } // namespace v1
1162 } // namespace filesystem
1163 } // namespace experimental
1164 
1165 _GLIBCXX_END_NAMESPACE_VERSION
1166 } // namespace std
1167 
1168 #endif // C++11
1169 
1170 #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H
1171