Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 94e2b94

Browse files
Zachary Turnertfiala
authored andcommitted
Resubmit "Add llvm::enumerate() to STLExtras."
The CL was originally failing due to the use of some C++14 specific features, so I've removed those. Hopefully this will satisfy the bots. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282867 91177308-0d34-0410-b5e6-96231b3b80d8 (cherry picked from commit f216a86)
1 parent 6a2627b commit 94e2b94

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

include/llvm/ADT/STLExtras.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,78 @@ template <typename T> struct deref {
613613
}
614614
};
615615

616+
namespace detail {
617+
template <typename I, typename V> class enumerator_impl {
618+
public:
619+
template <typename X> struct result_pair {
620+
result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {}
621+
622+
const std::size_t Index;
623+
X Value;
624+
};
625+
626+
struct iterator {
627+
iterator(I Iter, std::size_t Index) : Iter(Iter), Index(Index) {}
628+
629+
result_pair<const V> operator*() const {
630+
return result_pair<const V>(Index, *Iter);
631+
}
632+
result_pair<V> operator*() { return result_pair<V>(Index, *Iter); }
633+
634+
iterator &operator++() {
635+
++Iter;
636+
++Index;
637+
return *this;
638+
}
639+
640+
bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; }
641+
642+
private:
643+
I Iter;
644+
std::size_t Index;
645+
};
646+
647+
enumerator_impl(I Begin, I End)
648+
: Begin(std::move(Begin)), End(std::move(End)) {}
649+
650+
iterator begin() { return iterator(Begin, 0); }
651+
iterator end() { return iterator(End, std::size_t(-1)); }
652+
653+
iterator begin() const { return iterator(Begin, 0); }
654+
iterator end() const { return iterator(End, std::size_t(-1)); }
655+
656+
private:
657+
I Begin;
658+
I End;
659+
};
660+
661+
template <typename I>
662+
auto make_enumerator(I Begin, I End) -> enumerator_impl<I, decltype(*Begin)> {
663+
return enumerator_impl<I, decltype(*Begin)>(std::move(Begin), std::move(End));
664+
}
665+
}
666+
667+
/// Given an input range, returns a new range whose values are are pair (A,B)
668+
/// such that A is the 0-based index of the item in the sequence, and B is
669+
/// the value from the original sequence. Example:
670+
///
671+
/// std::vector<char> Items = {'A', 'B', 'C', 'D'};
672+
/// for (auto X : enumerate(Items)) {
673+
/// printf("Item %d - %c\n", X.Item, X.Value);
674+
/// }
675+
///
676+
/// Output:
677+
/// Item 0 - A
678+
/// Item 1 - B
679+
/// Item 2 - C
680+
/// Item 3 - D
681+
///
682+
template <typename R>
683+
auto enumerate(R &&Range)
684+
-> decltype(detail::make_enumerator(std::begin(Range), std::end(Range))) {
685+
return detail::make_enumerator(std::begin(Range), std::end(Range));
686+
}
687+
616688
} // End llvm namespace
617689

618690
#endif

unittests/ADT/STLExtrasTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "llvm/ADT/STLExtras.h"
1111
#include "gtest/gtest.h"
1212

13+
#include <vector>
14+
1315
using namespace llvm;
1416

1517
namespace {
@@ -37,4 +39,51 @@ TEST(STLExtrasTest, Rank) {
3739
EXPECT_EQ(4, f(rank<6>()));
3840
}
3941

42+
TEST(STLExtrasTest, Enumerate) {
43+
std::vector<char> foo = {'a', 'b', 'c'};
44+
45+
std::vector<std::pair<std::size_t, char>> results;
46+
47+
for (auto X : llvm::enumerate(foo)) {
48+
results.push_back(std::make_pair(X.Index, X.Value));
49+
}
50+
ASSERT_EQ(3u, results.size());
51+
EXPECT_EQ(0u, results[0].first);
52+
EXPECT_EQ('a', results[0].second);
53+
EXPECT_EQ(1u, results[1].first);
54+
EXPECT_EQ('b', results[1].second);
55+
EXPECT_EQ(2u, results[2].first);
56+
EXPECT_EQ('c', results[2].second);
57+
58+
results.clear();
59+
const std::vector<int> bar = {'1', '2', '3'};
60+
for (auto X : llvm::enumerate(bar)) {
61+
results.push_back(std::make_pair(X.Index, X.Value));
62+
}
63+
EXPECT_EQ(0u, results[0].first);
64+
EXPECT_EQ('1', results[0].second);
65+
EXPECT_EQ(1u, results[1].first);
66+
EXPECT_EQ('2', results[1].second);
67+
EXPECT_EQ(2u, results[2].first);
68+
EXPECT_EQ('3', results[2].second);
69+
70+
results.clear();
71+
const std::vector<int> baz;
72+
for (auto X : llvm::enumerate(baz)) {
73+
results.push_back(std::make_pair(X.Index, X.Value));
74+
}
75+
EXPECT_TRUE(baz.empty());
76+
}
77+
78+
TEST(STLExtrasTest, EnumerateModify) {
79+
std::vector<char> foo = {'a', 'b', 'c'};
80+
81+
for (auto X : llvm::enumerate(foo)) {
82+
++X.Value;
83+
}
84+
85+
EXPECT_EQ('b', foo[0]);
86+
EXPECT_EQ('c', foo[1]);
87+
EXPECT_EQ('d', foo[2]);
88+
}
4089
}

0 commit comments

Comments
 (0)