forked from CommitThis/zip-iterator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zip_view.hpp
134 lines (106 loc) · 2.68 KB
/
zip_view.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
#ifndef ZIP_VIEW_HPP
#define ZIP_VIEW_HPP
#include <cassert>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <typeinfo>
#include <ranges>
namespace c9::detail {
template <typename ... Args, std::size_t ... Index>
auto any_match_impl(std::tuple<Args...> const & lhs,
std::tuple<Args...> const & rhs,
std::index_sequence<Index...>) -> bool
{
auto result = false;
result = (... | (std::get<Index>(lhs) == std::get<Index>(rhs)));
return result;
}
template <typename ... Args>
auto any_match(std::tuple<Args...> const & lhs, std::tuple<Args...> const & rhs)
-> bool
{
return any_match_impl(lhs, rhs, std::index_sequence_for<Args...>{});
}
template <std::ranges::viewable_range ... Rng>
class zip_iterator
{
public:
using value_type = std::tuple<
std::ranges::range_reference_t<Rng>...
>;
zip_iterator() = delete;
zip_iterator(std::ranges::iterator_t<Rng> && ... iters)
: m_iters {std::forward<std::ranges::iterator_t<Rng>>(iters)...}
{
}
auto operator++() -> zip_iterator&
{
std::apply([](auto && ... args){ ((++args), ...); }, m_iters);
return *this;
}
auto operator++(int) -> zip_iterator
{
auto tmp = *this;
++*this;
return tmp;
}
auto operator!=(zip_iterator const & other) const
{
return !(*this == other);
}
auto operator==(zip_iterator const & other) const
{
auto result = false;
return any_match(m_iters, other.m_iters);
}
auto operator*() -> value_type
{
return std::apply([](auto && ... args){
return value_type(*args...);
}, m_iters);
}
private:
std::tuple<std::ranges::iterator_t<Rng>...> m_iters;
};
template <std::ranges::viewable_range ... T>
class zipper
{
public:
using zip_type = zip_iterator<T ...>;
template <typename ... Args>
zipper(Args && ... args)
: m_args{std::forward<Args>(args)...}
{
}
auto begin() -> zip_type
{
return std::apply([](auto && ... args){
return zip_type(std::ranges::begin(args)...);
}, m_args);
}
auto end() -> zip_type
{
return std::apply([](auto && ... args){
return zip_type(std::ranges::end(args)...);
}, m_args);
}
private:
std::tuple<T ...> m_args;
};
} // namespace c9::detail
#ifdef ZIP_VIEW_INJECT_STD_VIEWS_NAMESPACE
namespace std::ranges::views {
#else
namespace c9 {
#endif
template <std::ranges::viewable_range ... T>
auto zip(T && ... t)
{
return c9::detail::zipper<T ...>{std::forward<T>(t)...};
}
}
#endif // ZIP_VIEW_HPP