Skip to content

Commit c6fb3bf

Browse files
committed
Add initial zip implementation. It supports only sized ranges and is at most a forward_random_access_range
1 parent f0bc162 commit c6fb3bf

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ target_sources(containers PUBLIC
251251
source/containers/algorithms/transform_iterator.cpp
252252
source/containers/algorithms/uninitialized.cpp
253253
source/containers/algorithms/unique.cpp
254+
source/containers/algorithms/zip.cpp
254255
source/containers/std/list.cpp
255256
source/containers/std/std_allocator.cpp
256257
source/containers/std/vector.cpp
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright David Stone 2019.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
module;
7+
8+
#include <operators/forward.hpp>
9+
10+
export module containers.algorithms.zip;
11+
12+
import containers.algorithms.compare;
13+
import containers.array;
14+
import containers.begin_end;
15+
import containers.is_empty;
16+
import containers.is_iterator;
17+
import containers.iter_difference_t;
18+
import containers.range;
19+
import containers.range_view;
20+
import containers.size;
21+
22+
import bounded;
23+
import std_module;
24+
import tv;
25+
26+
using namespace bounded::literal;
27+
28+
namespace containers {
29+
30+
template<typename... Iterators>
31+
struct zip_iterator;
32+
33+
template<std::size_t... indexes>
34+
constexpr auto dereference(auto const & tuple, std::index_sequence<indexes...>) {
35+
return tv::tie(*tuple[bounded::constant<indexes>]...);
36+
}
37+
38+
template<typename... Iterators, std::size_t... indexes>
39+
constexpr auto add(tv::tuple<Iterators...> const & tuple, auto const offset, std::index_sequence<indexes...>) -> zip_iterator<Iterators...> {
40+
return zip_iterator<Iterators...>((tuple[bounded::constant<indexes>] + offset)...);
41+
}
42+
43+
template<typename... Iterators>
44+
struct zip_difference_type_impl {
45+
// TODO: Wrong type
46+
using type = std::common_type_t<iter_difference_t<Iterators>...>;
47+
};
48+
49+
template<>
50+
struct zip_difference_type_impl<> {
51+
using type = bounded::constant_t<0>;
52+
};
53+
54+
template<typename... Iterators>
55+
struct zip_iterator {
56+
using difference_type = typename zip_difference_type_impl<Iterators...>::type;
57+
58+
constexpr zip_iterator() = default;
59+
constexpr explicit zip_iterator(Iterators... its) requires(sizeof...(Iterators) > 0):
60+
m_its(std::move(its)...)
61+
{
62+
}
63+
64+
friend constexpr auto operator*(zip_iterator const & it) {
65+
return dereference(it.m_its, indexes());
66+
}
67+
friend constexpr auto operator+(zip_iterator, bounded::constant_t<1>) -> zip_iterator requires(sizeof...(Iterators) == 0) {
68+
std::unreachable();
69+
}
70+
friend constexpr auto operator+(zip_iterator const & it, difference_type const offset) -> zip_iterator {
71+
return add(it.m_its, offset, indexes());
72+
}
73+
74+
friend auto operator<=>(zip_iterator const &, zip_iterator const &) = default;
75+
private:
76+
using indexes = std::make_index_sequence<sizeof...(Iterators)>;
77+
[[no_unique_address]] tv::tuple<Iterators...> m_its;
78+
};
79+
80+
constexpr auto all_are_equal(auto const size, auto const ... sizes) -> bool {
81+
return (... and (size == sizes));
82+
}
83+
84+
constexpr auto all_are_equal() -> bool {
85+
return true;
86+
}
87+
88+
constexpr auto get_first_size(auto const r, auto...) {
89+
return containers::size(r);
90+
}
91+
92+
constexpr auto get_first_size() {
93+
return 0_bi;
94+
}
95+
96+
export constexpr auto zip(range auto && ... rs) {
97+
// TODO: Support unsized ranges
98+
if (!all_are_equal(containers::size(rs)...)) {
99+
throw std::runtime_error("Mismatched sizes in zip");
100+
}
101+
return containers::range_view(
102+
zip_iterator(containers::begin(rs)...),
103+
get_first_size(rs...)
104+
);
105+
}
106+
107+
} // namespace containers
108+
109+
static_assert(containers::iterator<containers::zip_iterator<>>);
110+
111+
static_assert(containers::is_empty(containers::zip()));
112+
113+
constexpr auto a1 = containers::array({1, 2});
114+
constexpr auto a2 = containers::array({3, 4});
115+
constexpr auto expected = containers::array({tv::tuple(1, 3), tv::tuple(2, 4)});
116+
static_assert(containers::equal(containers::zip(a1), a1));
117+
static_assert(containers::equal(containers::zip(a1, a2), expected));

source/containers/containers.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export import containers.algorithms.set;
4141
export import containers.algorithms.transform;
4242
export import containers.algorithms.uninitialized;
4343
export import containers.algorithms.unique;
44+
export import containers.algorithms.zip;
4445

4546
export import containers.std.vector;
4647

0 commit comments

Comments
 (0)