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