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