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