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