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 typename _Tp1_nocv = typename remove_cv<_Tp1>::type, 125 typename _Tp1_noptr = typename remove_pointer<_Tp1>::type> 126 using _Path = typename 127 std::enable_if<__and_<__not_<is_same<_Tp1_nocv, path>>, 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 168 = typename std::enable_if<std::is_same<_Val, char>::value>::type; 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>> 319 std::basic_string<_CharT, _Traits, _Allocator> 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; 327 std::u16string u16string() const; 328 std::u32string u32string() const; 329 330 // generic format observers 331 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 332 typename _Allocator = std::allocator<_CharT>> 333 std::basic_string<_CharT, _Traits, _Allocator> 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; 435 std::basic_string<typename remove_cv<_Tp>::type> __tmp; 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> 525 basic_ostream<_CharT, _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> 537 basic_istream<_CharT, _Traits>& 538 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) 539 { 540 basic_string<_CharT, _Traits> __tmp; 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 { 647 using _Cvt = std::codecvt<wchar_t, char, mbstate_t>; 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 718 class path::iterator 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*; 725 using iterator_category = std::bidirectional_iterator_tag; 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> 850 inline std::basic_string<_CharT, _Traits, _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 #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS 936 template<typename _CharT, typename _Traits, typename _Allocator> 937 inline std::basic_string<_CharT, _Traits, _Allocator> 938 path::generic_string(const _Allocator& __a) const 939 { return string<_CharT, _Traits, _Allocator>(__a); } 940 941 inline std::string 942 path::generic_string() const { return string(); } 943 944 #if _GLIBCXX_USE_WCHAR_T 945 inline std::wstring 946 path::generic_wstring() const { return wstring(); } 947 #endif 948 949 inline std::string 950 path::generic_u8string() const { return u8string(); } 951 952 inline std::u16string 953 path::generic_u16string() const { return u16string(); } 954 955 inline std::u32string 956 path::generic_u32string() const { return u32string(); } 957 #endif 958 959 inline int 960 path::compare(const string_type& __s) const { return compare(path(__s)); } 961 962 inline int 963 path::compare(const value_type* __s) const { return compare(path(__s)); } 964 965 #if __cplusplus >= 201402L 966 inline int 967 path::compare(basic_string_view<value_type> __s) const 968 { return compare(path(__s)); } 969 #endif 970 971 inline path 972 path::filename() const { return empty() ? path() : *--end(); } 973 974 inline path 975 path::stem() const 976 { 977 auto ext = _M_find_extension(); 978 if (ext.first && ext.second != 0) 979 return path{ext.first->substr(0, ext.second)}; 980 return {}; 981 } 982 983 inline path 984 path::extension() const 985 { 986 auto ext = _M_find_extension(); 987 if (ext.first && ext.second != string_type::npos) 988 return path{ext.first->substr(ext.second)}; 989 return {}; 990 } 991 992 inline bool 993 path::has_stem() const 994 { 995 auto ext = _M_find_extension(); 996 return ext.first && ext.second != 0; 997 } 998 999 inline bool 1000 path::has_extension() const 1001 { 1002 auto ext = _M_find_extension(); 1003 return ext.first && ext.second != string_type::npos; 1004 } 1005 1006 inline path::iterator 1007 path::begin() const 1008 { 1009 if (_M_type == _Type::_Multi) 1010 return iterator(this, _M_cmpts.begin()); 1011 return iterator(this, false); 1012 } 1013 1014 inline path::iterator 1015 path::end() const 1016 { 1017 if (_M_type == _Type::_Multi) 1018 return iterator(this, _M_cmpts.end()); 1019 return iterator(this, true); 1020 } 1021 1022 inline path::iterator& 1023 path::iterator::operator++() 1024 { 1025 __glibcxx_assert(_M_path != nullptr); 1026 if (_M_path->_M_type == _Type::_Multi) 1027 { 1028 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 1029 ++_M_cur; 1030 } 1031 else 1032 { 1033 __glibcxx_assert(!_M_at_end); 1034 _M_at_end = true; 1035 } 1036 return *this; 1037 } 1038 1039 inline path::iterator& 1040 path::iterator::operator--() 1041 { 1042 __glibcxx_assert(_M_path != nullptr); 1043 if (_M_path->_M_type == _Type::_Multi) 1044 { 1045 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); 1046 --_M_cur; 1047 } 1048 else 1049 { 1050 __glibcxx_assert(_M_at_end); 1051 _M_at_end = false; 1052 } 1053 return *this; 1054 } 1055 1056 inline path::iterator::reference 1057 path::iterator::operator*() const 1058 { 1059 __glibcxx_assert(_M_path != nullptr); 1060 if (_M_path->_M_type == _Type::_Multi) 1061 { 1062 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 1063 return *_M_cur; 1064 } 1065 return *_M_path; 1066 } 1067 1068 inline bool 1069 path::iterator::_M_equals(iterator __rhs) const 1070 { 1071 if (_M_path != __rhs._M_path) 1072 return false; 1073 if (_M_path == nullptr) 1074 return true; 1075 if (_M_path->_M_type == path::_Type::_Multi) 1076 return _M_cur == __rhs._M_cur; 1077 return _M_at_end == __rhs._M_at_end; 1078 } 1079 1080 // @} group filesystem-ts 1081 _GLIBCXX_END_NAMESPACE_CXX11 1082 } // namespace v1 1083 } // namespace filesystem 1084 } // namespace experimental 1085 1086 _GLIBCXX_END_NAMESPACE_VERSION 1087 } // namespace std 1088 1089 #endif // C++11 1090 1091 #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1092