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