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.

llvm-svn: 282867
This commit is contained in:
Zachary Turner 2016-09-30 15:43:59 +00:00
parent 17d9caf665
commit 4f20a0a4d9
2 changed files with 121 additions and 0 deletions

View File

@ -626,6 +626,78 @@ template <typename T> struct deref {
}
};
namespace detail {
template <typename I, typename V> class enumerator_impl {
public:
template <typename X> struct result_pair {
result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {}
const std::size_t Index;
X Value;
};
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;
};
enumerator_impl(I Begin, I End)
: Begin(std::move(Begin)), End(std::move(End)) {}
iterator begin() { return iterator(Begin, 0); }
iterator end() { return iterator(End, std::size_t(-1)); }
iterator begin() const { return iterator(Begin, 0); }
iterator end() const { return iterator(End, std::size_t(-1)); }
private:
I Begin;
I End;
};
template <typename I>
auto make_enumerator(I Begin, I End) -> enumerator_impl<I, decltype(*Begin)> {
return enumerator_impl<I, decltype(*Begin)>(std::move(Begin), std::move(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. Example:
///
/// std::vector<char> Items = {'A', 'B', 'C', 'D'};
/// for (auto X : enumerate(Items)) {
/// printf("Item %d - %c\n", X.Item, X.Value);
/// }
///
/// Output:
/// Item 0 - A
/// Item 1 - B
/// Item 2 - C
/// Item 3 - D
///
template <typename R>
auto enumerate(R &&Range)
-> decltype(detail::make_enumerator(std::begin(Range), std::end(Range))) {
return detail::make_enumerator(std::begin(Range), std::end(Range));
}
} // End llvm namespace
#endif

View File

@ -10,6 +10,8 @@
#include "llvm/ADT/STLExtras.h"
#include "gtest/gtest.h"
#include <vector>
using namespace llvm;
namespace {
@ -37,4 +39,51 @@ 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(3u, results.size());
EXPECT_EQ(0u, results[0].first);
EXPECT_EQ('a', results[0].second);
EXPECT_EQ(1u, results[1].first);
EXPECT_EQ('b', results[1].second);
EXPECT_EQ(2u, 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(0u, results[0].first);
EXPECT_EQ('1', results[0].second);
EXPECT_EQ(1u, results[1].first);
EXPECT_EQ('2', results[1].second);
EXPECT_EQ(2u, results[2].first);
EXPECT_EQ('3', results[2].second);
results.clear();
const std::vector<int> baz;
for (auto X : llvm::enumerate(baz)) {
results.push_back(std::make_pair(X.Index, X.Value));
}
EXPECT_TRUE(baz.empty());
}
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]);
}
}