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