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