libstdc++
bits/fs_path.h
Go to the documentation of this file.
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>,
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
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>>
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
336
337 // generic format observers
338 template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
339 typename _Allocator = std::allocator<_CharT>>
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>
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>
413 {
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
460 _S_string_from_iter(_InputIterator __source)
461 {
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(const string_type&, const _Allocator& __a);
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>
956 path::_S_str_convert(const string_type& __str, const _Allocator& __a)
957 {
958 static_assert(!is_same_v<_CharT, value_type>);
959
960 using _WString = basic_string<_CharT, _Traits, _Allocator>;
961
962 if (__str.size() == 0)
963 return _WString(__a);
964
965#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
966 // First convert native string from UTF-16 to to UTF-8.
967 // XXX This assumes that the execution wide-character set is UTF-16.
968 std::codecvt_utf8_utf16<value_type> __cvt;
969
970 using _CharAlloc = __alloc_rebind<_Allocator, char>;
971 using _String = basic_string<char, char_traits<char>, _CharAlloc>;
972 _String __u8str{_CharAlloc{__a}};
973 const value_type* __wfirst = __str.data();
974 const value_type* __wlast = __wfirst + __str.size();
975 if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
976 if constexpr (is_same_v<_CharT, char>)
977 return __u8str; // XXX assumes native ordinary encoding is UTF-8.
978 else {
979
980 const char* __first = __u8str.data();
981 const char* __last = __first + __u8str.size();
982#else
983 const value_type* __first = __str.data();
984 const value_type* __last = __first + __str.size();
985#endif
986
987 // Convert UTF-8 string to requested format.
988#ifdef _GLIBCXX_USE_CHAR8_T
989 if constexpr (is_same_v<_CharT, char8_t>)
990 return _WString(__first, __last, __a);
991 else
992#endif
993 {
994 // Convert UTF-8 to wide string.
995 _WString __wstr(__a);
996 struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
997 if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
998 return __wstr;
999 }
1000
1001#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1002 } }
1003#endif
1004 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1005 "Cannot convert character sequence",
1006 std::make_error_code(errc::illegal_byte_sequence)));
1007 }
1008
1009 template<typename _CharT, typename _Traits, typename _Allocator>
1010 inline basic_string<_CharT, _Traits, _Allocator>
1011 path::string(const _Allocator& __a) const
1012 {
1013 if constexpr (is_same_v<_CharT, value_type>)
1014 return { _M_pathname.c_str(), _M_pathname.length(), __a };
1015 else
1016 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
1017 }
1018
1019 inline std::string
1020 path::string() const { return string<char>(); }
1021
1022#if _GLIBCXX_USE_WCHAR_T
1023 inline std::wstring
1024 path::wstring() const { return string<wchar_t>(); }
1025#endif
1026
1027#ifdef _GLIBCXX_USE_CHAR8_T
1028 inline std::u8string
1029 path::u8string() const { return string<char8_t>(); }
1030#else
1031 inline std::string
1032 path::u8string() const
1033 {
1034#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1035 std::string __str;
1036 // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1037 std::codecvt_utf8_utf16<value_type> __cvt;
1038 const value_type* __first = _M_pathname.data();
1039 const value_type* __last = __first + _M_pathname.size();
1040 if (__str_codecvt_out_all(__first, __last, __str, __cvt))
1041 return __str;
1042 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1043 "Cannot convert character sequence",
1044 std::make_error_code(errc::illegal_byte_sequence)));
1045#else
1046 return _M_pathname;
1047#endif
1048 }
1049#endif // _GLIBCXX_USE_CHAR8_T
1050
1051 inline std::u16string
1052 path::u16string() const { return string<char16_t>(); }
1053
1054 inline std::u32string
1055 path::u32string() const { return string<char32_t>(); }
1056
1057 template<typename _CharT, typename _Traits, typename _Allocator>
1059 path::generic_string(const _Allocator& __a) const
1060 {
1061#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1062 const value_type __slash = L'/';
1063#else
1064 const value_type __slash = '/';
1065#endif
1066 string_type __str(__a);
1067
1068 if (_M_type() == _Type::_Root_dir)
1069 __str.assign(1, __slash);
1070 else
1071 {
1072 __str.reserve(_M_pathname.size());
1073 bool __add_slash = false;
1074 for (auto& __elem : *this)
1075 {
1076#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1077 if (__elem._M_type() == _Type::_Root_dir)
1078 {
1079 __str += __slash;
1080 continue;
1081 }
1082#endif
1083 if (__add_slash)
1084 __str += __slash;
1085 __str += __elem._M_pathname;
1086 __add_slash = __elem._M_type() == _Type::_Filename;
1087 }
1088 }
1089
1090 if constexpr (is_same_v<_CharT, value_type>)
1091 return __str;
1092 else
1093 return _S_str_convert<_CharT, _Traits>(__str, __a);
1094 }
1095
1096 inline std::string
1097 path::generic_string() const
1098 { return generic_string<char>(); }
1099
1100#if _GLIBCXX_USE_WCHAR_T
1101 inline std::wstring
1102 path::generic_wstring() const
1103 { return generic_string<wchar_t>(); }
1104#endif
1105
1106#ifdef _GLIBCXX_USE_CHAR8_T
1107 inline std::u8string
1108 path::generic_u8string() const
1109 { return generic_string<char8_t>(); }
1110#else
1111 inline std::string
1112 path::generic_u8string() const
1113 { return generic_string(); }
1114#endif
1115
1116 inline std::u16string
1117 path::generic_u16string() const
1118 { return generic_string<char16_t>(); }
1119
1120 inline std::u32string
1121 path::generic_u32string() const
1122 { return generic_string<char32_t>(); }
1123
1124 inline int
1125 path::compare(const string_type& __s) const noexcept
1126 { return compare(basic_string_view<value_type>(__s)); }
1127
1128 inline int
1129 path::compare(const value_type* __s) const noexcept
1130 { return compare(basic_string_view<value_type>(__s)); }
1131
1132 inline path
1133 path::filename() const
1134 {
1135 if (empty())
1136 return {};
1137 else if (_M_type() == _Type::_Filename)
1138 return *this;
1139 else if (_M_type() == _Type::_Multi)
1140 {
1141 if (_M_pathname.back() == preferred_separator)
1142 return {};
1143 auto& __last = *--end();
1144 if (__last._M_type() == _Type::_Filename)
1145 return __last;
1146 }
1147 return {};
1148 }
1149
1150 inline path
1151 path::stem() const
1152 {
1153 auto ext = _M_find_extension();
1154 if (ext.first && ext.second != 0)
1155 return path{ext.first->substr(0, ext.second)};
1156 return {};
1157 }
1158
1159 inline path
1160 path::extension() const
1161 {
1162 auto ext = _M_find_extension();
1163 if (ext.first && ext.second != string_type::npos)
1164 return path{ext.first->substr(ext.second)};
1165 return {};
1166 }
1167
1168 inline bool
1169 path::has_stem() const noexcept
1170 {
1171 auto ext = _M_find_extension();
1172 return ext.first && ext.second != 0;
1173 }
1174
1175 inline bool
1176 path::has_extension() const noexcept
1177 {
1178 auto ext = _M_find_extension();
1179 return ext.first && ext.second != string_type::npos;
1180 }
1181
1182 inline bool
1183 path::is_absolute() const noexcept
1184 {
1185#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1186 return has_root_name() && has_root_directory();
1187#else
1188 return has_root_directory();
1189#endif
1190 }
1191
1192 inline path::iterator
1193 path::begin() const
1194 {
1195 if (_M_type() == _Type::_Multi)
1196 return iterator(this, _M_cmpts.begin());
1197 return iterator(this, empty());
1198 }
1199
1200 inline path::iterator
1201 path::end() const
1202 {
1203 if (_M_type() == _Type::_Multi)
1204 return iterator(this, _M_cmpts.end());
1205 return iterator(this, true);
1206 }
1207
1208 inline path::iterator&
1209 path::iterator::operator++()
1210 {
1211 __glibcxx_assert(_M_path != nullptr);
1212 if (_M_path->_M_type() == _Type::_Multi)
1213 {
1214 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1215 ++_M_cur;
1216 }
1217 else
1218 {
1219 __glibcxx_assert(!_M_at_end);
1220 _M_at_end = true;
1221 }
1222 return *this;
1223 }
1224
1225 inline path::iterator&
1226 path::iterator::operator--()
1227 {
1228 __glibcxx_assert(_M_path != nullptr);
1229 if (_M_path->_M_type() == _Type::_Multi)
1230 {
1231 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1232 --_M_cur;
1233 }
1234 else
1235 {
1236 __glibcxx_assert(_M_at_end);
1237 _M_at_end = false;
1238 }
1239 return *this;
1240 }
1241
1242 inline path::iterator::reference
1243 path::iterator::operator*() const
1244 {
1245 __glibcxx_assert(_M_path != nullptr);
1246 if (_M_path->_M_type() == _Type::_Multi)
1247 {
1248 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1249 return *_M_cur;
1250 }
1251 return *_M_path;
1252 }
1253
1254 inline bool
1255 path::iterator::_M_equals(iterator __rhs) const
1256 {
1257 if (_M_path != __rhs._M_path)
1258 return false;
1259 if (_M_path == nullptr)
1260 return true;
1261 if (_M_path->_M_type() == path::_Type::_Multi)
1262 return _M_cur == __rhs._M_cur;
1263 return _M_at_end == __rhs._M_at_end;
1264 }
1265
1266 // @} group filesystem
1267_GLIBCXX_END_NAMESPACE_CXX11
1268} // namespace filesystem
1269
1270inline ptrdiff_t
1271distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
1272{ return __path_iter_distance(__first, __last); }
1273
1274template<typename _InputIterator, typename _Distance>
1275 void
1276 advance(filesystem::path::iterator& __i, _Distance __n)
1277 { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
1278
1279extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1280
1281_GLIBCXX_END_NAMESPACE_VERSION
1282} // namespace std
1283
1284#endif // C++17
1285
1286#endif // _GLIBCXX_FS_PATH_H
_GLIBCXX20_CONSTEXPR complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition: complex:387
_GLIBCXX20_CONSTEXPR complex< _Tp > operator/(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x divided by y.
Definition: complex:417
typename remove_cv< _Tp >::type remove_cv_t
Alias template for remove_cv.
Definition: type_traits:1437
typename remove_const< _Tp >::type remove_const_t
Alias template for remove_const.
Definition: type_traits:1429
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2384
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:47
basic_string< char32_t > u32string
A string of char32_t.
Definition: stringfwd.h:96
basic_string< char16_t > u16string
A string of char16_t.
Definition: stringfwd.h:93
_GLIBCXX_END_NAMESPACE_CXX11 typedef basic_string< char > string
A string of char.
Definition: stringfwd.h:79
basic_string< wchar_t > wstring
A string of wchar_t.
Definition: stringfwd.h:83
ISO C++ entities toplevel namespace is std.
constexpr const _Tp * begin(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to the first element of the initializer_list.
_GLIBCXX17_CONSTEXPR iterator_traits< _InputIterator >::difference_type distance(_InputIterator __first, _InputIterator __last)
A generalization of pointer arithmetic.
constexpr const _Tp * end(initializer_list< _Tp > __ils) noexcept
Return an iterator pointing to one past the last element of the initializer_list.
std::basic_istream< _CharT, _Traits > & operator>>(std::basic_istream< _CharT, _Traits > &__is, bitset< _Nb > &__x)
Global I/O operators for bitsets.
Definition: bitset:1470
auto quoted(const _CharT *__string, _CharT __delim=_CharT('"'), _CharT __escape = _CharT('\\'))
Manipulator for quoted strings.
Definition: iomanip:461
_GLIBCXX17_CONSTEXPR void advance(_InputIterator &__i, _Distance __n)
A generalization of pointer arithmetic.
Template class basic_istream.
Definition: istream:59
Template class basic_ostream.
Definition: ostream:59
Thrown to indicate error code of underlying system.
Definition: system_error:342
integral_constant
Definition: type_traits:58
is_base_of
Definition: type_traits:1303
Define a member typedef type only if a boolean constant is true.
Definition: type_traits:2046
void push_back(_CharT __c)
Append a single character.
const _CharT * data() const noexcept
Return const pointer to contents.
const _CharT * c_str() const noexcept
Return const pointer to null-terminated contents.
Primary class template codecvt.
Definition: codecvt.h:276
Container class for localization functionality.
static const locale & classic()
Return reference to the C locale.
Marking input iterators.
Bidirectional iterators support a superset of forward iterator operations.
path u8path(_InputIterator __first, _InputIterator __last)
Create a path from a UTF-8-encoded sequence of char.
size_t hash_value(const path &__p) noexcept
Compare paths.