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