source: Daodan/MSYS2/mingw32/include/c++/11.2.0/bits/fs_path.h

Last change on this file was 1166, checked in by rossy, 3 years ago

Daodan: Replace MinGW build env with an up-to-date MSYS2 env

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