fix path with string comparison
[kazan.git] / src / util / filesystem.h
1 /*
2 * Copyright 2017 Jacob Lifshay
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 */
23 #ifndef UTIL_FILESYSTEM_H_
24 #define UTIL_FILESYSTEM_H_
25
26 #include <string>
27 #include <utility>
28 #include <new>
29 #include <memory>
30 #include <cassert>
31 #include <limits>
32 #include "bit_intrinsics.h"
33 #include "string_view.h"
34 #include "void_t.h"
35 #include <type_traits>
36 #include <iterator>
37 #include "optional.h"
38 #include "text.h"
39 #include <cstdint>
40 #include <iomanip>
41 #include <istream>
42 #include <ostream>
43 #include <system_error>
44 #include <cstdint>
45 #include <chrono>
46 #include <ratio>
47
48 namespace vulkan_cpu
49 {
50 namespace util
51 {
52 namespace filesystem
53 {
54 namespace detail
55 {
56 enum class Path_traits_kind
57 {
58 posix,
59 windows,
60 };
61
62 #ifdef _WIN32
63 constexpr Path_traits_kind default_path_traits_kind = Path_traits_kind::windows;
64 typedef std::ratio<1, 10'000'000ULL> Filesystem_clock_period;
65 #elif defined(__linux__)
66 constexpr Path_traits_kind default_path_traits_kind = Path_traits_kind::posix;
67 typedef std::nano Filesystem_clock_period;
68 #else
69 #error filesystem is not implemented for your operating system
70 #endif
71
72 struct Filesystem_clock
73 {
74 typedef std::int64_t rep;
75 typedef Filesystem_clock_period period;
76 typedef std::chrono::duration<rep, period> duration;
77 typedef std::chrono::time_point<Filesystem_clock> time_point;
78 static constexpr bool is_steady = false;
79 static time_point now() noexcept;
80 };
81
82 template <Path_traits_kind Kind>
83 struct Path_traits
84 {
85 typedef char value_type;
86 static constexpr value_type preferred_separator = '/';
87 static constexpr bool needs_root_name_to_be_absolute = false;
88 };
89
90 template <>
91 struct Path_traits<Path_traits_kind::windows>
92 {
93 typedef wchar_t value_type;
94 static constexpr value_type preferred_separator = L'\\';
95 static constexpr bool needs_root_name_to_be_absolute = true;
96 };
97
98 enum class Path_part_kind
99 {
100 relative_root_name, // root name that has a current directory, like "C:" in windows
101 absolute_root_name, // root name that can't have a current directory, like "\\ABC" in windows
102 root_dir,
103 file_name,
104 multiple_parts,
105 path_separator,
106 };
107
108 template <typename T>
109 struct Path_is_convertable_char_type
110 {
111 static constexpr bool value = false;
112 };
113
114 template <typename T>
115 struct Path_is_convertable_char_type<const T> : public Path_is_convertable_char_type<T>
116 {
117 };
118
119 template <>
120 struct Path_is_convertable_char_type<char>
121 {
122 static constexpr bool value = true;
123 typedef char Char_type;
124 };
125
126 template <>
127 struct Path_is_convertable_char_type<wchar_t>
128 {
129 static constexpr bool value = true;
130 typedef wchar_t Char_type;
131 };
132
133 template <>
134 struct Path_is_convertable_char_type<char16_t>
135 {
136 static constexpr bool value = true;
137 typedef char16_t Char_type;
138 };
139
140 template <>
141 struct Path_is_convertable_char_type<char32_t>
142 {
143 static constexpr bool value = true;
144 typedef char32_t Char_type;
145 };
146
147 template <typename T, typename = void>
148 struct Path_is_convertable_iterator_type
149 {
150 static constexpr bool value = false;
151 };
152
153 template <typename T>
154 struct Path_is_convertable_iterator_type<T,
155 typename std::enable_if<Path_is_convertable_char_type<
156 typename std::iterator_traits<T>::value_type>::value>::
157 type>
158 {
159 static constexpr bool value = true;
160 typedef typename Path_is_convertable_char_type<
161 typename std::iterator_traits<T>::value_type>::Char_type Char_type;
162 };
163
164 struct Path_iterator_sentinel
165 {
166 };
167
168 template <typename Iterator>
169 class Path_convert_single_iterator_adaptor
170 {
171 private:
172 typedef std::iterator_traits<Iterator> Traits;
173 optional<Iterator> base_iterator;
174
175 public:
176 typedef typename Traits::value_type value_type;
177 typedef typename Traits::pointer pointer;
178 typedef typename Traits::reference reference;
179 typedef typename Traits::difference_type difference_type;
180 typedef std::input_iterator_tag iterator_category;
181 constexpr Path_convert_single_iterator_adaptor() noexcept : base_iterator()
182 {
183 }
184 constexpr explicit Path_convert_single_iterator_adaptor(Iterator iterator)
185 : base_iterator(std::move(iterator))
186 {
187 }
188 bool operator==(const Path_convert_single_iterator_adaptor &rt) const
189 {
190 if(base_iterator)
191 {
192 assert(!rt.base_iterator);
193 return **base_iterator == value_type();
194 }
195 if(rt.base_iterator)
196 return **rt.base_iterator == value_type();
197 return true;
198 }
199 bool operator!=(const Path_convert_single_iterator_adaptor &rt) const
200 {
201 return !operator==(rt);
202 }
203 bool operator==(Path_iterator_sentinel) const
204 {
205 if(base_iterator)
206 return **base_iterator == value_type();
207 return true;
208 }
209 bool operator!=(Path_iterator_sentinel) const
210 {
211 return !operator==(Path_iterator_sentinel());
212 }
213 Path_convert_single_iterator_adaptor &operator++()
214 {
215 if(base_iterator)
216 ++(*base_iterator);
217 return *this;
218 }
219 Path_convert_single_iterator_adaptor operator++(int)
220 {
221 if(base_iterator)
222 return Path_convert_single_iterator_adaptor((*base_iterator)++);
223 return {};
224 }
225 reference operator*() const
226 {
227 return **base_iterator;
228 }
229 pointer operator->() const
230 {
231 return std::addressof(operator*());
232 }
233 };
234
235 template <typename Iterator, typename Sentinel>
236 struct Iterator_and_sentinel
237 {
238 Iterator iterator;
239 Sentinel sentinel;
240 Iterator_and_sentinel(Iterator iterator, Sentinel sentinel)
241 : iterator(std::move(iterator)), sentinel(std::move(sentinel))
242 {
243 }
244 };
245
246 template <typename Dest_char_type,
247 typename Iterator,
248 typename Sentinel = Iterator,
249 typename Source_char_type =
250 typename Path_is_convertable_iterator_type<Iterator>::Char_type>
251 class Path_convert_iterator
252 {
253 private:
254 typedef decltype(text::Decode_encode_functions<Dest_char_type>::encode(
255 char32_t(), text::Convert_options())) Encode_result;
256 static_assert(std::is_same<typename Encode_result::Char_type, Dest_char_type>::value, "");
257
258 public:
259 typedef Dest_char_type value_type;
260 typedef const Dest_char_type *pointer;
261 typedef const Dest_char_type &reference;
262 typedef std::ptrdiff_t difference_type;
263 typedef std::input_iterator_tag iterator_category;
264
265 private:
266 Encode_result encode_result;
267 std::size_t encode_result_index;
268 util::optional<Iterator_and_sentinel<Iterator, Sentinel>> iterator_and_sentinel;
269 void convert_next()
270 {
271 std::char_traits<char32_t>::int_type ch =
272 text::Decode_encode_functions<Source_char_type>::decode(iterator_and_sentinel->iterator,
273 iterator_and_sentinel->sentinel,
274 text::Convert_options());
275 if(ch == std::char_traits<char32_t>::eof())
276 *this = Path_convert_iterator();
277 else
278 {
279 encode_result =
280 text::Decode_encode_functions<Dest_char_type>::encode(ch, text::Convert_options());
281 encode_result_index = 0;
282 }
283 }
284
285 public:
286 constexpr Path_convert_iterator() noexcept : encode_result(),
287 encode_result_index(),
288 iterator_and_sentinel()
289 {
290 }
291 Path_convert_iterator(Iterator iterator, Sentinel sentinel)
292 : encode_result(),
293 encode_result_index(),
294 iterator_and_sentinel(in_place, std::move(iterator), std::move(sentinel))
295 {
296 convert_next();
297 }
298 Path_convert_iterator &operator++()
299 {
300 if(++encode_result_index >= encode_result.size())
301 convert_next();
302 return *this;
303 }
304 Path_convert_iterator operator++(int)
305 {
306 auto retval = *this;
307 operator++();
308 return retval;
309 }
310 const Dest_char_type &operator*() const noexcept
311 {
312 return encode_result[encode_result_index];
313 }
314 const Dest_char_type *operator->() const noexcept
315 {
316 return &encode_result[encode_result_index];
317 }
318 bool operator==(const Path_convert_iterator &rt) const noexcept
319 {
320 return iterator_and_sentinel.has_value() == rt.iterator_and_sentinel.has_value();
321 }
322 bool operator!=(const Path_convert_iterator &rt) const noexcept
323 {
324 return !operator==(rt);
325 }
326 bool operator==(Path_iterator_sentinel) const noexcept
327 {
328 return !iterator_and_sentinel;
329 }
330 bool operator!=(Path_iterator_sentinel) const noexcept
331 {
332 return !operator==(Path_iterator_sentinel());
333 }
334 };
335
336 template <typename Path_char_type, typename Iterator, typename = void>
337 struct Path_convert_range
338 {
339 static constexpr bool is_convertible = false;
340 };
341
342 template <typename Path_char_type, typename Iterator>
343 struct
344 Path_convert_range<Path_char_type,
345 Iterator,
346 typename std::
347 enable_if<!std::
348 is_same<Path_char_type,
349 typename Path_is_convertable_iterator_type<Iterator>::
350 Char_type>::value
351 && Path_is_convertable_iterator_type<Iterator>::value>::type>
352 {
353 static constexpr bool is_convertible = true;
354 template <typename Traits = std::char_traits<Path_char_type>,
355 typename Allocator = std::allocator<Path_char_type>,
356 typename Sentinel>
357 static std::basic_string<Path_char_type, Traits, Allocator> to_string(
358 Iterator iterator, Sentinel sentinel, const Allocator &a = Allocator())
359 {
360 typedef Path_convert_iterator<Path_char_type, Iterator, Sentinel> Convert_iterator;
361 return std::basic_string<Path_char_type, Traits, Allocator>(
362 Convert_iterator(iterator, sentinel), Convert_iterator(), a);
363 }
364 };
365
366 template <typename Iterator>
367 struct Path_convert_range<typename Path_is_convertable_iterator_type<Iterator>::Char_type,
368 Iterator,
369 void>
370 {
371 static constexpr bool is_convertible = true;
372 typedef typename Path_is_convertable_iterator_type<Iterator>::Char_type Char_type;
373 static std::basic_string<Char_type> to_string(
374 Iterator iterator,
375 Iterator sentinel,
376 const std::allocator<Char_type> &a = std::allocator<Char_type>())
377 {
378 return std::basic_string<Char_type>(iterator, sentinel, a);
379 }
380 template <typename Traits = std::char_traits<Char_type>,
381 typename Allocator = std::allocator<Char_type>,
382 typename Sentinel>
383 static std::basic_string<Char_type, Traits, Allocator> to_string(
384 Iterator iterator, Sentinel sentinel, const Allocator &a = Allocator())
385 {
386 std::basic_string<Char_type, Traits, Allocator> retval(a);
387 while(iterator != sentinel)
388 retval += *iterator++;
389 return retval;
390 }
391 };
392
393 template <typename Path_char_type, typename Source, typename = void>
394 struct Path_convert_source
395 {
396 static constexpr bool is_convertible = false;
397 };
398
399 template <typename Path_char_type, typename Source_char_type, typename Traits, typename Allocator>
400 struct Path_convert_source<Path_char_type,
401 std::basic_string<Source_char_type, Traits, Allocator>,
402 typename std::
403 enable_if<!std::is_same<Path_char_type, Source_char_type>::value
404 && Path_convert_range<Path_char_type,
405 typename std::
406 basic_string<Source_char_type,
407 Traits,
408 Allocator>::
409 const_iterator>::
410 is_convertible>::type>
411 {
412 typedef Path_convert_range<Path_char_type,
413 typename std::basic_string<Source_char_type, Traits, Allocator>::
414 const_iterator> Convert_range;
415 static constexpr bool is_convertible = true;
416 template <typename Dest_traits = std::char_traits<Path_char_type>,
417 typename Dest_allocator = std::allocator<Path_char_type>>
418 static std::basic_string<Path_char_type, Dest_traits, Dest_allocator> to_string(
419 const std::basic_string<Source_char_type, Traits, Allocator> &source,
420 const Allocator &a = Allocator())
421 {
422 return Convert_range::template to_string<Dest_traits, Dest_allocator>(
423 source.begin(), source.end(), a);
424 }
425 };
426
427 template <typename Path_char_type, typename Source_char_type, typename Traits>
428 struct
429 Path_convert_source<Path_char_type,
430 basic_string_view<Source_char_type, Traits>,
431 typename std::
432 enable_if<Path_convert_range<Path_char_type,
433 typename basic_string_view<Source_char_type,
434 Traits>::
435 const_iterator>::is_convertible>::type>
436 {
437 typedef Path_convert_range<Path_char_type,
438 typename basic_string_view<Source_char_type, Traits>::const_iterator>
439 Convert_range;
440 static constexpr bool is_convertible = true;
441 template <typename Dest_traits = std::char_traits<Path_char_type>,
442 typename Allocator = std::allocator<Path_char_type>>
443 static std::basic_string<Path_char_type, Dest_traits, Allocator> to_string(
444 const basic_string_view<Source_char_type, Traits> &source, const Allocator &a = Allocator())
445 {
446 return Convert_range::template to_string<Dest_traits, Allocator>(
447 source.begin(), source.end(), a);
448 }
449 };
450
451 template <typename Char_type>
452 struct Path_convert_source<Char_type, std::basic_string<Char_type>, void>
453 {
454 static constexpr bool is_convertible = true;
455 template <typename Traits = std::char_traits<Char_type>,
456 typename Allocator = std::allocator<Char_type>>
457 static std::basic_string<Char_type, Traits, Allocator> to_string(
458 const std::basic_string<Char_type> &source, const Allocator &a = Allocator())
459 {
460 return std::basic_string<Char_type, Traits, Allocator>(source.begin(), source.end(), a);
461 }
462 static std::basic_string<Char_type> to_string(
463 const std::basic_string<Char_type> &source,
464 const std::allocator<Char_type> & = std::allocator<Char_type>())
465 {
466 return source;
467 }
468 };
469
470 template <typename Char_type, typename Iterator>
471 struct Path_convert_source<Char_type,
472 Iterator,
473 typename std::enable_if<!std::is_same<
474 typename Path_is_convertable_iterator_type<Iterator>::Char_type,
475 Char_type>::value>::type>
476 {
477 static constexpr bool is_convertible = true;
478 typedef Path_convert_range<Char_type, Path_convert_single_iterator_adaptor<Iterator>>
479 Convert_range;
480 template <typename Traits = std::char_traits<Char_type>,
481 typename Allocator = std::allocator<Char_type>>
482 static std::basic_string<Char_type, Traits, Allocator> to_string(
483 Iterator iterator, const Allocator &a = Allocator())
484 {
485 return Convert_range::template to_string<Traits, Allocator>(
486 Path_convert_single_iterator_adaptor<Iterator>(iterator), Path_iterator_sentinel(), a);
487 }
488 };
489
490 template <typename Char_type>
491 struct Path_convert_source<Char_type, const Char_type *, void>
492 {
493 static constexpr bool is_convertible = true;
494 template <typename Traits = std::char_traits<Char_type>,
495 typename Allocator = std::allocator<Char_type>>
496 static std::basic_string<Char_type, Traits, Allocator> to_string(
497 const Char_type *source, const Allocator &a = Allocator())
498 {
499 return {source, a};
500 }
501 };
502
503 template <typename Path_char_type, typename Source_char_type, std::size_t N>
504 struct Path_convert_source<Path_char_type, Source_char_type[N], void>
505 : public Path_convert_source<Path_char_type, const Source_char_type *, void>
506 {
507 };
508
509 struct Path_index_range
510 {
511 std::size_t begin;
512 std::size_t end;
513 constexpr Path_index_range() noexcept : begin(0), end(0)
514 {
515 }
516 constexpr Path_index_range(std::size_t begin, std::size_t end) noexcept : begin(begin), end(end)
517 {
518 }
519 template <typename Char_type, typename Traits>
520 constexpr Path_index_range(basic_string_view<Char_type, Traits> str,
521 typename basic_string_view<Char_type, Traits>::iterator begin,
522 typename basic_string_view<Char_type, Traits>::iterator end) noexcept
523 : begin(begin - str.begin()),
524 end(end - str.begin())
525 {
526 }
527 constexpr bool empty() const noexcept
528 {
529 return begin == end;
530 }
531 constexpr std::size_t size() const noexcept
532 {
533 return end - begin;
534 }
535 };
536
537 struct Path_tester;
538 }
539
540 template <detail::Path_traits_kind Traits_kind = detail::default_path_traits_kind,
541 typename Char_type = typename detail::Path_traits<Traits_kind>::value_type,
542 Char_type Preferred_separator = detail::Path_traits<Traits_kind>::preferred_separator,
543 bool Needs_root_name_to_be_absolute =
544 detail::Path_traits<Traits_kind>::needs_root_name_to_be_absolute>
545 class basic_path;
546
547 template <detail::Path_traits_kind Traits_kind,
548 typename Char_type,
549 Char_type Preferred_separator,
550 bool Needs_root_name_to_be_absolute>
551 std::size_t hash_value(
552 const basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>
553 &v) noexcept;
554
555 template <detail::Path_traits_kind Traits_kind,
556 typename Char_type,
557 Char_type Preferred_separator,
558 bool Needs_root_name_to_be_absolute>
559 class basic_path
560 {
561 friend struct detail::Path_tester;
562 friend std::size_t hash_value(const basic_path &v) noexcept;
563 static_assert(std::is_same<Char_type, char>::value || std::is_same<Char_type, wchar_t>::value,
564 "");
565
566 private:
567 typedef detail::Path_traits_kind Path_traits_kind;
568 typedef detail::Path_part_kind Path_part_kind;
569 typedef detail::Path_index_range Path_index_range;
570
571 public:
572 typedef Char_type value_type;
573 typedef std::basic_string<Char_type> string_type;
574 enum format
575 {
576 native_format,
577 generic_format,
578 auto_format
579 };
580 static constexpr Char_type preferred_separator = Preferred_separator;
581
582 private:
583 typedef basic_string_view<Char_type> string_view_type;
584 class Parts
585 {
586 private:
587 std::size_t allocated_count;
588 std::size_t used_count;
589 basic_path *values;
590
591 private:
592 static basic_path *allocate(std::size_t count);
593 template <typename... Args>
594 static void construct(basic_path &value, Args &&... args)
595 {
596 ::new(static_cast<void *>(&value)) basic_path(std::forward<Args>(args)...);
597 }
598 static void destruct(basic_path &value) noexcept
599 {
600 value.~basic_path();
601 }
602 static void deallocate(basic_path *values, std::size_t count) noexcept;
603 void reallocate(std::size_t new_allocated_count)
604 {
605 assert(new_allocated_count >= used_count);
606 if(used_count == 0)
607 {
608 deallocate(values, allocated_count);
609 values = nullptr;
610 allocated_count = 0; // set now in case allocate throws
611 values = allocate(new_allocated_count);
612 allocated_count = new_allocated_count;
613 }
614 else
615 {
616 Parts new_parts;
617 new_parts.reserve(new_allocated_count);
618 for(std::size_t i = 0; i < used_count; i++)
619 new_parts.push_back(std::move(values[i]));
620 swap(new_parts);
621 }
622 }
623 static constexpr std::uint64_t get_expanded_count_64(std::uint64_t count) noexcept
624 {
625 constexpr std::uint64_t high_bit = 1ULL << 63;
626 if(count == 0 || count >= high_bit)
627 return count;
628 return 1ULL << (64 - clz64(count - 1));
629 }
630 static constexpr std::uint32_t get_expanded_count_32(std::uint32_t count) noexcept
631 {
632 constexpr std::uint32_t high_bit = 1UL << 31;
633 if(count == 0 || count >= high_bit)
634 return count;
635 return 1UL << (32 - clz32(count - 1));
636 }
637 static constexpr std::size_t get_expanded_count(std::size_t count) noexcept
638 {
639 constexpr bool is_size_t_uint32_t = std::is_same<std::size_t, std::uint32_t>::value,
640 is_size_t_uint64_t = std::is_same<std::size_t, std::uint64_t>::value;
641 static_assert(is_size_t_uint32_t || is_size_t_uint64_t, "");
642 if(is_size_t_uint32_t)
643 return get_expanded_count_32(static_cast<std::uint32_t>(count));
644 return static_cast<std::size_t>(get_expanded_count_64(count));
645 }
646
647 public:
648 constexpr Parts() noexcept : allocated_count(0), used_count(0), values(nullptr)
649 {
650 }
651 Parts(const Parts &rt) : Parts()
652 {
653 Parts new_parts;
654 new_parts.reserve(rt.used_count);
655 for(std::size_t i = 0; i < rt.used_count; i++)
656 push_back(rt.values[i]);
657 swap(new_parts);
658 }
659 Parts(Parts &&rt) noexcept : Parts()
660 {
661 swap(rt);
662 }
663 Parts &operator=(Parts &&rt) noexcept
664 {
665 Parts(std::move(rt)).swap(*this);
666 return *this;
667 }
668 Parts &operator=(const Parts &rt)
669 {
670 if(this == &rt)
671 return *this;
672 if(allocated_count < rt.used_count)
673 {
674 Parts(rt).swap(*this);
675 return *this;
676 }
677 while(used_count > rt.used_count)
678 pop_back();
679 for(std::size_t i = 0; i < used_count; i++)
680 values[i] = rt[i];
681 while(used_count < rt.used_count)
682 push_back(rt[used_count]);
683 return *this;
684 }
685 ~Parts() noexcept
686 {
687 while(used_count > 0)
688 destruct(values[--used_count]);
689 deallocate(values, allocated_count);
690 }
691 void swap(Parts &rt) noexcept
692 {
693 using std::swap;
694 swap(allocated_count, rt.allocated_count);
695 swap(used_count, rt.used_count);
696 swap(values, rt.values);
697 }
698 void reserve(std::size_t new_allocated_count)
699 {
700 if(new_allocated_count > allocated_count)
701 reallocate(new_allocated_count);
702 }
703 bool empty() const noexcept
704 {
705 return used_count == 0;
706 }
707 std::size_t size() const noexcept
708 {
709 return used_count;
710 }
711 std::size_t capacity() const noexcept
712 {
713 return allocated_count;
714 }
715 typedef basic_path *iterator;
716 typedef const basic_path *const_iterator;
717 iterator begin() noexcept
718 {
719 return values;
720 }
721 iterator end() noexcept
722 {
723 return values + used_count;
724 }
725 const_iterator begin() const noexcept
726 {
727 return values;
728 }
729 const_iterator end() const noexcept
730 {
731 return values + used_count;
732 }
733 const_iterator cbegin() const noexcept
734 {
735 return values;
736 }
737 const_iterator cend() const noexcept
738 {
739 return values + used_count;
740 }
741 template <typename... Args>
742 void emplace_back(Args &&... args)
743 {
744 if(used_count >= allocated_count)
745 reallocate(get_expanded_count(used_count + 1));
746 construct(values[used_count], std::forward<Args>(args)...);
747 used_count++;
748 }
749 void push_back(const basic_path &v)
750 {
751 emplace_back(v);
752 }
753 void push_back(basic_path &&v)
754 {
755 emplace_back(v);
756 }
757 void pop_back() noexcept
758 {
759 assert(used_count > 0);
760 destruct(values[--used_count]);
761 }
762 void clear() noexcept
763 {
764 while(used_count > 0)
765 pop_back();
766 }
767 basic_path &operator[](std::size_t index) noexcept
768 {
769 assert(index < used_count);
770 return values[index];
771 }
772 const basic_path &operator[](std::size_t index) const noexcept
773 {
774 assert(index < used_count);
775 return values[index];
776 }
777 };
778
779 private:
780 Parts parts;
781 string_type value;
782 detail::Path_part_kind kind;
783
784 public:
785 class iterator
786 {
787 template <detail::Path_traits_kind, typename Char_type2, Char_type2, bool>
788 friend class basic_path;
789
790 public:
791 typedef basic_path value_type;
792 typedef const basic_path *pointer;
793 typedef const basic_path &reference;
794 typedef std::ptrdiff_t difference_type;
795 typedef std::bidirectional_iterator_tag iterator_category;
796
797 private:
798 const basic_path *path;
799 std::size_t index;
800 constexpr iterator(const basic_path *path, std::size_t index) noexcept : path(path),
801 index(index)
802 {
803 }
804
805 public:
806 constexpr iterator() noexcept : path(nullptr), index()
807 {
808 }
809 constexpr iterator &operator++() noexcept
810 {
811 index++;
812 return *this;
813 }
814 constexpr iterator &operator--() noexcept
815 {
816 index--;
817 return *this;
818 }
819 constexpr iterator operator++(int) noexcept
820 {
821 return iterator(path, index++);
822 }
823 constexpr iterator operator--(int) noexcept
824 {
825 return iterator(path, index--);
826 }
827 const basic_path *operator->() const
828 {
829 assert(path);
830 if(path->kind == Path_part_kind::multiple_parts)
831 return &path->parts[index];
832 return path;
833 }
834 const basic_path &operator*() const
835 {
836 return *operator->();
837 }
838 constexpr bool operator==(const iterator &rt) const noexcept
839 {
840 return index == rt.index;
841 }
842 constexpr bool operator!=(const iterator &rt) const noexcept
843 {
844 return index != rt.index;
845 }
846 };
847 typedef iterator const_iterator;
848
849 private:
850 static constexpr bool is_ascii_letter(Char_type v) noexcept
851 {
852 auto ch = static_cast<unsigned char>(v);
853 if(static_cast<Char_type>(ch) != v)
854 return false;
855 if(ch >= 'a' && ch <= 'z')
856 return true;
857 if(ch >= 'A' && ch <= 'Z')
858 return true;
859 return false;
860 }
861 template <typename Char_type2>
862 static constexpr bool is_separator(Char_type2 v) noexcept
863 {
864 return v == static_cast<Char_type2>('/')
865 || v == static_cast<Char_type2>(preferred_separator);
866 }
867 template <bool Ignore_root_parts = false, typename Fn>
868 static bool parse(
869 string_view_type value,
870 Fn callback,
871 [[gnu::unused]] format fmt = auto_format) noexcept(noexcept(callback(Path_index_range(),
872 Path_part_kind())))
873 {
874 constexpr Char_type colon = ':';
875 typedef typename std::char_traits<Char_type>::int_type Int_type;
876 constexpr Int_type eof = std::char_traits<Char_type>::eof();
877 auto char_iter = value.begin();
878 auto peek = [&]() -> Int_type
879 {
880 if(char_iter == value.end())
881 return eof;
882 return std::char_traits<Char_type>::to_int_type(*char_iter);
883 };
884 auto get = [&]() -> Int_type
885 {
886 if(char_iter == value.end())
887 return eof;
888 return std::char_traits<Char_type>::to_int_type(*char_iter++);
889 };
890 if(value.empty())
891 return true;
892 if(!Ignore_root_parts && Traits_kind == Path_traits_kind::windows && value.size() >= 2
893 && is_ascii_letter(value[0])
894 && value[1] == colon)
895 {
896 char_iter += 2;
897 if(!callback(Path_index_range(value, value.begin(), char_iter),
898 Path_part_kind::relative_root_name))
899 return false;
900 }
901 else if(!Ignore_root_parts && Traits_kind == Path_traits_kind::windows && value.size() >= 2
902 && is_separator(value[0])
903 && is_separator(value[1]))
904 {
905 while(peek() != eof && is_separator(peek()))
906 get();
907 while(peek() != eof && !is_separator(peek()))
908 get();
909 if(!callback(Path_index_range(value, value.begin(), char_iter),
910 Path_part_kind::absolute_root_name))
911 return false;
912 }
913 if(!Ignore_root_parts && peek() != eof && is_separator(peek()))
914 {
915 auto start_iter = char_iter;
916 do
917 {
918 get();
919 } while(peek() != eof && is_separator(peek()));
920 if(!callback(Path_index_range(value, start_iter, char_iter), Path_part_kind::root_dir))
921 return false;
922 }
923 if(Ignore_root_parts && peek() != eof && is_separator(peek()))
924 {
925 if(!callback(Path_index_range(value, char_iter, char_iter), Path_part_kind::file_name))
926 return false;
927 }
928 if(peek() != eof && !is_separator(peek()))
929 {
930 auto start_iter = char_iter;
931 do
932 {
933 get();
934 } while(peek() != eof && !is_separator(peek()));
935 if(!callback(Path_index_range(value, start_iter, char_iter), Path_part_kind::file_name))
936 return false;
937 }
938 while(peek() != eof)
939 {
940 auto start_iter = char_iter;
941 do
942 {
943 get();
944 } while(peek() != eof && is_separator(peek()));
945 if(!callback(Path_index_range(value, start_iter, char_iter),
946 Path_part_kind::path_separator))
947 return false;
948 start_iter = char_iter;
949 while(peek() != eof && !is_separator(peek()))
950 get();
951 if(!callback(Path_index_range(value, start_iter, char_iter), Path_part_kind::file_name))
952 return false;
953 }
954 return true;
955 }
956 void parse(format fmt = auto_format)
957 {
958 constexpr Char_type generic_separator = '/';
959 auto last_part_kind = Path_part_kind::multiple_parts;
960 std::size_t part_count = 0;
961 bool need_generic_conversion = false;
962 parse(value,
963 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
964 {
965 if(part_kind == Path_part_kind::path_separator)
966 return true;
967 if(generic_separator != preferred_separator && !need_generic_conversion)
968 {
969 for(std::size_t i = index_range.begin; i < index_range.end; i++)
970 {
971 if(is_separator(value[i]) && value[i] != generic_separator)
972 {
973 need_generic_conversion = true;
974 break;
975 }
976 }
977 }
978 last_part_kind = part_kind;
979 part_count++;
980 return true;
981 },
982 fmt);
983 if(part_count == 1 && !need_generic_conversion)
984 {
985 kind = last_part_kind;
986 parts.clear();
987 return;
988 }
989 else
990 {
991 kind = Path_part_kind::multiple_parts;
992 }
993 while(parts.size() > part_count)
994 parts.pop_back();
995 parts.reserve(part_count);
996 std::size_t part_index = 0;
997 parse(value,
998 [&](Path_index_range index_range, Path_part_kind part_kind)
999 {
1000 if(part_kind == Path_part_kind::path_separator)
1001 return true;
1002 if(part_index >= parts.size())
1003 parts.emplace_back();
1004 parts[part_index].value.assign(value.data() + index_range.begin,
1005 index_range.size());
1006 parts[part_index].kind = part_kind;
1007 change_separator(parts[part_index].value, generic_separator);
1008 part_index++;
1009 return true;
1010 },
1011 fmt);
1012 }
1013 static Path_index_range get_filename_index_range(string_view_type value) noexcept
1014 {
1015 Path_index_range retval(value.size(), value.size());
1016 parse(value,
1017 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1018 {
1019 if(part_kind == Path_part_kind::file_name)
1020 retval = index_range;
1021 return true;
1022 });
1023 return retval;
1024 }
1025 static Path_index_range get_stem_index_range(string_view_type value) noexcept
1026 {
1027 return get_stem_index_range(value, get_filename_index_range(value));
1028 }
1029 static Path_index_range get_stem_index_range(string_view_type value,
1030 Path_index_range filename_index_range) noexcept
1031 {
1032 constexpr Char_type dot = '.';
1033 if(filename_index_range.size() <= 1)
1034 return filename_index_range;
1035 for(std::size_t i = filename_index_range.end; i > filename_index_range.begin; i--)
1036 {
1037 if(value[i - 1] == dot)
1038 {
1039 if(i == filename_index_range.begin + 1)
1040 return filename_index_range;
1041 if(i == filename_index_range.begin + 2 && value[filename_index_range.begin] == dot)
1042 return filename_index_range;
1043 return Path_index_range(filename_index_range.begin, i - 1);
1044 }
1045 }
1046 return filename_index_range;
1047 }
1048 static Path_index_range get_extension_index_range(string_view_type value) noexcept
1049 {
1050 return get_extension_index_range(value, get_filename_index_range(value));
1051 }
1052 static Path_index_range get_extension_index_range(
1053 string_view_type value, Path_index_range filename_index_range) noexcept
1054 {
1055 return get_extension_index_range(
1056 value, filename_index_range, get_stem_index_range(value, filename_index_range));
1057 }
1058 static Path_index_range get_extension_index_range([[gnu::unused]] string_view_type value,
1059 Path_index_range filename_index_range,
1060 Path_index_range stem_index_range) noexcept
1061 {
1062 return Path_index_range(stem_index_range.end, filename_index_range.end);
1063 }
1064 static Path_index_range get_root_name_index_range(string_view_type value) noexcept
1065 {
1066 Path_index_range retval(0, 0);
1067 parse(value,
1068 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1069 {
1070 if(part_kind == Path_part_kind::absolute_root_name
1071 || part_kind == Path_part_kind::relative_root_name)
1072 retval = index_range;
1073 return false;
1074 });
1075 return retval;
1076 }
1077 static Path_index_range get_root_dir_index_range(string_view_type value) noexcept
1078 {
1079 Path_index_range retval(0, 0);
1080 parse(value,
1081 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1082 {
1083 if(part_kind == Path_part_kind::root_dir)
1084 {
1085 retval = index_range;
1086 }
1087 else if(part_kind == Path_part_kind::absolute_root_name
1088 || part_kind == Path_part_kind::relative_root_name)
1089 {
1090 retval = Path_index_range(index_range.end, index_range.end);
1091 return true;
1092 }
1093 return false;
1094 });
1095 return retval;
1096 }
1097 static Path_index_range get_root_path_index_range(string_view_type value) noexcept
1098 {
1099 Path_index_range retval(0, 0);
1100 parse(value,
1101 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1102 {
1103 if(part_kind == Path_part_kind::absolute_root_name
1104 || part_kind == Path_part_kind::relative_root_name)
1105 {
1106 retval = index_range;
1107 return true;
1108 }
1109 else if(part_kind == Path_part_kind::root_dir)
1110 {
1111 retval.end = index_range.end;
1112 return false;
1113 }
1114 return false;
1115 });
1116 return retval;
1117 }
1118 static Path_index_range get_relative_path_index_range(string_view_type value) noexcept
1119 {
1120 Path_index_range retval(value.size(), value.size());
1121 parse(value,
1122 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1123 {
1124 if(part_kind == Path_part_kind::absolute_root_name
1125 || part_kind == Path_part_kind::relative_root_name
1126 || part_kind == Path_part_kind::root_dir)
1127 {
1128 return true;
1129 }
1130 retval.begin = index_range.begin;
1131 return false;
1132 });
1133 return retval;
1134 }
1135 static Path_index_range get_parent_path_index_range(string_view_type value) noexcept
1136 {
1137 Path_index_range retval(0, 0);
1138 std::size_t last_file_name_end_index = 0;
1139 parse(value,
1140 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1141 {
1142 switch(part_kind)
1143 {
1144 case Path_part_kind::path_separator:
1145 return true;
1146 case Path_part_kind::absolute_root_name:
1147 case Path_part_kind::relative_root_name:
1148 case Path_part_kind::root_dir:
1149 retval.end = index_range.end;
1150 return true;
1151 case Path_part_kind::file_name:
1152 if(last_file_name_end_index != 0)
1153 retval.end = last_file_name_end_index;
1154 last_file_name_end_index = index_range.end;
1155 return true;
1156 case Path_part_kind::multiple_parts:
1157 break;
1158 }
1159 assert(false);
1160 return false;
1161 });
1162 return retval;
1163 }
1164
1165 public:
1166 basic_path() noexcept : parts(), value(), kind(Path_part_kind::multiple_parts)
1167 {
1168 }
1169 basic_path(const basic_path &) = default;
1170 basic_path(basic_path &&rt) noexcept : parts(), value(), kind()
1171 {
1172 swap(rt);
1173 }
1174 basic_path(string_type &&source, format fmt = auto_format)
1175 : parts(), value(std::move(source)), kind()
1176 {
1177 parse(fmt);
1178 }
1179 template <typename Source>
1180 basic_path(const Source &source, format fmt = auto_format)
1181 : basic_path(detail::Path_convert_source<Char_type, Source>::to_string(source), fmt)
1182 {
1183 }
1184 template <typename Input_iterator>
1185 basic_path(Input_iterator first, Input_iterator last, format fmt = auto_format)
1186 : basic_path(detail::Path_convert_range<Char_type, Input_iterator>::to_string(first, last),
1187 fmt)
1188 {
1189 }
1190 basic_path &operator=(const basic_path &rt) = default;
1191 basic_path &operator=(basic_path &&rt) noexcept
1192 {
1193 basic_path(std::move(rt)).swap(*this);
1194 return *this;
1195 }
1196 basic_path &operator=(string_type &&new_value)
1197 {
1198 value = std::move(new_value);
1199 parse();
1200 return *this;
1201 }
1202 template <typename Source>
1203 basic_path &operator=(const Source &source)
1204 {
1205 assign(source);
1206 return *this;
1207 }
1208 basic_path &assign(string_type &&new_value)
1209 {
1210 return operator=(new_value);
1211 }
1212 basic_path &assign(const string_type &new_value)
1213 {
1214 value = new_value;
1215 parse();
1216 return *this;
1217 }
1218 basic_path &assign(const string_view_type &new_value)
1219 {
1220 // use assign to prevent allocating a temporary string_type
1221 value.assign(new_value.data(), new_value.size());
1222 parse();
1223 return *this;
1224 }
1225 template <typename Source>
1226 basic_path &assign(const Source &source)
1227 {
1228 assign(detail::Path_convert_source<Char_type, Source>::to_string(source));
1229 return *this;
1230 }
1231 template <typename Input_iterator>
1232 basic_path &assign(Input_iterator first, Input_iterator last)
1233 {
1234 assign(detail::Path_convert_range<Char_type, Input_iterator>::to_string(first, last));
1235 return *this;
1236 }
1237
1238 private:
1239 template <bool Check_for_shared_memory = true>
1240 void append_string(string_view_type str)
1241 {
1242 bool just_need_to_assign = is_absolute(str);
1243 if(!just_need_to_assign && !get_root_name_index_range(str).empty())
1244 {
1245 auto my_root_name_index_range = get_root_name_index_range(value);
1246 auto str_root_name_index_range = get_root_name_index_range(str);
1247 if(my_root_name_index_range.empty()
1248 || string_view_type(value)
1249 .substr(my_root_name_index_range.begin, my_root_name_index_range.size())
1250 == str.substr(str_root_name_index_range.begin,
1251 str_root_name_index_range.size()))
1252 just_need_to_assign = true;
1253 }
1254 if(just_need_to_assign)
1255 {
1256 assign(str);
1257 return;
1258 }
1259 static_assert(std::is_same<typename string_view_type::iterator, const Char_type *>::value,
1260 "");
1261 if(Check_for_shared_memory && str.begin() <= value.data() + value.size()
1262 && str.end() >= value.data())
1263 {
1264 // value and str share memory, reallocate str
1265 append_string<false>(static_cast<string_type>(str));
1266 return;
1267 }
1268 auto str_root_name_index_range = get_root_name_index_range(str);
1269 assert(str_root_name_index_range.begin == 0);
1270 str.remove_prefix(str_root_name_index_range.end);
1271 if(!get_root_dir_index_range(str).empty())
1272 {
1273 auto my_root_name_index_range = get_root_name_index_range(value);
1274 assert(my_root_name_index_range.begin == 0);
1275 value.resize(my_root_name_index_range.end);
1276 }
1277 else if(!get_filename_index_range(value).empty()
1278 || (get_root_dir_index_range(value).empty() && is_absolute()))
1279 {
1280 value.reserve(value.size() + 1 + str.size());
1281 value += preferred_separator;
1282 }
1283 value += str;
1284 parse();
1285 }
1286
1287 public:
1288 basic_path &operator/=(const basic_path &p)
1289 {
1290 append_string(p.value);
1291 return *this;
1292 }
1293 basic_path &operator/=(const string_type &p)
1294 {
1295 append_string(p);
1296 return *this;
1297 }
1298 basic_path &operator/=(const string_view_type &p)
1299 {
1300 append_string(p);
1301 return *this;
1302 }
1303 template <typename Source>
1304 basic_path &operator/=(const Source &source)
1305 {
1306 append_string(detail::Path_convert_source<Char_type, Source>::to_string(source));
1307 return *this;
1308 }
1309 template <typename Source>
1310 basic_path &append(const Source &source)
1311 {
1312 operator/=(source);
1313 return *this;
1314 }
1315 template <typename Input_iterator>
1316 basic_path &append(Input_iterator first, Input_iterator last)
1317 {
1318 append_string(
1319 detail::Path_convert_range<Char_type, Input_iterator>::to_string(first, last));
1320 return *this;
1321 }
1322 friend basic_path operator/(const basic_path &l, const basic_path &r)
1323 {
1324 return basic_path(l) /= r;
1325 }
1326 friend basic_path operator/(basic_path &&l, const basic_path &r)
1327 {
1328 return l /= r;
1329 }
1330 basic_path &operator+=(const basic_path &p)
1331 {
1332 value += p.value;
1333 parse();
1334 return *this;
1335 }
1336 basic_path &operator+=(const string_type &p)
1337 {
1338 value += p;
1339 parse();
1340 return *this;
1341 }
1342 basic_path &operator+=(const string_view_type &p)
1343 {
1344 value += p;
1345 parse();
1346 return *this;
1347 }
1348 template <typename Source>
1349 basic_path &operator+=(const Source &source)
1350 {
1351 value += detail::Path_convert_source<Char_type, Source>::to_string(source);
1352 parse();
1353 return *this;
1354 }
1355 template <typename Source>
1356 basic_path &concat(const Source &source)
1357 {
1358 operator+=(source);
1359 return *this;
1360 }
1361 template <typename Input_iterator>
1362 basic_path &concat(Input_iterator first, Input_iterator last)
1363 {
1364 value += detail::Path_convert_range<Char_type, Input_iterator>::to_string(first, last);
1365 parse();
1366 return *this;
1367 }
1368 const Char_type *c_str() const noexcept
1369 {
1370 return value.c_str();
1371 }
1372 const string_type &native() const noexcept
1373 {
1374 return value;
1375 }
1376 operator string_type() const
1377 {
1378 return value;
1379 }
1380 void clear() noexcept
1381 {
1382 value.clear();
1383 parse();
1384 }
1385
1386 private:
1387 template <typename Char_type2, typename Traits, typename Allocator>
1388 static void change_separator(std::basic_string<Char_type2, Traits, Allocator> &str,
1389 Char_type2 separator) noexcept
1390 {
1391 for(auto &ch : str)
1392 {
1393 if(is_separator(ch))
1394 ch = separator;
1395 }
1396 }
1397 basic_path &change_separator(Char_type separator) noexcept
1398 {
1399 change_separator(value, separator);
1400 for(auto &part : parts)
1401 change_separator(part.value, separator);
1402 return *this;
1403 }
1404
1405 public:
1406 basic_path &make_preferred() noexcept
1407 {
1408 change_separator(preferred_separator);
1409 return *this;
1410 }
1411 basic_path &remove_filename()
1412 {
1413 auto filename_index_range = get_filename_index_range(value);
1414 if(!filename_index_range.empty())
1415 {
1416 value.erase(filename_index_range.begin, filename_index_range.size());
1417 parse();
1418 }
1419 return *this;
1420 }
1421 basic_path &replace_filename(const basic_path &replacement)
1422 {
1423 remove_filename();
1424 operator/=(replacement);
1425 return *this;
1426 }
1427 basic_path &replace_extension(const basic_path &replacement = basic_path())
1428 {
1429 constexpr Char_type dot = '.';
1430 auto extension_index_range = get_extension_index_range(value);
1431 if(!extension_index_range.empty())
1432 value.erase(extension_index_range.begin, extension_index_range.size());
1433 else if(replacement.value.empty())
1434 return *this;
1435 if(!replacement.value.empty() && replacement.value.front() != dot)
1436 {
1437 value.reserve(value.size() + 1 + replacement.value.size());
1438 value += dot;
1439 value += replacement.value;
1440 }
1441 else
1442 {
1443 value += replacement.value;
1444 }
1445 parse();
1446 return *this;
1447 }
1448 void swap(basic_path &other) noexcept
1449 {
1450 using std::swap;
1451 swap(value, other.value);
1452 parts.swap(other.parts);
1453 swap(kind, other.kind);
1454 }
1455 bool has_root_path() const noexcept
1456 {
1457 return !get_root_path_index_range(value).empty();
1458 }
1459 bool has_root_name() const noexcept
1460 {
1461 return !get_root_name_index_range(value).empty();
1462 }
1463 bool has_root_directory() const noexcept
1464 {
1465 return !get_root_dir_index_range(value).empty();
1466 }
1467 bool has_relative_path() const noexcept
1468 {
1469 return !get_relative_path_index_range(value).empty();
1470 }
1471 bool has_parent_path() const noexcept
1472 {
1473 return !get_parent_path_index_range(value).empty();
1474 }
1475 bool has_filename() const noexcept
1476 {
1477 return !get_filename_index_range(value).empty();
1478 }
1479 bool has_stem() const noexcept
1480 {
1481 return !get_stem_index_range(value).empty();
1482 }
1483 bool has_extension() const noexcept
1484 {
1485 return !get_extension_index_range(value).empty();
1486 }
1487
1488 private:
1489 static bool is_absolute(string_view_type value) noexcept
1490 {
1491 bool has_root_dir = false;
1492 bool has_relative_root_name = false;
1493 bool has_absolute_root_name = false;
1494 parse(value,
1495 [&]([[gnu::unused]] Path_index_range index_range, Path_part_kind part_kind) noexcept
1496 {
1497 if(part_kind == Path_part_kind::relative_root_name)
1498 {
1499 has_relative_root_name = true;
1500 return true;
1501 }
1502 else if(part_kind == Path_part_kind::absolute_root_name)
1503 {
1504 has_absolute_root_name = true;
1505 return false;
1506 }
1507 else if(part_kind == Path_part_kind::root_dir)
1508 {
1509 has_root_dir = true;
1510 }
1511 return false;
1512 });
1513 if(has_absolute_root_name)
1514 return true;
1515 if(has_root_dir)
1516 {
1517 if(Needs_root_name_to_be_absolute)
1518 return has_relative_root_name;
1519 return true;
1520 }
1521 return false;
1522 }
1523
1524 public:
1525 bool is_absolute() const noexcept
1526 {
1527 return is_absolute(value);
1528 }
1529 bool is_relative() const noexcept
1530 {
1531 return !is_absolute(value);
1532 }
1533 template <typename String_char_type,
1534 typename String_traits_type = std::char_traits<String_char_type>,
1535 typename Allocator = std::allocator<String_char_type>>
1536 std::basic_string<String_char_type, String_traits_type, Allocator> string(
1537 const Allocator &a = Allocator()) const
1538 {
1539 return detail::Path_convert_source<String_char_type,
1540 string_type>::template to_string<String_traits_type,
1541 Allocator>(value, a);
1542 }
1543 std::string string() const
1544 {
1545 return string<char>();
1546 }
1547 std::wstring wstring() const
1548 {
1549 return string<wchar_t>();
1550 }
1551 std::string u8string() const
1552 {
1553 return string<char>();
1554 }
1555 std::u16string u16string() const
1556 {
1557 return string<char16_t>();
1558 }
1559 std::u32string u32string() const
1560 {
1561 return string<char32_t>();
1562 }
1563 template <typename String_char_type,
1564 typename String_traits_type = std::char_traits<String_char_type>,
1565 typename Allocator = std::allocator<String_char_type>>
1566 std::basic_string<String_char_type, String_traits_type, Allocator> generic_string(
1567 const Allocator &a = Allocator()) const
1568 {
1569 auto retval =
1570 detail::Path_convert_source<String_char_type,
1571 string_type>::template to_string<String_traits_type,
1572 Allocator>(value, a);
1573 change_separator(retval, static_cast<String_char_type>('/'));
1574 return retval;
1575 }
1576 std::string generic_string() const
1577 {
1578 return generic_string<char>();
1579 }
1580 std::wstring generic_wstring() const
1581 {
1582 return generic_string<wchar_t>();
1583 }
1584 std::string generic_u8string() const
1585 {
1586 return generic_string<char>();
1587 }
1588 std::u16string generic_u16string() const
1589 {
1590 return generic_string<char16_t>();
1591 }
1592 std::u32string generic_u32string() const
1593 {
1594 return generic_string<char32_t>();
1595 }
1596 template <typename Stream_char_type, typename Stream_traits_type>
1597 friend std::basic_ostream<Stream_char_type, Stream_traits_type> &operator<<(
1598 std::basic_ostream<Stream_char_type, Stream_traits_type> &os, const basic_path &p)
1599 {
1600 os << std::quoted(p.string<Stream_char_type, Stream_traits_type>());
1601 return os;
1602 }
1603 template <typename Stream_char_type, typename Stream_traits_type>
1604 friend std::basic_istream<Stream_char_type, Stream_traits_type> &operator>>(
1605 std::basic_istream<Stream_char_type, Stream_traits_type> &is, basic_path &p)
1606 {
1607 std::basic_string<Stream_char_type, Stream_traits_type> str;
1608 is >> std::quoted(str);
1609 p = std::move(str);
1610 return is;
1611 }
1612
1613 private:
1614 static int compare_part(string_view_type a,
1615 Path_part_kind a_kind,
1616 string_view_type b,
1617 Path_part_kind b_kind) noexcept
1618 {
1619 constexpr Char_type generic_separator_char = '/';
1620 string_view_type generic_separator(&generic_separator_char, 1);
1621 if(a_kind == Path_part_kind::root_dir)
1622 a = generic_separator;
1623 if(b_kind == Path_part_kind::root_dir)
1624 b = generic_separator;
1625 for(std::size_t i = 0; i < a.size() && i < b.size(); i++)
1626 {
1627 Char_type a_char = a[i];
1628 Char_type b_char = b[i];
1629 if(a_char == preferred_separator)
1630 a_char = generic_separator_char;
1631 if(b_char == preferred_separator)
1632 b_char = generic_separator_char;
1633 if(a_char < b_char)
1634 return -1;
1635 if(a_char > b_char)
1636 return 1;
1637 }
1638 if(a.size() < b.size())
1639 return -1;
1640 if(a.size() > b.size())
1641 return 1;
1642 return 0;
1643 }
1644
1645 public:
1646 int compare(string_view_type str) const noexcept
1647 {
1648 int retval;
1649 if(kind != Path_part_kind::multiple_parts)
1650 {
1651 retval = 1; // non-empty is more than empty
1652 parse(str,
1653 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1654 {
1655 if(part_kind == Path_part_kind::path_separator)
1656 return true;
1657 if(retval == 1) // initial value
1658 retval = compare_part(value,
1659 kind,
1660 str.substr(index_range.begin, index_range.size()),
1661 part_kind);
1662 else
1663 retval = -1; // one-element is less than two-elements
1664 return retval == 0;
1665 });
1666 }
1667 else
1668 {
1669 retval = 0;
1670 auto part_iter = parts.begin();
1671 parse(str,
1672 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
1673 {
1674 if(part_kind == Path_part_kind::path_separator)
1675 return true;
1676 if(part_iter == parts.end())
1677 {
1678 retval = -1; // empty is less than non-empty
1679 }
1680 else
1681 {
1682 retval = compare_part(part_iter->value,
1683 part_iter->kind,
1684 str.substr(index_range.begin, index_range.size()),
1685 part_kind);
1686 ++part_iter;
1687 }
1688 return retval == 0;
1689 });
1690 if(retval == 0 && part_iter != parts.end())
1691 retval = 1; // more-elements is more than fewer-elements
1692 }
1693 return retval;
1694 }
1695 int compare(const string_type &str) const noexcept
1696 {
1697 return compare(string_view_type(str));
1698 }
1699 int compare(const Char_type *str) const
1700 {
1701 return compare(string_view_type(str));
1702 }
1703 int compare(const basic_path &rt) const noexcept
1704 {
1705 return compare(rt.value);
1706 }
1707 friend bool operator==(const basic_path &l, const basic_path &r) noexcept
1708 {
1709 return l.compare(r) == 0;
1710 }
1711 friend bool operator!=(const basic_path &l, const basic_path &r) noexcept
1712 {
1713 return l.compare(r) != 0;
1714 }
1715 friend bool operator<=(const basic_path &l, const basic_path &r) noexcept
1716 {
1717 return l.compare(r) <= 0;
1718 }
1719 friend bool operator>=(const basic_path &l, const basic_path &r) noexcept
1720 {
1721 return l.compare(r) >= 0;
1722 }
1723 friend bool operator<(const basic_path &l, const basic_path &r) noexcept
1724 {
1725 return l.compare(r) < 0;
1726 }
1727 friend bool operator>(const basic_path &l, const basic_path &r) noexcept
1728 {
1729 return l.compare(r) > 0;
1730 }
1731 friend bool operator==(const basic_path &l, string_view_type r) noexcept
1732 {
1733 return l.compare(r) == 0;
1734 }
1735 friend bool operator!=(const basic_path &l, string_view_type r) noexcept
1736 {
1737 return l.compare(r) != 0;
1738 }
1739 friend bool operator<=(const basic_path &l, string_view_type r) noexcept
1740 {
1741 return l.compare(r) <= 0;
1742 }
1743 friend bool operator>=(const basic_path &l, string_view_type r) noexcept
1744 {
1745 return l.compare(r) >= 0;
1746 }
1747 friend bool operator<(const basic_path &l, string_view_type r) noexcept
1748 {
1749 return l.compare(r) < 0;
1750 }
1751 friend bool operator>(const basic_path &l, string_view_type r) noexcept
1752 {
1753 return l.compare(r) > 0;
1754 }
1755 friend bool operator==(string_view_type l, const basic_path &r) noexcept
1756 {
1757 return r.compare(l) == 0;
1758 }
1759 friend bool operator!=(string_view_type l, const basic_path &r) noexcept
1760 {
1761 return r.compare(l) != 0;
1762 }
1763 friend bool operator<=(string_view_type l, const basic_path &r) noexcept
1764 {
1765 return r.compare(l) >= 0;
1766 }
1767 friend bool operator>=(string_view_type l, const basic_path &r) noexcept
1768 {
1769 return r.compare(l) <= 0;
1770 }
1771 friend bool operator<(string_view_type l, const basic_path &r) noexcept
1772 {
1773 return r.compare(l) > 0;
1774 }
1775 friend bool operator>(string_view_type l, const basic_path &r) noexcept
1776 {
1777 return r.compare(l) < 0;
1778 }
1779 friend bool operator==(const basic_path &l, string_type r) noexcept
1780 {
1781 return l.compare(r) == 0;
1782 }
1783 friend bool operator!=(const basic_path &l, string_type r) noexcept
1784 {
1785 return l.compare(r) != 0;
1786 }
1787 friend bool operator<=(const basic_path &l, string_type r) noexcept
1788 {
1789 return l.compare(r) <= 0;
1790 }
1791 friend bool operator>=(const basic_path &l, string_type r) noexcept
1792 {
1793 return l.compare(r) >= 0;
1794 }
1795 friend bool operator<(const basic_path &l, string_type r) noexcept
1796 {
1797 return l.compare(r) < 0;
1798 }
1799 friend bool operator>(const basic_path &l, string_type r) noexcept
1800 {
1801 return l.compare(r) > 0;
1802 }
1803 friend bool operator==(string_type l, const basic_path &r) noexcept
1804 {
1805 return r.compare(l) == 0;
1806 }
1807 friend bool operator!=(string_type l, const basic_path &r) noexcept
1808 {
1809 return r.compare(l) != 0;
1810 }
1811 friend bool operator<=(string_type l, const basic_path &r) noexcept
1812 {
1813 return r.compare(l) >= 0;
1814 }
1815 friend bool operator>=(string_type l, const basic_path &r) noexcept
1816 {
1817 return r.compare(l) <= 0;
1818 }
1819 friend bool operator<(string_type l, const basic_path &r) noexcept
1820 {
1821 return r.compare(l) > 0;
1822 }
1823 friend bool operator>(string_type l, const basic_path &r) noexcept
1824 {
1825 return r.compare(l) < 0;
1826 }
1827 friend bool operator==(const basic_path &l, const Char_type *r) noexcept
1828 {
1829 return l.compare(r) == 0;
1830 }
1831 friend bool operator!=(const basic_path &l, const Char_type *r) noexcept
1832 {
1833 return l.compare(r) != 0;
1834 }
1835 friend bool operator<=(const basic_path &l, const Char_type *r) noexcept
1836 {
1837 return l.compare(r) <= 0;
1838 }
1839 friend bool operator>=(const basic_path &l, const Char_type *r) noexcept
1840 {
1841 return l.compare(r) >= 0;
1842 }
1843 friend bool operator<(const basic_path &l, const Char_type *r) noexcept
1844 {
1845 return l.compare(r) < 0;
1846 }
1847 friend bool operator>(const basic_path &l, const Char_type *r) noexcept
1848 {
1849 return l.compare(r) > 0;
1850 }
1851 friend bool operator==(const Char_type *l, const basic_path &r) noexcept
1852 {
1853 return r.compare(l) == 0;
1854 }
1855 friend bool operator!=(const Char_type *l, const basic_path &r) noexcept
1856 {
1857 return r.compare(l) != 0;
1858 }
1859 friend bool operator<=(const Char_type *l, const basic_path &r) noexcept
1860 {
1861 return r.compare(l) >= 0;
1862 }
1863 friend bool operator>=(const Char_type *l, const basic_path &r) noexcept
1864 {
1865 return r.compare(l) <= 0;
1866 }
1867 friend bool operator<(const Char_type *l, const basic_path &r) noexcept
1868 {
1869 return r.compare(l) > 0;
1870 }
1871 friend bool operator>(const Char_type *l, const basic_path &r) noexcept
1872 {
1873 return r.compare(l) < 0;
1874 }
1875 iterator begin() const noexcept
1876 {
1877 return iterator(this, 0);
1878 }
1879 iterator end() const noexcept
1880 {
1881 return iterator(this, kind == Path_part_kind::multiple_parts ? parts.size() : 1);
1882 }
1883 basic_path root_name() const
1884 {
1885 auto index_range = get_root_name_index_range(value);
1886 if(index_range.empty())
1887 return {};
1888 return value.substr(index_range.begin, index_range.size());
1889 }
1890 basic_path root_directory() const
1891 {
1892 auto index_range = get_root_dir_index_range(value);
1893 if(index_range.empty())
1894 return {};
1895 return value.substr(index_range.begin, index_range.size());
1896 }
1897 basic_path root_path() const
1898 {
1899 auto index_range = get_root_path_index_range(value);
1900 if(index_range.empty())
1901 return {};
1902 return value.substr(index_range.begin, index_range.size());
1903 }
1904 basic_path relative_path() const
1905 {
1906 auto index_range = get_relative_path_index_range(value);
1907 if(index_range.empty())
1908 return {};
1909 return value.substr(index_range.begin, index_range.size());
1910 }
1911 basic_path parent_path() const
1912 {
1913 auto index_range = get_parent_path_index_range(value);
1914 if(index_range.empty())
1915 return {};
1916 return value.substr(index_range.begin, index_range.size());
1917 }
1918 basic_path filename() const
1919 {
1920 auto iter = end();
1921 if(iter == begin())
1922 return {};
1923 --iter;
1924 if(iter->kind == Path_part_kind::file_name)
1925 return *iter;
1926 return {};
1927 }
1928 basic_path stem() const
1929 {
1930 auto index_range = get_stem_index_range(value);
1931 if(index_range.empty())
1932 return {};
1933 return value.substr(index_range.begin, index_range.size());
1934 }
1935 basic_path extension() const
1936 {
1937 auto index_range = get_extension_index_range(value);
1938 if(index_range.empty())
1939 return {};
1940 return value.substr(index_range.begin, index_range.size());
1941 }
1942 bool empty() const noexcept
1943 {
1944 return begin() == end();
1945 }
1946 basic_path lexically_normal() const
1947 {
1948 constexpr Char_type dot = '.';
1949 constexpr std::size_t dot_dot_size = 2;
1950 constexpr Char_type dot_dot_storage[dot_dot_size + 1] = {dot, dot};
1951 string_view_type dot_dot(dot_dot_storage, dot_dot_size);
1952 if(empty())
1953 return {};
1954 auto relative_path_index_range = get_relative_path_index_range(value);
1955 auto root_name_index_range = get_root_name_index_range(value);
1956 bool has_root_dir = has_root_directory();
1957 basic_path retval;
1958 retval.value.reserve(value.size());
1959 retval.value.assign(value.data() + relative_path_index_range.begin,
1960 relative_path_index_range.size());
1961 std::size_t new_size = 0;
1962 for(std::size_t i = 0; i < retval.value.size(); i++)
1963 {
1964 if(is_separator(retval.value[i]))
1965 {
1966 while(i + 1 < retval.value.size() && is_separator(retval.value[i + 1]))
1967 i++;
1968 retval.value[new_size++] = preferred_separator;
1969 }
1970 else
1971 {
1972 retval.value[new_size++] = retval.value[i];
1973 }
1974 }
1975 retval.value.resize(new_size);
1976 new_size = 0;
1977 bool last_was_separator = true;
1978 for(std::size_t i = 0; i < retval.value.size(); i++)
1979 {
1980 if(last_was_separator && retval.value[i] == dot)
1981 {
1982 if(i + 1 >= retval.value.size())
1983 break; // don't write the dot
1984 if(retval.value[i + 1] == preferred_separator)
1985 {
1986 i++;
1987 last_was_separator = true;
1988 continue; // skip the dot and separator
1989 }
1990 }
1991 if(retval.value[i] == preferred_separator)
1992 last_was_separator = true;
1993 else
1994 last_was_separator = false;
1995 retval.value[new_size++] = retval.value[i];
1996 }
1997 retval.value.resize(new_size);
1998 retval.parts.reserve(parts.size());
1999 new_size = 0;
2000 parse<true>(retval.value,
2001 [&](Path_index_range index_range, Path_part_kind part_kind) noexcept
2002 {
2003 if(part_kind == Path_part_kind::path_separator)
2004 return true;
2005 assert(part_kind == Path_part_kind::file_name);
2006 if(index_range.size() == 2 && retval.value[index_range.begin] == dot
2007 && retval.value[index_range.begin + 1] == dot)
2008 {
2009 if(new_size == 0 && has_root_dir)
2010 return true;
2011 if(new_size != 0)
2012 {
2013 new_size--;
2014 return true;
2015 }
2016 }
2017 if(new_size >= retval.parts.size())
2018 retval.parts.emplace_back();
2019 retval.parts[new_size].value.assign(retval.value.data() + index_range.begin,
2020 index_range.size());
2021 retval.parts[new_size].kind = Path_part_kind::file_name;
2022 new_size++;
2023 return true;
2024 });
2025 if(new_size >= 2 && retval.parts[new_size - 1].value.empty()
2026 && retval.parts[new_size - 2].value == dot_dot)
2027 new_size--;
2028 std::size_t needed_space = 0;
2029 if(!root_name_index_range.empty())
2030 needed_space++;
2031 if(has_root_dir)
2032 needed_space++;
2033 if(needed_space > 0)
2034 {
2035 while(retval.parts.size() < new_size + needed_space)
2036 retval.parts.emplace_back();
2037 for(std::size_t source = new_size - 1, target = new_size + needed_space - 1, i = 0;
2038 i < new_size;
2039 source--, target--, i++)
2040 retval.parts[target] = std::move(retval.parts[source]);
2041 std::size_t root_part_index = 0;
2042 if(!root_name_index_range.empty())
2043 {
2044 retval.parts[root_part_index].value.assign(
2045 value.data() + root_name_index_range.begin, root_name_index_range.size());
2046 change_separator(retval.parts[root_part_index].value, static_cast<Char_type>('/'));
2047 retval.parts[root_part_index].parts = Parts();
2048 retval.parts[root_part_index].kind = begin()->kind;
2049 root_part_index++;
2050 }
2051 if(has_root_dir)
2052 {
2053 retval.parts[root_part_index].value.assign(1, static_cast<Char_type>('/'));
2054 retval.parts[root_part_index].parts = Parts();
2055 retval.parts[root_part_index].kind = Path_part_kind::root_dir;
2056 }
2057 }
2058 if(new_size + needed_space == 0)
2059 {
2060 if(retval.parts.empty())
2061 retval.parts.emplace_back();
2062 retval.parts[new_size].value.assign(1, dot);
2063 retval.parts[new_size].parts = Parts();
2064 retval.parts[new_size].kind = Path_part_kind::file_name;
2065 new_size++;
2066 }
2067 while(retval.parts.size() > new_size + needed_space)
2068 retval.parts.pop_back();
2069 retval.value.clear();
2070 bool need_seperator = false;
2071 for(auto &part : retval.parts)
2072 {
2073 switch(part.kind)
2074 {
2075 case Path_part_kind::absolute_root_name:
2076 case Path_part_kind::relative_root_name:
2077 retval.value += part.value;
2078 change_separator(retval.value, preferred_separator);
2079 need_seperator = false;
2080 // absolute_root_name will be followed by root_dir if we need a seperator
2081 continue;
2082 case Path_part_kind::file_name:
2083 if(need_seperator)
2084 retval.value += preferred_separator;
2085 retval.value += part.value;
2086 need_seperator = true;
2087 continue;
2088 case Path_part_kind::root_dir:
2089 retval.value += preferred_separator;
2090 need_seperator = false;
2091 continue;
2092 case Path_part_kind::path_separator:
2093 case Path_part_kind::multiple_parts:
2094 break;
2095 }
2096 assert(false);
2097 }
2098 retval.parse();
2099 return retval;
2100 }
2101 basic_path lexically_relative(const basic_path &base) const
2102 {
2103 constexpr Char_type dot_char = '.';
2104 constexpr std::size_t dot_dot_size = 2;
2105 constexpr std::size_t dot_size = 1;
2106 constexpr Char_type dot_dot_storage[dot_dot_size + 1] = {dot_char, dot_char};
2107 constexpr Char_type dot_storage[dot_size + 1] = {dot_char};
2108 string_view_type dot_dot(dot_dot_storage, dot_dot_size);
2109 string_view_type dot(dot_storage, dot_size);
2110 if(root_name() != base.root_name())
2111 return {};
2112 if(is_absolute() != base.is_absolute())
2113 return {};
2114 if(!has_root_directory() && base.has_root_directory())
2115 return {};
2116 auto a = begin();
2117 auto b = base.begin();
2118 while(a != end() && b != base.end() && *a == *b)
2119 {
2120 ++a;
2121 ++b;
2122 }
2123 if(a == end() && b == base.end())
2124 return dot;
2125 std::ptrdiff_t n = 0;
2126 for(auto i = b; i != base.end(); ++i)
2127 {
2128 if(i->kind == Path_part_kind::file_name)
2129 {
2130 if(i->value == dot_dot)
2131 n--;
2132 else if(i->value != dot)
2133 n++;
2134 }
2135 }
2136 if(n < 0)
2137 return {};
2138 std::size_t retval_value_reserve_size = static_cast<std::size_t>(n) * (dot_dot.size() + 1);
2139 std::size_t retval_parts_reserve_size = n;
2140 for(auto i = a; i != end(); ++i)
2141 {
2142 retval_value_reserve_size += 1 + i->value.size();
2143 retval_parts_reserve_size++;
2144 }
2145 basic_path retval;
2146 retval.value.reserve(retval_value_reserve_size);
2147 retval.parts.reserve(retval_parts_reserve_size);
2148 for(std::size_t i = n; i > 0; i--)
2149 retval /= dot_dot;
2150 for(auto i = a; i != end(); ++i)
2151 retval /= *i;
2152 return retval;
2153 }
2154 basic_path lexically_proximate(const basic_path &base) const
2155 {
2156 auto retval = lexically_relative(base);
2157 if(retval.empty())
2158 return *this;
2159 return retval;
2160 }
2161 };
2162
2163 template <detail::Path_traits_kind Traits_kind,
2164 typename Char_type,
2165 Char_type Preferred_separator,
2166 bool Needs_root_name_to_be_absolute>
2167 void swap(
2168 basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute> &l,
2169 basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>
2170 &r) noexcept
2171 {
2172 l.swap(r);
2173 }
2174
2175 /** @note the filesystem specification specifies to have hash_value instead of a std::hash
2176 * specialization */
2177 template <detail::Path_traits_kind Traits_kind,
2178 typename Char_type,
2179 Char_type Preferred_separator,
2180 bool Needs_root_name_to_be_absolute>
2181 std::size_t hash_value(
2182 const basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>
2183 &v) noexcept
2184 {
2185 std::size_t retval = 0;
2186 for(auto &part : v.parts)
2187 {
2188 retval *= 849372545UL;
2189 retval ^= std::hash<std::basic_string<Char_type>>()(part.value);
2190 }
2191 return retval;
2192 }
2193
2194 template <detail::Path_traits_kind Traits_kind,
2195 typename Char_type,
2196 Char_type Preferred_separator,
2197 bool Needs_root_name_to_be_absolute>
2198 constexpr Char_type basic_path<Traits_kind,
2199 Char_type,
2200 Preferred_separator,
2201 Needs_root_name_to_be_absolute>::preferred_separator;
2202
2203 template <detail::Path_traits_kind Traits_kind,
2204 typename Char_type,
2205 Char_type Preferred_separator,
2206 bool Needs_root_name_to_be_absolute>
2207 basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>
2208 *basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>::
2209 Parts::allocate(std::size_t count)
2210 {
2211 if(count == 0)
2212 return nullptr;
2213 return std::allocator<basic_path>().allocate(count);
2214 }
2215
2216 template <detail::Path_traits_kind Traits_kind,
2217 typename Char_type,
2218 Char_type Preferred_separator,
2219 bool Needs_root_name_to_be_absolute>
2220 void basic_path<Traits_kind, Char_type, Preferred_separator, Needs_root_name_to_be_absolute>::
2221 Parts::deallocate(basic_path *values, std::size_t count) noexcept
2222 {
2223 if(count != 0)
2224 std::allocator<basic_path>().deallocate(values, count);
2225 }
2226
2227 typedef basic_path<> path;
2228
2229 template <typename Source>
2230 path u8path(const Source &source)
2231 {
2232 return path(source);
2233 }
2234
2235 template <typename Input_iterator>
2236 path u8path(Input_iterator first, Input_iterator last)
2237 {
2238 return path(first, last);
2239 }
2240
2241 enum class file_type
2242 {
2243 none,
2244 not_found,
2245 regular,
2246 directory,
2247 symlink,
2248 block,
2249 character,
2250 fifo,
2251 socket,
2252 unknown
2253 };
2254
2255 enum class perms : std::uint16_t
2256 {
2257 none = 0,
2258 owner_read = 0400,
2259 owner_write = 0200,
2260 owner_exec = 0100,
2261 owner_all = 0700,
2262 group_read = 040,
2263 group_write = 020,
2264 group_exec = 010,
2265 group_all = 070,
2266 others_read = 04,
2267 others_write = 02,
2268 others_exec = 01,
2269 others_all = 07,
2270 all = 0777,
2271 set_uid = 04000,
2272 set_gid = 02000,
2273 sticky_bit = 01000,
2274 mask = 07777,
2275 unknown = 0xFFFFU
2276 };
2277
2278 constexpr perms operator&(perms a, perms b) noexcept
2279 {
2280 return static_cast<perms>(static_cast<std::uint16_t>(a) & static_cast<std::uint16_t>(b));
2281 }
2282
2283 constexpr perms operator|(perms a, perms b) noexcept
2284 {
2285 return static_cast<perms>(static_cast<std::uint16_t>(a) | static_cast<std::uint16_t>(b));
2286 }
2287
2288 constexpr perms operator^(perms a, perms b) noexcept
2289 {
2290 return static_cast<perms>(static_cast<std::uint16_t>(a) ^ static_cast<std::uint16_t>(b));
2291 }
2292
2293 constexpr perms operator~(perms v) noexcept
2294 {
2295 return static_cast<perms>(~static_cast<std::uint16_t>(v));
2296 }
2297
2298 constexpr perms &operator&=(perms &a, perms b) noexcept
2299 {
2300 return a = a & b;
2301 }
2302
2303 constexpr perms &operator|=(perms &a, perms b) noexcept
2304 {
2305 return a = a | b;
2306 }
2307
2308 constexpr perms &operator^=(perms &a, perms b) noexcept
2309 {
2310 return a = a ^ b;
2311 }
2312
2313 enum class perm_options : std::uint8_t
2314 {
2315 replace = 0x0,
2316 add = 0x1,
2317 remove = 0x2,
2318
2319 nofollow = 0x4
2320 };
2321
2322 constexpr perm_options operator&(perm_options a, perm_options b) noexcept
2323 {
2324 return static_cast<perm_options>(static_cast<std::uint8_t>(a) & static_cast<std::uint8_t>(b));
2325 }
2326
2327 constexpr perm_options operator|(perm_options a, perm_options b) noexcept
2328 {
2329 return static_cast<perm_options>(static_cast<std::uint8_t>(a) | static_cast<std::uint8_t>(b));
2330 }
2331
2332 constexpr perm_options operator^(perm_options a, perm_options b) noexcept
2333 {
2334 return static_cast<perm_options>(static_cast<std::uint8_t>(a) ^ static_cast<std::uint8_t>(b));
2335 }
2336
2337 constexpr perm_options operator~(perm_options v) noexcept
2338 {
2339 return static_cast<perm_options>(~static_cast<std::uint8_t>(v));
2340 }
2341
2342 constexpr perm_options &operator&=(perm_options &a, perm_options b) noexcept
2343 {
2344 return a = a & b;
2345 }
2346
2347 constexpr perm_options &operator|=(perm_options &a, perm_options b) noexcept
2348 {
2349 return a = a | b;
2350 }
2351
2352 constexpr perm_options &operator^=(perm_options &a, perm_options b) noexcept
2353 {
2354 return a = a ^ b;
2355 }
2356
2357 enum class copy_options : std::uint8_t
2358 {
2359 none = 0x0,
2360 skip_existing = 0x1,
2361 overwrite_existing = 0x2,
2362 update_existing = 0x3,
2363
2364 // none = 0x0,
2365 recursive = 0x4,
2366
2367 // none = 0x0,
2368 copy_symlinks = 0x8,
2369 skip_symlinks = 0x10,
2370
2371 // none = 0x0,
2372 directories_only = 0x20,
2373 create_symlinks = 0x40,
2374 create_hard_links = 0x60
2375 };
2376
2377 constexpr copy_options operator&(copy_options a, copy_options b) noexcept
2378 {
2379 return static_cast<copy_options>(static_cast<std::uint8_t>(a) & static_cast<std::uint8_t>(b));
2380 }
2381
2382 constexpr copy_options operator|(copy_options a, copy_options b) noexcept
2383 {
2384 return static_cast<copy_options>(static_cast<std::uint8_t>(a) | static_cast<std::uint8_t>(b));
2385 }
2386
2387 constexpr copy_options operator^(copy_options a, copy_options b) noexcept
2388 {
2389 return static_cast<copy_options>(static_cast<std::uint8_t>(a) ^ static_cast<std::uint8_t>(b));
2390 }
2391
2392 constexpr copy_options operator~(copy_options v) noexcept
2393 {
2394 return static_cast<copy_options>(~static_cast<std::uint8_t>(v));
2395 }
2396
2397 constexpr copy_options &operator&=(copy_options &a, copy_options b) noexcept
2398 {
2399 return a = a & b;
2400 }
2401
2402 constexpr copy_options &operator|=(copy_options &a, copy_options b) noexcept
2403 {
2404 return a = a | b;
2405 }
2406
2407 constexpr copy_options &operator^=(copy_options &a, copy_options b) noexcept
2408 {
2409 return a = a ^ b;
2410 }
2411
2412 enum class directory_options : std::uint8_t
2413 {
2414 none = 0x0,
2415 follow_directory_symlink = 0x1,
2416 skip_permission_denied = 0x2
2417 };
2418
2419 constexpr directory_options operator&(directory_options a, directory_options b) noexcept
2420 {
2421 return static_cast<directory_options>(static_cast<std::uint8_t>(a)
2422 & static_cast<std::uint8_t>(b));
2423 }
2424
2425 constexpr directory_options operator|(directory_options a, directory_options b) noexcept
2426 {
2427 return static_cast<directory_options>(static_cast<std::uint8_t>(a)
2428 | static_cast<std::uint8_t>(b));
2429 }
2430
2431 constexpr directory_options operator^(directory_options a, directory_options b) noexcept
2432 {
2433 return static_cast<directory_options>(static_cast<std::uint8_t>(a)
2434 ^ static_cast<std::uint8_t>(b));
2435 }
2436
2437 constexpr directory_options operator~(directory_options v) noexcept
2438 {
2439 return static_cast<directory_options>(~static_cast<std::uint8_t>(v));
2440 }
2441
2442 constexpr directory_options &operator&=(directory_options &a, directory_options b) noexcept
2443 {
2444 return a = a & b;
2445 }
2446
2447 constexpr directory_options &operator|=(directory_options &a, directory_options b) noexcept
2448 {
2449 return a = a | b;
2450 }
2451
2452 constexpr directory_options &operator^=(directory_options &a, directory_options b) noexcept
2453 {
2454 return a = a ^ b;
2455 }
2456
2457 using file_time_type = std::chrono::time_point<detail::Filesystem_clock>;
2458
2459 class file_status
2460 {
2461 private:
2462 file_type type_value;
2463 perms permissions_value;
2464
2465 public:
2466 constexpr file_status() noexcept : file_status(file_type::none)
2467 {
2468 }
2469 constexpr explicit file_status(file_type type_value,
2470 perms permissions_value = perms::unknown) noexcept
2471 : type_value(type_value),
2472 permissions_value(permissions_value)
2473 {
2474 }
2475 constexpr file_type type() const noexcept
2476 {
2477 return type_value;
2478 }
2479 constexpr void type(file_type new_value) noexcept
2480 {
2481 type_value = new_value;
2482 }
2483 constexpr perms permissions() const noexcept
2484 {
2485 return permissions_value;
2486 }
2487 constexpr void permissions(perms new_value) noexcept
2488 {
2489 permissions_value = new_value;
2490 }
2491 };
2492
2493 constexpr bool status_known(file_status s) noexcept
2494 {
2495 return s.type() != file_type::none;
2496 }
2497
2498 constexpr bool exists(file_status s) noexcept
2499 {
2500 return status_known(s) && s.type() != file_type::not_found;
2501 }
2502
2503 constexpr bool is_block_file(file_status s) noexcept
2504 {
2505 return s.type() == file_type::block;
2506 }
2507
2508 constexpr bool is_character_file(file_status s) noexcept
2509 {
2510 return s.type() == file_type::character;
2511 }
2512
2513 constexpr bool is_directory(file_status s) noexcept
2514 {
2515 return s.type() == file_type::directory;
2516 }
2517
2518 constexpr bool is_fifo(file_status s) noexcept
2519 {
2520 return s.type() == file_type::fifo;
2521 }
2522
2523 constexpr bool is_regular_file(file_status s) noexcept
2524 {
2525 return s.type() == file_type::regular;
2526 }
2527
2528 constexpr bool is_socket(file_status s) noexcept
2529 {
2530 return s.type() == file_type::socket;
2531 }
2532
2533 constexpr bool is_symlink(file_status s) noexcept
2534 {
2535 return s.type() == file_type::symlink;
2536 }
2537
2538 constexpr bool is_other(file_status s) noexcept
2539 {
2540 return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);
2541 }
2542
2543 struct space_info
2544 {
2545 std::uintmax_t capacity;
2546 std::uintmax_t free;
2547 std::uintmax_t available;
2548 };
2549
2550 class filesystem_error : public std::system_error
2551 {
2552 private:
2553 path p1;
2554 path p2;
2555 std::string what_value;
2556
2557 private:
2558 std::string make_what()
2559 {
2560 std::string retval = "filesystem_error: ";
2561 retval += system_error::what();
2562 if(!p1.empty())
2563 retval = std::move(retval) + " \"" + p1.string() + "\"";
2564 if(!p2.empty())
2565 retval = std::move(retval) + " \"" + p2.string() + "\"";
2566 return retval;
2567 }
2568
2569 public:
2570 filesystem_error(const std::string &what_arg, std::error_code ec)
2571 : system_error(ec, what_arg), p1(), p2(), what_value(make_what())
2572 {
2573 }
2574 filesystem_error(const std::string &what_arg, const path &p1, std::error_code ec)
2575 : system_error(ec, what_arg), p1(p1), p2(), what_value(make_what())
2576 {
2577 }
2578 filesystem_error(const std::string &what_arg,
2579 const path &p1,
2580 const path &p2,
2581 std::error_code ec)
2582 : system_error(ec, what_arg), p1(p1), p2(p2), what_value(make_what())
2583 {
2584 }
2585 const path &path1() const noexcept
2586 {
2587 return p1;
2588 }
2589 const path &path2() const noexcept
2590 {
2591 return p2;
2592 }
2593 virtual const char *what() const noexcept override
2594 {
2595 return what_value.c_str();
2596 }
2597 };
2598
2599 namespace detail
2600 {
2601 inline void set_or_throw_error(std::error_code *ec,
2602 string_view error_message,
2603 std::error_code error)
2604 {
2605 if(ec)
2606 *ec = error;
2607 else
2608 throw filesystem_error(std::string(error_message), error);
2609 }
2610
2611 inline void set_or_throw_error(std::error_code *ec,
2612 string_view error_message,
2613 const path &p1,
2614 std::error_code error)
2615 {
2616 if(ec)
2617 *ec = error;
2618 else
2619 throw filesystem_error(std::string(error_message), p1, error);
2620 }
2621
2622 inline void set_or_throw_error(std::error_code *ec,
2623 string_view error_message,
2624 const path &p1,
2625 const path &p2,
2626 std::error_code error)
2627 {
2628 if(ec)
2629 *ec = error;
2630 else
2631 throw filesystem_error(std::string(error_message), p1, p2, error);
2632 }
2633
2634 struct Stat_results;
2635
2636 std::uintmax_t file_size(const path &p, std::error_code *ec);
2637 std::uintmax_t hard_link_count(const path &p, std::error_code *ec);
2638 file_time_type last_write_time(const path &p, std::error_code *ec);
2639 file_status status(const path &p, bool follow_symlink, std::error_code *ec);
2640 }
2641
2642 inline std::uintmax_t file_size(const path &p)
2643 {
2644 return detail::file_size(p, nullptr);
2645 }
2646
2647 inline std::uintmax_t file_size(const path &p, std::error_code &ec) noexcept
2648 {
2649 return detail::file_size(p, &ec);
2650 }
2651
2652 inline std::uintmax_t hard_link_count(const path &p)
2653 {
2654 return detail::hard_link_count(p, nullptr);
2655 }
2656
2657 inline std::uintmax_t hard_link_count(const path &p, std::error_code &ec) noexcept
2658 {
2659 return detail::hard_link_count(p, &ec);
2660 }
2661
2662 inline file_time_type last_write_time(const path &p)
2663 {
2664 return detail::last_write_time(p, nullptr);
2665 }
2666
2667 inline file_time_type last_write_time(const path &p, std::error_code &ec) noexcept
2668 {
2669 return detail::last_write_time(p, &ec);
2670 }
2671
2672 inline file_status status(const path &p)
2673 {
2674 return detail::status(p, true, nullptr);
2675 }
2676
2677 inline file_status status(const path &p, std::error_code &ec) noexcept
2678 {
2679 return detail::status(p, true, &ec);
2680 }
2681
2682 inline file_status symlink_status(const path &p)
2683 {
2684 return detail::status(p, false, nullptr);
2685 }
2686
2687 inline file_status symlink_status(const path &p, std::error_code &ec) noexcept
2688 {
2689 return detail::status(p, false, &ec);
2690 }
2691
2692 inline bool exists(const path &p)
2693 {
2694 return exists(status(p));
2695 }
2696
2697 inline bool exists(const path &p, std::error_code &ec) noexcept
2698 {
2699 return exists(status(p, ec));
2700 }
2701
2702 inline bool is_block_file(const path &p)
2703 {
2704 return is_block_file(status(p));
2705 }
2706
2707 inline bool is_block_file(const path &p, std::error_code &ec) noexcept
2708 {
2709 return is_block_file(status(p, ec));
2710 }
2711
2712 inline bool is_character_file(const path &p)
2713 {
2714 return is_character_file(status(p));
2715 }
2716
2717 inline bool is_character_file(const path &p, std::error_code &ec) noexcept
2718 {
2719 return is_character_file(status(p, ec));
2720 }
2721
2722 inline bool is_directory(const path &p)
2723 {
2724 return is_directory(status(p));
2725 }
2726
2727 inline bool is_directory(const path &p, std::error_code &ec) noexcept
2728 {
2729 return is_directory(status(p, ec));
2730 }
2731
2732 inline bool is_fifo(const path &p)
2733 {
2734 return is_fifo(status(p));
2735 }
2736
2737 inline bool is_fifo(const path &p, std::error_code &ec) noexcept
2738 {
2739 return is_fifo(status(p, ec));
2740 }
2741
2742 inline bool is_other(const path &p)
2743 {
2744 return is_other(status(p));
2745 }
2746
2747 inline bool is_other(const path &p, std::error_code &ec) noexcept
2748 {
2749 return is_other(status(p, ec));
2750 }
2751
2752 inline bool is_regular_file(const path &p)
2753 {
2754 return is_regular_file(status(p));
2755 }
2756
2757 inline bool is_regular_file(const path &p, std::error_code &ec) noexcept
2758 {
2759 return is_regular_file(status(p, ec));
2760 }
2761
2762 inline bool is_socket(const path &p)
2763 {
2764 return is_socket(status(p));
2765 }
2766
2767 inline bool is_socket(const path &p, std::error_code &ec) noexcept
2768 {
2769 return is_socket(status(p, ec));
2770 }
2771
2772 inline bool is_symlink(const path &p)
2773 {
2774 return is_symlink(status(p));
2775 }
2776
2777 inline bool is_symlink(const path &p, std::error_code &ec) noexcept
2778 {
2779 return is_symlink(status(p, ec));
2780 }
2781
2782 class directory_iterator;
2783
2784 class directory_entry
2785 {
2786 friend class directory_iterator;
2787
2788 private:
2789 filesystem::path path_value;
2790 file_status status_value{};
2791 file_status symlink_status_value{};
2792 std::uintmax_t file_size_value{};
2793 std::uintmax_t hard_link_count_value{};
2794 file_time_type::rep last_write_time_value{};
2795 struct Flags
2796 {
2797 bool has_status_type_value : 1;
2798 bool has_symlink_status_type_value : 1;
2799 bool has_status_full_value : 1;
2800 bool has_symlink_status_full_value : 1;
2801 bool has_file_size_value : 1;
2802 bool has_hard_link_count_value : 1;
2803 bool has_last_write_time_value : 1;
2804 char : 0;
2805 constexpr Flags() noexcept : has_status_type_value(false),
2806 has_symlink_status_type_value(false),
2807 has_status_full_value(false),
2808 has_symlink_status_full_value(false),
2809 has_file_size_value(false),
2810 has_hard_link_count_value(false),
2811 has_last_write_time_value(false)
2812 {
2813 }
2814 };
2815 Flags flags{};
2816
2817 private:
2818 void refresh(std::error_code *ec);
2819 file_status status(bool follow_symlink, bool only_need_type, std::error_code *ec) const
2820 {
2821 if(ec)
2822 ec->clear();
2823 bool has_symlink_status_value = (only_need_type && flags.has_symlink_status_type_value)
2824 || flags.has_symlink_status_full_value;
2825 bool has_status_value =
2826 (only_need_type && flags.has_status_type_value) || flags.has_status_full_value;
2827 if(has_symlink_status_value
2828 && (!follow_symlink || !filesystem::is_symlink(symlink_status_value)))
2829 return symlink_status_value;
2830 if(has_status_value && follow_symlink)
2831 return status_value;
2832 return detail::status(path_value, follow_symlink, ec);
2833 }
2834
2835 public:
2836 directory_entry() noexcept = default;
2837 explicit directory_entry(const filesystem::path &path_value) : path_value(path_value)
2838 {
2839 refresh();
2840 }
2841 directory_entry(const filesystem::path &path_value, std::error_code &ec)
2842 : path_value(path_value)
2843 {
2844 refresh(ec);
2845 }
2846 directory_entry(const directory_entry &) = default;
2847 directory_entry(directory_entry &&) noexcept = default;
2848 directory_entry &operator=(const directory_entry &) = default;
2849 directory_entry &operator=(directory_entry &&) noexcept = default;
2850 void assign(const filesystem::path &p)
2851 {
2852 path_value = p;
2853 refresh();
2854 }
2855 void assign(const filesystem::path &p, std::error_code &ec)
2856 {
2857 path_value = p;
2858 refresh(ec);
2859 }
2860 void replace_filename(const filesystem::path &p)
2861 {
2862 path_value.replace_filename(p);
2863 refresh();
2864 }
2865 void replace_filename(const filesystem::path &p, std::error_code &ec)
2866 {
2867 path_value.replace_filename(p);
2868 refresh(ec);
2869 }
2870 void refresh()
2871 {
2872 refresh(nullptr);
2873 }
2874 void refresh(std::error_code &ec) noexcept
2875 {
2876 return refresh(&ec);
2877 }
2878 const filesystem::path &path() const noexcept
2879 {
2880 return path_value;
2881 }
2882 operator const filesystem::path &() const noexcept
2883 {
2884 return path_value;
2885 }
2886 bool exists() const
2887 {
2888 return filesystem::exists(status(true, true, nullptr));
2889 }
2890 bool exists(std::error_code &ec) const noexcept
2891 {
2892 return filesystem::exists(status(true, true, &ec));
2893 }
2894 bool is_block_file() const
2895 {
2896 return filesystem::is_block_file(status(true, true, nullptr));
2897 }
2898 bool is_block_file(std::error_code &ec) const noexcept
2899 {
2900 return filesystem::is_block_file(status(true, true, &ec));
2901 }
2902 bool is_character_file() const
2903 {
2904 return filesystem::is_character_file(status(true, true, nullptr));
2905 }
2906 bool is_character_file(std::error_code &ec) const noexcept
2907 {
2908 return filesystem::is_character_file(status(true, true, &ec));
2909 }
2910 bool is_directory() const
2911 {
2912 return filesystem::is_directory(status(true, true, nullptr));
2913 }
2914 bool is_directory(std::error_code &ec) const noexcept
2915 {
2916 return filesystem::is_directory(status(true, true, &ec));
2917 }
2918 bool is_fifo() const
2919 {
2920 return filesystem::is_fifo(status(true, true, nullptr));
2921 }
2922 bool is_fifo(std::error_code &ec) const noexcept
2923 {
2924 return filesystem::is_fifo(status(true, true, &ec));
2925 }
2926 bool is_other() const
2927 {
2928 return filesystem::is_other(status(true, true, nullptr));
2929 }
2930 bool is_other(std::error_code &ec) const noexcept
2931 {
2932 return filesystem::is_other(status(true, true, &ec));
2933 }
2934 bool is_regular_file() const
2935 {
2936 return filesystem::is_regular_file(status(true, true, nullptr));
2937 }
2938 bool is_regular_file(std::error_code &ec) const noexcept
2939 {
2940 return filesystem::is_regular_file(status(true, true, &ec));
2941 }
2942 bool is_socket() const
2943 {
2944 return filesystem::is_socket(status(true, true, nullptr));
2945 }
2946 bool is_socket(std::error_code &ec) const noexcept
2947 {
2948 return filesystem::is_socket(status(true, true, &ec));
2949 }
2950 bool is_symlink() const
2951 {
2952 return filesystem::is_symlink(status(false, true, nullptr));
2953 }
2954 bool is_symlink(std::error_code &ec) const noexcept
2955 {
2956 return filesystem::is_symlink(status(false, true, &ec));
2957 }
2958 std::uintmax_t file_size() const
2959 {
2960 if(flags.has_file_size_value)
2961 return file_size_value;
2962 return filesystem::file_size(path_value);
2963 }
2964 std::uintmax_t file_size(std::error_code &ec) const noexcept
2965 {
2966 ec.clear();
2967 if(flags.has_file_size_value)
2968 return file_size_value;
2969 return filesystem::file_size(path_value, ec);
2970 }
2971 std::uintmax_t hard_link_count() const
2972 {
2973 if(flags.has_hard_link_count_value)
2974 return hard_link_count_value;
2975 return filesystem::hard_link_count(path_value);
2976 }
2977 std::uintmax_t hard_link_count(std::error_code &ec) const noexcept
2978 {
2979 ec.clear();
2980 if(flags.has_hard_link_count_value)
2981 return hard_link_count_value;
2982 return filesystem::hard_link_count(path_value, ec);
2983 }
2984 file_time_type last_write_time() const
2985 {
2986 if(flags.has_last_write_time_value)
2987 return file_time_type(file_time_type::duration(last_write_time_value));
2988 return filesystem::last_write_time(path_value);
2989 }
2990 file_time_type last_write_time(std::error_code &ec) const noexcept
2991 {
2992 ec.clear();
2993 if(flags.has_last_write_time_value)
2994 return file_time_type(file_time_type::duration(last_write_time_value));
2995 return filesystem::last_write_time(path_value, ec);
2996 }
2997 file_status status() const
2998 {
2999 return status(true, false, nullptr);
3000 }
3001 file_status status(std::error_code &ec) const noexcept
3002 {
3003 return status(true, false, &ec);
3004 }
3005 file_status symlink_status() const
3006 {
3007 return status(false, false, nullptr);
3008 }
3009 file_status symlink_status(std::error_code &ec) const noexcept
3010 {
3011 return status(false, false, &ec);
3012 }
3013 bool operator==(const directory_entry &rt) const noexcept
3014 {
3015 return path_value == rt.path_value;
3016 }
3017 bool operator!=(const directory_entry &rt) const noexcept
3018 {
3019 return path_value != rt.path_value;
3020 }
3021 bool operator>=(const directory_entry &rt) const noexcept
3022 {
3023 return path_value >= rt.path_value;
3024 }
3025 bool operator<=(const directory_entry &rt) const noexcept
3026 {
3027 return path_value <= rt.path_value;
3028 }
3029 bool operator>(const directory_entry &rt) const noexcept
3030 {
3031 return path_value > rt.path_value;
3032 }
3033 bool operator<(const directory_entry &rt) const noexcept
3034 {
3035 return path_value < rt.path_value;
3036 }
3037 };
3038
3039 class directory_iterator
3040 {
3041 public:
3042 typedef directory_entry value_type;
3043 typedef std::ptrdiff_t difference_type;
3044 typedef const directory_entry *pointer;
3045 typedef const directory_entry &reference;
3046 typedef std::input_iterator_tag iterator_category;
3047
3048 private:
3049 struct Implementation;
3050
3051 private:
3052 std::shared_ptr<Implementation> implementation;
3053 directory_entry current_entry;
3054
3055 private:
3056 static std::shared_ptr<Implementation> create(directory_entry &current_entry,
3057 const path &p,
3058 directory_options options,
3059 std::error_code *ec);
3060 static void increment(std::shared_ptr<Implementation> &implementation,
3061 directory_entry &current_entry,
3062 std::error_code *ec);
3063
3064 private:
3065 directory_iterator(const path &p, directory_options options, std::error_code *ec)
3066 : implementation(nullptr), current_entry()
3067 {
3068 implementation = create(current_entry, p, options, ec);
3069 }
3070
3071 public:
3072 directory_iterator() noexcept : implementation(nullptr), current_entry()
3073 {
3074 }
3075 directory_iterator(const directory_iterator &rt) = default;
3076 directory_iterator(directory_iterator &&rt) noexcept = default;
3077 explicit directory_iterator(const path &p)
3078 : directory_iterator(p, directory_options::none, nullptr)
3079 {
3080 }
3081 directory_iterator(const path &p, directory_options options)
3082 : directory_iterator(p, options, nullptr)
3083 {
3084 }
3085 directory_iterator(const path &p, std::error_code &ec) noexcept
3086 : directory_iterator(p, directory_options::none, &ec)
3087 {
3088 }
3089 directory_iterator(const path &p, directory_options options, std::error_code &ec) noexcept
3090 : directory_iterator(p, options, &ec)
3091 {
3092 }
3093 directory_iterator &operator=(const directory_iterator &rt)
3094 {
3095 return operator=(directory_iterator(rt));
3096 }
3097 directory_iterator &operator=(directory_iterator &&rt) noexcept
3098 {
3099 directory_iterator temp(std::move(rt));
3100 using std::swap;
3101 swap(temp.implementation, implementation);
3102 swap(temp.current_entry, current_entry);
3103 return *this;
3104 }
3105 directory_iterator &operator++()
3106 {
3107 increment(implementation, current_entry, nullptr);
3108 return *this;
3109 }
3110 directory_iterator &increment(std::error_code &ec) noexcept
3111 {
3112 increment(implementation, current_entry, &ec);
3113 return *this;
3114 }
3115 friend bool operator==(const directory_iterator &a, const directory_iterator &b) noexcept
3116 {
3117 return a.implementation == b.implementation;
3118 }
3119 friend bool operator!=(const directory_iterator &a, const directory_iterator &b) noexcept
3120 {
3121 return a.implementation != b.implementation;
3122 }
3123 const directory_entry &operator*() const noexcept
3124 {
3125 return current_entry;
3126 }
3127 const directory_entry *operator->() const noexcept
3128 {
3129 return &current_entry;
3130 }
3131 };
3132
3133 inline directory_iterator begin(directory_iterator iter) noexcept
3134 {
3135 return iter;
3136 }
3137
3138 inline directory_iterator end(const directory_iterator &) noexcept
3139 {
3140 return directory_iterator();
3141 }
3142
3143 #warning finish implementing util::filesystem
3144
3145 // TODO: implement recursive_directory_iterator
3146 class[[deprecated(
3147 "recursive_directory_iterator is not implemented yet")]] recursive_directory_iterator;
3148
3149 // TODO: implement absolute
3150 [[deprecated("absolute is not implemented yet")]] path absolute(const path &p);
3151 [[deprecated("absolute is not implemented yet")]] path absolute(const path &p,
3152 std::error_code &ec) noexcept;
3153
3154 // TODO: implement canonical
3155 [[deprecated("canonical is not implemented yet")]] path canonical(const path &p);
3156 [[deprecated("canonical is not implemented yet")]] path canonical(const path &p, const path &base);
3157 [[deprecated("canonical is not implemented yet")]] path canonical(const path &p,
3158 std::error_code &ec) noexcept;
3159 [[deprecated("canonical is not implemented yet")]] path canonical(const path &p,
3160 const path &base,
3161 std::error_code &ec) noexcept;
3162
3163 // TODO: implement weakly_canonical
3164 [[deprecated("weakly_canonical is not implemented yet")]] path weakly_canonical(const path &p);
3165 [[deprecated("weakly_canonical is not implemented yet")]] path weakly_canonical(
3166 const path &p, std::error_code &ec) noexcept;
3167
3168 // TODO: implement relative
3169 [[deprecated("relative is not implemented yet")]] path relative(const path &p);
3170 [[deprecated("relative is not implemented yet")]] path relative(const path &p, const path &base);
3171 [[deprecated("relative is not implemented yet")]] path relative(const path &p,
3172 std::error_code &ec) noexcept;
3173 [[deprecated("relative is not implemented yet")]] path relative(const path &p,
3174 const path &base,
3175 std::error_code &ec) noexcept;
3176
3177 // TODO: implement proximate
3178 [[deprecated("proximate is not implemented yet")]] path proximate(const path &p);
3179 [[deprecated("proximate is not implemented yet")]] path proximate(const path &p, const path &base);
3180 [[deprecated("proximate is not implemented yet")]] path proximate(const path &p,
3181 std::error_code &ec) noexcept;
3182 [[deprecated("proximate is not implemented yet")]] path proximate(const path &p,
3183 const path &base,
3184 std::error_code &ec) noexcept;
3185
3186 // TODO: implement copy
3187 [[deprecated("copy is not implemented yet")]] void copy(const path &from, const path &to);
3188 [[deprecated("copy is not implemented yet")]] void copy(const path &from,
3189 const path &to,
3190 std::error_code &ec) noexcept;
3191 [[deprecated("copy is not implemented yet")]] void copy(const path &from,
3192 const path &to,
3193 copy_options options);
3194 [[deprecated("copy is not implemented yet")]] void copy(const path &from,
3195 const path &to,
3196 copy_options options,
3197 std::error_code &ec) noexcept;
3198
3199 // TODO: implement copy_file
3200 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path &from, const path &to);
3201 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path &from,
3202 const path &to,
3203 std::error_code &ec) noexcept;
3204 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path &from,
3205 const path &to,
3206 copy_options options);
3207 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path &from,
3208 const path &to,
3209 copy_options options,
3210 std::error_code &ec) noexcept;
3211
3212 // TODO: implement copy_symlink
3213 [[deprecated("copy_symlink is not implemented yet")]] void copy_symlink(const path &from,
3214 const path &to);
3215 [[deprecated("copy_symlink is not implemented yet")]] void copy_symlink(
3216 const path &from, const path &to, std::error_code &ec) noexcept;
3217
3218 // TODO: implement create_directory
3219 [[deprecated("create_directory is not implemented yet")]] void create_directory(const path &p);
3220 [[deprecated("create_directory is not implemented yet")]] void create_directory(
3221 const path &p, std::error_code &ec) noexcept;
3222 [[deprecated("create_directory is not implemented yet")]] void create_directory(
3223 const path &p, const path &existing_p);
3224 [[deprecated("create_directory is not implemented yet")]] void create_directory(
3225 const path &p, const path &existing_p, std::error_code &ec) noexcept;
3226
3227 // TODO: implement create_directories
3228 [[deprecated("create_directories is not implemented yet")]] void create_directories(const path &p);
3229 [[deprecated("create_directories is not implemented yet")]] void create_directories(
3230 const path &p, std::error_code &ec) noexcept;
3231
3232 // TODO: implement create_hard_link
3233 [[deprecated("create_hard_link is not implemented yet")]] void create_hard_link(const path &target,
3234 const path &link);
3235 [[deprecated("create_hard_link is not implemented yet")]] void create_hard_link(
3236 const path &target, const path &link, std::error_code &ec) noexcept;
3237
3238 // TODO: implement create_symlink
3239 [[deprecated("create_symlink is not implemented yet")]] void create_symlink(const path &target,
3240 const path &link);
3241 [[deprecated("create_symlink is not implemented yet")]] void create_symlink(
3242 const path &target, const path &link, std::error_code &ec) noexcept;
3243
3244 // TODO: implement create_directory_symlink
3245 [[deprecated("create_directory_symlink is not implemented yet")]] void create_directory_symlink(
3246 const path &target, const path &link);
3247 [[deprecated("create_directory_symlink is not implemented yet")]] void create_directory_symlink(
3248 const path &target, const path &link, std::error_code &ec) noexcept;
3249
3250 // TODO: implement current_path
3251 [[deprecated("current_path is not implemented yet")]] path current_path();
3252 [[deprecated("current_path is not implemented yet")]] path current_path(
3253 std::error_code &ec) noexcept;
3254 [[deprecated("current_path is not implemented yet")]] void current_path(const path &p);
3255 [[deprecated("current_path is not implemented yet")]] void current_path(
3256 const path &p, std::error_code &ec) noexcept;
3257
3258 // TODO: implement equivalent
3259 [[deprecated("equivalent is not implemented yet")]] bool equivalent(const path &p1, const path &p2);
3260 [[deprecated("equivalent is not implemented yet")]] bool equivalent(const path &p1,
3261 const path &p2,
3262 std::error_code &ec) noexcept;
3263
3264 // TODO: implement permissions
3265 [[deprecated("permissions is not implemented yet")]] void permissions(const path &p, perms prms);
3266 [[deprecated("permissions is not implemented yet")]] void permissions(const path &p,
3267 perms prms,
3268 perm_options options);
3269 [[deprecated("permissions is not implemented yet")]] void permissions(const path &p,
3270 perms prms,
3271 std::error_code &ec) noexcept;
3272 [[deprecated("permissions is not implemented yet")]] void permissions(const path &p,
3273 perms prms,
3274 perm_options options,
3275 std::error_code &ec) noexcept;
3276
3277 // TODO: implement read_symlink
3278 [[deprecated("read_symlink is not implemented yet")]] path read_symlink(const path &p);
3279 [[deprecated("read_symlink is not implemented yet")]] path read_symlink(
3280 const path &p, std::error_code &ec) noexcept;
3281
3282 // TODO: implement remove
3283 [[deprecated("remove is not implemented yet")]] bool remove(const path &p);
3284 [[deprecated("remove is not implemented yet")]] bool remove(const path &p,
3285 std::error_code &ec) noexcept;
3286
3287 // TODO: implement remove_all
3288 [[deprecated("remove_all is not implemented yet")]] std::uintmax_t remove_all(const path &p);
3289 [[deprecated("remove_all is not implemented yet")]] std::uintmax_t remove_all(
3290 const path &p, std::error_code &ec) noexcept;
3291
3292 // TODO: implement rename
3293 [[deprecated("rename is not implemented yet")]] void rename(const path &old_p, const path &new_p);
3294 [[deprecated("rename is not implemented yet")]] void rename(const path &old_p,
3295 const path &new_p,
3296 std::error_code &ec) noexcept;
3297
3298 // TODO: implement resize_file
3299 [[deprecated("resize_file is not implemented yet")]] void resize_file(const path &p,
3300 std::uintmax_t new_size);
3301 [[deprecated("resize_file is not implemented yet")]] void resize_file(const path &p,
3302 std::uintmax_t new_size,
3303 std::error_code &ec) noexcept;
3304
3305 // TODO: implement space
3306 [[deprecated("space is not implemented yet")]] space_info space(const path &p);
3307 [[deprecated("space is not implemented yet")]] space_info space(const path &p,
3308 std::error_code &ec) noexcept;
3309
3310 // TODO: implement temp_directory_path
3311 [[deprecated("temp_directory_path is not implemented yet")]] path temp_directory_path();
3312 [[deprecated("temp_directory_path is not implemented yet")]] path temp_directory_path(
3313 std::error_code &ec) noexcept;
3314
3315 // TODO: implement is_empty
3316 [[deprecated("is_empty is not implemented yet")]] bool is_empty(const path &p);
3317 [[deprecated("is_empty is not implemented yet")]] bool is_empty(const path &p,
3318 std::error_code &ec) noexcept;
3319 }
3320 }
3321 }
3322
3323 #endif /* UTIL_FILESYSTEM_H_ */