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));
0 commit comments