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