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