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