Add llvm::enumerate() to stl extras

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 29 14:03:38 PDT 2016


Here's the latest iteration.  Added doxygen comments and removed postfix ++
operator and operator==.  Also removed the overload of llvm::enumerate()
and used a single function that takes an rvalue reference instead of
overloading on const Range& and Range&

>From ae8f3cb0a9d1958b4c2dd3fcff84e22cd9bb4ba9 Mon Sep 17 00:00:00 2001
From: Zachary Turner <zturner at google.com>
Date: Thu, 29 Sep 2016 11:13:38 -0700
Subject: [PATCH] Add llvm::enumerate to STLExtras.

---
 include/llvm/ADT/STLExtras.h    | 54
+++++++++++++++++++++++++++++++++++++++++
 unittests/ADT/STLExtrasTest.cpp | 42 ++++++++++++++++++++++++++++++++
 2 files changed, 96 insertions(+)

diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h
index e6215e4..63f919d 100644
--- a/include/llvm/ADT/STLExtras.h
+++ b/include/llvm/ADT/STLExtras.h
@@ -626,6 +626,60 @@ template <typename T> struct deref {
   }
 };

+namespace detail {
+template <typename I, typename V> class enumerator_impl {
+public:
+  template <typename V> struct result_pair {
+    result_pair(std::size_t Index, V Value) : Index(Index), Value(Value) {}
+
+    const std::size_t Index;
+    V Value;
+  };
+
+  template <typename I, typename V> struct iterator {
+    iterator(I Iter, std::size_t Index) : Iter(Iter), Index(Index) {}
+
+    result_pair<const V> operator*() const {
+      return result_pair<const V>(Index, *Iter);
+    }
+    result_pair<V> operator*() { return result_pair<V>(Index, *Iter); }
+
+    iterator &operator++() {
+      ++Iter;
+      ++Index;
+      return *this;
+    }
+
+    bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; }
+
+  private:
+    I Iter;
+    std::size_t Index;
+  };
+
+  explicit enumerator_impl(I Begin, I End) : Begin(Begin), End(End) {}
+
+  iterator<I, V> begin() { return iterator<I, V>(Begin, 0); }
+  iterator<I, V> end() { return iterator<I, V>(End, std::size_t(-1)); }
+
+  iterator<I, V> begin() const { return iterator<I, V>(Begin, 0); }
+  iterator<I, V> end() const { return iterator<I, V>(End,
std::size_t(-1)); }
+
+private:
+  I Begin;
+  I End;
+};
+}
+
+/// Given an input range, returns a new range whose values are are pair
(A,B)
+/// such that A is the 0-based index of the item in the sequence, and B is
+/// the value from the original sequence.
+template <typename R> auto enumerate(R &&Range) {
+  typedef decltype(std::begin(Range)) I;
+  typedef decltype(*std::begin(Range)) V;
+  return detail::enumerator_impl<I, V>(std::begin(Range), std::end(Range));
+}
+
 } // End llvm namespace

 #endif
diff --git a/unittests/ADT/STLExtrasTest.cpp
b/unittests/ADT/STLExtrasTest.cpp
index dc62b03..d7457f5 100644
--- a/unittests/ADT/STLExtrasTest.cpp
+++ b/unittests/ADT/STLExtrasTest.cpp
@@ -10,6 +10,8 @@
 #include "llvm/ADT/STLExtras.h"
 #include "gtest/gtest.h"

+#include <vector>
+
 using namespace llvm;

 namespace {
@@ -37,4 +39,44 @@ TEST(STLExtrasTest, Rank) {
   EXPECT_EQ(4, f(rank<6>()));
 }

+TEST(STLExtrasTest, Enumerate) {
+  std::vector<char> foo = {'a', 'b', 'c'};
+
+  std::vector<std::pair<std::size_t, char>> results;
+
+  for (auto X : llvm::enumerate(foo)) {
+    results.push_back(std::make_pair(X.Index, X.Value));
+  }
+  ASSERT_EQ(3, results.size());
+  EXPECT_EQ(0, results[0].first);
+  EXPECT_EQ('a', results[0].second);
+  EXPECT_EQ(1, results[1].first);
+  EXPECT_EQ('b', results[1].second);
+  EXPECT_EQ(2, results[2].first);
+  EXPECT_EQ('c', results[2].second);
+
+  results.clear();
+  const std::vector<int> bar = {'1', '2', '3'};
+  for (auto X : llvm::enumerate(bar)) {
+    results.push_back(std::make_pair(X.Index, X.Value));
+  }
+  EXPECT_EQ(0, results[0].first);
+  EXPECT_EQ('1', results[0].second);
+  EXPECT_EQ(1, results[1].first);
+  EXPECT_EQ('2', results[1].second);
+  EXPECT_EQ(2, results[2].first);
+  EXPECT_EQ('3', results[2].second);
+}
+
+TEST(STLExtrasTest, EnumerateModify) {
+  std::vector<char> foo = {'a', 'b', 'c'};
+
+  for (auto X : llvm::enumerate(foo)) {
+    ++X.Value;
+  }
+
+  EXPECT_EQ('b', foo[0]);
+  EXPECT_EQ('c', foo[1]);
+  EXPECT_EQ('d', foo[2]);
+}
 }

On Thu, Sep 29, 2016 at 1:33 PM Adrian McCarthy <amccarth at google.com> wrote:

> I'm looking at http://en.cppreference.com/w/cpp/language/range-for, which
> suggests that the range-based for is going to call begin and end on your
> range to get the iterators, and then use operator!= and operator++ (prefix)
> on the iterators.
>
> Since you're testing only with range-based for loops, perhaps the
> unnecessary bits should be cut (like operator== and operator++(int)
> (postfix)).  Either that or test those explicitly.
>
> On Thu, Sep 29, 2016 at 1:11 PM, Zachary Turner <zturner at google.com>
> wrote:
>
> I don't think so, but someone correct me if I'm wrong.  enumerator works
> with ranges, not iterators.  So by extension enumerate should also be
> considered to return a range, and not an iterator.  The baggage associated
> with ranges are much less than that associated with iterators.  As long as
> you have a begin and an end you're good to go.
>
> But then again who knows, someone with more knowledge than me will have to
> chime in :)
>
> On Thu, Sep 29, 2016 at 1:06 PM Adrian McCarthy <amccarth at google.com>
> wrote:
>
> Should `enumerator_impl::iterator` have the extra baggage for
> `std::iterator_traits`, like typedefs for `value_type`,
> `iterator_category`, and such?
>
> On the other hand, if this is strictly for range-based for loops, then
> perhaps you don't even need the post-fix increment.
>
>
> On Thu, Sep 29, 2016 at 12:34 PM, Zachary Turner via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
> Yes, you beat me to it.  I just used container in my example, but the
> implementation is supposed to work with any range
>
> On Thu, Sep 29, 2016 at 12:33 PM Krzysztof Parzyszek via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
> On 9/29/2016 2:27 PM, Krzysztof Parzyszek via llvm-commits wrote:
> >
> > How about enumerate(range) instead of container?
>
> Nevermind.  It's the same thing.
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160929/7d390d3b/attachment.html>


More information about the llvm-commits mailing list