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