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