931 lines · c
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___FILESYSTEM_PATH_H11#define _LIBCPP___FILESYSTEM_PATH_H12 13#include <__algorithm/replace.h>14#include <__algorithm/replace_copy.h>15#include <__config>16#include <__functional/unary_function.h>17#include <__fwd/functional.h>18#include <__iterator/back_insert_iterator.h>19#include <__iterator/iterator_traits.h>20#include <__memory/addressof.h>21#include <__type_traits/decay.h>22#include <__type_traits/enable_if.h>23#include <__type_traits/is_pointer.h>24#include <__type_traits/remove_const.h>25#include <__type_traits/remove_pointer.h>26#include <__utility/move.h>27#include <string>28#include <string_view>29 30#if _LIBCPP_HAS_LOCALIZATION31# include <iomanip> // for quoted32#endif33 34#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)35# pragma GCC system_header36#endif37 38_LIBCPP_PUSH_MACROS39#include <__undef_macros>40 41#if _LIBCPP_STD_VER >= 1742 43_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM44 45template <class _Tp>46struct __can_convert_char {47 static const bool value = false;48};49template <class _Tp>50struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};51template <>52struct __can_convert_char<char> {53 static const bool value = true;54 using __char_type _LIBCPP_NODEBUG = char;55};56template <>57struct __can_convert_char<wchar_t> {58 static const bool value = true;59 using __char_type _LIBCPP_NODEBUG = wchar_t;60};61# if _LIBCPP_HAS_CHAR8_T62template <>63struct __can_convert_char<char8_t> {64 static const bool value = true;65 using __char_type _LIBCPP_NODEBUG = char8_t;66};67# endif68template <>69struct __can_convert_char<char16_t> {70 static const bool value = true;71 using __char_type _LIBCPP_NODEBUG = char16_t;72};73template <>74struct __can_convert_char<char32_t> {75 static const bool value = true;76 using __char_type _LIBCPP_NODEBUG = char32_t;77};78 79template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0>80_LIBCPP_HIDE_FROM_ABI bool __is_separator(_ECharT __e) {81# if defined(_LIBCPP_WIN32API)82 return __e == _ECharT('/') || __e == _ECharT('\\');83# else84 return __e == _ECharT('/');85# endif86}87 88# if _LIBCPP_HAS_CHAR8_T89typedef u8string __u8_string;90# else91typedef string __u8_string;92# endif93 94struct _NullSentinel {};95 96template <class _Tp>97using _Void _LIBCPP_NODEBUG = void;98 99template <class _Tp, class = void>100struct __is_pathable_string : public false_type {};101 102template <class _ECharT, class _Traits, class _Alloc>103struct __is_pathable_string< basic_string<_ECharT, _Traits, _Alloc>,104 _Void<typename __can_convert_char<_ECharT>::__char_type> >105 : public __can_convert_char<_ECharT> {106 using _Str _LIBCPP_NODEBUG = basic_string<_ECharT, _Traits, _Alloc>;107 108 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }109 110 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); }111 112 _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Str const& __s) { return __s.empty() ? _ECharT{} : __s[0]; }113};114 115template <class _ECharT, class _Traits>116struct __is_pathable_string< basic_string_view<_ECharT, _Traits>,117 _Void<typename __can_convert_char<_ECharT>::__char_type> >118 : public __can_convert_char<_ECharT> {119 using _Str _LIBCPP_NODEBUG = basic_string_view<_ECharT, _Traits>;120 121 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }122 123 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(_Str const& __s) { return __s.data() + __s.length(); }124 125 _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Str const& __s) { return __s.empty() ? _ECharT{} : __s[0]; }126};127 128template <class _Source,129 class _DS = __decay_t<_Source>,130 class _UnqualPtrType = __remove_const_t<__remove_pointer_t<_DS> >,131 bool _IsCharPtr = is_pointer<_DS>::value && __can_convert_char<_UnqualPtrType>::value>132struct __is_pathable_char_array : false_type {};133 134template <class _Source, class _ECharT, class _UPtr>135struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true> : __can_convert_char<__remove_const_t<_ECharT> > {136 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }137 138 _LIBCPP_HIDE_FROM_ABI static _ECharT const* __range_end(const _ECharT* __b) {139 using _Iter = const _ECharT*;140 const _ECharT __sentinel = _ECharT{};141 _Iter __e = __b;142 for (; *__e != __sentinel; ++__e)143 ;144 return __e;145 }146 147 _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }148};149 150template <class _Iter, bool _IsIt = __has_input_iterator_category<_Iter>::value, class = void>151struct __is_pathable_iter : false_type {};152 153template <class _Iter>154struct __is_pathable_iter<155 _Iter,156 true,157 _Void<typename __can_convert_char< typename iterator_traits<_Iter>::value_type>::__char_type> >158 : __can_convert_char<typename iterator_traits<_Iter>::value_type> {159 using _ECharT _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::value_type;160 161 _LIBCPP_HIDE_FROM_ABI static _Iter __range_begin(_Iter __b) { return __b; }162 163 _LIBCPP_HIDE_FROM_ABI static _NullSentinel __range_end(_Iter) { return _NullSentinel{}; }164 165 _LIBCPP_HIDE_FROM_ABI static _ECharT __first_or_null(_Iter __b) { return *__b; }166};167 168template <class _Tp,169 bool _IsStringT = __is_pathable_string<_Tp>::value,170 bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,171 bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value>172struct __is_pathable : false_type {173 static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");174};175 176template <class _Tp>177struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};178 179template <class _Tp>180struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {};181 182template <class _Tp>183struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};184 185# if defined(_LIBCPP_WIN32API)186typedef wstring __path_string;187typedef wchar_t __path_value;188# else189typedef string __path_string;190typedef char __path_value;191# endif192 193# if defined(_LIBCPP_WIN32API)194_LIBCPP_EXPORTED_FROM_ABI size_t __wide_to_char(const wstring&, char*, size_t);195_LIBCPP_EXPORTED_FROM_ABI size_t __char_to_wide(const string&, wchar_t*, size_t);196# endif197 198template <class _ECharT>199struct _PathCVT;200 201# if _LIBCPP_HAS_LOCALIZATION202template <class _ECharT>203struct _PathCVT {204 static_assert(__can_convert_char<_ECharT>::value, "Char type not convertible");205 206 typedef __narrow_to_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Narrower;207# if defined(_LIBCPP_WIN32API)208 typedef __widen_from_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Widener;209# endif210 211 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _ECharT const* __b, _ECharT const* __e) {212# if defined(_LIBCPP_WIN32API)213 string __utf8;214 _Narrower()(back_inserter(__utf8), __b, __e);215 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());216# else217 _Narrower()(back_inserter(__dest), __b, __e);218# endif219 }220 221 template <class _Iter>222 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {223 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");224 if (__b == __e)225 return;226 basic_string<_ECharT> __tmp(__b, __e);227# if defined(_LIBCPP_WIN32API)228 string __utf8;229 _Narrower()(back_inserter(__utf8), __tmp.data(), __tmp.data() + __tmp.length());230 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());231# else232 _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length());233# endif234 }235 236 template <class _Iter>237 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {238 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");239 const _ECharT __sentinel = _ECharT{};240 if (*__b == __sentinel)241 return;242 basic_string<_ECharT> __tmp;243 for (; *__b != __sentinel; ++__b)244 __tmp.push_back(*__b);245# if defined(_LIBCPP_WIN32API)246 string __utf8;247 _Narrower()(back_inserter(__utf8), __tmp.data(), __tmp.data() + __tmp.length());248 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());249# else250 _Narrower()(back_inserter(__dest), __tmp.data(), __tmp.data() + __tmp.length());251# endif252 }253 254 template <class _Source>255 _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) {256 using _Traits = __is_pathable<_Source>;257 __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));258 }259};260# endif // _LIBCPP_HAS_LOCALIZATION261 262template <>263struct _PathCVT<__path_value> {264 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0>265 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {266 for (; __b != __e; ++__b)267 __dest.push_back(*__b);268 }269 270 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0>271 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {272 __dest.append(__b, __e);273 }274 275 template <class _Iter>276 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {277 const char __sentinel = char{};278 for (; *__b != __sentinel; ++__b)279 __dest.push_back(*__b);280 }281 282 template <class _Source>283 _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) {284 using _Traits = __is_pathable<_Source>;285 __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));286 }287};288 289# if defined(_LIBCPP_WIN32API)290template <>291struct _PathCVT<char> {292 _LIBCPP_HIDE_FROM_ABI static void __append_string(__path_string& __dest, const basic_string<char>& __str) {293 size_t __size = __char_to_wide(__str, nullptr, 0);294 size_t __pos = __dest.size();295 __dest.resize(__pos + __size);296 __char_to_wide(__str, const_cast<__path_value*>(__dest.data()) + __pos, __size);297 }298 299 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0>300 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {301 basic_string<char> __tmp(__b, __e);302 __append_string(__dest, __tmp);303 }304 305 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0>306 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {307 basic_string<char> __tmp(__b, __e);308 __append_string(__dest, __tmp);309 }310 311 template <class _Iter>312 _LIBCPP_HIDE_FROM_ABI static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {313 const char __sentinel = char{};314 basic_string<char> __tmp;315 for (; *__b != __sentinel; ++__b)316 __tmp.push_back(*__b);317 __append_string(__dest, __tmp);318 }319 320 template <class _Source>321 _LIBCPP_HIDE_FROM_ABI static void __append_source(__path_string& __dest, _Source const& __s) {322 using _Traits = __is_pathable<_Source>;323 __append_range(__dest, _Traits::__range_begin(__s), _Traits::__range_end(__s));324 }325};326 327# if _LIBCPP_HAS_LOCALIZATION328template <class _ECharT>329struct _PathExport {330 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower;331 typedef __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Widener;332 333 template <class _Str>334 _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) {335 string __utf8;336 _Narrower()(back_inserter(__utf8), __src.data(), __src.data() + __src.size());337 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());338 }339};340 341template <>342struct _PathExport<char> {343 template <class _Str>344 _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) {345 size_t __size = __wide_to_char(__src, nullptr, 0);346 size_t __pos = __dest.size();347 __dest.resize(__size);348 __wide_to_char(__src, const_cast<char*>(__dest.data()) + __pos, __size);349 }350};351 352template <>353struct _PathExport<wchar_t> {354 template <class _Str>355 _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) {356 __dest.append(__src.begin(), __src.end());357 }358};359 360template <>361struct _PathExport<char16_t> {362 template <class _Str>363 _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) {364 __dest.append(__src.begin(), __src.end());365 }366};367 368# if _LIBCPP_HAS_CHAR8_T369template <>370struct _PathExport<char8_t> {371 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower;372 373 template <class _Str>374 _LIBCPP_HIDE_FROM_ABI static void __append(_Str& __dest, const __path_string& __src) {375 _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size());376 }377};378# endif // _LIBCPP_HAS_CHAR8_T379# endif // _LIBCPP_HAS_LOCALIZATION380# endif // _LIBCPP_WIN32API381 382class _LIBCPP_EXPORTED_FROM_ABI path {383 template <class _SourceOrIter, class _Tp = path&>384 using _EnableIfPathable _LIBCPP_NODEBUG = __enable_if_t<__is_pathable<_SourceOrIter>::value, _Tp>;385 386 template <class _Tp>387 using _SourceChar _LIBCPP_NODEBUG = typename __is_pathable<_Tp>::__char_type;388 389 template <class _Tp>390 using _SourceCVT _LIBCPP_NODEBUG = _PathCVT<_SourceChar<_Tp> >;391 392public:393# if defined(_LIBCPP_WIN32API)394 typedef wchar_t value_type;395 static constexpr value_type preferred_separator = L'\\';396# else397 typedef char value_type;398 static constexpr value_type preferred_separator = '/';399# endif400 typedef basic_string<value_type> string_type;401 typedef basic_string_view<value_type> __string_view;402 403 enum format : unsigned char { auto_format, native_format, generic_format };404 405 // constructors and destructor406 _LIBCPP_HIDE_FROM_ABI path() noexcept {}407 _LIBCPP_HIDE_FROM_ABI path(const path& __p) : __pn_(__p.__pn_) {}408 _LIBCPP_HIDE_FROM_ABI path(path&& __p) noexcept : __pn_(std::move(__p.__pn_)) {}409 410 _LIBCPP_HIDE_FROM_ABI path(string_type&& __s, format = format::auto_format) noexcept : __pn_(std::move(__s)) {}411 412 template <class _Source, class = _EnableIfPathable<_Source, void> >413 _LIBCPP_HIDE_FROM_ABI path(const _Source& __src, format = format::auto_format) {414 _SourceCVT<_Source>::__append_source(__pn_, __src);415 }416 417 template <class _InputIt>418 _LIBCPP_HIDE_FROM_ABI path(_InputIt __first, _InputIt __last, format = format::auto_format) {419 typedef typename iterator_traits<_InputIt>::value_type _ItVal;420 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);421 }422 423 /*424 #if _LIBCPP_HAS_LOCALIZATION425 // TODO Implement locale conversions.426 template <class _Source, class = _EnableIfPathable<_Source, void> >427 path(const _Source& __src, const locale& __loc, format = format::auto_format);428 template <class _InputIt>429 path(_InputIt __first, _InputIt _last, const locale& __loc,430 format = format::auto_format);431 #endif432 */433 434 _LIBCPP_HIDE_FROM_ABI ~path() = default;435 436 // assignments437 _LIBCPP_HIDE_FROM_ABI path& operator=(const path& __p) {438 __pn_ = __p.__pn_;439 return *this;440 }441 442 _LIBCPP_HIDE_FROM_ABI path& operator=(path&& __p) noexcept {443 __pn_ = std::move(__p.__pn_);444 return *this;445 }446 447 _LIBCPP_HIDE_FROM_ABI path& operator=(string_type&& __s) noexcept {448 __pn_ = std::move(__s);449 return *this;450 }451 452 _LIBCPP_HIDE_FROM_ABI path& assign(string_type&& __s) noexcept {453 __pn_ = std::move(__s);454 return *this;455 }456 457 template <class _Source>458 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator=(const _Source& __src) {459 return this->assign(__src);460 }461 462 template <class _Source>463 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> assign(const _Source& __src) {464 __pn_.clear();465 _SourceCVT<_Source>::__append_source(__pn_, __src);466 return *this;467 }468 469 template <class _InputIt>470 _LIBCPP_HIDE_FROM_ABI path& assign(_InputIt __first, _InputIt __last) {471 typedef typename iterator_traits<_InputIt>::value_type _ItVal;472 __pn_.clear();473 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);474 return *this;475 }476 477public:478 // appends479# if defined(_LIBCPP_WIN32API)480 _LIBCPP_HIDE_FROM_ABI path& operator/=(const path& __p) {481 auto __p_root_name = __p.__root_name();482 auto __p_root_name_size = __p_root_name.size();483 if (__p.is_absolute() || (!__p_root_name.empty() && __p_root_name != __string_view(root_name().__pn_))) {484 __pn_ = __p.__pn_;485 return *this;486 }487 if (__p.has_root_directory()) {488 path __root_name_str = root_name();489 __pn_ = __root_name_str.native();490 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);491 return *this;492 }493 if (has_filename() || (!has_root_directory() && is_absolute()))494 __pn_ += preferred_separator;495 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);496 return *this;497 }498 template <class _Source>499 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator/=(const _Source& __src) {500 return operator/=(path(__src));501 }502 503 template <class _Source>504 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) {505 return operator/=(path(__src));506 }507 508 template <class _InputIt>509 _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) {510 return operator/=(path(__first, __last));511 }512# else513 _LIBCPP_HIDE_FROM_ABI path& operator/=(const path& __p) {514 if (__p.is_absolute()) {515 __pn_ = __p.__pn_;516 return *this;517 }518 if (has_filename())519 __pn_ += preferred_separator;520 __pn_ += __p.native();521 return *this;522 }523 524 // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src525 // is known at compile time to be "/' since the user almost certainly intended526 // to append a separator instead of overwriting the path with "/"527 template <class _Source>528 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator/=(const _Source& __src) {529 return this->append(__src);530 }531 532 template <class _Source>533 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> append(const _Source& __src) {534 using _Traits = __is_pathable<_Source>;535 using _CVT = _PathCVT<_SourceChar<_Source> >;536 bool __source_is_absolute = filesystem::__is_separator(_Traits::__first_or_null(__src));537 if (__source_is_absolute)538 __pn_.clear();539 else if (has_filename())540 __pn_ += preferred_separator;541 _CVT::__append_source(__pn_, __src);542 return *this;543 }544 545 template <class _InputIt>546 _LIBCPP_HIDE_FROM_ABI path& append(_InputIt __first, _InputIt __last) {547 typedef typename iterator_traits<_InputIt>::value_type _ItVal;548 static_assert(__can_convert_char<_ItVal>::value, "Must convertible");549 using _CVT = _PathCVT<_ItVal>;550 if (__first != __last && filesystem::__is_separator(*__first))551 __pn_.clear();552 else if (has_filename())553 __pn_ += preferred_separator;554 _CVT::__append_range(__pn_, __first, __last);555 return *this;556 }557# endif558 559 // concatenation560 _LIBCPP_HIDE_FROM_ABI path& operator+=(const path& __x) {561 __pn_ += __x.__pn_;562 return *this;563 }564 565 _LIBCPP_HIDE_FROM_ABI path& operator+=(const string_type& __x) {566 __pn_ += __x;567 return *this;568 }569 570 _LIBCPP_HIDE_FROM_ABI path& operator+=(__string_view __x) {571 __pn_ += __x;572 return *this;573 }574 575 _LIBCPP_HIDE_FROM_ABI path& operator+=(const value_type* __x) {576 __pn_ += __x;577 return *this;578 }579 580 _LIBCPP_HIDE_FROM_ABI path& operator+=(value_type __x) {581 __pn_ += __x;582 return *this;583 }584 585 template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0>586 _LIBCPP_HIDE_FROM_ABI path& operator+=(_ECharT __x) {587 _PathCVT<_ECharT>::__append_source(__pn_, basic_string_view<_ECharT>(std::addressof(__x), 1));588 return *this;589 }590 591 template <class _Source>592 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> operator+=(const _Source& __x) {593 return this->concat(__x);594 }595 596 template <class _Source>597 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> concat(const _Source& __x) {598 _SourceCVT<_Source>::__append_source(__pn_, __x);599 return *this;600 }601 602 template <class _InputIt>603 _LIBCPP_HIDE_FROM_ABI path& concat(_InputIt __first, _InputIt __last) {604 typedef typename iterator_traits<_InputIt>::value_type _ItVal;605 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);606 return *this;607 }608 609 // modifiers610 _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __pn_.clear(); }611 612 _LIBCPP_HIDE_FROM_ABI path& make_preferred() {613# if defined(_LIBCPP_WIN32API)614 std::replace(__pn_.begin(), __pn_.end(), L'/', L'\\');615# endif616 return *this;617 }618 619 _LIBCPP_HIDE_FROM_ABI path& remove_filename() {620 auto __fname = __filename();621 if (!__fname.empty())622 __pn_.erase(__fname.data() - __pn_.data());623 return *this;624 }625 626 _LIBCPP_HIDE_FROM_ABI path& replace_filename(const path& __replacement) {627 remove_filename();628 return (*this /= __replacement);629 }630 631 path& replace_extension(const path& __replacement = path());632 633 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept {634 return __lhs.__compare(__rhs.__pn_) == 0;635 }636# if _LIBCPP_STD_VER <= 17637 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept {638 return __lhs.__compare(__rhs.__pn_) != 0;639 }640 friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept {641 return __lhs.__compare(__rhs.__pn_) < 0;642 }643 friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept {644 return __lhs.__compare(__rhs.__pn_) <= 0;645 }646 friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept {647 return __lhs.__compare(__rhs.__pn_) > 0;648 }649 friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept {650 return __lhs.__compare(__rhs.__pn_) >= 0;651 }652# else // _LIBCPP_STD_VER <= 17653 friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const path& __lhs, const path& __rhs) noexcept {654 return __lhs.__compare(__rhs.__pn_) <=> 0;655 }656# endif // _LIBCPP_STD_VER <= 17657 658 friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) {659 path __result(__lhs);660 __result /= __rhs;661 return __result;662 }663 664 _LIBCPP_HIDE_FROM_ABI void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); }665 666 // private helper to allow reserving memory in the path667 _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __s) { __pn_.reserve(__s); }668 669 // native format observers670 _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept { return __pn_; }671 672 _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept { return __pn_.c_str(); }673 674 _LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; }675 676# if defined(_LIBCPP_WIN32API)677 _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return __pn_; }678 679 _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const {680 std::wstring __s;681 __s.resize(__pn_.size());682 std::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/');683 return __s;684 }685 686# if _LIBCPP_HAS_LOCALIZATION687 template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> >688 _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const {689 using _Str = basic_string<_ECharT, _Traits, _Allocator>;690 _Str __s(__a);691 __s.reserve(__pn_.size());692 _PathExport<_ECharT>::__append(__s, __pn_);693 return __s;694 }695 696 _LIBCPP_HIDE_FROM_ABI std::string string() const { return string<char>(); }697 _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const {698 using _CVT = __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__>;699 __u8_string __s;700 __s.reserve(__pn_.size());701 _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());702 return __s;703 }704 705 _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); }706 _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); }707 708 // generic format observers709 template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> >710 _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator>711 generic_string(const _Allocator& __a = _Allocator()) const {712 using _Str = basic_string<_ECharT, _Traits, _Allocator>;713 _Str __s = string<_ECharT, _Traits, _Allocator>(__a);714 // Note: This (and generic_u8string below) is slightly suboptimal as715 // it iterates twice over the string; once to convert it to the right716 // character type, and once to replace path delimiters.717 std::replace(__s.begin(), __s.end(), static_cast<_ECharT>('\\'), static_cast<_ECharT>('/'));718 return __s;719 }720 721 _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return generic_string<char>(); }722 _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return generic_string<char16_t>(); }723 _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return generic_string<char32_t>(); }724 _LIBCPP_HIDE_FROM_ABI __u8_string generic_u8string() const {725 __u8_string __s = u8string();726 std::replace(__s.begin(), __s.end(), '\\', '/');727 return __s;728 }729# endif // _LIBCPP_HAS_LOCALIZATION730# else /* _LIBCPP_WIN32API */731 732 _LIBCPP_HIDE_FROM_ABI std::string string() const { return __pn_; }733# if _LIBCPP_HAS_CHAR8_T734 _LIBCPP_HIDE_FROM_ABI std::u8string u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); }735# else736 _LIBCPP_HIDE_FROM_ABI std::string u8string() const { return __pn_; }737# endif738 739# if _LIBCPP_HAS_LOCALIZATION740 template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> >741 _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const {742 using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>;743 using _Str = basic_string<_ECharT, _Traits, _Allocator>;744 _Str __s(__a);745 __s.reserve(__pn_.size());746 _CVT()(std::back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());747 return __s;748 }749 750# if _LIBCPP_HAS_WIDE_CHARACTERS751 _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return string<wchar_t>(); }752# endif753 _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); }754 _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); }755# endif // _LIBCPP_HAS_LOCALIZATION756 757 // generic format observers758 _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return __pn_; }759# if _LIBCPP_HAS_CHAR8_T760 _LIBCPP_HIDE_FROM_ABI std::u8string generic_u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); }761# else762 _LIBCPP_HIDE_FROM_ABI std::string generic_u8string() const { return __pn_; }763# endif764 765# if _LIBCPP_HAS_LOCALIZATION766 template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> >767 _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator>768 generic_string(const _Allocator& __a = _Allocator()) const {769 return string<_ECharT, _Traits, _Allocator>(__a);770 }771 772# if _LIBCPP_HAS_WIDE_CHARACTERS773 _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { return string<wchar_t>(); }774# endif775 _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return string<char16_t>(); }776 _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return string<char32_t>(); }777# endif // _LIBCPP_HAS_LOCALIZATION778# endif /* !_LIBCPP_WIN32API */779 780private:781 int __compare(__string_view) const;782 __string_view __root_name() const;783 __string_view __root_directory() const;784 __string_view __root_path_raw() const;785 __string_view __relative_path() const;786 __string_view __parent_path() const;787 __string_view __filename() const;788 __string_view __stem() const;789 __string_view __extension() const;790 791public:792 // compare793 _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept { return __compare(__p.__pn_); }794 _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return __compare(__s); }795 _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const { return __compare(__s); }796 _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return __compare(__s); }797 798 // decomposition799 _LIBCPP_HIDE_FROM_ABI path root_name() const { return string_type(__root_name()); }800 _LIBCPP_HIDE_FROM_ABI path root_directory() const { return string_type(__root_directory()); }801 _LIBCPP_HIDE_FROM_ABI path root_path() const {802# if defined(_LIBCPP_WIN32API)803 return string_type(__root_path_raw());804# else805 return root_name().append(string_type(__root_directory()));806# endif807 }808 _LIBCPP_HIDE_FROM_ABI path relative_path() const { return string_type(__relative_path()); }809 _LIBCPP_HIDE_FROM_ABI path parent_path() const { return string_type(__parent_path()); }810 _LIBCPP_HIDE_FROM_ABI path filename() const { return string_type(__filename()); }811 _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); }812 _LIBCPP_HIDE_FROM_ABI path extension() const { return string_type(__extension()); }813 814 // query815 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __pn_.empty(); }816 817 _LIBCPP_HIDE_FROM_ABI bool has_root_name() const { return !__root_name().empty(); }818 _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const { return !__root_directory().empty(); }819 _LIBCPP_HIDE_FROM_ABI bool has_root_path() const { return !__root_path_raw().empty(); }820 _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const { return !__relative_path().empty(); }821 _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const { return !__parent_path().empty(); }822 _LIBCPP_HIDE_FROM_ABI bool has_filename() const { return !__filename().empty(); }823 _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); }824 _LIBCPP_HIDE_FROM_ABI bool has_extension() const { return !__extension().empty(); }825 826 _LIBCPP_HIDE_FROM_ABI bool is_absolute() const {827# if defined(_LIBCPP_WIN32API)828 __string_view __root_name_str = __root_name();829 __string_view __root_dir = __root_directory();830 if (__root_name_str.size() == 2 && __root_name_str[1] == ':') {831 // A drive letter with no root directory is relative, e.g. x:example.832 return !__root_dir.empty();833 }834 // If no root name, it's relative, e.g. \example is relative to the current drive835 if (__root_name_str.empty())836 return false;837 if (__root_name_str.size() < 3)838 return false;839 // A server root name, like \\server, is always absolute840 if (__root_name_str[0] != '/' && __root_name_str[0] != '\\')841 return false;842 if (__root_name_str[1] != '/' && __root_name_str[1] != '\\')843 return false;844 // Seems to be a server root name845 return true;846# else847 return has_root_directory();848# endif849 }850 _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); }851 852 // relative paths853 path lexically_normal() const;854 path lexically_relative(const path& __base) const;855 856 _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const {857 path __result = this->lexically_relative(__base);858 if (__result.native().empty())859 return *this;860 return __result;861 }862 863 // iterators864 class iterator;865 typedef iterator const_iterator;866 867 iterator begin() const;868 iterator end() const;869 870# if _LIBCPP_HAS_LOCALIZATION871 template <872 class _CharT,873 class _Traits,874 __enable_if_t<is_same<_CharT, value_type>::value && is_same<_Traits, char_traits<value_type> >::value, int> = 0>875 _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>&876 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {877 __os << std::__quoted(__p.native());878 return __os;879 }880 881 template <882 class _CharT,883 class _Traits,884 __enable_if_t<!is_same<_CharT, value_type>::value || !is_same<_Traits, char_traits<value_type> >::value, int> = 0>885 _LIBCPP_HIDE_FROM_ABI friend basic_ostream<_CharT, _Traits>&886 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {887 __os << std::__quoted(__p.string<_CharT, _Traits>());888 return __os;889 }890 891 template <class _CharT, class _Traits>892 _LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT, _Traits>&893 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) {894 basic_string<_CharT, _Traits> __tmp;895 __is >> std::__quoted(__tmp);896 __p = __tmp;897 return __is;898 }899# endif // _LIBCPP_HAS_LOCALIZATION900 901private:902 inline _LIBCPP_HIDE_FROM_ABI path& __assign_view(__string_view const& __s) {903 __pn_ = string_type(__s);904 return *this;905 }906 string_type __pn_;907};908 909inline _LIBCPP_HIDE_FROM_ABI void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }910 911_LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept;912 913_LIBCPP_END_NAMESPACE_FILESYSTEM914 915_LIBCPP_BEGIN_NAMESPACE_STD916 917template <>918struct hash<filesystem::path> : __unary_function<filesystem::path, size_t> {919 _LIBCPP_HIDE_FROM_ABI size_t operator()(filesystem::path const& __p) const noexcept {920 return filesystem::hash_value(__p);921 }922};923 924_LIBCPP_END_NAMESPACE_STD925 926#endif // _LIBCPP_STD_VER >= 17927 928_LIBCPP_POP_MACROS929 930#endif // _LIBCPP___FILESYSTEM_PATH_H931