master
  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
 47template <class _Tp>
 48struct __can_convert_char {
 49  static const bool value = false;
 50};
 51template <class _Tp>
 52struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};
 53template <>
 54struct __can_convert_char<char> {
 55  static const bool value           = true;
 56  using __char_type _LIBCPP_NODEBUG = char;
 57};
 58template <>
 59struct __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
 64template <>
 65struct __can_convert_char<char8_t> {
 66  static const bool value           = true;
 67  using __char_type _LIBCPP_NODEBUG = char8_t;
 68};
 69#  endif
 70template <>
 71struct __can_convert_char<char16_t> {
 72  static const bool value           = true;
 73  using __char_type _LIBCPP_NODEBUG = char16_t;
 74};
 75template <>
 76struct __can_convert_char<char32_t> {
 77  static const bool value           = true;
 78  using __char_type _LIBCPP_NODEBUG = char32_t;
 79};
 80
 81template <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
 91typedef u8string __u8_string;
 92#  else
 93typedef string __u8_string;
 94#  endif
 95
 96struct _NullSentinel {};
 97
 98template <class _Tp>
 99using _Void _LIBCPP_NODEBUG = void;
100
101template <class _Tp, class = void>
102struct __is_pathable_string : public false_type {};
103
104template <class _ECharT, class _Traits, class _Alloc>
105struct __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
117template <class _ECharT, class _Traits>
118struct __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
130template <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>
134struct __is_pathable_char_array : false_type {};
135
136template <class _Source, class _ECharT, class _UPtr>
137struct __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
152template <class _Iter, bool _IsIt = __has_input_iterator_category<_Iter>::value, class = void>
153struct __is_pathable_iter : false_type {};
154
155template <class _Iter>
156struct __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
170template <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>
174struct __is_pathable : false_type {
175  static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
176};
177
178template <class _Tp>
179struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
180
181template <class _Tp>
182struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {};
183
184template <class _Tp>
185struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
186
187#  if defined(_LIBCPP_WIN32API)
188typedef wstring __path_string;
189typedef wchar_t __path_value;
190#  else
191typedef string __path_string;
192typedef 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
200template <class _ECharT>
201struct _PathCVT;
202
203#  if _LIBCPP_HAS_LOCALIZATION
204template <class _ECharT>
205struct _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
264template <>
265struct _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)
292template <>
293struct _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
329template <class _ECharT>
330struct _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
342template <>
343struct _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
353template <>
354struct _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
361template <>
362struct _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
370template <>
371struct _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
382class _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
392public:
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
477public:
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
780private:
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
791public:
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
901private:
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
909inline _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
919template <>
920struct _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