Skip to content

Commit 32379dd

Browse files
Brian Favelatimshen91dexonsmithJustin Lebarjoker-eph
authored
Add zip range adapter and other utility functions (#5425)
Last set of cherry picks for reverse iteration, this time enabling utilities that the ReverseIterator test uses in upstream --------- Co-authored-by: Tim Shen <[email protected]> Co-authored-by: Duncan P. N. Exon Smith <[email protected]> Co-authored-by: Justin Lebar <[email protected]> Co-authored-by: Mehdi Amini <[email protected]>
1 parent 44f8833 commit 32379dd

3 files changed

Lines changed: 193 additions & 0 deletions

File tree

include/llvm/ADT/STLExtras.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,95 @@ make_filter_range(RangeT &&Range, PredicateT Pred) {
343343
FilterIteratorT(std::end(std::forward<RangeT>(Range))));
344344
}
345345

346+
// forward declarations required by zip_shortest/zip_first
347+
template <typename R, class UnaryPredicate>
348+
bool all_of(R &&range, UnaryPredicate &&P);
349+
350+
template <size_t... I> struct index_sequence;
351+
352+
template <class... Ts> struct index_sequence_for;
353+
354+
namespace detail {
355+
template <typename... Iters> class zip_first {
356+
public:
357+
typedef std::input_iterator_tag iterator_category;
358+
typedef std::tuple<decltype(*std::declval<Iters>())...> value_type;
359+
std::tuple<Iters...> iterators;
360+
361+
private:
362+
template <size_t... Ns> value_type deres(index_sequence<Ns...>) {
363+
return value_type(*std::get<Ns>(iterators)...);
364+
}
365+
366+
template <size_t... Ns> decltype(iterators) tup_inc(index_sequence<Ns...>) {
367+
return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...);
368+
}
369+
370+
public:
371+
value_type operator*() { return deres(index_sequence_for<Iters...>{}); }
372+
373+
void operator++() { iterators = tup_inc(index_sequence_for<Iters...>{}); }
374+
375+
bool operator!=(const zip_first<Iters...> &other) const {
376+
return std::get<0>(iterators) != std::get<0>(other.iterators);
377+
}
378+
zip_first(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
379+
};
380+
381+
template <typename... Iters> class zip_shortest : public zip_first<Iters...> {
382+
template <size_t... Ns>
383+
bool test(const zip_first<Iters...> &other, index_sequence<Ns...>) const {
384+
return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
385+
std::get<Ns>(other.iterators)...},
386+
identity<bool>{});
387+
}
388+
389+
public:
390+
bool operator!=(const zip_first<Iters...> &other) const {
391+
return test(other, index_sequence_for<Iters...>{});
392+
}
393+
zip_shortest(Iters &&... ts)
394+
: zip_first<Iters...>(std::forward<Iters>(ts)...) {}
395+
};
396+
397+
template <template <typename...> class ItType, typename... Args> class zippy {
398+
public:
399+
typedef ItType<decltype(std::begin(std::declval<Args>()))...> iterator;
400+
401+
private:
402+
std::tuple<Args...> ts;
403+
404+
template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
405+
return iterator(std::begin(std::get<Ns>(ts))...);
406+
}
407+
template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
408+
return iterator(std::end(std::get<Ns>(ts))...);
409+
}
410+
411+
public:
412+
iterator begin() { return begin_impl(index_sequence_for<Args...>{}); }
413+
iterator end() { return end_impl(index_sequence_for<Args...>{}); }
414+
zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
415+
};
416+
} // End detail namespace
417+
418+
/// zip iterator for two or more iteratable types.
419+
template <typename T, typename U, typename... Args>
420+
detail::zippy<detail::zip_shortest, T, U, Args...> zip(T &&t, U &&u,
421+
Args &&... args) {
422+
return detail::zippy<detail::zip_shortest, T, U, Args...>(
423+
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
424+
}
425+
426+
/// zip iterator that, for the sake of efficiency, assumes the first iteratee to
427+
/// be the shortest.
428+
template <typename T, typename U, typename... Args>
429+
detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u,
430+
Args &&... args) {
431+
return detail::zippy<detail::zip_first, T, U, Args...>(
432+
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
433+
}
434+
346435
//===----------------------------------------------------------------------===//
347436
// Extra additions to <utility>
348437
//===----------------------------------------------------------------------===//

include/llvm/ADT/iterator.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,23 @@ struct pointee_iterator
233233
T &operator*() const { return **this->I; }
234234
};
235235

236+
template <typename WrappedIteratorT,
237+
typename T = decltype(&*std::declval<WrappedIteratorT>())>
238+
class pointer_iterator
239+
: public iterator_adaptor_base<pointer_iterator<WrappedIteratorT>,
240+
WrappedIteratorT, T> {
241+
mutable T Ptr;
242+
243+
public:
244+
pointer_iterator() {}
245+
246+
explicit pointer_iterator(WrappedIteratorT u)
247+
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
248+
249+
T &operator*() { return Ptr = &*this->I; }
250+
const T &operator*() const { return Ptr = &*this->I; }
251+
};
252+
236253
}
237254

238255
#endif

unittests/ADT/IteratorTest.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,91 @@ TEST(FilterIteratorTest, InputIterator) {
167167
EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
168168
}
169169

170+
TEST(PointerIterator, Basic) {
171+
int A[] = {1, 2, 3, 4};
172+
pointer_iterator<int *> Begin(std::begin(A)), End(std::end(A));
173+
EXPECT_EQ(A, *Begin);
174+
++Begin;
175+
EXPECT_EQ(A + 1, *Begin);
176+
++Begin;
177+
EXPECT_EQ(A + 2, *Begin);
178+
++Begin;
179+
EXPECT_EQ(A + 3, *Begin);
180+
++Begin;
181+
EXPECT_EQ(Begin, End);
182+
}
183+
184+
TEST(PointerIterator, Const) {
185+
int A[] = {1, 2, 3, 4};
186+
const pointer_iterator<int *> Begin(std::begin(A));
187+
EXPECT_EQ(A, *Begin);
188+
EXPECT_EQ(A + 1, std::next(*Begin, 1));
189+
EXPECT_EQ(A + 2, std::next(*Begin, 2));
190+
EXPECT_EQ(A + 3, std::next(*Begin, 3));
191+
EXPECT_EQ(A + 4, std::next(*Begin, 4));
192+
}
193+
194+
TEST(ZipIteratorTest, Basic) {
195+
using namespace std;
196+
const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
197+
SmallVector<bool, 6> odd{1, 1, 0, 1, 1, 1};
198+
const char message[] = "yynyyy\0";
199+
200+
for (auto tup : zip(pi, odd, message)) {
201+
EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
202+
EXPECT_EQ(get<0>(tup) & 0x01 ? 'y' : 'n', get<2>(tup));
203+
}
204+
205+
// note the rvalue
206+
for (auto tup : zip(pi, SmallVector<bool, 0>{1, 1, 0, 1, 1})) {
207+
EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
208+
}
209+
}
210+
211+
TEST(ZipIteratorTest, ZipFirstBasic) {
212+
using namespace std;
213+
const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
214+
unsigned iters = 0;
215+
216+
for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
217+
EXPECT_EQ(get<0>(tup), get<1>(tup) & 0x01);
218+
iters += 1;
219+
}
220+
221+
EXPECT_EQ(iters, 4u);
222+
}
223+
224+
TEST(ZipIteratorTest, Mutability) {
225+
using namespace std;
226+
const SmallVector<unsigned, 4> pi{3, 1, 4, 1, 5, 9};
227+
char message[] = "hello zip\0";
228+
229+
for (auto tup : zip(pi, message, message)) {
230+
EXPECT_EQ(get<1>(tup), get<2>(tup));
231+
get<2>(tup) = get<0>(tup) & 0x01 ? 'y' : 'n';
232+
}
233+
234+
// note the rvalue
235+
for (auto tup : zip(message, "yynyyyzip\0")) {
236+
EXPECT_EQ(get<0>(tup), get<1>(tup));
237+
}
238+
}
239+
240+
TEST(ZipIteratorTest, ZipFirstMutability) {
241+
using namespace std;
242+
vector<unsigned> pi{3, 1, 4, 1, 5, 9};
243+
unsigned iters = 0;
244+
245+
for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
246+
get<1>(tup) = get<0>(tup);
247+
iters += 1;
248+
}
249+
250+
EXPECT_EQ(iters, 4u);
251+
252+
for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
253+
EXPECT_EQ(get<0>(tup), get<1>(tup));
254+
}
255+
}
256+
170257
} // anonymous namespace

0 commit comments

Comments
 (0)