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