// Class filesystem::path -*- C++ -*-
// Copyright (C) 2014-2017 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
// .
/** @file experimental/bits/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
#else
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if __cplusplus == 201402L
# include
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
# include
#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
namespace experimental
{
namespace filesystem
{
inline namespace v1
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_BEGIN_NAMESPACE_CXX11
#if __cplusplus == 201402L
using std::experimental::basic_string_view;
#elif __cplusplus > 201402L
using std::basic_string_view;
#endif
/**
* @ingroup filesystem
* @{
*/
/// A filesystem path.
class path
{
template
struct __is_encoded_char : std::false_type { };
template>
using __is_path_iter_src
= __and_<__is_encoded_char,
std::is_base_of>;
template
static __is_path_iter_src<_Iter>
__is_path_src(_Iter, int);
template
static __is_encoded_char<_CharT>
__is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
#if __cplusplus >= 201402L
template
static __is_encoded_char<_CharT>
__is_path_src(const basic_string_view<_CharT, _Traits>&, int);
#endif
template
static std::false_type
__is_path_src(const _Unknown&, ...);
template
struct __constructible_from;
template
struct __constructible_from<_Iter, _Iter>
: __is_path_iter_src<_Iter>
{ };
template
struct __constructible_from<_Source, void>
: decltype(__is_path_src(std::declval<_Source>(), 0))
{ };
template
using _Path = typename
std::enable_if<__and_<__not_>,
__constructible_from<_Tp1, _Tp2>>::value,
path>::type;
template
static _Source
_S_range_begin(_Source __begin) { return __begin; }
struct __null_terminated { };
template
static __null_terminated
_S_range_end(_Source) { return {}; }
template
static const _CharT*
_S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data(); }
template
static const _CharT*
_S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
{ return __str.data() + __str.size(); }
#if __cplusplus >= 201402L
template
static const _CharT*
_S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data(); }
template
static const _CharT*
_S_range_end(const basic_string_view<_CharT, _Traits>& __str)
{ return __str.data() + __str.size(); }
#endif
template())),
typename _Val = typename std::iterator_traits<_Iter>::value_type>
using __value_type_is_char
= typename std::enable_if::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 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();
}
path(string_type&& __source)
: _M_pathname(std::move(__source))
{ _M_split_cmpts(); }
template>
path(_Source const& __source)
: _M_pathname(_S_convert(_S_range_begin(__source),
_S_range_end(__source)))
{ _M_split_cmpts(); }
template>
path(_InputIterator __first, _InputIterator __last)
: _M_pathname(_S_convert(__first, __last))
{ _M_split_cmpts(); }
template,
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 _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;
path& operator=(string_type&& __source);
path& assign(string_type&& __source);
template
_Path<_Source>&
operator=(_Source const& __source)
{ return *this = path(__source); }
template
_Path<_Source>&
assign(_Source const& __source)
{ return *this = path(__source); }
template
_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
_Path<_Source>&
operator/=(_Source const& __source)
{ return append(__source); }
template
_Path<_Source>&
append(_Source const& __source)
{
return _M_append(_S_convert(_S_range_begin(__source),
_S_range_end(__source)));
}
template
_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);
#if __cplusplus >= 201402L
path& operator+=(basic_string_view __x);
#endif
template
_Path<_Source>&
operator+=(_Source const& __x) { return concat(__x); }
template
_Path<_CharT*, _CharT*>&
operator+=(_CharT __x);
template
_Path<_Source>&
concat(_Source const& __x)
{ return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
template
_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 _Allocator = std::allocator<_CharT>>
std::basic_string<_CharT, _Traits, _Allocator>
string(const _Allocator& __a = _Allocator()) const;
std::string string() const;
#if _GLIBCXX_USE_WCHAR_T
std::wstring wstring() const;
#endif
std::string u8string() const;
std::u16string u16string() const;
std::u32string u32string() const;
// generic format observers
template,
typename _Allocator = std::allocator<_CharT>>
std::basic_string<_CharT, _Traits, _Allocator>
generic_string(const _Allocator& __a = _Allocator()) const;
std::string generic_string() const;
#if _GLIBCXX_USE_WCHAR_T
std::wstring generic_wstring() const;
#endif
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;
#if __cplusplus >= 201402L
int compare(const basic_string_view __s) const;
#endif
// 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_assert(!empty());
__glibcxx_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 _M_find_extension() const;
template
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
static string_type
_S_convert(_Iter __first, _Iter __last)
{
using __value_type = typename std::iterator_traits<_Iter>::value_type;
return _Cvt::type>::
_S_convert(__first, __last);
}
template
static string_type
_S_convert(_InputIterator __src, __null_terminated)
{
using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
std::basic_string::type> __tmp;
for (; *__src != _Tp{}; ++__src)
__tmp.push_back(*__src);
return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
}
static string_type
_S_convert_loc(const char* __first, const char* __last,
const std::locale& __loc);
template
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
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
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;
__os << __quoted_string{__tmp, '"', '\\'};
return __os;
}
/// Read a path from a stream
template
basic_istream<_CharT, _Traits>&
operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
{
basic_string<_CharT, _Traits> __tmp;
using __quoted_string
= std::__detail::_Quoted_string;
if (__is >> __quoted_string{ __tmp, '"', '\\' })
__p = std::move(__tmp);
return __is;
}
// TODO constrain with _Path