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