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