1 // Class filesystem::path -*- C++ -*- 2 3 // Copyright (C) 2014-2022 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 include/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{filesystem} 28 */ 29 30 #ifndef _GLIBCXX_FS_PATH_H 31 #define _GLIBCXX_FS_PATH_H 1 32 33 #if __cplusplus >= 201703L 34 35 #include <type_traits> 36 #include <locale> 37 #include <iosfwd> 38 #include <iomanip> 39 #include <codecvt> 40 #include <string_view> 41 #include <system_error> 42 #include <bits/stl_algobase.h> 43 #include <bits/stl_pair.h> 44 #include <bits/locale_conv.h> 45 #include <ext/concurrence.h> 46 #include <bits/shared_ptr.h> 47 #include <bits/unique_ptr.h> 48 49 #if __cplusplus > 201703L 50 # include <compare> 51 #endif 52 53 #if defined(_WIN32) && !defined(__CYGWIN__) 54 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 55 #endif 56 57 namespace std _GLIBCXX_VISIBILITY(default) 58 { 59 _GLIBCXX_BEGIN_NAMESPACE_VERSION 60 61 namespace filesystem 62 { 63 _GLIBCXX_BEGIN_NAMESPACE_CXX11 64 65 class path; 66 67 /// @cond undocumented 68 namespace __detail 69 { 70 /// @addtogroup filesystem 71 /// @{ 72 template<typename _CharT> 73 inline constexpr bool __is_encoded_char = false; 74 template<> 75 inline constexpr bool __is_encoded_char<char> = true; 76 #ifdef _GLIBCXX_USE_CHAR8_T 77 template<> 78 inline constexpr bool __is_encoded_char<char8_t> = true; 79 #endif 80 #if _GLIBCXX_USE_WCHAR_T 81 template<> 82 inline constexpr bool __is_encoded_char<wchar_t> = true; 83 #endif 84 template<> 85 inline constexpr bool __is_encoded_char<char16_t> = true; 86 template<> 87 inline constexpr bool __is_encoded_char<char32_t> = true; 88 89 #if __cpp_concepts >= 201907L 90 template<typename _Iter> 91 using __safe_iterator_traits = std::iterator_traits<_Iter>; 92 #else 93 template<typename _Iter> 94 struct __safe_iterator_traits : std::iterator_traits<_Iter> 95 { }; 96 97 // Protect against ill-formed iterator_traits specializations in C++17 98 template<> struct __safe_iterator_traits<void*> { }; 99 template<> struct __safe_iterator_traits<const void*> { }; 100 template<> struct __safe_iterator_traits<volatile void*> { }; 101 template<> struct __safe_iterator_traits<const volatile void*> { }; 102 #endif 103 104 template<typename _Iter_traits, typename = void> 105 inline constexpr bool __is_path_iter_src = false; 106 107 template<typename _Iter_traits> 108 inline constexpr bool 109 __is_path_iter_src<_Iter_traits, void_t<typename _Iter_traits::value_type>> 110 = __is_encoded_char<typename _Iter_traits::value_type>; 111 112 template<typename _Source> 113 inline constexpr bool __is_path_src 114 = __is_path_iter_src<iterator_traits<decay_t<_Source>>>; 115 116 template<> 117 inline constexpr bool __is_path_src<path> = false; 118 119 template<> 120 inline constexpr bool __is_path_src<volatile path> = false; 121 122 template<> 123 inline constexpr bool __is_path_src<void*> = false; 124 125 template<> 126 inline constexpr bool __is_path_src<const void*> = false; 127 128 template<> 129 inline constexpr bool __is_path_src<volatile void*> = false; 130 131 template<> 132 inline constexpr bool __is_path_src<const volatile void*> = false; 133 134 template<typename _CharT, typename _Traits, typename _Alloc> 135 inline constexpr bool 136 __is_path_src<basic_string<_CharT, _Traits, _Alloc>> 137 = __is_encoded_char<_CharT>; 138 139 template<typename _CharT, typename _Traits> 140 inline constexpr bool 141 __is_path_src<basic_string_view<_CharT, _Traits>> 142 = __is_encoded_char<_CharT>; 143 144 // SFINAE constraint for Source parameters as required by [fs.path.req]. 145 template<typename _Tp> 146 using _Path = enable_if_t<__is_path_src<_Tp>, path>; 147 148 // SFINAE constraint for InputIterator parameters as required by [fs.req]. 149 template<typename _Iter, typename _Tr = __safe_iterator_traits<_Iter>> 150 using _Path2 = enable_if_t<__is_path_iter_src<_Tr>, path>; 151 152 #if __cpp_lib_concepts 153 template<typename _Iter> 154 constexpr bool __is_contiguous = std::contiguous_iterator<_Iter>; 155 #else 156 template<typename _Iter> 157 constexpr bool __is_contiguous = false; 158 #endif 159 160 template<typename _Tp> 161 constexpr bool __is_contiguous<_Tp*> = true; 162 163 template<typename _Tp, typename _Seq> 164 constexpr bool 165 __is_contiguous<__gnu_cxx::__normal_iterator<_Tp*, _Seq>> = true; 166 167 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T 168 // For POSIX treat char8_t sequences as char without encoding conversions. 169 template<typename _EcharT> 170 using __unified_u8_t 171 = __conditional_t<is_same_v<_EcharT, char8_t>, char, _EcharT>; 172 #else 173 template<typename _EcharT> 174 using __unified_u8_t = _EcharT; 175 #endif 176 177 // The __effective_range overloads convert a Source parameter into 178 // either a basic_string_view<C> or basic_string<C> containing the 179 // effective range of the Source, as defined in [fs.path.req]. 180 181 template<typename _CharT, typename _Traits, typename _Alloc> 182 inline basic_string_view<_CharT> 183 __effective_range(const basic_string<_CharT, _Traits, _Alloc>& __source) 184 noexcept 185 { return __source; } 186 187 template<typename _CharT, typename _Traits> 188 inline basic_string_view<_CharT> 189 __effective_range(const basic_string_view<_CharT, _Traits>& __source) 190 noexcept 191 { return __source; } 192 193 // Return the effective range of an NTCTS. 194 template<typename _Source> 195 auto 196 __effective_range(const _Source& __source) 197 { 198 // Remove a level of normal/safe iterator indirection, or decay an array. 199 using _Iter = decltype(std::__niter_base(__source)); 200 using value_type = typename iterator_traits<_Iter>::value_type; 201 202 if constexpr (__is_contiguous<_Iter>) 203 return basic_string_view<value_type>{&*__source}; 204 else 205 { 206 // _Source is an input iterator that iterates over an NTCTS. 207 // Create a basic_string by reading until the null character. 208 basic_string<__unified_u8_t<value_type>> __str; 209 _Source __it = __source; 210 for (value_type __ch = *__it; __ch != value_type(); __ch = *++__it) 211 __str.push_back(__ch); 212 return __str; 213 } 214 } 215 216 // The value type of a Source parameter's effective range. 217 template<typename _Source> 218 struct __source_value_type_impl 219 { 220 using type 221 = typename __safe_iterator_traits<decay_t<_Source>>::value_type; 222 }; 223 224 template<typename _CharT, typename _Traits, typename _Alloc> 225 struct __source_value_type_impl<basic_string<_CharT, _Traits, _Alloc>> 226 { 227 using type = _CharT; 228 }; 229 230 template<typename _CharT, typename _Traits> 231 struct __source_value_type_impl<basic_string_view<_CharT, _Traits>> 232 { 233 using type = _CharT; 234 }; 235 236 // The value type of a Source parameter's effective range. 237 template<typename _Source> 238 using __source_value_t = typename __source_value_type_impl<_Source>::type; 239 240 // SFINAE helper to check that an effective range has value_type char, 241 // as required by path constructors taking a std::locale parameter. 242 // The type _Tp must have already been checked by _Path<Tp> or _Path2<_Tp>. 243 template<typename _Tp, typename _Val = __source_value_t<_Tp>> 244 using __value_type_is_char 245 = std::enable_if_t<std::is_same_v<_Val, char>, _Val>; 246 247 // As above, but also allows char8_t, as required by u8path 248 // C++20 [depr.fs.path.factory] 249 template<typename _Tp, typename _Val = __source_value_t<_Tp>> 250 using __value_type_is_char_or_char8_t 251 = std::enable_if_t<std::is_same_v<_Val, char> 252 #ifdef _GLIBCXX_USE_CHAR8_T 253 || std::is_same_v<_Val, char8_t> 254 #endif 255 , _Val>; 256 257 // Create a basic_string<C> or basic_string_view<C> from an iterator range. 258 template<typename _InputIterator> 259 inline auto 260 __string_from_range(_InputIterator __first, _InputIterator __last) 261 { 262 using _EcharT 263 = typename std::iterator_traits<_InputIterator>::value_type; 264 static_assert(__is_encoded_char<_EcharT>); // C++17 [fs.req]/3 265 266 if constexpr (__is_contiguous<_InputIterator>) 267 { 268 // For contiguous iterators we can just return a string view. 269 if (auto __len = __last - __first) [[__likely__]] 270 return basic_string_view<_EcharT>(&*__first, __len); 271 return basic_string_view<_EcharT>(); 272 } 273 else 274 { 275 // Conversion requires contiguous characters, so create a string. 276 return basic_string<__unified_u8_t<_EcharT>>(__first, __last); 277 } 278 } 279 280 /// @} group filesystem 281 } // namespace __detail 282 /// @endcond 283 284 /// @addtogroup filesystem 285 /// @{ 286 287 /// A filesystem path 288 /** 289 * @ingroup filesystem 290 * @headerfile filesystem 291 * @since C++17 292 */ 293 class path 294 { 295 public: 296 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 297 using value_type = wchar_t; 298 static constexpr value_type preferred_separator = L'\\'; 299 #else 300 # ifdef _GLIBCXX_DOXYGEN 301 /// Windows uses wchar_t for path::value_type, POSIX uses char. 302 using value_type = __os_dependent__; 303 # else 304 using value_type = char; 305 # endif 306 static constexpr value_type preferred_separator = '/'; 307 #endif 308 using string_type = std::basic_string<value_type>; 309 310 /// path::format is ignored in this implementation 311 enum format : unsigned char { native_format, generic_format, auto_format }; 312 313 // constructors and destructor 314 315 path() noexcept { } 316 317 path(const path& __p) = default; 318 319 path(path&& __p) noexcept 320 : _M_pathname(std::move(__p._M_pathname)), 321 _M_cmpts(std::move(__p._M_cmpts)) 322 { __p.clear(); } 323 324 path(string_type&& __source, format = auto_format) 325 : _M_pathname(std::move(__source)) 326 { _M_split_cmpts(); } 327 328 template<typename _Source, 329 typename _Require = __detail::_Path<_Source>> 330 path(_Source const& __source, format = auto_format) 331 : _M_pathname(_S_convert(__detail::__effective_range(__source))) 332 { _M_split_cmpts(); } 333 334 template<typename _InputIterator, 335 typename _Require = __detail::_Path2<_InputIterator>> 336 path(_InputIterator __first, _InputIterator __last, format = auto_format) 337 : _M_pathname(_S_convert(__detail::__string_from_range(__first, __last))) 338 { _M_split_cmpts(); } 339 340 template<typename _Source, 341 typename _Require = __detail::_Path<_Source>, 342 typename _Require2 = __detail::__value_type_is_char<_Source>> 343 path(_Source const& __src, const locale& __loc, format = auto_format) 344 : _M_pathname(_S_convert_loc(__detail::__effective_range(__src), __loc)) 345 { _M_split_cmpts(); } 346 347 template<typename _InputIterator, 348 typename _Require = __detail::_Path2<_InputIterator>, 349 typename _Req2 = __detail::__value_type_is_char<_InputIterator>> 350 path(_InputIterator __first, _InputIterator __last, const locale& __loc, 351 format = auto_format) 352 : _M_pathname(_S_convert_loc(__first, __last, __loc)) 353 { _M_split_cmpts(); } 354 355 ~path() = default; 356 357 // assignments 358 359 path& operator=(const path&); 360 path& operator=(path&&) noexcept; 361 path& operator=(string_type&& __source); 362 path& assign(string_type&& __source); 363 364 template<typename _Source> 365 __detail::_Path<_Source>& 366 operator=(_Source const& __source) 367 { return *this = path(__source); } 368 369 template<typename _Source> 370 __detail::_Path<_Source>& 371 assign(_Source const& __source) 372 { return *this = path(__source); } 373 374 template<typename _InputIterator> 375 __detail::_Path2<_InputIterator>& 376 assign(_InputIterator __first, _InputIterator __last) 377 { return *this = path(__first, __last); } 378 379 // appends 380 381 path& operator/=(const path& __p); 382 383 template<typename _Source> 384 __detail::_Path<_Source>& 385 operator/=(_Source const& __source) 386 { 387 _M_append(_S_convert(__detail::__effective_range(__source))); 388 return *this; 389 } 390 391 template<typename _Source> 392 __detail::_Path<_Source>& 393 append(_Source const& __source) 394 { 395 _M_append(_S_convert(__detail::__effective_range(__source))); 396 return *this; 397 } 398 399 template<typename _InputIterator> 400 __detail::_Path2<_InputIterator>& 401 append(_InputIterator __first, _InputIterator __last) 402 { 403 _M_append(_S_convert(__detail::__string_from_range(__first, __last))); 404 return *this; 405 } 406 407 // concatenation 408 409 path& operator+=(const path& __x); 410 path& operator+=(const string_type& __x); 411 path& operator+=(const value_type* __x); 412 path& operator+=(value_type __x); 413 path& operator+=(basic_string_view<value_type> __x); 414 415 template<typename _Source> 416 __detail::_Path<_Source>& 417 operator+=(_Source const& __x) { return concat(__x); } 418 419 template<typename _CharT> 420 __detail::_Path2<_CharT*>& 421 operator+=(_CharT __x); 422 423 template<typename _Source> 424 __detail::_Path<_Source>& 425 concat(_Source const& __x) 426 { 427 _M_concat(_S_convert(__detail::__effective_range(__x))); 428 return *this; 429 } 430 431 template<typename _InputIterator> 432 __detail::_Path2<_InputIterator>& 433 concat(_InputIterator __first, _InputIterator __last) 434 { 435 _M_concat(_S_convert(__detail::__string_from_range(__first, __last))); 436 return *this; 437 } 438 439 // modifiers 440 441 void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } 442 443 path& make_preferred(); 444 path& remove_filename(); 445 path& replace_filename(const path& __replacement); 446 path& replace_extension(const path& __replacement = path()); 447 448 void swap(path& __rhs) noexcept; 449 450 // native format observers 451 452 const string_type& native() const noexcept { return _M_pathname; } 453 const value_type* c_str() const noexcept { return _M_pathname.c_str(); } 454 operator string_type() const { return _M_pathname; } 455 456 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 457 typename _Allocator = std::allocator<_CharT>> 458 std::basic_string<_CharT, _Traits, _Allocator> 459 string(const _Allocator& __a = _Allocator()) const; 460 461 std::string string() const; 462 #if _GLIBCXX_USE_WCHAR_T 463 std::wstring wstring() const; 464 #endif 465 #ifdef _GLIBCXX_USE_CHAR8_T 466 __attribute__((__abi_tag__("__u8"))) 467 std::u8string u8string() const; 468 #else 469 std::string u8string() const; 470 #endif // _GLIBCXX_USE_CHAR8_T 471 std::u16string u16string() const; 472 std::u32string u32string() const; 473 474 // generic format observers 475 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 476 typename _Allocator = std::allocator<_CharT>> 477 std::basic_string<_CharT, _Traits, _Allocator> 478 generic_string(const _Allocator& __a = _Allocator()) const; 479 480 std::string generic_string() const; 481 #if _GLIBCXX_USE_WCHAR_T 482 std::wstring generic_wstring() const; 483 #endif 484 #ifdef _GLIBCXX_USE_CHAR8_T 485 __attribute__((__abi_tag__("__u8"))) 486 std::u8string generic_u8string() const; 487 #else 488 std::string generic_u8string() const; 489 #endif // _GLIBCXX_USE_CHAR8_T 490 std::u16string generic_u16string() const; 491 std::u32string generic_u32string() const; 492 493 // compare 494 495 int compare(const path& __p) const noexcept; 496 int compare(const string_type& __s) const noexcept; 497 int compare(const value_type* __s) const noexcept; 498 int compare(basic_string_view<value_type> __s) const noexcept; 499 500 // decomposition 501 502 path root_name() const; 503 path root_directory() const; 504 path root_path() const; 505 path relative_path() const; 506 path parent_path() const; 507 path filename() const; 508 path stem() const; 509 path extension() const; 510 511 // query 512 513 [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); } 514 bool has_root_name() const noexcept; 515 bool has_root_directory() const noexcept; 516 bool has_root_path() const noexcept; 517 bool has_relative_path() const noexcept; 518 bool has_parent_path() const noexcept; 519 bool has_filename() const noexcept; 520 bool has_stem() const noexcept; 521 bool has_extension() const noexcept; 522 bool is_absolute() const noexcept; 523 bool is_relative() const noexcept { return !is_absolute(); } 524 525 // generation 526 path lexically_normal() const; 527 path lexically_relative(const path& base) const; 528 path lexically_proximate(const path& base) const; 529 530 // iterators 531 class iterator; 532 using const_iterator = iterator; 533 534 iterator begin() const noexcept; 535 iterator end() const noexcept; 536 537 /// Write a path to a stream 538 template<typename _CharT, typename _Traits> 539 friend std::basic_ostream<_CharT, _Traits>& 540 operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p) 541 { 542 __os << std::quoted(__p.string<_CharT, _Traits>()); 543 return __os; 544 } 545 546 /// Read a path from a stream 547 template<typename _CharT, typename _Traits> 548 friend std::basic_istream<_CharT, _Traits>& 549 operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p) 550 { 551 std::basic_string<_CharT, _Traits> __tmp; 552 if (__is >> std::quoted(__tmp)) 553 __p = std::move(__tmp); 554 return __is; 555 } 556 557 // non-member operators 558 559 /// Compare paths 560 friend bool operator==(const path& __lhs, const path& __rhs) noexcept 561 { return path::_S_compare(__lhs, __rhs) == 0; } 562 563 #if __cpp_lib_three_way_comparison 564 /// Compare paths 565 friend strong_ordering 566 operator<=>(const path& __lhs, const path& __rhs) noexcept 567 { return path::_S_compare(__lhs, __rhs) <=> 0; } 568 #else 569 /// Compare paths 570 friend bool operator!=(const path& __lhs, const path& __rhs) noexcept 571 { return !(__lhs == __rhs); } 572 573 /// Compare paths 574 friend bool operator<(const path& __lhs, const path& __rhs) noexcept 575 { return __lhs.compare(__rhs) < 0; } 576 577 /// Compare paths 578 friend bool operator<=(const path& __lhs, const path& __rhs) noexcept 579 { return !(__rhs < __lhs); } 580 581 /// Compare paths 582 friend bool operator>(const path& __lhs, const path& __rhs) noexcept 583 { return __rhs < __lhs; } 584 585 /// Compare paths 586 friend bool operator>=(const path& __lhs, const path& __rhs) noexcept 587 { return !(__lhs < __rhs); } 588 #endif 589 590 /// Append one path to another 591 friend path operator/(const path& __lhs, const path& __rhs) 592 { 593 path __result(__lhs); 594 __result /= __rhs; 595 return __result; 596 } 597 598 private: 599 enum class _Type : unsigned char { 600 _Multi = 0, _Root_name, _Root_dir, _Filename 601 }; 602 603 path(basic_string_view<value_type> __str, _Type __type); 604 605 enum class _Split { _Stem, _Extension }; 606 607 void _M_append(basic_string_view<value_type>); 608 void _M_concat(basic_string_view<value_type>); 609 610 pair<const string_type*, size_t> _M_find_extension() const noexcept; 611 612 // path::_S_convert creates a basic_string<value_type> or 613 // basic_string_view<value_type> from a basic_string<C> or 614 // basic_string_view<C>, for an encoded character type C, 615 // performing the conversions required by [fs.path.type.cvt]. 616 template<typename _Tp> 617 static auto 618 _S_convert(_Tp __str) 619 noexcept(is_same_v<typename _Tp::value_type, value_type>) 620 { 621 if constexpr (is_same_v<typename _Tp::value_type, value_type>) 622 return __str; // No conversion needed. 623 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T 624 else if constexpr (is_same_v<_Tp, std::u8string>) 625 // Calling _S_convert<char8_t> will return a u8string_view that 626 // refers to __str and would dangle after this function returns. 627 // Return a string_type instead, to avoid dangling. 628 return string_type(_S_convert(__str.data(), 629 __str.data() + __str.size())); 630 #endif 631 else 632 return _S_convert(__str.data(), __str.data() + __str.size()); 633 } 634 635 template<typename _EcharT> 636 static auto 637 _S_convert(const _EcharT* __first, const _EcharT* __last); 638 639 // _S_convert_loc converts a range of char to string_type, using the 640 // supplied locale for encoding conversions. 641 642 static string_type 643 _S_convert_loc(const char* __first, const char* __last, 644 const std::locale& __loc); 645 646 template<typename _Iter> 647 static string_type 648 _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) 649 { 650 const auto __s = __detail::__string_from_range(__first, __last); 651 return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); 652 } 653 654 template<typename _Tp> 655 static string_type 656 _S_convert_loc(const _Tp& __s, const std::locale& __loc) 657 { 658 return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); 659 } 660 661 template<typename _CharT, typename _Traits, typename _Allocator> 662 static basic_string<_CharT, _Traits, _Allocator> 663 _S_str_convert(basic_string_view<value_type>, const _Allocator&); 664 665 // Returns lhs.compare(rhs), but defined after path::iterator is complete. 666 __attribute__((__always_inline__)) 667 static int 668 _S_compare(const path& __lhs, const path& __rhs) noexcept; 669 670 void _M_split_cmpts(); 671 672 _Type _M_type() const noexcept { return _M_cmpts.type(); } 673 674 string_type _M_pathname; 675 676 struct _Cmpt; 677 678 struct _List 679 { 680 using value_type = _Cmpt; 681 using iterator = value_type*; 682 using const_iterator = const value_type*; 683 684 _List(); 685 _List(const _List&); 686 _List(_List&&) = default; 687 _List& operator=(const _List&); 688 _List& operator=(_List&&) = default; 689 ~_List() = default; 690 691 _Type type() const noexcept 692 { return _Type(reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3); } 693 694 void type(_Type) noexcept; 695 696 int size() const noexcept; // zero unless type() == _Type::_Multi 697 bool empty() const noexcept; // true unless type() == _Type::_Multi 698 void clear(); 699 void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); } 700 int capacity() const noexcept; 701 void reserve(int, bool); ///< @pre type() == _Type::_Multi 702 703 // All the member functions below here have a precondition !empty() 704 // (and they should only be called from within the library). 705 706 iterator begin() noexcept; 707 iterator end() noexcept; 708 const_iterator begin() const noexcept; 709 const_iterator end() const noexcept; 710 711 value_type& front() noexcept; 712 value_type& back() noexcept; 713 const value_type& front() const noexcept; 714 const value_type& back() const noexcept; 715 716 void pop_back(); 717 void _M_erase_from(const_iterator __pos); // erases [__pos,end()) 718 719 struct _Impl; 720 struct _Impl_deleter 721 { 722 void operator()(_Impl*) const noexcept; 723 }; 724 unique_ptr<_Impl, _Impl_deleter> _M_impl; 725 }; 726 _List _M_cmpts; 727 728 struct _Parser; 729 730 template<typename _EcharT> struct _Codecvt; 731 }; 732 733 /// @{ 734 /// @relates std::filesystem::path 735 736 #if __cpp_concepts >= 201907L 737 // Workaround for PR libstdc++/106201 738 inline void 739 swap(same_as<path> auto& __lhs, same_as<path> auto& __rhs) noexcept 740 { __lhs.swap(__rhs); } 741 #else 742 inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } 743 #endif 744 745 size_t hash_value(const path& __p) noexcept; 746 747 /// @} 748 749 /// Exception type thrown by the Filesystem library 750 /** 751 * @headerfile filesystem 752 * @since C++17 753 */ 754 class filesystem_error : public std::system_error 755 { 756 public: 757 filesystem_error(const string& __what_arg, error_code __ec); 758 759 filesystem_error(const string& __what_arg, const path& __p1, 760 error_code __ec); 761 762 filesystem_error(const string& __what_arg, const path& __p1, 763 const path& __p2, error_code __ec); 764 765 filesystem_error(const filesystem_error&) = default; 766 filesystem_error& operator=(const filesystem_error&) = default; 767 768 // No move constructor or assignment operator. 769 // Copy rvalues instead, so that _M_impl is not left empty. 770 771 ~filesystem_error(); 772 773 const path& path1() const noexcept; 774 const path& path2() const noexcept; 775 const char* what() const noexcept; 776 777 private: 778 struct _Impl; 779 std::__shared_ptr<const _Impl> _M_impl; 780 }; 781 782 /// @cond undocumented 783 namespace __detail 784 { 785 [[noreturn]] inline void 786 __throw_conversion_error() 787 { 788 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 789 "Cannot convert character sequence", 790 std::make_error_code(errc::illegal_byte_sequence))); 791 } 792 793 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 794 template<typename _Tp> 795 inline std::wstring 796 __wstr_from_utf8(const _Tp& __str) 797 { 798 static_assert(std::is_same_v<typename _Tp::value_type, char>); 799 std::wstring __wstr; 800 // XXX This assumes native wide encoding is UTF-16. 801 std::codecvt_utf8_utf16<wchar_t> __wcvt; 802 const auto __p = __str.data(); 803 if (!__str_codecvt_in_all(__p, __p + __str.size(), __wstr, __wcvt)) 804 __detail::__throw_conversion_error(); 805 return __wstr; 806 } 807 #endif 808 809 } // namespace __detail 810 /// @endcond 811 812 813 /** Create a path from a UTF-8-encoded sequence of char 814 * 815 * @relates std::filesystem::path 816 * @headerfile filesystem 817 * @since C++17 818 */ 819 template<typename _InputIterator, 820 typename _Require = __detail::_Path2<_InputIterator>, 821 typename _CharT 822 = __detail::__value_type_is_char_or_char8_t<_InputIterator>> 823 inline path 824 u8path(_InputIterator __first, _InputIterator __last) 825 { 826 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 827 if constexpr (is_same_v<_CharT, char>) 828 return path{ __detail::__wstr_from_utf8( 829 __detail::__string_from_range(__first, __last)) }; 830 else 831 return path{ __first, __last }; // constructor handles char8_t 832 #else 833 // This assumes native normal encoding is UTF-8. 834 return path{ __first, __last }; 835 #endif 836 } 837 838 /** Create a path from a UTF-8-encoded sequence of char 839 * 840 * @relates std::filesystem::path 841 * @headerfile filesystem 842 * @since C++17 843 */ 844 template<typename _Source, 845 typename _Require = __detail::_Path<_Source>, 846 typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>> 847 inline path 848 u8path(const _Source& __source) 849 { 850 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 851 if constexpr (is_same_v<_CharT, char>) 852 return path{ __detail::__wstr_from_utf8( 853 __detail::__effective_range(__source)) }; 854 else 855 return path{ __source }; // constructor handles char8_t 856 #else 857 // This assumes native normal encoding is UTF-8. 858 return path{ __source }; 859 #endif 860 } 861 862 /// @cond undocumented 863 864 struct path::_Cmpt : path 865 { 866 _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos); 867 868 _Cmpt() : _M_pos(-1) { } 869 870 size_t _M_pos; 871 }; 872 873 // path::_Codecvt<C> Performs conversions between C and path::string_type. 874 // The native encoding of char strings is the OS-dependent current 875 // encoding for pathnames. FIXME: We assume this is UTF-8 everywhere, 876 // but should use a Windows API to query it. 877 878 // Converts between native pathname encoding and char16_t or char32_t. 879 template<typename _EcharT> 880 struct path::_Codecvt 881 // Need derived class here because std::codecvt has protected destructor. 882 : std::codecvt<_EcharT, char, mbstate_t> 883 { }; 884 885 // Converts between native pathname encoding and native wide encoding. 886 // The native encoding for wide strings is the execution wide-character 887 // set encoding. FIXME: We assume that this is either UTF-32 or UTF-16 888 // (depending on the width of wchar_t). That matches GCC's default, 889 // but can be changed with -fwide-exec-charset. 890 // We need a custom codecvt converting the native pathname encoding 891 // to/from the native wide encoding. 892 template<> 893 struct path::_Codecvt<wchar_t> 894 : __conditional_t<sizeof(wchar_t) == sizeof(char32_t), 895 std::codecvt_utf8<wchar_t>, // UTF-8 <-> UTF-32 896 std::codecvt_utf8_utf16<wchar_t>> // UTF-8 <-> UTF-16 897 { }; 898 899 template<typename _EcharT> 900 auto 901 path::_S_convert(const _EcharT* __f, const _EcharT* __l) 902 { 903 static_assert(__detail::__is_encoded_char<_EcharT>); 904 905 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 906 # define _GLIBCXX_CONV_FROM_UTF8(S) __detail::__wstr_from_utf8(S) 907 #else 908 # define _GLIBCXX_CONV_FROM_UTF8(S) S 909 #endif 910 911 if constexpr (is_same_v<_EcharT, value_type>) 912 return basic_string_view<value_type>(__f, __l - __f); 913 #ifdef _GLIBCXX_USE_CHAR8_T 914 else if constexpr (is_same_v<_EcharT, char8_t>) 915 { 916 string_view __str(reinterpret_cast<const char*>(__f), __l - __f); 917 return _GLIBCXX_CONV_FROM_UTF8(__str); 918 } 919 #endif 920 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 921 else if constexpr (is_same_v<_EcharT, char>) 922 { 923 std::wstring __wstr; 924 path::_Codecvt<wchar_t> __cvt; 925 if (__str_codecvt_in_all(__f, __l, __wstr, __cvt)) 926 return __wstr; 927 } 928 #endif 929 else 930 { 931 path::_Codecvt<_EcharT> __cvt; 932 std::string __str; 933 if (__str_codecvt_out_all(__f, __l, __str, __cvt)) 934 return _GLIBCXX_CONV_FROM_UTF8(__str); 935 } 936 __detail::__throw_conversion_error(); 937 } 938 #undef _GLIBCXX_CONV_FROM_UTF8 939 940 /// @endcond 941 942 /// An iterator for the components of a path 943 /** 944 * @headerfile filesystem 945 * @since C++17 946 */ 947 class path::iterator 948 { 949 public: 950 using difference_type = std::ptrdiff_t; 951 using value_type = path; 952 using reference = const path&; 953 using pointer = const path*; 954 using iterator_category = std::bidirectional_iterator_tag; 955 956 iterator() noexcept : _M_path(nullptr), _M_cur(), _M_at_end() { } 957 958 iterator(const iterator&) = default; 959 iterator& operator=(const iterator&) = default; 960 961 reference operator*() const noexcept; 962 pointer operator->() const noexcept { return std::__addressof(**this); } 963 964 iterator& operator++() noexcept; 965 966 iterator operator++(int) noexcept 967 { auto __tmp = *this; ++*this; return __tmp; } 968 969 iterator& operator--() noexcept; 970 971 iterator operator--(int) noexcept 972 { auto __tmp = *this; --*this; return __tmp; } 973 974 friend bool 975 operator==(const iterator& __lhs, const iterator& __rhs) noexcept 976 { return __lhs._M_equals(__rhs); } 977 978 friend bool 979 operator!=(const iterator& __lhs, const iterator& __rhs) noexcept 980 { return !__lhs._M_equals(__rhs); } 981 982 private: 983 friend class path; 984 985 bool 986 _M_is_multi() const noexcept 987 { return _M_path->_M_type() == _Type::_Multi; } 988 989 friend difference_type 990 __path_iter_distance(const iterator& __first, const iterator& __last) 991 noexcept 992 { 993 __glibcxx_assert(__first._M_path != nullptr); 994 __glibcxx_assert(__first._M_path == __last._M_path); 995 if (__first._M_is_multi()) 996 return std::distance(__first._M_cur, __last._M_cur); 997 else if (__first._M_at_end == __last._M_at_end) 998 return 0; 999 else 1000 return __first._M_at_end ? -1 : 1; 1001 } 1002 1003 friend void 1004 __path_iter_advance(iterator& __i, difference_type __n) noexcept 1005 { 1006 if (__n == 1) 1007 ++__i; 1008 else if (__n == -1) 1009 --__i; 1010 else if (__n != 0) 1011 { 1012 __glibcxx_assert(__i._M_path != nullptr); 1013 __glibcxx_assert(__i._M_is_multi()); 1014 // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n); 1015 __i._M_cur += __n; 1016 } 1017 } 1018 1019 iterator(const path* __path, path::_List::const_iterator __iter) noexcept 1020 : _M_path(__path), _M_cur(__iter), _M_at_end() 1021 { } 1022 1023 iterator(const path* __path, bool __at_end) noexcept 1024 : _M_path(__path), _M_cur(), _M_at_end(__at_end) 1025 { } 1026 1027 bool _M_equals(iterator) const noexcept; 1028 1029 const path* _M_path; 1030 path::_List::const_iterator _M_cur; 1031 bool _M_at_end; // only used when type != _Multi 1032 }; 1033 1034 1035 inline path& 1036 path::operator=(path&& __p) noexcept 1037 { 1038 if (&__p == this) [[__unlikely__]] 1039 return *this; 1040 1041 _M_pathname = std::move(__p._M_pathname); 1042 _M_cmpts = std::move(__p._M_cmpts); 1043 __p.clear(); 1044 return *this; 1045 } 1046 1047 inline path& 1048 path::operator=(string_type&& __source) 1049 { return *this = path(std::move(__source)); } 1050 1051 inline path& 1052 path::assign(string_type&& __source) 1053 { return *this = path(std::move(__source)); } 1054 1055 inline path& 1056 path::operator+=(const string_type& __x) 1057 { 1058 _M_concat(__x); 1059 return *this; 1060 } 1061 1062 inline path& 1063 path::operator+=(const value_type* __x) 1064 { 1065 _M_concat(__x); 1066 return *this; 1067 } 1068 1069 inline path& 1070 path::operator+=(value_type __x) 1071 { 1072 _M_concat(basic_string_view<value_type>(&__x, 1)); 1073 return *this; 1074 } 1075 1076 inline path& 1077 path::operator+=(basic_string_view<value_type> __x) 1078 { 1079 _M_concat(__x); 1080 return *this; 1081 } 1082 1083 template<typename _CharT> 1084 inline __detail::_Path2<_CharT*>& 1085 path::operator+=(const _CharT __x) 1086 { 1087 _M_concat(_S_convert(&__x, &__x + 1)); 1088 return *this; 1089 } 1090 1091 inline path& 1092 path::make_preferred() 1093 { 1094 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1095 auto __pos = _M_pathname.find(L'/'); 1096 while (__pos != _M_pathname.npos) 1097 { 1098 _M_pathname[__pos] = preferred_separator; 1099 __pos = _M_pathname.find(L'/', __pos); 1100 } 1101 #endif 1102 return *this; 1103 } 1104 1105 inline void path::swap(path& __rhs) noexcept 1106 { 1107 _M_pathname.swap(__rhs._M_pathname); 1108 _M_cmpts.swap(__rhs._M_cmpts); 1109 } 1110 1111 /// @cond undocumented 1112 template<typename _CharT, typename _Traits, typename _Allocator> 1113 std::basic_string<_CharT, _Traits, _Allocator> 1114 path::_S_str_convert(basic_string_view<value_type> __str, 1115 const _Allocator& __a) 1116 { 1117 static_assert(!is_same_v<_CharT, value_type>); 1118 1119 using _WString = basic_string<_CharT, _Traits, _Allocator>; 1120 1121 if (__str.size() == 0) 1122 return _WString(__a); 1123 1124 #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1125 string_view __u8str = __str; 1126 #else 1127 // First convert native string from UTF-16 to to UTF-8. 1128 // XXX This assumes that the execution wide-character set is UTF-16. 1129 std::codecvt_utf8_utf16<value_type> __cvt; 1130 1131 using _CharAlloc = __alloc_rebind<_Allocator, char>; 1132 using _String = basic_string<char, char_traits<char>, _CharAlloc>; 1133 _String __u8str{_CharAlloc{__a}}; 1134 const value_type* __wfirst = __str.data(); 1135 const value_type* __wlast = __wfirst + __str.size(); 1136 if (!__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) 1137 __detail::__throw_conversion_error(); 1138 if constexpr (is_same_v<_CharT, char>) 1139 return __u8str; // XXX assumes native ordinary encoding is UTF-8. 1140 else 1141 #endif 1142 { 1143 const char* __first = __u8str.data(); 1144 const char* __last = __first + __u8str.size(); 1145 1146 // Convert UTF-8 string to requested format. 1147 #ifdef _GLIBCXX_USE_CHAR8_T 1148 if constexpr (is_same_v<_CharT, char8_t>) 1149 return _WString(__first, __last, __a); 1150 else 1151 #endif 1152 { 1153 // Convert UTF-8 to wide string. 1154 _WString __wstr(__a); 1155 path::_Codecvt<_CharT> __cvt; 1156 if (__str_codecvt_in_all(__first, __last, __wstr, __cvt)) 1157 return __wstr; 1158 } 1159 } 1160 __detail::__throw_conversion_error(); 1161 } 1162 /// @endcond 1163 1164 template<typename _CharT, typename _Traits, typename _Allocator> 1165 inline basic_string<_CharT, _Traits, _Allocator> 1166 path::string(const _Allocator& __a) const 1167 { 1168 if constexpr (is_same_v<_CharT, value_type>) 1169 return { _M_pathname.c_str(), _M_pathname.length(), __a }; 1170 else 1171 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); 1172 } 1173 1174 inline std::string 1175 path::string() const { return string<char>(); } 1176 1177 #if _GLIBCXX_USE_WCHAR_T 1178 inline std::wstring 1179 path::wstring() const { return string<wchar_t>(); } 1180 #endif 1181 1182 #ifdef _GLIBCXX_USE_CHAR8_T 1183 inline std::u8string 1184 path::u8string() const { return string<char8_t>(); } 1185 #else 1186 inline std::string 1187 path::u8string() const 1188 { 1189 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1190 std::string __str; 1191 // convert from native wide encoding (assumed to be UTF-16) to UTF-8 1192 std::codecvt_utf8_utf16<value_type> __cvt; 1193 const value_type* __first = _M_pathname.data(); 1194 const value_type* __last = __first + _M_pathname.size(); 1195 if (__str_codecvt_out_all(__first, __last, __str, __cvt)) 1196 return __str; 1197 __detail::__throw_conversion_error(); 1198 #else 1199 return _M_pathname; 1200 #endif 1201 } 1202 #endif // _GLIBCXX_USE_CHAR8_T 1203 1204 inline std::u16string 1205 path::u16string() const { return string<char16_t>(); } 1206 1207 inline std::u32string 1208 path::u32string() const { return string<char32_t>(); } 1209 1210 template<typename _CharT, typename _Traits, typename _Allocator> 1211 inline std::basic_string<_CharT, _Traits, _Allocator> 1212 path::generic_string(const _Allocator& __a) const 1213 { 1214 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1215 const value_type __slash = L'/'; 1216 #else 1217 const value_type __slash = '/'; 1218 #endif 1219 using _Alloc2 = typename allocator_traits<_Allocator>::template 1220 rebind_alloc<value_type>; 1221 basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a); 1222 1223 if (_M_type() == _Type::_Root_dir) 1224 __str.assign(1, __slash); 1225 else 1226 { 1227 __str.reserve(_M_pathname.size()); 1228 bool __add_slash = false; 1229 for (auto& __elem : *this) 1230 { 1231 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1232 if (__elem._M_type() == _Type::_Root_dir) 1233 { 1234 __str += __slash; 1235 continue; 1236 } 1237 #endif 1238 if (__add_slash) 1239 __str += __slash; 1240 __str += basic_string_view<value_type>(__elem._M_pathname); 1241 __add_slash = __elem._M_type() == _Type::_Filename; 1242 } 1243 } 1244 1245 if constexpr (is_same_v<_CharT, value_type>) 1246 return __str; 1247 else 1248 return _S_str_convert<_CharT, _Traits>(__str, __a); 1249 } 1250 1251 inline std::string 1252 path::generic_string() const 1253 { return generic_string<char>(); } 1254 1255 #if _GLIBCXX_USE_WCHAR_T 1256 inline std::wstring 1257 path::generic_wstring() const 1258 { return generic_string<wchar_t>(); } 1259 #endif 1260 1261 #ifdef _GLIBCXX_USE_CHAR8_T 1262 inline std::u8string 1263 path::generic_u8string() const 1264 { return generic_string<char8_t>(); } 1265 #else 1266 inline std::string 1267 path::generic_u8string() const 1268 { return generic_string(); } 1269 #endif 1270 1271 inline std::u16string 1272 path::generic_u16string() const 1273 { return generic_string<char16_t>(); } 1274 1275 inline std::u32string 1276 path::generic_u32string() const 1277 { return generic_string<char32_t>(); } 1278 1279 inline int 1280 path::compare(const string_type& __s) const noexcept 1281 { return compare(basic_string_view<value_type>(__s)); } 1282 1283 inline int 1284 path::compare(const value_type* __s) const noexcept 1285 { return compare(basic_string_view<value_type>(__s)); } 1286 1287 inline path 1288 path::filename() const 1289 { 1290 if (empty()) 1291 return {}; 1292 else if (_M_type() == _Type::_Filename) 1293 return *this; 1294 else if (_M_type() == _Type::_Multi) 1295 { 1296 if (_M_pathname.back() == preferred_separator) 1297 return {}; 1298 auto __last = --end(); 1299 if (__last->_M_type() == _Type::_Filename) 1300 return *__last; 1301 } 1302 return {}; 1303 } 1304 1305 inline path 1306 path::stem() const 1307 { 1308 auto ext = _M_find_extension(); 1309 if (ext.first && ext.second != 0) 1310 return path{ext.first->substr(0, ext.second)}; 1311 return {}; 1312 } 1313 1314 inline path 1315 path::extension() const 1316 { 1317 auto ext = _M_find_extension(); 1318 if (ext.first && ext.second != string_type::npos) 1319 return path{ext.first->substr(ext.second)}; 1320 return {}; 1321 } 1322 1323 inline bool 1324 path::has_stem() const noexcept 1325 { 1326 auto ext = _M_find_extension(); 1327 return ext.first && ext.second != 0; 1328 } 1329 1330 inline bool 1331 path::has_extension() const noexcept 1332 { 1333 auto ext = _M_find_extension(); 1334 return ext.first && ext.second != string_type::npos; 1335 } 1336 1337 inline bool 1338 path::is_absolute() const noexcept 1339 { 1340 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 1341 return has_root_name() && has_root_directory(); 1342 #else 1343 return has_root_directory(); 1344 #endif 1345 } 1346 1347 inline path::iterator 1348 path::begin() const noexcept 1349 { 1350 if (_M_type() == _Type::_Multi) 1351 return iterator(this, _M_cmpts.begin()); 1352 return iterator(this, empty()); 1353 } 1354 1355 inline path::iterator 1356 path::end() const noexcept 1357 { 1358 if (_M_type() == _Type::_Multi) 1359 return iterator(this, _M_cmpts.end()); 1360 return iterator(this, true); 1361 } 1362 1363 inline path::iterator& 1364 path::iterator::operator++() noexcept 1365 { 1366 __glibcxx_assert(_M_path != nullptr); 1367 if (_M_is_multi()) 1368 { 1369 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 1370 ++_M_cur; 1371 } 1372 else 1373 { 1374 __glibcxx_assert(!_M_at_end); 1375 _M_at_end = true; 1376 } 1377 return *this; 1378 } 1379 1380 inline path::iterator& 1381 path::iterator::operator--() noexcept 1382 { 1383 __glibcxx_assert(_M_path != nullptr); 1384 if (_M_is_multi()) 1385 { 1386 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); 1387 --_M_cur; 1388 } 1389 else 1390 { 1391 __glibcxx_assert(_M_at_end); 1392 _M_at_end = false; 1393 } 1394 return *this; 1395 } 1396 1397 inline path::iterator::reference 1398 path::iterator::operator*() const noexcept 1399 { 1400 __glibcxx_assert(_M_path != nullptr); 1401 if (_M_is_multi()) 1402 { 1403 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 1404 return *_M_cur; 1405 } 1406 return *_M_path; 1407 } 1408 1409 inline bool 1410 path::iterator::_M_equals(iterator __rhs) const noexcept 1411 { 1412 if (_M_path != __rhs._M_path) 1413 return false; 1414 if (_M_path == nullptr) 1415 return true; 1416 if (_M_is_multi()) 1417 return _M_cur == __rhs._M_cur; 1418 return _M_at_end == __rhs._M_at_end; 1419 } 1420 1421 // Define this now that path and path::iterator are complete. 1422 // It needs to consider the string_view(Range&&) constructor during 1423 // overload resolution, which depends on whether range<path> is satisfied, 1424 // which depends on whether path::iterator is complete. 1425 inline int 1426 path::_S_compare(const path& __lhs, const path& __rhs) noexcept 1427 { return __lhs.compare(__rhs); } 1428 1429 /// @} group filesystem 1430 _GLIBCXX_END_NAMESPACE_CXX11 1431 } // namespace filesystem 1432 1433 /// @cond undocumented 1434 1435 inline ptrdiff_t 1436 distance(filesystem::path::iterator __first, filesystem::path::iterator __last) 1437 noexcept 1438 { return __path_iter_distance(__first, __last); } 1439 1440 template<typename _Distance> 1441 inline void 1442 advance(filesystem::path::iterator& __i, _Distance __n) noexcept 1443 { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); } 1444 1445 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>; 1446 1447 /// @endcond 1448 1449 // _GLIBCXX_RESOLVE_LIB_DEFECTS 1450 // 3657. std::hash<std::filesystem::path> is not enabled 1451 template<> 1452 struct hash<filesystem::path> 1453 { 1454 size_t 1455 operator()(const filesystem::path& __p) const noexcept 1456 { return filesystem::hash_value(__p); } 1457 }; 1458 1459 _GLIBCXX_END_NAMESPACE_VERSION 1460 } // namespace std 1461 1462 #endif // C++17 1463 1464 #endif // _GLIBCXX_FS_PATH_H 1465