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