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