]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/bits/fs_path.h
PR libstdc++/80762 avoid ambiguous __constructible_from<void, void>
[thirdparty/gcc.git] / libstdc++-v3 / include / bits / fs_path.h
CommitLineData
641cb5a6
JW
1// Class filesystem::path -*- C++ -*-
2
85ec4feb 3// Copyright (C) 2014-2018 Free Software Foundation, Inc.
641cb5a6
JW
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 <vector>
38#include <locale>
39#include <iosfwd>
9534a5e6 40#include <iomanip>
641cb5a6
JW
41#include <codecvt>
42#include <string_view>
43#include <system_error>
44#include <bits/stl_algobase.h>
641cb5a6 45#include <bits/locale_conv.h>
24d9b090
JW
46#include <ext/concurrence.h>
47#include <bits/shared_ptr.h>
641cb5a6
JW
48
49#if defined(_WIN32) && !defined(__CYGWIN__)
50# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
51# include <algorithm>
52#endif
53
54namespace std _GLIBCXX_VISIBILITY(default)
55{
56_GLIBCXX_BEGIN_NAMESPACE_VERSION
57
58namespace filesystem
59{
60_GLIBCXX_BEGIN_NAMESPACE_CXX11
61
62 /**
63 * @ingroup filesystem
64 * @{
65 */
66
67 /// A filesystem path.
68 class path
69 {
49d729ea
JW
70 template<typename _CharT, typename _Ch = remove_const_t<_CharT>>
71 using __is_encoded_char
72 = __or_<is_same<_Ch, char>, is_same<_Ch, wchar_t>,
73 is_same<_Ch, char16_t>, is_same<_Ch, char32_t>>;
641cb5a6
JW
74
75 template<typename _Iter,
76 typename _Iter_traits = std::iterator_traits<_Iter>>
77 using __is_path_iter_src
78 = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
79 std::is_base_of<std::input_iterator_tag,
80 typename _Iter_traits::iterator_category>>;
81
82 template<typename _Iter>
83 static __is_path_iter_src<_Iter>
84 __is_path_src(_Iter, int);
85
86 template<typename _CharT, typename _Traits, typename _Alloc>
87 static __is_encoded_char<_CharT>
88 __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
89
90 template<typename _CharT, typename _Traits>
91 static __is_encoded_char<_CharT>
92 __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
93
94 template<typename _Unknown>
95 static std::false_type
96 __is_path_src(const _Unknown&, ...);
97
98 template<typename _Tp1, typename _Tp2>
99 struct __constructible_from;
100
101 template<typename _Iter>
102 struct __constructible_from<_Iter, _Iter>
103 : __is_path_iter_src<_Iter>
104 { };
105
106 template<typename _Source>
107 struct __constructible_from<_Source, void>
108 : decltype(__is_path_src(std::declval<_Source>(), 0))
109 { };
110
111 template<typename _Tp1, typename _Tp2 = void>
112 using _Path = typename
6b7c0b55
JW
113 std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
114 __not_<is_void<_Tp1>>,
641cb5a6
JW
115 __constructible_from<_Tp1, _Tp2>>::value,
116 path>::type;
117
118 template<typename _Source>
119 static _Source
120 _S_range_begin(_Source __begin) { return __begin; }
121
122 struct __null_terminated { };
123
124 template<typename _Source>
125 static __null_terminated
126 _S_range_end(_Source) { return {}; }
127
128 template<typename _CharT, typename _Traits, typename _Alloc>
129 static const _CharT*
130 _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
131 { return __str.data(); }
132
133 template<typename _CharT, typename _Traits, typename _Alloc>
134 static const _CharT*
135 _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
136 { return __str.data() + __str.size(); }
137
138 template<typename _CharT, typename _Traits>
139 static const _CharT*
140 _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
141 { return __str.data(); }
142
143 template<typename _CharT, typename _Traits>
144 static const _CharT*
145 _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
146 { return __str.data() + __str.size(); }
147
148 template<typename _Tp,
149 typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
150 typename _Val = typename std::iterator_traits<_Iter>::value_type>
151 using __value_type_is_char
49d729ea 152 = std::enable_if_t<std::is_same_v<std::remove_const_t<_Val>, char>>;
641cb5a6
JW
153
154 public:
155#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
156 typedef wchar_t value_type;
157 static constexpr value_type preferred_separator = L'\\';
158#else
159 typedef char value_type;
160 static constexpr value_type preferred_separator = '/';
161#endif
162 typedef std::basic_string<value_type> string_type;
163
0348dd00
JW
164 enum format { native_format, generic_format, auto_format };
165
641cb5a6
JW
166 // constructors and destructor
167
168 path() noexcept { }
169
170 path(const path& __p) = default;
171
172 path(path&& __p) noexcept
173 : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
174 {
175 _M_split_cmpts();
176 __p.clear();
177 }
178
0348dd00 179 path(string_type&& __source, format = auto_format)
641cb5a6
JW
180 : _M_pathname(std::move(__source))
181 { _M_split_cmpts(); }
182
183 template<typename _Source,
184 typename _Require = _Path<_Source>>
0348dd00 185 path(_Source const& __source, format = auto_format)
641cb5a6
JW
186 : _M_pathname(_S_convert(_S_range_begin(__source),
187 _S_range_end(__source)))
188 { _M_split_cmpts(); }
189
190 template<typename _InputIterator,
191 typename _Require = _Path<_InputIterator, _InputIterator>>
0348dd00 192 path(_InputIterator __first, _InputIterator __last, format = auto_format)
641cb5a6
JW
193 : _M_pathname(_S_convert(__first, __last))
194 { _M_split_cmpts(); }
195
196 template<typename _Source,
197 typename _Require = _Path<_Source>,
198 typename _Require2 = __value_type_is_char<_Source>>
0348dd00 199 path(_Source const& __source, const locale& __loc, format = auto_format)
641cb5a6
JW
200 : _M_pathname(_S_convert_loc(_S_range_begin(__source),
201 _S_range_end(__source), __loc))
202 { _M_split_cmpts(); }
203
204 template<typename _InputIterator,
205 typename _Require = _Path<_InputIterator, _InputIterator>,
206 typename _Require2 = __value_type_is_char<_InputIterator>>
0348dd00
JW
207 path(_InputIterator __first, _InputIterator __last, const locale& __loc,
208 format = auto_format)
641cb5a6
JW
209 : _M_pathname(_S_convert_loc(__first, __last, __loc))
210 { _M_split_cmpts(); }
211
212 ~path() = default;
213
214 // assignments
215
216 path& operator=(const path& __p) = default;
217 path& operator=(path&& __p) noexcept;
218 path& operator=(string_type&& __source);
219 path& assign(string_type&& __source);
220
221 template<typename _Source>
222 _Path<_Source>&
223 operator=(_Source const& __source)
224 { return *this = path(__source); }
225
226 template<typename _Source>
227 _Path<_Source>&
228 assign(_Source const& __source)
229 { return *this = path(__source); }
230
231 template<typename _InputIterator>
232 _Path<_InputIterator, _InputIterator>&
233 assign(_InputIterator __first, _InputIterator __last)
234 { return *this = path(__first, __last); }
235
236 // appends
237
9534a5e6 238 path& operator/=(const path& __p);
641cb5a6
JW
239
240 template <class _Source>
241 _Path<_Source>&
242 operator/=(_Source const& __source)
6cda876d 243 { return _M_append(path(__source)); }
641cb5a6
JW
244
245 template<typename _Source>
246 _Path<_Source>&
247 append(_Source const& __source)
6cda876d 248 { return _M_append(path(__source)); }
641cb5a6
JW
249
250 template<typename _InputIterator>
251 _Path<_InputIterator, _InputIterator>&
252 append(_InputIterator __first, _InputIterator __last)
6cda876d 253 { return _M_append(path(__first, __last)); }
641cb5a6
JW
254
255 // concatenation
256
257 path& operator+=(const path& __x);
258 path& operator+=(const string_type& __x);
259 path& operator+=(const value_type* __x);
260 path& operator+=(value_type __x);
261 path& operator+=(basic_string_view<value_type> __x);
262
263 template<typename _Source>
264 _Path<_Source>&
265 operator+=(_Source const& __x) { return concat(__x); }
266
267 template<typename _CharT>
268 _Path<_CharT*, _CharT*>&
269 operator+=(_CharT __x);
270
271 template<typename _Source>
272 _Path<_Source>&
273 concat(_Source const& __x)
274 { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
275
276 template<typename _InputIterator>
277 _Path<_InputIterator, _InputIterator>&
278 concat(_InputIterator __first, _InputIterator __last)
279 { return *this += _S_convert(__first, __last); }
280
281 // modifiers
282
283 void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
284
285 path& make_preferred();
286 path& remove_filename();
287 path& replace_filename(const path& __replacement);
288 path& replace_extension(const path& __replacement = path());
289
290 void swap(path& __rhs) noexcept;
291
292 // native format observers
293
294 const string_type& native() const noexcept { return _M_pathname; }
295 const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
296 operator string_type() const { return _M_pathname; }
297
298 template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
299 typename _Allocator = std::allocator<_CharT>>
300 std::basic_string<_CharT, _Traits, _Allocator>
301 string(const _Allocator& __a = _Allocator()) const;
302
303 std::string string() const;
304#if _GLIBCXX_USE_WCHAR_T
305 std::wstring wstring() const;
306#endif
307 std::string u8string() const;
308 std::u16string u16string() const;
309 std::u32string u32string() const;
310
311 // generic format observers
312 template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
313 typename _Allocator = std::allocator<_CharT>>
314 std::basic_string<_CharT, _Traits, _Allocator>
315 generic_string(const _Allocator& __a = _Allocator()) const;
316
317 std::string generic_string() const;
318#if _GLIBCXX_USE_WCHAR_T
319 std::wstring generic_wstring() const;
320#endif
321 std::string generic_u8string() const;
322 std::u16string generic_u16string() const;
323 std::u32string generic_u32string() const;
324
325 // compare
326
327 int compare(const path& __p) const noexcept;
328 int compare(const string_type& __s) const;
329 int compare(const value_type* __s) const;
330 int compare(const basic_string_view<value_type> __s) const;
331
332 // decomposition
333
334 path root_name() const;
335 path root_directory() const;
336 path root_path() const;
337 path relative_path() const;
338 path parent_path() const;
339 path filename() const;
340 path stem() const;
341 path extension() const;
342
343 // query
344
d69f1ec7 345 [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); }
641cb5a6
JW
346 bool has_root_name() const;
347 bool has_root_directory() const;
348 bool has_root_path() const;
349 bool has_relative_path() const;
350 bool has_parent_path() const;
351 bool has_filename() const;
352 bool has_stem() const;
353 bool has_extension() const;
9534a5e6 354 bool is_absolute() const;
641cb5a6
JW
355 bool is_relative() const { return !is_absolute(); }
356
357 // generation
358 path lexically_normal() const;
359 path lexically_relative(const path& base) const;
360 path lexically_proximate(const path& base) const;
361
362 // iterators
363 class iterator;
364 typedef iterator const_iterator;
365
366 iterator begin() const;
367 iterator end() const;
368
b0874c66
JW
369 /// Write a path to a stream
370 template<typename _CharT, typename _Traits>
371 friend std::basic_ostream<_CharT, _Traits>&
372 operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p)
373 {
374 __os << std::quoted(__p.string<_CharT, _Traits>());
375 return __os;
376 }
377
378 /// Read a path from a stream
379 template<typename _CharT, typename _Traits>
380 friend std::basic_istream<_CharT, _Traits>&
381 operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p)
382 {
383 std::basic_string<_CharT, _Traits> __tmp;
384 if (__is >> std::quoted(__tmp))
385 __p = std::move(__tmp);
386 return __is;
387 }
388
49d729ea
JW
389 // Create a basic_string by reading until a null character.
390 template<typename _InputIterator,
391 typename _Traits = std::iterator_traits<_InputIterator>,
392 typename _CharT
393 = typename std::remove_cv_t<typename _Traits::value_type>>
394 static std::basic_string<_CharT>
395 _S_string_from_iter(_InputIterator __source)
396 {
397 std::basic_string<_CharT> __str;
398 for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
399 __str.push_back(__ch);
400 return __str;
401 }
402
641cb5a6
JW
403 private:
404 enum class _Type : unsigned char {
405 _Multi, _Root_name, _Root_dir, _Filename
406 };
407
408 path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
409 {
410 __glibcxx_assert(_M_type != _Type::_Multi);
411 }
412
413 enum class _Split { _Stem, _Extension };
414
9534a5e6 415 path& _M_append(path __p);
641cb5a6
JW
416
417 pair<const string_type*, size_t> _M_find_extension() const;
418
419 template<typename _CharT>
420 struct _Cvt;
421
422 static string_type
423 _S_convert(value_type* __src, __null_terminated)
424 { return string_type(__src); }
425
426 static string_type
427 _S_convert(const value_type* __src, __null_terminated)
428 { return string_type(__src); }
429
430 template<typename _Iter>
431 static string_type
432 _S_convert(_Iter __first, _Iter __last)
433 {
434 using __value_type = typename std::iterator_traits<_Iter>::value_type;
435 return _Cvt<typename remove_cv<__value_type>::type>::
436 _S_convert(__first, __last);
437 }
438
439 template<typename _InputIterator>
440 static string_type
441 _S_convert(_InputIterator __src, __null_terminated)
442 {
49d729ea
JW
443 auto __s = _S_string_from_iter(__src);
444 return _S_convert(__s.c_str(), __s.c_str() + __s.size());
641cb5a6
JW
445 }
446
447 static string_type
448 _S_convert_loc(const char* __first, const char* __last,
449 const std::locale& __loc);
450
451 template<typename _Iter>
452 static string_type
453 _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
454 {
455 const std::string __str(__first, __last);
456 return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
457 }
458
459 template<typename _InputIterator>
460 static string_type
461 _S_convert_loc(_InputIterator __src, __null_terminated,
462 const std::locale& __loc)
463 {
49d729ea
JW
464 std::string __s = _S_string_from_iter(__src);
465 return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
641cb5a6
JW
466 }
467
468 template<typename _CharT, typename _Traits, typename _Allocator>
469 static basic_string<_CharT, _Traits, _Allocator>
470 _S_str_convert(const string_type&, const _Allocator& __a);
471
472 bool _S_is_dir_sep(value_type __ch)
473 {
474#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
475 return __ch == L'/' || __ch == preferred_separator;
476#else
477 return __ch == '/';
478#endif
479 }
480
481 void _M_split_cmpts();
482 void _M_trim();
483 void _M_add_root_name(size_t __n);
484 void _M_add_root_dir(size_t __pos);
485 void _M_add_filename(size_t __pos, size_t __n);
486
487 string_type _M_pathname;
488
489 struct _Cmpt;
490 using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
491 _List _M_cmpts; // empty unless _M_type == _Type::_Multi
cf290ea3 492 _Type _M_type = _Type::_Filename;
641cb5a6
JW
493 };
494
641cb5a6
JW
495 inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
496
497 size_t hash_value(const path& __p) noexcept;
498
499 /// Compare paths
500 inline bool operator<(const path& __lhs, const path& __rhs) noexcept
501 { return __lhs.compare(__rhs) < 0; }
502
503 /// Compare paths
504 inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
505 { return !(__rhs < __lhs); }
506
507 /// Compare paths
508 inline bool operator>(const path& __lhs, const path& __rhs) noexcept
509 { return __rhs < __lhs; }
510
511 /// Compare paths
512 inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
513 { return !(__lhs < __rhs); }
514
515 /// Compare paths
516 inline bool operator==(const path& __lhs, const path& __rhs) noexcept
517 { return __lhs.compare(__rhs) == 0; }
518
519 /// Compare paths
520 inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
521 { return !(__lhs == __rhs); }
522
523 /// Append one path to another
524 inline path operator/(const path& __lhs, const path& __rhs)
a989f637
JW
525 {
526 path __result(__lhs);
527 __result /= __rhs;
528 return __result;
529 }
641cb5a6 530
9534a5e6 531 template<typename _InputIterator>
641cb5a6 532 inline auto
9534a5e6
JW
533 u8path(_InputIterator __first, _InputIterator __last)
534 -> decltype(filesystem::path(__first, __last, std::locale::classic()))
641cb5a6
JW
535 {
536#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
9534a5e6
JW
537 codecvt_utf8<path::value_type> __cvt;
538 path::string_type __tmp;
539 if constexpr (is_pointer_v<_InputIterator>)
540 {
541 if (__str_codecvt_in(__first, __last, __tmp, __cvt))
542 return path{ __tmp };
543 }
544 else
545 {
546 const std::string __u8str{__first, __last};
547 const char* const __ptr = __u8str.data();
548 if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
549 return path{ __tmp };
550 }
551 return {};
641cb5a6 552#else
9534a5e6 553 return path{ __first, __last };
641cb5a6
JW
554#endif
555 }
556
9534a5e6 557 template<typename _Source>
641cb5a6 558 inline auto
9534a5e6
JW
559 u8path(const _Source& __source)
560 -> decltype(filesystem::path(__source, std::locale::classic()))
641cb5a6
JW
561 {
562#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
9534a5e6
JW
563 if constexpr (is_convertible_v<const _Source&, std::string_view>)
564 {
565 const std::string_view __s = __source;
566 return filesystem::u8path(__s.data(), __s.data() + __s.size());
567 }
641cb5a6 568 else
9534a5e6
JW
569 {
570 std::string __s = path::_S_string_from_iter(__source);
571 return filesystem::u8path(__s.data(), __s.data() + __s.size());
572 }
641cb5a6 573#else
9534a5e6 574 return path{ __source };
641cb5a6
JW
575#endif
576 }
577
578 class filesystem_error : public std::system_error
579 {
580 public:
24d9b090 581 filesystem_error(const string& __what_arg, error_code __ec);
641cb5a6
JW
582
583 filesystem_error(const string& __what_arg, const path& __p1,
24d9b090 584 error_code __ec);
641cb5a6
JW
585
586 filesystem_error(const string& __what_arg, const path& __p1,
24d9b090
JW
587 const path& __p2, error_code __ec);
588
589 filesystem_error(const filesystem_error&) = default;
590 filesystem_error& operator=(const filesystem_error&) = default;
591
592 // No move constructor or assignment operator.
593 // Copy rvalues instead, so that _M_impl is not left empty.
641cb5a6
JW
594
595 ~filesystem_error();
596
24d9b090
JW
597 const path& path1() const noexcept;
598 const path& path2() const noexcept;
599 const char* what() const noexcept;
641cb5a6
JW
600
601 private:
24d9b090
JW
602 struct _Impl;
603 std::__shared_ptr<const _Impl> _M_impl;
641cb5a6
JW
604 };
605
606 struct path::_Cmpt : path
607 {
608 _Cmpt(string_type __s, _Type __t, size_t __pos)
609 : path(std::move(__s), __t), _M_pos(__pos) { }
610
611 _Cmpt() : _M_pos(-1) { }
612
613 size_t _M_pos;
614 };
615
616 // specialize _Cvt for degenerate 'noconv' case
617 template<>
618 struct path::_Cvt<path::value_type>
619 {
620 template<typename _Iter>
621 static string_type
622 _S_convert(_Iter __first, _Iter __last)
623 { return string_type{__first, __last}; }
624 };
625
626 template<typename _CharT>
627 struct path::_Cvt
628 {
629#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
630 static string_type
631 _S_wconvert(const char* __f, const char* __l, true_type)
632 {
633 using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
634 const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
635 std::wstring __wstr;
636 if (__str_codecvt_in(__f, __l, __wstr, __cvt))
637 return __wstr;
638 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
639 "Cannot convert character sequence",
640 std::make_error_code(errc::illegal_byte_sequence)));
641 }
642
643 static string_type
644 _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
645 {
646 std::codecvt_utf8<_CharT> __cvt;
647 std::string __str;
648 if (__str_codecvt_out(__f, __l, __str, __cvt))
649 {
650 const char* __f2 = __str.data();
651 const char* __l2 = __f2 + __str.size();
652 std::codecvt_utf8<wchar_t> __wcvt;
653 std::wstring __wstr;
654 if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
655 return __wstr;
656 }
657 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
658 "Cannot convert character sequence",
659 std::make_error_code(errc::illegal_byte_sequence)));
660 }
661
662 static string_type
663 _S_convert(const _CharT* __f, const _CharT* __l)
664 {
665 return _S_wconvert(__f, __l, is_same<_CharT, char>{});
666 }
667#else
668 static string_type
669 _S_convert(const _CharT* __f, const _CharT* __l)
670 {
671 std::codecvt_utf8<_CharT> __cvt;
672 std::string __str;
673 if (__str_codecvt_out(__f, __l, __str, __cvt))
674 return __str;
675 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
676 "Cannot convert character sequence",
677 std::make_error_code(errc::illegal_byte_sequence)));
678 }
679#endif
680
681 static string_type
682 _S_convert(_CharT* __f, _CharT* __l)
683 {
684 return _S_convert(const_cast<const _CharT*>(__f),
685 const_cast<const _CharT*>(__l));
686 }
687
688 template<typename _Iter>
689 static string_type
690 _S_convert(_Iter __first, _Iter __last)
691 {
692 const std::basic_string<_CharT> __str(__first, __last);
693 return _S_convert(__str.data(), __str.data() + __str.size());
694 }
695
696 template<typename _Iter, typename _Cont>
697 static string_type
698 _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
699 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
700 { return _S_convert(__first.base(), __last.base()); }
701 };
702
703 /// An iterator for the components of a path
704 class path::iterator
705 {
706 public:
707 using difference_type = std::ptrdiff_t;
708 using value_type = path;
709 using reference = const path&;
710 using pointer = const path*;
711 using iterator_category = std::bidirectional_iterator_tag;
712
713 iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
714
715 iterator(const iterator&) = default;
716 iterator& operator=(const iterator&) = default;
717
718 reference operator*() const;
719 pointer operator->() const { return std::__addressof(**this); }
720
721 iterator& operator++();
722 iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
723
724 iterator& operator--();
725 iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
726
727 friend bool operator==(const iterator& __lhs, const iterator& __rhs)
728 { return __lhs._M_equals(__rhs); }
729
730 friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
731 { return !__lhs._M_equals(__rhs); }
732
733 private:
734 friend class path;
735
736 iterator(const path* __path, path::_List::const_iterator __iter)
737 : _M_path(__path), _M_cur(__iter), _M_at_end()
738 { }
739
740 iterator(const path* __path, bool __at_end)
741 : _M_path(__path), _M_cur(), _M_at_end(__at_end)
742 { }
743
744 bool _M_equals(iterator) const;
745
746 const path* _M_path;
747 path::_List::const_iterator _M_cur;
748 bool _M_at_end; // only used when type != _Multi
749 };
750
751
752 inline path&
753 path::operator=(path&& __p) noexcept
754 {
755 _M_pathname = std::move(__p._M_pathname);
756 _M_cmpts = std::move(__p._M_cmpts);
757 _M_type = __p._M_type;
758 __p.clear();
759 return *this;
760 }
761
762 inline path&
763 path::operator=(string_type&& __source)
764 { return *this = path(std::move(__source)); }
765
766 inline path&
767 path::assign(string_type&& __source)
768 { return *this = path(std::move(__source)); }
769
770 inline path&
771 path::operator+=(const path& __p)
772 {
773 return operator+=(__p.native());
774 }
775
776 inline path&
777 path::operator+=(const string_type& __x)
778 {
779 _M_pathname += __x;
780 _M_split_cmpts();
781 return *this;
782 }
783
784 inline path&
785 path::operator+=(const value_type* __x)
786 {
787 _M_pathname += __x;
788 _M_split_cmpts();
789 return *this;
790 }
791
792 inline path&
793 path::operator+=(value_type __x)
794 {
795 _M_pathname += __x;
796 _M_split_cmpts();
797 return *this;
798 }
799
800 inline path&
801 path::operator+=(basic_string_view<value_type> __x)
802 {
803 _M_pathname.append(__x.data(), __x.size());
804 _M_split_cmpts();
805 return *this;
806 }
807
808 template<typename _CharT>
809 inline path::_Path<_CharT*, _CharT*>&
810 path::operator+=(_CharT __x)
811 {
812 auto* __addr = std::__addressof(__x);
813 return concat(__addr, __addr + 1);
814 }
815
816 inline path&
817 path::make_preferred()
818 {
819#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
820 std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
821 preferred_separator);
822#endif
823 return *this;
824 }
825
826 inline void path::swap(path& __rhs) noexcept
827 {
828 _M_pathname.swap(__rhs._M_pathname);
829 _M_cmpts.swap(__rhs._M_cmpts);
830 std::swap(_M_type, __rhs._M_type);
831 }
832
833 template<typename _CharT, typename _Traits, typename _Allocator>
834 std::basic_string<_CharT, _Traits, _Allocator>
835 path::_S_str_convert(const string_type& __str, const _Allocator& __a)
836 {
837 if (__str.size() == 0)
838 return std::basic_string<_CharT, _Traits, _Allocator>(__a);
839
840 const value_type* __first = __str.data();
841 const value_type* __last = __first + __str.size();
842
843#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
844 using _CharAlloc = __alloc_rebind<_Allocator, char>;
845 using _String = basic_string<char, char_traits<char>, _CharAlloc>;
846 using _WString = basic_string<_CharT, _Traits, _Allocator>;
847
848 // use codecvt_utf8<wchar_t> to convert native string to UTF-8
849 codecvt_utf8<value_type> __cvt;
850 _String __u8str{_CharAlloc{__a}};
851 if (__str_codecvt_out(__first, __last, __u8str, __cvt))
852 {
853 if constexpr (is_same_v<_CharT, char>)
854 return __u8str;
855 else
856 {
857 _WString __wstr;
858 // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
859 codecvt_utf8<_CharT> __cvt;
860 const char* __f = __u8str.data();
861 const char* __l = __f + __u8str.size();
862 if (__str_codecvt_in(__f, __l, __wstr, __cvt))
863 return __wstr;
864 }
865 }
866#else
867 codecvt_utf8<_CharT> __cvt;
868 basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
869 if (__str_codecvt_in(__first, __last, __wstr, __cvt))
870 return __wstr;
871#endif
872 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
873 "Cannot convert character sequence",
874 std::make_error_code(errc::illegal_byte_sequence)));
875 }
876
877 template<typename _CharT, typename _Traits, typename _Allocator>
878 inline basic_string<_CharT, _Traits, _Allocator>
879 path::string(const _Allocator& __a) const
880 {
881 if constexpr (is_same_v<_CharT, value_type>)
49d729ea 882 {
641cb5a6 883#if _GLIBCXX_USE_CXX11_ABI
49d729ea 884 return { _M_pathname, __a };
641cb5a6 885#else
49d729ea
JW
886 if constexpr (is_same_v<_Allocator, string_type::allocator_type>)
887 return _M_pathname;
888 else
889 return { _M_pathname, string_type::size_type(0), __a };
641cb5a6 890#endif
49d729ea 891 }
641cb5a6
JW
892 else
893 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
894 }
895
896 inline std::string
897 path::string() const { return string<char>(); }
898
899#if _GLIBCXX_USE_WCHAR_T
900 inline std::wstring
901 path::wstring() const { return string<wchar_t>(); }
902#endif
903
904 inline std::string
905 path::u8string() const
906 {
907#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
908 std::string __str;
909 // convert from native encoding to UTF-8
910 codecvt_utf8<value_type> __cvt;
911 const value_type* __first = _M_pathname.data();
912 const value_type* __last = __first + _M_pathname.size();
913 if (__str_codecvt_out(__first, __last, __str, __cvt))
914 return __str;
915 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
916 "Cannot convert character sequence",
917 std::make_error_code(errc::illegal_byte_sequence)));
918#else
919 return _M_pathname;
920#endif
921 }
922
923 inline std::u16string
924 path::u16string() const { return string<char16_t>(); }
925
926 inline std::u32string
927 path::u32string() const { return string<char32_t>(); }
928
929 template<typename _CharT, typename _Traits, typename _Allocator>
930 inline std::basic_string<_CharT, _Traits, _Allocator>
931 path::generic_string(const _Allocator& __a) const
932 {
933#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
934 const value_type __slash = L'/';
935#else
936 const value_type __slash = '/';
937#endif
938 string_type __str(__a);
939
940 if (_M_type == _Type::_Root_dir)
941 __str.assign(1, __slash);
942 else
943 {
944 __str.reserve(_M_pathname.size());
945 bool __add_slash = false;
946 for (auto& __elem : *this)
947 {
948 if (__add_slash)
949 __str += __slash;
950 __str += __elem._M_pathname;
951 __add_slash = __elem._M_type == _Type::_Filename;
952 }
953 }
954
955 if constexpr (is_same_v<_CharT, value_type>)
956 return __str;
957 else
958 return _S_str_convert<_CharT, _Traits>(__str, __a);
959 }
960
961 inline std::string
962 path::generic_string() const
963 { return generic_string<char>(); }
964
965#if _GLIBCXX_USE_WCHAR_T
966 inline std::wstring
967 path::generic_wstring() const
968 { return generic_string<wchar_t>(); }
969#endif
970
971 inline std::string
972 path::generic_u8string() const
973 { return generic_string(); }
974
975 inline std::u16string
976 path::generic_u16string() const
977 { return generic_string<char16_t>(); }
978
979 inline std::u32string
980 path::generic_u32string() const
981 { return generic_string<char32_t>(); }
982
983 inline int
984 path::compare(const string_type& __s) const { return compare(path(__s)); }
985
986 inline int
987 path::compare(const value_type* __s) const { return compare(path(__s)); }
988
989 inline int
990 path::compare(basic_string_view<value_type> __s) const
991 { return compare(path(__s)); }
992
993 inline path
994 path::filename() const
995 {
996 if (empty())
997 return {};
998 else if (_M_type == _Type::_Filename)
999 return *this;
1000 else if (_M_type == _Type::_Multi)
1001 {
1002 if (_M_pathname.back() == preferred_separator)
1003 return {};
1004 auto& __last = *--end();
1005 if (__last._M_type == _Type::_Filename)
1006 return __last;
1007 }
1008 return {};
1009 }
1010
1011 inline path
1012 path::stem() const
1013 {
1014 auto ext = _M_find_extension();
1015 if (ext.first && ext.second != 0)
1016 return path{ext.first->substr(0, ext.second)};
1017 return {};
1018 }
1019
1020 inline path
1021 path::extension() const
1022 {
1023 auto ext = _M_find_extension();
1024 if (ext.first && ext.second != string_type::npos)
1025 return path{ext.first->substr(ext.second)};
1026 return {};
1027 }
1028
1029 inline bool
1030 path::has_stem() const
1031 {
1032 auto ext = _M_find_extension();
1033 return ext.first && ext.second != 0;
1034 }
1035
1036 inline bool
1037 path::has_extension() const
1038 {
1039 auto ext = _M_find_extension();
1040 return ext.first && ext.second != string_type::npos;
1041 }
1042
9534a5e6
JW
1043 inline bool
1044 path::is_absolute() const
1045 {
1046#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1047 return has_root_name() && has_root_directory();
1048#else
1049 return has_root_directory();
1050#endif
1051 }
1052
641cb5a6
JW
1053 inline path::iterator
1054 path::begin() const
1055 {
1056 if (_M_type == _Type::_Multi)
1057 return iterator(this, _M_cmpts.begin());
cf290ea3 1058 return iterator(this, empty());
641cb5a6
JW
1059 }
1060
1061 inline path::iterator
1062 path::end() const
1063 {
1064 if (_M_type == _Type::_Multi)
1065 return iterator(this, _M_cmpts.end());
1066 return iterator(this, true);
1067 }
1068
9534a5e6
JW
1069#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1070 inline path& path::operator/=(const path& __p)
1071 {
1072 // Much simpler than the specification in the standard,
1073 // as any path with root-name or root-dir is absolute.
1074 if (__p.is_absolute())
1075 operator=(__p);
1076 else
1077 {
1078 if (has_filename() || (_M_type == _Type::_Root_name))
1079 _M_pathname += preferred_separator;
1080 _M_pathname += __p.native();
1081 _M_split_cmpts();
1082 }
1083 return *this;
1084 }
1085#endif
1086
1087 inline path&
1088 path::_M_append(path __p)
1089 {
1090 if (__p.is_absolute())
1091 operator=(std::move(__p));
1092#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1093 else if (__p.has_root_name() && __p.root_name() != root_name())
1094 operator=(std::move(__p));
1095#endif
1096 else
1097 operator/=(const_cast<const path&>(__p));
1098 return *this;
1099 }
1100
641cb5a6
JW
1101 inline path::iterator&
1102 path::iterator::operator++()
1103 {
1104 __glibcxx_assert(_M_path != nullptr);
1105 if (_M_path->_M_type == _Type::_Multi)
1106 {
1107 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1108 ++_M_cur;
1109 }
1110 else
1111 {
1112 __glibcxx_assert(!_M_at_end);
1113 _M_at_end = true;
1114 }
1115 return *this;
1116 }
1117
1118 inline path::iterator&
1119 path::iterator::operator--()
1120 {
1121 __glibcxx_assert(_M_path != nullptr);
1122 if (_M_path->_M_type == _Type::_Multi)
1123 {
1124 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
1125 --_M_cur;
1126 }
1127 else
1128 {
1129 __glibcxx_assert(_M_at_end);
1130 _M_at_end = false;
1131 }
1132 return *this;
1133 }
1134
1135 inline path::iterator::reference
1136 path::iterator::operator*() const
1137 {
1138 __glibcxx_assert(_M_path != nullptr);
1139 if (_M_path->_M_type == _Type::_Multi)
1140 {
1141 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
1142 return *_M_cur;
1143 }
1144 return *_M_path;
1145 }
1146
1147 inline bool
1148 path::iterator::_M_equals(iterator __rhs) const
1149 {
1150 if (_M_path != __rhs._M_path)
1151 return false;
1152 if (_M_path == nullptr)
1153 return true;
1154 if (_M_path->_M_type == path::_Type::_Multi)
1155 return _M_cur == __rhs._M_cur;
1156 return _M_at_end == __rhs._M_at_end;
1157 }
1158
1159 // @} group filesystem
1160_GLIBCXX_END_NAMESPACE_CXX11
1161} // namespace filesystem
1162
24d9b090
JW
1163extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
1164
641cb5a6
JW
1165_GLIBCXX_END_NAMESPACE_VERSION
1166} // namespace std
1167
1168#endif // C++17
1169
1170#endif // _GLIBCXX_FS_PATH_H