#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/Config/abi-breaking.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
std::end(std::forward<RangeT>(Range)), Pred));
}
+/// A pseudo-iterator adaptor that is designed to implement "early increment"
+/// style loops.
+///
+/// This is *not a normal iterator* and should almost never be used directly. It
+/// is intended primarily to be used with range based for loops and some range
+/// algorithms.
+///
+/// The iterator isn't quite an `OutputIterator` or an `InputIterator` but
+/// somewhere between them. The constraints of these iterators are:
+///
+/// - On construction or after being incremented, it is comparable and
+/// dereferencable. It is *not* incrementable.
+/// - After being dereferenced, it is neither comparable nor dereferencable, it
+/// is only incrementable.
+///
+/// This means you can only dereference the iterator once, and you can only
+/// increment it once between dereferences.
+template <typename WrappedIteratorT>
+class early_inc_iterator_impl
+ : public iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
+ WrappedIteratorT, std::input_iterator_tag> {
+ using BaseT =
+ iterator_adaptor_base<early_inc_iterator_impl<WrappedIteratorT>,
+ WrappedIteratorT, std::input_iterator_tag>;
+
+ using PointerT = typename std::iterator_traits<WrappedIteratorT>::pointer;
+
+protected:
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ bool IsEarlyIncremented = false;
+#endif
+
+public:
+ early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {}
+
+ using BaseT::operator*;
+ typename BaseT::reference operator*() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ assert(!IsEarlyIncremented && "Cannot dereference twice!");
+ IsEarlyIncremented = true;
+#endif
+ return *(this->I)++;
+ }
+
+ using BaseT::operator++;
+ early_inc_iterator_impl &operator++() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ assert(IsEarlyIncremented && "Cannot increment before dereferencing!");
+ IsEarlyIncremented = false;
+#endif
+ return *this;
+ }
+
+ using BaseT::operator==;
+ bool operator==(const early_inc_iterator_impl &RHS) const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ assert(!IsEarlyIncremented && "Cannot compare after dereferencing!");
+#endif
+ return BaseT::operator==(RHS);
+ }
+};
+
+/// Make a range that does early increment to allow mutation of the underlying
+/// range without disrupting iteration.
+///
+/// The underlying iterator will be incremented immediately after it is
+/// dereferenced, allowing deletion of the current node or insertion of nodes to
+/// not disrupt iteration provided they do not invalidate the *next* iterator --
+/// the current iterator can be invalidated.
+///
+/// This requires a very exact pattern of use that is only really suitable to
+/// range based for loops and other range algorithms that explicitly guarantee
+/// to dereference exactly once each element, and to increment exactly once each
+/// element.
+template <typename RangeT>
+iterator_range<early_inc_iterator_impl<detail::IterOfRange<RangeT>>>
+make_early_inc_range(RangeT &&Range) {
+ using EarlyIncIteratorT =
+ early_inc_iterator_impl<detail::IterOfRange<RangeT>>;
+ return make_range(EarlyIncIteratorT(std::begin(std::forward<RangeT>(Range))),
+ EarlyIncIteratorT(std::end(std::forward<RangeT>(Range))));
+}
+
// forward declarations required by zip_shortest/zip_first
template <typename R, typename UnaryPredicate>
bool all_of(R &&range, UnaryPredicate P);
EXPECT_EQ(5, count);
}
+TEST(STLExtrasTest, EarlyIncrementTest) {
+ std::list<int> L = {1, 2, 3, 4};
+
+ auto EIR = make_early_inc_range(L);
+
+ auto I = EIR.begin();
+ auto EI = EIR.end();
+ EXPECT_NE(I, EI);
+
+ EXPECT_EQ(1, *I);
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+#ifndef NDEBUG
+ // Repeated dereferences are not allowed.
+ EXPECT_DEATH(*I, "Cannot dereference");
+ // Comparison after dereference is not allowed.
+ EXPECT_DEATH((void)(I == EI), "Cannot compare");
+ EXPECT_DEATH((void)(I != EI), "Cannot compare");
+#endif
+#endif
+
+ ++I;
+ EXPECT_NE(I, EI);
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+#ifndef NDEBUG
+ // You cannot increment prior to dereference.
+ EXPECT_DEATH(++I, "Cannot increment");
+#endif
+#endif
+ EXPECT_EQ(2, *I);
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+#ifndef NDEBUG
+ // Repeated dereferences are not allowed.
+ EXPECT_DEATH(*I, "Cannot dereference");
+#endif
+#endif
+
+ // Inserting shouldn't break anything. We should be able to keep dereferencing
+ // the currrent iterator and increment. The increment to go to the "next"
+ // iterator from before we inserted.
+ L.insert(std::next(L.begin(), 2), -1);
+ ++I;
+ EXPECT_EQ(3, *I);
+
+ // Erasing the front including the current doesn't break incrementing.
+ L.erase(L.begin(), std::prev(L.end()));
+ ++I;
+ EXPECT_EQ(4, *I);
+ ++I;
+ EXPECT_EQ(EIR.end(), I);
+}
+
} // namespace