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