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