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