|
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 const 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 /// Exception type thrown by the Filesystem library 00616 class filesystem_error : public std::system_error 00617 { 00618 public: 00619 filesystem_error(const string& __what_arg, error_code __ec); 00620 00621 filesystem_error(const string& __what_arg, const path& __p1, 00622 error_code __ec); 00623 00624 filesystem_error(const string& __what_arg, const path& __p1, 00625 const path& __p2, error_code __ec); 00626 00627 filesystem_error(const filesystem_error&) = default; 00628 filesystem_error& operator=(const filesystem_error&) = default; 00629 00630 // No move constructor or assignment operator. 00631 // Copy rvalues instead, so that _M_impl is not left empty. 00632 00633 ~filesystem_error(); 00634 00635 const path& path1() const noexcept; 00636 const path& path2() const noexcept; 00637 const char* what() const noexcept; 00638 00639 private: 00640 struct _Impl; 00641 std::__shared_ptr<const _Impl> _M_impl; 00642 }; 00643 00644 /// Create a path from a UTF-8-encoded sequence of char 00645 template<typename _InputIterator> 00646 inline auto 00647 u8path(_InputIterator __first, _InputIterator __last) 00648 -> decltype(filesystem::path(__first, __last, std::locale::classic())) 00649 { 00650 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00651 // XXX This assumes native wide encoding is UTF-16. 00652 std::codecvt_utf8_utf16<path::value_type> __cvt; 00653 path::string_type __tmp; 00654 if constexpr (is_pointer_v<_InputIterator>) 00655 { 00656 if (__str_codecvt_in_all(__first, __last, __tmp, __cvt)) 00657 return path{ __tmp }; 00658 } 00659 else 00660 { 00661 const std::string __u8str{__first, __last}; 00662 const char* const __ptr = __u8str.data(); 00663 if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt)) 00664 return path{ __tmp }; 00665 } 00666 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00667 "Cannot convert character sequence", 00668 std::make_error_code(errc::illegal_byte_sequence))); 00669 #else 00670 // This assumes native normal encoding is UTF-8. 00671 return path{ __first, __last }; 00672 #endif 00673 } 00674 00675 /// Create a path from a UTF-8-encoded sequence of char 00676 template<typename _Source> 00677 inline auto 00678 u8path(const _Source& __source) 00679 -> decltype(filesystem::path(__source, std::locale::classic())) 00680 { 00681 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00682 if constexpr (is_convertible_v<const _Source&, std::string_view>) 00683 { 00684 const std::string_view __s = __source; 00685 return filesystem::u8path(__s.data(), __s.data() + __s.size()); 00686 } 00687 else 00688 { 00689 std::string __s = path::_S_string_from_iter(__source); 00690 return filesystem::u8path(__s.data(), __s.data() + __s.size()); 00691 } 00692 #else 00693 return path{ __source }; 00694 #endif 00695 } 00696 00697 struct path::_Cmpt : path 00698 { 00699 _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos) 00700 : path(__s, __t), _M_pos(__pos) { } 00701 00702 _Cmpt() : _M_pos(-1) { } 00703 00704 size_t _M_pos; 00705 }; 00706 00707 // specialize _Cvt for degenerate 'noconv' case 00708 template<> 00709 struct path::_Cvt<path::value_type> 00710 { 00711 template<typename _Iter> 00712 static string_type 00713 _S_convert(_Iter __first, _Iter __last) 00714 { return string_type{__first, __last}; } 00715 }; 00716 00717 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T 00718 // For POSIX converting from char8_t to char is also 'noconv' 00719 template<> 00720 struct path::_Cvt<char8_t> 00721 { 00722 template<typename _Iter> 00723 static string_type 00724 _S_convert(_Iter __first, _Iter __last) 00725 { return string_type(__first, __last); } 00726 }; 00727 #endif 00728 00729 template<typename _CharT> 00730 struct path::_Cvt 00731 { 00732 static string_type 00733 _S_convert(const _CharT* __f, const _CharT* __l) 00734 { 00735 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00736 std::wstring __wstr; 00737 if constexpr (is_same_v<_CharT, char>) 00738 { 00739 struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t> 00740 { } __cvt; 00741 if (__str_codecvt_in_all(__f, __l, __wstr, __cvt)) 00742 return __wstr; 00743 } 00744 #ifdef _GLIBCXX_USE_CHAR8_T 00745 else if constexpr (is_same_v<_CharT, char8_t>) 00746 { 00747 const char* __f2 = (const char*)__f; 00748 const char* __l2 = (const char*)__l; 00749 std::codecvt_utf8_utf16<wchar_t> __wcvt; 00750 if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt)) 00751 return __wstr; 00752 } 00753 #endif 00754 else // char16_t or char32_t 00755 { 00756 struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> 00757 { } __cvt; 00758 std::string __str; 00759 if (__str_codecvt_out_all(__f, __l, __str, __cvt)) 00760 { 00761 const char* __f2 = __str.data(); 00762 const char* __l2 = __f2 + __str.size(); 00763 std::codecvt_utf8_utf16<wchar_t> __wcvt; 00764 if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt)) 00765 return __wstr; 00766 } 00767 } 00768 #else // ! windows 00769 struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> 00770 { } __cvt; 00771 std::string __str; 00772 if (__str_codecvt_out_all(__f, __l, __str, __cvt)) 00773 return __str; 00774 #endif 00775 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00776 "Cannot convert character sequence", 00777 std::make_error_code(errc::illegal_byte_sequence))); 00778 } 00779 00780 static string_type 00781 _S_convert(_CharT* __f, _CharT* __l) 00782 { 00783 return _S_convert(const_cast<const _CharT*>(__f), 00784 const_cast<const _CharT*>(__l)); 00785 } 00786 00787 template<typename _Iter> 00788 static string_type 00789 _S_convert(_Iter __first, _Iter __last) 00790 { 00791 const std::basic_string<_CharT> __str(__first, __last); 00792 return _S_convert(__str.data(), __str.data() + __str.size()); 00793 } 00794 00795 template<typename _Iter, typename _Cont> 00796 static string_type 00797 _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first, 00798 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last) 00799 { return _S_convert(__first.base(), __last.base()); } 00800 }; 00801 00802 /// An iterator for the components of a path 00803 class path::iterator 00804 { 00805 public: 00806 using difference_type = std::ptrdiff_t; 00807 using value_type = path; 00808 using reference = const path&; 00809 using pointer = const path*; 00810 using iterator_category = std::bidirectional_iterator_tag; 00811 00812 iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { } 00813 00814 iterator(const iterator&) = default; 00815 iterator& operator=(const iterator&) = default; 00816 00817 reference operator*() const; 00818 pointer operator->() const { return std::__addressof(**this); } 00819 00820 iterator& operator++(); 00821 iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } 00822 00823 iterator& operator--(); 00824 iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; } 00825 00826 friend bool operator==(const iterator& __lhs, const iterator& __rhs) 00827 { return __lhs._M_equals(__rhs); } 00828 00829 friend bool operator!=(const iterator& __lhs, const iterator& __rhs) 00830 { return !__lhs._M_equals(__rhs); } 00831 00832 private: 00833 friend class path; 00834 00835 bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; } 00836 00837 friend difference_type 00838 __path_iter_distance(const iterator& __first, const iterator& __last) 00839 { 00840 __glibcxx_assert(__first._M_path != nullptr); 00841 __glibcxx_assert(__first._M_path == __last._M_path); 00842 if (__first._M_is_multi()) 00843 return std::distance(__first._M_cur, __last._M_cur); 00844 else if (__first._M_at_end == __last._M_at_end) 00845 return 0; 00846 else 00847 return __first._M_at_end ? -1 : 1; 00848 } 00849 00850 friend void 00851 __path_iter_advance(iterator& __i, difference_type __n) 00852 { 00853 if (__n == 1) 00854 ++__i; 00855 else if (__n == -1) 00856 --__i; 00857 else if (__n != 0) 00858 { 00859 __glibcxx_assert(__i._M_path != nullptr); 00860 __glibcxx_assert(__i._M_is_multi()); 00861 // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n); 00862 __i._M_cur += __n; 00863 } 00864 } 00865 00866 iterator(const path* __path, path::_List::const_iterator __iter) 00867 : _M_path(__path), _M_cur(__iter), _M_at_end() 00868 { } 00869 00870 iterator(const path* __path, bool __at_end) 00871 : _M_path(__path), _M_cur(), _M_at_end(__at_end) 00872 { } 00873 00874 bool _M_equals(iterator) const; 00875 00876 const path* _M_path; 00877 path::_List::const_iterator _M_cur; 00878 bool _M_at_end; // only used when type != _Multi 00879 }; 00880 00881 00882 inline path& 00883 path::operator=(path&& __p) noexcept 00884 { 00885 if (&__p == this) [[__unlikely__]] 00886 return *this; 00887 00888 _M_pathname = std::move(__p._M_pathname); 00889 _M_cmpts = std::move(__p._M_cmpts); 00890 __p.clear(); 00891 return *this; 00892 } 00893 00894 inline path& 00895 path::operator=(string_type&& __source) 00896 { return *this = path(std::move(__source)); } 00897 00898 inline path& 00899 path::assign(string_type&& __source) 00900 { return *this = path(std::move(__source)); } 00901 00902 inline path& 00903 path::operator+=(const string_type& __x) 00904 { 00905 _M_concat(__x); 00906 return *this; 00907 } 00908 00909 inline path& 00910 path::operator+=(const value_type* __x) 00911 { 00912 _M_concat(__x); 00913 return *this; 00914 } 00915 00916 inline path& 00917 path::operator+=(value_type __x) 00918 { 00919 _M_concat(basic_string_view<value_type>(&__x, 1)); 00920 return *this; 00921 } 00922 00923 inline path& 00924 path::operator+=(basic_string_view<value_type> __x) 00925 { 00926 _M_concat(__x); 00927 return *this; 00928 } 00929 00930 template<typename _CharT> 00931 inline path::_Path<_CharT*, _CharT*>& 00932 path::operator+=(_CharT __x) 00933 { 00934 auto* __addr = std::__addressof(__x); 00935 return concat(__addr, __addr + 1); 00936 } 00937 00938 inline path& 00939 path::make_preferred() 00940 { 00941 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00942 std::replace(_M_pathname.begin(), _M_pathname.end(), L'/', 00943 preferred_separator); 00944 #endif 00945 return *this; 00946 } 00947 00948 inline void path::swap(path& __rhs) noexcept 00949 { 00950 _M_pathname.swap(__rhs._M_pathname); 00951 _M_cmpts.swap(__rhs._M_cmpts); 00952 } 00953 00954 template<typename _CharT, typename _Traits, typename _Allocator> 00955 std::basic_string<_CharT, _Traits, _Allocator> 00956 path::_S_str_convert(const string_type& __str, const _Allocator& __a) 00957 { 00958 static_assert(!is_same_v<_CharT, value_type>); 00959 00960 using _WString = basic_string<_CharT, _Traits, _Allocator>; 00961 00962 if (__str.size() == 0) 00963 return _WString(__a); 00964 00965 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00966 // First convert native string from UTF-16 to to UTF-8. 00967 // XXX This assumes that the execution wide-character set is UTF-16. 00968 std::codecvt_utf8_utf16<value_type> __cvt; 00969 00970 using _CharAlloc = __alloc_rebind<_Allocator, char>; 00971 using _String = basic_string<char, char_traits<char>, _CharAlloc>; 00972 _String __u8str{_CharAlloc{__a}}; 00973 const value_type* __wfirst = __str.data(); 00974 const value_type* __wlast = __wfirst + __str.size(); 00975 if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) { 00976 if constexpr (is_same_v<_CharT, char>) 00977 return __u8str; // XXX assumes native ordinary encoding is UTF-8. 00978 else { 00979 00980 const char* __first = __u8str.data(); 00981 const char* __last = __first + __u8str.size(); 00982 #else 00983 const value_type* __first = __str.data(); 00984 const value_type* __last = __first + __str.size(); 00985 #endif 00986 00987 // Convert UTF-8 string to requested format. 00988 #ifdef _GLIBCXX_USE_CHAR8_T 00989 if constexpr (is_same_v<_CharT, char8_t>) 00990 return _WString(__first, __last, __a); 00991 else 00992 #endif 00993 { 00994 // Convert UTF-8 to wide string. 00995 _WString __wstr(__a); 00996 struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt; 00997 if (__str_codecvt_in_all(__first, __last, __wstr, __cvt)) 00998 return __wstr; 00999 } 01000 01001 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01002 } } 01003 #endif 01004 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 01005 "Cannot convert character sequence", 01006 std::make_error_code(errc::illegal_byte_sequence))); 01007 } 01008 01009 template<typename _CharT, typename _Traits, typename _Allocator> 01010 inline basic_string<_CharT, _Traits, _Allocator> 01011 path::string(const _Allocator& __a) const 01012 { 01013 if constexpr (is_same_v<_CharT, value_type>) 01014 return { _M_pathname.c_str(), _M_pathname.length(), __a }; 01015 else 01016 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); 01017 } 01018 01019 inline std::string 01020 path::string() const { return string<char>(); } 01021 01022 #if _GLIBCXX_USE_WCHAR_T 01023 inline std::wstring 01024 path::wstring() const { return string<wchar_t>(); } 01025 #endif 01026 01027 #ifdef _GLIBCXX_USE_CHAR8_T 01028 inline std::u8string 01029 path::u8string() const { return string<char8_t>(); } 01030 #else 01031 inline std::string 01032 path::u8string() const 01033 { 01034 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01035 std::string __str; 01036 // convert from native wide encoding (assumed to be UTF-16) to UTF-8 01037 std::codecvt_utf8_utf16<value_type> __cvt; 01038 const value_type* __first = _M_pathname.data(); 01039 const value_type* __last = __first + _M_pathname.size(); 01040 if (__str_codecvt_out_all(__first, __last, __str, __cvt)) 01041 return __str; 01042 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 01043 "Cannot convert character sequence", 01044 std::make_error_code(errc::illegal_byte_sequence))); 01045 #else 01046 return _M_pathname; 01047 #endif 01048 } 01049 #endif // _GLIBCXX_USE_CHAR8_T 01050 01051 inline std::u16string 01052 path::u16string() const { return string<char16_t>(); } 01053 01054 inline std::u32string 01055 path::u32string() const { return string<char32_t>(); } 01056 01057 template<typename _CharT, typename _Traits, typename _Allocator> 01058 inline std::basic_string<_CharT, _Traits, _Allocator> 01059 path::generic_string(const _Allocator& __a) const 01060 { 01061 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01062 const value_type __slash = L'/'; 01063 #else 01064 const value_type __slash = '/'; 01065 #endif 01066 string_type __str(__a); 01067 01068 if (_M_type() == _Type::_Root_dir) 01069 __str.assign(1, __slash); 01070 else 01071 { 01072 __str.reserve(_M_pathname.size()); 01073 bool __add_slash = false; 01074 for (auto& __elem : *this) 01075 { 01076 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01077 if (__elem._M_type() == _Type::_Root_dir) 01078 { 01079 __str += __slash; 01080 continue; 01081 } 01082 #endif 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