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