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