2 * Copyright 2017 Jacob Lifshay
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:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
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
23 #ifndef UTIL_FILESYSTEM_H_
24 #define UTIL_FILESYSTEM_H_
32 #include "bit_intrinsics.h"
33 #include "string_view.h"
35 #include <type_traits>
43 #include <system_error>
56 enum class Path_traits_kind
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
;
69 #error filesystem is not implemented for your operating system
72 struct Filesystem_clock
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
;
82 template <Path_traits_kind Kind
>
85 typedef char value_type
;
86 static constexpr value_type preferred_separator
= '/';
87 static constexpr bool needs_root_name_to_be_absolute
= false;
91 struct Path_traits
<Path_traits_kind::windows
>
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;
98 enum class Path_part_kind
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
108 template <typename T
>
109 struct Path_is_convertable_char_type
111 static constexpr bool value
= false;
114 template <typename T
>
115 struct Path_is_convertable_char_type
<const T
> : public Path_is_convertable_char_type
<T
>
120 struct Path_is_convertable_char_type
<char>
122 static constexpr bool value
= true;
123 typedef char Char_type
;
127 struct Path_is_convertable_char_type
<wchar_t>
129 static constexpr bool value
= true;
130 typedef wchar_t Char_type
;
134 struct Path_is_convertable_char_type
<char16_t
>
136 static constexpr bool value
= true;
137 typedef char16_t Char_type
;
141 struct Path_is_convertable_char_type
<char32_t
>
143 static constexpr bool value
= true;
144 typedef char32_t Char_type
;
147 template <typename T
, typename
= void>
148 struct Path_is_convertable_iterator_type
150 static constexpr bool value
= false;
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
>::
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
;
164 struct Path_iterator_sentinel
168 template <typename Iterator
>
169 class Path_convert_single_iterator_adaptor
172 typedef std::iterator_traits
<Iterator
> Traits
;
173 optional
<Iterator
> base_iterator
;
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()
184 constexpr explicit Path_convert_single_iterator_adaptor(Iterator iterator
)
185 : base_iterator(std::move(iterator
))
188 bool operator==(const Path_convert_single_iterator_adaptor
&rt
) const
192 assert(!rt
.base_iterator
);
193 return **base_iterator
== value_type();
196 return **rt
.base_iterator
== value_type();
199 bool operator!=(const Path_convert_single_iterator_adaptor
&rt
) const
201 return !operator==(rt
);
203 bool operator==(Path_iterator_sentinel
) const
206 return **base_iterator
== value_type();
209 bool operator!=(Path_iterator_sentinel
) const
211 return !operator==(Path_iterator_sentinel());
213 Path_convert_single_iterator_adaptor
&operator++()
219 Path_convert_single_iterator_adaptor
operator++(int)
222 return Path_convert_single_iterator_adaptor((*base_iterator
)++);
225 reference
operator*() const
227 return **base_iterator
;
229 pointer
operator->() const
231 return std::addressof(operator*());
235 template <typename Iterator
, typename Sentinel
>
236 struct Iterator_and_sentinel
240 Iterator_and_sentinel(Iterator iterator
, Sentinel sentinel
)
241 : iterator(std::move(iterator
)), sentinel(std::move(sentinel
))
246 template <typename Dest_char_type
,
248 typename Sentinel
= Iterator
,
249 typename Source_char_type
=
250 typename Path_is_convertable_iterator_type
<Iterator
>::Char_type
>
251 class Path_convert_iterator
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
, "");
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
;
266 Encode_result encode_result
;
267 std::size_t encode_result_index
;
268 util::optional
<Iterator_and_sentinel
<Iterator
, Sentinel
>> iterator_and_sentinel
;
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();
280 text::Decode_encode_functions
<Dest_char_type
>::encode(ch
, text::Convert_options());
281 encode_result_index
= 0;
286 constexpr Path_convert_iterator() noexcept
: encode_result(),
287 encode_result_index(),
288 iterator_and_sentinel()
291 Path_convert_iterator(Iterator iterator
, Sentinel sentinel
)
293 encode_result_index(),
294 iterator_and_sentinel(in_place
, std::move(iterator
), std::move(sentinel
))
298 Path_convert_iterator
&operator++()
300 if(++encode_result_index
>= encode_result
.size())
304 Path_convert_iterator
operator++(int)
310 const Dest_char_type
&operator*() const noexcept
312 return encode_result
[encode_result_index
];
314 const Dest_char_type
*operator->() const noexcept
316 return &encode_result
[encode_result_index
];
318 bool operator==(const Path_convert_iterator
&rt
) const noexcept
320 return iterator_and_sentinel
.has_value() == rt
.iterator_and_sentinel
.has_value();
322 bool operator!=(const Path_convert_iterator
&rt
) const noexcept
324 return !operator==(rt
);
326 bool operator==(Path_iterator_sentinel
) const noexcept
328 return !iterator_and_sentinel
;
330 bool operator!=(Path_iterator_sentinel
) const noexcept
332 return !operator==(Path_iterator_sentinel());
336 template <typename Path_char_type
, typename Iterator
, typename
= void>
337 struct Path_convert_range
339 static constexpr bool is_convertible
= false;
342 template <typename Path_char_type
, typename Iterator
>
344 Path_convert_range
<Path_char_type
,
348 is_same
<Path_char_type
,
349 typename Path_is_convertable_iterator_type
<Iterator
>::
351 && Path_is_convertable_iterator_type
<Iterator
>::value
>::type
>
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
>,
357 static std::basic_string
<Path_char_type
, Traits
, Allocator
> to_string(
358 Iterator iterator
, Sentinel sentinel
, const Allocator
&a
= Allocator())
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
);
366 template <typename Iterator
>
367 struct Path_convert_range
<typename Path_is_convertable_iterator_type
<Iterator
>::Char_type
,
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(
376 const std::allocator
<Char_type
> &a
= std::allocator
<Char_type
>())
378 return std::basic_string
<Char_type
>(iterator
, sentinel
, a
);
380 template <typename Traits
= std::char_traits
<Char_type
>,
381 typename Allocator
= std::allocator
<Char_type
>,
383 static std::basic_string
<Char_type
, Traits
, Allocator
> to_string(
384 Iterator iterator
, Sentinel sentinel
, const Allocator
&a
= Allocator())
386 std::basic_string
<Char_type
, Traits
, Allocator
> retval(a
);
387 while(iterator
!= sentinel
)
388 retval
+= *iterator
++;
393 template <typename Path_char_type
, typename Source
, typename
= void>
394 struct Path_convert_source
396 static constexpr bool is_convertible
= false;
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
>,
403 enable_if
<!std::is_same
<Path_char_type
, Source_char_type
>::value
404 && Path_convert_range
<Path_char_type
,
406 basic_string
<Source_char_type
,
410 is_convertible
>::type
>
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())
422 return Convert_range::template to_string
<Dest_traits
, Dest_allocator
>(
423 source
.begin(), source
.end(), a
);
427 template <typename Path_char_type
, typename Source_char_type
, typename Traits
>
429 Path_convert_source
<Path_char_type
,
430 basic_string_view
<Source_char_type
, Traits
>,
432 enable_if
<Path_convert_range
<Path_char_type
,
433 typename basic_string_view
<Source_char_type
,
435 const_iterator
>::is_convertible
>::type
>
437 typedef Path_convert_range
<Path_char_type
,
438 typename basic_string_view
<Source_char_type
, Traits
>::const_iterator
>
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())
446 return Convert_range::template to_string
<Dest_traits
, Allocator
>(
447 source
.begin(), source
.end(), a
);
451 template <typename Char_type
>
452 struct Path_convert_source
<Char_type
, std::basic_string
<Char_type
>, void>
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())
460 return std::basic_string
<Char_type
, Traits
, Allocator
>(source
.begin(), source
.end(), a
);
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
>())
470 template <typename Char_type
, typename Iterator
>
471 struct Path_convert_source
<Char_type
,
473 typename
std::enable_if
<!std::is_same
<
474 typename Path_is_convertable_iterator_type
<Iterator
>::Char_type
,
475 Char_type
>::value
>::type
>
477 static constexpr bool is_convertible
= true;
478 typedef Path_convert_range
<Char_type
, Path_convert_single_iterator_adaptor
<Iterator
>>
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())
485 return Convert_range::template to_string
<Traits
, Allocator
>(
486 Path_convert_single_iterator_adaptor
<Iterator
>(iterator
), Path_iterator_sentinel(), a
);
490 template <typename Char_type
>
491 struct Path_convert_source
<Char_type
, const Char_type
*, void>
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())
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>
509 struct Path_index_range
513 constexpr Path_index_range() noexcept
: begin(0), end(0)
516 constexpr Path_index_range(std::size_t begin
, std::size_t end
) noexcept
: begin(begin
), end(end
)
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())
527 constexpr bool empty() const noexcept
531 constexpr std::size_t size() const noexcept
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
>
547 template <detail::Path_traits_kind Traits_kind
,
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
>
555 template <detail::Path_traits_kind Traits_kind
,
557 Char_type Preferred_separator
,
558 bool Needs_root_name_to_be_absolute
>
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
,
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
;
572 typedef Char_type value_type
;
573 typedef std::basic_string
<Char_type
> string_type
;
580 static constexpr Char_type preferred_separator
= Preferred_separator
;
583 typedef basic_string_view
<Char_type
> string_view_type
;
587 std::size_t allocated_count
;
588 std::size_t used_count
;
592 static basic_path
*allocate(std::size_t count
);
593 template <typename
... Args
>
594 static void construct(basic_path
&value
, Args
&&... args
)
596 ::new(static_cast<void *>(&value
)) basic_path(std::forward
<Args
>(args
)...);
598 static void destruct(basic_path
&value
) noexcept
602 static void deallocate(basic_path
*values
, std::size_t count
) noexcept
;
603 void reallocate(std::size_t new_allocated_count
)
605 assert(new_allocated_count
>= used_count
);
608 deallocate(values
, allocated_count
);
610 allocated_count
= 0; // set now in case allocate throws
611 values
= allocate(new_allocated_count
);
612 allocated_count
= new_allocated_count
;
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
]));
623 static constexpr std::uint64_t get_expanded_count_64(std::uint64_t count
) noexcept
625 constexpr std::uint64_t high_bit
= 1ULL << 63;
626 if(count
== 0 || count
>= high_bit
)
628 return 1ULL << (64 - clz64(count
- 1));
630 static constexpr std::uint32_t get_expanded_count_32(std::uint32_t count
) noexcept
632 constexpr std::uint32_t high_bit
= 1UL << 31;
633 if(count
== 0 || count
>= high_bit
)
635 return 1UL << (32 - clz32(count
- 1));
637 static constexpr std::size_t get_expanded_count(std::size_t count
) noexcept
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
));
648 constexpr Parts() noexcept
: allocated_count(0), used_count(0), values(nullptr)
651 Parts(const Parts
&rt
) : 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
]);
659 Parts(Parts
&&rt
) noexcept
: Parts()
663 Parts
&operator=(Parts
&&rt
) noexcept
665 Parts(std::move(rt
)).swap(*this);
668 Parts
&operator=(const Parts
&rt
)
672 if(allocated_count
< rt
.used_count
)
674 Parts(rt
).swap(*this);
677 while(used_count
> rt
.used_count
)
679 for(std::size_t i
= 0; i
< used_count
; i
++)
681 while(used_count
< rt
.used_count
)
682 push_back(rt
[used_count
]);
687 while(used_count
> 0)
688 destruct(values
[--used_count
]);
689 deallocate(values
, allocated_count
);
691 void swap(Parts
&rt
) noexcept
694 swap(allocated_count
, rt
.allocated_count
);
695 swap(used_count
, rt
.used_count
);
696 swap(values
, rt
.values
);
698 void reserve(std::size_t new_allocated_count
)
700 if(new_allocated_count
> allocated_count
)
701 reallocate(new_allocated_count
);
703 bool empty() const noexcept
705 return used_count
== 0;
707 std::size_t size() const noexcept
711 std::size_t capacity() const noexcept
713 return allocated_count
;
715 typedef basic_path
*iterator
;
716 typedef const basic_path
*const_iterator
;
717 iterator
begin() noexcept
721 iterator
end() noexcept
723 return values
+ used_count
;
725 const_iterator
begin() const noexcept
729 const_iterator
end() const noexcept
731 return values
+ used_count
;
733 const_iterator
cbegin() const noexcept
737 const_iterator
cend() const noexcept
739 return values
+ used_count
;
741 template <typename
... Args
>
742 void emplace_back(Args
&&... args
)
744 if(used_count
>= allocated_count
)
745 reallocate(get_expanded_count(used_count
+ 1));
746 construct(values
[used_count
], std::forward
<Args
>(args
)...);
749 void push_back(const basic_path
&v
)
753 void push_back(basic_path
&&v
)
757 void pop_back() noexcept
759 assert(used_count
> 0);
760 destruct(values
[--used_count
]);
762 void clear() noexcept
764 while(used_count
> 0)
767 basic_path
&operator[](std::size_t index
) noexcept
769 assert(index
< used_count
);
770 return values
[index
];
772 const basic_path
&operator[](std::size_t index
) const noexcept
774 assert(index
< used_count
);
775 return values
[index
];
782 detail::Path_part_kind kind
;
787 template <detail::Path_traits_kind
, typename Char_type2
, Char_type2
, bool>
788 friend class basic_path
;
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
;
798 const basic_path
*path
;
800 constexpr iterator(const basic_path
*path
, std::size_t index
) noexcept
: path(path
),
806 constexpr iterator() noexcept
: path(nullptr), index()
809 constexpr iterator
&operator++() noexcept
814 constexpr iterator
&operator--() noexcept
819 constexpr iterator
operator++(int) noexcept
821 return iterator(path
, index
++);
823 constexpr iterator
operator--(int) noexcept
825 return iterator(path
, index
--);
827 const basic_path
*operator->() const
830 if(path
->kind
== Path_part_kind::multiple_parts
)
831 return &path
->parts
[index
];
834 const basic_path
&operator*() const
836 return *operator->();
838 constexpr bool operator==(const iterator
&rt
) const noexcept
840 return index
== rt
.index
;
842 constexpr bool operator!=(const iterator
&rt
) const noexcept
844 return index
!= rt
.index
;
847 typedef iterator const_iterator
;
850 static constexpr bool is_ascii_letter(Char_type v
) noexcept
852 auto ch
= static_cast<unsigned char>(v
);
853 if(static_cast<Char_type
>(ch
) != v
)
855 if(ch
>= 'a' && ch
<= 'z')
857 if(ch
>= 'A' && ch
<= 'Z')
861 template <typename Char_type2
>
862 static constexpr bool is_separator(Char_type2 v
) noexcept
864 return v
== static_cast<Char_type2
>('/')
865 || v
== static_cast<Char_type2
>(preferred_separator
);
867 template <bool Ignore_root_parts
= false, typename Fn
>
869 string_view_type value
,
871 [[gnu::unused
]] format fmt
= auto_format
) noexcept(noexcept(callback(Path_index_range(),
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
880 if(char_iter
== value
.end())
882 return std::char_traits
<Char_type
>::to_int_type(*char_iter
);
884 auto get
= [&]() -> Int_type
886 if(char_iter
== value
.end())
888 return std::char_traits
<Char_type
>::to_int_type(*char_iter
++);
892 if(!Ignore_root_parts
&& Traits_kind
== Path_traits_kind::windows
&& value
.size() >= 2
893 && is_ascii_letter(value
[0])
894 && value
[1] == colon
)
897 if(!callback(Path_index_range(value
, value
.begin(), char_iter
),
898 Path_part_kind::relative_root_name
))
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]))
905 while(peek() != eof
&& is_separator(peek()))
907 while(peek() != eof
&& !is_separator(peek()))
909 if(!callback(Path_index_range(value
, value
.begin(), char_iter
),
910 Path_part_kind::absolute_root_name
))
913 if(!Ignore_root_parts
&& peek() != eof
&& is_separator(peek()))
915 auto start_iter
= char_iter
;
919 } while(peek() != eof
&& is_separator(peek()));
920 if(!callback(Path_index_range(value
, start_iter
, char_iter
), Path_part_kind::root_dir
))
923 if(Ignore_root_parts
&& peek() != eof
&& is_separator(peek()))
925 if(!callback(Path_index_range(value
, char_iter
, char_iter
), Path_part_kind::file_name
))
928 if(peek() != eof
&& !is_separator(peek()))
930 auto start_iter
= char_iter
;
934 } while(peek() != eof
&& !is_separator(peek()));
935 if(!callback(Path_index_range(value
, start_iter
, char_iter
), Path_part_kind::file_name
))
940 auto start_iter
= char_iter
;
944 } while(peek() != eof
&& is_separator(peek()));
945 if(!callback(Path_index_range(value
, start_iter
, char_iter
),
946 Path_part_kind::path_separator
))
948 start_iter
= char_iter
;
949 while(peek() != eof
&& !is_separator(peek()))
951 if(!callback(Path_index_range(value
, start_iter
, char_iter
), Path_part_kind::file_name
))
956 void parse(format fmt
= auto_format
)
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;
963 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
965 if(part_kind
== Path_part_kind::path_separator
)
967 if(generic_separator
!= preferred_separator
&& !need_generic_conversion
)
969 for(std::size_t i
= index_range
.begin
; i
< index_range
.end
; i
++)
971 if(is_separator(value
[i
]) && value
[i
] != generic_separator
)
973 need_generic_conversion
= true;
978 last_part_kind
= part_kind
;
983 if(part_count
== 1 && !need_generic_conversion
)
985 kind
= last_part_kind
;
991 kind
= Path_part_kind::multiple_parts
;
993 while(parts
.size() > part_count
)
995 parts
.reserve(part_count
);
996 std::size_t part_index
= 0;
998 [&](Path_index_range index_range
, Path_part_kind part_kind
)
1000 if(part_kind
== Path_part_kind::path_separator
)
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
);
1013 static Path_index_range
get_filename_index_range(string_view_type value
) noexcept
1015 Path_index_range
retval(value
.size(), value
.size());
1017 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1019 if(part_kind
== Path_part_kind::file_name
)
1020 retval
= index_range
;
1025 static Path_index_range
get_stem_index_range(string_view_type value
) noexcept
1027 return get_stem_index_range(value
, get_filename_index_range(value
));
1029 static Path_index_range
get_stem_index_range(string_view_type value
,
1030 Path_index_range filename_index_range
) noexcept
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
--)
1037 if(value
[i
- 1] == dot
)
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);
1046 return filename_index_range
;
1048 static Path_index_range
get_extension_index_range(string_view_type value
) noexcept
1050 return get_extension_index_range(value
, get_filename_index_range(value
));
1052 static Path_index_range
get_extension_index_range(
1053 string_view_type value
, Path_index_range filename_index_range
) noexcept
1055 return get_extension_index_range(
1056 value
, filename_index_range
, get_stem_index_range(value
, filename_index_range
));
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
1062 return Path_index_range(stem_index_range
.end
, filename_index_range
.end
);
1064 static Path_index_range
get_root_name_index_range(string_view_type value
) noexcept
1066 Path_index_range
retval(0, 0);
1068 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1070 if(part_kind
== Path_part_kind::absolute_root_name
1071 || part_kind
== Path_part_kind::relative_root_name
)
1072 retval
= index_range
;
1077 static Path_index_range
get_root_dir_index_range(string_view_type value
) noexcept
1079 Path_index_range
retval(0, 0);
1081 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1083 if(part_kind
== Path_part_kind::root_dir
)
1085 retval
= index_range
;
1087 else if(part_kind
== Path_part_kind::absolute_root_name
1088 || part_kind
== Path_part_kind::relative_root_name
)
1090 retval
= Path_index_range(index_range
.end
, index_range
.end
);
1097 static Path_index_range
get_root_path_index_range(string_view_type value
) noexcept
1099 Path_index_range
retval(0, 0);
1101 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1103 if(part_kind
== Path_part_kind::absolute_root_name
1104 || part_kind
== Path_part_kind::relative_root_name
)
1106 retval
= index_range
;
1109 else if(part_kind
== Path_part_kind::root_dir
)
1111 retval
.end
= index_range
.end
;
1118 static Path_index_range
get_relative_path_index_range(string_view_type value
) noexcept
1120 Path_index_range
retval(value
.size(), value
.size());
1122 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
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
)
1130 retval
.begin
= index_range
.begin
;
1135 static Path_index_range
get_parent_path_index_range(string_view_type value
) noexcept
1137 Path_index_range
retval(0, 0);
1138 std::size_t last_file_name_end_index
= 0;
1140 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1144 case Path_part_kind::path_separator
:
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
;
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
;
1156 case Path_part_kind::multiple_parts
:
1166 basic_path() noexcept
: parts(), value(), kind(Path_part_kind::multiple_parts
)
1169 basic_path(const basic_path
&) = default;
1170 basic_path(basic_path
&&rt
) noexcept
: parts(), value(), kind()
1174 basic_path(string_type
&&source
, format fmt
= auto_format
)
1175 : parts(), value(std::move(source
)), kind()
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
)
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
),
1190 basic_path
&operator=(const basic_path
&rt
) = default;
1191 basic_path
&operator=(basic_path
&&rt
) noexcept
1193 basic_path(std::move(rt
)).swap(*this);
1196 basic_path
&operator=(string_type
&&new_value
)
1198 value
= std::move(new_value
);
1202 template <typename Source
>
1203 basic_path
&operator=(const Source
&source
)
1208 basic_path
&assign(string_type
&&new_value
)
1210 return operator=(new_value
);
1212 basic_path
&assign(const string_type
&new_value
)
1218 basic_path
&assign(const string_view_type
&new_value
)
1220 // use assign to prevent allocating a temporary string_type
1221 value
.assign(new_value
.data(), new_value
.size());
1225 template <typename Source
>
1226 basic_path
&assign(const Source
&source
)
1228 assign(detail::Path_convert_source
<Char_type
, Source
>::to_string(source
));
1231 template <typename Input_iterator
>
1232 basic_path
&assign(Input_iterator first
, Input_iterator last
)
1234 assign(detail::Path_convert_range
<Char_type
, Input_iterator
>::to_string(first
, last
));
1239 template <bool Check_for_shared_memory
= true>
1240 void append_string(string_view_type str
)
1242 bool just_need_to_assign
= is_absolute(str
);
1243 if(!just_need_to_assign
&& !get_root_name_index_range(str
).empty())
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;
1254 if(just_need_to_assign
)
1259 static_assert(std::is_same
<typename
string_view_type::iterator
, const Char_type
*>::value
,
1261 if(Check_for_shared_memory
&& str
.begin() <= value
.data() + value
.size()
1262 && str
.end() >= value
.data())
1264 // value and str share memory, reallocate str
1265 append_string
<false>(static_cast<string_type
>(str
));
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())
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
);
1277 else if(!get_filename_index_range(value
).empty()
1278 || (get_root_dir_index_range(value
).empty() && is_absolute()))
1280 value
.reserve(value
.size() + 1 + str
.size());
1281 value
+= preferred_separator
;
1288 basic_path
&operator/=(const basic_path
&p
)
1290 append_string(p
.value
);
1293 basic_path
&operator/=(const string_type
&p
)
1298 basic_path
&operator/=(const string_view_type
&p
)
1303 template <typename Source
>
1304 basic_path
&operator/=(const Source
&source
)
1306 append_string(detail::Path_convert_source
<Char_type
, Source
>::to_string(source
));
1309 template <typename Source
>
1310 basic_path
&append(const Source
&source
)
1315 template <typename Input_iterator
>
1316 basic_path
&append(Input_iterator first
, Input_iterator last
)
1319 detail::Path_convert_range
<Char_type
, Input_iterator
>::to_string(first
, last
));
1322 friend basic_path
operator/(const basic_path
&l
, const basic_path
&r
)
1324 return basic_path(l
) /= r
;
1326 friend basic_path
operator/(basic_path
&&l
, const basic_path
&r
)
1330 basic_path
&operator+=(const basic_path
&p
)
1336 basic_path
&operator+=(const string_type
&p
)
1342 basic_path
&operator+=(const string_view_type
&p
)
1348 template <typename Source
>
1349 basic_path
&operator+=(const Source
&source
)
1351 value
+= detail::Path_convert_source
<Char_type
, Source
>::to_string(source
);
1355 template <typename Source
>
1356 basic_path
&concat(const Source
&source
)
1361 template <typename Input_iterator
>
1362 basic_path
&concat(Input_iterator first
, Input_iterator last
)
1364 value
+= detail::Path_convert_range
<Char_type
, Input_iterator
>::to_string(first
, last
);
1368 const Char_type
*c_str() const noexcept
1370 return value
.c_str();
1372 const string_type
&native() const noexcept
1376 operator string_type() const
1380 void clear() noexcept
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
1393 if(is_separator(ch
))
1397 basic_path
&change_separator(Char_type separator
) noexcept
1399 change_separator(value
, separator
);
1400 for(auto &part
: parts
)
1401 change_separator(part
.value
, separator
);
1406 basic_path
&make_preferred() noexcept
1408 change_separator(preferred_separator
);
1411 basic_path
&remove_filename()
1413 auto filename_index_range
= get_filename_index_range(value
);
1414 if(!filename_index_range
.empty())
1416 value
.erase(filename_index_range
.begin
, filename_index_range
.size());
1421 basic_path
&replace_filename(const basic_path
&replacement
)
1424 operator/=(replacement
);
1427 basic_path
&replace_extension(const basic_path
&replacement
= basic_path())
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())
1435 if(!replacement
.value
.empty() && replacement
.value
.front() != dot
)
1437 value
.reserve(value
.size() + 1 + replacement
.value
.size());
1439 value
+= replacement
.value
;
1443 value
+= replacement
.value
;
1448 void swap(basic_path
&other
) noexcept
1451 swap(value
, other
.value
);
1452 parts
.swap(other
.parts
);
1453 swap(kind
, other
.kind
);
1455 bool has_root_path() const noexcept
1457 return !get_root_path_index_range(value
).empty();
1459 bool has_root_name() const noexcept
1461 return !get_root_name_index_range(value
).empty();
1463 bool has_root_directory() const noexcept
1465 return !get_root_dir_index_range(value
).empty();
1467 bool has_relative_path() const noexcept
1469 return !get_relative_path_index_range(value
).empty();
1471 bool has_parent_path() const noexcept
1473 return !get_parent_path_index_range(value
).empty();
1475 bool has_filename() const noexcept
1477 return !get_filename_index_range(value
).empty();
1479 bool has_stem() const noexcept
1481 return !get_stem_index_range(value
).empty();
1483 bool has_extension() const noexcept
1485 return !get_extension_index_range(value
).empty();
1489 static bool is_absolute(string_view_type value
) noexcept
1491 bool has_root_dir
= false;
1492 bool has_relative_root_name
= false;
1493 bool has_absolute_root_name
= false;
1495 [&]([[gnu::unused
]] Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1497 if(part_kind
== Path_part_kind::relative_root_name
)
1499 has_relative_root_name
= true;
1502 else if(part_kind
== Path_part_kind::absolute_root_name
)
1504 has_absolute_root_name
= true;
1507 else if(part_kind
== Path_part_kind::root_dir
)
1509 has_root_dir
= true;
1513 if(has_absolute_root_name
)
1517 if(Needs_root_name_to_be_absolute
)
1518 return has_relative_root_name
;
1525 bool is_absolute() const noexcept
1527 return is_absolute(value
);
1529 bool is_relative() const noexcept
1531 return !is_absolute(value
);
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
1539 return detail::Path_convert_source
<String_char_type
,
1540 string_type
>::template to_string
<String_traits_type
,
1541 Allocator
>(value
, a
);
1543 std::string
string() const
1545 return string
<char>();
1547 std::wstring
wstring() const
1549 return string
<wchar_t>();
1551 std::string
u8string() const
1553 return string
<char>();
1555 std::u16string
u16string() const
1557 return string
<char16_t
>();
1559 std::u32string
u32string() const
1561 return string
<char32_t
>();
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
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
>('/'));
1576 std::string
generic_string() const
1578 return generic_string
<char>();
1580 std::wstring
generic_wstring() const
1582 return generic_string
<wchar_t>();
1584 std::string
generic_u8string() const
1586 return generic_string
<char>();
1588 std::u16string
generic_u16string() const
1590 return generic_string
<char16_t
>();
1592 std::u32string
generic_u32string() const
1594 return generic_string
<char32_t
>();
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
)
1600 os
<< std::quoted(p
.string
<Stream_char_type
, Stream_traits_type
>());
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
)
1607 std::basic_string
<Stream_char_type
, Stream_traits_type
> str
;
1608 is
>> std::quoted(str
);
1614 static int compare_part(string_view_type a
,
1615 Path_part_kind a_kind
,
1617 Path_part_kind b_kind
) noexcept
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
++)
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
;
1638 if(a
.size() < b
.size())
1640 if(a
.size() > b
.size())
1646 int compare(string_view_type str
) const noexcept
1649 if(kind
!= Path_part_kind::multiple_parts
)
1651 retval
= 1; // non-empty is more than empty
1653 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1655 if(part_kind
== Path_part_kind::path_separator
)
1657 if(retval
== 1) // initial value
1658 retval
= compare_part(value
,
1660 str
.substr(index_range
.begin
, index_range
.size()),
1663 retval
= -1; // one-element is less than two-elements
1670 auto part_iter
= parts
.begin();
1672 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
1674 if(part_kind
== Path_part_kind::path_separator
)
1676 if(part_iter
== parts
.end())
1678 retval
= -1; // empty is less than non-empty
1682 retval
= compare_part(part_iter
->value
,
1684 str
.substr(index_range
.begin
, index_range
.size()),
1690 if(retval
== 0 && part_iter
!= parts
.end())
1691 retval
= 1; // more-elements is more than fewer-elements
1695 int compare(const string_type
&str
) const noexcept
1697 return compare(string_view_type(str
));
1699 int compare(const Char_type
*str
) const
1701 return compare(string_view_type(str
));
1703 int compare(const basic_path
&rt
) const noexcept
1705 return compare(rt
.value
);
1707 friend bool operator==(const basic_path
&l
, const basic_path
&r
) noexcept
1709 return l
.compare(r
) == 0;
1711 friend bool operator!=(const basic_path
&l
, const basic_path
&r
) noexcept
1713 return l
.compare(r
) != 0;
1715 friend bool operator<=(const basic_path
&l
, const basic_path
&r
) noexcept
1717 return l
.compare(r
) <= 0;
1719 friend bool operator>=(const basic_path
&l
, const basic_path
&r
) noexcept
1721 return l
.compare(r
) >= 0;
1723 friend bool operator<(const basic_path
&l
, const basic_path
&r
) noexcept
1725 return l
.compare(r
) < 0;
1727 friend bool operator>(const basic_path
&l
, const basic_path
&r
) noexcept
1729 return l
.compare(r
) > 0;
1731 friend bool operator==(const basic_path
&l
, string_view_type r
) noexcept
1733 return l
.compare(r
) == 0;
1735 friend bool operator!=(const basic_path
&l
, string_view_type r
) noexcept
1737 return l
.compare(r
) != 0;
1739 friend bool operator<=(const basic_path
&l
, string_view_type r
) noexcept
1741 return l
.compare(r
) <= 0;
1743 friend bool operator>=(const basic_path
&l
, string_view_type r
) noexcept
1745 return l
.compare(r
) >= 0;
1747 friend bool operator<(const basic_path
&l
, string_view_type r
) noexcept
1749 return l
.compare(r
) < 0;
1751 friend bool operator>(const basic_path
&l
, string_view_type r
) noexcept
1753 return l
.compare(r
) > 0;
1755 friend bool operator==(string_view_type l
, const basic_path
&r
) noexcept
1757 return r
.compare(l
) == 0;
1759 friend bool operator!=(string_view_type l
, const basic_path
&r
) noexcept
1761 return r
.compare(l
) != 0;
1763 friend bool operator<=(string_view_type l
, const basic_path
&r
) noexcept
1765 return r
.compare(l
) >= 0;
1767 friend bool operator>=(string_view_type l
, const basic_path
&r
) noexcept
1769 return r
.compare(l
) <= 0;
1771 friend bool operator<(string_view_type l
, const basic_path
&r
) noexcept
1773 return r
.compare(l
) > 0;
1775 friend bool operator>(string_view_type l
, const basic_path
&r
) noexcept
1777 return r
.compare(l
) < 0;
1779 friend bool operator==(const basic_path
&l
, string_type r
) noexcept
1781 return l
.compare(r
) == 0;
1783 friend bool operator!=(const basic_path
&l
, string_type r
) noexcept
1785 return l
.compare(r
) != 0;
1787 friend bool operator<=(const basic_path
&l
, string_type r
) noexcept
1789 return l
.compare(r
) <= 0;
1791 friend bool operator>=(const basic_path
&l
, string_type r
) noexcept
1793 return l
.compare(r
) >= 0;
1795 friend bool operator<(const basic_path
&l
, string_type r
) noexcept
1797 return l
.compare(r
) < 0;
1799 friend bool operator>(const basic_path
&l
, string_type r
) noexcept
1801 return l
.compare(r
) > 0;
1803 friend bool operator==(string_type l
, const basic_path
&r
) noexcept
1805 return r
.compare(l
) == 0;
1807 friend bool operator!=(string_type l
, const basic_path
&r
) noexcept
1809 return r
.compare(l
) != 0;
1811 friend bool operator<=(string_type l
, const basic_path
&r
) noexcept
1813 return r
.compare(l
) >= 0;
1815 friend bool operator>=(string_type l
, const basic_path
&r
) noexcept
1817 return r
.compare(l
) <= 0;
1819 friend bool operator<(string_type l
, const basic_path
&r
) noexcept
1821 return r
.compare(l
) > 0;
1823 friend bool operator>(string_type l
, const basic_path
&r
) noexcept
1825 return r
.compare(l
) < 0;
1827 friend bool operator==(const basic_path
&l
, const Char_type
*r
) noexcept
1829 return l
.compare(r
) == 0;
1831 friend bool operator!=(const basic_path
&l
, const Char_type
*r
) noexcept
1833 return l
.compare(r
) != 0;
1835 friend bool operator<=(const basic_path
&l
, const Char_type
*r
) noexcept
1837 return l
.compare(r
) <= 0;
1839 friend bool operator>=(const basic_path
&l
, const Char_type
*r
) noexcept
1841 return l
.compare(r
) >= 0;
1843 friend bool operator<(const basic_path
&l
, const Char_type
*r
) noexcept
1845 return l
.compare(r
) < 0;
1847 friend bool operator>(const basic_path
&l
, const Char_type
*r
) noexcept
1849 return l
.compare(r
) > 0;
1851 friend bool operator==(const Char_type
*l
, const basic_path
&r
) noexcept
1853 return r
.compare(l
) == 0;
1855 friend bool operator!=(const Char_type
*l
, const basic_path
&r
) noexcept
1857 return r
.compare(l
) != 0;
1859 friend bool operator<=(const Char_type
*l
, const basic_path
&r
) noexcept
1861 return r
.compare(l
) >= 0;
1863 friend bool operator>=(const Char_type
*l
, const basic_path
&r
) noexcept
1865 return r
.compare(l
) <= 0;
1867 friend bool operator<(const Char_type
*l
, const basic_path
&r
) noexcept
1869 return r
.compare(l
) > 0;
1871 friend bool operator>(const Char_type
*l
, const basic_path
&r
) noexcept
1873 return r
.compare(l
) < 0;
1875 iterator
begin() const noexcept
1877 return iterator(this, 0);
1879 iterator
end() const noexcept
1881 return iterator(this, kind
== Path_part_kind::multiple_parts
? parts
.size() : 1);
1883 basic_path
root_name() const
1885 auto index_range
= get_root_name_index_range(value
);
1886 if(index_range
.empty())
1888 return value
.substr(index_range
.begin
, index_range
.size());
1890 basic_path
root_directory() const
1892 auto index_range
= get_root_dir_index_range(value
);
1893 if(index_range
.empty())
1895 return value
.substr(index_range
.begin
, index_range
.size());
1897 basic_path
root_path() const
1899 auto index_range
= get_root_path_index_range(value
);
1900 if(index_range
.empty())
1902 return value
.substr(index_range
.begin
, index_range
.size());
1904 basic_path
relative_path() const
1906 auto index_range
= get_relative_path_index_range(value
);
1907 if(index_range
.empty())
1909 return value
.substr(index_range
.begin
, index_range
.size());
1911 basic_path
parent_path() const
1913 auto index_range
= get_parent_path_index_range(value
);
1914 if(index_range
.empty())
1916 return value
.substr(index_range
.begin
, index_range
.size());
1918 basic_path
filename() const
1924 if(iter
->kind
== Path_part_kind::file_name
)
1928 basic_path
stem() const
1930 auto index_range
= get_stem_index_range(value
);
1931 if(index_range
.empty())
1933 return value
.substr(index_range
.begin
, index_range
.size());
1935 basic_path
extension() const
1937 auto index_range
= get_extension_index_range(value
);
1938 if(index_range
.empty())
1940 return value
.substr(index_range
.begin
, index_range
.size());
1942 bool empty() const noexcept
1944 return begin() == end();
1946 basic_path
lexically_normal() const
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
);
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();
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
++)
1964 if(is_separator(retval
.value
[i
]))
1966 while(i
+ 1 < retval
.value
.size() && is_separator(retval
.value
[i
+ 1]))
1968 retval
.value
[new_size
++] = preferred_separator
;
1972 retval
.value
[new_size
++] = retval
.value
[i
];
1975 retval
.value
.resize(new_size
);
1977 bool last_was_separator
= true;
1978 for(std::size_t i
= 0; i
< retval
.value
.size(); i
++)
1980 if(last_was_separator
&& retval
.value
[i
] == dot
)
1982 if(i
+ 1 >= retval
.value
.size())
1983 break; // don't write the dot
1984 if(retval
.value
[i
+ 1] == preferred_separator
)
1987 last_was_separator
= true;
1988 continue; // skip the dot and separator
1991 if(retval
.value
[i
] == preferred_separator
)
1992 last_was_separator
= true;
1994 last_was_separator
= false;
1995 retval
.value
[new_size
++] = retval
.value
[i
];
1997 retval
.value
.resize(new_size
);
1998 retval
.parts
.reserve(parts
.size());
2000 parse
<true>(retval
.value
,
2001 [&](Path_index_range index_range
, Path_part_kind part_kind
) noexcept
2003 if(part_kind
== Path_part_kind::path_separator
)
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
)
2009 if(new_size
== 0 && has_root_dir
)
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
;
2025 if(new_size
>= 2 && retval
.parts
[new_size
- 1].value
.empty()
2026 && retval
.parts
[new_size
- 2].value
== dot_dot
)
2028 std::size_t needed_space
= 0;
2029 if(!root_name_index_range
.empty())
2033 if(needed_space
> 0)
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;
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())
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
;
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
;
2058 if(new_size
+ needed_space
== 0)
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
;
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
)
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
2082 case Path_part_kind::file_name
:
2084 retval
.value
+= preferred_separator
;
2085 retval
.value
+= part
.value
;
2086 need_seperator
= true;
2088 case Path_part_kind::root_dir
:
2089 retval
.value
+= preferred_separator
;
2090 need_seperator
= false;
2092 case Path_part_kind::path_separator
:
2093 case Path_part_kind::multiple_parts
:
2101 basic_path
lexically_relative(const basic_path
&base
) const
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())
2112 if(is_absolute() != base
.is_absolute())
2114 if(!has_root_directory() && base
.has_root_directory())
2117 auto b
= base
.begin();
2118 while(a
!= end() && b
!= base
.end() && *a
== *b
)
2123 if(a
== end() && b
== base
.end())
2125 std::ptrdiff_t n
= 0;
2126 for(auto i
= b
; i
!= base
.end(); ++i
)
2128 if(i
->kind
== Path_part_kind::file_name
)
2130 if(i
->value
== dot_dot
)
2132 else if(i
->value
!= dot
)
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
)
2142 retval_value_reserve_size
+= 1 + i
->value
.size();
2143 retval_parts_reserve_size
++;
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
--)
2150 for(auto i
= a
; i
!= end(); ++i
)
2154 basic_path
lexically_proximate(const basic_path
&base
) const
2156 auto retval
= lexically_relative(base
);
2163 template <detail::Path_traits_kind Traits_kind
,
2165 Char_type Preferred_separator
,
2166 bool Needs_root_name_to_be_absolute
>
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
>
2175 /** @note the filesystem specification specifies to have hash_value instead of a std::hash
2177 template <detail::Path_traits_kind Traits_kind
,
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
>
2185 std::size_t retval
= 0;
2186 for(auto &part
: v
.parts
)
2188 retval
*= 849372545UL;
2189 retval
^= std::hash
<std::basic_string
<Char_type
>>()(part
.value
);
2194 template <detail::Path_traits_kind Traits_kind
,
2196 Char_type Preferred_separator
,
2197 bool Needs_root_name_to_be_absolute
>
2198 constexpr Char_type basic_path
<Traits_kind
,
2200 Preferred_separator
,
2201 Needs_root_name_to_be_absolute
>::preferred_separator
;
2203 template <detail::Path_traits_kind Traits_kind
,
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
)
2213 return std::allocator
<basic_path
>().allocate(count
);
2216 template <detail::Path_traits_kind Traits_kind
,
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
2224 std::allocator
<basic_path
>().deallocate(values
, count
);
2227 typedef basic_path
<> path
;
2229 template <typename Source
>
2230 path
u8path(const Source
&source
)
2232 return path(source
);
2235 template <typename Input_iterator
>
2236 path
u8path(Input_iterator first
, Input_iterator last
)
2238 return path(first
, last
);
2241 enum class file_type
2255 enum class perms
: std::uint16_t
2278 constexpr perms
operator&(perms a
, perms b
) noexcept
2280 return static_cast<perms
>(static_cast<std::uint16_t>(a
) & static_cast<std::uint16_t>(b
));
2283 constexpr perms
operator|(perms a
, perms b
) noexcept
2285 return static_cast<perms
>(static_cast<std::uint16_t>(a
) | static_cast<std::uint16_t>(b
));
2288 constexpr perms
operator^(perms a
, perms b
) noexcept
2290 return static_cast<perms
>(static_cast<std::uint16_t>(a
) ^ static_cast<std::uint16_t>(b
));
2293 constexpr perms
operator~(perms v
) noexcept
2295 return static_cast<perms
>(~static_cast<std::uint16_t>(v
));
2298 constexpr perms
&operator&=(perms
&a
, perms b
) noexcept
2303 constexpr perms
&operator|=(perms
&a
, perms b
) noexcept
2308 constexpr perms
&operator^=(perms
&a
, perms b
) noexcept
2313 enum class perm_options
: std::uint8_t
2322 constexpr perm_options
operator&(perm_options a
, perm_options b
) noexcept
2324 return static_cast<perm_options
>(static_cast<std::uint8_t>(a
) & static_cast<std::uint8_t>(b
));
2327 constexpr perm_options
operator|(perm_options a
, perm_options b
) noexcept
2329 return static_cast<perm_options
>(static_cast<std::uint8_t>(a
) | static_cast<std::uint8_t>(b
));
2332 constexpr perm_options
operator^(perm_options a
, perm_options b
) noexcept
2334 return static_cast<perm_options
>(static_cast<std::uint8_t>(a
) ^ static_cast<std::uint8_t>(b
));
2337 constexpr perm_options
operator~(perm_options v
) noexcept
2339 return static_cast<perm_options
>(~static_cast<std::uint8_t>(v
));
2342 constexpr perm_options
&operator&=(perm_options
&a
, perm_options b
) noexcept
2347 constexpr perm_options
&operator|=(perm_options
&a
, perm_options b
) noexcept
2352 constexpr perm_options
&operator^=(perm_options
&a
, perm_options b
) noexcept
2357 enum class copy_options
: std::uint8_t
2360 skip_existing
= 0x1,
2361 overwrite_existing
= 0x2,
2362 update_existing
= 0x3,
2368 copy_symlinks
= 0x8,
2369 skip_symlinks
= 0x10,
2372 directories_only
= 0x20,
2373 create_symlinks
= 0x40,
2374 create_hard_links
= 0x60
2377 constexpr copy_options
operator&(copy_options a
, copy_options b
) noexcept
2379 return static_cast<copy_options
>(static_cast<std::uint8_t>(a
) & static_cast<std::uint8_t>(b
));
2382 constexpr copy_options
operator|(copy_options a
, copy_options b
) noexcept
2384 return static_cast<copy_options
>(static_cast<std::uint8_t>(a
) | static_cast<std::uint8_t>(b
));
2387 constexpr copy_options
operator^(copy_options a
, copy_options b
) noexcept
2389 return static_cast<copy_options
>(static_cast<std::uint8_t>(a
) ^ static_cast<std::uint8_t>(b
));
2392 constexpr copy_options
operator~(copy_options v
) noexcept
2394 return static_cast<copy_options
>(~static_cast<std::uint8_t>(v
));
2397 constexpr copy_options
&operator&=(copy_options
&a
, copy_options b
) noexcept
2402 constexpr copy_options
&operator|=(copy_options
&a
, copy_options b
) noexcept
2407 constexpr copy_options
&operator^=(copy_options
&a
, copy_options b
) noexcept
2412 enum class directory_options
: std::uint8_t
2415 follow_directory_symlink
= 0x1,
2416 skip_permission_denied
= 0x2
2419 constexpr directory_options
operator&(directory_options a
, directory_options b
) noexcept
2421 return static_cast<directory_options
>(static_cast<std::uint8_t>(a
)
2422 & static_cast<std::uint8_t>(b
));
2425 constexpr directory_options
operator|(directory_options a
, directory_options b
) noexcept
2427 return static_cast<directory_options
>(static_cast<std::uint8_t>(a
)
2428 | static_cast<std::uint8_t>(b
));
2431 constexpr directory_options
operator^(directory_options a
, directory_options b
) noexcept
2433 return static_cast<directory_options
>(static_cast<std::uint8_t>(a
)
2434 ^ static_cast<std::uint8_t>(b
));
2437 constexpr directory_options
operator~(directory_options v
) noexcept
2439 return static_cast<directory_options
>(~static_cast<std::uint8_t>(v
));
2442 constexpr directory_options
&operator&=(directory_options
&a
, directory_options b
) noexcept
2447 constexpr directory_options
&operator|=(directory_options
&a
, directory_options b
) noexcept
2452 constexpr directory_options
&operator^=(directory_options
&a
, directory_options b
) noexcept
2457 using file_time_type
= std::chrono::time_point
<detail::Filesystem_clock
>;
2462 file_type type_value
;
2463 perms permissions_value
;
2466 constexpr file_status() noexcept
: file_status(file_type::none
)
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
)
2475 constexpr file_type
type() const noexcept
2479 constexpr void type(file_type new_value
) noexcept
2481 type_value
= new_value
;
2483 constexpr perms
permissions() const noexcept
2485 return permissions_value
;
2487 constexpr void permissions(perms new_value
) noexcept
2489 permissions_value
= new_value
;
2493 constexpr bool status_known(file_status s
) noexcept
2495 return s
.type() != file_type::none
;
2498 constexpr bool exists(file_status s
) noexcept
2500 return status_known(s
) && s
.type() != file_type::not_found
;
2503 constexpr bool is_block_file(file_status s
) noexcept
2505 return s
.type() == file_type::block
;
2508 constexpr bool is_character_file(file_status s
) noexcept
2510 return s
.type() == file_type::character
;
2513 constexpr bool is_directory(file_status s
) noexcept
2515 return s
.type() == file_type::directory
;
2518 constexpr bool is_fifo(file_status s
) noexcept
2520 return s
.type() == file_type::fifo
;
2523 constexpr bool is_regular_file(file_status s
) noexcept
2525 return s
.type() == file_type::regular
;
2528 constexpr bool is_socket(file_status s
) noexcept
2530 return s
.type() == file_type::socket
;
2533 constexpr bool is_symlink(file_status s
) noexcept
2535 return s
.type() == file_type::symlink
;
2538 constexpr bool is_other(file_status s
) noexcept
2540 return exists(s
) && !is_regular_file(s
) && !is_directory(s
) && !is_symlink(s
);
2545 std::uintmax_t capacity
;
2546 std::uintmax_t free
;
2547 std::uintmax_t available
;
2550 class filesystem_error
: public std::system_error
2555 std::string what_value
;
2558 std::string
make_what()
2560 std::string retval
= "filesystem_error: ";
2561 retval
+= system_error::what();
2563 retval
= std::move(retval
) + " \"" + p1
.string() + "\"";
2565 retval
= std::move(retval
) + " \"" + p2
.string() + "\"";
2570 filesystem_error(const std::string
&what_arg
, std::error_code ec
)
2571 : system_error(ec
, what_arg
), p1(), p2(), what_value(make_what())
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())
2578 filesystem_error(const std::string
&what_arg
,
2582 : system_error(ec
, what_arg
), p1(p1
), p2(p2
), what_value(make_what())
2585 const path
&path1() const noexcept
2589 const path
&path2() const noexcept
2593 virtual const char *what() const noexcept override
2595 return what_value
.c_str();
2601 inline void set_or_throw_error(std::error_code
*ec
,
2602 string_view error_message
,
2603 std::error_code error
)
2608 throw filesystem_error(std::string(error_message
), error
);
2611 inline void set_or_throw_error(std::error_code
*ec
,
2612 string_view error_message
,
2614 std::error_code error
)
2619 throw filesystem_error(std::string(error_message
), p1
, error
);
2622 inline void set_or_throw_error(std::error_code
*ec
,
2623 string_view error_message
,
2626 std::error_code error
)
2631 throw filesystem_error(std::string(error_message
), p1
, p2
, error
);
2634 struct Stat_results
;
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
);
2642 inline std::uintmax_t file_size(const path
&p
)
2644 return detail::file_size(p
, nullptr);
2647 inline std::uintmax_t file_size(const path
&p
, std::error_code
&ec
) noexcept
2649 return detail::file_size(p
, &ec
);
2652 inline std::uintmax_t hard_link_count(const path
&p
)
2654 return detail::hard_link_count(p
, nullptr);
2657 inline std::uintmax_t hard_link_count(const path
&p
, std::error_code
&ec
) noexcept
2659 return detail::hard_link_count(p
, &ec
);
2662 inline file_time_type
last_write_time(const path
&p
)
2664 return detail::last_write_time(p
, nullptr);
2667 inline file_time_type
last_write_time(const path
&p
, std::error_code
&ec
) noexcept
2669 return detail::last_write_time(p
, &ec
);
2672 inline file_status
status(const path
&p
)
2674 return detail::status(p
, true, nullptr);
2677 inline file_status
status(const path
&p
, std::error_code
&ec
) noexcept
2679 return detail::status(p
, true, &ec
);
2682 inline file_status
symlink_status(const path
&p
)
2684 return detail::status(p
, false, nullptr);
2687 inline file_status
symlink_status(const path
&p
, std::error_code
&ec
) noexcept
2689 return detail::status(p
, false, &ec
);
2692 inline bool exists(const path
&p
)
2694 return exists(status(p
));
2697 inline bool exists(const path
&p
, std::error_code
&ec
) noexcept
2699 return exists(status(p
, ec
));
2702 inline bool is_block_file(const path
&p
)
2704 return is_block_file(status(p
));
2707 inline bool is_block_file(const path
&p
, std::error_code
&ec
) noexcept
2709 return is_block_file(status(p
, ec
));
2712 inline bool is_character_file(const path
&p
)
2714 return is_character_file(status(p
));
2717 inline bool is_character_file(const path
&p
, std::error_code
&ec
) noexcept
2719 return is_character_file(status(p
, ec
));
2722 inline bool is_directory(const path
&p
)
2724 return is_directory(status(p
));
2727 inline bool is_directory(const path
&p
, std::error_code
&ec
) noexcept
2729 return is_directory(status(p
, ec
));
2732 inline bool is_fifo(const path
&p
)
2734 return is_fifo(status(p
));
2737 inline bool is_fifo(const path
&p
, std::error_code
&ec
) noexcept
2739 return is_fifo(status(p
, ec
));
2742 inline bool is_other(const path
&p
)
2744 return is_other(status(p
));
2747 inline bool is_other(const path
&p
, std::error_code
&ec
) noexcept
2749 return is_other(status(p
, ec
));
2752 inline bool is_regular_file(const path
&p
)
2754 return is_regular_file(status(p
));
2757 inline bool is_regular_file(const path
&p
, std::error_code
&ec
) noexcept
2759 return is_regular_file(status(p
, ec
));
2762 inline bool is_socket(const path
&p
)
2764 return is_socket(status(p
));
2767 inline bool is_socket(const path
&p
, std::error_code
&ec
) noexcept
2769 return is_socket(status(p
, ec
));
2772 inline bool is_symlink(const path
&p
)
2774 return is_symlink(status(p
));
2777 inline bool is_symlink(const path
&p
, std::error_code
&ec
) noexcept
2779 return is_symlink(status(p
, ec
));
2782 class directory_iterator
;
2784 class directory_entry
2786 friend class directory_iterator
;
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
{};
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;
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)
2818 void refresh(std::error_code
*ec
);
2819 file_status
status(bool follow_symlink
, bool only_need_type
, std::error_code
*ec
) const
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
);
2836 directory_entry() noexcept
= default;
2837 explicit directory_entry(const filesystem::path
&path_value
) : path_value(path_value
)
2841 directory_entry(const filesystem::path
&path_value
, std::error_code
&ec
)
2842 : path_value(path_value
)
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
)
2855 void assign(const filesystem::path
&p
, std::error_code
&ec
)
2860 void replace_filename(const filesystem::path
&p
)
2862 path_value
.replace_filename(p
);
2865 void replace_filename(const filesystem::path
&p
, std::error_code
&ec
)
2867 path_value
.replace_filename(p
);
2874 void refresh(std::error_code
&ec
) noexcept
2876 return refresh(&ec
);
2878 const filesystem::path
&path() const noexcept
2882 operator const filesystem::path
&() const noexcept
2888 return filesystem::exists(status(true, true, nullptr));
2890 bool exists(std::error_code
&ec
) const noexcept
2892 return filesystem::exists(status(true, true, &ec
));
2894 bool is_block_file() const
2896 return filesystem::is_block_file(status(true, true, nullptr));
2898 bool is_block_file(std::error_code
&ec
) const noexcept
2900 return filesystem::is_block_file(status(true, true, &ec
));
2902 bool is_character_file() const
2904 return filesystem::is_character_file(status(true, true, nullptr));
2906 bool is_character_file(std::error_code
&ec
) const noexcept
2908 return filesystem::is_character_file(status(true, true, &ec
));
2910 bool is_directory() const
2912 return filesystem::is_directory(status(true, true, nullptr));
2914 bool is_directory(std::error_code
&ec
) const noexcept
2916 return filesystem::is_directory(status(true, true, &ec
));
2918 bool is_fifo() const
2920 return filesystem::is_fifo(status(true, true, nullptr));
2922 bool is_fifo(std::error_code
&ec
) const noexcept
2924 return filesystem::is_fifo(status(true, true, &ec
));
2926 bool is_other() const
2928 return filesystem::is_other(status(true, true, nullptr));
2930 bool is_other(std::error_code
&ec
) const noexcept
2932 return filesystem::is_other(status(true, true, &ec
));
2934 bool is_regular_file() const
2936 return filesystem::is_regular_file(status(true, true, nullptr));
2938 bool is_regular_file(std::error_code
&ec
) const noexcept
2940 return filesystem::is_regular_file(status(true, true, &ec
));
2942 bool is_socket() const
2944 return filesystem::is_socket(status(true, true, nullptr));
2946 bool is_socket(std::error_code
&ec
) const noexcept
2948 return filesystem::is_socket(status(true, true, &ec
));
2950 bool is_symlink() const
2952 return filesystem::is_symlink(status(false, true, nullptr));
2954 bool is_symlink(std::error_code
&ec
) const noexcept
2956 return filesystem::is_symlink(status(false, true, &ec
));
2958 std::uintmax_t file_size() const
2960 if(flags
.has_file_size_value
)
2961 return file_size_value
;
2962 return filesystem::file_size(path_value
);
2964 std::uintmax_t file_size(std::error_code
&ec
) const noexcept
2967 if(flags
.has_file_size_value
)
2968 return file_size_value
;
2969 return filesystem::file_size(path_value
, ec
);
2971 std::uintmax_t hard_link_count() const
2973 if(flags
.has_hard_link_count_value
)
2974 return hard_link_count_value
;
2975 return filesystem::hard_link_count(path_value
);
2977 std::uintmax_t hard_link_count(std::error_code
&ec
) const noexcept
2980 if(flags
.has_hard_link_count_value
)
2981 return hard_link_count_value
;
2982 return filesystem::hard_link_count(path_value
, ec
);
2984 file_time_type
last_write_time() const
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
);
2990 file_time_type
last_write_time(std::error_code
&ec
) const noexcept
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
);
2997 file_status
status() const
2999 return status(true, false, nullptr);
3001 file_status
status(std::error_code
&ec
) const noexcept
3003 return status(true, false, &ec
);
3005 file_status
symlink_status() const
3007 return status(false, false, nullptr);
3009 file_status
symlink_status(std::error_code
&ec
) const noexcept
3011 return status(false, false, &ec
);
3013 bool operator==(const directory_entry
&rt
) const noexcept
3015 return path_value
== rt
.path_value
;
3017 bool operator!=(const directory_entry
&rt
) const noexcept
3019 return path_value
!= rt
.path_value
;
3021 bool operator>=(const directory_entry
&rt
) const noexcept
3023 return path_value
>= rt
.path_value
;
3025 bool operator<=(const directory_entry
&rt
) const noexcept
3027 return path_value
<= rt
.path_value
;
3029 bool operator>(const directory_entry
&rt
) const noexcept
3031 return path_value
> rt
.path_value
;
3033 bool operator<(const directory_entry
&rt
) const noexcept
3035 return path_value
< rt
.path_value
;
3039 class directory_iterator
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
;
3049 struct Implementation
;
3052 std::shared_ptr
<Implementation
> implementation
;
3053 directory_entry current_entry
;
3056 static std::shared_ptr
<Implementation
> create(directory_entry
¤t_entry
,
3058 directory_options options
,
3059 std::error_code
*ec
);
3060 static void increment(std::shared_ptr
<Implementation
> &implementation
,
3061 directory_entry
¤t_entry
,
3062 std::error_code
*ec
);
3065 directory_iterator(const path
&p
, directory_options options
, std::error_code
*ec
)
3066 : implementation(nullptr), current_entry()
3068 implementation
= create(current_entry
, p
, options
, ec
);
3072 directory_iterator() noexcept
: implementation(nullptr), current_entry()
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)
3081 directory_iterator(const path
&p
, directory_options options
)
3082 : directory_iterator(p
, options
, nullptr)
3085 directory_iterator(const path
&p
, std::error_code
&ec
) noexcept
3086 : directory_iterator(p
, directory_options::none
, &ec
)
3089 directory_iterator(const path
&p
, directory_options options
, std::error_code
&ec
) noexcept
3090 : directory_iterator(p
, options
, &ec
)
3093 directory_iterator
&operator=(const directory_iterator
&rt
)
3095 return operator=(directory_iterator(rt
));
3097 directory_iterator
&operator=(directory_iterator
&&rt
) noexcept
3099 directory_iterator
temp(std::move(rt
));
3101 swap(temp
.implementation
, implementation
);
3102 swap(temp
.current_entry
, current_entry
);
3105 directory_iterator
&operator++()
3107 increment(implementation
, current_entry
, nullptr);
3110 directory_iterator
&increment(std::error_code
&ec
) noexcept
3112 increment(implementation
, current_entry
, &ec
);
3115 friend bool operator==(const directory_iterator
&a
, const directory_iterator
&b
) noexcept
3117 return a
.implementation
== b
.implementation
;
3119 friend bool operator!=(const directory_iterator
&a
, const directory_iterator
&b
) noexcept
3121 return a
.implementation
!= b
.implementation
;
3123 const directory_entry
&operator*() const noexcept
3125 return current_entry
;
3127 const directory_entry
*operator->() const noexcept
3129 return ¤t_entry
;
3133 inline directory_iterator
begin(directory_iterator iter
) noexcept
3138 inline directory_iterator
end(const directory_iterator
&) noexcept
3140 return directory_iterator();
3143 #warning finish implementing util::filesystem
3145 // TODO: implement recursive_directory_iterator
3147 "recursive_directory_iterator is not implemented yet")]] recursive_directory_iterator
;
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
;
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
,
3161 std::error_code
&ec
) noexcept
;
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
;
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
,
3175 std::error_code
&ec
) noexcept
;
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
,
3184 std::error_code
&ec
) noexcept
;
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
,
3190 std::error_code
&ec
) noexcept
;
3191 [[deprecated("copy is not implemented yet")]] void copy(const path
&from
,
3193 copy_options options
);
3194 [[deprecated("copy is not implemented yet")]] void copy(const path
&from
,
3196 copy_options options
,
3197 std::error_code
&ec
) noexcept
;
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
,
3203 std::error_code
&ec
) noexcept
;
3204 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path
&from
,
3206 copy_options options
);
3207 [[deprecated("copy_file is not implemented yet")]] void copy_file(const path
&from
,
3209 copy_options options
,
3210 std::error_code
&ec
) noexcept
;
3212 // TODO: implement copy_symlink
3213 [[deprecated("copy_symlink is not implemented yet")]] void copy_symlink(const path
&from
,
3215 [[deprecated("copy_symlink is not implemented yet")]] void copy_symlink(
3216 const path
&from
, const path
&to
, std::error_code
&ec
) noexcept
;
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
;
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
;
3232 // TODO: implement create_hard_link
3233 [[deprecated("create_hard_link is not implemented yet")]] void create_hard_link(const path
&target
,
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
;
3238 // TODO: implement create_symlink
3239 [[deprecated("create_symlink is not implemented yet")]] void create_symlink(const path
&target
,
3241 [[deprecated("create_symlink is not implemented yet")]] void create_symlink(
3242 const path
&target
, const path
&link
, std::error_code
&ec
) noexcept
;
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
;
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
;
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
,
3262 std::error_code
&ec
) noexcept
;
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
,
3268 perm_options options
);
3269 [[deprecated("permissions is not implemented yet")]] void permissions(const path
&p
,
3271 std::error_code
&ec
) noexcept
;
3272 [[deprecated("permissions is not implemented yet")]] void permissions(const path
&p
,
3274 perm_options options
,
3275 std::error_code
&ec
) noexcept
;
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
;
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
;
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
;
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
,
3296 std::error_code
&ec
) noexcept
;
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
;
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
;
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
;
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
;
3323 #endif /* UTIL_FILESYSTEM_H_ */