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