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