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