libstdc++
|
00001 // Class filesystem::path -*- C++ -*- 00002 00003 // Copyright (C) 2014-2019 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file include/bits/fs_path.h 00026 * This is an internal header file, included by other library headers. 00027 * Do not attempt to use it directly. @headername{filesystem} 00028 */ 00029 00030 #ifndef _GLIBCXX_FS_PATH_H 00031 #define _GLIBCXX_FS_PATH_H 1 00032 00033 #if __cplusplus >= 201703L 00034 00035 #include <utility> 00036 #include <type_traits> 00037 #include <locale> 00038 #include <iosfwd> 00039 #include <iomanip> 00040 #include <codecvt> 00041 #include <string_view> 00042 #include <system_error> 00043 #include <bits/stl_algobase.h> 00044 #include <bits/locale_conv.h> 00045 #include <ext/concurrence.h> 00046 #include <bits/shared_ptr.h> 00047 #include <bits/unique_ptr.h> 00048 00049 #if defined(_WIN32) && !defined(__CYGWIN__) 00050 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 00051 # include <algorithm> 00052 #endif 00053 00054 namespace std _GLIBCXX_VISIBILITY(default) 00055 { 00056 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00057 00058 namespace filesystem 00059 { 00060 _GLIBCXX_BEGIN_NAMESPACE_CXX11 00061 00062 /** 00063 * @ingroup filesystem 00064 * @{ 00065 */ 00066 00067 /// A filesystem path. 00068 class path 00069 { 00070 template<typename _CharT, typename _Ch = remove_const_t<_CharT>> 00071 using __is_encoded_char 00072 = __or_<is_same<_Ch, char>, 00073 #ifdef _GLIBCXX_USE_CHAR8_T 00074 is_same<_Ch, char8_t>, 00075 #endif 00076 is_same<_Ch, wchar_t>, 00077 is_same<_Ch, char16_t>, 00078 is_same<_Ch, char32_t>>; 00079 00080 template<typename _Iter, 00081 typename _Iter_traits = std::iterator_traits<_Iter>> 00082 using __is_path_iter_src 00083 = __and_<__is_encoded_char<typename _Iter_traits::value_type>, 00084 std::is_base_of<std::input_iterator_tag, 00085 typename _Iter_traits::iterator_category>>; 00086 00087 template<typename _Iter> 00088 static __is_path_iter_src<_Iter> 00089 __is_path_src(_Iter, int); 00090 00091 template<typename _CharT, typename _Traits, typename _Alloc> 00092 static __is_encoded_char<_CharT> 00093 __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); 00094 00095 template<typename _CharT, typename _Traits> 00096 static __is_encoded_char<_CharT> 00097 __is_path_src(const basic_string_view<_CharT, _Traits>&, int); 00098 00099 template<typename _Unknown> 00100 static std::false_type 00101 __is_path_src(const _Unknown&, ...); 00102 00103 template<typename _Tp1, typename _Tp2> 00104 struct __constructible_from; 00105 00106 template<typename _Iter> 00107 struct __constructible_from<_Iter, _Iter> 00108 : __is_path_iter_src<_Iter> 00109 { }; 00110 00111 template<typename _Source> 00112 struct __constructible_from<_Source, void> 00113 : decltype(__is_path_src(std::declval<_Source>(), 0)) 00114 { }; 00115 00116 template<typename _Tp1, typename _Tp2 = void> 00117 using _Path = typename 00118 std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>, 00119 __not_<is_void<remove_pointer_t<_Tp1>>>, 00120 __constructible_from<_Tp1, _Tp2>>::value, 00121 path>::type; 00122 00123 template<typename _Source> 00124 static _Source 00125 _S_range_begin(_Source __begin) { return __begin; } 00126 00127 struct __null_terminated { }; 00128 00129 template<typename _Source> 00130 static __null_terminated 00131 _S_range_end(_Source) { return {}; } 00132 00133 template<typename _CharT, typename _Traits, typename _Alloc> 00134 static const _CharT* 00135 _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) 00136 { return __str.data(); } 00137 00138 template<typename _CharT, typename _Traits, typename _Alloc> 00139 static const _CharT* 00140 _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) 00141 { return __str.data() + __str.size(); } 00142 00143 template<typename _CharT, typename _Traits> 00144 static const _CharT* 00145 _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) 00146 { return __str.data(); } 00147 00148 template<typename _CharT, typename _Traits> 00149 static const _CharT* 00150 _S_range_end(const basic_string_view<_CharT, _Traits>& __str) 00151 { return __str.data() + __str.size(); } 00152 00153 template<typename _Tp, 00154 typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())), 00155 typename _Val = typename std::iterator_traits<_Iter>::value_type> 00156 using __value_type_is_char 00157 = std::enable_if_t<std::is_same_v<std::remove_const_t<_Val>, char>>; 00158 00159 public: 00160 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00161 typedef wchar_t value_type; 00162 static constexpr value_type preferred_separator = L'\\'; 00163 #else 00164 typedef char value_type; 00165 static constexpr value_type preferred_separator = '/'; 00166 #endif 00167 typedef std::basic_string<value_type> string_type; 00168 00169 enum format : unsigned char { native_format, generic_format, auto_format }; 00170 00171 // constructors and destructor 00172 00173 path() noexcept { } 00174 00175 path(const path& __p) = default; 00176 00177 path(path&& __p) 00178 #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_FULLY_DYNAMIC_STRING == 0 00179 noexcept 00180 #endif 00181 : _M_pathname(std::move(__p._M_pathname)), 00182 _M_cmpts(std::move(__p._M_cmpts)) 00183 { __p.clear(); } 00184 00185 path(string_type&& __source, format = auto_format) 00186 : _M_pathname(std::move(__source)) 00187 { _M_split_cmpts(); } 00188 00189 template<typename _Source, 00190 typename _Require = _Path<_Source>> 00191 path(_Source const& __source, format = auto_format) 00192 : _M_pathname(_S_convert(_S_range_begin(__source), 00193 _S_range_end(__source))) 00194 { _M_split_cmpts(); } 00195 00196 template<typename _InputIterator, 00197 typename _Require = _Path<_InputIterator, _InputIterator>> 00198 path(_InputIterator __first, _InputIterator __last, format = auto_format) 00199 : _M_pathname(_S_convert(__first, __last)) 00200 { _M_split_cmpts(); } 00201 00202 template<typename _Source, 00203 typename _Require = _Path<_Source>, 00204 typename _Require2 = __value_type_is_char<_Source>> 00205 path(_Source const& __source, const locale& __loc, format = auto_format) 00206 : _M_pathname(_S_convert_loc(_S_range_begin(__source), 00207 _S_range_end(__source), __loc)) 00208 { _M_split_cmpts(); } 00209 00210 template<typename _InputIterator, 00211 typename _Require = _Path<_InputIterator, _InputIterator>, 00212 typename _Require2 = __value_type_is_char<_InputIterator>> 00213 path(_InputIterator __first, _InputIterator __last, const locale& __loc, 00214 format = auto_format) 00215 : _M_pathname(_S_convert_loc(__first, __last, __loc)) 00216 { _M_split_cmpts(); } 00217 00218 ~path() = default; 00219 00220 // assignments 00221 00222 path& operator=(const path&); 00223 path& operator=(path&&) noexcept; 00224 path& operator=(string_type&& __source); 00225 path& assign(string_type&& __source); 00226 00227 template<typename _Source> 00228 _Path<_Source>& 00229 operator=(_Source const& __source) 00230 { return *this = path(__source); } 00231 00232 template<typename _Source> 00233 _Path<_Source>& 00234 assign(_Source const& __source) 00235 { return *this = path(__source); } 00236 00237 template<typename _InputIterator> 00238 _Path<_InputIterator, _InputIterator>& 00239 assign(_InputIterator __first, _InputIterator __last) 00240 { return *this = path(__first, __last); } 00241 00242 // appends 00243 00244 path& operator/=(const path& __p); 00245 00246 template <class _Source> 00247 _Path<_Source>& 00248 operator/=(_Source const& __source) 00249 { 00250 _M_append(_S_convert(_S_range_begin(__source), _S_range_end(__source))); 00251 return *this; 00252 } 00253 00254 template<typename _Source> 00255 _Path<_Source>& 00256 append(_Source const& __source) 00257 { 00258 _M_append(_S_convert(_S_range_begin(__source), _S_range_end(__source))); 00259 return *this; 00260 } 00261 00262 template<typename _InputIterator> 00263 _Path<_InputIterator, _InputIterator>& 00264 append(_InputIterator __first, _InputIterator __last) 00265 { 00266 _M_append(_S_convert(__first, __last)); 00267 return *this; 00268 } 00269 00270 // concatenation 00271 00272 path& operator+=(const path& __x); 00273 path& operator+=(const string_type& __x); 00274 path& operator+=(const value_type* __x); 00275 path& operator+=(value_type __x); 00276 path& operator+=(basic_string_view<value_type> __x); 00277 00278 template<typename _Source> 00279 _Path<_Source>& 00280 operator+=(_Source const& __x) { return concat(__x); } 00281 00282 template<typename _CharT> 00283 _Path<_CharT*, _CharT*>& 00284 operator+=(_CharT __x); 00285 00286 template<typename _Source> 00287 _Path<_Source>& 00288 concat(_Source const& __x) 00289 { 00290 _M_concat(_S_convert(_S_range_begin(__x), _S_range_end(__x))); 00291 return *this; 00292 } 00293 00294 template<typename _InputIterator> 00295 _Path<_InputIterator, _InputIterator>& 00296 concat(_InputIterator __first, _InputIterator __last) 00297 { 00298 _M_concat(_S_convert(__first, __last)); 00299 return *this; 00300 } 00301 00302 // modifiers 00303 00304 void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } 00305 00306 path& make_preferred(); 00307 path& remove_filename(); 00308 path& replace_filename(const path& __replacement); 00309 path& replace_extension(const path& __replacement = path()); 00310 00311 void swap(path& __rhs) noexcept; 00312 00313 // native format observers 00314 00315 const string_type& native() const noexcept { return _M_pathname; } 00316 const value_type* c_str() const noexcept { return _M_pathname.c_str(); } 00317 operator string_type() const { return _M_pathname; } 00318 00319 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00320 typename _Allocator = std::allocator<_CharT>> 00321 std::basic_string<_CharT, _Traits, _Allocator> 00322 string(const _Allocator& __a = _Allocator()) const; 00323 00324 std::string string() const; 00325 #if _GLIBCXX_USE_WCHAR_T 00326 std::wstring wstring() const; 00327 #endif 00328 #ifdef _GLIBCXX_USE_CHAR8_T 00329 __attribute__((__abi_tag__("__u8"))) 00330 std::u8string u8string() const; 00331 #else 00332 std::string u8string() const; 00333 #endif // _GLIBCXX_USE_CHAR8_T 00334 std::u16string u16string() const; 00335 std::u32string u32string() const; 00336 00337 // generic format observers 00338 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00339 typename _Allocator = std::allocator<_CharT>> 00340 std::basic_string<_CharT, _Traits, _Allocator> 00341 generic_string(const _Allocator& __a = _Allocator()) const; 00342 00343 std::string generic_string() const; 00344 #if _GLIBCXX_USE_WCHAR_T 00345 std::wstring generic_wstring() const; 00346 #endif 00347 #ifdef _GLIBCXX_USE_CHAR8_T 00348 __attribute__((__abi_tag__("__u8"))) 00349 std::u8string generic_u8string() const; 00350 #else 00351 std::string generic_u8string() const; 00352 #endif // _GLIBCXX_USE_CHAR8_T 00353 std::u16string generic_u16string() const; 00354 std::u32string generic_u32string() const; 00355 00356 // compare 00357 00358 int compare(const path& __p) const noexcept; 00359 int compare(const string_type& __s) const noexcept; 00360 int compare(const value_type* __s) const noexcept; 00361 int compare(basic_string_view<value_type> __s) const noexcept; 00362 00363 // decomposition 00364 00365 path root_name() const; 00366 path root_directory() const; 00367 path root_path() const; 00368 path relative_path() const; 00369 path parent_path() const; 00370 path filename() const; 00371 path stem() const; 00372 path extension() const; 00373 00374 // query 00375 00376 [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); } 00377 bool has_root_name() const noexcept; 00378 bool has_root_directory() const noexcept; 00379 bool has_root_path() const noexcept; 00380 bool has_relative_path() const noexcept; 00381 bool has_parent_path() const noexcept; 00382 bool has_filename() const noexcept; 00383 bool has_stem() const noexcept; 00384 bool has_extension() const noexcept; 00385 bool is_absolute() const noexcept; 00386 bool is_relative() const noexcept { return !is_absolute(); } 00387 00388 // generation 00389 path lexically_normal() const; 00390 path lexically_relative(const path& base) const; 00391 path lexically_proximate(const path& base) const; 00392 00393 // iterators 00394 class iterator; 00395 typedef iterator const_iterator; 00396 00397 iterator begin() const; 00398 iterator end() const; 00399 00400 /// Write a path to a stream 00401 template<typename _CharT, typename _Traits> 00402 friend std::basic_ostream<_CharT, _Traits>& 00403 operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p) 00404 { 00405 __os << std::quoted(__p.string<_CharT, _Traits>()); 00406 return __os; 00407 } 00408 00409 /// Read a path from a stream 00410 template<typename _CharT, typename _Traits> 00411 friend std::basic_istream<_CharT, _Traits>& 00412 operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p) 00413 { 00414 std::basic_string<_CharT, _Traits> __tmp; 00415 if (__is >> std::quoted(__tmp)) 00416 __p = std::move(__tmp); 00417 return __is; 00418 } 00419 00420 // non-member operators 00421 00422 /// Compare paths 00423 friend bool operator<(const path& __lhs, const path& __rhs) noexcept 00424 { return __lhs.compare(__rhs) < 0; } 00425 00426 /// Compare paths 00427 friend bool operator<=(const path& __lhs, const path& __rhs) noexcept 00428 { return !(__rhs < __lhs); } 00429 00430 /// Compare paths 00431 friend bool operator>(const path& __lhs, const path& __rhs) noexcept 00432 { return __rhs < __lhs; } 00433 00434 /// Compare paths 00435 friend bool operator>=(const path& __lhs, const path& __rhs) noexcept 00436 { return !(__lhs < __rhs); } 00437 00438 /// Compare paths 00439 friend bool operator==(const path& __lhs, const path& __rhs) noexcept 00440 { return __lhs.compare(__rhs) == 0; } 00441 00442 /// Compare paths 00443 friend bool operator!=(const path& __lhs, const path& __rhs) noexcept 00444 { return !(__lhs == __rhs); } 00445 00446 /// Append one path to another 00447 friend path operator/(const path& __lhs, const path& __rhs) 00448 { 00449 path __result(__lhs); 00450 __result /= __rhs; 00451 return __result; 00452 } 00453 00454 // Create a basic_string by reading until a null character. 00455 template<typename _InputIterator, 00456 typename _Traits = std::iterator_traits<_InputIterator>, 00457 typename _CharT 00458 = typename std::remove_cv_t<typename _Traits::value_type>> 00459 static std::basic_string<_CharT> 00460 _S_string_from_iter(_InputIterator __source) 00461 { 00462 std::basic_string<_CharT> __str; 00463 for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source) 00464 __str.push_back(__ch); 00465 return __str; 00466 } 00467 00468 private: 00469 enum class _Type : unsigned char { 00470 _Multi = 0, _Root_name, _Root_dir, _Filename 00471 }; 00472 00473 path(basic_string_view<value_type> __str, _Type __type) 00474 : _M_pathname(__str) 00475 { 00476 __glibcxx_assert(__type != _Type::_Multi); 00477 _M_cmpts.type(__type); 00478 } 00479 00480 enum class _Split { _Stem, _Extension }; 00481 00482 void _M_append(basic_string_view<value_type>); 00483 void _M_concat(basic_string_view<value_type>); 00484 00485 pair<const string_type*, size_t> _M_find_extension() const noexcept; 00486 00487 template<typename _CharT> 00488 struct _Cvt; 00489 00490 static basic_string_view<value_type> 00491 _S_convert(value_type* __src, __null_terminated) 00492 { return __src; } 00493 00494 static basic_string_view<value_type> 00495 _S_convert(const value_type* __src, __null_terminated) 00496 { return __src; } 00497 00498 static basic_string_view<value_type> 00499 _S_convert(value_type* __first, value_type* __last) 00500 { return {__first, __last - __first}; } 00501 00502 static basic_string_view<value_type> 00503 _S_convert(const value_type* __first, const value_type* __last) 00504 { return {__first, __last - __first}; } 00505 00506 template<typename _Iter> 00507 static string_type 00508 _S_convert(_Iter __first, _Iter __last) 00509 { 00510 using __value_type = typename std::iterator_traits<_Iter>::value_type; 00511 return _Cvt<typename remove_cv<__value_type>::type>:: 00512 _S_convert(__first, __last); 00513 } 00514 00515 template<typename _InputIterator> 00516 static string_type 00517 _S_convert(_InputIterator __src, __null_terminated) 00518 { 00519 // Read from iterator into basic_string until a null value is seen: 00520 auto __s = _S_string_from_iter(__src); 00521 // Convert (if needed) from iterator's value type to path::value_type: 00522 return string_type(_S_convert(__s.data(), __s.data() + __s.size())); 00523 } 00524 00525 static string_type 00526 _S_convert_loc(const char* __first, const char* __last, 00527 const std::locale& __loc); 00528 00529 template<typename _Iter> 00530 static string_type 00531 _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) 00532 { 00533 const std::string __str(__first, __last); 00534 return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc); 00535 } 00536 00537 template<typename _InputIterator> 00538 static string_type 00539 _S_convert_loc(_InputIterator __src, __null_terminated, 00540 const std::locale& __loc) 00541 { 00542 std::string __s = _S_string_from_iter(__src); 00543 return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); 00544 } 00545 00546 template<typename _CharT, typename _Traits, typename _Allocator> 00547 static basic_string<_CharT, _Traits, _Allocator> 00548 _S_str_convert(const string_type&, const _Allocator& __a); 00549 00550 void _M_split_cmpts(); 00551 00552 _Type _M_type() const noexcept { return _M_cmpts.type(); } 00553 00554 string_type _M_pathname; 00555 00556 struct _Cmpt; 00557 00558 struct _List 00559 { 00560 using value_type = _Cmpt; 00561 using iterator = value_type*; 00562 using const_iterator = const value_type*; 00563 00564 _List(); 00565 _List(const _List&); 00566 _List(_List&&) = default; 00567 _List& operator=(const _List&); 00568 _List& operator=(_List&&) = default; 00569 ~_List() = default; 00570 00571 _Type type() const noexcept 00572 { return _Type{reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3}; } 00573 00574 void type(_Type) noexcept; 00575 00576 int size() const noexcept; // zero unless type() == _Type::_Multi 00577 bool empty() const noexcept; // true unless type() == _Type::_Multi 00578 void clear(); 00579 void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); } 00580 int capacity() const noexcept; 00581 void reserve(int, bool); ///< @pre type() == _Type::_Multi 00582 00583 // All the member functions below here have a precondition !empty() 00584 // (and they should only be called from within the library). 00585 00586 iterator begin(); 00587 iterator end(); 00588 const_iterator begin() const; 00589 const_iterator end() const; 00590 00591 value_type& front() noexcept; 00592 value_type& back() noexcept; 00593 const value_type& front() const noexcept; 00594 const value_type& back() const noexcept; 00595 00596 void pop_back(); 00597 void _M_erase_from(const_iterator __pos); // erases [__pos,end()) 00598 00599 struct _Impl; 00600 struct _Impl_deleter 00601 { 00602 void operator()(_Impl*) const noexcept; 00603 }; 00604 unique_ptr<_Impl, _Impl_deleter> _M_impl; 00605 }; 00606 _List _M_cmpts; 00607 00608 struct _Parser; 00609 }; 00610 00611 inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } 00612 00613 size_t hash_value(const path& __p) noexcept; 00614 00615 template<typename _InputIterator> 00616 inline auto 00617 u8path(_InputIterator __first, _InputIterator __last) 00618 -> decltype(filesystem::path(__first, __last, std::locale::classic())) 00619 { 00620 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00621 codecvt_utf8<path::value_type> __cvt; 00622 path::string_type __tmp; 00623 if constexpr (is_pointer_v<_InputIterator>) 00624 { 00625 if (__str_codecvt_in(__first, __last, __tmp, __cvt)) 00626 return path{ __tmp }; 00627 } 00628 else 00629 { 00630 const std::string __u8str{__first, __last}; 00631 const char* const __ptr = __u8str.data(); 00632 if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt)) 00633 return path{ __tmp }; 00634 } 00635 return {}; 00636 #else 00637 return path{ __first, __last }; 00638 #endif 00639 } 00640 00641 template<typename _Source> 00642 inline auto 00643 u8path(const _Source& __source) 00644 -> decltype(filesystem::path(__source, std::locale::classic())) 00645 { 00646 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00647 if constexpr (is_convertible_v<const _Source&, std::string_view>) 00648 { 00649 const std::string_view __s = __source; 00650 return filesystem::u8path(__s.data(), __s.data() + __s.size()); 00651 } 00652 else 00653 { 00654 std::string __s = path::_S_string_from_iter(__source); 00655 return filesystem::u8path(__s.data(), __s.data() + __s.size()); 00656 } 00657 #else 00658 return path{ __source }; 00659 #endif 00660 } 00661 00662 class filesystem_error : public std::system_error 00663 { 00664 public: 00665 filesystem_error(const string& __what_arg, error_code __ec); 00666 00667 filesystem_error(const string& __what_arg, const path& __p1, 00668 error_code __ec); 00669 00670 filesystem_error(const string& __what_arg, const path& __p1, 00671 const path& __p2, error_code __ec); 00672 00673 filesystem_error(const filesystem_error&) = default; 00674 filesystem_error& operator=(const filesystem_error&) = default; 00675 00676 // No move constructor or assignment operator. 00677 // Copy rvalues instead, so that _M_impl is not left empty. 00678 00679 ~filesystem_error(); 00680 00681 const path& path1() const noexcept; 00682 const path& path2() const noexcept; 00683 const char* what() const noexcept; 00684 00685 private: 00686 struct _Impl; 00687 std::__shared_ptr<const _Impl> _M_impl; 00688 }; 00689 00690 struct path::_Cmpt : path 00691 { 00692 _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos) 00693 : path(__s, __t), _M_pos(__pos) { } 00694 00695 _Cmpt() : _M_pos(-1) { } 00696 00697 size_t _M_pos; 00698 }; 00699 00700 // specialize _Cvt for degenerate 'noconv' case 00701 template<> 00702 struct path::_Cvt<path::value_type> 00703 { 00704 template<typename _Iter> 00705 static string_type 00706 _S_convert(_Iter __first, _Iter __last) 00707 { return string_type{__first, __last}; } 00708 }; 00709 00710 template<typename _CharT> 00711 struct path::_Cvt 00712 { 00713 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00714 static string_type 00715 _S_wconvert(const char* __f, const char* __l, true_type) 00716 { 00717 using _Cvt = std::codecvt<wchar_t, char, mbstate_t>; 00718 const auto& __cvt = std::use_facet<_Cvt>(std::locale{}); 00719 std::wstring __wstr; 00720 if (__str_codecvt_in(__f, __l, __wstr, __cvt)) 00721 return __wstr; 00722 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00723 "Cannot convert character sequence", 00724 std::make_error_code(errc::illegal_byte_sequence))); 00725 } 00726 00727 static string_type 00728 _S_wconvert(const _CharT* __f, const _CharT* __l, false_type) 00729 { 00730 std::codecvt_utf8<_CharT> __cvt; 00731 std::string __str; 00732 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00733 { 00734 const char* __f2 = __str.data(); 00735 const char* __l2 = __f2 + __str.size(); 00736 std::codecvt_utf8<wchar_t> __wcvt; 00737 std::wstring __wstr; 00738 if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt)) 00739 return __wstr; 00740 } 00741 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00742 "Cannot convert character sequence", 00743 std::make_error_code(errc::illegal_byte_sequence))); 00744 } 00745 00746 static string_type 00747 _S_convert(const _CharT* __f, const _CharT* __l) 00748 { 00749 return _S_wconvert(__f, __l, is_same<_CharT, char>{}); 00750 } 00751 #else 00752 static string_type 00753 _S_convert(const _CharT* __f, const _CharT* __l) 00754 { 00755 #ifdef _GLIBCXX_USE_CHAR8_T 00756 if constexpr (is_same_v<_CharT, char8_t>) 00757 { 00758 string_type __str(__f, __l); 00759 return __str; 00760 } 00761 else 00762 { 00763 #endif 00764 std::codecvt_utf8<_CharT> __cvt; 00765 std::string __str; 00766 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00767 return __str; 00768 #ifdef _GLIBCXX_USE_CHAR8_T 00769 } 00770 #endif 00771 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00772 "Cannot convert character sequence", 00773 std::make_error_code(errc::illegal_byte_sequence))); 00774 } 00775 #endif 00776 00777 static string_type 00778 _S_convert(_CharT* __f, _CharT* __l) 00779 { 00780 return _S_convert(const_cast<const _CharT*>(__f), 00781 const_cast<const _CharT*>(__l)); 00782 } 00783 00784 template<typename _Iter> 00785 static string_type 00786 _S_convert(_Iter __first, _Iter __last) 00787 { 00788 const std::basic_string<_CharT> __str(__first, __last); 00789 return _S_convert(__str.data(), __str.data() + __str.size()); 00790 } 00791 00792 template<typename _Iter, typename _Cont> 00793 static string_type 00794 _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first, 00795 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last) 00796 { return _S_convert(__first.base(), __last.base()); } 00797 }; 00798 00799 /// An iterator for the components of a path 00800 class path::iterator 00801 { 00802 public: 00803 using difference_type = std::ptrdiff_t; 00804 using value_type = path; 00805 using reference = const path&; 00806 using pointer = const path*; 00807 using iterator_category = std::bidirectional_iterator_tag; 00808 00809 iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { } 00810 00811 iterator(const iterator&) = default; 00812 iterator& operator=(const iterator&) = default; 00813 00814 reference operator*() const; 00815 pointer operator->() const { return std::__addressof(**this); } 00816 00817 iterator& operator++(); 00818 iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } 00819 00820 iterator& operator--(); 00821 iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; } 00822 00823 friend bool operator==(const iterator& __lhs, const iterator& __rhs) 00824 { return __lhs._M_equals(__rhs); } 00825 00826 friend bool operator!=(const iterator& __lhs, const iterator& __rhs) 00827 { return !__lhs._M_equals(__rhs); } 00828 00829 private: 00830 friend class path; 00831 00832 bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; } 00833 00834 friend difference_type 00835 __path_iter_distance(const iterator& __first, const iterator& __last) 00836 { 00837 __glibcxx_assert(__first._M_path != nullptr); 00838 __glibcxx_assert(__first._M_path == __last._M_path); 00839 if (__first._M_is_multi()) 00840 return std::distance(__first._M_cur, __last._M_cur); 00841 else if (__first._M_at_end == __last._M_at_end) 00842 return 0; 00843 else 00844 return __first._M_at_end ? -1 : 1; 00845 } 00846 00847 friend void 00848 __path_iter_advance(iterator& __i, difference_type __n) 00849 { 00850 if (__n == 1) 00851 ++__i; 00852 else if (__n == -1) 00853 --__i; 00854 else if (__n != 0) 00855 { 00856 __glibcxx_assert(__i._M_path != nullptr); 00857 __glibcxx_assert(__i._M_is_multi()); 00858 // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n); 00859 __i._M_cur += __n; 00860 } 00861 } 00862 00863 iterator(const path* __path, path::_List::const_iterator __iter) 00864 : _M_path(__path), _M_cur(__iter), _M_at_end() 00865 { } 00866 00867 iterator(const path* __path, bool __at_end) 00868 : _M_path(__path), _M_cur(), _M_at_end(__at_end) 00869 { } 00870 00871 bool _M_equals(iterator) const; 00872 00873 const path* _M_path; 00874 path::_List::const_iterator _M_cur; 00875 bool _M_at_end; // only used when type != _Multi 00876 }; 00877 00878 00879 inline path& 00880 path::operator=(path&& __p) noexcept 00881 { 00882 if (&__p == this) [[__unlikely__]] 00883 return *this; 00884 00885 _M_pathname = std::move(__p._M_pathname); 00886 _M_cmpts = std::move(__p._M_cmpts); 00887 __p.clear(); 00888 return *this; 00889 } 00890 00891 inline path& 00892 path::operator=(string_type&& __source) 00893 { return *this = path(std::move(__source)); } 00894 00895 inline path& 00896 path::assign(string_type&& __source) 00897 { return *this = path(std::move(__source)); } 00898 00899 inline path& 00900 path::operator+=(const string_type& __x) 00901 { 00902 _M_concat(__x); 00903 return *this; 00904 } 00905 00906 inline path& 00907 path::operator+=(const value_type* __x) 00908 { 00909 _M_concat(__x); 00910 return *this; 00911 } 00912 00913 inline path& 00914 path::operator+=(value_type __x) 00915 { 00916 _M_concat(basic_string_view<value_type>(&__x, 1)); 00917 return *this; 00918 } 00919 00920 inline path& 00921 path::operator+=(basic_string_view<value_type> __x) 00922 { 00923 _M_concat(__x); 00924 return *this; 00925 } 00926 00927 template<typename _CharT> 00928 inline path::_Path<_CharT*, _CharT*>& 00929 path::operator+=(_CharT __x) 00930 { 00931 auto* __addr = std::__addressof(__x); 00932 return concat(__addr, __addr + 1); 00933 } 00934 00935 inline path& 00936 path::make_preferred() 00937 { 00938 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00939 std::replace(_M_pathname.begin(), _M_pathname.end(), L'/', 00940 preferred_separator); 00941 #endif 00942 return *this; 00943 } 00944 00945 inline void path::swap(path& __rhs) noexcept 00946 { 00947 _M_pathname.swap(__rhs._M_pathname); 00948 _M_cmpts.swap(__rhs._M_cmpts); 00949 } 00950 00951 template<typename _CharT, typename _Traits, typename _Allocator> 00952 std::basic_string<_CharT, _Traits, _Allocator> 00953 path::_S_str_convert(const string_type& __str, const _Allocator& __a) 00954 { 00955 if (__str.size() == 0) 00956 return std::basic_string<_CharT, _Traits, _Allocator>(__a); 00957 00958 const value_type* __first = __str.data(); 00959 const value_type* __last = __first + __str.size(); 00960 00961 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00962 using _CharAlloc = __alloc_rebind<_Allocator, char>; 00963 using _String = basic_string<char, char_traits<char>, _CharAlloc>; 00964 using _WString = basic_string<_CharT, _Traits, _Allocator>; 00965 00966 // use codecvt_utf8<wchar_t> to convert native string to UTF-8 00967 codecvt_utf8<value_type> __cvt; 00968 _String __u8str{_CharAlloc{__a}}; 00969 if (__str_codecvt_out(__first, __last, __u8str, __cvt)) 00970 { 00971 if constexpr (is_same_v<_CharT, char>) 00972 return __u8str; 00973 #ifdef _GLIBCXX_USE_CHAR8_T 00974 else if constexpr (is_same_v<_CharT, char8_t>) 00975 { 00976 const char* __f = __u8str.data(); 00977 const char* __l = __f + __u8str.size(); 00978 _WString __wstr(__f, __l); 00979 return __wstr; 00980 } 00981 #endif 00982 else 00983 { 00984 _WString __wstr; 00985 // use codecvt_utf8<_CharT> to convert UTF-8 to wide string 00986 codecvt_utf8<_CharT> __cvt; 00987 const char* __f = __u8str.data(); 00988 const char* __l = __f + __u8str.size(); 00989 if (__str_codecvt_in(__f, __l, __wstr, __cvt)) 00990 return __wstr; 00991 } 00992 } 00993 #else 00994 #ifdef _GLIBCXX_USE_CHAR8_T 00995 if constexpr (is_same_v<_CharT, char8_t>) 00996 { 00997 basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a}; 00998 return __wstr; 00999 } 01000 else 01001 { 01002 #endif 01003 codecvt_utf8<_CharT> __cvt; 01004 basic_string<_CharT, _Traits, _Allocator> __wstr{__a}; 01005 if (__str_codecvt_in(__first, __last, __wstr, __cvt)) 01006 return __wstr; 01007 #ifdef _GLIBCXX_USE_CHAR8_T 01008 } 01009 #endif 01010 #endif 01011 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 01012 "Cannot convert character sequence", 01013 std::make_error_code(errc::illegal_byte_sequence))); 01014 } 01015 01016 template<typename _CharT, typename _Traits, typename _Allocator> 01017 inline basic_string<_CharT, _Traits, _Allocator> 01018 path::string(const _Allocator& __a) const 01019 { 01020 if constexpr (is_same_v<_CharT, value_type>) 01021 return { _M_pathname, __a }; 01022 else 01023 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); 01024 } 01025 01026 inline std::string 01027 path::string() const { return string<char>(); } 01028 01029 #if _GLIBCXX_USE_WCHAR_T 01030 inline std::wstring 01031 path::wstring() const { return string<wchar_t>(); } 01032 #endif 01033 01034 #ifdef _GLIBCXX_USE_CHAR8_T 01035 inline std::u8string 01036 path::u8string() const { return string<char8_t>(); } 01037 #else 01038 inline std::string 01039 path::u8string() const 01040 { 01041 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01042 std::string __str; 01043 // convert from native encoding to UTF-8 01044 codecvt_utf8<value_type> __cvt; 01045 const value_type* __first = _M_pathname.data(); 01046 const value_type* __last = __first + _M_pathname.size(); 01047 if (__str_codecvt_out(__first, __last, __str, __cvt)) 01048 return __str; 01049 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 01050 "Cannot convert character sequence", 01051 std::make_error_code(errc::illegal_byte_sequence))); 01052 #else 01053 return _M_pathname; 01054 #endif 01055 } 01056 #endif // _GLIBCXX_USE_CHAR8_T 01057 01058 inline std::u16string 01059 path::u16string() const { return string<char16_t>(); } 01060 01061 inline std::u32string 01062 path::u32string() const { return string<char32_t>(); } 01063 01064 template<typename _CharT, typename _Traits, typename _Allocator> 01065 inline std::basic_string<_CharT, _Traits, _Allocator> 01066 path::generic_string(const _Allocator& __a) const 01067 { 01068 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01069 const value_type __slash = L'/'; 01070 #else 01071 const value_type __slash = '/'; 01072 #endif 01073 string_type __str(__a); 01074 01075 if (_M_type() == _Type::_Root_dir) 01076 __str.assign(1, __slash); 01077 else 01078 { 01079 __str.reserve(_M_pathname.size()); 01080 bool __add_slash = false; 01081 for (auto& __elem : *this) 01082 { 01083 if (__add_slash) 01084 __str += __slash; 01085 __str += __elem._M_pathname; 01086 __add_slash = __elem._M_type() == _Type::_Filename; 01087 } 01088 } 01089 01090 if constexpr (is_same_v<_CharT, value_type>) 01091 return __str; 01092 else 01093 return _S_str_convert<_CharT, _Traits>(__str, __a); 01094 } 01095 01096 inline std::string 01097 path::generic_string() const 01098 { return generic_string<char>(); } 01099 01100 #if _GLIBCXX_USE_WCHAR_T 01101 inline std::wstring 01102 path::generic_wstring() const 01103 { return generic_string<wchar_t>(); } 01104 #endif 01105 01106 #ifdef _GLIBCXX_USE_CHAR8_T 01107 inline std::u8string 01108 path::generic_u8string() const 01109 { return generic_string<char8_t>(); } 01110 #else 01111 inline std::string 01112 path::generic_u8string() const 01113 { return generic_string(); } 01114 #endif 01115 01116 inline std::u16string 01117 path::generic_u16string() const 01118 { return generic_string<char16_t>(); } 01119 01120 inline std::u32string 01121 path::generic_u32string() const 01122 { return generic_string<char32_t>(); } 01123 01124 inline int 01125 path::compare(const string_type& __s) const noexcept 01126 { return compare(basic_string_view<value_type>(__s)); } 01127 01128 inline int 01129 path::compare(const value_type* __s) const noexcept 01130 { return compare(basic_string_view<value_type>(__s)); } 01131 01132 inline path 01133 path::filename() const 01134 { 01135 if (empty()) 01136 return {}; 01137 else if (_M_type() == _Type::_Filename) 01138 return *this; 01139 else if (_M_type() == _Type::_Multi) 01140 { 01141 if (_M_pathname.back() == preferred_separator) 01142 return {}; 01143 auto& __last = *--end(); 01144 if (__last._M_type() == _Type::_Filename) 01145 return __last; 01146 } 01147 return {}; 01148 } 01149 01150 inline path 01151 path::stem() const 01152 { 01153 auto ext = _M_find_extension(); 01154 if (ext.first && ext.second != 0) 01155 return path{ext.first->substr(0, ext.second)}; 01156 return {}; 01157 } 01158 01159 inline path 01160 path::extension() const 01161 { 01162 auto ext = _M_find_extension(); 01163 if (ext.first && ext.second != string_type::npos) 01164 return path{ext.first->substr(ext.second)}; 01165 return {}; 01166 } 01167 01168 inline bool 01169 path::has_stem() const noexcept 01170 { 01171 auto ext = _M_find_extension(); 01172 return ext.first && ext.second != 0; 01173 } 01174 01175 inline bool 01176 path::has_extension() const noexcept 01177 { 01178 auto ext = _M_find_extension(); 01179 return ext.first && ext.second != string_type::npos; 01180 } 01181 01182 inline bool 01183 path::is_absolute() const noexcept 01184 { 01185 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01186 return has_root_name() && has_root_directory(); 01187 #else 01188 return has_root_directory(); 01189 #endif 01190 } 01191 01192 inline path::iterator 01193 path::begin() const 01194 { 01195 if (_M_type() == _Type::_Multi) 01196 return iterator(this, _M_cmpts.begin()); 01197 return iterator(this, empty()); 01198 } 01199 01200 inline path::iterator 01201 path::end() const 01202 { 01203 if (_M_type() == _Type::_Multi) 01204 return iterator(this, _M_cmpts.end()); 01205 return iterator(this, true); 01206 } 01207 01208 inline path::iterator& 01209 path::iterator::operator++() 01210 { 01211 __glibcxx_assert(_M_path != nullptr); 01212 if (_M_path->_M_type() == _Type::_Multi) 01213 { 01214 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01215 ++_M_cur; 01216 } 01217 else 01218 { 01219 __glibcxx_assert(!_M_at_end); 01220 _M_at_end = true; 01221 } 01222 return *this; 01223 } 01224 01225 inline path::iterator& 01226 path::iterator::operator--() 01227 { 01228 __glibcxx_assert(_M_path != nullptr); 01229 if (_M_path->_M_type() == _Type::_Multi) 01230 { 01231 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); 01232 --_M_cur; 01233 } 01234 else 01235 { 01236 __glibcxx_assert(_M_at_end); 01237 _M_at_end = false; 01238 } 01239 return *this; 01240 } 01241 01242 inline path::iterator::reference 01243 path::iterator::operator*() const 01244 { 01245 __glibcxx_assert(_M_path != nullptr); 01246 if (_M_path->_M_type() == _Type::_Multi) 01247 { 01248 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01249 return *_M_cur; 01250 } 01251 return *_M_path; 01252 } 01253 01254 inline bool 01255 path::iterator::_M_equals(iterator __rhs) const 01256 { 01257 if (_M_path != __rhs._M_path) 01258 return false; 01259 if (_M_path == nullptr) 01260 return true; 01261 if (_M_path->_M_type() == path::_Type::_Multi) 01262 return _M_cur == __rhs._M_cur; 01263 return _M_at_end == __rhs._M_at_end; 01264 } 01265 01266 // @} group filesystem 01267 _GLIBCXX_END_NAMESPACE_CXX11 01268 } // namespace filesystem 01269 01270 inline ptrdiff_t 01271 distance(filesystem::path::iterator __first, filesystem::path::iterator __last) 01272 { return __path_iter_distance(__first, __last); } 01273 01274 template<typename _InputIterator, typename _Distance> 01275 void 01276 advance(filesystem::path::iterator& __i, _Distance __n) 01277 { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); } 01278 01279 extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>; 01280 01281 _GLIBCXX_END_NAMESPACE_VERSION 01282 } // namespace std 01283 01284 #endif // C++17 01285 01286 #endif // _GLIBCXX_FS_PATH_H