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