Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / include / __filesystem / path.h
blob8a9350be2a00f775c806d8736d7b0045d761c536
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 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___FILESYSTEM_PATH_H
11 #define _LIBCPP___FILESYSTEM_PATH_H
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>
30 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
31 # include <iomanip> // for quoted
32 # include <locale>
33 #endif
35 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
36 # pragma GCC system_header
37 #endif
39 #ifndef _LIBCPP_CXX03_LANG
41 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
43 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH
45 template <class _Tp>
46 struct __can_convert_char {
47 static const bool value = false;
49 template <class _Tp>
50 struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};
51 template <>
52 struct __can_convert_char<char> {
53 static const bool value = true;
54 using __char_type = char;
56 template <>
57 struct __can_convert_char<wchar_t> {
58 static const bool value = true;
59 using __char_type = wchar_t;
61 #ifndef _LIBCPP_HAS_NO_CHAR8_T
62 template <>
63 struct __can_convert_char<char8_t> {
64 static const bool value = true;
65 using __char_type = char8_t;
67 #endif
68 template <>
69 struct __can_convert_char<char16_t> {
70 static const bool value = true;
71 using __char_type = char16_t;
73 template <>
74 struct __can_convert_char<char32_t> {
75 static const bool value = true;
76 using __char_type = char32_t;
79 template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0>
80 _LIBCPP_HIDE_FROM_ABI
81 bool
82 __is_separator(_ECharT __e) {
83 #if defined(_LIBCPP_WIN32API)
84 return __e == _ECharT('/') || __e == _ECharT('\\');
85 #else
86 return __e == _ECharT('/');
87 #endif
90 #ifndef _LIBCPP_HAS_NO_CHAR8_T
91 typedef u8string __u8_string;
92 #else
93 typedef string __u8_string;
94 #endif
96 struct _NullSentinel {};
98 template <class _Tp>
99 using _Void = void;
101 template <class _Tp, class = void>
102 struct __is_pathable_string : public false_type {};
104 template <class _ECharT, class _Traits, class _Alloc>
105 struct __is_pathable_string<
106 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>;
111 _LIBCPP_HIDE_FROM_ABI
112 static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
114 _LIBCPP_HIDE_FROM_ABI
115 static _ECharT const* __range_end(_Str const& __s) {
116 return __s.data() + __s.length();
119 _LIBCPP_HIDE_FROM_ABI
120 static _ECharT __first_or_null(_Str const& __s) {
121 return __s.empty() ? _ECharT{} : __s[0];
125 template <class _ECharT, class _Traits>
126 struct __is_pathable_string<
127 basic_string_view<_ECharT, _Traits>,
128 _Void<typename __can_convert_char<_ECharT>::__char_type> >
129 : public __can_convert_char<_ECharT> {
130 using _Str = basic_string_view<_ECharT, _Traits>;
132 _LIBCPP_HIDE_FROM_ABI
133 static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
135 _LIBCPP_HIDE_FROM_ABI
136 static _ECharT const* __range_end(_Str const& __s) {
137 return __s.data() + __s.length();
140 _LIBCPP_HIDE_FROM_ABI
141 static _ECharT __first_or_null(_Str const& __s) {
142 return __s.empty() ? _ECharT{} : __s[0];
146 template <class _Source, class _DS = __decay_t<_Source>,
147 class _UnqualPtrType =
148 __remove_const_t<__remove_pointer_t<_DS> >,
149 bool _IsCharPtr = is_pointer<_DS>::value&&
150 __can_convert_char<_UnqualPtrType>::value>
151 struct __is_pathable_char_array : false_type {};
153 template <class _Source, class _ECharT, class _UPtr>
154 struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true>
155 : __can_convert_char<__remove_const_t<_ECharT> > {
156 _LIBCPP_HIDE_FROM_ABI
157 static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }
159 _LIBCPP_HIDE_FROM_ABI
160 static _ECharT const* __range_end(const _ECharT* __b) {
161 using _Iter = const _ECharT*;
162 const _ECharT __sentinel = _ECharT{};
163 _Iter __e = __b;
164 for (; *__e != __sentinel; ++__e)
166 return __e;
169 _LIBCPP_HIDE_FROM_ABI
170 static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }
173 template <class _Iter, bool _IsIt = __has_input_iterator_category<_Iter>::value,
174 class = void>
175 struct __is_pathable_iter : false_type {};
177 template <class _Iter>
178 struct __is_pathable_iter<
179 _Iter, true,
180 _Void<typename __can_convert_char<
181 typename iterator_traits<_Iter>::value_type>::__char_type> >
182 : __can_convert_char<typename iterator_traits<_Iter>::value_type> {
183 using _ECharT = typename iterator_traits<_Iter>::value_type;
185 _LIBCPP_HIDE_FROM_ABI
186 static _Iter __range_begin(_Iter __b) { return __b; }
188 _LIBCPP_HIDE_FROM_ABI
189 static _NullSentinel __range_end(_Iter) { return _NullSentinel{}; }
191 _LIBCPP_HIDE_FROM_ABI
192 static _ECharT __first_or_null(_Iter __b) { return *__b; }
195 template <class _Tp, bool _IsStringT = __is_pathable_string<_Tp>::value,
196 bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,
197 bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value>
198 struct __is_pathable : false_type {
199 static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
202 template <class _Tp>
203 struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
205 template <class _Tp>
206 struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {
209 template <class _Tp>
210 struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
212 #if defined(_LIBCPP_WIN32API)
213 typedef wstring __path_string;
214 typedef wchar_t __path_value;
215 #else
216 typedef string __path_string;
217 typedef char __path_value;
218 #endif
220 #if defined(_LIBCPP_WIN32API)
221 _LIBCPP_EXPORTED_FROM_ABI size_t __wide_to_char(const wstring&, char*, size_t);
222 _LIBCPP_EXPORTED_FROM_ABI size_t __char_to_wide(const string&, wchar_t*, size_t);
223 #endif
225 template <class _ECharT>
226 struct _PathCVT;
228 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
229 template <class _ECharT>
230 struct _PathCVT {
231 static_assert(__can_convert_char<_ECharT>::value,
232 "Char type not convertible");
234 typedef __narrow_to_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Narrower;
235 #if defined(_LIBCPP_WIN32API)
236 typedef __widen_from_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Widener;
237 #endif
239 _LIBCPP_HIDE_FROM_ABI
240 static void __append_range(__path_string& __dest, _ECharT const* __b,
241 _ECharT const* __e) {
242 #if defined(_LIBCPP_WIN32API)
243 string __utf8;
244 _Narrower()(back_inserter(__utf8), __b, __e);
245 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());
246 #else
247 _Narrower()(back_inserter(__dest), __b, __e);
248 #endif
251 template <class _Iter>
252 _LIBCPP_HIDE_FROM_ABI
253 static void __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
254 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
255 if (__b == __e)
256 return;
257 basic_string<_ECharT> __tmp(__b, __e);
258 #if defined(_LIBCPP_WIN32API)
259 string __utf8;
260 _Narrower()(back_inserter(__utf8), __tmp.data(),
261 __tmp.data() + __tmp.length());
262 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());
263 #else
264 _Narrower()(back_inserter(__dest), __tmp.data(),
265 __tmp.data() + __tmp.length());
266 #endif
269 template <class _Iter>
270 _LIBCPP_HIDE_FROM_ABI
271 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {
272 static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
273 const _ECharT __sentinel = _ECharT{};
274 if (*__b == __sentinel)
275 return;
276 basic_string<_ECharT> __tmp;
277 for (; *__b != __sentinel; ++__b)
278 __tmp.push_back(*__b);
279 #if defined(_LIBCPP_WIN32API)
280 string __utf8;
281 _Narrower()(back_inserter(__utf8), __tmp.data(),
282 __tmp.data() + __tmp.length());
283 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());
284 #else
285 _Narrower()(back_inserter(__dest), __tmp.data(),
286 __tmp.data() + __tmp.length());
287 #endif
290 template <class _Source>
291 _LIBCPP_HIDE_FROM_ABI
292 static void __append_source(__path_string& __dest, _Source const& __s) {
293 using _Traits = __is_pathable<_Source>;
294 __append_range(__dest, _Traits::__range_begin(__s),
295 _Traits::__range_end(__s));
298 #endif // !_LIBCPP_HAS_NO_LOCALIZATION
300 template <>
301 struct _PathCVT<__path_value> {
303 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0>
304 _LIBCPP_HIDE_FROM_ABI
305 static void
306 __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
307 for (; __b != __e; ++__b)
308 __dest.push_back(*__b);
311 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0>
312 _LIBCPP_HIDE_FROM_ABI
313 static void
314 __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
315 __dest.append(__b, __e);
318 template <class _Iter>
319 _LIBCPP_HIDE_FROM_ABI
320 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {
321 const char __sentinel = char{};
322 for (; *__b != __sentinel; ++__b)
323 __dest.push_back(*__b);
326 template <class _Source>
327 _LIBCPP_HIDE_FROM_ABI
328 static void __append_source(__path_string& __dest, _Source const& __s) {
329 using _Traits = __is_pathable<_Source>;
330 __append_range(__dest, _Traits::__range_begin(__s),
331 _Traits::__range_end(__s));
335 #if defined(_LIBCPP_WIN32API)
336 template <>
337 struct _PathCVT<char> {
339 _LIBCPP_HIDE_FROM_ABI
340 static void
341 __append_string(__path_string& __dest, const basic_string<char> &__str) {
342 size_t __size = __char_to_wide(__str, nullptr, 0);
343 size_t __pos = __dest.size();
344 __dest.resize(__pos + __size);
345 __char_to_wide(__str, const_cast<__path_value*>(__dest.data()) + __pos, __size);
348 template <class _Iter, __enable_if_t<__has_exactly_input_iterator_category<_Iter>::value, int> = 0>
349 _LIBCPP_HIDE_FROM_ABI
350 static void
351 __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
352 basic_string<char> __tmp(__b, __e);
353 __append_string(__dest, __tmp);
356 template <class _Iter, __enable_if_t<__has_forward_iterator_category<_Iter>::value, int> = 0>
357 _LIBCPP_HIDE_FROM_ABI
358 static void
359 __append_range(__path_string& __dest, _Iter __b, _Iter __e) {
360 basic_string<char> __tmp(__b, __e);
361 __append_string(__dest, __tmp);
364 template <class _Iter>
365 _LIBCPP_HIDE_FROM_ABI
366 static void __append_range(__path_string& __dest, _Iter __b, _NullSentinel) {
367 const char __sentinel = char{};
368 basic_string<char> __tmp;
369 for (; *__b != __sentinel; ++__b)
370 __tmp.push_back(*__b);
371 __append_string(__dest, __tmp);
374 template <class _Source>
375 _LIBCPP_HIDE_FROM_ABI
376 static void __append_source(__path_string& __dest, _Source const& __s) {
377 using _Traits = __is_pathable<_Source>;
378 __append_range(__dest, _Traits::__range_begin(__s),
379 _Traits::__range_end(__s));
383 template <class _ECharT>
384 struct _PathExport {
385 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower;
386 typedef __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Widener;
388 template <class _Str>
389 _LIBCPP_HIDE_FROM_ABI
390 static void __append(_Str& __dest, const __path_string& __src) {
391 string __utf8;
392 _Narrower()(back_inserter(__utf8), __src.data(), __src.data() + __src.size());
393 _Widener()(back_inserter(__dest), __utf8.data(), __utf8.data() + __utf8.size());
397 template <>
398 struct _PathExport<char> {
399 template <class _Str>
400 _LIBCPP_HIDE_FROM_ABI
401 static void __append(_Str& __dest, const __path_string& __src) {
402 size_t __size = __wide_to_char(__src, nullptr, 0);
403 size_t __pos = __dest.size();
404 __dest.resize(__size);
405 __wide_to_char(__src, const_cast<char*>(__dest.data()) + __pos, __size);
409 template <>
410 struct _PathExport<wchar_t> {
411 template <class _Str>
412 _LIBCPP_HIDE_FROM_ABI
413 static void __append(_Str& __dest, const __path_string& __src) {
414 __dest.append(__src.begin(), __src.end());
418 template <>
419 struct _PathExport<char16_t> {
420 template <class _Str>
421 _LIBCPP_HIDE_FROM_ABI
422 static void __append(_Str& __dest, const __path_string& __src) {
423 __dest.append(__src.begin(), __src.end());
427 #ifndef _LIBCPP_HAS_NO_CHAR8_T
428 template <>
429 struct _PathExport<char8_t> {
430 typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower;
432 template <class _Str>
433 _LIBCPP_HIDE_FROM_ABI
434 static void __append(_Str& __dest, const __path_string& __src) {
435 _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size());
438 #endif /* !_LIBCPP_HAS_NO_CHAR8_T */
439 #endif /* _LIBCPP_WIN32API */
441 class _LIBCPP_EXPORTED_FROM_ABI path {
442 template <class _SourceOrIter, class _Tp = path&>
443 using _EnableIfPathable = __enable_if_t<__is_pathable<_SourceOrIter>::value, _Tp>;
445 template <class _Tp>
446 using _SourceChar = typename __is_pathable<_Tp>::__char_type;
448 template <class _Tp>
449 using _SourceCVT = _PathCVT<_SourceChar<_Tp> >;
451 public:
452 #if defined(_LIBCPP_WIN32API)
453 typedef wchar_t value_type;
454 static constexpr value_type preferred_separator = L'\\';
455 #else
456 typedef char value_type;
457 static constexpr value_type preferred_separator = '/';
458 #endif
459 typedef basic_string<value_type> string_type;
460 typedef basic_string_view<value_type> __string_view;
462 enum format : unsigned char {
463 auto_format,
464 native_format,
465 generic_format
468 // constructors and destructor
469 _LIBCPP_HIDE_FROM_ABI path() noexcept {}
470 _LIBCPP_HIDE_FROM_ABI path(const path& __p) : __pn_(__p.__pn_) {}
471 _LIBCPP_HIDE_FROM_ABI path(path&& __p) noexcept
472 : __pn_(_VSTD::move(__p.__pn_)) {}
474 _LIBCPP_HIDE_FROM_ABI
475 path(string_type&& __s, format = format::auto_format) noexcept
476 : __pn_(_VSTD::move(__s)) {}
478 template <class _Source, class = _EnableIfPathable<_Source, void> >
479 _LIBCPP_HIDE_FROM_ABI
480 path(const _Source& __src, format = format::auto_format) {
481 _SourceCVT<_Source>::__append_source(__pn_, __src);
484 template <class _InputIt>
485 _LIBCPP_HIDE_FROM_ABI
486 path(_InputIt __first, _InputIt __last, format = format::auto_format) {
487 typedef typename iterator_traits<_InputIt>::value_type _ItVal;
488 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
492 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
493 // TODO Implement locale conversions.
494 template <class _Source, class = _EnableIfPathable<_Source, void> >
495 path(const _Source& __src, const locale& __loc, format = format::auto_format);
496 template <class _InputIt>
497 path(_InputIt __first, _InputIt _last, const locale& __loc,
498 format = format::auto_format);
499 #endif
502 _LIBCPP_HIDE_FROM_ABI
503 ~path() = default;
505 // assignments
506 _LIBCPP_HIDE_FROM_ABI
507 path& operator=(const path& __p) {
508 __pn_ = __p.__pn_;
509 return *this;
512 _LIBCPP_HIDE_FROM_ABI
513 path& operator=(path&& __p) noexcept {
514 __pn_ = _VSTD::move(__p.__pn_);
515 return *this;
518 _LIBCPP_HIDE_FROM_ABI
519 path& operator=(string_type&& __s) noexcept {
520 __pn_ = _VSTD::move(__s);
521 return *this;
524 _LIBCPP_HIDE_FROM_ABI
525 path& assign(string_type&& __s) noexcept {
526 __pn_ = _VSTD::move(__s);
527 return *this;
530 template <class _Source>
531 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source>
532 operator=(const _Source& __src) {
533 return this->assign(__src);
536 template <class _Source>
537 _LIBCPP_HIDE_FROM_ABI
538 _EnableIfPathable<_Source> assign(const _Source& __src) {
539 __pn_.clear();
540 _SourceCVT<_Source>::__append_source(__pn_, __src);
541 return *this;
544 template <class _InputIt>
545 _LIBCPP_HIDE_FROM_ABI
546 path& assign(_InputIt __first, _InputIt __last) {
547 typedef typename iterator_traits<_InputIt>::value_type _ItVal;
548 __pn_.clear();
549 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
550 return *this;
553 public:
554 // appends
555 #if defined(_LIBCPP_WIN32API)
556 _LIBCPP_HIDE_FROM_ABI
557 path& operator/=(const path& __p) {
558 auto __p_root_name = __p.__root_name();
559 auto __p_root_name_size = __p_root_name.size();
560 if (__p.is_absolute() ||
561 (!__p_root_name.empty() && __p_root_name != __string_view(root_name().__pn_))) {
562 __pn_ = __p.__pn_;
563 return *this;
565 if (__p.has_root_directory()) {
566 path __root_name_str = root_name();
567 __pn_ = __root_name_str.native();
568 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);
569 return *this;
571 if (has_filename() || (!has_root_directory() && is_absolute()))
572 __pn_ += preferred_separator;
573 __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size);
574 return *this;
576 template <class _Source>
577 _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
578 operator/=(const _Source& __src) {
579 return operator/=(path(__src));
582 template <class _Source>
583 _LIBCPP_HIDE_FROM_ABI
584 _EnableIfPathable<_Source> append(const _Source& __src) {
585 return operator/=(path(__src));
588 template <class _InputIt>
589 _LIBCPP_HIDE_FROM_ABI
590 path& append(_InputIt __first, _InputIt __last) {
591 return operator/=(path(__first, __last));
593 #else
594 _LIBCPP_HIDE_FROM_ABI
595 path& operator/=(const path& __p) {
596 if (__p.is_absolute()) {
597 __pn_ = __p.__pn_;
598 return *this;
600 if (has_filename())
601 __pn_ += preferred_separator;
602 __pn_ += __p.native();
603 return *this;
606 // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
607 // is known at compile time to be "/' since the user almost certainly intended
608 // to append a separator instead of overwriting the path with "/"
609 template <class _Source>
610 _LIBCPP_HIDE_FROM_ABI _EnableIfPathable<_Source>
611 operator/=(const _Source& __src) {
612 return this->append(__src);
615 template <class _Source>
616 _LIBCPP_HIDE_FROM_ABI
617 _EnableIfPathable<_Source> append(const _Source& __src) {
618 using _Traits = __is_pathable<_Source>;
619 using _CVT = _PathCVT<_SourceChar<_Source> >;
620 bool __source_is_absolute = _VSTD_FS::__is_separator(_Traits::__first_or_null(__src));
621 if (__source_is_absolute)
622 __pn_.clear();
623 else if (has_filename())
624 __pn_ += preferred_separator;
625 _CVT::__append_source(__pn_, __src);
626 return *this;
629 template <class _InputIt>
630 _LIBCPP_HIDE_FROM_ABI
631 path& append(_InputIt __first, _InputIt __last) {
632 typedef typename iterator_traits<_InputIt>::value_type _ItVal;
633 static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
634 using _CVT = _PathCVT<_ItVal>;
635 if (__first != __last && _VSTD_FS::__is_separator(*__first))
636 __pn_.clear();
637 else if (has_filename())
638 __pn_ += preferred_separator;
639 _CVT::__append_range(__pn_, __first, __last);
640 return *this;
642 #endif
644 // concatenation
645 _LIBCPP_HIDE_FROM_ABI
646 path& operator+=(const path& __x) {
647 __pn_ += __x.__pn_;
648 return *this;
651 _LIBCPP_HIDE_FROM_ABI
652 path& operator+=(const string_type& __x) {
653 __pn_ += __x;
654 return *this;
657 _LIBCPP_HIDE_FROM_ABI
658 path& operator+=(__string_view __x) {
659 __pn_ += __x;
660 return *this;
663 _LIBCPP_HIDE_FROM_ABI
664 path& operator+=(const value_type* __x) {
665 __pn_ += __x;
666 return *this;
669 _LIBCPP_HIDE_FROM_ABI
670 path& operator+=(value_type __x) {
671 __pn_ += __x;
672 return *this;
675 template <class _ECharT, __enable_if_t<__can_convert_char<_ECharT>::value, int> = 0>
676 _LIBCPP_HIDE_FROM_ABI
677 path&
678 operator+=(_ECharT __x) {
679 _PathCVT<_ECharT>::__append_source(__pn_,
680 basic_string_view<_ECharT>(&__x, 1));
681 return *this;
684 template <class _Source>
685 _LIBCPP_HIDE_FROM_ABI
686 _EnableIfPathable<_Source> operator+=(const _Source& __x) {
687 return this->concat(__x);
690 template <class _Source>
691 _LIBCPP_HIDE_FROM_ABI
692 _EnableIfPathable<_Source> concat(const _Source& __x) {
693 _SourceCVT<_Source>::__append_source(__pn_, __x);
694 return *this;
697 template <class _InputIt>
698 _LIBCPP_HIDE_FROM_ABI
699 path& concat(_InputIt __first, _InputIt __last) {
700 typedef typename iterator_traits<_InputIt>::value_type _ItVal;
701 _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
702 return *this;
705 // modifiers
706 _LIBCPP_HIDE_FROM_ABI
707 void clear() noexcept { __pn_.clear(); }
709 _LIBCPP_HIDE_FROM_ABI
710 path& make_preferred() {
711 #if defined(_LIBCPP_WIN32API)
712 _VSTD::replace(__pn_.begin(), __pn_.end(), L'/', L'\\');
713 #endif
714 return *this;
717 _LIBCPP_HIDE_FROM_ABI
718 path& remove_filename() {
719 auto __fname = __filename();
720 if (!__fname.empty())
721 __pn_.erase(__fname.data() - __pn_.data());
722 return *this;
725 _LIBCPP_HIDE_FROM_ABI
726 path& replace_filename(const path& __replacement) {
727 remove_filename();
728 return (*this /= __replacement);
731 path& replace_extension(const path& __replacement = path());
733 friend _LIBCPP_HIDE_FROM_ABI bool operator==(const path& __lhs, const path& __rhs) noexcept {
734 return __lhs.__compare(__rhs.__pn_) == 0;
736 # if _LIBCPP_STD_VER <= 17
737 friend _LIBCPP_HIDE_FROM_ABI bool operator!=(const path& __lhs, const path& __rhs) noexcept {
738 return __lhs.__compare(__rhs.__pn_) != 0;
740 friend _LIBCPP_HIDE_FROM_ABI bool operator<(const path& __lhs, const path& __rhs) noexcept {
741 return __lhs.__compare(__rhs.__pn_) < 0;
743 friend _LIBCPP_HIDE_FROM_ABI bool operator<=(const path& __lhs, const path& __rhs) noexcept {
744 return __lhs.__compare(__rhs.__pn_) <= 0;
746 friend _LIBCPP_HIDE_FROM_ABI bool operator>(const path& __lhs, const path& __rhs) noexcept {
747 return __lhs.__compare(__rhs.__pn_) > 0;
749 friend _LIBCPP_HIDE_FROM_ABI bool operator>=(const path& __lhs, const path& __rhs) noexcept {
750 return __lhs.__compare(__rhs.__pn_) >= 0;
752 # else // _LIBCPP_STD_VER <= 17
753 friend _LIBCPP_HIDE_FROM_ABI strong_ordering operator<=>(const path& __lhs, const path& __rhs) noexcept {
754 return __lhs.__compare(__rhs.__pn_) <=> 0;
756 # endif // _LIBCPP_STD_VER <= 17
758 friend _LIBCPP_HIDE_FROM_ABI path operator/(const path& __lhs, const path& __rhs) {
759 path __result(__lhs);
760 __result /= __rhs;
761 return __result;
764 _LIBCPP_HIDE_FROM_ABI
765 void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); }
767 // private helper to allow reserving memory in the path
768 _LIBCPP_HIDE_FROM_ABI
769 void __reserve(size_t __s) { __pn_.reserve(__s); }
771 // native format observers
772 _LIBCPP_HIDE_FROM_ABI
773 const string_type& native() const noexcept { return __pn_; }
775 _LIBCPP_HIDE_FROM_ABI
776 const value_type* c_str() const noexcept { return __pn_.c_str(); }
778 _LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; }
780 #if defined(_LIBCPP_WIN32API)
781 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring wstring() const { return __pn_; }
783 _LIBCPP_HIDE_FROM_ABI
784 _VSTD::wstring generic_wstring() const {
785 _VSTD::wstring __s;
786 __s.resize(__pn_.size());
787 _VSTD::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/');
788 return __s;
791 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
792 template <class _ECharT, class _Traits = char_traits<_ECharT>,
793 class _Allocator = allocator<_ECharT> >
794 _LIBCPP_HIDE_FROM_ABI
795 basic_string<_ECharT, _Traits, _Allocator>
796 string(const _Allocator& __a = _Allocator()) const {
797 using _Str = basic_string<_ECharT, _Traits, _Allocator>;
798 _Str __s(__a);
799 __s.reserve(__pn_.size());
800 _PathExport<_ECharT>::__append(__s, __pn_);
801 return __s;
804 _LIBCPP_HIDE_FROM_ABI _VSTD::string string() const {
805 return string<char>();
807 _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const {
808 using _CVT = __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__>;
809 __u8_string __s;
810 __s.reserve(__pn_.size());
811 _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());
812 return __s;
815 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string u16string() const {
816 return string<char16_t>();
818 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string u32string() const {
819 return string<char32_t>();
822 // generic format observers
823 template <class _ECharT, class _Traits = char_traits<_ECharT>,
824 class _Allocator = allocator<_ECharT> >
825 _LIBCPP_HIDE_FROM_ABI
826 basic_string<_ECharT, _Traits, _Allocator>
827 generic_string(const _Allocator& __a = _Allocator()) const {
828 using _Str = basic_string<_ECharT, _Traits, _Allocator>;
829 _Str __s = string<_ECharT, _Traits, _Allocator>(__a);
830 // Note: This (and generic_u8string below) is slightly suboptimal as
831 // it iterates twice over the string; once to convert it to the right
832 // character type, and once to replace path delimiters.
833 _VSTD::replace(__s.begin(), __s.end(),
834 static_cast<_ECharT>('\\'), static_cast<_ECharT>('/'));
835 return __s;
838 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_string() const { return generic_string<char>(); }
839 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string generic_u16string() const { return generic_string<char16_t>(); }
840 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string generic_u32string() const { return generic_string<char32_t>(); }
841 _LIBCPP_HIDE_FROM_ABI
842 __u8_string generic_u8string() const {
843 __u8_string __s = u8string();
844 _VSTD::replace(__s.begin(), __s.end(), '\\', '/');
845 return __s;
847 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */
848 #else /* _LIBCPP_WIN32API */
850 _LIBCPP_HIDE_FROM_ABI _VSTD::string string() const { return __pn_; }
851 #ifndef _LIBCPP_HAS_NO_CHAR8_T
852 _LIBCPP_HIDE_FROM_ABI _VSTD::u8string u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); }
853 #else
854 _LIBCPP_HIDE_FROM_ABI _VSTD::string u8string() const { return __pn_; }
855 #endif
857 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
858 template <class _ECharT, class _Traits = char_traits<_ECharT>,
859 class _Allocator = allocator<_ECharT> >
860 _LIBCPP_HIDE_FROM_ABI
861 basic_string<_ECharT, _Traits, _Allocator>
862 string(const _Allocator& __a = _Allocator()) const {
863 using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>;
864 using _Str = basic_string<_ECharT, _Traits, _Allocator>;
865 _Str __s(__a);
866 __s.reserve(__pn_.size());
867 _CVT()(std::back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());
868 return __s;
871 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
872 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring wstring() const {
873 return string<wchar_t>();
875 #endif
876 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string u16string() const {
877 return string<char16_t>();
879 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string u32string() const {
880 return string<char32_t>();
882 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */
884 // generic format observers
885 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_string() const { return __pn_; }
886 #ifndef _LIBCPP_HAS_NO_CHAR8_T
887 _LIBCPP_HIDE_FROM_ABI _VSTD::u8string generic_u8string() const { return _VSTD::u8string(__pn_.begin(), __pn_.end()); }
888 #else
889 _LIBCPP_HIDE_FROM_ABI _VSTD::string generic_u8string() const { return __pn_; }
890 #endif
892 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
893 template <class _ECharT, class _Traits = char_traits<_ECharT>,
894 class _Allocator = allocator<_ECharT> >
895 _LIBCPP_HIDE_FROM_ABI
896 basic_string<_ECharT, _Traits, _Allocator>
897 generic_string(const _Allocator& __a = _Allocator()) const {
898 return string<_ECharT, _Traits, _Allocator>(__a);
901 #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
902 _LIBCPP_HIDE_FROM_ABI _VSTD::wstring generic_wstring() const { return string<wchar_t>(); }
903 #endif
904 _LIBCPP_HIDE_FROM_ABI _VSTD::u16string generic_u16string() const { return string<char16_t>(); }
905 _LIBCPP_HIDE_FROM_ABI _VSTD::u32string generic_u32string() const { return string<char32_t>(); }
906 #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */
907 #endif /* !_LIBCPP_WIN32API */
909 private:
910 int __compare(__string_view) const;
911 __string_view __root_name() const;
912 __string_view __root_directory() const;
913 __string_view __root_path_raw() const;
914 __string_view __relative_path() const;
915 __string_view __parent_path() const;
916 __string_view __filename() const;
917 __string_view __stem() const;
918 __string_view __extension() const;
920 public:
921 // compare
922 _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept {
923 return __compare(__p.__pn_);
925 _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const {
926 return __compare(__s);
928 _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const {
929 return __compare(__s);
931 _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const {
932 return __compare(__s);
935 // decomposition
936 _LIBCPP_HIDE_FROM_ABI path root_name() const {
937 return string_type(__root_name());
939 _LIBCPP_HIDE_FROM_ABI path root_directory() const {
940 return string_type(__root_directory());
942 _LIBCPP_HIDE_FROM_ABI path root_path() const {
943 #if defined(_LIBCPP_WIN32API)
944 return string_type(__root_path_raw());
945 #else
946 return root_name().append(string_type(__root_directory()));
947 #endif
949 _LIBCPP_HIDE_FROM_ABI path relative_path() const {
950 return string_type(__relative_path());
952 _LIBCPP_HIDE_FROM_ABI path parent_path() const {
953 return string_type(__parent_path());
955 _LIBCPP_HIDE_FROM_ABI path filename() const {
956 return string_type(__filename());
958 _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); }
959 _LIBCPP_HIDE_FROM_ABI path extension() const {
960 return string_type(__extension());
963 // query
964 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI bool
965 empty() const noexcept {
966 return __pn_.empty();
969 _LIBCPP_HIDE_FROM_ABI bool has_root_name() const {
970 return !__root_name().empty();
972 _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const {
973 return !__root_directory().empty();
975 _LIBCPP_HIDE_FROM_ABI bool has_root_path() const {
976 return !__root_path_raw().empty();
978 _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const {
979 return !__relative_path().empty();
981 _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const {
982 return !__parent_path().empty();
984 _LIBCPP_HIDE_FROM_ABI bool has_filename() const {
985 return !__filename().empty();
987 _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); }
988 _LIBCPP_HIDE_FROM_ABI bool has_extension() const {
989 return !__extension().empty();
992 _LIBCPP_HIDE_FROM_ABI bool is_absolute() const {
993 #if defined(_LIBCPP_WIN32API)
994 __string_view __root_name_str = __root_name();
995 __string_view __root_dir = __root_directory();
996 if (__root_name_str.size() == 2 && __root_name_str[1] == ':') {
997 // A drive letter with no root directory is relative, e.g. x:example.
998 return !__root_dir.empty();
1000 // If no root name, it's relative, e.g. \example is relative to the current drive
1001 if (__root_name_str.empty())
1002 return false;
1003 if (__root_name_str.size() < 3)
1004 return false;
1005 // A server root name, like \\server, is always absolute
1006 if (__root_name_str[0] != '/' && __root_name_str[0] != '\\')
1007 return false;
1008 if (__root_name_str[1] != '/' && __root_name_str[1] != '\\')
1009 return false;
1010 // Seems to be a server root name
1011 return true;
1012 #else
1013 return has_root_directory();
1014 #endif
1016 _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); }
1018 // relative paths
1019 path lexically_normal() const;
1020 path lexically_relative(const path& __base) const;
1022 _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const {
1023 path __result = this->lexically_relative(__base);
1024 if (__result.native().empty())
1025 return *this;
1026 return __result;
1029 // iterators
1030 class _LIBCPP_EXPORTED_FROM_ABI iterator;
1031 typedef iterator const_iterator;
1033 iterator begin() const;
1034 iterator end() const;
1036 #if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
1037 template <class _CharT, class _Traits, __enable_if_t<is_same<_CharT, value_type>::value &&
1038 is_same<_Traits, char_traits<value_type> >::value, int> = 0>
1039 _LIBCPP_HIDE_FROM_ABI friend
1040 basic_ostream<_CharT, _Traits>&
1041 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
1042 __os << _VSTD::__quoted(__p.native());
1043 return __os;
1046 template <class _CharT, class _Traits, __enable_if_t<!is_same<_CharT, value_type>::value ||
1047 !is_same<_Traits, char_traits<value_type> >::value, int> = 0>
1048 _LIBCPP_HIDE_FROM_ABI friend
1049 basic_ostream<_CharT, _Traits>&
1050 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
1051 __os << _VSTD::__quoted(__p.string<_CharT, _Traits>());
1052 return __os;
1055 template <class _CharT, class _Traits>
1056 _LIBCPP_HIDE_FROM_ABI friend basic_istream<_CharT, _Traits>&
1057 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) {
1058 basic_string<_CharT, _Traits> __tmp;
1059 __is >> _VSTD::__quoted(__tmp);
1060 __p = __tmp;
1061 return __is;
1063 #endif // !_LIBCPP_HAS_NO_LOCALIZATION
1065 private:
1066 inline _LIBCPP_HIDE_FROM_ABI path& __assign_view(__string_view const& __s) {
1067 __pn_ = string_type(__s);
1068 return *this;
1070 string_type __pn_;
1073 inline _LIBCPP_HIDE_FROM_ABI void swap(path& __lhs, path& __rhs) noexcept {
1074 __lhs.swap(__rhs);
1077 _LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept;
1079 _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP
1081 _LIBCPP_END_NAMESPACE_FILESYSTEM
1083 _LIBCPP_BEGIN_NAMESPACE_STD
1085 template <>
1086 struct _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY hash<_VSTD_FS::path> : __unary_function<_VSTD_FS::path, size_t> {
1087 _LIBCPP_HIDE_FROM_ABI size_t operator()(_VSTD_FS::path const& __p) const noexcept {
1088 return _VSTD_FS::hash_value(__p);
1092 _LIBCPP_END_NAMESPACE_STD
1094 #endif // _LIBCPP_CXX03_LANG
1096 #endif // _LIBCPP___FILESYSTEM_PATH_H