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 experimental/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{experimental/filesystem} 00028 */ 00029 00030 #ifndef _GLIBCXX_EXPERIMENTAL_FS_PATH_H 00031 #define _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1 00032 00033 #if __cplusplus < 201103L 00034 # include <bits/c++0x_warning.h> 00035 #else 00036 00037 #include <utility> 00038 #include <type_traits> 00039 #include <vector> 00040 #include <locale> 00041 #include <iosfwd> 00042 #include <codecvt> 00043 #include <system_error> 00044 #include <bits/stl_algobase.h> 00045 #include <bits/quoted_string.h> 00046 #include <bits/locale_conv.h> 00047 #if __cplusplus == 201402L 00048 # include <experimental/string_view> 00049 #endif 00050 00051 #if defined(_WIN32) && !defined(__CYGWIN__) 00052 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 00053 # include <algorithm> 00054 #endif 00055 00056 namespace std _GLIBCXX_VISIBILITY(default) 00057 { 00058 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00059 00060 namespace experimental 00061 { 00062 namespace filesystem 00063 { 00064 inline namespace v1 00065 { 00066 _GLIBCXX_BEGIN_NAMESPACE_CXX11 00067 00068 #if __cplusplus == 201402L 00069 using std::experimental::basic_string_view; 00070 #elif __cplusplus > 201402L 00071 using std::basic_string_view; 00072 #endif 00073 00074 /** 00075 * @ingroup filesystem-ts 00076 * @{ 00077 */ 00078 00079 /// A filesystem path. 00080 class path 00081 { 00082 template<typename _CharT, 00083 typename _Ch = typename remove_const<_CharT>::type> 00084 using __is_encoded_char 00085 = __or_<is_same<_Ch, char>, 00086 is_same<_Ch, wchar_t>, 00087 #ifdef _GLIBCXX_USE_CHAR8_T 00088 is_same<_Ch, char8_t>, 00089 #endif 00090 is_same<_Ch, char16_t>, 00091 is_same<_Ch, char32_t>>; 00092 00093 template<typename _Iter, 00094 typename _Iter_traits = std::iterator_traits<_Iter>> 00095 using __is_path_iter_src 00096 = __and_<__is_encoded_char<typename _Iter_traits::value_type>, 00097 std::is_base_of<std::input_iterator_tag, 00098 typename _Iter_traits::iterator_category>>; 00099 00100 template<typename _Iter> 00101 static __is_path_iter_src<_Iter> 00102 __is_path_src(_Iter, int); 00103 00104 template<typename _CharT, typename _Traits, typename _Alloc> 00105 static __is_encoded_char<_CharT> 00106 __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); 00107 00108 #if __cplusplus >= 201402L 00109 template<typename _CharT, typename _Traits> 00110 static __is_encoded_char<_CharT> 00111 __is_path_src(const basic_string_view<_CharT, _Traits>&, int); 00112 #endif 00113 00114 template<typename _Unknown> 00115 static std::false_type 00116 __is_path_src(const _Unknown&, ...); 00117 00118 template<typename _Tp1, typename _Tp2> 00119 struct __constructible_from; 00120 00121 template<typename _Iter> 00122 struct __constructible_from<_Iter, _Iter> 00123 : __is_path_iter_src<_Iter> 00124 { }; 00125 00126 template<typename _Source> 00127 struct __constructible_from<_Source, void> 00128 : decltype(__is_path_src(std::declval<_Source>(), 0)) 00129 { }; 00130 00131 template<typename _Tp1, typename _Tp2 = void, 00132 typename _Tp1_nocv = typename remove_cv<_Tp1>::type, 00133 typename _Tp1_noptr = typename remove_pointer<_Tp1>::type> 00134 using _Path = typename 00135 std::enable_if<__and_<__not_<is_same<_Tp1_nocv, path>>, 00136 __not_<is_void<_Tp1_noptr>>, 00137 __constructible_from<_Tp1, _Tp2>>::value, 00138 path>::type; 00139 00140 template<typename _Source> 00141 static _Source 00142 _S_range_begin(_Source __begin) { return __begin; } 00143 00144 struct __null_terminated { }; 00145 00146 template<typename _Source> 00147 static __null_terminated 00148 _S_range_end(_Source) { return {}; } 00149 00150 template<typename _CharT, typename _Traits, typename _Alloc> 00151 static const _CharT* 00152 _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) 00153 { return __str.data(); } 00154 00155 template<typename _CharT, typename _Traits, typename _Alloc> 00156 static const _CharT* 00157 _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) 00158 { return __str.data() + __str.size(); } 00159 00160 #if __cplusplus >= 201402L 00161 template<typename _CharT, typename _Traits> 00162 static const _CharT* 00163 _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) 00164 { return __str.data(); } 00165 00166 template<typename _CharT, typename _Traits> 00167 static const _CharT* 00168 _S_range_end(const basic_string_view<_CharT, _Traits>& __str) 00169 { return __str.data() + __str.size(); } 00170 #endif 00171 00172 template<typename _Tp, 00173 typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())), 00174 typename _Val = typename std::iterator_traits<_Iter>::value_type> 00175 using __value_type_is_char = typename std::enable_if< 00176 std::is_same<typename std::remove_const<_Val>::type, char>::value 00177 >::type; 00178 00179 public: 00180 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00181 typedef wchar_t value_type; 00182 static constexpr value_type preferred_separator = L'\\'; 00183 #else 00184 typedef char value_type; 00185 static constexpr value_type preferred_separator = '/'; 00186 #endif 00187 typedef std::basic_string<value_type> string_type; 00188 00189 // constructors and destructor 00190 00191 path() noexcept { } 00192 00193 path(const path& __p) = default; 00194 00195 path(path&& __p) noexcept 00196 : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type) 00197 { 00198 if (_M_type == _Type::_Multi) 00199 _M_split_cmpts(); 00200 __p.clear(); 00201 } 00202 00203 path(string_type&& __source) 00204 : _M_pathname(std::move(__source)) 00205 { _M_split_cmpts(); } 00206 00207 template<typename _Source, 00208 typename _Require = _Path<_Source>> 00209 path(_Source const& __source) 00210 : _M_pathname(_S_convert(_S_range_begin(__source), 00211 _S_range_end(__source))) 00212 { _M_split_cmpts(); } 00213 00214 template<typename _InputIterator, 00215 typename _Require = _Path<_InputIterator, _InputIterator>> 00216 path(_InputIterator __first, _InputIterator __last) 00217 : _M_pathname(_S_convert(__first, __last)) 00218 { _M_split_cmpts(); } 00219 00220 template<typename _Source, 00221 typename _Require = _Path<_Source>, 00222 typename _Require2 = __value_type_is_char<_Source>> 00223 path(_Source const& __source, const locale& __loc) 00224 : _M_pathname(_S_convert_loc(_S_range_begin(__source), 00225 _S_range_end(__source), __loc)) 00226 { _M_split_cmpts(); } 00227 00228 template<typename _InputIterator, 00229 typename _Require = _Path<_InputIterator, _InputIterator>, 00230 typename _Require2 = __value_type_is_char<_InputIterator>> 00231 path(_InputIterator __first, _InputIterator __last, const locale& __loc) 00232 : _M_pathname(_S_convert_loc(__first, __last, __loc)) 00233 { _M_split_cmpts(); } 00234 00235 ~path() = default; 00236 00237 // assignments 00238 00239 path& operator=(const path& __p) = default; 00240 path& operator=(path&& __p) noexcept; 00241 path& operator=(string_type&& __source); 00242 path& assign(string_type&& __source); 00243 00244 template<typename _Source> 00245 _Path<_Source>& 00246 operator=(_Source const& __source) 00247 { return *this = path(__source); } 00248 00249 template<typename _Source> 00250 _Path<_Source>& 00251 assign(_Source const& __source) 00252 { return *this = path(__source); } 00253 00254 template<typename _InputIterator> 00255 _Path<_InputIterator, _InputIterator>& 00256 assign(_InputIterator __first, _InputIterator __last) 00257 { return *this = path(__first, __last); } 00258 00259 // appends 00260 00261 path& operator/=(const path& __p) { return _M_append(__p._M_pathname); } 00262 00263 template <class _Source> 00264 _Path<_Source>& 00265 operator/=(_Source const& __source) 00266 { return append(__source); } 00267 00268 template<typename _Source> 00269 _Path<_Source>& 00270 append(_Source const& __source) 00271 { 00272 return _M_append(_S_convert(_S_range_begin(__source), 00273 _S_range_end(__source))); 00274 } 00275 00276 template<typename _InputIterator> 00277 _Path<_InputIterator, _InputIterator>& 00278 append(_InputIterator __first, _InputIterator __last) 00279 { return _M_append(_S_convert(__first, __last)); } 00280 00281 // concatenation 00282 00283 path& operator+=(const path& __x); 00284 path& operator+=(const string_type& __x); 00285 path& operator+=(const value_type* __x); 00286 path& operator+=(value_type __x); 00287 #if __cplusplus >= 201402L 00288 path& operator+=(basic_string_view<value_type> __x); 00289 #endif 00290 00291 template<typename _Source> 00292 _Path<_Source>& 00293 operator+=(_Source const& __x) { return concat(__x); } 00294 00295 template<typename _CharT> 00296 _Path<_CharT*, _CharT*>& 00297 operator+=(_CharT __x); 00298 00299 template<typename _Source> 00300 _Path<_Source>& 00301 concat(_Source const& __x) 00302 { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); } 00303 00304 template<typename _InputIterator> 00305 _Path<_InputIterator, _InputIterator>& 00306 concat(_InputIterator __first, _InputIterator __last) 00307 { return *this += _S_convert(__first, __last); } 00308 00309 // modifiers 00310 00311 void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } 00312 00313 path& make_preferred(); 00314 path& remove_filename(); 00315 path& replace_filename(const path& __replacement); 00316 path& replace_extension(const path& __replacement = path()); 00317 00318 void swap(path& __rhs) noexcept; 00319 00320 // native format observers 00321 00322 const string_type& native() const noexcept { return _M_pathname; } 00323 const value_type* c_str() const noexcept { return _M_pathname.c_str(); } 00324 operator string_type() const { return _M_pathname; } 00325 00326 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00327 typename _Allocator = std::allocator<_CharT>> 00328 std::basic_string<_CharT, _Traits, _Allocator> 00329 string(const _Allocator& __a = _Allocator()) const; 00330 00331 std::string string() const; 00332 #if _GLIBCXX_USE_WCHAR_T 00333 std::wstring wstring() const; 00334 #endif 00335 #ifdef _GLIBCXX_USE_CHAR8_T 00336 __attribute__((__abi_tag__("__u8"))) 00337 std::u8string u8string() const; 00338 #else 00339 std::string u8string() const; 00340 #endif // _GLIBCXX_USE_CHAR8_T 00341 std::u16string u16string() const; 00342 std::u32string u32string() const; 00343 00344 // generic format observers 00345 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00346 typename _Allocator = std::allocator<_CharT>> 00347 std::basic_string<_CharT, _Traits, _Allocator> 00348 generic_string(const _Allocator& __a = _Allocator()) const; 00349 00350 std::string generic_string() const; 00351 #if _GLIBCXX_USE_WCHAR_T 00352 std::wstring generic_wstring() const; 00353 #endif 00354 #ifdef _GLIBCXX_USE_CHAR8_T 00355 __attribute__((__abi_tag__("__u8"))) 00356 std::u8string generic_u8string() const; 00357 #else 00358 std::string generic_u8string() const; 00359 #endif // _GLIBCXX_USE_CHAR8_T 00360 std::u16string generic_u16string() const; 00361 std::u32string generic_u32string() const; 00362 00363 // compare 00364 00365 int compare(const path& __p) const noexcept; 00366 int compare(const string_type& __s) const; 00367 int compare(const value_type* __s) const; 00368 #if __cplusplus >= 201402L 00369 int compare(const basic_string_view<value_type> __s) const; 00370 #endif 00371 00372 // decomposition 00373 00374 path root_name() const; 00375 path root_directory() const; 00376 path root_path() const; 00377 path relative_path() const; 00378 path parent_path() const; 00379 path filename() const; 00380 path stem() const; 00381 path extension() const; 00382 00383 // query 00384 00385 _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_pathname.empty(); } 00386 bool has_root_name() const; 00387 bool has_root_directory() const; 00388 bool has_root_path() const; 00389 bool has_relative_path() const; 00390 bool has_parent_path() const; 00391 bool has_filename() const; 00392 bool has_stem() const; 00393 bool has_extension() const; 00394 bool is_absolute() const; 00395 bool is_relative() const { return !is_absolute(); } 00396 00397 // iterators 00398 class iterator; 00399 typedef iterator const_iterator; 00400 00401 iterator begin() const; 00402 iterator end() const; 00403 00404 // Create a basic_string by reading until a null character. 00405 template<typename _InputIterator, 00406 typename _Traits = std::iterator_traits<_InputIterator>, 00407 typename _CharT 00408 = typename std::remove_cv<typename _Traits::value_type>::type> 00409 static std::basic_string<_CharT> 00410 _S_string_from_iter(_InputIterator __source) 00411 { 00412 std::basic_string<_CharT> __str; 00413 for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source) 00414 __str.push_back(__ch); 00415 return __str; 00416 } 00417 00418 private: 00419 enum class _Type : unsigned char { 00420 _Multi, _Root_name, _Root_dir, _Filename 00421 }; 00422 00423 path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type) 00424 { 00425 __glibcxx_assert(!empty()); 00426 __glibcxx_assert(_M_type != _Type::_Multi); 00427 } 00428 00429 enum class _Split { _Stem, _Extension }; 00430 00431 path& _M_append(const string_type& __str) 00432 { 00433 if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back()) 00434 && !__str.empty() && !_S_is_dir_sep(__str.front())) 00435 _M_pathname += preferred_separator; 00436 _M_pathname += __str; 00437 _M_split_cmpts(); 00438 return *this; 00439 } 00440 00441 pair<const string_type*, size_t> _M_find_extension() const; 00442 00443 template<typename _CharT> 00444 struct _Cvt; 00445 00446 static string_type 00447 _S_convert(value_type* __src, __null_terminated) 00448 { return string_type(__src); } 00449 00450 static string_type 00451 _S_convert(const value_type* __src, __null_terminated) 00452 { return string_type(__src); } 00453 00454 template<typename _Iter> 00455 static string_type 00456 _S_convert(_Iter __first, _Iter __last) 00457 { 00458 using __value_type = typename std::iterator_traits<_Iter>::value_type; 00459 return _Cvt<typename remove_cv<__value_type>::type>:: 00460 _S_convert(__first, __last); 00461 } 00462 00463 template<typename _InputIterator> 00464 static string_type 00465 _S_convert(_InputIterator __src, __null_terminated) 00466 { 00467 auto __s = _S_string_from_iter(__src); 00468 return _S_convert(__s.c_str(), __s.c_str() + __s.size()); 00469 } 00470 00471 static string_type 00472 _S_convert_loc(const char* __first, const char* __last, 00473 const std::locale& __loc); 00474 00475 template<typename _Iter> 00476 static string_type 00477 _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) 00478 { 00479 const std::string __str(__first, __last); 00480 return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc); 00481 } 00482 00483 template<typename _InputIterator> 00484 static string_type 00485 _S_convert_loc(_InputIterator __src, __null_terminated, 00486 const std::locale& __loc) 00487 { 00488 std::string __s = _S_string_from_iter(__src); 00489 return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); 00490 } 00491 00492 static bool _S_is_dir_sep(value_type __ch) 00493 { 00494 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00495 return __ch == L'/' || __ch == preferred_separator; 00496 #else 00497 return __ch == '/'; 00498 #endif 00499 } 00500 00501 void _M_split_cmpts(); 00502 void _M_trim(); 00503 void _M_add_root_name(size_t __n); 00504 void _M_add_root_dir(size_t __pos); 00505 void _M_add_filename(size_t __pos, size_t __n); 00506 00507 string_type _M_pathname; 00508 00509 struct _Cmpt; 00510 using _List = _GLIBCXX_STD_C::vector<_Cmpt>; 00511 _List _M_cmpts; // empty unless _M_type == _Type::_Multi 00512 _Type _M_type = _Type::_Multi; 00513 }; 00514 00515 inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } 00516 00517 size_t hash_value(const path& __p) noexcept; 00518 00519 /// Compare paths 00520 inline bool operator<(const path& __lhs, const path& __rhs) noexcept 00521 { return __lhs.compare(__rhs) < 0; } 00522 00523 /// Compare paths 00524 inline bool operator<=(const path& __lhs, const path& __rhs) noexcept 00525 { return !(__rhs < __lhs); } 00526 00527 /// Compare paths 00528 inline bool operator>(const path& __lhs, const path& __rhs) noexcept 00529 { return __rhs < __lhs; } 00530 00531 /// Compare paths 00532 inline bool operator>=(const path& __lhs, const path& __rhs) noexcept 00533 { return !(__lhs < __rhs); } 00534 00535 /// Compare paths 00536 inline bool operator==(const path& __lhs, const path& __rhs) noexcept 00537 { return __lhs.compare(__rhs) == 0; } 00538 00539 /// Compare paths 00540 inline bool operator!=(const path& __lhs, const path& __rhs) noexcept 00541 { return !(__lhs == __rhs); } 00542 00543 /// Append one path to another 00544 inline path operator/(const path& __lhs, const path& __rhs) 00545 { 00546 path __result(__lhs); 00547 __result /= __rhs; 00548 return __result; 00549 } 00550 00551 /// Write a path to a stream 00552 template<typename _CharT, typename _Traits> 00553 basic_ostream<_CharT, _Traits>& 00554 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) 00555 { 00556 auto __tmp = __p.string<_CharT, _Traits>(); 00557 using __quoted_string 00558 = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; 00559 __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')}; 00560 return __os; 00561 } 00562 00563 /// Read a path from a stream 00564 template<typename _CharT, typename _Traits> 00565 basic_istream<_CharT, _Traits>& 00566 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) 00567 { 00568 basic_string<_CharT, _Traits> __tmp; 00569 using __quoted_string 00570 = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; 00571 if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') }) 00572 __p = std::move(__tmp); 00573 return __is; 00574 } 00575 00576 // TODO constrain with _Path<Source> and __value_type_is_char 00577 template<typename _Source> 00578 inline path 00579 u8path(const _Source& __source) 00580 { 00581 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00582 return path{ path::string_type{__source} }; 00583 #else 00584 return path{ __source }; 00585 #endif 00586 } 00587 00588 // TODO constrain with _Path<InputIterator, InputIterator> and __value_type_is_char 00589 template<typename _InputIterator> 00590 inline path 00591 u8path(_InputIterator __first, _InputIterator __last) 00592 { 00593 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00594 return path{ path::string_type{__first, __last} }; 00595 #else 00596 return path{ __first, __last }; 00597 #endif 00598 } 00599 00600 class filesystem_error : public std::system_error 00601 { 00602 public: 00603 filesystem_error(const string& __what_arg, error_code __ec) 00604 : system_error(__ec, __what_arg) { } 00605 00606 filesystem_error(const string& __what_arg, const path& __p1, 00607 error_code __ec) 00608 : system_error(__ec, __what_arg), _M_path1(__p1) { } 00609 00610 filesystem_error(const string& __what_arg, const path& __p1, 00611 const path& __p2, error_code __ec) 00612 : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2) 00613 { } 00614 00615 ~filesystem_error(); 00616 00617 const path& path1() const noexcept { return _M_path1; } 00618 const path& path2() const noexcept { return _M_path2; } 00619 const char* what() const noexcept { return _M_what.c_str(); } 00620 00621 private: 00622 std::string _M_gen_what(); 00623 00624 path _M_path1; 00625 path _M_path2; 00626 std::string _M_what = _M_gen_what(); 00627 }; 00628 00629 struct path::_Cmpt : path 00630 { 00631 _Cmpt(string_type __s, _Type __t, size_t __pos) 00632 : path(std::move(__s), __t), _M_pos(__pos) { } 00633 00634 _Cmpt() : _M_pos(-1) { } 00635 00636 size_t _M_pos; 00637 }; 00638 00639 // specialize _Cvt for degenerate 'noconv' case 00640 template<> 00641 struct path::_Cvt<path::value_type> 00642 { 00643 template<typename _Iter> 00644 static string_type 00645 _S_convert(_Iter __first, _Iter __last) 00646 { return string_type{__first, __last}; } 00647 }; 00648 00649 template<typename _CharT> 00650 struct path::_Cvt 00651 { 00652 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00653 static string_type 00654 _S_wconvert(const char* __f, const char* __l, true_type) 00655 { 00656 using _Cvt = std::codecvt<wchar_t, char, mbstate_t>; 00657 const auto& __cvt = std::use_facet<_Cvt>(std::locale{}); 00658 std::wstring __wstr; 00659 if (__str_codecvt_in(__f, __l, __wstr, __cvt)) 00660 return __wstr; 00661 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00662 "Cannot convert character sequence", 00663 std::make_error_code(errc::illegal_byte_sequence))); 00664 } 00665 00666 static string_type 00667 _S_wconvert(const _CharT* __f, const _CharT* __l, false_type) 00668 { 00669 std::codecvt_utf8<_CharT> __cvt; 00670 std::string __str; 00671 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00672 { 00673 const char* __f2 = __str.data(); 00674 const char* __l2 = __f2 + __str.size(); 00675 std::codecvt_utf8<wchar_t> __wcvt; 00676 std::wstring __wstr; 00677 if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt)) 00678 return __wstr; 00679 } 00680 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00681 "Cannot convert character sequence", 00682 std::make_error_code(errc::illegal_byte_sequence))); 00683 } 00684 00685 static string_type 00686 _S_convert(const _CharT* __f, const _CharT* __l) 00687 { 00688 return _S_wconvert(__f, __l, is_same<_CharT, char>{}); 00689 } 00690 #else 00691 static string_type 00692 _S_convert(const _CharT* __f, const _CharT* __l) 00693 { 00694 #ifdef _GLIBCXX_USE_CHAR8_T 00695 if constexpr (is_same<_CharT, char8_t>::value) 00696 { 00697 string_type __str(__f, __l); 00698 return __str; 00699 } 00700 else 00701 { 00702 #endif 00703 std::codecvt_utf8<_CharT> __cvt; 00704 std::string __str; 00705 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00706 return __str; 00707 #ifdef _GLIBCXX_USE_CHAR8_T 00708 } 00709 #endif 00710 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00711 "Cannot convert character sequence", 00712 std::make_error_code(errc::illegal_byte_sequence))); 00713 } 00714 #endif 00715 00716 static string_type 00717 _S_convert(_CharT* __f, _CharT* __l) 00718 { 00719 return _S_convert(const_cast<const _CharT*>(__f), 00720 const_cast<const _CharT*>(__l)); 00721 } 00722 00723 template<typename _Iter> 00724 static string_type 00725 _S_convert(_Iter __first, _Iter __last) 00726 { 00727 const std::basic_string<_CharT> __str(__first, __last); 00728 return _S_convert(__str.data(), __str.data() + __str.size()); 00729 } 00730 00731 template<typename _Iter, typename _Cont> 00732 static string_type 00733 _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first, 00734 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last) 00735 { return _S_convert(__first.base(), __last.base()); } 00736 }; 00737 00738 /// An iterator for the components of a path 00739 class path::iterator 00740 { 00741 public: 00742 using difference_type = std::ptrdiff_t; 00743 using value_type = path; 00744 using reference = const path&; 00745 using pointer = const path*; 00746 using iterator_category = std::bidirectional_iterator_tag; 00747 00748 iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { } 00749 00750 iterator(const iterator&) = default; 00751 iterator& operator=(const iterator&) = default; 00752 00753 reference operator*() const; 00754 pointer operator->() const { return std::__addressof(**this); } 00755 00756 iterator& operator++(); 00757 iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } 00758 00759 iterator& operator--(); 00760 iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; } 00761 00762 friend bool operator==(const iterator& __lhs, const iterator& __rhs) 00763 { return __lhs._M_equals(__rhs); } 00764 00765 friend bool operator!=(const iterator& __lhs, const iterator& __rhs) 00766 { return !__lhs._M_equals(__rhs); } 00767 00768 private: 00769 friend class path; 00770 00771 iterator(const path* __path, path::_List::const_iterator __iter) 00772 : _M_path(__path), _M_cur(__iter), _M_at_end() 00773 { } 00774 00775 iterator(const path* __path, bool __at_end) 00776 : _M_path(__path), _M_cur(), _M_at_end(__at_end) 00777 { } 00778 00779 bool _M_equals(iterator) const; 00780 00781 const path* _M_path; 00782 path::_List::const_iterator _M_cur; 00783 bool _M_at_end; // only used when type != _Multi 00784 }; 00785 00786 00787 inline path& 00788 path::operator=(path&& __p) noexcept 00789 { 00790 _M_pathname = std::move(__p._M_pathname); 00791 _M_cmpts = std::move(__p._M_cmpts); 00792 _M_type = __p._M_type; 00793 __p.clear(); 00794 return *this; 00795 } 00796 00797 inline path& 00798 path::operator=(string_type&& __source) 00799 { return *this = path(std::move(__source)); } 00800 00801 inline path& 00802 path::assign(string_type&& __source) 00803 { return *this = path(std::move(__source)); } 00804 00805 inline path& 00806 path::operator+=(const path& __p) 00807 { 00808 return operator+=(__p.native()); 00809 } 00810 00811 inline path& 00812 path::operator+=(const string_type& __x) 00813 { 00814 _M_pathname += __x; 00815 _M_split_cmpts(); 00816 return *this; 00817 } 00818 00819 inline path& 00820 path::operator+=(const value_type* __x) 00821 { 00822 _M_pathname += __x; 00823 _M_split_cmpts(); 00824 return *this; 00825 } 00826 00827 inline path& 00828 path::operator+=(value_type __x) 00829 { 00830 _M_pathname += __x; 00831 _M_split_cmpts(); 00832 return *this; 00833 } 00834 00835 #if __cplusplus >= 201402L 00836 inline path& 00837 path::operator+=(basic_string_view<value_type> __x) 00838 { 00839 _M_pathname.append(__x.data(), __x.size()); 00840 _M_split_cmpts(); 00841 return *this; 00842 } 00843 #endif 00844 00845 template<typename _CharT> 00846 inline path::_Path<_CharT*, _CharT*>& 00847 path::operator+=(_CharT __x) 00848 { 00849 auto* __addr = std::__addressof(__x); 00850 return concat(__addr, __addr + 1); 00851 } 00852 00853 inline path& 00854 path::make_preferred() 00855 { 00856 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00857 std::replace(_M_pathname.begin(), _M_pathname.end(), L'/', 00858 preferred_separator); 00859 #endif 00860 return *this; 00861 } 00862 00863 inline void path::swap(path& __rhs) noexcept 00864 { 00865 _M_pathname.swap(__rhs._M_pathname); 00866 _M_cmpts.swap(__rhs._M_cmpts); 00867 std::swap(_M_type, __rhs._M_type); 00868 } 00869 00870 template<typename _CharT, typename _Traits, typename _Allocator> 00871 inline std::basic_string<_CharT, _Traits, _Allocator> 00872 path::string(const _Allocator& __a) const 00873 { 00874 if (is_same<_CharT, value_type>::value) 00875 return { _M_pathname.begin(), _M_pathname.end(), __a }; 00876 00877 const value_type* __first = _M_pathname.data(); 00878 const value_type* __last = __first + _M_pathname.size(); 00879 00880 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00881 using _CharAlloc = __alloc_rebind<_Allocator, char>; 00882 using _String = basic_string<char, char_traits<char>, _CharAlloc>; 00883 using _WString = basic_string<_CharT, _Traits, _Allocator>; 00884 00885 // use codecvt_utf8<wchar_t> to convert native string to UTF-8 00886 codecvt_utf8<value_type> __cvt; 00887 _String __u8str{_CharAlloc{__a}}; 00888 if (__str_codecvt_out(__first, __last, __u8str, __cvt)) 00889 { 00890 struct 00891 { 00892 const _String* 00893 operator()(const _String& __from, _String&, true_type) 00894 { return std::__addressof(__from); } 00895 00896 _WString* 00897 operator()(const _String& __from, _WString& __to, false_type) 00898 { 00899 #ifdef _GLIBCXX_USE_CHAR8_T 00900 if constexpr (is_same<_CharT, char8_t>::value) 00901 { 00902 __to.assign(__from.begin(), __from.end()); 00903 return std::__addressof(__to); 00904 } 00905 else 00906 { 00907 #endif 00908 // use codecvt_utf8<_CharT> to convert UTF-8 to wide string 00909 codecvt_utf8<_CharT> __cvt; 00910 const char* __f = __from.data(); 00911 const char* __l = __f + __from.size(); 00912 if (__str_codecvt_in(__f, __l, __to, __cvt)) 00913 return std::__addressof(__to); 00914 #ifdef _GLIBCXX_USE_CHAR8_T 00915 } 00916 #endif 00917 return nullptr; 00918 } 00919 } __dispatch; 00920 _WString __wstr; 00921 if (auto* __p = __dispatch(__u8str, __wstr, is_same<_CharT, char>{})) 00922 return *__p; 00923 } 00924 #else 00925 #ifdef _GLIBCXX_USE_CHAR8_T 00926 if constexpr (is_same<_CharT, char8_t>::value) 00927 { 00928 basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a}; 00929 return __wstr; 00930 } 00931 else 00932 { 00933 #endif 00934 codecvt_utf8<_CharT> __cvt; 00935 basic_string<_CharT, _Traits, _Allocator> __wstr{__a}; 00936 if (__str_codecvt_in(__first, __last, __wstr, __cvt)) 00937 return __wstr; 00938 #ifdef _GLIBCXX_USE_CHAR8_T 00939 } 00940 #endif 00941 #endif 00942 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00943 "Cannot convert character sequence", 00944 std::make_error_code(errc::illegal_byte_sequence))); 00945 } 00946 00947 inline std::string 00948 path::string() const { return string<char>(); } 00949 00950 #if _GLIBCXX_USE_WCHAR_T 00951 inline std::wstring 00952 path::wstring() const { return string<wchar_t>(); } 00953 #endif 00954 00955 #ifdef _GLIBCXX_USE_CHAR8_T 00956 inline std::u8string 00957 path::u8string() const { return string<char8_t>(); } 00958 #else 00959 inline std::string 00960 path::u8string() const 00961 { 00962 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00963 std::string __str; 00964 // convert from native encoding to UTF-8 00965 codecvt_utf8<value_type> __cvt; 00966 const value_type* __first = _M_pathname.data(); 00967 const value_type* __last = __first + _M_pathname.size(); 00968 if (__str_codecvt_out(__first, __last, __str, __cvt)) 00969 return __str; 00970 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00971 "Cannot convert character sequence", 00972 std::make_error_code(errc::illegal_byte_sequence))); 00973 #else 00974 return _M_pathname; 00975 #endif 00976 } 00977 #endif // _GLIBCXX_USE_CHAR8_T 00978 00979 inline std::u16string 00980 path::u16string() const { return string<char16_t>(); } 00981 00982 inline std::u32string 00983 path::u32string() const { return string<char32_t>(); } 00984 00985 #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00986 template<typename _CharT, typename _Traits, typename _Allocator> 00987 inline std::basic_string<_CharT, _Traits, _Allocator> 00988 path::generic_string(const _Allocator& __a) const 00989 { return string<_CharT, _Traits, _Allocator>(__a); } 00990 00991 inline std::string 00992 path::generic_string() const { return string(); } 00993 00994 #if _GLIBCXX_USE_WCHAR_T 00995 inline std::wstring 00996 path::generic_wstring() const { return wstring(); } 00997 #endif 00998 00999 #ifdef _GLIBCXX_USE_CHAR8_T 01000 inline std::u8string 01001 path::generic_u8string() const { return u8string(); } 01002 #else 01003 inline std::string 01004 path::generic_u8string() const { return u8string(); } 01005 #endif 01006 01007 inline std::u16string 01008 path::generic_u16string() const { return u16string(); } 01009 01010 inline std::u32string 01011 path::generic_u32string() const { return u32string(); } 01012 #endif 01013 01014 inline int 01015 path::compare(const string_type& __s) const { return compare(path(__s)); } 01016 01017 inline int 01018 path::compare(const value_type* __s) const { return compare(path(__s)); } 01019 01020 #if __cplusplus >= 201402L 01021 inline int 01022 path::compare(basic_string_view<value_type> __s) const 01023 { return compare(path(__s)); } 01024 #endif 01025 01026 inline path 01027 path::filename() const { return empty() ? path() : *--end(); } 01028 01029 inline path 01030 path::stem() const 01031 { 01032 auto ext = _M_find_extension(); 01033 if (ext.first && ext.second != 0) 01034 return path{ext.first->substr(0, ext.second)}; 01035 return {}; 01036 } 01037 01038 inline path 01039 path::extension() const 01040 { 01041 auto ext = _M_find_extension(); 01042 if (ext.first && ext.second != string_type::npos) 01043 return path{ext.first->substr(ext.second)}; 01044 return {}; 01045 } 01046 01047 inline bool 01048 path::has_stem() const 01049 { 01050 auto ext = _M_find_extension(); 01051 return ext.first && ext.second != 0; 01052 } 01053 01054 inline bool 01055 path::has_extension() const 01056 { 01057 auto ext = _M_find_extension(); 01058 return ext.first && ext.second != string_type::npos; 01059 } 01060 01061 inline bool 01062 path::is_absolute() const 01063 { 01064 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 01065 return has_root_name() && has_root_directory(); 01066 #else 01067 return has_root_directory(); 01068 #endif 01069 } 01070 01071 inline path::iterator 01072 path::begin() const 01073 { 01074 if (_M_type == _Type::_Multi) 01075 return iterator(this, _M_cmpts.begin()); 01076 return iterator(this, false); 01077 } 01078 01079 inline path::iterator 01080 path::end() const 01081 { 01082 if (_M_type == _Type::_Multi) 01083 return iterator(this, _M_cmpts.end()); 01084 return iterator(this, true); 01085 } 01086 01087 inline path::iterator& 01088 path::iterator::operator++() 01089 { 01090 __glibcxx_assert(_M_path != nullptr); 01091 if (_M_path->_M_type == _Type::_Multi) 01092 { 01093 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01094 ++_M_cur; 01095 } 01096 else 01097 { 01098 __glibcxx_assert(!_M_at_end); 01099 _M_at_end = true; 01100 } 01101 return *this; 01102 } 01103 01104 inline path::iterator& 01105 path::iterator::operator--() 01106 { 01107 __glibcxx_assert(_M_path != nullptr); 01108 if (_M_path->_M_type == _Type::_Multi) 01109 { 01110 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); 01111 --_M_cur; 01112 } 01113 else 01114 { 01115 __glibcxx_assert(_M_at_end); 01116 _M_at_end = false; 01117 } 01118 return *this; 01119 } 01120 01121 inline path::iterator::reference 01122 path::iterator::operator*() const 01123 { 01124 __glibcxx_assert(_M_path != nullptr); 01125 if (_M_path->_M_type == _Type::_Multi) 01126 { 01127 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01128 return *_M_cur; 01129 } 01130 return *_M_path; 01131 } 01132 01133 inline bool 01134 path::iterator::_M_equals(iterator __rhs) const 01135 { 01136 if (_M_path != __rhs._M_path) 01137 return false; 01138 if (_M_path == nullptr) 01139 return true; 01140 if (_M_path->_M_type == path::_Type::_Multi) 01141 return _M_cur == __rhs._M_cur; 01142 return _M_at_end == __rhs._M_at_end; 01143 } 01144 01145 // @} group filesystem-ts 01146 _GLIBCXX_END_NAMESPACE_CXX11 01147 } // namespace v1 01148 } // namespace filesystem 01149 } // namespace experimental 01150 01151 _GLIBCXX_END_NAMESPACE_VERSION 01152 } // namespace std 01153 01154 #endif // C++11 01155 01156 #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H