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