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