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