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