mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1017 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1017 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C++
		
	
	
	
| // Class filesystem::path -*- C++ -*-
 | |
| 
 | |
| // Copyright (C) 2014-2015 Free Software Foundation, Inc.
 | |
| //
 | |
| // This file is part of the GNU ISO C++ Library.  This library is free
 | |
| // software; you can redistribute it and/or modify it under the
 | |
| // terms of the GNU General Public License as published by the
 | |
| // Free Software Foundation; either version 3, or (at your option)
 | |
| // any later version.
 | |
| 
 | |
| // This library is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| // GNU General Public License for more details.
 | |
| 
 | |
| // Under Section 7 of GPL version 3, you are granted additional
 | |
| // permissions described in the GCC Runtime Library Exception, version
 | |
| // 3.1, as published by the Free Software Foundation.
 | |
| 
 | |
| // You should have received a copy of the GNU General Public License and
 | |
| // a copy of the GCC Runtime Library Exception along with this program;
 | |
| // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | |
| // <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| /** @file experimental/fs_path.h
 | |
|  *  This is an internal header file, included by other library headers.
 | |
|  *  Do not attempt to use it directly. @headername{experimental/filesystem}
 | |
|  */
 | |
| 
 | |
| #ifndef _GLIBCXX_EXPERIMENTAL_FS_PATH_H
 | |
| #define _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1
 | |
| 
 | |
| #if __cplusplus < 201103L
 | |
| # include <bits/c++0x_warning.h>
 | |
| #else
 | |
| 
 | |
| #include <utility>
 | |
| #include <type_traits>
 | |
| #include <vector>
 | |
| #include <locale>
 | |
| #include <iosfwd>
 | |
| #include <codecvt>
 | |
| #include <system_error>
 | |
| #include <bits/stl_algobase.h>
 | |
| #include <bits/quoted_string.h>
 | |
| #include <bits/locale_conv.h>
 | |
| 
 | |
| #if defined(_WIN32) && !defined(__CYGWIN__)
 | |
| # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
 | |
| # include <algorithm>
 | |
| #endif
 | |
| 
 | |
| namespace std _GLIBCXX_VISIBILITY(default)
 | |
| {
 | |
| namespace experimental
 | |
| {
 | |
| namespace filesystem
 | |
| {
 | |
| inline namespace v1
 | |
| {
 | |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION
 | |
| _GLIBCXX_BEGIN_NAMESPACE_CXX11
 | |
| 
 | |
|   /**
 | |
|    * @ingroup filesystem
 | |
|    * @{
 | |
|    */
 | |
| 
 | |
|   /// A filesystem path.
 | |
|   class path
 | |
|   {
 | |
|     template<typename _CharT>
 | |
|       struct __is_encoded_char : std::false_type { };
 | |
| 
 | |
|     template<typename _Iter,
 | |
| 	     typename _Iter_traits = std::iterator_traits<_Iter>>
 | |
|       using __is_path_iter_src
 | |
| 	= __and_<__is_encoded_char<typename _Iter_traits::value_type>,
 | |
| 		 std::is_base_of<std::input_iterator_tag,
 | |
| 				 typename _Iter_traits::iterator_category>>;
 | |
| 
 | |
|     template<typename _Iter>
 | |
|       static __is_path_iter_src<_Iter>
 | |
|       __is_path_src(_Iter, int);
 | |
| 
 | |
|     template<typename _CharT, typename _Traits, typename _Alloc>
 | |
|       static __is_encoded_char<_CharT>
 | |
|       __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
 | |
| 
 | |
|     template<typename _Unknown>
 | |
|       static std::false_type
 | |
|       __is_path_src(const _Unknown&, ...);
 | |
| 
 | |
|     template<typename _Tp1, typename _Tp2>
 | |
|       struct __constructible_from;
 | |
| 
 | |
|     template<typename _Iter>
 | |
|       struct __constructible_from<_Iter, _Iter>
 | |
|       : __is_path_iter_src<_Iter>
 | |
|       { };
 | |
| 
 | |
|     template<typename _Source>
 | |
|       struct __constructible_from<_Source, void>
 | |
|       : decltype(__is_path_src(std::declval<_Source>(), 0))
 | |
|       { };
 | |
| 
 | |
|     template<typename _Tp1, typename _Tp2 = void>
 | |
|       using _Path = typename
 | |
| 	std::enable_if<__and_<__not_<is_same<_Tp1, path>>,
 | |
| 			      __constructible_from<_Tp1, _Tp2>>::value,
 | |
| 		       path>::type;
 | |
| 
 | |
|     template<typename _Source>
 | |
|       static _Source
 | |
|       _S_range_begin(_Source __begin) { return __begin; }
 | |
| 
 | |
|     struct __null_terminated { };
 | |
| 
 | |
|     template<typename _Source>
 | |
|       static __null_terminated
 | |
|       _S_range_end(_Source) { return {}; }
 | |
| 
 | |
|     template<typename _CharT, typename _Traits, typename _Alloc>
 | |
|       static const _CharT*
 | |
|       _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
 | |
|       { return __str.data(); }
 | |
| 
 | |
|     template<typename _CharT, typename _Traits, typename _Alloc>
 | |
|       static const _CharT*
 | |
|       _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
 | |
|       { return __str.data() + __str.size(); }
 | |
| 
 | |
|     template<typename _Tp,
 | |
| 	     typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
 | |
| 	     typename _Val = typename std::iterator_traits<_Iter>::value_type>
 | |
|       using __value_type_is_char
 | |
| 	= typename std::enable_if<std::is_same<_Val, char>::value>::type;
 | |
| 
 | |
|   public:
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|     typedef wchar_t				value_type;
 | |
|     static constexpr value_type			preferred_separator = L'\\';
 | |
| #else
 | |
|     typedef char				value_type;
 | |
|     static constexpr value_type			preferred_separator = '/';
 | |
| #endif
 | |
|     typedef std::basic_string<value_type>	string_type;
 | |
| 
 | |
|     // constructors and destructor
 | |
| 
 | |
|     path() noexcept { }
 | |
| 
 | |
|     path(const path& __p) = default;
 | |
| 
 | |
|     path(path&& __p) noexcept
 | |
|     : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
 | |
|     {
 | |
|       _M_split_cmpts();
 | |
|       __p.clear();
 | |
|     }
 | |
| 
 | |
|     template<typename _Source,
 | |
| 	     typename _Require = _Path<_Source>>
 | |
|       path(_Source const& __source)
 | |
|       : _M_pathname(_S_convert(_S_range_begin(__source),
 | |
| 			       _S_range_end(__source)))
 | |
|       { _M_split_cmpts(); }
 | |
| 
 | |
|     template<typename _InputIterator,
 | |
| 	     typename _Require = _Path<_InputIterator, _InputIterator>>
 | |
|       path(_InputIterator __first, _InputIterator __last)
 | |
|       : _M_pathname(_S_convert(__first, __last))
 | |
|       { _M_split_cmpts(); }
 | |
| 
 | |
|     template<typename _Source,
 | |
| 	     typename _Require = _Path<_Source>,
 | |
| 	     typename _Require2 = __value_type_is_char<_Source>>
 | |
|       path(_Source const& __source, const locale& __loc)
 | |
|       : _M_pathname(_S_convert_loc(_S_range_begin(__source),
 | |
| 				   _S_range_end(__source), __loc))
 | |
|       { _M_split_cmpts(); }
 | |
| 
 | |
|     template<typename _InputIterator,
 | |
| 	     typename _Require = _Path<_InputIterator, _InputIterator>,
 | |
| 	     typename _Require2 = __value_type_is_char<_InputIterator>>
 | |
|       path(_InputIterator __first, _InputIterator __last, const locale& __loc)
 | |
|       : _M_pathname(_S_convert_loc(__first, __last, __loc))
 | |
|       { _M_split_cmpts(); }
 | |
| 
 | |
|     ~path() = default;
 | |
| 
 | |
|     // assignments
 | |
| 
 | |
|     path& operator=(const path& __p) = default;
 | |
|     path& operator=(path&& __p) noexcept;
 | |
| 
 | |
|     template<typename _Source>
 | |
|       _Path<_Source>&
 | |
|       operator=(_Source const& __source)
 | |
|       { return *this = path(__source); }
 | |
| 
 | |
|     template<typename _Source>
 | |
|       _Path<_Source>&
 | |
|       assign(_Source const& __source)
 | |
|       { return *this = path(__source); }
 | |
| 
 | |
|     template<typename _InputIterator>
 | |
|       _Path<_InputIterator, _InputIterator>&
 | |
|       assign(_InputIterator __first, _InputIterator __last)
 | |
|       { return *this = path(__first, __last); }
 | |
| 
 | |
|     // appends
 | |
| 
 | |
|     path& operator/=(const path& __p) { return _M_append(__p._M_pathname); }
 | |
| 
 | |
|     template <class _Source>
 | |
|       _Path<_Source>&
 | |
|       operator/=(_Source const& __source)
 | |
|       { return append(__source); }
 | |
| 
 | |
|     template<typename _Source>
 | |
|       _Path<_Source>&
 | |
|       append(_Source const& __source)
 | |
|       {
 | |
| 	return _M_append(_S_convert(_S_range_begin(__source),
 | |
| 				    _S_range_end(__source)));
 | |
|       }
 | |
| 
 | |
|     template<typename _InputIterator>
 | |
|       _Path<_InputIterator, _InputIterator>&
 | |
|       append(_InputIterator __first, _InputIterator __last)
 | |
|       { return _M_append(_S_convert(__first, __last)); }
 | |
| 
 | |
|     // concatenation
 | |
| 
 | |
|     path& operator+=(const path& __x);
 | |
|     path& operator+=(const string_type& __x);
 | |
|     path& operator+=(const value_type* __x);
 | |
|     path& operator+=(value_type __x);
 | |
| 
 | |
|     template<typename _Source>
 | |
|       _Path<_Source>&
 | |
|       operator+=(_Source const& __x) { return concat(__x); }
 | |
| 
 | |
|     template<typename _CharT>
 | |
|       _Path<_CharT*, _CharT*>&
 | |
|       operator+=(_CharT __x);
 | |
| 
 | |
|     template<typename _Source>
 | |
|       _Path<_Source>&
 | |
|       concat(_Source const& __x)
 | |
|       { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
 | |
| 
 | |
|     template<typename _InputIterator>
 | |
|       _Path<_InputIterator, _InputIterator>&
 | |
|       concat(_InputIterator __first, _InputIterator __last)
 | |
|       { return *this += _S_convert(__first, __last); }
 | |
| 
 | |
|     // modifiers
 | |
| 
 | |
|     void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
 | |
| 
 | |
|     path& make_preferred();
 | |
|     path& remove_filename();
 | |
|     path& replace_filename(const path& __replacement);
 | |
|     path& replace_extension(const path& __replacement = path());
 | |
| 
 | |
|     void swap(path& __rhs) noexcept;
 | |
| 
 | |
|     // native format observers
 | |
| 
 | |
|     const string_type&  native() const noexcept { return _M_pathname; }
 | |
|     const value_type*   c_str() const noexcept { return _M_pathname.c_str(); }
 | |
|     operator string_type() const { return _M_pathname; }
 | |
| 
 | |
|     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
 | |
| 	     typename _Allocator = std::allocator<_CharT>>
 | |
|       std::basic_string<_CharT, _Traits, _Allocator>
 | |
|       string(const _Allocator& __a = _Allocator()) const;
 | |
| 
 | |
|     std::string    string() const;
 | |
|     std::wstring   wstring() const;
 | |
|     std::string    u8string() const;
 | |
|     std::u16string u16string() const;
 | |
|     std::u32string u32string() const;
 | |
| 
 | |
|     // generic format observers
 | |
|     template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
 | |
| 	     typename _Allocator = std::allocator<_CharT>>
 | |
|       std::basic_string<_CharT, _Traits, _Allocator>
 | |
|       generic_string(const _Allocator& __a = _Allocator()) const;
 | |
| 
 | |
|     std::string    generic_string() const;
 | |
|     std::wstring   generic_wstring() const;
 | |
|     std::string    generic_u8string() const;
 | |
|     std::u16string generic_u16string() const;
 | |
|     std::u32string generic_u32string() const;
 | |
| 
 | |
|     // compare
 | |
| 
 | |
|     int compare(const path& __p) const noexcept;
 | |
|     int compare(const string_type& __s) const;
 | |
|     int compare(const value_type* __s) const;
 | |
| 
 | |
|     // decomposition
 | |
| 
 | |
|     path root_name() const;
 | |
|     path root_directory() const;
 | |
|     path root_path() const;
 | |
|     path relative_path() const;
 | |
|     path parent_path() const;
 | |
|     path filename() const;
 | |
|     path stem() const;
 | |
|     path extension() const;
 | |
| 
 | |
|     // query
 | |
| 
 | |
|     bool empty() const noexcept { return _M_pathname.empty(); }
 | |
|     bool has_root_name() const;
 | |
|     bool has_root_directory() const;
 | |
|     bool has_root_path() const;
 | |
|     bool has_relative_path() const;
 | |
|     bool has_parent_path() const;
 | |
|     bool has_filename() const;
 | |
|     bool has_stem() const;
 | |
|     bool has_extension() const;
 | |
|     bool is_absolute() const;
 | |
|     bool is_relative() const { return !is_absolute(); }
 | |
| 
 | |
|     // iterators
 | |
|     class iterator;
 | |
|     typedef iterator const_iterator;
 | |
| 
 | |
|     iterator begin() const;
 | |
|     iterator end() const;
 | |
| 
 | |
|   private:
 | |
|     enum class _Type : unsigned char {
 | |
| 	_Multi, _Root_name, _Root_dir, _Filename
 | |
|     };
 | |
| 
 | |
|     path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
 | |
|     {
 | |
|       _GLIBCXX_DEBUG_ASSERT(!empty());
 | |
|       _GLIBCXX_DEBUG_ASSERT(_M_type != _Type::_Multi);
 | |
|     }
 | |
| 
 | |
|     enum class _Split { _Stem, _Extension };
 | |
| 
 | |
|     path& _M_append(const string_type& __str)
 | |
|     {
 | |
|       if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
 | |
| 	  && !__str.empty() && !_S_is_dir_sep(__str.front()))
 | |
| 	_M_pathname += preferred_separator;
 | |
|       _M_pathname += __str;
 | |
|       _M_split_cmpts();
 | |
|       return *this;
 | |
|     }
 | |
| 
 | |
|     pair<const string_type*, size_t> _M_find_extension() const;
 | |
| 
 | |
|     template<typename _CharT>
 | |
|       struct _Cvt;
 | |
| 
 | |
|     static string_type
 | |
|     _S_convert(value_type* __src, __null_terminated)
 | |
|     { return string_type(__src); }
 | |
| 
 | |
|     static string_type
 | |
|     _S_convert(const value_type* __src, __null_terminated)
 | |
|     { return string_type(__src); }
 | |
| 
 | |
|     template<typename _Iter>
 | |
|       static string_type
 | |
|       _S_convert(_Iter __first, _Iter __last)
 | |
|       {
 | |
| 	using __value_type = typename std::iterator_traits<_Iter>::value_type;
 | |
| 	return _Cvt<__value_type>::_S_convert(__first, __last);
 | |
|       }
 | |
| 
 | |
|     template<typename _InputIterator>
 | |
|       static string_type
 | |
|       _S_convert(_InputIterator __src, __null_terminated)
 | |
|       {
 | |
| 	using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
 | |
| 	std::basic_string<_Tp> __tmp;
 | |
| 	while (*__src != _Tp{})
 | |
| 	  __tmp.push_back(*__src++);
 | |
| 	return _S_convert(__tmp.data(), __tmp.data() + __tmp.size());
 | |
|       }
 | |
| 
 | |
|     static string_type
 | |
|     _S_convert_loc(const char* __first, const char* __last,
 | |
| 		   const std::locale& __loc);
 | |
| 
 | |
|     template<typename _Iter>
 | |
|       static string_type
 | |
|       _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
 | |
|       {
 | |
| 	const std::string __str(__first, __last);
 | |
| 	return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
 | |
|       }
 | |
| 
 | |
|     template<typename _InputIterator>
 | |
|       static string_type
 | |
|       _S_convert_loc(_InputIterator __src, __null_terminated,
 | |
| 		     const std::locale& __loc)
 | |
|       {
 | |
| 	std::string __tmp;
 | |
| 	while (*__src != '\0')
 | |
| 	  __tmp.push_back(*__src++);
 | |
| 	return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
 | |
|       }
 | |
| 
 | |
|     bool _S_is_dir_sep(value_type __ch)
 | |
|     {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|       return __ch == L'/' || __ch == preferred_separator;
 | |
| #else
 | |
|       return __ch == '/';
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     void _M_split_cmpts();
 | |
|     void _M_trim();
 | |
|     void _M_add_root_name(size_t __n);
 | |
|     void _M_add_root_dir(size_t __pos);
 | |
|     void _M_add_filename(size_t __pos, size_t __n);
 | |
| 
 | |
|     string_type _M_pathname;
 | |
| 
 | |
|     struct _Cmpt;
 | |
|     using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
 | |
|     _List _M_cmpts; // empty unless _M_type == _Type::_Multi
 | |
|     _Type _M_type = _Type::_Multi;
 | |
|   };
 | |
| 
 | |
|   inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
 | |
| 
 | |
|   size_t hash_value(const path& __p) noexcept;
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator<(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return __lhs.compare(__rhs) < 0; }
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return !(__rhs < __lhs); }
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator>(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return __rhs < __lhs; }
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return !(__lhs < __rhs); }
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator==(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return __lhs.compare(__rhs) == 0; }
 | |
| 
 | |
|   /// Compare paths
 | |
|   inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
 | |
|   { return !(__lhs == __rhs); }
 | |
| 
 | |
|   /// Append one path to another
 | |
|   inline path operator/(const path& __lhs, const path& __rhs)
 | |
|   { return path(__lhs) /= __rhs; }
 | |
| 
 | |
|   /// Write a path to a stream
 | |
|   template<typename _CharT, typename _Traits>
 | |
|     basic_ostream<_CharT, _Traits>&
 | |
|     operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
 | |
|     {
 | |
|       auto __tmp = __p.string<_CharT, _Traits>();
 | |
|       using __quoted_string
 | |
| 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
 | |
|       __os << __quoted_string{__tmp, '"', '\\'};
 | |
|       return __os;
 | |
|     }
 | |
| 
 | |
|   /// Read a path from a stream
 | |
|   template<typename _CharT, typename _Traits>
 | |
|     basic_istream<_CharT, _Traits>&
 | |
|     operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
 | |
|     {
 | |
|       basic_string<_CharT, _Traits> __tmp;
 | |
|       using __quoted_string
 | |
| 	= std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
 | |
|       if (__is >> __quoted_string{ __tmp, '"', '\\' })
 | |
| 	__p = std::move(__tmp);
 | |
|       return __is;
 | |
|     }
 | |
| 
 | |
|   // TODO constrain with _Path<Source> and __value_type_is_char
 | |
|   template<typename _Source>
 | |
|     inline path
 | |
|     u8path(const _Source& __source)
 | |
|     {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|       return path{ path::string_type{__source} };
 | |
| #else
 | |
|       return path{ __source };
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|   // TODO constrain with _Path<InputIterator, InputIterator> and __value_type_is_char
 | |
|   template<typename _InputIterator>
 | |
|     inline path
 | |
|     u8path(_InputIterator __first, _InputIterator __last)
 | |
|     {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|       return path{ path::string_type{__first, __last} };
 | |
| #else
 | |
|       return path{ __first, __last };
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|   class filesystem_error : public std::system_error
 | |
|   {
 | |
|   public:
 | |
|     filesystem_error(const string& __what_arg, error_code __ec)
 | |
|     : system_error(__ec, __what_arg) { }
 | |
| 
 | |
|     filesystem_error(const string& __what_arg, const path& __p1,
 | |
| 		     error_code __ec)
 | |
|     : system_error(__ec, __what_arg), _M_path1(__p1) { }
 | |
| 
 | |
|     filesystem_error(const string& __what_arg, const path& __p1,
 | |
| 		     const path& __p2, error_code __ec)
 | |
|     : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
 | |
|     { }
 | |
| 
 | |
|     ~filesystem_error();
 | |
| 
 | |
|     const path& path1() const noexcept { return _M_path1; }
 | |
|     const path& path2() const noexcept { return _M_path2; }
 | |
|     const char* what() const noexcept { return _M_what.c_str(); }
 | |
| 
 | |
|   private:
 | |
|     std::string _M_gen_what();
 | |
| 
 | |
|     path _M_path1;
 | |
|     path _M_path2;
 | |
|     std::string _M_what = _M_gen_what();
 | |
|   };
 | |
| 
 | |
|   struct path::_Cmpt : path
 | |
|   {
 | |
|     _Cmpt(string_type __s, _Type __t, size_t __pos)
 | |
|       : path(std::move(__s), __t), _M_pos(__pos) { }
 | |
| 
 | |
|     _Cmpt() : _M_pos(-1) { }
 | |
| 
 | |
|     size_t _M_pos;
 | |
|   };
 | |
| 
 | |
|   template<>
 | |
|     struct path::__is_encoded_char<char> : std::true_type
 | |
|     { using value_type = char; };
 | |
| 
 | |
|   template<>
 | |
|     struct path::__is_encoded_char<wchar_t> : std::true_type
 | |
|     { using value_type = wchar_t; };
 | |
| 
 | |
|   template<>
 | |
|     struct path::__is_encoded_char<char16_t> : std::true_type
 | |
|     { using value_type = char16_t; };
 | |
| 
 | |
|   template<>
 | |
|     struct path::__is_encoded_char<char32_t> : std::true_type
 | |
|     { using value_type = char32_t; };
 | |
| 
 | |
|   // specialize _Cvt for degenerate 'noconv' case
 | |
|   template<>
 | |
|     struct path::_Cvt<path::value_type>
 | |
|     {
 | |
|       template<typename _Iter>
 | |
| 	static string_type
 | |
| 	_S_convert(_Iter __first, _Iter __last)
 | |
| 	{ return string_type{__first, __last}; }
 | |
|     };
 | |
| 
 | |
|   template<typename _CharT>
 | |
|     struct path::_Cvt
 | |
|     {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|       static string_type
 | |
|       _S_wconvert(const char* __f, const char* __l, true_type)
 | |
|       {
 | |
| 	using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
 | |
| 	const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
 | |
| 	std::wstring __wstr;
 | |
| 	if (__str_codecvt_in(__f, __l, __wstr, __cvt))
 | |
| 	    return __wstr;
 | |
| 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 | |
| 	      "Cannot convert character sequence",
 | |
| 	      std::make_error_code(errc::illegal_byte_sequence)));
 | |
|       }
 | |
| 
 | |
|       static string_type
 | |
|       _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
 | |
|       {
 | |
| 	std::codecvt_utf8<_CharT> __cvt;
 | |
| 	std::string __str;
 | |
| 	if (__str_codecvt_out(__f, __l, __str, __cvt))
 | |
| 	  {
 | |
| 	    const char* __f2 = __str.data();
 | |
| 	    const char* __l2 = __f2 + __str.size();
 | |
| 	    std::codecvt_utf8<wchar_t> __wcvt;
 | |
| 	    std::wstring __wstr;
 | |
| 	    if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
 | |
| 	      return __wstr;
 | |
| 	  }
 | |
| 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 | |
| 	      "Cannot convert character sequence",
 | |
| 	      std::make_error_code(errc::illegal_byte_sequence)));
 | |
|       }
 | |
| 
 | |
|       static string_type
 | |
|       _S_convert(const _CharT* __f, const _CharT* __l)
 | |
|       {
 | |
| 	return _S_wconvert(__f, __l, is_same<_CharT, char>{});
 | |
|       }
 | |
| #else
 | |
|       static string_type
 | |
|       _S_convert(const _CharT* __f, const _CharT* __l)
 | |
|       {
 | |
| 	std::codecvt_utf8<_CharT> __cvt;
 | |
| 	std::string __str;
 | |
| 	if (__str_codecvt_out(__f, __l, __str, __cvt))
 | |
| 	  return __str;
 | |
| 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 | |
| 	      "Cannot convert character sequence",
 | |
| 	      std::make_error_code(errc::illegal_byte_sequence)));
 | |
|       }
 | |
| #endif
 | |
| 
 | |
|       static string_type
 | |
|       _S_convert(_CharT* __f, _CharT* __l)
 | |
|       {
 | |
| 	return _S_convert(const_cast<const _CharT*>(__f),
 | |
| 			  const_cast<const _CharT*>(__l));
 | |
|       }
 | |
| 
 | |
|       template<typename _Iter>
 | |
| 	static string_type
 | |
| 	_S_convert(_Iter __first, _Iter __last)
 | |
| 	{
 | |
| 	  const std::basic_string<_CharT> __str(__first, __last);
 | |
| 	  return _S_convert(__str.data(), __str.data() + __str.size());
 | |
| 	}
 | |
| 
 | |
|       template<typename _Iter, typename _Cont>
 | |
| 	static string_type
 | |
| 	_S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
 | |
| 		  __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
 | |
| 	{ return _S_convert(__first.base(), __last.base()); }
 | |
|     };
 | |
| 
 | |
|   /// An iterator for the components of a path
 | |
|   class path::iterator
 | |
|   {
 | |
|   public:
 | |
|     using difference_type	= std::ptrdiff_t;
 | |
|     using value_type		= path;
 | |
|     using reference		= const path&;
 | |
|     using pointer		= const path*;
 | |
|     using iterator_category	= std::bidirectional_iterator_tag;
 | |
| 
 | |
|     iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
 | |
| 
 | |
|     iterator(const iterator&) = default;
 | |
|     iterator& operator=(const iterator&) = default;
 | |
| 
 | |
|     reference operator*() const;
 | |
|     pointer   operator->() const { return std::__addressof(**this); }
 | |
| 
 | |
|     iterator& operator++();
 | |
|     iterator  operator++(int) { auto __tmp = *this; ++_M_cur; return __tmp; }
 | |
| 
 | |
|     iterator& operator--();
 | |
|     iterator  operator--(int) { auto __tmp = *this; --_M_cur; return __tmp; }
 | |
| 
 | |
|     friend bool operator==(const iterator& __lhs, const iterator& __rhs)
 | |
|     { return __lhs._M_equals(__rhs); }
 | |
| 
 | |
|     friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
 | |
|     { return !__lhs._M_equals(__rhs); }
 | |
| 
 | |
|   private:
 | |
|     friend class path;
 | |
| 
 | |
|     iterator(const path* __path, path::_List::const_iterator __iter)
 | |
|     : _M_path(__path), _M_cur(__iter), _M_at_end()
 | |
|     { }
 | |
| 
 | |
|     iterator(const path* __path, bool __at_end)
 | |
|     : _M_path(__path), _M_cur(), _M_at_end(__at_end)
 | |
|     { }
 | |
| 
 | |
|     bool _M_equals(iterator) const;
 | |
| 
 | |
|     const path* 		_M_path;
 | |
|     path::_List::const_iterator _M_cur;
 | |
|     bool			_M_at_end;  // only used when type != _Multi
 | |
|   };
 | |
| 
 | |
| 
 | |
|   inline path&
 | |
|   path::operator=(path&& __p) noexcept
 | |
|   {
 | |
|     _M_pathname = std::move(__p._M_pathname);
 | |
|     _M_cmpts = std::move(__p._M_cmpts);
 | |
|     _M_type = __p._M_type;
 | |
|     __p.clear();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline path&
 | |
|   path::operator+=(const path& __p)
 | |
|   {
 | |
|     return operator+=(__p.native());
 | |
|   }
 | |
| 
 | |
|   inline path&
 | |
|   path::operator+=(const string_type& __x)
 | |
|   {
 | |
|     _M_pathname += __x;
 | |
|     _M_split_cmpts();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline path&
 | |
|   path::operator+=(const value_type* __x)
 | |
|   {
 | |
|     _M_pathname += __x;
 | |
|     _M_split_cmpts();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline path&
 | |
|   path::operator+=(value_type __x)
 | |
|   {
 | |
|     _M_pathname += __x;
 | |
|     _M_split_cmpts();
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   template<typename _CharT>
 | |
|     inline path::_Path<_CharT*, _CharT*>&
 | |
|     path::operator+=(_CharT __x)
 | |
|     {
 | |
|       auto* __addr = std::__addressof(__x);
 | |
|       return concat(__addr, __addr + 1);
 | |
|     }
 | |
| 
 | |
|   inline path&
 | |
|   path::make_preferred()
 | |
|   {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|     std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
 | |
| 		 preferred_separator);
 | |
| #endif
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline void path::swap(path& __rhs) noexcept
 | |
|   {
 | |
|     _M_pathname.swap(__rhs._M_pathname);
 | |
|     _M_cmpts.swap(__rhs._M_cmpts);
 | |
|     std::swap(_M_type, __rhs._M_type);
 | |
|   }
 | |
| 
 | |
|   template<typename _CharT, typename _Traits, typename _Allocator>
 | |
|     inline std::basic_string<_CharT, _Traits, _Allocator>
 | |
|     path::string(const _Allocator& __a) const
 | |
|     {
 | |
|       if (is_same<_CharT, value_type>::value)
 | |
| 	return { _M_pathname.begin(), _M_pathname.end(), __a };
 | |
| 
 | |
|       const value_type* __first = _M_pathname.data();
 | |
|       const value_type* __last = __first + _M_pathname.size();
 | |
| 
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|       using _CharAlloc = __alloc_rebind<_Allocator, char>;
 | |
|       using _String = basic_string<char, char_traits<char>, _CharAlloc>;
 | |
|       using _WString = basic_string<_CharT, _Traits, _Allocator>;
 | |
| 
 | |
|       // use codecvt_utf8<wchar_t> to convert native string to UTF-8
 | |
|       codecvt_utf8<value_type> __cvt;
 | |
|       _String __u8str{_CharAlloc{__a}};
 | |
|       if (__str_codecvt_out(__first, __last, __u8str, __cvt))
 | |
| 	{
 | |
| 	  struct
 | |
| 	  {
 | |
| 	    const _String*
 | |
| 	    operator()(const _String& __from, _String&, true_type)
 | |
| 	    { return std::__addressof(__from); }
 | |
| 
 | |
| 	    _WString*
 | |
| 	    operator()(const _String& __from, _WString& __to, false_type)
 | |
| 	    {
 | |
| 	      // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
 | |
| 	      codecvt_utf8<_CharT> __cvt;
 | |
| 	      const char* __f = __from.data();
 | |
| 	      const char* __l = __f + __from.size();
 | |
| 	      if (__str_codecvt_in(__f, __l, __to, __cvt))
 | |
| 		return std::__addressof(__to);
 | |
| 	      return nullptr;
 | |
| 	    }
 | |
| 	  } __dispatch;
 | |
| 	  _WString __wstr;
 | |
| 	  if (auto* __p = __dispatch(__u8str, __wstr, is_same<_CharT, char>{}))
 | |
| 	    return *__p;
 | |
| 	}
 | |
| #else
 | |
|       codecvt_utf8<_CharT> __cvt;
 | |
|       basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
 | |
|       if (__str_codecvt_in(__first, __last, __wstr, __cvt))
 | |
| 	return __wstr;
 | |
| #endif
 | |
|       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 | |
| 	    "Cannot convert character sequence",
 | |
| 	    std::make_error_code(errc::illegal_byte_sequence)));
 | |
|     }
 | |
| 
 | |
|   inline std::string
 | |
|   path::string() const { return string<char>(); }
 | |
| 
 | |
|   inline std::wstring
 | |
|   path::wstring() const { return string<wchar_t>(); }
 | |
| 
 | |
|   inline std::string
 | |
|   path::u8string() const
 | |
|   {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|     std::string __str;
 | |
|     // convert from native encoding to UTF-8
 | |
|     codecvt_utf8<value_type> __cvt;
 | |
|     const value_type* __first = _M_pathname.data();
 | |
|     const value_type* __last = __first + _M_pathname.size();
 | |
|     if (__str_codecvt_out(__first, __last, __str, __cvt))
 | |
|       return __str;
 | |
|     _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 | |
| 	  "Cannot convert character sequence",
 | |
| 	  std::make_error_code(errc::illegal_byte_sequence)));
 | |
| #else
 | |
|     return _M_pathname;
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   inline std::u16string
 | |
|   path::u16string() const { return string<char16_t>(); }
 | |
| 
 | |
|   inline std::u32string
 | |
|   path::u32string() const { return string<char32_t>(); }
 | |
| 
 | |
| #ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|   template<typename _CharT, typename _Traits, typename _Allocator>
 | |
|     inline std::basic_string<_CharT, _Traits, _Allocator>
 | |
|     path::generic_string(const _Allocator& __a) const
 | |
|     { return string<_CharT, _Traits, _Allocator>(__a); }
 | |
| 
 | |
|   inline std::string
 | |
|   path::generic_string() const { return string(); }
 | |
| 
 | |
|   inline std::wstring
 | |
|   path::generic_wstring() const { return wstring(); }
 | |
| 
 | |
|   inline std::string
 | |
|   path::generic_u8string() const { return u8string(); }
 | |
| 
 | |
|   inline std::u16string
 | |
|   path::generic_u16string() const { return u16string(); }
 | |
| 
 | |
|   inline std::u32string
 | |
|   path::generic_u32string() const { return u32string(); }
 | |
| #endif
 | |
| 
 | |
|   inline int
 | |
|   path::compare(const string_type& __s) const { return compare(path(__s)); }
 | |
| 
 | |
|   inline int
 | |
|   path::compare(const value_type* __s) const { return compare(path(__s)); }
 | |
| 
 | |
|   inline path
 | |
|   path::filename() const { return empty() ? path() : *--end(); }
 | |
| 
 | |
|   inline path
 | |
|   path::stem() const
 | |
|   {
 | |
|     auto ext = _M_find_extension();
 | |
|     if (ext.first && ext.second != 0)
 | |
|       return path{ext.first->substr(0, ext.second)};
 | |
|     return {};
 | |
|   }
 | |
| 
 | |
|   inline path
 | |
|   path::extension() const
 | |
|   {
 | |
|     auto ext = _M_find_extension();
 | |
|     if (ext.first && ext.second != string_type::npos)
 | |
|       return path{ext.first->substr(ext.second)};
 | |
|     return {};
 | |
|   }
 | |
| 
 | |
|   inline bool
 | |
|   path::has_stem() const
 | |
|   {
 | |
|     auto ext = _M_find_extension();
 | |
|     return ext.first && ext.second != 0;
 | |
|   }
 | |
| 
 | |
|   inline bool
 | |
|   path::has_extension() const
 | |
|   {
 | |
|     auto ext = _M_find_extension();
 | |
|     return ext.first && ext.second != string_type::npos;
 | |
|   }
 | |
| 
 | |
|   inline bool
 | |
|   path::is_absolute() const
 | |
|   {
 | |
| #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
 | |
|     return has_root_name();
 | |
| #else
 | |
|     return has_root_directory();
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   inline path::iterator
 | |
|   path::begin() const
 | |
|   {
 | |
|     if (_M_type == _Type::_Multi)
 | |
|       return iterator(this, _M_cmpts.begin());
 | |
|     return iterator(this, false);
 | |
|   }
 | |
| 
 | |
|   inline path::iterator
 | |
|   path::end() const
 | |
|   {
 | |
|     if (_M_type == _Type::_Multi)
 | |
|       return iterator(this, _M_cmpts.end());
 | |
|     return iterator(this, true);
 | |
|   }
 | |
| 
 | |
|   inline path::iterator&
 | |
|   path::iterator::operator++()
 | |
|   {
 | |
|     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
 | |
|     if (_M_path->_M_type == _Type::_Multi)
 | |
|       {
 | |
| 	_GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.end());
 | |
| 	++_M_cur;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	_GLIBCXX_DEBUG_ASSERT(!_M_at_end);
 | |
| 	_M_at_end = true;
 | |
|       }
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline path::iterator&
 | |
|   path::iterator::operator--()
 | |
|   {
 | |
|     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
 | |
|     if (_M_path->_M_type == _Type::_Multi)
 | |
|       {
 | |
| 	_GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.begin());
 | |
| 	--_M_cur;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	_GLIBCXX_DEBUG_ASSERT(_M_at_end);
 | |
| 	_M_at_end = false;
 | |
|       }
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   inline path::iterator::reference
 | |
|   path::iterator::operator*() const
 | |
|   {
 | |
|     _GLIBCXX_DEBUG_ASSERT(_M_path != nullptr);
 | |
|     if (_M_path->_M_type == _Type::_Multi)
 | |
|       {
 | |
| 	_GLIBCXX_DEBUG_ASSERT(_M_cur != _M_path->_M_cmpts.end());
 | |
| 	return *_M_cur;
 | |
|       }
 | |
|     return *_M_path;
 | |
|   }
 | |
| 
 | |
|   inline bool
 | |
|   path::iterator::_M_equals(iterator __rhs) const
 | |
|   {
 | |
|     if (_M_path != __rhs._M_path)
 | |
|       return false;
 | |
|     if (_M_path == nullptr)
 | |
|       return true;
 | |
|     if (_M_path->_M_type == path::_Type::_Multi)
 | |
|       return _M_cur == __rhs._M_cur;
 | |
|     return _M_at_end == __rhs._M_at_end;
 | |
|   }
 | |
| 
 | |
|   // @} group filesystem
 | |
| _GLIBCXX_END_NAMESPACE_CXX11
 | |
| _GLIBCXX_END_NAMESPACE_VERSION
 | |
| } // namespace v1
 | |
| } // namespace filesystem
 | |
| } // namespace experimental
 | |
| } // namespace std
 | |
| 
 | |
| #endif // C++11
 | |
| 
 | |
| #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H
 |