llvm.org GIT mirror llvm / 39e53ee
[ADT] Improve the genericity of llvm::enumerate(). There were some issues in the implementation of enumerate() preventing it from being used in various contexts. These were all related to the fact that it did not supporter llvm's iterator_facade_base class. So this patch adds support for that and additionally exposes a new helper method to_vector() that will evaluate an entire range and store the results in a vector. Differential Revision: https://reviews.llvm.org/D30853 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297633 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 3 years ago
3 changed file(s) with 108 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
2727 #include // for std::pair
2828
2929 #include "llvm/ADT/Optional.h"
30 #include "llvm/ADT/SmallVector.h"
3031 #include "llvm/ADT/iterator.h"
3132 #include "llvm/ADT/iterator_range.h"
3233 #include "llvm/Support/Compiler.h"
4243
4344 template
4445 using IterOfRange = decltype(std::begin(std::declval()));
46
47 template
48 using ValueOfRange = typename std::remove_reference
49 *std::begin(std::declval()))>::type;
4550
4651 } // End detail namespace
4752
882887 return std::partition(std::begin(Range), std::end(Range), P);
883888 }
884889
890 /// \brief Given a range of type R, iterate the entire range and return a
891 /// SmallVector with elements of the vector. This is useful, for example,
892 /// when you want to iterate a range and then sort the results.
893 template
894 SmallVector, Size> to_vector(R &&Range) {
895 return {std::begin(Range), std::end(Range)};
896 }
897
885898 /// Provide a container algorithm similar to C++ Library Fundamentals v2's
886899 /// `erase_if` which is equivalent to:
887900 ///
976989 };
977990
978991 namespace detail {
979 template class enumerator_impl {
980 public:
981 template struct result_pair {
982 result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {}
983
984 const std::size_t Index;
985 X Value;
986 };
987
988 class iterator {
989 typedef
990 typename std::iterator_traits>::reference iter_reference;
991 typedef result_pair result_type;
992
993 public:
994 iterator(IterOfRange &&Iter, std::size_t Index)
995 : Iter(Iter), Index(Index) {}
996
997 result_type operator*() const { return result_type(Index, *Iter); }
998
999 iterator &operator++() {
1000 ++Iter;
1001 ++Index;
1002 return *this;
1003 }
1004
1005 bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; }
1006
1007 private:
1008 IterOfRange Iter;
1009 std::size_t Index;
1010 };
1011
1012 public:
1013 explicit enumerator_impl(R &&Range) : Range(std::forward(Range)) {}
1014
1015 iterator begin() { return iterator(std::begin(Range), 0); }
1016 iterator end() { return iterator(std::end(Range), std::size_t(-1)); }
992 template class enumerator_iter;
993
994 template struct result_pair {
995 friend class enumerator_iter;
996
997 result_pair() : Index(-1) {}
998 result_pair(std::size_t Index, IterOfRange Iter)
999 : Index(Index), Iter(Iter) {}
1000
1001 result_pair &operator=(const result_pair &Other) {
1002 Index = Other.Index;
1003 Iter = Other.Iter;
1004 return *this;
1005 }
1006
1007 std::size_t index() const { return Index; }
1008 const ValueOfRange &value() const { return *Iter; }
1009 ValueOfRange &value() { return *Iter; }
10171010
10181011 private:
1019 R Range;
1012 std::size_t Index;
1013 IterOfRange Iter;
1014 };
1015
1016 template
1017 class enumerator_iter
1018 : public iterator_facade_base<
1019 enumerator_iter, std::forward_iterator_tag, result_pair,
1020 typename std::iterator_traits>::difference_type,
1021 typename std::iterator_traits>::pointer,
1022 typename std::iterator_traits>::reference> {
1023 using result_type = result_pair;
1024
1025 public:
1026 enumerator_iter(std::size_t Index, IterOfRange Iter)
1027 : Result(Index, Iter) {}
1028
1029 result_type &operator*() { return Result; }
1030 const result_type &operator*() const { return Result; }
1031
1032 enumerator_iter &operator++() {
1033 assert(Result.Index != -1);
1034 ++Result.Iter;
1035 ++Result.Index;
1036 return *this;
1037 }
1038
1039 bool operator==(const enumerator_iter &RHS) const {
1040 // Don't compare indices here, only iterators. It's possible for an end
1041 // iterator to have different indices depending on whether it was created
1042 // by calling std::end() versus incrementing a valid iterator.
1043 return Result.Iter == RHS.Result.Iter;
1044 }
1045
1046 enumerator_iter &operator=(const enumerator_iter &Other) {
1047 Result = Other.Result;
1048 return *this;
1049 }
1050
1051 private:
1052 result_type Result;
1053 };
1054
1055 template class enumerator {
1056 public:
1057 explicit enumerator(R &&Range) : TheRange(std::forward(Range)) {}
1058
1059 enumerator_iter begin() {
1060 return enumerator_iter(0, std::begin(TheRange));
1061 }
1062 enumerator_iter end() {
1063 return enumerator_iter(-1, std::end(TheRange));
1064 }
1065
1066 private:
1067 R TheRange;
10201068 };
10211069 }
10221070
10351083 /// Item 2 - C
10361084 /// Item 3 - D
10371085 ///
1038 template detail::enumerator_impl enumerate(R &&Range) {
1039 return detail::enumerator_impl(std::forward(Range));
1086 template detail::enumerator enumerate(R &&TheRange) {
1087 return detail::enumerator(std::forward(TheRange));
10401088 }
10411089
10421090 namespace detail {
4747 std::vector CharResults;
4848
4949 for (auto X : llvm::enumerate(foo)) {
50 CharResults.emplace_back(X.Index, X.Value);
50 CharResults.emplace_back(X.index(), X.value());
5151 }
5252 ASSERT_EQ(3u, CharResults.size());
5353 EXPECT_EQ(CharPairType(0u, 'a'), CharResults[0]);
5959 std::vector IntResults;
6060 const std::vector bar = {1, 2, 3};
6161 for (auto X : llvm::enumerate(bar)) {
62 IntResults.emplace_back(X.Index, X.Value);
62 IntResults.emplace_back(X.index(), X.value());
6363 }
6464 ASSERT_EQ(3u, IntResults.size());
6565 EXPECT_EQ(IntPairType(0u, 1), IntResults[0]);
7070 IntResults.clear();
7171 const std::vector baz{};
7272 for (auto X : llvm::enumerate(baz)) {
73 IntResults.emplace_back(X.Index, X.Value);
73 IntResults.emplace_back(X.index(), X.value());
7474 }
7575 EXPECT_TRUE(IntResults.empty());
7676 }
8181 std::vector foo = {'a', 'b', 'c'};
8282
8383 for (auto X : llvm::enumerate(foo)) {
84 ++X.Value;
84 ++X.value();
8585 }
8686 EXPECT_EQ('b', foo[0]);
8787 EXPECT_EQ('c', foo[1]);
9696 auto Enumerator = llvm::enumerate(std::vector{1, 2, 3});
9797
9898 for (auto X : llvm::enumerate(std::vector{1, 2, 3})) {
99 Results.emplace_back(X.Index, X.Value);
99 Results.emplace_back(X.index(), X.value());
100100 }
101101
102102 ASSERT_EQ(3u, Results.size());
113113 std::vector Results;
114114
115115 for (auto X : llvm::enumerate(std::vector{'1', '2', '3'})) {
116 ++X.Value;
117 Results.emplace_back(X.Index, X.Value);
116 ++X.value();
117 Results.emplace_back(X.index(), X.value());
118118 }
119119
120120 ASSERT_EQ(3u, Results.size());
254254 EXPECT_EQ(1, count(v, 4));
255255 }
256256
257 TEST(STLExtrasTest, ToVector) {
258 std::vector v = {'a', 'b', 'c'};
259 auto Enumerated = to_vector<4>(enumerate(v));
260 ASSERT_EQ(3, Enumerated.size());
261 for (size_t I = 0; I < v.size(); ++I) {
262 EXPECT_EQ(I, Enumerated[I].index());
263 EXPECT_EQ(v[I], Enumerated[I].value());
264 }
265 }
266
257267 TEST(STLExtrasTest, ConcatRange) {
258268 std::vector Expected = {1, 2, 3, 4, 5, 6, 7, 8};
259269 std::vector Test;
581581 /// True if the instruction can be built solely by mutating the opcode.
582582 bool canMutate() const {
583583 for (const auto &Renderer : enumerate(OperandRenderers)) {
584 if (const auto *Copy = dyn_cast(&*Renderer.Value)) {
584 if (const auto *Copy = dyn_cast(&*Renderer.value())) {
585585 if (Matched.getOperand(Copy->getSymbolicName()).getOperandIndex() !=
586 Renderer.Index)
586 Renderer.index())
587587 return false;
588588 } else
589589 return false;