1 // Class filesystem::path -*- C++ -*-
3 // Copyright (C) 2014-2022 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file experimental/bits/fs_path.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{experimental/filesystem}
30 #ifndef _GLIBCXX_EXPERIMENTAL_FS_PATH_H
31 #define _GLIBCXX_EXPERIMENTAL_FS_PATH_H 1
33 #if __cplusplus < 201103L
34 # include <bits/c++0x_warning.h>
38 #include <type_traits>
43 #include <system_error>
44 #include <bits/stl_algobase.h>
45 #include <bits/quoted_string.h>
46 #include <bits/locale_conv.h>
47 #if __cplusplus == 201402L
48 # include <experimental/string_view>
51 #if defined(_WIN32) && !defined(__CYGWIN__)
52 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
56 namespace std
_GLIBCXX_VISIBILITY(default)
58 _GLIBCXX_BEGIN_NAMESPACE_VERSION
60 namespace experimental
66 _GLIBCXX_BEGIN_NAMESPACE_CXX11
68 #if __cplusplus == 201402L
69 using std::experimental::basic_string_view
;
70 #elif __cplusplus > 201402L
71 using std::basic_string_view
;
74 /// @cond undocumented
77 /** @addtogroup filesystem-ts
81 template<typename _CharT
,
82 typename _Ch
= typename remove_const
<_CharT
>::type
>
83 using __is_encoded_char
84 = __or_
<is_same
<_Ch
, char>,
85 is_same
<_Ch
, wchar_t>,
86 #ifdef _GLIBCXX_USE_CHAR8_T
87 is_same
<_Ch
, char8_t
>,
89 is_same
<_Ch
, char16_t
>,
90 is_same
<_Ch
, char32_t
>>;
92 template<typename _Iter
,
93 typename _Iter_traits
= std::iterator_traits
<_Iter
>>
94 using __is_path_iter_src
95 = __and_
<__is_encoded_char
<typename
_Iter_traits::value_type
>,
96 std::is_base_of
<std::input_iterator_tag
,
97 typename
_Iter_traits::iterator_category
>>;
99 template<typename _Iter
>
100 static __is_path_iter_src
<_Iter
>
101 __is_path_src(_Iter
, int);
103 template<typename _CharT
, typename _Traits
, typename _Alloc
>
104 static __is_encoded_char
<_CharT
>
105 __is_path_src(const basic_string
<_CharT
, _Traits
, _Alloc
>&, int);
107 #if __cplusplus >= 201402L
108 template<typename _CharT
, typename _Traits
>
109 static __is_encoded_char
<_CharT
>
110 __is_path_src(const basic_string_view
<_CharT
, _Traits
>&, int);
113 template<typename _Unknown
>
114 static std::false_type
115 __is_path_src(const _Unknown
&, ...);
117 template<typename _Tp1
, typename _Tp2
>
118 struct __constructible_from
;
120 template<typename _Iter
>
121 struct __constructible_from
<_Iter
, _Iter
>
122 : __is_path_iter_src
<_Iter
>
125 template<typename _Source
>
126 struct __constructible_from
<_Source
, void>
127 : decltype(__is_path_src(std::declval
<const _Source
&>(), 0))
130 template<typename _Tp1
, typename _Tp2
= void,
131 typename _Tp1_nocv
= typename remove_cv
<_Tp1
>::type
,
132 typename _Tp1_noptr
= typename remove_pointer
<_Tp1
>::type
>
133 using _Path
= typename
134 std::enable_if
<__and_
<__not_
<is_same
<_Tp1_nocv
, path
>>,
135 __not_
<is_void
<_Tp1_noptr
>>,
136 __constructible_from
<_Tp1
, _Tp2
>>::value
,
139 template<typename _Source
>
141 _S_range_begin(_Source __begin
) { return __begin
; }
143 struct __null_terminated
{ };
145 template<typename _Source
>
146 inline __null_terminated
147 _S_range_end(_Source
) { return {}; }
149 template<typename _CharT
, typename _Traits
, typename _Alloc
>
151 _S_range_begin(const basic_string
<_CharT
, _Traits
, _Alloc
>& __str
)
152 { return __str
.data(); }
154 template<typename _CharT
, typename _Traits
, typename _Alloc
>
156 _S_range_end(const basic_string
<_CharT
, _Traits
, _Alloc
>& __str
)
157 { return __str
.data() + __str
.size(); }
159 #if __cplusplus >= 201402L
160 template<typename _CharT
, typename _Traits
>
162 _S_range_begin(const basic_string_view
<_CharT
, _Traits
>& __str
)
163 { return __str
.data(); }
165 template<typename _CharT
, typename _Traits
>
167 _S_range_end(const basic_string_view
<_CharT
, _Traits
>& __str
)
168 { return __str
.data() + __str
.size(); }
171 template<typename _Tp
,
172 typename _Iter
= decltype(_S_range_begin(std::declval
<_Tp
>())),
173 typename _Val
= typename
std::iterator_traits
<_Iter
>::value_type
,
174 typename _UnqualVal
= typename
std::remove_const
<_Val
>::type
>
175 using __value_type_is_char
= typename
std::enable_if
<
176 std::is_same
<_UnqualVal
, char>::value
,
179 template<typename _Tp
,
180 typename _Iter
= decltype(_S_range_begin(std::declval
<_Tp
>())),
181 typename _Val
= typename
std::iterator_traits
<_Iter
>::value_type
,
182 typename _UnqualVal
= typename
std::remove_const
<_Val
>::type
>
183 using __value_type_is_char_or_char8_t
= typename
std::enable_if
<
185 std::is_same
<_UnqualVal
, char>
186 #ifdef _GLIBCXX_USE_CHAR8_T
187 ,std::is_same
<_UnqualVal
, char8_t
>
189 >::value
, _UnqualVal
>::type
;
191 /// @} group filesystem-ts
192 } // namespace __detail
195 /** @addtogroup filesystem-ts
199 /// A filesystem path.
200 /// @ingroup filesystem-ts
204 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
205 typedef wchar_t value_type
;
206 static constexpr value_type preferred_separator
= L
'\\';
208 typedef char value_type
;
209 static constexpr value_type preferred_separator
= '/';
211 typedef std::basic_string
<value_type
> string_type
;
213 // constructors and destructor
217 path(const path
& __p
) = default;
219 path(path
&& __p
) noexcept
220 : _M_pathname(std::move(__p
._M_pathname
)), _M_type(__p
._M_type
)
222 if (_M_type
== _Type::_Multi
)
227 path(string_type
&& __source
)
228 : _M_pathname(std::move(__source
))
229 { _M_split_cmpts(); }
231 template<typename _Source
,
232 typename _Require
= __detail::_Path
<_Source
>>
233 path(_Source
const& __source
)
234 : _M_pathname(_S_convert(__detail::_S_range_begin(__source
),
235 __detail::_S_range_end(__source
)))
236 { _M_split_cmpts(); }
238 template<typename _InputIterator
,
239 typename _Require
= __detail::_Path
<_InputIterator
, _InputIterator
>>
240 path(_InputIterator __first
, _InputIterator __last
)
241 : _M_pathname(_S_convert(__first
, __last
))
242 { _M_split_cmpts(); }
244 template<typename _Source
,
245 typename _Require
= __detail::_Path
<_Source
>,
246 typename _Require2
= __detail::__value_type_is_char
<_Source
>>
247 path(_Source
const& __source
, const locale
& __loc
)
248 : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source
),
249 __detail::_S_range_end(__source
), __loc
))
250 { _M_split_cmpts(); }
252 template<typename _InputIterator
,
253 typename _Require
= __detail::_Path
<_InputIterator
, _InputIterator
>,
254 typename _Require2
= __detail::__value_type_is_char
<_InputIterator
>>
255 path(_InputIterator __first
, _InputIterator __last
, const locale
& __loc
)
256 : _M_pathname(_S_convert_loc(__first
, __last
, __loc
))
257 { _M_split_cmpts(); }
263 path
& operator=(const path
& __p
) = default;
264 path
& operator=(path
&& __p
) noexcept
;
265 path
& operator=(string_type
&& __source
);
266 path
& assign(string_type
&& __source
);
268 template<typename _Source
>
269 __detail::_Path
<_Source
>&
270 operator=(_Source
const& __source
)
271 { return *this = path(__source
); }
273 template<typename _Source
>
274 __detail::_Path
<_Source
>&
275 assign(_Source
const& __source
)
276 { return *this = path(__source
); }
278 template<typename _InputIterator
>
279 __detail::_Path
<_InputIterator
, _InputIterator
>&
280 assign(_InputIterator __first
, _InputIterator __last
)
281 { return *this = path(__first
, __last
); }
285 path
& operator/=(const path
& __p
) { return _M_append(__p
._M_pathname
); }
287 template<typename _Source
>
288 __detail::_Path
<_Source
>&
289 operator/=(_Source
const& __source
)
290 { return append(__source
); }
292 template<typename _Source
>
293 __detail::_Path
<_Source
>&
294 append(_Source
const& __source
)
296 return _M_append(_S_convert(__detail::_S_range_begin(__source
),
297 __detail::_S_range_end(__source
)));
300 template<typename _InputIterator
>
301 __detail::_Path
<_InputIterator
, _InputIterator
>&
302 append(_InputIterator __first
, _InputIterator __last
)
303 { return _M_append(_S_convert(__first
, __last
)); }
307 path
& operator+=(const path
& __x
);
308 path
& operator+=(const string_type
& __x
);
309 path
& operator+=(const value_type
* __x
);
310 path
& operator+=(value_type __x
);
311 #if __cplusplus >= 201402L
312 path
& operator+=(basic_string_view
<value_type
> __x
);
315 template<typename _Source
>
316 __detail::_Path
<_Source
>&
317 operator+=(_Source
const& __x
) { return concat(__x
); }
319 template<typename _CharT
>
320 __detail::_Path
<_CharT
*, _CharT
*>&
321 operator+=(_CharT __x
);
323 template<typename _Source
>
324 __detail::_Path
<_Source
>&
325 concat(_Source
const& __x
)
327 return *this += _S_convert(__detail::_S_range_begin(__x
),
328 __detail::_S_range_end(__x
));
331 template<typename _InputIterator
>
332 __detail::_Path
<_InputIterator
, _InputIterator
>&
333 concat(_InputIterator __first
, _InputIterator __last
)
334 { return *this += _S_convert(__first
, __last
); }
338 void clear() noexcept
{ _M_pathname
.clear(); _M_split_cmpts(); }
340 path
& make_preferred();
341 path
& remove_filename();
342 path
& replace_filename(const path
& __replacement
);
343 path
& replace_extension(const path
& __replacement
= path());
345 void swap(path
& __rhs
) noexcept
;
347 // native format observers
349 const string_type
& native() const noexcept
{ return _M_pathname
; }
350 const value_type
* c_str() const noexcept
{ return _M_pathname
.c_str(); }
351 operator string_type() const { return _M_pathname
; }
353 template<typename _CharT
, typename _Traits
= std::char_traits
<_CharT
>,
354 typename _Allocator
= std::allocator
<_CharT
>>
355 std::basic_string
<_CharT
, _Traits
, _Allocator
>
356 string(const _Allocator
& __a
= _Allocator()) const;
358 std::string
string() const;
359 #if _GLIBCXX_USE_WCHAR_T
360 std::wstring
wstring() const;
362 #ifdef _GLIBCXX_USE_CHAR8_T
363 __attribute__((__abi_tag__("__u8")))
364 std::u8string
u8string() const;
366 std::string
u8string() const;
367 #endif // _GLIBCXX_USE_CHAR8_T
368 std::u16string
u16string() const;
369 std::u32string
u32string() const;
371 // generic format observers
372 template<typename _CharT
, typename _Traits
= std::char_traits
<_CharT
>,
373 typename _Allocator
= std::allocator
<_CharT
>>
374 std::basic_string
<_CharT
, _Traits
, _Allocator
>
375 generic_string(const _Allocator
& __a
= _Allocator()) const;
377 std::string
generic_string() const;
378 #if _GLIBCXX_USE_WCHAR_T
379 std::wstring
generic_wstring() const;
381 #ifdef _GLIBCXX_USE_CHAR8_T
382 __attribute__((__abi_tag__("__u8")))
383 std::u8string
generic_u8string() const;
385 std::string
generic_u8string() const;
386 #endif // _GLIBCXX_USE_CHAR8_T
387 std::u16string
generic_u16string() const;
388 std::u32string
generic_u32string() const;
392 int compare(const path
& __p
) const noexcept
;
393 int compare(const string_type
& __s
) const;
394 int compare(const value_type
* __s
) const;
395 #if __cplusplus >= 201402L
396 int compare(const basic_string_view
<value_type
> __s
) const;
401 path
root_name() const;
402 path
root_directory() const;
403 path
root_path() const;
404 path
relative_path() const;
405 path
parent_path() const;
406 path
filename() const;
408 path
extension() const;
412 _GLIBCXX_NODISCARD
bool empty() const noexcept
{ return _M_pathname
.empty(); }
413 bool has_root_name() const;
414 bool has_root_directory() const;
415 bool has_root_path() const;
416 bool has_relative_path() const;
417 bool has_parent_path() const;
418 bool has_filename() const;
419 bool has_stem() const;
420 bool has_extension() const;
421 bool is_absolute() const;
422 bool is_relative() const { return !is_absolute(); }
426 typedef iterator const_iterator
;
428 iterator
begin() const;
429 iterator
end() const;
431 /// @cond undocumented
432 // Create a basic_string by reading until a null character.
433 template<typename _InputIterator
,
434 typename _Traits
= std::iterator_traits
<_InputIterator
>,
436 = typename
std::remove_cv
<typename
_Traits::value_type
>::type
>
437 static std::basic_string
<_CharT
>
438 _S_string_from_iter(_InputIterator __source
)
440 std::basic_string
<_CharT
> __str
;
441 for (_CharT __ch
= *__source
; __ch
!= _CharT(); __ch
= *++__source
)
442 __str
.push_back(__ch
);
448 enum class _Type
: unsigned char {
449 _Multi
, _Root_name
, _Root_dir
, _Filename
452 path(string_type __str
, _Type __type
) : _M_pathname(__str
), _M_type(__type
)
454 __glibcxx_assert(!empty());
455 __glibcxx_assert(_M_type
!= _Type::_Multi
);
458 enum class _Split
{ _Stem
, _Extension
};
460 path
& _M_append(const string_type
& __str
)
462 if (!_M_pathname
.empty() && !_S_is_dir_sep(_M_pathname
.back())
463 && !__str
.empty() && !_S_is_dir_sep(__str
.front()))
464 _M_pathname
+= preferred_separator
;
465 _M_pathname
+= __str
;
470 pair
<const string_type
*, size_t> _M_find_extension() const;
472 template<typename _CharT
>
476 _S_convert(value_type
* __src
, __detail::__null_terminated
)
477 { return string_type(__src
); }
480 _S_convert(const value_type
* __src
, __detail::__null_terminated
)
481 { return string_type(__src
); }
483 template<typename _Iter
>
485 _S_convert(_Iter __first
, _Iter __last
)
487 using __value_type
= typename
std::iterator_traits
<_Iter
>::value_type
;
488 return _Cvt
<typename remove_cv
<__value_type
>::type
>::
489 _S_convert(__first
, __last
);
492 template<typename _InputIterator
>
494 _S_convert(_InputIterator __src
, __detail::__null_terminated
)
496 auto __s
= _S_string_from_iter(__src
);
497 return _S_convert(__s
.c_str(), __s
.c_str() + __s
.size());
501 _S_convert_loc(const char* __first
, const char* __last
,
502 const std::locale
& __loc
);
505 _S_convert_loc(char* __first
, char* __last
, const std::locale
& __loc
)
507 return _S_convert_loc(const_cast<const char*>(__first
),
508 const_cast<const char*>(__last
), __loc
);
511 template<typename _Iter
>
513 _S_convert_loc(_Iter __first
, _Iter __last
, const std::locale
& __loc
)
515 const std::string
__str(__first
, __last
);
516 return _S_convert_loc(__str
.data(), __str
.data()+__str
.size(), __loc
);
519 template<typename _InputIterator
>
521 _S_convert_loc(_InputIterator __src
, __detail::__null_terminated
,
522 const std::locale
& __loc
)
524 const std::string __s
= _S_string_from_iter(__src
);
525 return _S_convert_loc(__s
.data(), __s
.data() + __s
.size(), __loc
);
528 static bool _S_is_dir_sep(value_type __ch
)
530 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
531 return __ch
== L
'/' || __ch
== preferred_separator
;
537 void _M_split_cmpts();
539 void _M_add_root_name(size_t __n
);
540 void _M_add_root_dir(size_t __pos
);
541 void _M_add_filename(size_t __pos
, size_t __n
);
543 string_type _M_pathname
;
546 using _List
= _GLIBCXX_STD_C::vector
<_Cmpt
>;
547 _List _M_cmpts
; // empty unless _M_type == _Type::_Multi
548 _Type _M_type
= _Type::_Multi
;
551 /// @relates std::experimental::filesystem::path @{
553 /// Swap overload for paths
554 inline void swap(path
& __lhs
, path
& __rhs
) noexcept
{ __lhs
.swap(__rhs
); }
556 /// Compute a hash value for a path
557 size_t hash_value(const path
& __p
) noexcept
;
560 inline bool operator<(const path
& __lhs
, const path
& __rhs
) noexcept
;
563 inline bool operator<=(const path
& __lhs
, const path
& __rhs
) noexcept
564 { return !(__rhs
< __lhs
); }
567 inline bool operator>(const path
& __lhs
, const path
& __rhs
) noexcept
568 { return __rhs
< __lhs
; }
571 inline bool operator>=(const path
& __lhs
, const path
& __rhs
) noexcept
572 { return !(__lhs
< __rhs
); }
575 inline bool operator==(const path
& __lhs
, const path
& __rhs
) noexcept
;
578 inline bool operator!=(const path
& __lhs
, const path
& __rhs
) noexcept
579 { return !(__lhs
== __rhs
); }
581 /// Append one path to another
582 inline path
operator/(const path
& __lhs
, const path
& __rhs
)
584 path
__result(__lhs
);
589 /// Write a path to a stream
590 template<typename _CharT
, typename _Traits
>
591 basic_ostream
<_CharT
, _Traits
>&
592 operator<<(basic_ostream
<_CharT
, _Traits
>& __os
, const path
& __p
)
594 auto __tmp
= __p
.string
<_CharT
, _Traits
>();
595 using __quoted_string
596 = std::__detail::_Quoted_string
<decltype(__tmp
)&, _CharT
>;
597 __os
<< __quoted_string
{__tmp
, _CharT('"'), _CharT('\\')};
601 /// Read a path from a stream
602 template<typename _CharT
, typename _Traits
>
603 basic_istream
<_CharT
, _Traits
>&
604 operator>>(basic_istream
<_CharT
, _Traits
>& __is
, path
& __p
)
606 basic_string
<_CharT
, _Traits
> __tmp
;
607 using __quoted_string
608 = std::__detail::_Quoted_string
<decltype(__tmp
)&, _CharT
>;
609 if (__is
>> __quoted_string
{ __tmp
, _CharT('"'), _CharT('\\') })
610 __p
= std::move(__tmp
);
614 /// Create a path from a UTF-8-encoded sequence of char
615 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
616 template<typename _InputIterator
>
618 __u8path(_InputIterator __first
, _InputIterator __last
, char)
620 // XXX This assumes native wide encoding is UTF-16.
621 std::codecvt_utf8_utf16
<path::value_type
> __cvt
;
622 path::string_type __tmp
;
623 const std::string __u8str
{__first
, __last
};
624 const char* const __ptr
= __u8str
.data();
625 if (__str_codecvt_in_all(__ptr
, __ptr
+ __u8str
.size(), __tmp
, __cvt
))
626 return path
{ __tmp
};
627 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
628 "Cannot convert character sequence",
629 std::make_error_code(errc::illegal_byte_sequence
)));
632 #ifdef _GLIBCXX_USE_CHAR8_T
633 template<typename _InputIterator
>
635 __u8path(_InputIterator __first
, _InputIterator __last
, char8_t
)
637 return path
{ __first
, __last
};
639 #endif // _GLIBCXX_USE_CHAR8_T
640 #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
642 template<typename _InputIterator
,
643 typename _Require
= __detail::_Path
<_InputIterator
, _InputIterator
>,
645 __detail::__value_type_is_char_or_char8_t
<_InputIterator
>>
647 u8path(_InputIterator __first
, _InputIterator __last
)
649 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
650 return __u8path(__first
, __last
, _CharT
{});
652 return path
{ __first
, __last
};
656 /// Create a path from a UTF-8-encoded sequence of char
657 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
659 __u8path(const string
& __s
, char)
661 return filesystem::u8path(__s
.data(), __s
.data() + __s
.size());
664 template<typename _Source
>
665 inline __enable_if_t
<is_convertible
<const _Source
&, string
>::value
, path
>
666 __u8path(const _Source
& __source
, char)
668 std::string __s
= __source
;
669 return filesystem::u8path(__s
.data(), __s
.data() + __s
.size());
672 template<typename _Source
>
673 inline __enable_if_t
<!is_convertible
<const _Source
&, string
>::value
, path
>
674 __u8path(const _Source
& __source
, char)
676 std::string __s
= path::_S_string_from_iter(__source
);
677 return filesystem::u8path(__s
.data(), __s
.data() + __s
.size());
680 #ifdef _GLIBCXX_USE_CHAR8_T
681 template<typename _Source
>
683 __u8path(const _Source
& __source
, char8_t
)
685 return path
{ __source
};
687 #endif // _GLIBCXX_USE_CHAR8_T
688 #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
690 template<typename _Source
,
691 typename _Require
= __detail::_Path
<_Source
>,
693 __detail::__value_type_is_char_or_char8_t
<_Source
>>
695 u8path(const _Source
& __source
)
697 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
698 return __u8path(__source
, _CharT
{});
700 return path
{ __source
};
706 /// Exception type thrown by the Filesystem TS library
707 class filesystem_error
: public std::system_error
710 filesystem_error(const string
& __what_arg
, error_code __ec
)
711 : system_error(__ec
, __what_arg
) { }
713 filesystem_error(const string
& __what_arg
, const path
& __p1
,
715 : system_error(__ec
, __what_arg
), _M_path1(__p1
) { }
717 filesystem_error(const string
& __what_arg
, const path
& __p1
,
718 const path
& __p2
, error_code __ec
)
719 : system_error(__ec
, __what_arg
), _M_path1(__p1
), _M_path2(__p2
)
724 const path
& path1() const noexcept
{ return _M_path1
; }
725 const path
& path2() const noexcept
{ return _M_path2
; }
726 const char* what() const noexcept
{ return _M_what
.c_str(); }
729 std::string
_M_gen_what();
733 std::string _M_what
= _M_gen_what();
736 /// @cond undocumented
737 struct path::_Cmpt
: path
739 _Cmpt(string_type __s
, _Type __t
, size_t __pos
)
740 : path(std::move(__s
), __t
), _M_pos(__pos
) { }
742 _Cmpt() : _M_pos(-1) { }
747 // specialize _Cvt for degenerate 'noconv' case
749 struct path::_Cvt
<path::value_type
>
751 template<typename _Iter
>
753 _S_convert(_Iter __first
, _Iter __last
)
754 { return string_type
{__first
, __last
}; }
757 template<typename _CharT
>
760 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
761 #ifdef _GLIBCXX_USE_CHAR8_T
763 _S_wconvert(const char8_t
* __f
, const char8_t
* __l
, const char8_t
*)
765 const char* __f2
= (const char*)__f
;
766 const char* __l2
= (const char*)__l
;
768 std::codecvt_utf8_utf16
<wchar_t> __wcvt
;
769 if (__str_codecvt_in_all(__f2
, __l2
, __wstr
, __wcvt
))
775 _S_wconvert(const char* __f
, const char* __l
, const char*)
777 using _Cvt
= std::codecvt
<wchar_t, char, mbstate_t>;
778 const auto& __cvt
= std::use_facet
<_Cvt
>(std::locale
{});
780 if (__str_codecvt_in_all(__f
, __l
, __wstr
, __cvt
))
782 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
783 "Cannot convert character sequence",
784 std::make_error_code(errc::illegal_byte_sequence
)));
788 _S_wconvert(const _CharT
* __f
, const _CharT
* __l
, const void*)
790 struct _UCvt
: std::codecvt
<_CharT
, char, std::mbstate_t>
793 if (__str_codecvt_out_all(__f
, __l
, __str
, __cvt
))
795 const char* __f2
= __str
.data();
796 const char* __l2
= __f2
+ __str
.size();
797 std::codecvt_utf8_utf16
<wchar_t> __wcvt
;
799 if (__str_codecvt_in_all(__f2
, __l2
, __wstr
, __wcvt
))
802 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
803 "Cannot convert character sequence",
804 std::make_error_code(errc::illegal_byte_sequence
)));
808 _S_convert(const _CharT
* __f
, const _CharT
* __l
)
810 return _S_wconvert(__f
, __l
, (const _CharT
*)nullptr);
814 _S_convert(const _CharT
* __f
, const _CharT
* __l
)
816 #ifdef _GLIBCXX_USE_CHAR8_T
817 if constexpr (is_same
<_CharT
, char8_t
>::value
)
818 return string_type(__f
, __l
);
822 struct _UCvt
: std::codecvt
<_CharT
, char, std::mbstate_t>
825 if (__str_codecvt_out_all(__f
, __l
, __str
, __cvt
))
827 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
828 "Cannot convert character sequence",
829 std::make_error_code(errc::illegal_byte_sequence
)));
835 _S_convert(_CharT
* __f
, _CharT
* __l
)
837 return _S_convert(const_cast<const _CharT
*>(__f
),
838 const_cast<const _CharT
*>(__l
));
841 template<typename _Iter
>
843 _S_convert(_Iter __first
, _Iter __last
)
845 const std::basic_string
<_CharT
> __str(__first
, __last
);
846 return _S_convert(__str
.data(), __str
.data() + __str
.size());
849 template<typename _Iter
, typename _Cont
>
851 _S_convert(__gnu_cxx::__normal_iterator
<_Iter
, _Cont
> __first
,
852 __gnu_cxx::__normal_iterator
<_Iter
, _Cont
> __last
)
853 { return _S_convert(__first
.base(), __last
.base()); }
857 /// An iterator for the components of a path
861 using difference_type
= std::ptrdiff_t;
862 using value_type
= path
;
863 using reference
= const path
&;
864 using pointer
= const path
*;
865 using iterator_category
= std::bidirectional_iterator_tag
;
867 iterator() noexcept
: _M_path(nullptr), _M_cur(), _M_at_end() { }
869 iterator(const iterator
&) = default;
870 iterator
& operator=(const iterator
&) = default;
872 reference
operator*() const noexcept
;
873 pointer
operator->() const noexcept
{ return std::__addressof(**this); }
875 iterator
& operator++() noexcept
;
877 iterator
operator++(int) noexcept
878 { auto __tmp
= *this; ++*this; return __tmp
; }
880 iterator
& operator--() noexcept
;
882 iterator
operator--(int) noexcept
883 { auto __tmp
= *this; --*this; return __tmp
; }
886 operator==(const iterator
& __lhs
, const iterator
& __rhs
) noexcept
887 { return __lhs
._M_equals(__rhs
); }
890 operator!=(const iterator
& __lhs
, const iterator
& __rhs
) noexcept
891 { return !__lhs
._M_equals(__rhs
); }
896 iterator(const path
* __path
, path::_List::const_iterator __iter
) noexcept
897 : _M_path(__path
), _M_cur(__iter
), _M_at_end()
900 iterator(const path
* __path
, bool __at_end
) noexcept
901 : _M_path(__path
), _M_cur(), _M_at_end(__at_end
)
904 bool _M_equals(iterator
) const noexcept
;
907 path::_List::const_iterator _M_cur
;
908 bool _M_at_end
; // only used when type != _Multi
913 path::operator=(path
&& __p
) noexcept
915 _M_pathname
= std::move(__p
._M_pathname
);
916 _M_cmpts
= std::move(__p
._M_cmpts
);
917 _M_type
= __p
._M_type
;
923 path::operator=(string_type
&& __source
)
924 { return *this = path(std::move(__source
)); }
927 path::assign(string_type
&& __source
)
928 { return *this = path(std::move(__source
)); }
931 path::operator+=(const path
& __p
)
933 return operator+=(__p
.native());
937 path::operator+=(const string_type
& __x
)
945 path::operator+=(const value_type
* __x
)
953 path::operator+=(value_type __x
)
960 #if __cplusplus >= 201402L
962 path::operator+=(basic_string_view
<value_type
> __x
)
964 _M_pathname
.append(__x
.data(), __x
.size());
970 template<typename _CharT
>
971 inline __detail::_Path
<_CharT
*, _CharT
*>&
972 path::operator+=(_CharT __x
)
974 auto* __addr
= std::__addressof(__x
);
975 return concat(__addr
, __addr
+ 1);
979 path::make_preferred()
981 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
982 std::replace(_M_pathname
.begin(), _M_pathname
.end(), L
'/',
983 preferred_separator
);
988 inline void path::swap(path
& __rhs
) noexcept
990 _M_pathname
.swap(__rhs
._M_pathname
);
991 _M_cmpts
.swap(__rhs
._M_cmpts
);
992 std::swap(_M_type
, __rhs
._M_type
);
995 template<typename _CharT
, typename _Traits
, typename _Allocator
>
996 inline std::basic_string
<_CharT
, _Traits
, _Allocator
>
997 path::string(const _Allocator
& __a
) const
999 if (is_same
<_CharT
, value_type
>::value
)
1000 return { _M_pathname
.begin(), _M_pathname
.end(), __a
};
1002 using _WString
= basic_string
<_CharT
, _Traits
, _Allocator
>;
1004 const value_type
* __first
= _M_pathname
.data();
1005 const value_type
* __last
= __first
+ _M_pathname
.size();
1007 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1008 using _CharAlloc
= __alloc_rebind
<_Allocator
, char>;
1009 using _String
= basic_string
<char, char_traits
<char>, _CharAlloc
>;
1011 // First convert native string from UTF-16 to to UTF-8.
1012 // XXX This assumes that the execution wide-character set is UTF-16.
1013 codecvt_utf8_utf16
<value_type
> __cvt
;
1014 _String __u8str
{_CharAlloc
{__a
}};
1015 if (__str_codecvt_out_all(__first
, __last
, __u8str
, __cvt
))
1020 operator()(const _String
& __from
, _String
&, true_type
)
1021 { return std::__addressof(__from
); }
1024 operator()(const _String
& __from
, _WString
& __to
, false_type
)
1026 #ifdef _GLIBCXX_USE_CHAR8_T
1027 if constexpr (is_same
<_CharT
, char8_t
>::value
)
1029 __to
.assign(__from
.begin(), __from
.end());
1030 return std::__addressof(__to
);
1035 // Convert UTF-8 to wide string.
1036 struct _UCvt
: std::codecvt
<_CharT
, char, std::mbstate_t>
1038 const char* __f
= __from
.data();
1039 const char* __l
= __f
+ __from
.size();
1040 if (__str_codecvt_in_all(__f
, __l
, __to
, __cvt
))
1041 return std::__addressof(__to
);
1046 _WString
__wstr(__a
);
1047 if (auto* __p
= __dispatch(__u8str
, __wstr
, is_same
<_CharT
, char>{}))
1051 #ifdef _GLIBCXX_USE_CHAR8_T
1052 if constexpr (is_same
<_CharT
, char8_t
>::value
)
1053 return _WString(__first
, __last
, __a
);
1057 struct _UCvt
: std::codecvt
<_CharT
, char, std::mbstate_t> { } __cvt
;
1058 _WString
__wstr(__a
);
1059 if (__str_codecvt_in_all(__first
, __last
, __wstr
, __cvt
))
1063 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1064 "Cannot convert character sequence",
1065 std::make_error_code(errc::illegal_byte_sequence
)));
1069 path::string() const { return string
<char>(); }
1071 #if _GLIBCXX_USE_WCHAR_T
1073 path::wstring() const { return string
<wchar_t>(); }
1076 #ifdef _GLIBCXX_USE_CHAR8_T
1077 inline std::u8string
1078 path::u8string() const { return string
<char8_t
>(); }
1081 path::u8string() const
1083 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1085 // convert from native wide encoding (assumed to be UTF-16) to UTF-8
1086 std::codecvt_utf8_utf16
<value_type
> __cvt
;
1087 const value_type
* __first
= _M_pathname
.data();
1088 const value_type
* __last
= __first
+ _M_pathname
.size();
1089 if (__str_codecvt_out_all(__first
, __last
, __str
, __cvt
))
1091 _GLIBCXX_THROW_OR_ABORT(filesystem_error(
1092 "Cannot convert character sequence",
1093 std::make_error_code(errc::illegal_byte_sequence
)));
1098 #endif // _GLIBCXX_USE_CHAR8_T
1100 inline std::u16string
1101 path::u16string() const { return string
<char16_t
>(); }
1103 inline std::u32string
1104 path::u32string() const { return string
<char32_t
>(); }
1106 template<typename _CharT
, typename _Traits
, typename _Allocator
>
1107 inline std::basic_string
<_CharT
, _Traits
, _Allocator
>
1108 path::generic_string(const _Allocator
& __a
) const
1110 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1111 const _CharT __slash
= is_same
<_CharT
, wchar_t>::value
1113 : _CharT('/'); // Assume value is correct for the encoding.
1115 const _CharT __slash
= _CharT('/');
1117 basic_string
<_CharT
, _Traits
, _Allocator
> __str(__a
);
1118 __str
.reserve(_M_pathname
.size());
1119 bool __add_slash
= false;
1120 for (auto& __elem
: *this)
1122 if (__elem
._M_type
== _Type::_Root_dir
)
1129 __str
+= __elem
.string
<_CharT
, _Traits
, _Allocator
>(__a
);
1130 __add_slash
= __elem
._M_type
== _Type::_Filename
;
1136 path::generic_string() const { return generic_string
<char>(); }
1138 #if _GLIBCXX_USE_WCHAR_T
1140 path::generic_wstring() const { return generic_string
<wchar_t>(); }
1143 #ifdef _GLIBCXX_USE_CHAR8_T
1144 inline std::u8string
1145 path::generic_u8string() const { return generic_string
<char8_t
>(); }
1148 path::generic_u8string() const { return generic_string
<char>(); }
1151 inline std::u16string
1152 path::generic_u16string() const { return generic_string
<char16_t
>(); }
1154 inline std::u32string
1155 path::generic_u32string() const { return generic_string
<char32_t
>(); }
1158 path::compare(const string_type
& __s
) const { return compare(path(__s
)); }
1161 path::compare(const value_type
* __s
) const { return compare(path(__s
)); }
1163 #if __cplusplus >= 201402L
1165 path::compare(basic_string_view
<value_type
> __s
) const
1166 { return compare(path(__s
)); }
1170 path::filename() const { return empty() ? path() : *--end(); }
1175 auto ext
= _M_find_extension();
1176 if (ext
.first
&& ext
.second
!= 0)
1177 return path
{ext
.first
->substr(0, ext
.second
)};
1182 path::extension() const
1184 auto ext
= _M_find_extension();
1185 if (ext
.first
&& ext
.second
!= string_type::npos
)
1186 return path
{ext
.first
->substr(ext
.second
)};
1191 path::has_stem() const
1193 auto ext
= _M_find_extension();
1194 return ext
.first
&& ext
.second
!= 0;
1198 path::has_extension() const
1200 auto ext
= _M_find_extension();
1201 return ext
.first
&& ext
.second
!= string_type::npos
;
1205 path::is_absolute() const
1207 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
1208 return has_root_name() && has_root_directory();
1210 return has_root_directory();
1214 inline path::iterator
1215 path::begin() const noexcept
1217 if (_M_type
== _Type::_Multi
)
1218 return iterator(this, _M_cmpts
.begin());
1219 return iterator(this, false);
1222 inline path::iterator
1223 path::end() const noexcept
1225 if (_M_type
== _Type::_Multi
)
1226 return iterator(this, _M_cmpts
.end());
1227 return iterator(this, true);
1230 inline path::iterator
&
1231 path::iterator::operator++() noexcept
1233 __glibcxx_assert(_M_path
!= nullptr);
1234 if (_M_path
->_M_type
== _Type::_Multi
)
1236 __glibcxx_assert(_M_cur
!= _M_path
->_M_cmpts
.end());
1241 __glibcxx_assert(!_M_at_end
);
1247 inline path::iterator
&
1248 path::iterator::operator--() noexcept
1250 __glibcxx_assert(_M_path
!= nullptr);
1251 if (_M_path
->_M_type
== _Type::_Multi
)
1253 __glibcxx_assert(_M_cur
!= _M_path
->_M_cmpts
.begin());
1258 __glibcxx_assert(_M_at_end
);
1264 inline path::iterator::reference
1265 path::iterator::operator*() const noexcept
1267 __glibcxx_assert(_M_path
!= nullptr);
1268 if (_M_path
->_M_type
== _Type::_Multi
)
1270 __glibcxx_assert(_M_cur
!= _M_path
->_M_cmpts
.end());
1277 path::iterator::_M_equals(iterator __rhs
) const noexcept
1279 if (_M_path
!= __rhs
._M_path
)
1281 if (_M_path
== nullptr)
1283 if (_M_path
->_M_type
== path::_Type::_Multi
)
1284 return _M_cur
== __rhs
._M_cur
;
1285 return _M_at_end
== __rhs
._M_at_end
;
1288 // Define these now that path and path::iterator are complete.
1289 // They needs to consider the string_view(Range&&) constructor during
1290 // overload resolution, which depends on whether range<path> is satisfied,
1291 // which depends on whether path::iterator is complete.
1292 inline bool operator<(const path
& __lhs
, const path
& __rhs
) noexcept
1293 { return __lhs
.compare(__rhs
) < 0; }
1295 inline bool operator==(const path
& __lhs
, const path
& __rhs
) noexcept
1296 { return __lhs
.compare(__rhs
) == 0; }
1298 /// @} group filesystem-ts
1299 _GLIBCXX_END_NAMESPACE_CXX11
1301 } // namespace filesystem
1302 } // namespace experimental
1304 _GLIBCXX_END_NAMESPACE_VERSION
1309 #endif // _GLIBCXX_EXPERIMENTAL_FS_PATH_H