diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -671,9 +671,7 @@ public: zip_common(Iters &&... ts) : iterators(std::forward(ts)...) {} - value_type operator*() { return deref(std::index_sequence_for{}); } - - const value_type operator*() const { + value_type operator*() const { return deref(std::index_sequence_for{}); } @@ -844,8 +842,6 @@ : iterators(std::forward(ts.first)...), end_iterators(std::forward(ts.second)...) {} - value_type operator*() { return deref(std::index_sequence_for{}); } - value_type operator*() const { return deref(std::index_sequence_for{}); } @@ -1939,8 +1935,7 @@ } std::size_t index() const { return Index; } - const value_reference value() const { return *Iter; } - value_reference value() { return *Iter; } + value_reference value() const { return *Iter; } private: std::size_t Index = std::numeric_limits::max(); @@ -1949,11 +1944,8 @@ template class enumerator_iter - : public iterator_facade_base< - enumerator_iter, std::forward_iterator_tag, result_pair, - typename std::iterator_traits>::difference_type, - typename std::iterator_traits>::pointer, - typename std::iterator_traits>::reference> { + : public iterator_facade_base, std::forward_iterator_tag, + const result_pair> { using result_type = result_pair; public: @@ -1963,7 +1955,6 @@ enumerator_iter(std::size_t Index, IterOfRange Iter) : Result(Index, Iter) {} - result_type &operator*() { return Result; } const result_type &operator*() const { return Result; } enumerator_iter &operator++() { diff --git a/llvm/include/llvm/ADT/iterator.h b/llvm/include/llvm/ADT/iterator.h --- a/llvm/include/llvm/ADT/iterator.h +++ b/llvm/include/llvm/ADT/iterator.h @@ -42,8 +42,7 @@ /// (All of the following methods) /// - DerivedT &operator=(const DerivedT &R); /// - bool operator==(const DerivedT &R) const; -/// - const T &operator*() const; -/// - T &operator*(); +/// - T &operator*() const; /// - DerivedT &operator++(); /// /// Bidirectional Iterators: @@ -348,8 +347,7 @@ explicit pointer_iterator(WrappedIteratorT u) : pointer_iterator::iterator_adaptor_base(std::move(u)) {} - T &operator*() { return Ptr = &*this->I; } - const T &operator*() const { return Ptr = &*this->I; } + T &operator*() const { return Ptr = &*this->I; } }; template ::iterator_category, typename std::iterator_traits>::iterator_category>; +// Check that dereferencing works correctly adapting pointers and proxies. +template +struct PointerWrapper : public iterator_adaptor_base, T *> { + PointerWrapper(T *I) : iterator_adaptor_base(I) {} +}; +struct IntProxy { + int &I; + IntProxy(int &I) : I(I) {} + void operator=(int NewValue) { I = NewValue; } +}; +struct ConstIntProxy { + const int &I; + ConstIntProxy(const int &I) : I(I) {} +}; +template +struct PointerProxyWrapper + : public iterator_adaptor_base, T *, + std::random_access_iterator_tag, T, + ptrdiff_t, T *, ProxyT> { + PointerProxyWrapper(T *I) + : iterator_adaptor_base(I) {} +}; +using IntIterator = PointerWrapper; +using ConstIntIterator = PointerWrapper; +using IntProxyIterator = PointerProxyWrapper; +using ConstIntProxyIterator = PointerProxyWrapper; + +template ::value, bool> = false> +constexpr bool canAssignFromInt(T &&) { + return true; +} +template ::value, bool> = false> +constexpr bool canAssignFromInt(T &&) { + return false; +} + +TEST(IteratorAdaptorTest, Dereference) { + int Number = 1; + + // Construct some iterators and check whether they can be assigned to. + IntIterator I(&Number); + const IntIterator IC(&Number); + ConstIntIterator CI(&Number); + const ConstIntIterator CIC(&Number); + EXPECT_EQ(true, canAssignFromInt(*I)); // int * + EXPECT_EQ(true, canAssignFromInt(*IC)); // int *const + EXPECT_EQ(false, canAssignFromInt(*CI)); // const int * + EXPECT_EQ(false, canAssignFromInt(*CIC)); // const int *const + + // Prove that dereference and assignment work. + EXPECT_EQ(1, *I); + EXPECT_EQ(1, *IC); + EXPECT_EQ(1, *CI); + EXPECT_EQ(1, *CIC); + *I = 2; + EXPECT_EQ(2, Number); + *IC = 3; + EXPECT_EQ(3, Number); + + // Construct some proxy iterators and check whether they can be assigned to. + IntProxyIterator P(&Number); + const IntProxyIterator PC(&Number); + ConstIntProxyIterator CP(&Number); + const ConstIntProxyIterator CPC(&Number); + EXPECT_EQ(true, canAssignFromInt(*P)); // int * + EXPECT_EQ(true, canAssignFromInt(*PC)); // int *const + EXPECT_EQ(false, canAssignFromInt(*CP)); // const int * + EXPECT_EQ(false, canAssignFromInt(*CPC)); // const int *const + + // Prove that dereference and assignment work. + EXPECT_EQ(3, (*P).I); + EXPECT_EQ(3, (*PC).I); + EXPECT_EQ(3, (*CP).I); + EXPECT_EQ(3, (*CPC).I); + *P = 4; + EXPECT_EQ(4, Number); + *PC = 5; + EXPECT_EQ(5, Number); +} + // pointeE_iterator static_assert(IsAdaptedIterCategorySame::value, ""); @@ -178,6 +262,16 @@ EXPECT_EQ((SmallVector{1, 3, 5}), Actual); } +TEST(FilterIteratorTest, Enumerate) { + auto IsOdd = [](auto N) { return N.value() % 2 == 1; }; + int A[] = {0, 1, 2, 3, 4, 5, 6}; + auto Enumerate = llvm::enumerate(A); + SmallVector Actual; + for (auto IndexedValue : make_filter_range(Enumerate, IsOdd)) + Actual.push_back(IndexedValue.value()); + EXPECT_EQ((SmallVector{1, 3, 5}), Actual); +} + TEST(FilterIteratorTest, CallableObject) { int Counter = 0; struct Callable {