forked from ryanhaining/cppitertools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zip_longest.hpp
147 lines (121 loc) · 4.55 KB
/
zip_longest.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#ifndef ITER_ZIP_LONGEST_HPP_
#define ITER_ZIP_LONGEST_HPP_
#include "internal/iter_tuples.hpp"
#include "internal/iterbase.hpp"
#include <boost/optional.hpp>
#include <iterator>
#include <tuple>
#include <utility>
namespace iter {
namespace impl {
template <typename TupleType, std::size_t... Is>
class ZippedLongest;
template <typename TupleType, std::size_t... Is>
ZippedLongest<TupleType, Is...> zip_longest_impl(
TupleType&&, std::index_sequence<Is...>);
}
template <typename... Containers>
auto zip_longest(Containers&&... containers);
}
template <typename TupleType, std::size_t... Is>
class iter::impl::ZippedLongest {
private:
TupleType containers_;
friend ZippedLongest zip_longest_impl<TupleType, Is...>(
TupleType&&, std::index_sequence<Is...>);
template <std::size_t I, typename TupleTypeT>
using OptType = boost::optional<iterator_deref<
std::tuple_element_t<I, std::remove_reference_t<TupleTypeT>>>>;
template <std::size_t I, typename TupleTypeT>
using ConstOptType = boost::optional<const_iterator_type_deref<
std::tuple_element_t<I, std::remove_reference_t<TupleTypeT>>>>;
template <typename TupleTypeT,
template <std::size_t, typename> class OptTempl>
using ZipIterDeref = std::tuple<OptTempl<Is, TupleTypeT>...>;
ZippedLongest(TupleType&& containers) : containers_(std::move(containers)) {}
public:
ZippedLongest(ZippedLongest&&) = default;
template <typename TupleTypeT, template <typename> class IterTuple,
template <std::size_t, typename> class OptTempl>
class Iterator {
#if NO_GCC_FRIEND_ERROR
private:
template <typename, template <typename> class,
template <std::size_t, typename> class>
friend class Iterator;
#else
public:
#endif
IterTuple<TupleTypeT> iters_;
IterTuple<TupleTypeT> ends_;
public:
using iterator_category = std::input_iterator_tag;
using value_type = ZipIterDeref<TupleTypeT, OptTempl>;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
Iterator(IterTuple<TupleTypeT>&& iters, IterTuple<TupleTypeT>&& ends)
: iters_(std::move(iters)), ends_(std::move(ends)) {}
Iterator& operator++() {
// increment every iterator that's not already at
// the end
absorb(((std::get<Is>(iters_) != std::get<Is>(ends_))
? (++std::get<Is>(iters_), 0)
: 0)...);
return *this;
}
Iterator operator++(int) {
auto ret = *this;
++*this;
return ret;
}
template <typename T, template <typename> class TT,
template <std::size_t, typename> class TU>
bool operator!=(const Iterator<T, TT, TU>& other) const {
return (... || (std::get<Is>(iters_) != std::get<Is>(other.iters_)));
}
template <typename T, template <typename> class TT,
template <std::size_t, typename> class TU>
bool operator==(const Iterator<T, TT, TU>& other) const {
return !(*this != other);
}
ZipIterDeref<TupleTypeT, OptTempl> operator*() {
return {((std::get<Is>(iters_) != std::get<Is>(ends_))
? OptTempl<Is, TupleTypeT>{*std::get<Is>(iters_)}
: OptTempl<Is, TupleTypeT>{})...};
}
auto operator-> () -> ArrowProxy<decltype(**this)> {
return {**this};
}
};
Iterator<TupleType, iterator_tuple_type, OptType> begin() {
return {{get_begin(std::get<Is>(containers_))...},
{get_end(std::get<Is>(containers_))...}};
}
Iterator<TupleType, iterator_tuple_type, OptType> end() {
return {{get_end(std::get<Is>(containers_))...},
{get_end(std::get<Is>(containers_))...}};
}
Iterator<AsConst<TupleType>, const_iterator_tuple_type, ConstOptType> begin()
const {
return {{get_begin(std::as_const(std::get<Is>(containers_)))...},
{get_end(std::as_const(std::get<Is>(containers_)))...}};
}
Iterator<AsConst<TupleType>, const_iterator_tuple_type, ConstOptType> end()
const {
return {{get_end(std::as_const(std::get<Is>(containers_)))...},
{get_end(std::as_const(std::get<Is>(containers_)))...}};
}
};
template <typename TupleType, std::size_t... Is>
iter::impl::ZippedLongest<TupleType, Is...> iter::impl::zip_longest_impl(
TupleType&& containers, std::index_sequence<Is...>) {
return {std::move(containers)};
}
template <typename... Containers>
auto iter::zip_longest(Containers&&... containers) {
return impl::zip_longest_impl(
std::tuple<Containers...>{std::forward<Containers>(containers)...},
std::index_sequence_for<Containers...>{});
}
#endif