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