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