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