Rewrite std::filesystem::path iterators and parser
This patch entirely rewrites the parsing logic for paths. Unlike the previous
implementation this one stores information about the current state; For example
if we are in a trailing separator or a root separator. This avoids the need for
extra lookahead (and extra work) when incrementing or decrementing an iterator.
Roughly this gives us a 15% speedup over the previous implementation.
Unfortunately this implementation is still a lot slower than libstdc++'s.
Because libstdc++ pre-parses and splits the path upon construction their
iterators are trivial to increment/decrement. This makes libc++ lazy parsing
100x slower than libstdc++. However the pre-parsing libstdc++ causes a ton
of extra and unneeded allocations when constructing the string. For example
`path("/foo/bar/")` would require at least 5 allocations with libstdc++
whereas libc++ uses only one. The non-allocating behavior is much preferable
when you consider filesystem usages like 'exists("/foo/bar/")'.
Even then libc++'s path seems to be twice as slow to simply construct compared
to libstdc++. More investigation is needed about this.
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@285526 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/experimental/filesystem b/include/experimental/filesystem
index c1427c8..1a8dee9 100644
--- a/include/experimental/filesystem
+++ b/include/experimental/filesystem
@@ -1083,7 +1083,8 @@
typedef const path& reference;
public:
_LIBCPP_INLINE_VISIBILITY
- iterator() : __elem_(), __path_ptr_(nullptr), __pos_(0) {}
+ iterator() : __stashed_elem_(), __path_ptr_(nullptr),
+ __entry_(), __state_(__singular) {}
iterator(const iterator&) = default;
~iterator() = default;
@@ -1092,16 +1093,20 @@
_LIBCPP_INLINE_VISIBILITY
reference operator*() const {
- return __elem_;
+ return __stashed_elem_;
}
_LIBCPP_INLINE_VISIBILITY
pointer operator->() const {
- return &__elem_;
+ return &__stashed_elem_;
}
_LIBCPP_INLINE_VISIBILITY
iterator& operator++() {
+ _LIBCPP_ASSERT(__state_ != __singular,
+ "attempting to increment a singular iterator");
+ _LIBCPP_ASSERT(__state_ != __at_end,
+ "attempting to increment the end iterator");
return __increment();
}
@@ -1114,6 +1119,10 @@
_LIBCPP_INLINE_VISIBILITY
iterator& operator--() {
+ _LIBCPP_ASSERT(__state_ != __singular,
+ "attempting to decrement a singular iterator");
+ _LIBCPP_ASSERT(__entry_.data() != __path_ptr_->native().data(),
+ "attempting to decrement the begin iterator");
return __decrement();
}
@@ -1127,21 +1136,25 @@
private:
friend class path;
+ static constexpr unsigned char __singular = 0;
+ static constexpr unsigned char __at_end = 6;
+
inline _LIBCPP_INLINE_VISIBILITY
friend bool operator==(const iterator&, const iterator&);
_LIBCPP_FUNC_VIS iterator& __increment();
_LIBCPP_FUNC_VIS iterator& __decrement();
- path __elem_;
+ path __stashed_elem_;
const path* __path_ptr_;
- size_t __pos_;
+ path::__string_view __entry_;
+ unsigned char __state_;
};
inline _LIBCPP_INLINE_VISIBILITY
bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) {
return __lhs.__path_ptr_ == __rhs.__path_ptr_ &&
- __lhs.__pos_ == __rhs.__pos_;
+ __lhs.__entry_.data() == __rhs.__entry_.data();
}
inline _LIBCPP_INLINE_VISIBILITY