xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/include/experimental/bits/fs_path.h (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg // Class filesystem::path -*- C++ -*-
236ac495dSmrg 
3*8feb0f0bSmrg // Copyright (C) 2014-2020 Free Software Foundation, Inc.
436ac495dSmrg //
536ac495dSmrg // This file is part of the GNU ISO C++ Library.  This library is free
636ac495dSmrg // software; you can redistribute it and/or modify it under the
736ac495dSmrg // terms of the GNU General Public License as published by the
836ac495dSmrg // Free Software Foundation; either version 3, or (at your option)
936ac495dSmrg // any later version.
1036ac495dSmrg 
1136ac495dSmrg // This library is distributed in the hope that it will be useful,
1236ac495dSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
1336ac495dSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1436ac495dSmrg // GNU General Public License for more details.
1536ac495dSmrg 
1636ac495dSmrg // Under Section 7 of GPL version 3, you are granted additional
1736ac495dSmrg // permissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg // 3.1, as published by the Free Software Foundation.
1936ac495dSmrg 
2036ac495dSmrg // You should have received a copy of the GNU General Public License and
2136ac495dSmrg // a copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2336ac495dSmrg // <http://www.gnu.org/licenses/>.
2436ac495dSmrg 
2536ac495dSmrg /** @file experimental/bits/fs_path.h
2636ac495dSmrg  *  This is an internal header file, included by other library headers.
2736ac495dSmrg  *  Do not attempt to use it directly. @headername{experimental/filesystem}
2836ac495dSmrg  */
2936ac495dSmrg 
3036ac495dSmrg #ifndef _GLIBCXX_EXPERIMENTAL_FS_PATH_H
3136ac495dSmrg #define _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1
3236ac495dSmrg 
3336ac495dSmrg #if __cplusplus < 201103L
3436ac495dSmrg # include <bits/c++0x_warning.h>
3536ac495dSmrg #else
3636ac495dSmrg 
3736ac495dSmrg #include <utility>
3836ac495dSmrg #include <type_traits>
3936ac495dSmrg #include <vector>
4036ac495dSmrg #include <locale>
4136ac495dSmrg #include <iosfwd>
4236ac495dSmrg #include <codecvt>
4336ac495dSmrg #include <system_error>
4436ac495dSmrg #include <bits/stl_algobase.h>
4536ac495dSmrg #include <bits/quoted_string.h>
4636ac495dSmrg #include <bits/locale_conv.h>
4736ac495dSmrg #if __cplusplus == 201402L
4836ac495dSmrg # include <experimental/string_view>
4936ac495dSmrg #endif
5036ac495dSmrg 
5136ac495dSmrg #if defined(_WIN32) && !defined(__CYGWIN__)
5236ac495dSmrg # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
5336ac495dSmrg # include <algorithm>
5436ac495dSmrg #endif
5536ac495dSmrg 
_GLIBCXX_VISIBILITY(default)5636ac495dSmrg namespace std _GLIBCXX_VISIBILITY(default)
5736ac495dSmrg {
58a2dc1f3fSmrg _GLIBCXX_BEGIN_NAMESPACE_VERSION
59a2dc1f3fSmrg 
6036ac495dSmrg namespace experimental
6136ac495dSmrg {
6236ac495dSmrg namespace filesystem
6336ac495dSmrg {
6436ac495dSmrg inline namespace v1
6536ac495dSmrg {
6636ac495dSmrg _GLIBCXX_BEGIN_NAMESPACE_CXX11
6736ac495dSmrg 
6836ac495dSmrg #if __cplusplus == 201402L
6936ac495dSmrg   using std::experimental::basic_string_view;
7036ac495dSmrg #elif __cplusplus > 201402L
7136ac495dSmrg   using std::basic_string_view;
7236ac495dSmrg #endif
7336ac495dSmrg 
74*8feb0f0bSmrg   /** @addtogroup filesystem-ts
7536ac495dSmrg    *  @{
7636ac495dSmrg    */
7736ac495dSmrg 
78*8feb0f0bSmrg   /// @cond undocumented
79*8feb0f0bSmrg namespace __detail
8036ac495dSmrg {
81c0a68be4Smrg   template<typename _CharT,
82c0a68be4Smrg 	   typename _Ch = typename remove_const<_CharT>::type>
83c0a68be4Smrg     using __is_encoded_char
84c0a68be4Smrg       = __or_<is_same<_Ch, char>,
85c0a68be4Smrg 	      is_same<_Ch, wchar_t>,
86c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
87c0a68be4Smrg 	      is_same<_Ch, char8_t>,
88c0a68be4Smrg #endif
89c0a68be4Smrg 	      is_same<_Ch, char16_t>,
90c0a68be4Smrg 	      is_same<_Ch, char32_t>>;
9136ac495dSmrg 
9236ac495dSmrg   template<typename _Iter,
9336ac495dSmrg 	   typename _Iter_traits = std::iterator_traits<_Iter>>
9436ac495dSmrg     using __is_path_iter_src
9536ac495dSmrg       = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
9636ac495dSmrg 	       std::is_base_of<std::input_iterator_tag,
9736ac495dSmrg 			       typename _Iter_traits::iterator_category>>;
9836ac495dSmrg 
9936ac495dSmrg   template<typename _Iter>
10036ac495dSmrg     static __is_path_iter_src<_Iter>
10136ac495dSmrg     __is_path_src(_Iter, int);
10236ac495dSmrg 
10336ac495dSmrg   template<typename _CharT, typename _Traits, typename _Alloc>
10436ac495dSmrg     static __is_encoded_char<_CharT>
10536ac495dSmrg     __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
10636ac495dSmrg 
10736ac495dSmrg #if __cplusplus >= 201402L
10836ac495dSmrg   template<typename _CharT, typename _Traits>
10936ac495dSmrg     static __is_encoded_char<_CharT>
11036ac495dSmrg     __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
11136ac495dSmrg #endif
11236ac495dSmrg 
11336ac495dSmrg   template<typename _Unknown>
11436ac495dSmrg     static std::false_type
11536ac495dSmrg     __is_path_src(const _Unknown&, ...);
11636ac495dSmrg 
11736ac495dSmrg   template<typename _Tp1, typename _Tp2>
11836ac495dSmrg     struct __constructible_from;
11936ac495dSmrg 
12036ac495dSmrg   template<typename _Iter>
12136ac495dSmrg     struct __constructible_from<_Iter, _Iter>
12236ac495dSmrg     : __is_path_iter_src<_Iter>
12336ac495dSmrg     { };
12436ac495dSmrg 
12536ac495dSmrg   template<typename _Source>
12636ac495dSmrg     struct __constructible_from<_Source, void>
127*8feb0f0bSmrg     : decltype(__is_path_src(std::declval<const _Source&>(), 0))
12836ac495dSmrg     { };
12936ac495dSmrg 
130a2dc1f3fSmrg   template<typename _Tp1, typename _Tp2 = void,
131a2dc1f3fSmrg 	   typename _Tp1_nocv = typename remove_cv<_Tp1>::type,
132a2dc1f3fSmrg 	   typename _Tp1_noptr = typename remove_pointer<_Tp1>::type>
13336ac495dSmrg     using _Path = typename
134a2dc1f3fSmrg       std::enable_if<__and_<__not_<is_same<_Tp1_nocv, path>>,
135a2dc1f3fSmrg 			    __not_<is_void<_Tp1_noptr>>,
13636ac495dSmrg 			    __constructible_from<_Tp1, _Tp2>>::value,
13736ac495dSmrg 		     path>::type;
13836ac495dSmrg 
13936ac495dSmrg   template<typename _Source>
140*8feb0f0bSmrg     inline _Source
14136ac495dSmrg     _S_range_begin(_Source __begin) { return __begin; }
14236ac495dSmrg 
143*8feb0f0bSmrg   struct __nul_terminated { };
14436ac495dSmrg 
14536ac495dSmrg   template<typename _Source>
146*8feb0f0bSmrg     inline __nul_terminated
14736ac495dSmrg     _S_range_end(_Source) { return {}; }
14836ac495dSmrg 
14936ac495dSmrg   template<typename _CharT, typename _Traits, typename _Alloc>
150*8feb0f0bSmrg     inline const _CharT*
15136ac495dSmrg     _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
15236ac495dSmrg     { return __str.data(); }
15336ac495dSmrg 
15436ac495dSmrg   template<typename _CharT, typename _Traits, typename _Alloc>
155*8feb0f0bSmrg     inline const _CharT*
15636ac495dSmrg     _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
15736ac495dSmrg     { return __str.data() + __str.size(); }
15836ac495dSmrg 
15936ac495dSmrg #if __cplusplus >= 201402L
16036ac495dSmrg   template<typename _CharT, typename _Traits>
161*8feb0f0bSmrg     inline const _CharT*
16236ac495dSmrg     _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
16336ac495dSmrg     { return __str.data(); }
16436ac495dSmrg 
16536ac495dSmrg   template<typename _CharT, typename _Traits>
166*8feb0f0bSmrg     inline const _CharT*
16736ac495dSmrg     _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
16836ac495dSmrg     { return __str.data() + __str.size(); }
16936ac495dSmrg #endif
17036ac495dSmrg 
17136ac495dSmrg   template<typename _Tp,
17236ac495dSmrg 	   typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
173*8feb0f0bSmrg 	   typename _Val = typename std::iterator_traits<_Iter>::value_type,
174*8feb0f0bSmrg 	   typename _UnqualVal = typename std::remove_const<_Val>::type>
175c0a68be4Smrg     using __value_type_is_char = typename std::enable_if<
176*8feb0f0bSmrg       std::is_same<_UnqualVal, char>::value,
177*8feb0f0bSmrg       _UnqualVal>::type;
17836ac495dSmrg 
179*8feb0f0bSmrg   template<typename _Tp,
180*8feb0f0bSmrg 	   typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
181*8feb0f0bSmrg 	   typename _Val = typename std::iterator_traits<_Iter>::value_type,
182*8feb0f0bSmrg 	   typename _UnqualVal = typename std::remove_const<_Val>::type>
183*8feb0f0bSmrg     using __value_type_is_char_or_char8_t = typename std::enable_if<
184*8feb0f0bSmrg       __or_<
185*8feb0f0bSmrg 	std::is_same<_UnqualVal, char>
186*8feb0f0bSmrg #ifdef _GLIBCXX_USE_CHAR8_T
187*8feb0f0bSmrg 	,std::is_same<_UnqualVal, char8_t>
188*8feb0f0bSmrg #endif
189*8feb0f0bSmrg       >::value, _UnqualVal>::type;
190*8feb0f0bSmrg 
191*8feb0f0bSmrg } // namespace __detail
192*8feb0f0bSmrg   /// @endcond
193*8feb0f0bSmrg 
194*8feb0f0bSmrg   /// A filesystem path.
195*8feb0f0bSmrg   class path
196*8feb0f0bSmrg   {
19736ac495dSmrg   public:
19836ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
19936ac495dSmrg     typedef wchar_t				value_type;
20036ac495dSmrg     static constexpr value_type			preferred_separator = L'\\';
20136ac495dSmrg #else
20236ac495dSmrg     typedef char				value_type;
20336ac495dSmrg     static constexpr value_type			preferred_separator = '/';
20436ac495dSmrg #endif
20536ac495dSmrg     typedef std::basic_string<value_type>	string_type;
20636ac495dSmrg 
20736ac495dSmrg     // constructors and destructor
20836ac495dSmrg 
20936ac495dSmrg     path() noexcept { }
21036ac495dSmrg 
21136ac495dSmrg     path(const path& __p) = default;
21236ac495dSmrg 
21336ac495dSmrg     path(path&& __p) noexcept
21436ac495dSmrg     : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
21536ac495dSmrg     {
216a2dc1f3fSmrg       if (_M_type == _Type::_Multi)
21736ac495dSmrg 	_M_split_cmpts();
21836ac495dSmrg       __p.clear();
21936ac495dSmrg     }
22036ac495dSmrg 
22136ac495dSmrg     path(string_type&& __source)
22236ac495dSmrg     : _M_pathname(std::move(__source))
22336ac495dSmrg     { _M_split_cmpts(); }
22436ac495dSmrg 
22536ac495dSmrg     template<typename _Source,
226*8feb0f0bSmrg 	     typename _Require = __detail::_Path<_Source>>
22736ac495dSmrg       path(_Source const& __source)
228*8feb0f0bSmrg       : _M_pathname(_S_convert(__detail::_S_range_begin(__source),
229*8feb0f0bSmrg 			       __detail::_S_range_end(__source)))
23036ac495dSmrg       { _M_split_cmpts(); }
23136ac495dSmrg 
23236ac495dSmrg     template<typename _InputIterator,
233*8feb0f0bSmrg 	     typename _Require = __detail::_Path<_InputIterator, _InputIterator>>
23436ac495dSmrg       path(_InputIterator __first, _InputIterator __last)
23536ac495dSmrg       : _M_pathname(_S_convert(__first, __last))
23636ac495dSmrg       { _M_split_cmpts(); }
23736ac495dSmrg 
23836ac495dSmrg     template<typename _Source,
239*8feb0f0bSmrg 	     typename _Require = __detail::_Path<_Source>,
240*8feb0f0bSmrg 	     typename _Require2 = __detail::__value_type_is_char<_Source>>
24136ac495dSmrg       path(_Source const& __source, const locale& __loc)
242*8feb0f0bSmrg       : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source),
243*8feb0f0bSmrg 				   __detail::_S_range_end(__source), __loc))
24436ac495dSmrg       { _M_split_cmpts(); }
24536ac495dSmrg 
24636ac495dSmrg     template<typename _InputIterator,
247*8feb0f0bSmrg 	     typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
248*8feb0f0bSmrg 	     typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
24936ac495dSmrg       path(_InputIterator __first, _InputIterator __last, const locale& __loc)
25036ac495dSmrg       : _M_pathname(_S_convert_loc(__first, __last, __loc))
25136ac495dSmrg       { _M_split_cmpts(); }
25236ac495dSmrg 
25336ac495dSmrg     ~path() = default;
25436ac495dSmrg 
25536ac495dSmrg     // assignments
25636ac495dSmrg 
25736ac495dSmrg     path& operator=(const path& __p) = default;
25836ac495dSmrg     path& operator=(path&& __p) noexcept;
25936ac495dSmrg     path& operator=(string_type&& __source);
26036ac495dSmrg     path& assign(string_type&& __source);
26136ac495dSmrg 
26236ac495dSmrg     template<typename _Source>
263*8feb0f0bSmrg       __detail::_Path<_Source>&
26436ac495dSmrg       operator=(_Source const& __source)
26536ac495dSmrg       { return *this = path(__source); }
26636ac495dSmrg 
26736ac495dSmrg     template<typename _Source>
268*8feb0f0bSmrg       __detail::_Path<_Source>&
26936ac495dSmrg       assign(_Source const& __source)
27036ac495dSmrg       { return *this = path(__source); }
27136ac495dSmrg 
27236ac495dSmrg     template<typename _InputIterator>
273*8feb0f0bSmrg       __detail::_Path<_InputIterator, _InputIterator>&
27436ac495dSmrg       assign(_InputIterator __first, _InputIterator __last)
27536ac495dSmrg       { return *this = path(__first, __last); }
27636ac495dSmrg 
27736ac495dSmrg     // appends
27836ac495dSmrg 
27936ac495dSmrg     path& operator/=(const path& __p) { return _M_append(__p._M_pathname); }
28036ac495dSmrg 
281*8feb0f0bSmrg     template<typename _Source>
282*8feb0f0bSmrg       __detail::_Path<_Source>&
28336ac495dSmrg       operator/=(_Source const& __source)
28436ac495dSmrg       { return append(__source); }
28536ac495dSmrg 
28636ac495dSmrg     template<typename _Source>
287*8feb0f0bSmrg       __detail::_Path<_Source>&
28836ac495dSmrg       append(_Source const& __source)
28936ac495dSmrg       {
290*8feb0f0bSmrg 	return _M_append(_S_convert(__detail::_S_range_begin(__source),
291*8feb0f0bSmrg 				    __detail::_S_range_end(__source)));
29236ac495dSmrg       }
29336ac495dSmrg 
29436ac495dSmrg     template<typename _InputIterator>
295*8feb0f0bSmrg       __detail::_Path<_InputIterator, _InputIterator>&
29636ac495dSmrg       append(_InputIterator __first, _InputIterator __last)
29736ac495dSmrg       { return _M_append(_S_convert(__first, __last)); }
29836ac495dSmrg 
29936ac495dSmrg     // concatenation
30036ac495dSmrg 
30136ac495dSmrg     path& operator+=(const path& __x);
30236ac495dSmrg     path& operator+=(const string_type& __x);
30336ac495dSmrg     path& operator+=(const value_type* __x);
30436ac495dSmrg     path& operator+=(value_type __x);
30536ac495dSmrg #if __cplusplus >= 201402L
30636ac495dSmrg     path& operator+=(basic_string_view<value_type> __x);
30736ac495dSmrg #endif
30836ac495dSmrg 
30936ac495dSmrg     template<typename _Source>
310*8feb0f0bSmrg       __detail::_Path<_Source>&
31136ac495dSmrg       operator+=(_Source const& __x) { return concat(__x); }
31236ac495dSmrg 
31336ac495dSmrg     template<typename _CharT>
314*8feb0f0bSmrg       __detail::_Path<_CharT*, _CharT*>&
31536ac495dSmrg       operator+=(_CharT __x);
31636ac495dSmrg 
31736ac495dSmrg     template<typename _Source>
318*8feb0f0bSmrg       __detail::_Path<_Source>&
31936ac495dSmrg       concat(_Source const& __x)
320*8feb0f0bSmrg       {
321*8feb0f0bSmrg 	return *this += _S_convert(__detail::_S_range_begin(__x),
322*8feb0f0bSmrg 				   __detail::_S_range_end(__x));
323*8feb0f0bSmrg       }
32436ac495dSmrg 
32536ac495dSmrg     template<typename _InputIterator>
326*8feb0f0bSmrg       __detail::_Path<_InputIterator, _InputIterator>&
32736ac495dSmrg       concat(_InputIterator __first, _InputIterator __last)
32836ac495dSmrg       { return *this += _S_convert(__first, __last); }
32936ac495dSmrg 
33036ac495dSmrg     // modifiers
33136ac495dSmrg 
33236ac495dSmrg     void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
33336ac495dSmrg 
33436ac495dSmrg     path& make_preferred();
33536ac495dSmrg     path& remove_filename();
33636ac495dSmrg     path& replace_filename(const path& __replacement);
33736ac495dSmrg     path& replace_extension(const path& __replacement = path());
33836ac495dSmrg 
33936ac495dSmrg     void swap(path& __rhs) noexcept;
34036ac495dSmrg 
34136ac495dSmrg     // native format observers
34236ac495dSmrg 
34336ac495dSmrg     const string_type&  native() const noexcept { return _M_pathname; }
34436ac495dSmrg     const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
34536ac495dSmrg     operator string_type() const { return _M_pathname; }
34636ac495dSmrg 
34736ac495dSmrg     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
34836ac495dSmrg 	     typename _Allocator = std::allocator<_CharT>>
34936ac495dSmrg       std::basic_string<_CharT, _Traits, _Allocator>
35036ac495dSmrg       string(const _Allocator& __a = _Allocator()) const;
35136ac495dSmrg 
35236ac495dSmrg     std::string    string() const;
35336ac495dSmrg #if _GLIBCXX_USE_WCHAR_T
35436ac495dSmrg     std::wstring   wstring() const;
35536ac495dSmrg #endif
356c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
357c0a68be4Smrg     __attribute__((__abi_tag__("__u8")))
358c0a68be4Smrg     std::u8string  u8string() const;
359c0a68be4Smrg #else
36036ac495dSmrg     std::string    u8string() const;
361c0a68be4Smrg #endif // _GLIBCXX_USE_CHAR8_T
36236ac495dSmrg     std::u16string u16string() const;
36336ac495dSmrg     std::u32string u32string() const;
36436ac495dSmrg 
36536ac495dSmrg     // generic format observers
36636ac495dSmrg     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
36736ac495dSmrg 	     typename _Allocator = std::allocator<_CharT>>
36836ac495dSmrg       std::basic_string<_CharT, _Traits, _Allocator>
36936ac495dSmrg       generic_string(const _Allocator& __a = _Allocator()) const;
37036ac495dSmrg 
37136ac495dSmrg     std::string    generic_string() const;
37236ac495dSmrg #if _GLIBCXX_USE_WCHAR_T
37336ac495dSmrg     std::wstring   generic_wstring() const;
37436ac495dSmrg #endif
375c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
376c0a68be4Smrg     __attribute__((__abi_tag__("__u8")))
377c0a68be4Smrg     std::u8string  generic_u8string() const;
378c0a68be4Smrg #else
37936ac495dSmrg     std::string    generic_u8string() const;
380c0a68be4Smrg #endif // _GLIBCXX_USE_CHAR8_T
38136ac495dSmrg     std::u16string generic_u16string() const;
38236ac495dSmrg     std::u32string generic_u32string() const;
38336ac495dSmrg 
38436ac495dSmrg     // compare
38536ac495dSmrg 
38636ac495dSmrg     int compare(const path& __p) const noexcept;
38736ac495dSmrg     int compare(const string_type& __s) const;
38836ac495dSmrg     int compare(const value_type* __s) const;
38936ac495dSmrg #if __cplusplus >= 201402L
39036ac495dSmrg     int compare(const basic_string_view<value_type> __s) const;
39136ac495dSmrg #endif
39236ac495dSmrg 
39336ac495dSmrg     // decomposition
39436ac495dSmrg 
39536ac495dSmrg     path root_name() const;
39636ac495dSmrg     path root_directory() const;
39736ac495dSmrg     path root_path() const;
39836ac495dSmrg     path relative_path() const;
39936ac495dSmrg     path parent_path() const;
40036ac495dSmrg     path filename() const;
40136ac495dSmrg     path stem() const;
40236ac495dSmrg     path extension() const;
40336ac495dSmrg 
40436ac495dSmrg     // query
40536ac495dSmrg 
406c0a68be4Smrg     _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_pathname.empty(); }
40736ac495dSmrg     bool has_root_name() const;
40836ac495dSmrg     bool has_root_directory() const;
40936ac495dSmrg     bool has_root_path() const;
41036ac495dSmrg     bool has_relative_path() const;
41136ac495dSmrg     bool has_parent_path() const;
41236ac495dSmrg     bool has_filename() const;
41336ac495dSmrg     bool has_stem() const;
41436ac495dSmrg     bool has_extension() const;
415c0a68be4Smrg     bool is_absolute() const;
41636ac495dSmrg     bool is_relative() const { return !is_absolute(); }
41736ac495dSmrg 
41836ac495dSmrg     // iterators
41936ac495dSmrg     class iterator;
42036ac495dSmrg     typedef iterator const_iterator;
42136ac495dSmrg 
42236ac495dSmrg     iterator begin() const;
42336ac495dSmrg     iterator end() const;
42436ac495dSmrg 
425*8feb0f0bSmrg     /// @cond undocumented
426c0a68be4Smrg     // Create a basic_string by reading until a null character.
427c0a68be4Smrg     template<typename _InputIterator,
428c0a68be4Smrg 	     typename _Traits = std::iterator_traits<_InputIterator>,
429c0a68be4Smrg 	     typename _CharT
430c0a68be4Smrg 	       = typename std::remove_cv<typename _Traits::value_type>::type>
431c0a68be4Smrg       static std::basic_string<_CharT>
432c0a68be4Smrg       _S_string_from_iter(_InputIterator __source)
433c0a68be4Smrg       {
434c0a68be4Smrg 	std::basic_string<_CharT> __str;
435c0a68be4Smrg 	for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
436c0a68be4Smrg 	  __str.push_back(__ch);
437c0a68be4Smrg 	return __str;
438c0a68be4Smrg       }
439*8feb0f0bSmrg     /// @endcond
440c0a68be4Smrg 
44136ac495dSmrg   private:
44236ac495dSmrg     enum class _Type : unsigned char {
44336ac495dSmrg 	_Multi, _Root_name, _Root_dir, _Filename
44436ac495dSmrg     };
44536ac495dSmrg 
44636ac495dSmrg     path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
44736ac495dSmrg     {
44836ac495dSmrg       __glibcxx_assert(!empty());
44936ac495dSmrg       __glibcxx_assert(_M_type != _Type::_Multi);
45036ac495dSmrg     }
45136ac495dSmrg 
45236ac495dSmrg     enum class _Split { _Stem, _Extension };
45336ac495dSmrg 
45436ac495dSmrg     path& _M_append(const string_type& __str)
45536ac495dSmrg     {
45636ac495dSmrg       if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
45736ac495dSmrg 	  && !__str.empty() && !_S_is_dir_sep(__str.front()))
45836ac495dSmrg 	_M_pathname += preferred_separator;
45936ac495dSmrg       _M_pathname += __str;
46036ac495dSmrg       _M_split_cmpts();
46136ac495dSmrg       return *this;
46236ac495dSmrg     }
46336ac495dSmrg 
46436ac495dSmrg     pair<const string_type*, size_t> _M_find_extension() const;
46536ac495dSmrg 
46636ac495dSmrg     template<typename _CharT>
46736ac495dSmrg       struct _Cvt;
46836ac495dSmrg 
46936ac495dSmrg     static string_type
470*8feb0f0bSmrg     _S_convert(value_type* __src, __detail::__nul_terminated)
47136ac495dSmrg     { return string_type(__src); }
47236ac495dSmrg 
47336ac495dSmrg     static string_type
474*8feb0f0bSmrg     _S_convert(const value_type* __src, __detail::__nul_terminated)
47536ac495dSmrg     { return string_type(__src); }
47636ac495dSmrg 
47736ac495dSmrg     template<typename _Iter>
47836ac495dSmrg       static string_type
47936ac495dSmrg       _S_convert(_Iter __first, _Iter __last)
48036ac495dSmrg       {
48136ac495dSmrg 	using __value_type = typename std::iterator_traits<_Iter>::value_type;
48236ac495dSmrg 	return _Cvt<typename remove_cv<__value_type>::type>::
48336ac495dSmrg 	  _S_convert(__first, __last);
48436ac495dSmrg       }
48536ac495dSmrg 
48636ac495dSmrg     template<typename _InputIterator>
48736ac495dSmrg       static string_type
488*8feb0f0bSmrg       _S_convert(_InputIterator __src, __detail::__nul_terminated)
48936ac495dSmrg       {
490c0a68be4Smrg 	auto __s = _S_string_from_iter(__src);
491c0a68be4Smrg 	return _S_convert(__s.c_str(), __s.c_str() + __s.size());
49236ac495dSmrg       }
49336ac495dSmrg 
49436ac495dSmrg     static string_type
49536ac495dSmrg     _S_convert_loc(const char* __first, const char* __last,
49636ac495dSmrg 		   const std::locale& __loc);
49736ac495dSmrg 
49836ac495dSmrg     template<typename _Iter>
49936ac495dSmrg       static string_type
50036ac495dSmrg       _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
50136ac495dSmrg       {
50236ac495dSmrg 	const std::string __str(__first, __last);
50336ac495dSmrg 	return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
50436ac495dSmrg       }
50536ac495dSmrg 
50636ac495dSmrg     template<typename _InputIterator>
50736ac495dSmrg       static string_type
508*8feb0f0bSmrg       _S_convert_loc(_InputIterator __src, __detail::__nul_terminated,
50936ac495dSmrg 		     const std::locale& __loc)
51036ac495dSmrg       {
511c0a68be4Smrg 	const std::string __s = _S_string_from_iter(__src);
512c0a68be4Smrg 	return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
51336ac495dSmrg       }
51436ac495dSmrg 
515a2dc1f3fSmrg     static bool _S_is_dir_sep(value_type __ch)
51636ac495dSmrg     {
51736ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
51836ac495dSmrg       return __ch == L'/' || __ch == preferred_separator;
51936ac495dSmrg #else
52036ac495dSmrg       return __ch == '/';
52136ac495dSmrg #endif
52236ac495dSmrg     }
52336ac495dSmrg 
52436ac495dSmrg     void _M_split_cmpts();
52536ac495dSmrg     void _M_trim();
52636ac495dSmrg     void _M_add_root_name(size_t __n);
52736ac495dSmrg     void _M_add_root_dir(size_t __pos);
52836ac495dSmrg     void _M_add_filename(size_t __pos, size_t __n);
52936ac495dSmrg 
53036ac495dSmrg     string_type _M_pathname;
53136ac495dSmrg 
53236ac495dSmrg     struct _Cmpt;
53336ac495dSmrg     using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
53436ac495dSmrg     _List _M_cmpts; // empty unless _M_type == _Type::_Multi
53536ac495dSmrg     _Type _M_type = _Type::_Multi;
53636ac495dSmrg   };
53736ac495dSmrg 
538*8feb0f0bSmrg   /// @relates std::experimental::filesystem::path @{
539*8feb0f0bSmrg 
540*8feb0f0bSmrg   /// Swap overload for paths
54136ac495dSmrg   inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
54236ac495dSmrg 
543*8feb0f0bSmrg   /// Compute a hash value for a path
54436ac495dSmrg   size_t hash_value(const path& __p) noexcept;
54536ac495dSmrg 
54636ac495dSmrg   /// Compare paths
54736ac495dSmrg   inline bool operator<(const path& __lhs, const path& __rhs) noexcept
54836ac495dSmrg   { return __lhs.compare(__rhs) < 0; }
54936ac495dSmrg 
55036ac495dSmrg   /// Compare paths
55136ac495dSmrg   inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
55236ac495dSmrg   { return !(__rhs < __lhs); }
55336ac495dSmrg 
55436ac495dSmrg   /// Compare paths
55536ac495dSmrg   inline bool operator>(const path& __lhs, const path& __rhs) noexcept
55636ac495dSmrg   { return __rhs < __lhs; }
55736ac495dSmrg 
55836ac495dSmrg   /// Compare paths
55936ac495dSmrg   inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
56036ac495dSmrg   { return !(__lhs < __rhs); }
56136ac495dSmrg 
56236ac495dSmrg   /// Compare paths
56336ac495dSmrg   inline bool operator==(const path& __lhs, const path& __rhs) noexcept
56436ac495dSmrg   { return __lhs.compare(__rhs) == 0; }
56536ac495dSmrg 
56636ac495dSmrg   /// Compare paths
56736ac495dSmrg   inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
56836ac495dSmrg   { return !(__lhs == __rhs); }
56936ac495dSmrg 
57036ac495dSmrg   /// Append one path to another
57136ac495dSmrg   inline path operator/(const path& __lhs, const path& __rhs)
57236ac495dSmrg   {
57336ac495dSmrg     path __result(__lhs);
57436ac495dSmrg     __result /= __rhs;
57536ac495dSmrg     return __result;
57636ac495dSmrg   }
57736ac495dSmrg 
57836ac495dSmrg   /// Write a path to a stream
57936ac495dSmrg   template<typename _CharT, typename _Traits>
58036ac495dSmrg     basic_ostream<_CharT, _Traits>&
58136ac495dSmrg     operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
58236ac495dSmrg     {
58336ac495dSmrg       auto __tmp = __p.string<_CharT, _Traits>();
58436ac495dSmrg       using __quoted_string
58536ac495dSmrg 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
586c0a68be4Smrg       __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')};
58736ac495dSmrg       return __os;
58836ac495dSmrg     }
58936ac495dSmrg 
59036ac495dSmrg   /// Read a path from a stream
59136ac495dSmrg   template<typename _CharT, typename _Traits>
59236ac495dSmrg     basic_istream<_CharT, _Traits>&
59336ac495dSmrg     operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
59436ac495dSmrg     {
59536ac495dSmrg       basic_string<_CharT, _Traits> __tmp;
59636ac495dSmrg       using __quoted_string
59736ac495dSmrg 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
598c0a68be4Smrg       if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') })
59936ac495dSmrg 	__p = std::move(__tmp);
60036ac495dSmrg       return __is;
60136ac495dSmrg     }
60236ac495dSmrg 
603c0a68be4Smrg   /// Create a path from a UTF-8-encoded sequence of char
604*8feb0f0bSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
60536ac495dSmrg   template<typename _InputIterator>
60636ac495dSmrg     inline path
607*8feb0f0bSmrg     __u8path(_InputIterator __first, _InputIterator __last, char)
60836ac495dSmrg     {
609c0a68be4Smrg       // XXX This assumes native wide encoding is UTF-16.
610c0a68be4Smrg       std::codecvt_utf8_utf16<path::value_type> __cvt;
611c0a68be4Smrg       path::string_type __tmp;
612c0a68be4Smrg       const std::string __u8str{__first, __last};
613c0a68be4Smrg       const char* const __ptr = __u8str.data();
614c0a68be4Smrg       if (__str_codecvt_in_all(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
615c0a68be4Smrg 	return path{ __tmp };
616c0a68be4Smrg       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
617c0a68be4Smrg 	    "Cannot convert character sequence",
618c0a68be4Smrg 	    std::make_error_code(errc::illegal_byte_sequence)));
619*8feb0f0bSmrg     }
620*8feb0f0bSmrg 
621*8feb0f0bSmrg #ifdef _GLIBCXX_USE_CHAR8_T
622*8feb0f0bSmrg   template<typename _InputIterator>
623*8feb0f0bSmrg     inline path
624*8feb0f0bSmrg     __u8path(_InputIterator __first, _InputIterator __last, char8_t)
625*8feb0f0bSmrg     {
626*8feb0f0bSmrg       return path{ __first, __last };
627*8feb0f0bSmrg     }
628*8feb0f0bSmrg #endif // _GLIBCXX_USE_CHAR8_T
629*8feb0f0bSmrg #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
630*8feb0f0bSmrg 
631*8feb0f0bSmrg   template<typename _InputIterator,
632*8feb0f0bSmrg 	   typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
633*8feb0f0bSmrg 	   typename _CharT =
634*8feb0f0bSmrg 	     __detail::__value_type_is_char_or_char8_t<_InputIterator>>
635*8feb0f0bSmrg     inline path
636*8feb0f0bSmrg     u8path(_InputIterator __first, _InputIterator __last)
637*8feb0f0bSmrg     {
638*8feb0f0bSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
639*8feb0f0bSmrg       return __u8path(__first, __last, _CharT{});
64036ac495dSmrg #else
64136ac495dSmrg       return path{ __first, __last };
64236ac495dSmrg #endif
64336ac495dSmrg     }
64436ac495dSmrg 
645c0a68be4Smrg   /// Create a path from a UTF-8-encoded sequence of char
646*8feb0f0bSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
647*8feb0f0bSmrg   inline path
648*8feb0f0bSmrg   __u8path(const string& __s, char)
649*8feb0f0bSmrg   {
650*8feb0f0bSmrg     return filesystem::u8path(__s.data(), __s.data() + __s.size());
651*8feb0f0bSmrg   }
652*8feb0f0bSmrg 
653c0a68be4Smrg   template<typename _Source>
654*8feb0f0bSmrg     inline __enable_if_t<is_convertible<const _Source&, string>::value, path>
655*8feb0f0bSmrg     __u8path(const _Source& __source, char)
656*8feb0f0bSmrg     {
657*8feb0f0bSmrg       std::string __s = __source;
658*8feb0f0bSmrg       return filesystem::u8path(__s.data(), __s.data() + __s.size());
659*8feb0f0bSmrg     }
660*8feb0f0bSmrg 
661*8feb0f0bSmrg   template<typename _Source>
662*8feb0f0bSmrg     inline __enable_if_t<!is_convertible<const _Source&, string>::value, path>
663*8feb0f0bSmrg     __u8path(const _Source& __source, char)
664*8feb0f0bSmrg     {
665*8feb0f0bSmrg       std::string __s = path::_S_string_from_iter(__source);
666*8feb0f0bSmrg       return filesystem::u8path(__s.data(), __s.data() + __s.size());
667*8feb0f0bSmrg     }
668*8feb0f0bSmrg 
669*8feb0f0bSmrg #ifdef _GLIBCXX_USE_CHAR8_T
670*8feb0f0bSmrg   template<typename _Source>
671*8feb0f0bSmrg     inline path
672*8feb0f0bSmrg     __u8path(const _Source& __source, char8_t)
673*8feb0f0bSmrg     {
674*8feb0f0bSmrg       return path{ __source };
675*8feb0f0bSmrg     }
676*8feb0f0bSmrg #endif // _GLIBCXX_USE_CHAR8_T
677*8feb0f0bSmrg #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
678*8feb0f0bSmrg 
679*8feb0f0bSmrg   template<typename _Source,
680*8feb0f0bSmrg 	   typename _Require = __detail::_Path<_Source>,
681*8feb0f0bSmrg 	   typename _CharT =
682*8feb0f0bSmrg 	     __detail::__value_type_is_char_or_char8_t<_Source>>
683c0a68be4Smrg     inline path
684c0a68be4Smrg     u8path(const _Source& __source)
685c0a68be4Smrg     {
686c0a68be4Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
687*8feb0f0bSmrg       return __u8path(__source, _CharT{});
688c0a68be4Smrg #else
689c0a68be4Smrg       return path{ __source };
690c0a68be4Smrg #endif
691c0a68be4Smrg     }
692c0a68be4Smrg 
693*8feb0f0bSmrg   /// @}
694*8feb0f0bSmrg 
695*8feb0f0bSmrg   /// Exception type thrown by the Filesystem TS library
69636ac495dSmrg   class filesystem_error : public std::system_error
69736ac495dSmrg   {
69836ac495dSmrg   public:
69936ac495dSmrg     filesystem_error(const string& __what_arg, error_code __ec)
70036ac495dSmrg     : system_error(__ec, __what_arg) { }
70136ac495dSmrg 
70236ac495dSmrg     filesystem_error(const string& __what_arg, const path& __p1,
70336ac495dSmrg 		     error_code __ec)
70436ac495dSmrg     : system_error(__ec, __what_arg), _M_path1(__p1) { }
70536ac495dSmrg 
70636ac495dSmrg     filesystem_error(const string& __what_arg, const path& __p1,
70736ac495dSmrg 		     const path& __p2, error_code __ec)
70836ac495dSmrg     : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
70936ac495dSmrg     { }
71036ac495dSmrg 
71136ac495dSmrg     ~filesystem_error();
71236ac495dSmrg 
71336ac495dSmrg     const path& path1() const noexcept { return _M_path1; }
71436ac495dSmrg     const path& path2() const noexcept { return _M_path2; }
71536ac495dSmrg     const char* what() const noexcept { return _M_what.c_str(); }
71636ac495dSmrg 
71736ac495dSmrg   private:
71836ac495dSmrg     std::string _M_gen_what();
71936ac495dSmrg 
72036ac495dSmrg     path _M_path1;
72136ac495dSmrg     path _M_path2;
72236ac495dSmrg     std::string _M_what = _M_gen_what();
72336ac495dSmrg   };
72436ac495dSmrg 
725*8feb0f0bSmrg   /// @cond undocumented
72636ac495dSmrg   struct path::_Cmpt : path
72736ac495dSmrg   {
72836ac495dSmrg     _Cmpt(string_type __s, _Type __t, size_t __pos)
72936ac495dSmrg       : path(std::move(__s), __t), _M_pos(__pos) { }
73036ac495dSmrg 
73136ac495dSmrg     _Cmpt() : _M_pos(-1) { }
73236ac495dSmrg 
73336ac495dSmrg     size_t _M_pos;
73436ac495dSmrg   };
73536ac495dSmrg 
73636ac495dSmrg   // specialize _Cvt for degenerate 'noconv' case
73736ac495dSmrg   template<>
73836ac495dSmrg     struct path::_Cvt<path::value_type>
73936ac495dSmrg     {
74036ac495dSmrg       template<typename _Iter>
74136ac495dSmrg 	static string_type
74236ac495dSmrg 	_S_convert(_Iter __first, _Iter __last)
74336ac495dSmrg 	{ return string_type{__first, __last}; }
74436ac495dSmrg     };
74536ac495dSmrg 
74636ac495dSmrg   template<typename _CharT>
74736ac495dSmrg     struct path::_Cvt
74836ac495dSmrg     {
74936ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
750*8feb0f0bSmrg #ifdef _GLIBCXX_USE_CHAR8_T
75136ac495dSmrg       static string_type
752*8feb0f0bSmrg       _S_wconvert(const char8_t* __f, const char8_t* __l, const char8_t*)
753*8feb0f0bSmrg       {
754*8feb0f0bSmrg 	const char* __f2 = (const char*)__f;
755*8feb0f0bSmrg 	const char* __l2 = (const char*)__l;
756*8feb0f0bSmrg 	std::wstring __wstr;
757*8feb0f0bSmrg 	std::codecvt_utf8_utf16<wchar_t> __wcvt;
758*8feb0f0bSmrg 	if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
759*8feb0f0bSmrg 	  return __wstr;
760*8feb0f0bSmrg       }
761*8feb0f0bSmrg #endif
762*8feb0f0bSmrg 
763*8feb0f0bSmrg       static string_type
764*8feb0f0bSmrg       _S_wconvert(const char* __f, const char* __l, const char*)
76536ac495dSmrg       {
76636ac495dSmrg 	using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
76736ac495dSmrg 	const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
76836ac495dSmrg 	std::wstring __wstr;
769c0a68be4Smrg 	if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
77036ac495dSmrg 	    return __wstr;
77136ac495dSmrg 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
77236ac495dSmrg 	      "Cannot convert character sequence",
77336ac495dSmrg 	      std::make_error_code(errc::illegal_byte_sequence)));
77436ac495dSmrg       }
77536ac495dSmrg 
77636ac495dSmrg       static string_type
777*8feb0f0bSmrg       _S_wconvert(const _CharT* __f, const _CharT* __l, const void*)
778c0a68be4Smrg       {
779c0a68be4Smrg 	struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
780c0a68be4Smrg 	{ } __cvt;
78136ac495dSmrg 	std::string __str;
782c0a68be4Smrg 	if (__str_codecvt_out_all(__f, __l, __str, __cvt))
78336ac495dSmrg 	  {
78436ac495dSmrg 	    const char* __f2 = __str.data();
78536ac495dSmrg 	    const char* __l2 = __f2 + __str.size();
786c0a68be4Smrg 	    std::codecvt_utf8_utf16<wchar_t> __wcvt;
78736ac495dSmrg 	    std::wstring __wstr;
788c0a68be4Smrg 	    if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
78936ac495dSmrg 	      return __wstr;
79036ac495dSmrg 	  }
79136ac495dSmrg 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
79236ac495dSmrg 	      "Cannot convert character sequence",
79336ac495dSmrg 	      std::make_error_code(errc::illegal_byte_sequence)));
79436ac495dSmrg       }
79536ac495dSmrg 
79636ac495dSmrg       static string_type
79736ac495dSmrg       _S_convert(const _CharT* __f, const _CharT* __l)
79836ac495dSmrg       {
799*8feb0f0bSmrg 	return _S_wconvert(__f, __l, (const _CharT*)nullptr);
80036ac495dSmrg       }
80136ac495dSmrg #else
80236ac495dSmrg       static string_type
80336ac495dSmrg       _S_convert(const _CharT* __f, const _CharT* __l)
80436ac495dSmrg       {
805c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
806c0a68be4Smrg 	if constexpr (is_same<_CharT, char8_t>::value)
807c0a68be4Smrg 	  return string_type(__f, __l);
808c0a68be4Smrg 	else
809c0a68be4Smrg #endif
810*8feb0f0bSmrg 	  {
811c0a68be4Smrg 	    struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
812c0a68be4Smrg 	    { } __cvt;
81336ac495dSmrg 	    std::string __str;
814c0a68be4Smrg 	    if (__str_codecvt_out_all(__f, __l, __str, __cvt))
81536ac495dSmrg 	      return __str;
81636ac495dSmrg 	    _GLIBCXX_THROW_OR_ABORT(filesystem_error(
81736ac495dSmrg 		  "Cannot convert character sequence",
81836ac495dSmrg 		  std::make_error_code(errc::illegal_byte_sequence)));
81936ac495dSmrg 	  }
820*8feb0f0bSmrg       }
82136ac495dSmrg #endif
82236ac495dSmrg 
82336ac495dSmrg       static string_type
82436ac495dSmrg       _S_convert(_CharT* __f, _CharT* __l)
82536ac495dSmrg       {
82636ac495dSmrg 	return _S_convert(const_cast<const _CharT*>(__f),
82736ac495dSmrg 			  const_cast<const _CharT*>(__l));
82836ac495dSmrg       }
82936ac495dSmrg 
83036ac495dSmrg       template<typename _Iter>
83136ac495dSmrg 	static string_type
83236ac495dSmrg 	_S_convert(_Iter __first, _Iter __last)
83336ac495dSmrg 	{
83436ac495dSmrg 	  const std::basic_string<_CharT> __str(__first, __last);
83536ac495dSmrg 	  return _S_convert(__str.data(), __str.data() + __str.size());
83636ac495dSmrg 	}
83736ac495dSmrg 
83836ac495dSmrg       template<typename _Iter, typename _Cont>
83936ac495dSmrg 	static string_type
84036ac495dSmrg 	_S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
84136ac495dSmrg 		  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
84236ac495dSmrg 	{ return _S_convert(__first.base(), __last.base()); }
84336ac495dSmrg     };
844*8feb0f0bSmrg   /// @endcond
84536ac495dSmrg 
84636ac495dSmrg   /// An iterator for the components of a path
84736ac495dSmrg   class path::iterator
84836ac495dSmrg   {
84936ac495dSmrg   public:
85036ac495dSmrg     using difference_type	= std::ptrdiff_t;
85136ac495dSmrg     using value_type		= path;
85236ac495dSmrg     using reference		= const path&;
85336ac495dSmrg     using pointer		= const path*;
85436ac495dSmrg     using iterator_category	= std::bidirectional_iterator_tag;
85536ac495dSmrg 
85636ac495dSmrg     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
85736ac495dSmrg 
85836ac495dSmrg     iterator(const iterator&) = default;
85936ac495dSmrg     iterator& operator=(const iterator&) = default;
86036ac495dSmrg 
86136ac495dSmrg     reference operator*() const;
86236ac495dSmrg     pointer   operator->() const { return std::__addressof(**this); }
86336ac495dSmrg 
86436ac495dSmrg     iterator& operator++();
86536ac495dSmrg     iterator  operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
86636ac495dSmrg 
86736ac495dSmrg     iterator& operator--();
86836ac495dSmrg     iterator  operator--(int) { auto __tmp = *this; --*this; return __tmp; }
86936ac495dSmrg 
87036ac495dSmrg     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
87136ac495dSmrg     { return __lhs._M_equals(__rhs); }
87236ac495dSmrg 
87336ac495dSmrg     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
87436ac495dSmrg     { return !__lhs._M_equals(__rhs); }
87536ac495dSmrg 
87636ac495dSmrg   private:
87736ac495dSmrg     friend class path;
87836ac495dSmrg 
87936ac495dSmrg     iterator(const path* __path, path::_List::const_iterator __iter)
88036ac495dSmrg     : _M_path(__path), _M_cur(__iter), _M_at_end()
88136ac495dSmrg     { }
88236ac495dSmrg 
88336ac495dSmrg     iterator(const path* __path, bool __at_end)
88436ac495dSmrg     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
88536ac495dSmrg     { }
88636ac495dSmrg 
88736ac495dSmrg     bool _M_equals(iterator) const;
88836ac495dSmrg 
88936ac495dSmrg     const path* 		_M_path;
89036ac495dSmrg     path::_List::const_iterator _M_cur;
89136ac495dSmrg     bool			_M_at_end;  // only used when type != _Multi
89236ac495dSmrg   };
89336ac495dSmrg 
89436ac495dSmrg 
89536ac495dSmrg   inline path&
89636ac495dSmrg   path::operator=(path&& __p) noexcept
89736ac495dSmrg   {
89836ac495dSmrg     _M_pathname = std::move(__p._M_pathname);
89936ac495dSmrg     _M_cmpts = std::move(__p._M_cmpts);
90036ac495dSmrg     _M_type = __p._M_type;
90136ac495dSmrg     __p.clear();
90236ac495dSmrg     return *this;
90336ac495dSmrg   }
90436ac495dSmrg 
90536ac495dSmrg   inline path&
90636ac495dSmrg   path::operator=(string_type&& __source)
90736ac495dSmrg   { return *this = path(std::move(__source)); }
90836ac495dSmrg 
90936ac495dSmrg   inline path&
91036ac495dSmrg   path::assign(string_type&& __source)
91136ac495dSmrg   { return *this = path(std::move(__source)); }
91236ac495dSmrg 
91336ac495dSmrg   inline path&
91436ac495dSmrg   path::operator+=(const path& __p)
91536ac495dSmrg   {
91636ac495dSmrg     return operator+=(__p.native());
91736ac495dSmrg   }
91836ac495dSmrg 
91936ac495dSmrg   inline path&
92036ac495dSmrg   path::operator+=(const string_type& __x)
92136ac495dSmrg   {
92236ac495dSmrg     _M_pathname += __x;
92336ac495dSmrg     _M_split_cmpts();
92436ac495dSmrg     return *this;
92536ac495dSmrg   }
92636ac495dSmrg 
92736ac495dSmrg   inline path&
92836ac495dSmrg   path::operator+=(const value_type* __x)
92936ac495dSmrg   {
93036ac495dSmrg     _M_pathname += __x;
93136ac495dSmrg     _M_split_cmpts();
93236ac495dSmrg     return *this;
93336ac495dSmrg   }
93436ac495dSmrg 
93536ac495dSmrg   inline path&
93636ac495dSmrg   path::operator+=(value_type __x)
93736ac495dSmrg   {
93836ac495dSmrg     _M_pathname += __x;
93936ac495dSmrg     _M_split_cmpts();
94036ac495dSmrg     return *this;
94136ac495dSmrg   }
94236ac495dSmrg 
94336ac495dSmrg #if __cplusplus >= 201402L
94436ac495dSmrg   inline path&
94536ac495dSmrg   path::operator+=(basic_string_view<value_type> __x)
94636ac495dSmrg   {
94736ac495dSmrg     _M_pathname.append(__x.data(), __x.size());
94836ac495dSmrg     _M_split_cmpts();
94936ac495dSmrg     return *this;
95036ac495dSmrg   }
95136ac495dSmrg #endif
95236ac495dSmrg 
95336ac495dSmrg   template<typename _CharT>
954*8feb0f0bSmrg     inline __detail::_Path<_CharT*, _CharT*>&
95536ac495dSmrg     path::operator+=(_CharT __x)
95636ac495dSmrg     {
95736ac495dSmrg       auto* __addr = std::__addressof(__x);
95836ac495dSmrg       return concat(__addr, __addr + 1);
95936ac495dSmrg     }
96036ac495dSmrg 
96136ac495dSmrg   inline path&
96236ac495dSmrg   path::make_preferred()
96336ac495dSmrg   {
96436ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
96536ac495dSmrg     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
96636ac495dSmrg 		 preferred_separator);
96736ac495dSmrg #endif
96836ac495dSmrg     return *this;
96936ac495dSmrg   }
97036ac495dSmrg 
97136ac495dSmrg   inline void path::swap(path& __rhs) noexcept
97236ac495dSmrg   {
97336ac495dSmrg     _M_pathname.swap(__rhs._M_pathname);
97436ac495dSmrg     _M_cmpts.swap(__rhs._M_cmpts);
97536ac495dSmrg     std::swap(_M_type, __rhs._M_type);
97636ac495dSmrg   }
97736ac495dSmrg 
97836ac495dSmrg   template<typename _CharT, typename _Traits, typename _Allocator>
97936ac495dSmrg     inline std::basic_string<_CharT, _Traits, _Allocator>
98036ac495dSmrg     path::string(const _Allocator& __a) const
98136ac495dSmrg     {
98236ac495dSmrg       if (is_same<_CharT, value_type>::value)
98336ac495dSmrg 	return { _M_pathname.begin(), _M_pathname.end(), __a };
98436ac495dSmrg 
985c0a68be4Smrg       using _WString = basic_string<_CharT, _Traits, _Allocator>;
986c0a68be4Smrg 
98736ac495dSmrg       const value_type* __first = _M_pathname.data();
98836ac495dSmrg       const value_type* __last = __first + _M_pathname.size();
98936ac495dSmrg 
99036ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
99136ac495dSmrg       using _CharAlloc = __alloc_rebind<_Allocator, char>;
99236ac495dSmrg       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
99336ac495dSmrg 
994c0a68be4Smrg       // First convert native string from UTF-16 to to UTF-8.
995c0a68be4Smrg       // XXX This assumes that the execution wide-character set is UTF-16.
996c0a68be4Smrg       codecvt_utf8_utf16<value_type> __cvt;
99736ac495dSmrg       _String __u8str{_CharAlloc{__a}};
998c0a68be4Smrg       if (__str_codecvt_out_all(__first, __last, __u8str, __cvt))
99936ac495dSmrg 	{
100036ac495dSmrg 	  struct
100136ac495dSmrg 	  {
100236ac495dSmrg 	    const _String*
100336ac495dSmrg 	    operator()(const _String& __from, _String&, true_type)
100436ac495dSmrg 	    { return std::__addressof(__from); }
100536ac495dSmrg 
100636ac495dSmrg 	    _WString*
100736ac495dSmrg 	    operator()(const _String& __from, _WString& __to, false_type)
100836ac495dSmrg 	    {
1009c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
1010c0a68be4Smrg 	      if constexpr (is_same<_CharT, char8_t>::value)
1011c0a68be4Smrg 	        {
1012c0a68be4Smrg 	          __to.assign(__from.begin(), __from.end());
1013c0a68be4Smrg 	          return std::__addressof(__to);
1014c0a68be4Smrg 	        }
1015c0a68be4Smrg 	      else
1016c0a68be4Smrg #endif
1017c0a68be4Smrg 	        {
1018c0a68be4Smrg 	          // Convert UTF-8 to wide string.
1019c0a68be4Smrg 	          struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
1020c0a68be4Smrg 		  { } __cvt;
102136ac495dSmrg 	          const char* __f = __from.data();
102236ac495dSmrg 	          const char* __l = __f + __from.size();
1023c0a68be4Smrg 	          if (__str_codecvt_in_all(__f, __l, __to, __cvt))
102436ac495dSmrg 		    return std::__addressof(__to);
1025c0a68be4Smrg 	        }
102636ac495dSmrg 	      return nullptr;
102736ac495dSmrg 	    }
102836ac495dSmrg 	  } __dispatch;
1029c0a68be4Smrg 	  _WString __wstr(__a);
103036ac495dSmrg 	  if (auto* __p = __dispatch(__u8str, __wstr, is_same<_CharT, char>{}))
103136ac495dSmrg 	    return *__p;
103236ac495dSmrg 	}
103336ac495dSmrg #else
1034c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
1035c0a68be4Smrg       if constexpr (is_same<_CharT, char8_t>::value)
1036c0a68be4Smrg           return _WString(__first, __last, __a);
1037c0a68be4Smrg       else
1038c0a68be4Smrg #endif
1039c0a68be4Smrg         {
1040c0a68be4Smrg           struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
1041c0a68be4Smrg           _WString __wstr(__a);
1042c0a68be4Smrg           if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
104336ac495dSmrg 	    return __wstr;
1044c0a68be4Smrg         }
104536ac495dSmrg #endif
104636ac495dSmrg       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
104736ac495dSmrg 	    "Cannot convert character sequence",
104836ac495dSmrg 	    std::make_error_code(errc::illegal_byte_sequence)));
104936ac495dSmrg     }
105036ac495dSmrg 
105136ac495dSmrg   inline std::string
105236ac495dSmrg   path::string() const { return string<char>(); }
105336ac495dSmrg 
105436ac495dSmrg #if _GLIBCXX_USE_WCHAR_T
105536ac495dSmrg   inline std::wstring
105636ac495dSmrg   path::wstring() const { return string<wchar_t>(); }
105736ac495dSmrg #endif
105836ac495dSmrg 
1059c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
1060c0a68be4Smrg   inline std::u8string
1061c0a68be4Smrg   path::u8string() const { return string<char8_t>(); }
1062c0a68be4Smrg #else
106336ac495dSmrg   inline std::string
106436ac495dSmrg   path::u8string() const
106536ac495dSmrg   {
106636ac495dSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
106736ac495dSmrg     std::string __str;
1068c0a68be4Smrg     // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1069c0a68be4Smrg     std::codecvt_utf8_utf16<value_type> __cvt;
107036ac495dSmrg     const value_type* __first = _M_pathname.data();
107136ac495dSmrg     const value_type* __last = __first + _M_pathname.size();
1072c0a68be4Smrg     if (__str_codecvt_out_all(__first, __last, __str, __cvt))
107336ac495dSmrg       return __str;
107436ac495dSmrg     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
107536ac495dSmrg 	  "Cannot convert character sequence",
107636ac495dSmrg 	  std::make_error_code(errc::illegal_byte_sequence)));
107736ac495dSmrg #else
107836ac495dSmrg     return _M_pathname;
107936ac495dSmrg #endif
108036ac495dSmrg   }
1081c0a68be4Smrg #endif // _GLIBCXX_USE_CHAR8_T
108236ac495dSmrg 
108336ac495dSmrg   inline std::u16string
108436ac495dSmrg   path::u16string() const { return string<char16_t>(); }
108536ac495dSmrg 
108636ac495dSmrg   inline std::u32string
108736ac495dSmrg   path::u32string() const { return string<char32_t>(); }
108836ac495dSmrg 
108936ac495dSmrg   template<typename _CharT, typename _Traits, typename _Allocator>
109036ac495dSmrg     inline std::basic_string<_CharT, _Traits, _Allocator>
109136ac495dSmrg     path::generic_string(const _Allocator& __a) const
1092*8feb0f0bSmrg     {
1093*8feb0f0bSmrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1094*8feb0f0bSmrg       const _CharT __slash = is_same<_CharT, wchar_t>::value
1095*8feb0f0bSmrg 	? _CharT(L'/')
1096*8feb0f0bSmrg 	: _CharT('/'); // Assume value is correct for the encoding.
1097*8feb0f0bSmrg #else
1098*8feb0f0bSmrg       const _CharT __slash = _CharT('/');
1099*8feb0f0bSmrg #endif
1100*8feb0f0bSmrg       basic_string<_CharT, _Traits, _Allocator> __str(__a);
1101*8feb0f0bSmrg       __str.reserve(_M_pathname.size());
1102*8feb0f0bSmrg       bool __add_slash = false;
1103*8feb0f0bSmrg       for (auto& __elem : *this)
1104*8feb0f0bSmrg 	{
1105*8feb0f0bSmrg 	  if (__elem._M_type == _Type::_Root_dir)
1106*8feb0f0bSmrg 	    {
1107*8feb0f0bSmrg 	      __str += __slash;
1108*8feb0f0bSmrg 	      continue;
1109*8feb0f0bSmrg 	    }
1110*8feb0f0bSmrg 	  if (__add_slash)
1111*8feb0f0bSmrg 	    __str += __slash;
1112*8feb0f0bSmrg 	  __str += __elem.string<_CharT, _Traits, _Allocator>(__a);
1113*8feb0f0bSmrg 	  __add_slash = __elem._M_type == _Type::_Filename;
1114*8feb0f0bSmrg 	}
1115*8feb0f0bSmrg       return __str;
1116*8feb0f0bSmrg     }
111736ac495dSmrg 
111836ac495dSmrg   inline std::string
1119*8feb0f0bSmrg   path::generic_string() const { return generic_string<char>(); }
112036ac495dSmrg 
112136ac495dSmrg #if _GLIBCXX_USE_WCHAR_T
112236ac495dSmrg   inline std::wstring
1123*8feb0f0bSmrg   path::generic_wstring() const { return generic_string<wchar_t>(); }
112436ac495dSmrg #endif
112536ac495dSmrg 
1126c0a68be4Smrg #ifdef _GLIBCXX_USE_CHAR8_T
1127c0a68be4Smrg   inline std::u8string
1128*8feb0f0bSmrg   path::generic_u8string() const { return generic_string<char8_t>(); }
1129c0a68be4Smrg #else
113036ac495dSmrg   inline std::string
1131*8feb0f0bSmrg   path::generic_u8string() const { return generic_string<char>(); }
1132c0a68be4Smrg #endif
113336ac495dSmrg 
113436ac495dSmrg   inline std::u16string
1135*8feb0f0bSmrg   path::generic_u16string() const { return generic_string<char16_t>(); }
113636ac495dSmrg 
113736ac495dSmrg   inline std::u32string
1138*8feb0f0bSmrg   path::generic_u32string() const { return generic_string<char32_t>(); }
113936ac495dSmrg 
114036ac495dSmrg   inline int
114136ac495dSmrg   path::compare(const string_type& __s) const { return compare(path(__s)); }
114236ac495dSmrg 
114336ac495dSmrg   inline int
114436ac495dSmrg   path::compare(const value_type* __s) const { return compare(path(__s)); }
114536ac495dSmrg 
114636ac495dSmrg #if __cplusplus >= 201402L
114736ac495dSmrg   inline int
114836ac495dSmrg   path::compare(basic_string_view<value_type> __s) const
114936ac495dSmrg   { return compare(path(__s)); }
115036ac495dSmrg #endif
115136ac495dSmrg 
115236ac495dSmrg   inline path
115336ac495dSmrg   path::filename() const { return empty() ? path() : *--end(); }
115436ac495dSmrg 
115536ac495dSmrg   inline path
115636ac495dSmrg   path::stem() const
115736ac495dSmrg   {
115836ac495dSmrg     auto ext = _M_find_extension();
115936ac495dSmrg     if (ext.first && ext.second != 0)
116036ac495dSmrg       return path{ext.first->substr(0, ext.second)};
116136ac495dSmrg     return {};
116236ac495dSmrg   }
116336ac495dSmrg 
116436ac495dSmrg   inline path
116536ac495dSmrg   path::extension() const
116636ac495dSmrg   {
116736ac495dSmrg     auto ext = _M_find_extension();
116836ac495dSmrg     if (ext.first && ext.second != string_type::npos)
116936ac495dSmrg       return path{ext.first->substr(ext.second)};
117036ac495dSmrg     return {};
117136ac495dSmrg   }
117236ac495dSmrg 
117336ac495dSmrg   inline bool
117436ac495dSmrg   path::has_stem() const
117536ac495dSmrg   {
117636ac495dSmrg     auto ext = _M_find_extension();
117736ac495dSmrg     return ext.first && ext.second != 0;
117836ac495dSmrg   }
117936ac495dSmrg 
118036ac495dSmrg   inline bool
118136ac495dSmrg   path::has_extension() const
118236ac495dSmrg   {
118336ac495dSmrg     auto ext = _M_find_extension();
118436ac495dSmrg     return ext.first && ext.second != string_type::npos;
118536ac495dSmrg   }
118636ac495dSmrg 
1187c0a68be4Smrg   inline bool
1188c0a68be4Smrg   path::is_absolute() const
1189c0a68be4Smrg   {
1190c0a68be4Smrg #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1191c0a68be4Smrg     return has_root_name() && has_root_directory();
1192c0a68be4Smrg #else
1193c0a68be4Smrg     return has_root_directory();
1194c0a68be4Smrg #endif
1195c0a68be4Smrg   }
1196c0a68be4Smrg 
119736ac495dSmrg   inline path::iterator
119836ac495dSmrg   path::begin() const
119936ac495dSmrg   {
120036ac495dSmrg     if (_M_type == _Type::_Multi)
120136ac495dSmrg       return iterator(this, _M_cmpts.begin());
120236ac495dSmrg     return iterator(this, false);
120336ac495dSmrg   }
120436ac495dSmrg 
120536ac495dSmrg   inline path::iterator
120636ac495dSmrg   path::end() const
120736ac495dSmrg   {
120836ac495dSmrg     if (_M_type == _Type::_Multi)
120936ac495dSmrg       return iterator(this, _M_cmpts.end());
121036ac495dSmrg     return iterator(this, true);
121136ac495dSmrg   }
121236ac495dSmrg 
121336ac495dSmrg   inline path::iterator&
121436ac495dSmrg   path::iterator::operator++()
121536ac495dSmrg   {
121636ac495dSmrg     __glibcxx_assert(_M_path != nullptr);
121736ac495dSmrg     if (_M_path->_M_type == _Type::_Multi)
121836ac495dSmrg       {
121936ac495dSmrg 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
122036ac495dSmrg 	++_M_cur;
122136ac495dSmrg       }
122236ac495dSmrg     else
122336ac495dSmrg       {
122436ac495dSmrg 	__glibcxx_assert(!_M_at_end);
122536ac495dSmrg 	_M_at_end = true;
122636ac495dSmrg       }
122736ac495dSmrg     return *this;
122836ac495dSmrg   }
122936ac495dSmrg 
123036ac495dSmrg   inline path::iterator&
123136ac495dSmrg   path::iterator::operator--()
123236ac495dSmrg   {
123336ac495dSmrg     __glibcxx_assert(_M_path != nullptr);
123436ac495dSmrg     if (_M_path->_M_type == _Type::_Multi)
123536ac495dSmrg       {
123636ac495dSmrg 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
123736ac495dSmrg 	--_M_cur;
123836ac495dSmrg       }
123936ac495dSmrg     else
124036ac495dSmrg       {
124136ac495dSmrg 	__glibcxx_assert(_M_at_end);
124236ac495dSmrg 	_M_at_end = false;
124336ac495dSmrg       }
124436ac495dSmrg     return *this;
124536ac495dSmrg   }
124636ac495dSmrg 
124736ac495dSmrg   inline path::iterator::reference
124836ac495dSmrg   path::iterator::operator*() const
124936ac495dSmrg   {
125036ac495dSmrg     __glibcxx_assert(_M_path != nullptr);
125136ac495dSmrg     if (_M_path->_M_type == _Type::_Multi)
125236ac495dSmrg       {
125336ac495dSmrg 	__glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
125436ac495dSmrg 	return *_M_cur;
125536ac495dSmrg       }
125636ac495dSmrg     return *_M_path;
125736ac495dSmrg   }
125836ac495dSmrg 
125936ac495dSmrg   inline bool
126036ac495dSmrg   path::iterator::_M_equals(iterator __rhs) const
126136ac495dSmrg   {
126236ac495dSmrg     if (_M_path != __rhs._M_path)
126336ac495dSmrg       return false;
126436ac495dSmrg     if (_M_path == nullptr)
126536ac495dSmrg       return true;
126636ac495dSmrg     if (_M_path->_M_type == path::_Type::_Multi)
126736ac495dSmrg       return _M_cur == __rhs._M_cur;
126836ac495dSmrg     return _M_at_end == __rhs._M_at_end;
126936ac495dSmrg   }
127036ac495dSmrg 
1271*8feb0f0bSmrg   /// @} group filesystem-ts
127236ac495dSmrg _GLIBCXX_END_NAMESPACE_CXX11
127336ac495dSmrg } // namespace v1
127436ac495dSmrg } // namespace filesystem
127536ac495dSmrg } // namespace experimental
1276a2dc1f3fSmrg 
1277a2dc1f3fSmrg _GLIBCXX_END_NAMESPACE_VERSION
127836ac495dSmrg } // namespace std
127936ac495dSmrg 
128036ac495dSmrg #endif // C++11
128136ac495dSmrg 
128236ac495dSmrg #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H
1283