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