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-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___FILESYSTEM_PATH_H 11 #define _LIBCPP___FILESYSTEM_PATH_H 12 13 #include <__algorithm/replace.h> 14 #include <__algorithm/replace_copy.h> 15 #include <__availability> 16 #include <__config> 17 #include <__functional/hash.h> 18 #include <__functional/unary_function.h> 19 #include <__fwd/hash.h> 20 #include <__iterator/back_insert_iterator.h> 21 #include <__iterator/iterator_traits.h> 22 #include <__type_traits/decay.h> 23 #include <__type_traits/is_pointer.h> 24 #include <__type_traits/remove_const.h> 25 #include <__type_traits/remove_pointer.h> 26 #include <cstddef> 27 #include <string> 28 #include <string_view> 29 30 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 31 # include <iomanip> // for quoted 32 # include <locale> 33 #endif 34 35 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 36 # pragma GCC system_header 37 #endif 38 39 #if _LIBCPP_STD_VER >= 17 40 41 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 42 43 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH 44 45 template <class _Tp> 46 struct __can_convert_char { 47 static const bool value = false; 48 }; 49 template <class _Tp> 50 struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {}; 51 template <> 52 struct __can_convert_char<char> { 53 static const bool value = true; 54 using __char_type = char; 55 }; 56 template <> 57 struct __can_convert_char<wchar_t> { 58 static const bool value = true; 59 using __char_type = wchar_t; 60 }; 61 #ifndef _LIBCPP_HAS_NO_CHAR8_T 62 template <> 63 struct __can_convert_char<char8_t> { 64 static const bool value = true; 65 using __char_type = char8_t; 66 }; 67 #endif 68 template <> 69 struct __can_convert_char<char16_t> { 70 static const bool value = true; 71 using __char_type = char16_t; 72 }; 73 template <> 74 struct __can_convert_char<char32_t> { 75 static const bool value = true; 76 using __char_type = char32_t; 77 }; 78 79 template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0> 80 _LIBCPP_HIDE_FROM_ABI 81 bool 82 __is_separator(_ECharT __e) { 83 #if defined(_LIBCPP_WIN32API) 84 return __e == _ECharT('/') || __e == _ECharT('\\'); 85 #else 86 return __e == _ECharT('/'); 87 #endif 88 } 89 90 #ifndef _LIBCPP_HAS_NO_CHAR8_T 91 typedef u8string __u8_string; 92 #else 93 typedef string __u8_string; 94 #endif 95 96 struct _NullSentinel {}; 97 98 template <class _Tp> 99 using _Void = void; 100 101 template <class _Tp, class = void> 102 struct __is_pathable_string : public false_type {}; 103 104 template <class _ECharT, class _Traits, class _Alloc> 105 struct __is_pathable_string< 106 basic_string<_ECharT, _Traits, _Alloc>, 107 _Void<typename __can_convert_char<_ECharT>::__char_type> > 108 : public __can_convert_char<_ECharT> { 109 using _Str = basic_string<_ECharT, _Traits, _Alloc>; 110 111 _LIBCPP_HIDE_FROM_ABI 112 static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } 113 114 _LIBCPP_HIDE_FROM_ABI 115 static _ECharT const* __range_end(_Str const& __s) { 116 return __s.data() + __s.length(); 117 } 118 119 _LIBCPP_HIDE_FROM_ABI 120 static _ECharT __first_or_null(_Str const& __s) { 121 return __s.empty() ? _ECharT{} : __s[0]; 122 } 123 }; 124 125 template <class _ECharT, class _Traits> 126 struct __is_pathable_string< 127 basic_string_view<_ECharT, _Traits>, 128 _Void<typename __can_convert_char<_ECharT>::__char_type> > 129 : public __can_convert_char<_ECharT> { 130 using _Str = basic_string_view<_ECharT, _Traits>; 131 132 _LIBCPP_HIDE_FROM_ABI 133 static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); } 134 135 _LIBCPP_HIDE_FROM_ABI 136 static _ECharT const* __range_end(_Str const& __s) { 137 return __s.data() + __s.length(); 138 } 139 140 _LIBCPP_HIDE_FROM_ABI 141 static _ECharT __first_or_null(_Str const& __s) { 142 return __s.empty() ? _ECharT{} : __s[0]; 143 } 144 }; 145 146 template <class _Source, class _DS = __decay_t<_Source>, 147 class _UnqualPtrType = 148 __remove_const_t<__remove_pointer_t<_DS> >, 149 bool _IsCharPtr = is_pointer<_DS>::value&& 150 __can_convert_char<_UnqualPtrType>::value> 151 struct __is_pathable_char_array : false_type {}; 152 153 template <class _Source, class _ECharT, class _UPtr> 154 struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true> 155 : __can_convert_char<__remove_const_t<_ECharT> > { 156 _LIBCPP_HIDE_FROM_ABI 157 static _ECharT const* __range_begin(const _ECharT* __b) { return __b; } 158 159 _LIBCPP_HIDE_FROM_ABI 160 static _ECharT const* __range_end(const _ECharT* __b) { 161 using _Iter = const _ECharT*; 162 const _ECharT __sentinel = _ECharT{}; 163 _Iter __e = __b; 164 for (; *__e != __sentinel; ++__e) 165 ; 166 return __e; 167 } 168 169 _LIBCPP_HIDE_FROM_ABI 170 static _ECharT __first_or_null(const _ECharT* __b) { return *__b; } 171 }; 172 173 template <class _Iter, bool _IsIt = __has_input_iterator_category<_Iter>::value, 174 class = void> 175 struct __is_pathable_iter : false_type {}; 176 177 template <class _Iter> 178 struct __is_pathable_iter< 179 _Iter, true, 180 _Void<typename __can_convert_char< 181 typename iterator_traits<_Iter>::value_type>::__char_type> > 182 : __can_convert_char<typename iterator_traits<_Iter>::value_type> { 183 using _ECharT = typename iterator_traits<_Iter>::value_type; 184 185 _LIBCPP_HIDE_FROM_ABI 186 static _Iter __range_begin(_Iter __b) { return __b; } 187 188 _LIBCPP_HIDE_FROM_ABI 189 static _NullSentinel __range_end(_Iter) { return _NullSentinel{}; } 190 191 _LIBCPP_HIDE_FROM_ABI 192 static _ECharT __first_or_null(_Iter __b) { return *__b; } 193 }; 194 195 template <class _Tp, bool _IsStringT = __is_pathable_string<_Tp>::value, 196 bool _IsCharIterT = __is_pathable_char_array<_Tp>::value, 197 bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value> 198 struct __is_pathable : false_type { 199 static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false"); 200 }; 201 202 template <class _Tp> 203 struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {}; 204 205 template <class _Tp> 206 struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> { 207 }; 208 209 template <class _Tp> 210 struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {}; 211 212 #if defined(_LIBCPP_WIN32API) 213 typedef wstring __path_string; 214 typedef wchar_t __path_value; 215 #else 216 typedef string __path_string; 217 typedef char __path_value; 218 #endif 219 220 #if defined(_LIBCPP_WIN32API) 221 _LIBCPP_EXPORTED_FROM_ABI size_t __wide_to_char(const wstring&, char*, size_t); 222 _LIBCPP_EXPORTED_FROM_ABI size_t __char_to_wide(const string&, wchar_t*, size_t); 223 #endif 224 225 template <class _ECharT> 226 struct _PathCVT; 227 228 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 229 template <class _ECharT> 230 struct _PathCVT { 231 static_assert(__can_convert_char<_ECharT>::value, 232 "Char type not convertible"); 233 234 typedef __narrow_to_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Narrower; 235 #if defined(_LIBCPP_WIN32API) 236 typedef __widen_from_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Widener; 237 #endif 238 239 _LIBCPP_HIDE_FROM_ABI 240 static void __append_range(__path_string& __dest, _ECharT const* __b, 241 _ECharT const* __e) { 242 #if defined(_LIBCPP_WIN32API) 243 string __utf8; 244 _Narrower()(back_inserter(__utf8), __b, __e); 245 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); 246 #else 247 _Narrower()(back_inserter(__dest), __b, __e); 248 #endif 249 } 250 251 template <class _Iter> 252 _LIBCPP_HIDE_FROM_ABI 253 static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) { 254 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); 255 if (__b == __e) 256 return; 257 basic_string<_ECharT> __tmp(__b, __e); 258 #if defined(_LIBCPP_WIN32API) 259 string __utf8; 260 _Narrower()(back_inserter(__utf8), __tmp.data(), 261 __tmp.data() + __tmp.length()); 262 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); 263 #else 264 _Narrower()(back_inserter(__dest), __tmp.data(), 265 __tmp.data() + __tmp.length()); 266 #endif 267 } 268 269 template <class _Iter> 270 _LIBCPP_HIDE_FROM_ABI 271 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { 272 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload"); 273 const _ECharT __sentinel = _ECharT{}; 274 if (*__b == __sentinel) 275 return; 276 basic_string<_ECharT> __tmp; 277 for (; *__b != __sentinel; ++__b) 278 __tmp.push_back(*__b); 279 #if defined(_LIBCPP_WIN32API) 280 string __utf8; 281 _Narrower()(back_inserter(__utf8), __tmp.data(), 282 __tmp.data() + __tmp.length()); 283 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); 284 #else 285 _Narrower()(back_inserter(__dest), __tmp.data(), 286 __tmp.data() + __tmp.length()); 287 #endif 288 } 289 290 template <class _Source> 291 _LIBCPP_HIDE_FROM_ABI 292 static void __append_source(__path_string& __dest, _Source const& __s) { 293 using _Traits = __is_pathable<_Source>; 294 __append_range(__dest, _Traits::__range_begin(__s), 295 _Traits::__range_end(__s)); 296 } 297 }; 298 #endif // !_LIBCPP_HAS_NO_LOCALIZATION 299 300 template <> 301 struct _PathCVT<__path_value> { 302 303 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0> 304 _LIBCPP_HIDE_FROM_ABI 305 static void 306 __append_range(__path_string& __dest, _Iter __b, _Iter __e) { 307 for (; __b != __e; ++__b) 308 __dest.push_back(*__b); 309 } 310 311 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0> 312 _LIBCPP_HIDE_FROM_ABI 313 static void 314 __append_range(__path_string& __dest, _Iter __b, _Iter __e) { 315 __dest.append(__b, __e); 316 } 317 318 template <class _Iter> 319 _LIBCPP_HIDE_FROM_ABI 320 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { 321 const char __sentinel = char{}; 322 for (; *__b != __sentinel; ++__b) 323 __dest.push_back(*__b); 324 } 325 326 template <class _Source> 327 _LIBCPP_HIDE_FROM_ABI 328 static void __append_source(__path_string& __dest, _Source const& __s) { 329 using _Traits = __is_pathable<_Source>; 330 __append_range(__dest, _Traits::__range_begin(__s), 331 _Traits::__range_end(__s)); 332 } 333 }; 334 335 #if defined(_LIBCPP_WIN32API) 336 template <> 337 struct _PathCVT<char> { 338 339 _LIBCPP_HIDE_FROM_ABI 340 static void 341 __append_string(__path_string& __dest, const basic_string<char> &__str) { 342 size_t __size = __char_to_wide(__str, nullptr, 0); 343 size_t __pos = __dest.size(); 344 __dest.resize(__pos + __size); 345 __char_to_wide(__str, const_cast<__path_value*>(__dest.data()) + __pos, __size); 346 } 347 348 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0> 349 _LIBCPP_HIDE_FROM_ABI 350 static void 351 __append_range(__path_string& __dest, _Iter __b, _Iter __e) { 352 basic_string<char> __tmp(__b, __e); 353 __append_string(__dest, __tmp); 354 } 355 356 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0> 357 _LIBCPP_HIDE_FROM_ABI 358 static void 359 __append_range(__path_string& __dest, _Iter __b, _Iter __e) { 360 basic_string<char> __tmp(__b, __e); 361 __append_string(__dest, __tmp); 362 } 363 364 template <class _Iter> 365 _LIBCPP_HIDE_FROM_ABI 366 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) { 367 const char __sentinel = char{}; 368 basic_string<char> __tmp; 369 for (; *__b != __sentinel; ++__b) 370 __tmp.push_back(*__b); 371 __append_string(__dest, __tmp); 372 } 373 374 template <class _Source> 375 _LIBCPP_HIDE_FROM_ABI 376 static void __append_source(__path_string& __dest, _Source const& __s) { 377 using _Traits = __is_pathable<_Source>; 378 __append_range(__dest, _Traits::__range_begin(__s), 379 _Traits::__range_end(__s)); 380 } 381 }; 382 383 template <class _ECharT> 384 struct _PathExport { 385 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower; 386 typedef __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Widener; 387 388 template <class _Str> 389 _LIBCPP_HIDE_FROM_ABI 390 static void __append(_Str& __dest, const __path_string& __src) { 391 string __utf8; 392 _Narrower()(back_inserter(__utf8), __src.data(), __src.data() + __src.size()); 393 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size()); 394 } 395 }; 396 397 template <> 398 struct _PathExport<char> { 399 template <class _Str> 400 _LIBCPP_HIDE_FROM_ABI 401 static void __append(_Str& __dest, const __path_string& __src) { 402 size_t __size = __wide_to_char(__src, nullptr, 0); 403 size_t __pos = __dest.size(); 404 __dest.resize(__size); 405 __wide_to_char(__src, const_cast<char*>(__dest.data()) + __pos, __size); 406 } 407 }; 408 409 template <> 410 struct _PathExport<wchar_t> { 411 template <class _Str> 412 _LIBCPP_HIDE_FROM_ABI 413 static void __append(_Str& __dest, const __path_string& __src) { 414 __dest.append(__src.begin(), __src.end()); 415 } 416 }; 417 418 template <> 419 struct _PathExport<char16_t> { 420 template <class _Str> 421 _LIBCPP_HIDE_FROM_ABI 422 static void __append(_Str& __dest, const __path_string& __src) { 423 __dest.append(__src.begin(), __src.end()); 424 } 425 }; 426 427 #ifndef _LIBCPP_HAS_NO_CHAR8_T 428 template <> 429 struct _PathExport<char8_t> { 430 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower; 431 432 template <class _Str> 433 _LIBCPP_HIDE_FROM_ABI 434 static void __append(_Str& __dest, const __path_string& __src) { 435 _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size()); 436 } 437 }; 438 #endif /* !_LIBCPP_HAS_NO_CHAR8_T */ 439 #endif /* _LIBCPP_WIN32API */ 440 441 class _LIBCPP_EXPORTED_FROM_ABI path { 442 template <class _SourceOrIter, class _Tp = path&> 443 using _EnableIfPathable = __enable_if_t<__is_pathable<_SourceOrIter>::value, _Tp>; 444 445 template <class _Tp> 446 using _SourceChar = typename __is_pathable<_Tp>::__char_type; 447 448 template <class _Tp> 449 using _SourceCVT = _PathCVT<_SourceChar<_Tp> >; 450 451 public: 452 #if defined(_LIBCPP_WIN32API) 453 typedef wchar_t value_type; 454 static constexpr value_type preferred_separator = L'\\'; 455 #else 456 typedef char value_type; 457 static constexpr value_type preferred_separator = '/'; 458 #endif 459 typedef basic_string<value_type> string_type; 460 typedef basic_string_view<value_type> __string_view; 461 462 enum format : unsigned char { 463 auto_format, 464 native_format, 465 generic_format 466 }; 467 468 // constructors and destructor 469 _LIBCPP_HIDE_FROM_ABI path() noexcept {} 470 _LIBCPP_HIDE_FROM_ABI path(const path& __p) : __pn_(__p.__pn_) {} 471 _LIBCPP_HIDE_FROM_ABI path(path&& __p) noexcept 472 : __pn_(_VSTD::move(__p.__pn_)) {} 473 474 _LIBCPP_HIDE_FROM_ABI 475 path(string_type&& __s, format = format::auto_format) noexcept 476 : __pn_(_VSTD::move(__s)) {} 477 478 template <class _Source, class = _EnableIfPathable<_Source, void> > 479 _LIBCPP_HIDE_FROM_ABI 480 path(const _Source& __src, format = format::auto_format) { 481 _SourceCVT<_Source>::__append_source(__pn_, __src); 482 } 483 484 template <class _InputIt> 485 _LIBCPP_HIDE_FROM_ABI 486 path(_InputIt __first, _InputIt __last, format = format::auto_format) { 487 typedef typename iterator_traits<_InputIt>::value_type _ItVal; 488 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); 489 } 490 491 /* 492 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 493 // TODO Implement locale conversions. 494 template <class _Source, class = _EnableIfPathable<_Source, void> > 495 path(const _Source& __src, const locale& __loc, format = format::auto_format); 496 template <class _InputIt> 497 path(_InputIt __first, _InputIt _last, const locale& __loc, 498 format = format::auto_format); 499 #endif 500 */ 501 502 _LIBCPP_HIDE_FROM_ABI 503 ~path() = default; 504 505 // assignments 506 _LIBCPP_HIDE_FROM_ABI 507 path& operator=(const path& __p) { 508 __pn_ = __p.__pn_; 509 return *this; 510 } 511 512 _LIBCPP_HIDE_FROM_ABI 513 path& operator=(path&& __p) noexcept { 514 __pn_ = _VSTD::move(__p.__pn_); 515 return *this; 516 } 517 518 _LIBCPP_HIDE_FROM_ABI 519 path& operator=(string_type&& __s) noexcept { 520 __pn_ = _VSTD::move(__s); 521 return *this; 522 } 523 524 _LIBCPP_HIDE_FROM_ABI 525 path& assign(string_type&& __s) noexcept { 526 __pn_ = _VSTD::move(__s); 527 return *this; 528 } 529 530 template <class _Source> 531 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> 532 operator=(const _Source& __src) { 533 return this->assign(__src); 534 } 535 536 template <class _Source> 537 _LIBCPP_HIDE_FROM_ABI 538 _EnableIfPathable<_Source> assign(const _Source& __src) { 539 __pn_.clear(); 540 _SourceCVT<_Source>::__append_source(__pn_, __src); 541 return *this; 542 } 543 544 template <class _InputIt> 545 _LIBCPP_HIDE_FROM_ABI 546 path& assign(_InputIt __first, _InputIt __last) { 547 typedef typename iterator_traits<_InputIt>::value_type _ItVal; 548 __pn_.clear(); 549 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); 550 return *this; 551 } 552 553 public: 554 // appends 555 #if defined(_LIBCPP_WIN32API) 556 _LIBCPP_HIDE_FROM_ABI 557 path& operator/=(const path& __p) { 558 auto __p_root_name = __p.__root_name(); 559 auto __p_root_name_size = __p_root_name.size(); 560 if (__p.is_absolute() || 561 (!__p_root_name.empty() && __p_root_name != __string_view(root_name().__pn_))) { 562 __pn_ = __p.__pn_; 563 return *this; 564 } 565 if (__p.has_root_directory()) { 566 path __root_name_str = root_name(); 567 __pn_ = __root_name_str.native(); 568 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); 569 return *this; 570 } 571 if (has_filename() || (!has_root_directory() && is_absolute())) 572 __pn_ += preferred_separator; 573 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); 574 return *this; 575 } 576 template <class _Source> 577 _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source> 578 operator/=(const _Source& __src) { 579 return operator/=(path(__src)); 580 } 581 582 template <class _Source> 583 _LIBCPP_HIDE_FROM_ABI 584 _EnableIfPathable<_Source> append(const _Source& __src) { 585 return operator/=(path(__src)); 586 } 587 588 template <class _InputIt> 589 _LIBCPP_HIDE_FROM_ABI 590 path& append(_InputIt __first, _InputIt __last) { 591 return operator/=(path(__first, __last)); 592 } 593 #else 594 _LIBCPP_HIDE_FROM_ABI 595 path& operator/=(const path& __p) { 596 if (__p.is_absolute()) { 597 __pn_ = __p.__pn_; 598 return *this; 599 } 600 if (has_filename()) 601 __pn_ += preferred_separator; 602 __pn_ += __p.native(); 603 return *this; 604 } 605 606 // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src 607 // is known at compile time to be "/' since the user almost certainly intended 608 // to append a separator instead of overwriting the path with "/" 609 template <class _Source> 610 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source> 611 operator/=(const _Source& __src) { 612 return this->append(__src); 613 } 614 615 template <class _Source> 616 _LIBCPP_HIDE_FROM_ABI 617 _EnableIfPathable<_Source> append(const _Source& __src) { 618 using _Traits = __is_pathable<_Source>; 619 using _CVT = _PathCVT<_SourceChar<_Source> >; 620 bool __source_is_absolute = filesystem::__is_separator(_Traits::__first_or_null(__src)); 621 if (__source_is_absolute) 622 __pn_.clear(); 623 else if (has_filename()) 624 __pn_ += preferred_separator; 625 _CVT::__append_source(__pn_, __src); 626 return *this; 627 } 628 629 template <class _InputIt> 630 _LIBCPP_HIDE_FROM_ABI 631 path& append(_InputIt __first, _InputIt __last) { 632 typedef typename iterator_traits<_InputIt>::value_type _ItVal; 633 static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); 634 using _CVT = _PathCVT<_ItVal>; 635 if (__first != __last && filesystem::__is_separator(*__first)) 636 __pn_.clear(); 637 else if (has_filename()) 638 __pn_ += preferred_separator; 639 _CVT::__append_range(__pn_, __first, __last); 640 return *this; 641 } 642 #endif 643 644 // concatenation 645 _LIBCPP_HIDE_FROM_ABI 646 path& operator+=(const path& __x) { 647 __pn_ += __x.__pn_; 648 return *this; 649 } 650 651 _LIBCPP_HIDE_FROM_ABI 652 path& operator+=(const string_type& __x) { 653 __pn_ += __x; 654 return *this; 655 } 656 657 _LIBCPP_HIDE_FROM_ABI 658 path& operator+=(__string_view __x) { 659 __pn_ += __x; 660 return *this; 661 } 662 663 _LIBCPP_HIDE_FROM_ABI 664 path& operator+=(const value_type* __x) { 665 __pn_ += __x; 666 return *this; 667 } 668 669 _LIBCPP_HIDE_FROM_ABI 670 path& operator+=(value_type __x) { 671 __pn_ += __x; 672 return *this; 673 } 674 675 template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0> 676 _LIBCPP_HIDE_FROM_ABI 677 path& 678 operator+=(_ECharT __x) { 679 _PathCVT<_ECharT>::__append_source(__pn_, 680 basic_string_view<_ECharT>(&__x, 1)); 681 return *this; 682 } 683 684 template <class _Source> 685 _LIBCPP_HIDE_FROM_ABI 686 _EnableIfPathable<_Source> operator+=(const _Source& __x) { 687 return this->concat(__x); 688 } 689 690 template <class _Source> 691 _LIBCPP_HIDE_FROM_ABI 692 _EnableIfPathable<_Source> concat(const _Source& __x) { 693 _SourceCVT<_Source>::__append_source(__pn_, __x); 694 return *this; 695 } 696 697 template <class _InputIt> 698 _LIBCPP_HIDE_FROM_ABI 699 path& concat(_InputIt __first, _InputIt __last) { 700 typedef typename iterator_traits<_InputIt>::value_type _ItVal; 701 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last); 702 return *this; 703 } 704 705 // modifiers 706 _LIBCPP_HIDE_FROM_ABI 707 void clear() noexcept { __pn_.clear(); } 708 709 _LIBCPP_HIDE_FROM_ABI 710 path& make_preferred() { 711 #if defined(_LIBCPP_WIN32API) 712 _VSTD::replace(__pn_.begin(), __pn_.end(), L'/', L'\\'); 713 #endif 714 return *this; 715 } 716 717 _LIBCPP_HIDE_FROM_ABI 718 path& remove_filename() { 719 auto __fname = __filename(); 720 if (!__fname.empty()) 721 __pn_.erase(__fname.data() - __pn_.data()); 722 return *this; 723 } 724 725 _LIBCPP_HIDE_FROM_ABI 726 path& replace_filename(const path& __replacement) { 727 remove_filename(); 728 return (*this /= __replacement); 729 } 730 731 path& replace_extension(const path& __replacement = path()); 732 733 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept { 734 return __lhs.__compare(__rhs.__pn_) == 0; 735 } 736 # if _LIBCPP_STD_VER <= 17 737 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept { 738 return __lhs.__compare(__rhs.__pn_) != 0; 739 } 740 friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept { 741 return __lhs.__compare(__rhs.__pn_) < 0; 742 } 743 friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept { 744 return __lhs.__compare(__rhs.__pn_) <= 0; 745 } 746 friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept { 747 return __lhs.__compare(__rhs.__pn_) > 0; 748 } 749 friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept { 750 return __lhs.__compare(__rhs.__pn_) >= 0; 751 } 752 # else // _LIBCPP_STD_VER <= 17 753 friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const path& __lhs, const path& __rhs) noexcept { 754 return __lhs.__compare(__rhs.__pn_) <=> 0; 755 } 756 # endif // _LIBCPP_STD_VER <= 17 757 758 friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) { 759 path __result(__lhs); 760 __result /= __rhs; 761 return __result; 762 } 763 764 _LIBCPP_HIDE_FROM_ABI 765 void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); } 766 767 // private helper to allow reserving memory in the path 768 _LIBCPP_HIDE_FROM_ABI 769 void __reserve(size_t __s) { __pn_.reserve(__s); } 770 771 // native format observers 772 _LIBCPP_HIDE_FROM_ABI 773 const string_type& native() const noexcept { return __pn_; } 774 775 _LIBCPP_HIDE_FROM_ABI 776 const value_type* c_str() const noexcept { return __pn_.c_str(); } 777 778 _LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; } 779 780 #if defined(_LIBCPP_WIN32API) 781 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring wstring() const { return __pn_; } 782 783 _LIBCPP_HIDE_FROM_ABI 784 _VSTD::wstring generic_wstring() const { 785 _VSTD::wstring __s; 786 __s.resize(__pn_.size()); 787 _VSTD::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/'); 788 return __s; 789 } 790 791 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 792 template <class _ECharT, class _Traits = char_traits<_ECharT>, 793 class _Allocator = allocator<_ECharT> > 794 _LIBCPP_HIDE_FROM_ABI 795 basic_string<_ECharT, _Traits, _Allocator> 796 string(const _Allocator& __a = _Allocator()) const { 797 using _Str = basic_string<_ECharT, _Traits, _Allocator>; 798 _Str __s(__a); 799 __s.reserve(__pn_.size()); 800 _PathExport<_ECharT>::__append(__s, __pn_); 801 return __s; 802 } 803 804 _LIBCPP_HIDE_FROM_ABI _VSTD::string string() const { 805 return string<char>(); 806 } 807 _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const { 808 using _CVT = __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__>; 809 __u8_string __s; 810 __s.reserve(__pn_.size()); 811 _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); 812 return __s; 813 } 814 815 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string u16string() const { 816 return string<char16_t>(); 817 } 818 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string u32string() const { 819 return string<char32_t>(); 820 } 821 822 // generic format observers 823 template <class _ECharT, class _Traits = char_traits<_ECharT>, 824 class _Allocator = allocator<_ECharT> > 825 _LIBCPP_HIDE_FROM_ABI 826 basic_string<_ECharT, _Traits, _Allocator> 827 generic_string(const _Allocator& __a = _Allocator()) const { 828 using _Str = basic_string<_ECharT, _Traits, _Allocator>; 829 _Str __s = string<_ECharT, _Traits, _Allocator>(__a); 830 // Note: This (and generic_u8string below) is slightly suboptimal as 831 // it iterates twice over the string; once to convert it to the right 832 // character type, and once to replace path delimiters. 833 _VSTD::replace(__s.begin(), __s.end(), 834 static_cast<_ECharT>('\\'), static_cast<_ECharT>('/')); 835 return __s; 836 } 837 838 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_string() const { return generic_string<char>(); } 839 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string generic_u16string() const { return generic_string<char16_t>(); } 840 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string generic_u32string() const { return generic_string<char32_t>(); } 841 _LIBCPP_HIDE_FROM_ABI 842 __u8_string generic_u8string() const { 843 __u8_string __s = u8string(); 844 _VSTD::replace(__s.begin(), __s.end(), '\\', '/'); 845 return __s; 846 } 847 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ 848 #else /* _LIBCPP_WIN32API */ 849 850 _LIBCPP_HIDE_FROM_ABI _VSTD::string string() const { return __pn_; } 851 #ifndef _LIBCPP_HAS_NO_CHAR8_T 852 _LIBCPP_HIDE_FROM_ABI _VSTD::u8string u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); } 853 #else 854 _LIBCPP_HIDE_FROM_ABI _VSTD::string u8string() const { return __pn_; } 855 #endif 856 857 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 858 template <class _ECharT, class _Traits = char_traits<_ECharT>, 859 class _Allocator = allocator<_ECharT> > 860 _LIBCPP_HIDE_FROM_ABI 861 basic_string<_ECharT, _Traits, _Allocator> 862 string(const _Allocator& __a = _Allocator()) const { 863 using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>; 864 using _Str = basic_string<_ECharT, _Traits, _Allocator>; 865 _Str __s(__a); 866 __s.reserve(__pn_.size()); 867 _CVT()(std::back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size()); 868 return __s; 869 } 870 871 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 872 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring wstring() const { 873 return string<wchar_t>(); 874 } 875 #endif 876 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string u16string() const { 877 return string<char16_t>(); 878 } 879 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string u32string() const { 880 return string<char32_t>(); 881 } 882 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ 883 884 // generic format observers 885 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_string() const { return __pn_; } 886 #ifndef _LIBCPP_HAS_NO_CHAR8_T 887 _LIBCPP_HIDE_FROM_ABI _VSTD::u8string generic_u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); } 888 #else 889 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_u8string() const { return __pn_; } 890 #endif 891 892 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 893 template <class _ECharT, class _Traits = char_traits<_ECharT>, 894 class _Allocator = allocator<_ECharT> > 895 _LIBCPP_HIDE_FROM_ABI 896 basic_string<_ECharT, _Traits, _Allocator> 897 generic_string(const _Allocator& __a = _Allocator()) const { 898 return string<_ECharT, _Traits, _Allocator>(__a); 899 } 900 901 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 902 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring generic_wstring() const { return string<wchar_t>(); } 903 #endif 904 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string generic_u16string() const { return string<char16_t>(); } 905 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string generic_u32string() const { return string<char32_t>(); } 906 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ 907 #endif /* !_LIBCPP_WIN32API */ 908 909 private: 910 int __compare(__string_view) const; 911 __string_view __root_name() const; 912 __string_view __root_directory() const; 913 __string_view __root_path_raw() const; 914 __string_view __relative_path() const; 915 __string_view __parent_path() const; 916 __string_view __filename() const; 917 __string_view __stem() const; 918 __string_view __extension() const; 919 920 public: 921 // compare 922 _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept { 923 return __compare(__p.__pn_); 924 } 925 _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { 926 return __compare(__s); 927 } 928 _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const { 929 return __compare(__s); 930 } 931 _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { 932 return __compare(__s); 933 } 934 935 // decomposition 936 _LIBCPP_HIDE_FROM_ABI path root_name() const { 937 return string_type(__root_name()); 938 } 939 _LIBCPP_HIDE_FROM_ABI path root_directory() const { 940 return string_type(__root_directory()); 941 } 942 _LIBCPP_HIDE_FROM_ABI path root_path() const { 943 #if defined(_LIBCPP_WIN32API) 944 return string_type(__root_path_raw()); 945 #else 946 return root_name().append(string_type(__root_directory())); 947 #endif 948 } 949 _LIBCPP_HIDE_FROM_ABI path relative_path() const { 950 return string_type(__relative_path()); 951 } 952 _LIBCPP_HIDE_FROM_ABI path parent_path() const { 953 return string_type(__parent_path()); 954 } 955 _LIBCPP_HIDE_FROM_ABI path filename() const { 956 return string_type(__filename()); 957 } 958 _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); } 959 _LIBCPP_HIDE_FROM_ABI path extension() const { 960 return string_type(__extension()); 961 } 962 963 // query 964 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI bool 965 empty() const noexcept { 966 return __pn_.empty(); 967 } 968 969 _LIBCPP_HIDE_FROM_ABI bool has_root_name() const { 970 return !__root_name().empty(); 971 } 972 _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const { 973 return !__root_directory().empty(); 974 } 975 _LIBCPP_HIDE_FROM_ABI bool has_root_path() const { 976 return !__root_path_raw().empty(); 977 } 978 _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const { 979 return !__relative_path().empty(); 980 } 981 _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const { 982 return !__parent_path().empty(); 983 } 984 _LIBCPP_HIDE_FROM_ABI bool has_filename() const { 985 return !__filename().empty(); 986 } 987 _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); } 988 _LIBCPP_HIDE_FROM_ABI bool has_extension() const { 989 return !__extension().empty(); 990 } 991 992 _LIBCPP_HIDE_FROM_ABI bool is_absolute() const { 993 #if defined(_LIBCPP_WIN32API) 994 __string_view __root_name_str = __root_name(); 995 __string_view __root_dir = __root_directory(); 996 if (__root_name_str.size() == 2 && __root_name_str[1] == ':') { 997 // A drive letter with no root directory is relative, e.g. x:example. 998 return !__root_dir.empty(); 999 } 1000 // If no root name, it's relative, e.g. \example is relative to the current drive 1001 if (__root_name_str.empty()) 1002 return false; 1003 if (__root_name_str.size() < 3) 1004 return false; 1005 // A server root name, like \\server, is always absolute 1006 if (__root_name_str[0] != '/' && __root_name_str[0] != '\\') 1007 return false; 1008 if (__root_name_str[1] != '/' && __root_name_str[1] != '\\') 1009 return false; 1010 // Seems to be a server root name 1011 return true; 1012 #else 1013 return has_root_directory(); 1014 #endif 1015 } 1016 _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); } 1017 1018 // relative paths 1019 path lexically_normal() const; 1020 path lexically_relative(const path& __base) const; 1021 1022 _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const { 1023 path __result = this->lexically_relative(__base); 1024 if (__result.native().empty()) 1025 return *this; 1026 return __result; 1027 } 1028 1029 // iterators 1030 class _LIBCPP_EXPORTED_FROM_ABI iterator; 1031 typedef iterator const_iterator; 1032 1033 iterator begin() const; 1034 iterator end() const; 1035 1036 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 1037 template <class _CharT, class _Traits, __enable_if_t<is_same<_CharT, value_type>::value && 1038 is_same<_Traits, char_traits<value_type> >::value, int> = 0> 1039 _LIBCPP_HIDE_FROM_ABI friend 1040 basic_ostream<_CharT, _Traits>& 1041 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { 1042 __os << _VSTD::__quoted(__p.native()); 1043 return __os; 1044 } 1045 1046 template <class _CharT, class _Traits, __enable_if_t<!is_same<_CharT, value_type>::value || 1047 !is_same<_Traits, char_traits<value_type> >::value, int> = 0> 1048 _LIBCPP_HIDE_FROM_ABI friend 1049 basic_ostream<_CharT, _Traits>& 1050 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) { 1051 __os << _VSTD::__quoted(__p.string<_CharT, _Traits>()); 1052 return __os; 1053 } 1054 1055 template <class _CharT, class _Traits> 1056 _LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT, _Traits>& 1057 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) { 1058 basic_string<_CharT, _Traits> __tmp; 1059 __is >> _VSTD::__quoted(__tmp); 1060 __p = __tmp; 1061 return __is; 1062 } 1063 #endif // !_LIBCPP_HAS_NO_LOCALIZATION 1064 1065 private: 1066 inline _LIBCPP_HIDE_FROM_ABI path& __assign_view(__string_view const& __s) { 1067 __pn_ = string_type(__s); 1068 return *this; 1069 } 1070 string_type __pn_; 1071 }; 1072 1073 inline _LIBCPP_HIDE_FROM_ABI void swap(path& __lhs, path& __rhs) noexcept { 1074 __lhs.swap(__rhs); 1075 } 1076 1077 _LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept; 1078 1079 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP 1080 1081 _LIBCPP_END_NAMESPACE_FILESYSTEM 1082 1083 _LIBCPP_BEGIN_NAMESPACE_STD 1084 1085 template <> 1086 struct _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY hash<filesystem::path> : __unary_function<filesystem::path, size_t> { 1087 _LIBCPP_HIDE_FROM_ABI size_t operator()(filesystem::path const& __p) const noexcept { 1088 return filesystem::hash_value(__p); 1089 } 1090 }; 1091 1092 _LIBCPP_END_NAMESPACE_STD 1093 1094 #endif // _LIBCPP_STD_VER >= 17 1095 1096 #endif // _LIBCPP___FILESYSTEM_PATH_H 1097