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