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         const 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   /// Exception type thrown by the Filesystem library
00616   class filesystem_error : public std::system_error
00617   {
00618   public:
00619     filesystem_error(const string& __what_arg, error_code __ec);
00620 
00621     filesystem_error(const string& __what_arg, const path& __p1,
00622                      error_code __ec);
00623 
00624     filesystem_error(const string& __what_arg, const path& __p1,
00625                      const path& __p2, error_code __ec);
00626 
00627     filesystem_error(const filesystem_error&) = default;
00628     filesystem_error& operator=(const filesystem_error&) = default;
00629 
00630     // No move constructor or assignment operator.
00631     // Copy rvalues instead, so that _M_impl is not left empty.
00632 
00633     ~filesystem_error();
00634 
00635     const path& path1() const noexcept;
00636     const path& path2() const noexcept;
00637     const char* what() const noexcept;
00638 
00639   private:
00640     struct _Impl;
00641     std::__shared_ptr<const _Impl> _M_impl;
00642   };
00643 
00644   /// Create a path from a UTF-8-encoded sequence of char
00645   template<typename _InputIterator>
00646     inline auto
00647     u8path(_InputIterator __first, _InputIterator __last)
00648     -> decltype(filesystem::path(__first, __last, std::locale::classic()))
00649     {
00650 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
00651       // XXX This assumes native wide encoding is UTF-16.
00652       std::codecvt_utf8_utf16<path::value_type> __cvt;
00653       path::string_type __tmp;
00654       if constexpr (is_pointer_v<_InputIterator>)
00655         {
00656           if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
00657             return path{ __tmp };
00658         }
00659       else
00660         {
00661           const std::string __u8str{__first, __last};
00662           const char* const __ptr = __u8str.data();
00663           if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
00664             return path{ __tmp };
00665         }
00666       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
00667             "Cannot convert character sequence",
00668             std::make_error_code(errc::illegal_byte_sequence)));
00669 #else
00670       // This assumes native normal encoding is UTF-8.
00671       return path{ __first, __last };
00672 #endif
00673     }
00674 
00675   /// Create a path from a UTF-8-encoded sequence of char
00676   template<typename _Source>
00677     inline auto
00678     u8path(const _Source& __source)
00679     -> decltype(filesystem::path(__source, std::locale::classic()))
00680     {
00681 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
00682       if constexpr (is_convertible_v<const _Source&, std::string_view>)
00683         {
00684           const std::string_view __s = __source;
00685           return filesystem::u8path(__s.data(), __s.data() + __s.size());
00686         }
00687       else
00688         {
00689           std::string __s = path::_S_string_from_iter(__source);
00690           return filesystem::u8path(__s.data(), __s.data() + __s.size());
00691         }
00692 #else
00693       return path{ __source };
00694 #endif
00695     }
00696 
00697   struct path::_Cmpt : path
00698   {
00699     _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
00700       : path(__s, __t), _M_pos(__pos) { }
00701 
00702     _Cmpt() : _M_pos(-1) { }
00703 
00704     size_t _M_pos;
00705   };
00706 
00707   // specialize _Cvt for degenerate 'noconv' case
00708   template<>
00709     struct path::_Cvt<path::value_type>
00710     {
00711       template<typename _Iter>
00712         static string_type
00713         _S_convert(_Iter __first, _Iter __last)
00714         { return string_type{__first, __last}; }
00715     };
00716 
00717 #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS  && defined _GLIBCXX_USE_CHAR8_T
00718   // For POSIX converting from char8_t to char is also 'noconv'
00719   template<>
00720     struct path::_Cvt<char8_t>
00721     {
00722       template<typename _Iter>
00723         static string_type
00724         _S_convert(_Iter __first, _Iter __last)
00725         { return string_type(__first, __last); }
00726     };
00727 #endif
00728 
00729   template<typename _CharT>
00730     struct path::_Cvt
00731     {
00732       static string_type
00733       _S_convert(const _CharT* __f, const _CharT* __l)
00734       {
00735 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
00736         std::wstring __wstr;
00737         if constexpr (is_same_v<_CharT, char>)
00738           {
00739             struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
00740             { } __cvt;
00741             if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
00742               return __wstr;
00743           }
00744 #ifdef _GLIBCXX_USE_CHAR8_T
00745         else if constexpr (is_same_v<_CharT, char8_t>)
00746           {
00747             const char* __f2 = (const char*)__f;
00748             const char* __l2 = (const char*)__l;
00749             std::codecvt_utf8_utf16<wchar_t> __wcvt;
00750             if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
00751               return __wstr;
00752           }
00753 #endif
00754         else // char16_t or char32_t
00755           {
00756             struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
00757             { } __cvt;
00758             std::string __str;
00759             if (__str_codecvt_out_all(__f, __l, __str, __cvt))
00760               {
00761                 const char* __f2 = __str.data();
00762                 const char* __l2 = __f2 + __str.size();
00763                 std::codecvt_utf8_utf16<wchar_t> __wcvt;
00764                 if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
00765                   return __wstr;
00766               }
00767           }
00768 #else // ! windows
00769         struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
00770         { } __cvt;
00771         std::string __str;
00772         if (__str_codecvt_out_all(__f, __l, __str, __cvt))
00773           return __str;
00774 #endif
00775         _GLIBCXX_THROW_OR_ABORT(filesystem_error(
00776               "Cannot convert character sequence",
00777               std::make_error_code(errc::illegal_byte_sequence)));
00778       }
00779 
00780       static string_type
00781       _S_convert(_CharT* __f, _CharT* __l)
00782       {
00783         return _S_convert(const_cast<const _CharT*>(__f),
00784                           const_cast<const _CharT*>(__l));
00785       }
00786 
00787       template<typename _Iter>
00788         static string_type
00789         _S_convert(_Iter __first, _Iter __last)
00790         {
00791           const std::basic_string<_CharT> __str(__first, __last);
00792           return _S_convert(__str.data(), __str.data() + __str.size());
00793         }
00794 
00795       template<typename _Iter, typename _Cont>
00796         static string_type
00797         _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
00798                   __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
00799         { return _S_convert(__first.base(), __last.base()); }
00800     };
00801 
00802   /// An iterator for the components of a path
00803   class path::iterator
00804   {
00805   public:
00806     using difference_type       = std::ptrdiff_t;
00807     using value_type            = path;
00808     using reference             = const path&;
00809     using pointer               = const path*;
00810     using iterator_category     = std::bidirectional_iterator_tag;
00811 
00812     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
00813 
00814     iterator(const iterator&) = default;
00815     iterator& operator=(const iterator&) = default;
00816 
00817     reference operator*() const;
00818     pointer   operator->() const { return std::__addressof(**this); }
00819 
00820     iterator& operator++();
00821     iterator  operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
00822 
00823     iterator& operator--();
00824     iterator  operator--(int) { auto __tmp = *this; --*this; return __tmp; }
00825 
00826     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
00827     { return __lhs._M_equals(__rhs); }
00828 
00829     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
00830     { return !__lhs._M_equals(__rhs); }
00831 
00832   private:
00833     friend class path;
00834 
00835     bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
00836 
00837     friend difference_type
00838     __path_iter_distance(const iterator& __first, const iterator& __last)
00839     {
00840       __glibcxx_assert(__first._M_path != nullptr);
00841       __glibcxx_assert(__first._M_path == __last._M_path);
00842       if (__first._M_is_multi())
00843         return std::distance(__first._M_cur, __last._M_cur);
00844       else if (__first._M_at_end == __last._M_at_end)
00845         return 0;
00846       else
00847         return __first._M_at_end ? -1 : 1;
00848     }
00849 
00850     friend void
00851     __path_iter_advance(iterator& __i, difference_type __n)
00852     {
00853       if (__n == 1)
00854         ++__i;
00855       else if (__n == -1)
00856         --__i;
00857       else if (__n != 0)
00858         {
00859           __glibcxx_assert(__i._M_path != nullptr);
00860           __glibcxx_assert(__i._M_is_multi());
00861           // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
00862           __i._M_cur += __n;
00863         }
00864     }
00865 
00866     iterator(const path* __path, path::_List::const_iterator __iter)
00867     : _M_path(__path), _M_cur(__iter), _M_at_end()
00868     { }
00869 
00870     iterator(const path* __path, bool __at_end)
00871     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
00872     { }
00873 
00874     bool _M_equals(iterator) const;
00875 
00876     const path*                 _M_path;
00877     path::_List::const_iterator _M_cur;
00878     bool                        _M_at_end;  // only used when type != _Multi
00879   };
00880 
00881 
00882   inline path&
00883   path::operator=(path&& __p) noexcept
00884   {
00885     if (&__p == this) [[__unlikely__]]
00886       return *this;
00887 
00888     _M_pathname = std::move(__p._M_pathname);
00889     _M_cmpts = std::move(__p._M_cmpts);
00890     __p.clear();
00891     return *this;
00892   }
00893 
00894   inline path&
00895   path::operator=(string_type&& __source)
00896   { return *this = path(std::move(__source)); }
00897 
00898   inline path&
00899   path::assign(string_type&& __source)
00900   { return *this = path(std::move(__source)); }
00901 
00902   inline path&
00903   path::operator+=(const string_type& __x)
00904   {
00905     _M_concat(__x);
00906     return *this;
00907   }
00908 
00909   inline path&
00910   path::operator+=(const value_type* __x)
00911   {
00912     _M_concat(__x);
00913     return *this;
00914   }
00915 
00916   inline path&
00917   path::operator+=(value_type __x)
00918   {
00919     _M_concat(basic_string_view<value_type>(&__x, 1));
00920     return *this;
00921   }
00922 
00923   inline path&
00924   path::operator+=(basic_string_view<value_type> __x)
00925   {
00926     _M_concat(__x);
00927     return *this;
00928   }
00929 
00930   template<typename _CharT>
00931     inline path::_Path<_CharT*, _CharT*>&
00932     path::operator+=(_CharT __x)
00933     {
00934       auto* __addr = std::__addressof(__x);
00935       return concat(__addr, __addr + 1);
00936     }
00937 
00938   inline path&
00939   path::make_preferred()
00940   {
00941 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
00942     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
00943                  preferred_separator);
00944 #endif
00945     return *this;
00946   }
00947 
00948   inline void path::swap(path& __rhs) noexcept
00949   {
00950     _M_pathname.swap(__rhs._M_pathname);
00951     _M_cmpts.swap(__rhs._M_cmpts);
00952   }
00953 
00954   template<typename _CharT, typename _Traits, typename _Allocator>
00955     std::basic_string<_CharT, _Traits, _Allocator>
00956     path::_S_str_convert(const string_type& __str, const _Allocator& __a)
00957     {
00958       static_assert(!is_same_v<_CharT, value_type>);
00959 
00960       using _WString = basic_string<_CharT, _Traits, _Allocator>;
00961 
00962       if (__str.size() == 0)
00963         return _WString(__a);
00964 
00965 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
00966       // First convert native string from UTF-16 to to UTF-8.
00967       // XXX This assumes that the execution wide-character set is UTF-16.
00968       std::codecvt_utf8_utf16<value_type> __cvt;
00969 
00970       using _CharAlloc = __alloc_rebind<_Allocator, char>;
00971       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
00972       _String __u8str{_CharAlloc{__a}};
00973       const value_type* __wfirst = __str.data();
00974       const value_type* __wlast = __wfirst + __str.size();
00975       if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
00976       if constexpr (is_same_v<_CharT, char>)
00977         return __u8str; // XXX assumes native ordinary encoding is UTF-8.
00978       else {
00979 
00980       const char* __first = __u8str.data();
00981       const char* __last = __first + __u8str.size();
00982 #else
00983       const value_type* __first = __str.data();
00984       const value_type* __last = __first + __str.size();
00985 #endif
00986 
00987       // Convert UTF-8 string to requested format.
00988 #ifdef _GLIBCXX_USE_CHAR8_T
00989       if constexpr (is_same_v<_CharT, char8_t>)
00990         return _WString(__first, __last, __a);
00991       else
00992 #endif
00993         {
00994           // Convert UTF-8 to wide string.
00995           _WString __wstr(__a);
00996           struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
00997           if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
00998             return __wstr;
00999         }
01000 
01001 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
01002       } }
01003 #endif
01004       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
01005             "Cannot convert character sequence",
01006             std::make_error_code(errc::illegal_byte_sequence)));
01007     }
01008 
01009   template<typename _CharT, typename _Traits, typename _Allocator>
01010     inline basic_string<_CharT, _Traits, _Allocator>
01011     path::string(const _Allocator& __a) const
01012     {
01013       if constexpr (is_same_v<_CharT, value_type>)
01014         return { _M_pathname.c_str(), _M_pathname.length(), __a };
01015       else
01016         return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
01017     }
01018 
01019   inline std::string
01020   path::string() const { return string<char>(); }
01021 
01022 #if _GLIBCXX_USE_WCHAR_T
01023   inline std::wstring
01024   path::wstring() const { return string<wchar_t>(); }
01025 #endif
01026 
01027 #ifdef _GLIBCXX_USE_CHAR8_T
01028   inline std::u8string
01029   path::u8string() const { return string<char8_t>(); }
01030 #else
01031   inline std::string
01032   path::u8string() const
01033   {
01034 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
01035     std::string __str;
01036     // convert from native wide encoding (assumed to be UTF-16) to UTF-8
01037     std::codecvt_utf8_utf16<value_type> __cvt;
01038     const value_type* __first = _M_pathname.data();
01039     const value_type* __last = __first + _M_pathname.size();
01040     if (__str_codecvt_out_all(__first, __last, __str, __cvt))
01041       return __str;
01042     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
01043           "Cannot convert character sequence",
01044           std::make_error_code(errc::illegal_byte_sequence)));
01045 #else
01046     return _M_pathname;
01047 #endif
01048   }
01049 #endif // _GLIBCXX_USE_CHAR8_T
01050 
01051   inline std::u16string
01052   path::u16string() const { return string<char16_t>(); }
01053 
01054   inline std::u32string
01055   path::u32string() const { return string<char32_t>(); }
01056 
01057   template<typename _CharT, typename _Traits, typename _Allocator>
01058     inline std::basic_string<_CharT, _Traits, _Allocator>
01059     path::generic_string(const _Allocator& __a) const
01060     {
01061 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
01062       const value_type __slash = L'/';
01063 #else
01064       const value_type __slash = '/';
01065 #endif
01066       string_type __str(__a);
01067 
01068       if (_M_type() == _Type::_Root_dir)
01069         __str.assign(1, __slash);
01070       else
01071         {
01072           __str.reserve(_M_pathname.size());
01073           bool __add_slash = false;
01074           for (auto& __elem : *this)
01075             {
01076 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
01077               if (__elem._M_type() == _Type::_Root_dir)
01078                 {
01079                   __str += __slash;
01080                   continue;
01081                 }
01082 #endif
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