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