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