[llvm] r317902 - [ADT] Rewrite mapped_iterator in terms of iterator_adaptor_base.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 10 09:41:28 PST 2017


Author: lhames
Date: Fri Nov 10 09:41:28 2017
New Revision: 317902

URL: http://llvm.org/viewvc/llvm-project?rev=317902&view=rev
Log:
[ADT] Rewrite mapped_iterator in terms of iterator_adaptor_base.

Summary:
This eliminates the boilerplate implementation of the iterator interface in
mapped_iterator.

This patch also adds unit tests that verify that the mapped function is applied
by operator* and operator->, and that references returned by the map function
are returned via operator*.

Reviewers: dblaikie, chandlerc

Subscribers: llvm-commits, mgorny

Differential Revision: https://reviews.llvm.org/D39855

Added:
    llvm/trunk/unittests/ADT/MappedIteratorTest.cpp
Modified:
    llvm/trunk/include/llvm/ADT/STLExtras.h
    llvm/trunk/unittests/ADT/CMakeLists.txt

Modified: llvm/trunk/include/llvm/ADT/STLExtras.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/STLExtras.h?rev=317902&r1=317901&r2=317902&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/STLExtras.h (original)
+++ llvm/trunk/include/llvm/ADT/STLExtras.h Fri Nov 10 09:41:28 2017
@@ -132,91 +132,32 @@ inline void deleter(T *Ptr) {
 
 // mapped_iterator - This is a simple iterator adapter that causes a function to
 // be applied whenever operator* is invoked on the iterator.
-template <class RootIt, class UnaryFunc>
-class mapped_iterator {
-  RootIt current;
-  UnaryFunc Fn;
 
+template <typename ItTy, typename FuncTy,
+          typename FuncReturnTy =
+            decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))>
+class mapped_iterator
+    : public iterator_adaptor_base<
+             mapped_iterator<ItTy, FuncTy>, ItTy,
+             typename std::iterator_traits<ItTy>::iterator_category,
+             typename std::remove_reference<FuncReturnTy>::type> {
 public:
-  using iterator_category =
-      typename std::iterator_traits<RootIt>::iterator_category;
-  using difference_type =
-      typename std::iterator_traits<RootIt>::difference_type;
-  using value_type =
-      decltype(std::declval<UnaryFunc>()(*std::declval<RootIt>()));
-
-  using pointer = void;
-  using reference = void; // Can't modify value returned by fn
-
-  using iterator_type = RootIt;
-
-  inline explicit mapped_iterator(const RootIt &I, UnaryFunc F)
-    : current(I), Fn(F) {}
-
-  inline value_type operator*() const {   // All this work to do this
-    return Fn(*current);         // little change
-  }
-
-  mapped_iterator &operator++() {
-    ++current;
-    return *this;
-  }
-  mapped_iterator &operator--() {
-    --current;
-    return *this;
-  }
-  mapped_iterator operator++(int) {
-    mapped_iterator __tmp = *this;
-    ++current;
-    return __tmp;
-  }
-  mapped_iterator operator--(int) {
-    mapped_iterator __tmp = *this;
-    --current;
-    return __tmp;
-  }
-  mapped_iterator operator+(difference_type n) const {
-    return mapped_iterator(current + n, Fn);
-  }
-  mapped_iterator &operator+=(difference_type n) {
-    current += n;
-    return *this;
-  }
-  mapped_iterator operator-(difference_type n) const {
-    return mapped_iterator(current - n, Fn);
-  }
-  mapped_iterator &operator-=(difference_type n) {
-    current -= n;
-    return *this;
-  }
-  reference operator[](difference_type n) const { return *(*this + n); }
-
-  bool operator!=(const mapped_iterator &X) const { return !operator==(X); }
-  bool operator==(const mapped_iterator &X) const {
-    return current == X.current;
-  }
-  bool operator<(const mapped_iterator &X) const { return current < X.current; }
-
-  difference_type operator-(const mapped_iterator &X) const {
-    return current - X.current;
-  }
+  mapped_iterator(ItTy U, FuncTy F)
+    : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {}
 
-  inline const RootIt &getCurrent() const { return current; }
-  inline const UnaryFunc &getFunc() const { return Fn; }
-};
+  ItTy getCurrent() { return this->I; }
 
-template <class Iterator, class Func>
-inline mapped_iterator<Iterator, Func>
-operator+(typename mapped_iterator<Iterator, Func>::difference_type N,
-          const mapped_iterator<Iterator, Func> &X) {
-  return mapped_iterator<Iterator, Func>(X.getCurrent() - N, X.getFunc());
-}
+  FuncReturnTy operator*() { return F(*this->I); }
+
+private:
+  FuncTy F;
+};
 
 // map_iterator - Provide a convenient way to create mapped_iterators, just like
 // make_pair is useful for creating pairs...
 template <class ItTy, class FuncTy>
-inline mapped_iterator<ItTy, FuncTy> map_iterator(const ItTy &I, FuncTy F) {
-  return mapped_iterator<ItTy, FuncTy>(I, F);
+inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
+  return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F));
 }
 
 /// Helper to determine if type T has a member called rbegin().

Modified: llvm/trunk/unittests/ADT/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=317902&r1=317901&r2=317902&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ADT/CMakeLists.txt Fri Nov 10 09:41:28 2017
@@ -32,6 +32,7 @@ set(ADTSources
   IntrusiveRefCntPtrTest.cpp
   IteratorTest.cpp
   MakeUniqueTest.cpp
+  MappedIteratorTest.cpp
   MapVectorTest.cpp
   OptionalTest.cpp
   PackedVectorTest.cpp

Added: llvm/trunk/unittests/ADT/MappedIteratorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/MappedIteratorTest.cpp?rev=317902&view=auto
==============================================================================
--- llvm/trunk/unittests/ADT/MappedIteratorTest.cpp (added)
+++ llvm/trunk/unittests/ADT/MappedIteratorTest.cpp Fri Nov 10 09:41:28 2017
@@ -0,0 +1,51 @@
+//===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(MappedIteratorTest, ApplyFunctionOnDereference) {
+  std::vector<int> V({0});
+
+  auto I = map_iterator(V.begin(), [](int X) { return X + 1; });
+
+  EXPECT_EQ(*I, 1) << "should have applied function in dereference";
+}
+
+TEST(MappedIteratorTest, ApplyFunctionOnArrow) {
+  struct S {
+    int Z = 0;
+  };
+
+  std::vector<int> V({0});
+  S Y;
+  S* P = &Y;
+
+  auto I = map_iterator(V.begin(), [&](int X) -> S& { return *(P + X); });
+
+  I->Z = 42;
+
+  EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
+}
+
+TEST(MappedIteratorTest, FunctionPreservesReferences) {
+  std::vector<int> V({1});
+  std::map<int, int> M({ {1, 1} });
+
+  auto I = map_iterator(V.begin(), [&](int X) -> int& { return M[X]; });
+  *I = 42;
+
+  EXPECT_EQ(M[1], 42) << "assignment should have modified M";
+}
+
+} // anonymous namespace




More information about the llvm-commits mailing list