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