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# 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
48template <class _Tp>
49struct __can_convert_char {
50 static const bool value = false;
51};
52template <class _Tp>
53struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};
54template <>
55struct __can_convert_char<char> {
56 static const bool value = true;
57 using __char_type _LIBCPP_NODEBUG = char;
58};
59template <>
60struct __can_convert_char<wchar_t> {
61 static const bool value = true;
62 using __char_type _LIBCPP_NODEBUG = wchar_t;
63};
64# if _LIBCPP_HAS_CHAR8_T
65template <>
66struct __can_convert_char<char8_t> {
67 static const bool value = true;
68 using __char_type _LIBCPP_NODEBUG = char8_t;
69};
70# endif
71template <>
72struct __can_convert_char<char16_t> {
73 static const bool value = true;
74 using __char_type _LIBCPP_NODEBUG = char16_t;
75};
76template <>
77struct __can_convert_char<char32_t> {
78 static const bool value = true;
79 using __char_type _LIBCPP_NODEBUG = char32_t;
80};
81
82template <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# if _LIBCPP_HAS_CHAR8_T
92typedef u8string __u8_string;
93# else
94typedef string __u8_string;
95# endif
96
97struct _NullSentinel {};
98
99template <class _Tp>
100using _Void _LIBCPP_NODEBUG = void;
101
102template <class _Tp, class = void>
103struct __is_pathable_string : public false_type {};
104
105template <class _ECharT, class _Traits, class _Alloc>
106struct __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 _LIBCPP_NODEBUG = 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
118template <class _ECharT, class _Traits>
119struct __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 _LIBCPP_NODEBUG = 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
131template <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>
135struct __is_pathable_char_array : false_type {};
136
137template <class _Source, class _ECharT, class _UPtr>
138struct __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
153template <class _Iter, bool _IsIt = __has_input_iterator_category<_Iter>::value, class = void>
154struct __is_pathable_iter : false_type {};
155
156template <class _Iter>
157struct __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 _LIBCPP_NODEBUG = 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
171template <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>
175struct __is_pathable : false_type {
176 static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
177};
178
179template <class _Tp>
180struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
181
182template <class _Tp>
183struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {};
184
185template <class _Tp>
186struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
187
188# if defined(_LIBCPP_WIN32API)
189typedef wstring __path_string;
190typedef wchar_t __path_value;
191# else
192typedef string __path_string;
193typedef 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
201template <class _ECharT>
202struct _PathCVT;
203
204# if _LIBCPP_HAS_LOCALIZATION
205template <class _ECharT>
206struct _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(x&: __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(x&: __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(x&: __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_LOCALIZATION
264
265template <>
266struct _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(c: *__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(c: *__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)
293template <>
294struct _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
330template <class _ECharT>
331struct _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
343template <>
344struct _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
354template <>
355struct _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
362template <>
363struct _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# if _LIBCPP_HAS_CHAR8_T
371template <>
372struct _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_CHAR8_T
381# endif /* _LIBCPP_WIN32API */
382
383class _LIBCPP_EXPORTED_FROM_ABI path {
384 template <class _SourceOrIter, class _Tp = path&>
385 using _EnableIfPathable _LIBCPP_NODEBUG = __enable_if_t<__is_pathable<_SourceOrIter>::value, _Tp>;
386
387 template <class _Tp>
388 using _SourceChar _LIBCPP_NODEBUG = typename __is_pathable<_Tp>::__char_type;
389
390 template <class _Tp>
391 using _SourceCVT _LIBCPP_NODEBUG = _PathCVT<_SourceChar<_Tp> >;
392
393public:
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 _LIBCPP_HAS_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
478public:
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>(std::addressof(__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(pos: __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(str&: __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(requested_capacity: __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 _LIBCPP_HAS_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_LOCALIZATION
731# else /* _LIBCPP_WIN32API */
732
733 _LIBCPP_HIDE_FROM_ABI std::string string() const { return __pn_; }
734# if _LIBCPP_HAS_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 _LIBCPP_HAS_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# if _LIBCPP_HAS_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_LOCALIZATION
757
758 // generic format observers
759 _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return __pn_; }
760# if _LIBCPP_HAS_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 _LIBCPP_HAS_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# if _LIBCPP_HAS_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_LOCALIZATION
779# endif /* !_LIBCPP_WIN32API */
780
781private:
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
792public:
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(src: 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 [[__nodiscard__]] _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 _LIBCPP_HAS_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(s: __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_LOCALIZATION
901
902private:
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
910inline _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
920template <>
921struct _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