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