Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. // Class filesystem::path -*- C++ -*-
  2.  
  3. // Copyright (C) 2014-2015 Free Software Foundation, Inc.
  4. //
  5. // This file is part of the GNU ISO C++ Library.  This library is free
  6. // software; you can redistribute it and/or modify it under the
  7. // terms of the GNU General Public License as published by the
  8. // Free Software Foundation; either version 3, or (at your option)
  9. // any later version.
  10.  
  11. // This library is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. // GNU General Public License for more details.
  15.  
  16. // Under Section 7 of GPL version 3, you are granted additional
  17. // permissions described in the GCC Runtime Library Exception, version
  18. // 3.1, as published by the Free Software Foundation.
  19.  
  20. // You should have received a copy of the GNU General Public License and
  21. // a copy of the GCC Runtime Library Exception along with this program;
  22. // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
  23. // <http://www.gnu.org/licenses/>.
  24.  
  25. /** @file experimental/fs_path.h
  26.  *  This is an internal header file, included by other library headers.
  27.  *  Do not attempt to use it directly. @headername{experimental/filesystem}
  28.  */
  29.  
  30. #ifndef _GLIBCXX_EXPERIMENTAL_FS_PATH_H
  31. #define _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1
  32.  
  33. #if __cplusplus < 201103L
  34. # include <bits/c++0x_warning.h>
  35. #else
  36.  
  37. #include <utility>
  38. #include <type_traits>
  39. #include <vector>
  40. #include <locale>
  41. #include <iosfwd>
  42. #include <codecvt>
  43. #include <system_error>
  44. #include <bits/stl_algobase.h>
  45. #include <bits/quoted_string.h>
  46. #include <bits/locale_conv.h>
  47.  
  48. #if defined(_WIN32) && !defined(__CYGWIN__)
  49. # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
  50. # include <algorithm>
  51. #endif
  52.  
  53. namespace std _GLIBCXX_VISIBILITY(default)
  54. {
  55. namespace experimental
  56. {
  57. namespace filesystem
  58. {
  59. inline namespace v1
  60. {
  61. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  62. _GLIBCXX_BEGIN_NAMESPACE_CXX11
  63.  
  64.   /**
  65.    * @ingroup filesystem
  66.    * @{
  67.    */
  68.  
  69.   /// A filesystem path.
  70.   class path
  71.   {
  72.     template<typename _CharT>
  73.       struct __is_encoded_char : std::false_type { };
  74.  
  75.     template<typename _Iter,
  76.              typename _Iter_traits = std::iterator_traits<_Iter>>
  77.       using __is_path_iter_src
  78.         = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
  79.                  std::is_base_of<std::input_iterator_tag,
  80.                                  typename _Iter_traits::iterator_category>>;
  81.  
  82.     template<typename _Iter>
  83.       static __is_path_iter_src<_Iter>
  84.       __is_path_src(_Iter, int);
  85.  
  86.     template<typename _CharT, typename _Traits, typename _Alloc>
  87.       static __is_encoded_char<_CharT>
  88.       __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
  89.  
  90.     template<typename _Unknown>
  91.       static std::false_type
  92.       __is_path_src(const _Unknown&, ...);
  93.  
  94.     template<typename _Tp1, typename _Tp2>
  95.       struct __constructible_from;
  96.  
  97.     template<typename _Iter>
  98.       struct __constructible_from<_Iter, _Iter>
  99.       : __is_path_iter_src<_Iter>
  100.       { };
  101.  
  102.     template<typename _Source>
  103.       struct __constructible_from<_Source, void>
  104.       : decltype(__is_path_src(std::declval<_Source>(), 0))
  105.       { };
  106.  
  107.     template<typename _Tp1, typename _Tp2 = void>
  108.       using _Path = typename
  109.         std::enable_if<__and_<__not_<is_same<_Tp1, path>>,
  110.                               __constructible_from<_Tp1, _Tp2>>::value,
  111.                        path>::type;
  112.  
  113.     template<typename _Source>
  114.       static _Source
  115.       _S_range_begin(_Source __begin) { return __begin; }
  116.  
  117.     struct __null_terminated { };
  118.  
  119.     template<typename _Source>
  120.       static __null_terminated
  121.       _S_range_end(_Source) { return {}; }
  122.  
  123.     template<typename _CharT, typename _Traits, typename _Alloc>
  124.       static const _CharT*
  125.       _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
  126.       { return __str.data(); }
  127.  
  128.     template<typename _CharT, typename _Traits, typename _Alloc>
  129.       static const _CharT*
  130.       _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
  131.       { return __str.data() + __str.size(); }
  132.  
  133.     template<typename _Tp,
  134.              typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
  135.              typename _Val = typename std::iterator_traits<_Iter>::value_type>
  136.       using __value_type_is_char
  137.         = typename std::enable_if<std::is_same<_Val, char>::value>::type;
  138.  
  139.   public:
  140. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  141.     typedef wchar_t                             value_type;
  142.     static constexpr value_type                 preferred_separator = L'\\';
  143. #else
  144.     typedef char                                value_type;
  145.     static constexpr value_type                 preferred_separator = '/';
  146. #endif
  147.     typedef std::basic_string<value_type>       string_type;
  148.  
  149.     // constructors and destructor
  150.  
  151.     path() noexcept { }
  152.  
  153.     path(const path& __p) = default;
  154.  
  155.     path(path&& __p) noexcept
  156.     : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
  157.     {
  158.       _M_split_cmpts();
  159.       __p.clear();
  160.     }
  161.  
  162.     template<typename _Source,
  163.              typename _Require = _Path<_Source>>
  164.       path(_Source const& __source)
  165.       : _M_pathname(_S_convert(_S_range_begin(__source),
  166.                                _S_range_end(__source)))
  167.       { _M_split_cmpts(); }
  168.  
  169.     template<typename _InputIterator,
  170.              typename _Require = _Path<_InputIterator, _InputIterator>>
  171.       path(_InputIterator __first, _InputIterator __last)
  172.       : _M_pathname(_S_convert(__first, __last))
  173.       { _M_split_cmpts(); }
  174.  
  175.     template<typename _Source,
  176.              typename _Require = _Path<_Source>,
  177.              typename _Require2 = __value_type_is_char<_Source>>
  178.       path(_Source const& __source, const locale& __loc)
  179.       : _M_pathname(_S_convert_loc(_S_range_begin(__source),
  180.                                    _S_range_end(__source), __loc))
  181.       { _M_split_cmpts(); }
  182.  
  183.     template<typename _InputIterator,
  184.              typename _Require = _Path<_InputIterator, _InputIterator>,
  185.              typename _Require2 = __value_type_is_char<_InputIterator>>
  186.       path(_InputIterator __first, _InputIterator __last, const locale& __loc)
  187.       : _M_pathname(_S_convert_loc(__first, __last, __loc))
  188.       { _M_split_cmpts(); }
  189.  
  190.     ~path() = default;
  191.  
  192.     // assignments
  193.  
  194.     path& operator=(const path& __p) = default;
  195.     path& operator=(path&& __p) noexcept;
  196.  
  197.     template<typename _Source>
  198.       _Path<_Source>&
  199.       operator=(_Source const& __source)
  200.       { return *this = path(__source); }
  201.  
  202.     template<typename _Source>
  203.       _Path<_Source>&
  204.       assign(_Source const& __source)
  205.       { return *this = path(__source); }
  206.  
  207.     template<typename _InputIterator>
  208.       _Path<_InputIterator, _InputIterator>&
  209.       assign(_InputIterator __first, _InputIterator __last)
  210.       { return *this = path(__first, __last); }
  211.  
  212.     // appends
  213.  
  214.     path& operator/=(const path& __p) { return _M_append(__p._M_pathname); }
  215.  
  216.     template <class _Source>
  217.       _Path<_Source>&
  218.       operator/=(_Source const& __source)
  219.       { return append(__source); }
  220.  
  221.     template<typename _Source>
  222.       _Path<_Source>&
  223.       append(_Source const& __source)
  224.       {
  225.         return _M_append(_S_convert(_S_range_begin(__source),
  226.                                     _S_range_end(__source)));
  227.       }
  228.  
  229.     template<typename _InputIterator>
  230.       _Path<_InputIterator, _InputIterator>&
  231.       append(_InputIterator __first, _InputIterator __last)
  232.       { return _M_append(_S_convert(__first, __last)); }
  233.  
  234.     // concatenation
  235.  
  236.     path& operator+=(const path& __x);
  237.     path& operator+=(const string_type& __x);
  238.     path& operator+=(const value_type* __x);
  239.     path& operator+=(value_type __x);
  240.  
  241.     template<typename _Source>
  242.       _Path<_Source>&
  243.       operator+=(_Source const& __x) { return concat(__x); }
  244.  
  245.     template<typename _CharT>
  246.       _Path<_CharT*, _CharT*>&
  247.       operator+=(_CharT __x);
  248.  
  249.     template<typename _Source>
  250.       _Path<_Source>&
  251.       concat(_Source const& __x)
  252.       { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
  253.  
  254.     template<typename _InputIterator>
  255.       _Path<_InputIterator, _InputIterator>&
  256.       concat(_InputIterator __first, _InputIterator __last)
  257.       { return *this += _S_convert(__first, __last); }
  258.  
  259.     // modifiers
  260.  
  261.     void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
  262.  
  263.     path& make_preferred();
  264.     path& remove_filename();
  265.     path& replace_filename(const path& __replacement);
  266.     path& replace_extension(const path& __replacement = path());
  267.  
  268.     void swap(path& __rhs) noexcept;
  269.  
  270.     // native format observers
  271.  
  272.     const string_type&  native() const noexcept { return _M_pathname; }
  273.     const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
  274.     operator string_type() const { return _M_pathname; }
  275.  
  276.     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  277.              typename _Allocator = std::allocator<_CharT>>
  278.       std::basic_string<_CharT, _Traits, _Allocator>
  279.       string(const _Allocator& __a = _Allocator()) const;
  280.  
  281.     std::string    string() const;
  282. #if _GLIBCXX_USE_WCHAR_T
  283.     std::wstring   wstring() const;
  284. #endif
  285.     std::string    u8string() const;
  286.     std::u16string u16string() const;
  287.     std::u32string u32string() const;
  288.  
  289.     // generic format observers
  290.     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  291.              typename _Allocator = std::allocator<_CharT>>
  292.       std::basic_string<_CharT, _Traits, _Allocator>
  293.       generic_string(const _Allocator& __a = _Allocator()) const;
  294.  
  295.     std::string    generic_string() const;
  296. #if _GLIBCXX_USE_WCHAR_T
  297.     std::wstring   generic_wstring() const;
  298. #endif
  299.     std::string    generic_u8string() const;
  300.     std::u16string generic_u16string() const;
  301.     std::u32string generic_u32string() const;
  302.  
  303.     // compare
  304.  
  305.     int compare(const path& __p) const noexcept;
  306.     int compare(const string_type& __s) const;
  307.     int compare(const value_type* __s) const;
  308.  
  309.     // decomposition
  310.  
  311.     path root_name() const;
  312.     path root_directory() const;
  313.     path root_path() const;
  314.     path relative_path() const;
  315.     path parent_path() const;
  316.     path filename() const;
  317.     path stem() const;
  318.     path extension() const;
  319.  
  320.     // query
  321.  
  322.     bool empty() const noexcept { return _M_pathname.empty(); }
  323.     bool has_root_name() const;
  324.     bool has_root_directory() const;
  325.     bool has_root_path() const;
  326.     bool has_relative_path() const;
  327.     bool has_parent_path() const;
  328.     bool has_filename() const;
  329.     bool has_stem() const;
  330.     bool has_extension() const;
  331.     bool is_absolute() const;
  332.     bool is_relative() const { return !is_absolute(); }
  333.  
  334.     // iterators
  335.     class iterator;
  336.     typedef iterator const_iterator;
  337.  
  338.     iterator begin() const;
  339.     iterator end() const;
  340.  
  341.   private:
  342.     enum class _Type : unsigned char {
  343.         _Multi, _Root_name, _Root_dir, _Filename
  344.     };
  345.  
  346.     path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
  347.     {
  348.       _GLIBCXX_DEBUG_ASSERT(!empty());
  349.       _GLIBCXX_DEBUG_ASSERT(_M_type != _Type::_Multi);
  350.     }
  351.  
  352.     enum class _Split { _Stem, _Extension };
  353.  
  354.     path& _M_append(const string_type& __str)
  355.     {
  356.       if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
  357.           && !__str.empty() && !_S_is_dir_sep(__str.front()))
  358.         _M_pathname += preferred_separator;
  359.       _M_pathname += __str;
  360.       _M_split_cmpts();
  361.       return *this;
  362.     }
  363.  
  364.     pair<const string_type*, size_t> _M_find_extension() const;
  365.  
  366.     template<typename _CharT>
  367.       struct _Cvt;
  368.  
  369.     static string_type
  370.     _S_convert(value_type* __src, __null_terminated)
  371.     { return string_type(__src); }
  372.  
  373.     static string_type
  374.     _S_convert(const value_type* __src, __null_terminated)
  375.     { return string_type(__src); }
  376.  
  377.     template<typename _Iter>
  378.       static string_type
  379.       _S_convert(_Iter __first, _Iter __last)
  380.       {
  381.         using __value_type = typename std::iterator_traits<_Iter>::value_type;
  382.         return _Cvt<__value_type>::_S_convert(__first, __last);
  383.       }
  384.  
  385.     template<typename _InputIterator>
  386.       static string_type
  387.       _S_convert(_InputIterator __src, __null_terminated)
  388.       {
  389.         using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
  390.         std::basic_string<_Tp> __tmp;
  391.         while (*__src != _Tp{})
  392.           __tmp.push_back(*__src++);
  393.         return _S_convert(__tmp.data(), __tmp.data() + __tmp.size());
  394.       }
  395.  
  396.     static string_type
  397.     _S_convert_loc(const char* __first, const char* __last,
  398.                    const std::locale& __loc);
  399.  
  400.     template<typename _Iter>
  401.       static string_type
  402.       _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
  403.       {
  404.         const std::string __str(__first, __last);
  405.         return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
  406.       }
  407.  
  408.     template<typename _InputIterator>
  409.       static string_type
  410.       _S_convert_loc(_InputIterator __src, __null_terminated,
  411.                      const std::locale& __loc)
  412.       {
  413.         std::string __tmp;
  414.         while (*__src != '\0')
  415.           __tmp.push_back(*__src++);
  416.         return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
  417.       }
  418.  
  419.     bool _S_is_dir_sep(value_type __ch)
  420.     {
  421. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  422.       return __ch == L'/' || __ch == preferred_separator;
  423. #else
  424.       return __ch == '/';
  425. #endif
  426.     }
  427.  
  428.     void _M_split_cmpts();
  429.     void _M_trim();
  430.     void _M_add_root_name(size_t __n);
  431.     void _M_add_root_dir(size_t __pos);
  432.     void _M_add_filename(size_t __pos, size_t __n);
  433.  
  434.     string_type _M_pathname;
  435.  
  436.     struct _Cmpt;
  437.     using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
  438.     _List _M_cmpts; // empty unless _M_type == _Type::_Multi
  439.     _Type _M_type = _Type::_Multi;
  440.   };
  441.  
  442.   inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
  443.  
  444.   size_t hash_value(const path& __p) noexcept;
  445.  
  446.   /// Compare paths
  447.   inline bool operator<(const path& __lhs, const path& __rhs) noexcept
  448.   { return __lhs.compare(__rhs) < 0; }
  449.  
  450.   /// Compare paths
  451.   inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
  452.   { return !(__rhs < __lhs); }
  453.  
  454.   /// Compare paths
  455.   inline bool operator>(const path& __lhs, const path& __rhs) noexcept
  456.   { return __rhs < __lhs; }
  457.  
  458.   /// Compare paths
  459.   inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
  460.   { return !(__lhs < __rhs); }
  461.  
  462.   /// Compare paths
  463.   inline bool operator==(const path& __lhs, const path& __rhs) noexcept
  464.   { return __lhs.compare(__rhs) == 0; }
  465.  
  466.   /// Compare paths
  467.   inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
  468.   { return !(__lhs == __rhs); }
  469.  
  470.   /// Append one path to another
  471.   inline path operator/(const path& __lhs, const path& __rhs)
  472.   { return path(__lhs) /= __rhs; }
  473.  
  474.   /// Write a path to a stream
  475.   template<typename _CharT, typename _Traits>
  476.     basic_ostream<_CharT, _Traits>&
  477.     operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
  478.     {
  479.       auto __tmp = __p.string<_CharT, _Traits>();
  480.       using __quoted_string
  481.         = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
  482.       __os << __quoted_string{__tmp, '"', '\\'};
  483.       return __os;
  484.     }
  485.  
  486.   /// Read a path from a stream
  487.   template<typename _CharT, typename _Traits>
  488.     basic_istream<_CharT, _Traits>&
  489.     operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
  490.     {
  491.       basic_string<_CharT, _Traits> __tmp;
  492.       using __quoted_string
  493.         = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
  494.       if (__is >> __quoted_string{ __tmp, '"', '\\' })
  495.         __p = std::move(__tmp);
  496.       return __is;
  497.     }
  498.  
  499.   // TODO constrain with _Path<Source> and __value_type_is_char
  500.   template<typename _Source>
  501.     inline path
  502.     u8path(const _Source& __source)
  503.     {
  504. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  505.       return path{ path::string_type{__source} };
  506. #else
  507.       return path{ __source };
  508. #endif
  509.     }
  510.  
  511.   // TODO constrain with _Path<InputIterator, InputIterator> and __value_type_is_char
  512.   template<typename _InputIterator>
  513.     inline path
  514.     u8path(_InputIterator __first, _InputIterator __last)
  515.     {
  516. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  517.       return path{ path::string_type{__first, __last} };
  518. #else
  519.       return path{ __first, __last };
  520. #endif
  521.     }
  522.  
  523.   class filesystem_error : public std::system_error
  524.   {
  525.   public:
  526.     filesystem_error(const string& __what_arg, error_code __ec)
  527.     : system_error(__ec, __what_arg) { }
  528.  
  529.     filesystem_error(const string& __what_arg, const path& __p1,
  530.                      error_code __ec)
  531.     : system_error(__ec, __what_arg), _M_path1(__p1) { }
  532.  
  533.     filesystem_error(const string& __what_arg, const path& __p1,
  534.                      const path& __p2, error_code __ec)
  535.     : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
  536.     { }
  537.  
  538.     ~filesystem_error();
  539.  
  540.     const path& path1() const noexcept { return _M_path1; }
  541.     const path& path2() const noexcept { return _M_path2; }
  542.     const char* what() const noexcept { return _M_what.c_str(); }
  543.  
  544.   private:
  545.     std::string _M_gen_what();
  546.  
  547.     path _M_path1;
  548.     path _M_path2;
  549.     std::string _M_what = _M_gen_what();
  550.   };
  551.  
  552.   template<>
  553.     struct path::__is_encoded_char<char> : std::true_type
  554.     { using value_type = char; };
  555.  
  556.   template<>
  557.     struct path::__is_encoded_char<wchar_t> : std::true_type
  558.     { using value_type = wchar_t; };
  559.  
  560.   template<>
  561.     struct path::__is_encoded_char<char16_t> : std::true_type
  562.     { using value_type = char16_t; };
  563.  
  564.   template<>
  565.     struct path::__is_encoded_char<char32_t> : std::true_type
  566.     { using value_type = char32_t; };
  567.  
  568.   struct path::_Cmpt : path
  569.   {
  570.     _Cmpt(string_type __s, _Type __t, size_t __pos)
  571.       : path(std::move(__s), __t), _M_pos(__pos) { }
  572.  
  573.     _Cmpt() : _M_pos(-1) { }
  574.  
  575.     size_t _M_pos;
  576.   };
  577.  
  578.   // specialize _Cvt for degenerate 'noconv' case
  579.   template<>
  580.     struct path::_Cvt<path::value_type>
  581.     {
  582.       template<typename _Iter>
  583.         static string_type
  584.         _S_convert(_Iter __first, _Iter __last)
  585.         { return string_type{__first, __last}; }
  586.     };
  587.  
  588.   template<typename _CharT>
  589.     struct path::_Cvt
  590.     {
  591. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  592.       static string_type
  593.       _S_wconvert(const char* __f, const char* __l, true_type)
  594.       {
  595.         using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
  596.         const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
  597.         std::wstring __wstr;
  598.         if (__str_codecvt_in(__f, __l, __wstr, __cvt))
  599.             return __wstr;
  600.         _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  601.               "Cannot convert character sequence",
  602.               std::make_error_code(errc::illegal_byte_sequence)));
  603.       }
  604.  
  605.       static string_type
  606.       _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
  607.       {
  608.         std::codecvt_utf8<_CharT> __cvt;
  609.         std::string __str;
  610.         if (__str_codecvt_out(__f, __l, __str, __cvt))
  611.           {
  612.             const char* __f2 = __str.data();
  613.             const char* __l2 = __f2 + __str.size();
  614.             std::codecvt_utf8<wchar_t> __wcvt;
  615.             std::wstring __wstr;
  616.             if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
  617.               return __wstr;
  618.           }
  619.         _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  620.               "Cannot convert character sequence",
  621.               std::make_error_code(errc::illegal_byte_sequence)));
  622.       }
  623.  
  624.       static string_type
  625.       _S_convert(const _CharT* __f, const _CharT* __l)
  626.       {
  627.         return _S_wconvert(__f, __l, is_same<_CharT, char>{});
  628.       }
  629. #else
  630.       static string_type
  631.       _S_convert(const _CharT* __f, const _CharT* __l)
  632.       {
  633.         std::codecvt_utf8<_CharT> __cvt;
  634.         std::string __str;
  635.         if (__str_codecvt_out(__f, __l, __str, __cvt))
  636.           return __str;
  637.         _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  638.               "Cannot convert character sequence",
  639.               std::make_error_code(errc::illegal_byte_sequence)));
  640.       }
  641. #endif
  642.  
  643.       static string_type
  644.       _S_convert(_CharT* __f, _CharT* __l)
  645.       {
  646.         return _S_convert(const_cast<const _CharT*>(__f),
  647.                           const_cast<const _CharT*>(__l));
  648.       }
  649.  
  650.       template<typename _Iter>
  651.         static string_type
  652.         _S_convert(_Iter __first, _Iter __last)
  653.         {
  654.           const std::basic_string<_CharT> __str(__first, __last);
  655.           return _S_convert(__str.data(), __str.data() + __str.size());
  656.         }
  657.  
  658.       template<typename _Iter, typename _Cont>
  659.         static string_type
  660.         _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
  661.                   __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
  662.         { return _S_convert(__first.base(), __last.base()); }
  663.     };
  664.  
  665.   /// An iterator for the components of a path
  666.   class path::iterator
  667.   {
  668.   public:
  669.     using difference_type       = std::ptrdiff_t;
  670.     using value_type            = path;
  671.     using reference             = const path&;
  672.     using pointer               = const path*;
  673.     using iterator_category     = std::bidirectional_iterator_tag;
  674.  
  675.     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
  676.  
  677.     iterator(const iterator&) = default;
  678.     iterator& operator=(const iterator&) = default;
  679.  
  680.     reference operator*() const;
  681.     pointer   operator->() const { return std::__addressof(**this); }
  682.  
  683.     iterator& operator++();
  684.     iterator  operator++(int) { auto __tmp = *this; ++_M_cur; return __tmp; }
  685.  
  686.     iterator& operator--();
  687.     iterator  operator--(int) { auto __tmp = *this; --_M_cur; return __tmp; }
  688.  
  689.     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
  690.     { return __lhs._M_equals(__rhs); }
  691.  
  692.     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
  693.     { return !__lhs._M_equals(__rhs); }
  694.  
  695.   private:
  696.     friend class path;
  697.  
  698.     iterator(const path* __path, path::_List::const_iterator __iter)
  699.     : _M_path(__path), _M_cur(__iter), _M_at_end()
  700.     { }
  701.  
  702.     iterator(const path* __path, bool __at_end)
  703.     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
  704.     { }
  705.  
  706.     bool _M_equals(iterator) const;
  707.  
  708.     const path*                 _M_path;
  709.     path::_List::const_iterator _M_cur;
  710.     bool                        _M_at_end;  // only used when type != _Multi
  711.   };
  712.  
  713.  
  714.   inline path&
  715.   path::operator=(path&& __p) noexcept
  716.   {
  717.     _M_pathname = std::move(__p._M_pathname);
  718.     _M_cmpts = std::move(__p._M_cmpts);
  719.     _M_type = __p._M_type;
  720.     __p.clear();
  721.     return *this;
  722.   }
  723.  
  724.   inline path&
  725.   path::operator+=(const path& __p)
  726.   {
  727.     return operator+=(__p.native());
  728.   }
  729.  
  730.   inline path&
  731.   path::operator+=(const string_type& __x)
  732.   {
  733.     _M_pathname += __x;
  734.     _M_split_cmpts();
  735.     return *this;
  736.   }
  737.  
  738.   inline path&
  739.   path::operator+=(const value_type* __x)
  740.   {
  741.     _M_pathname += __x;
  742.     _M_split_cmpts();
  743.     return *this;
  744.   }
  745.  
  746.   inline path&
  747.   path::operator+=(value_type __x)
  748.   {
  749.     _M_pathname += __x;
  750.     _M_split_cmpts();
  751.     return *this;
  752.   }
  753.  
  754.   template<typename _CharT>
  755.     inline path::_Path<_CharT*, _CharT*>&
  756.     path::operator+=(_CharT __x)
  757.     {
  758.       auto* __addr = std::__addressof(__x);
  759.       return concat(__addr, __addr + 1);
  760.     }
  761.  
  762.   inline path&
  763.   path::make_preferred()
  764.   {
  765. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  766.     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
  767.                  preferred_separator);
  768. #endif
  769.     return *this;
  770.   }
  771.  
  772.   inline void path::swap(path& __rhs) noexcept
  773.   {
  774.     _M_pathname.swap(__rhs._M_pathname);
  775.     _M_cmpts.swap(__rhs._M_cmpts);
  776.     std::swap(_M_type, __rhs._M_type);
  777.   }
  778.  
  779.   template<typename _CharT, typename _Traits, typename _Allocator>
  780.     inline std::basic_string<_CharT, _Traits, _Allocator>
  781.     path::string(const _Allocator& __a) const
  782.     {
  783.       if (is_same<_CharT, value_type>::value)
  784.         return { _M_pathname.begin(), _M_pathname.end(), __a };
  785.  
  786.       const value_type* __first = _M_pathname.data();
  787.       const value_type* __last = __first + _M_pathname.size();
  788.  
  789. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  790.       using _CharAlloc = __alloc_rebind<_Allocator, char>;
  791.       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
  792.       using _WString = basic_string<_CharT, _Traits, _Allocator>;
  793.  
  794.       // use codecvt_utf8<wchar_t> to convert native string to UTF-8
  795.       codecvt_utf8<value_type> __cvt;
  796.       _String __u8str{_CharAlloc{__a}};
  797.       if (__str_codecvt_out(__first, __last, __u8str, __cvt))
  798.         {
  799.           struct
  800.           {
  801.             const _String*
  802.             operator()(const _String& __from, _String&, true_type)
  803.             { return std::__addressof(__from); }
  804.  
  805.             _WString*
  806.             operator()(const _String& __from, _WString& __to, false_type)
  807.             {
  808.               // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
  809.               codecvt_utf8<_CharT> __cvt;
  810.               const char* __f = __from.data();
  811.               const char* __l = __f + __from.size();
  812.               if (__str_codecvt_in(__f, __l, __to, __cvt))
  813.                 return std::__addressof(__to);
  814.               return nullptr;
  815.             }
  816.           } __dispatch;
  817.           _WString __wstr;
  818.           if (auto* __p = __dispatch(__u8str, __wstr, is_same<_CharT, char>{}))
  819.             return *__p;
  820.         }
  821. #else
  822.       codecvt_utf8<_CharT> __cvt;
  823.       basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
  824.       if (__str_codecvt_in(__first, __last, __wstr, __cvt))
  825.         return __wstr;
  826. #endif
  827.       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  828.             "Cannot convert character sequence",
  829.             std::make_error_code(errc::illegal_byte_sequence)));
  830.     }
  831.  
  832.   inline std::string
  833.   path::string() const { return string<char>(); }
  834.  
  835. #if _GLIBCXX_USE_WCHAR_T
  836.   inline std::wstring
  837.   path::wstring() const { return string<wchar_t>(); }
  838. #endif
  839.  
  840.   inline std::string
  841.   path::u8string() const
  842.   {
  843. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  844.     std::string __str;
  845.     // convert from native encoding to UTF-8
  846.     codecvt_utf8<value_type> __cvt;
  847.     const value_type* __first = _M_pathname.data();
  848.     const value_type* __last = __first + _M_pathname.size();
  849.     if (__str_codecvt_out(__first, __last, __str, __cvt))
  850.       return __str;
  851.     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  852.           "Cannot convert character sequence",
  853.           std::make_error_code(errc::illegal_byte_sequence)));
  854. #else
  855.     return _M_pathname;
  856. #endif
  857.   }
  858.  
  859.   inline std::u16string
  860.   path::u16string() const { return string<char16_t>(); }
  861.  
  862.   inline std::u32string
  863.   path::u32string() const { return string<char32_t>(); }
  864.  
  865. #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  866.   template<typename _CharT, typename _Traits, typename _Allocator>
  867.     inline std::basic_string<_CharT, _Traits, _Allocator>
  868.     path::generic_string(const _Allocator& __a) const
  869.     { return string<_CharT, _Traits, _Allocator>(__a); }
  870.  
  871.   inline std::string
  872.   path::generic_string() const { return string(); }
  873.  
  874. #if _GLIBCXX_USE_WCHAR_T
  875.   inline std::wstring
  876.   path::generic_wstring() const { return wstring(); }
  877. #endif
  878.  
  879.   inline std::string
  880.   path::generic_u8string() const { return u8string(); }
  881.  
  882.   inline std::u16string
  883.   path::generic_u16string() const { return u16string(); }
  884.  
  885.   inline std::u32string
  886.   path::generic_u32string() const { return u32string(); }
  887. #endif
  888.  
  889.   inline int
  890.   path::compare(const string_type& __s) const { return compare(path(__s)); }
  891.  
  892.   inline int
  893.   path::compare(const value_type* __s) const { return compare(path(__s)); }
  894.  
  895.   inline path
  896.   path::filename() const { return empty() ? path() : *--end(); }
  897.  
  898.   inline path
  899.   path::stem() const
  900.   {
  901.     auto ext = _M_find_extension();
  902.     if (ext.first && ext.second != 0)
  903.       return path{ext.first->substr(0, ext.second)};
  904.     return {};
  905.   }
  906.  
  907.   inline path
  908.   path::extension() const
  909.   {
  910.     auto ext = _M_find_extension();
  911.     if (ext.first && ext.second != string_type::npos)
  912.       return path{ext.first->substr(ext.second)};
  913.     return {};
  914.   }
  915.  
  916.   inline bool
  917.   path::has_stem() const
  918.   {
  919.     auto ext = _M_find_extension();
  920.     return ext.first && ext.second != 0;
  921.   }
  922.  
  923.   inline bool
  924.   path::has_extension() const
  925.   {
  926.     auto ext = _M_find_extension();
  927.     return ext.first && ext.second != string_type::npos;
  928.   }
  929.  
  930.   inline bool
  931.   path::is_absolute() const
  932.   {
  933. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  934.     return has_root_name();
  935. #else
  936.     return has_root_directory();
  937. #endif
  938.   }
  939.  
  940.   inline path::iterator
  941.   path::begin() const
  942.   {
  943.     if (_M_type == _Type::_Multi)
  944.       return iterator(this, _M_cmpts.begin());
  945.     return iterator(this, false);
  946.   }
  947.  
  948.   inline path::iterator
  949.   path::end() const
  950.   {
  951.     if (_M_type == _Type::_Multi)
  952.       return iterator(this, _M_cmpts.end());
  953.     return iterator(this, true);
  954.   }
  955.  
  956.   inline path::iterator&
  957.   path::iterator::operator++()
  958.   {
  959.     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
  960.     if (_M_path->_M_type == _Type::_Multi)
  961.       {
  962.         _GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.end());
  963.         ++_M_cur;
  964.       }
  965.     else
  966.       {
  967.         _GLIBCXX_DEBUG_ASSERT(!_M_at_end);
  968.         _M_at_end = true;
  969.       }
  970.     return *this;
  971.   }
  972.  
  973.   inline path::iterator&
  974.   path::iterator::operator--()
  975.   {
  976.     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
  977.     if (_M_path->_M_type == _Type::_Multi)
  978.       {
  979.         _GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.begin());
  980.         --_M_cur;
  981.       }
  982.     else
  983.       {
  984.         _GLIBCXX_DEBUG_ASSERT(_M_at_end);
  985.         _M_at_end = false;
  986.       }
  987.     return *this;
  988.   }
  989.  
  990.   inline path::iterator::reference
  991.   path::iterator::operator*() const
  992.   {
  993.     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
  994.     if (_M_path->_M_type == _Type::_Multi)
  995.       {
  996.         _GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.end());
  997.         return *_M_cur;
  998.       }
  999.     return *_M_path;
  1000.   }
  1001.  
  1002.   inline bool
  1003.   path::iterator::_M_equals(iterator __rhs) const
  1004.   {
  1005.     if (_M_path != __rhs._M_path)
  1006.       return false;
  1007.     if (_M_path == nullptr)
  1008.       return true;
  1009.     if (_M_path->_M_type == path::_Type::_Multi)
  1010.       return _M_cur == __rhs._M_cur;
  1011.     return _M_at_end == __rhs._M_at_end;
  1012.   }
  1013.  
  1014.   // @} group filesystem
  1015. _GLIBCXX_END_NAMESPACE_CXX11
  1016. _GLIBCXX_END_NAMESPACE_VERSION
  1017. } // namespace v1
  1018. } // namespace filesystem
  1019. } // namespace experimental
  1020. } // namespace std
  1021.  
  1022. #endif // C++11
  1023.  
  1024. #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H
  1025.