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