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