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