Skip to content

Commit d26a0c9

Browse files
committed
Add generate_until
1 parent 1955133 commit d26a0c9

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
@@ -235,6 +235,7 @@ target_sources(containers PUBLIC
235235
source/containers/algorithms/filter.cpp
236236
source/containers/algorithms/find.cpp
237237
source/containers/algorithms/generate.cpp
238+
source/containers/algorithms/generate_until.cpp
238239
source/containers/algorithms/keyed_binary_search.cpp
239240
source/containers/algorithms/keyed_erase.cpp
240241
source/containers/algorithms/keyed_insert.cpp
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright David Stone 2021.
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/arrow.hpp>
9+
10+
export module containers.algorithms.generate_until;
11+
12+
export import containers.common_iterator_functions;
13+
import containers.stored_function;
14+
15+
import bounded;
16+
import numeric_traits;
17+
import std_module;
18+
19+
using namespace bounded::literal;
20+
21+
namespace containers {
22+
23+
template<typename Function>
24+
struct generate_until_sentinel {
25+
explicit constexpr generate_until_sentinel(Function & is_done_):
26+
m_is_done(is_done_)
27+
{
28+
}
29+
constexpr auto is_done() const -> bool {
30+
return std::invoke(m_is_done);
31+
}
32+
private:
33+
[[no_unique_address]] stored_function<Function> m_is_done;
34+
};
35+
36+
template<typename Function>
37+
struct generate_until_iterator {
38+
using iterator_category = std::input_iterator_tag;
39+
// TODO: ???
40+
using difference_type = decltype(bounded::integer(std::int64_t()));
41+
42+
explicit constexpr generate_until_iterator(Function & generator):
43+
m_generator(generator)
44+
{
45+
}
46+
generate_until_iterator(generate_until_iterator &&) = default;
47+
generate_until_iterator(generate_until_iterator const &) = delete;
48+
auto operator=(generate_until_iterator &&) & -> generate_until_iterator & = default;
49+
auto operator=(generate_until_iterator const &) & -> generate_until_iterator & = delete;
50+
51+
constexpr auto operator*() const -> decltype(auto) {
52+
return std::invoke(m_generator);
53+
}
54+
OPERATORS_ARROW_DEFINITIONS
55+
56+
template<typename UntilFunction>
57+
friend constexpr auto operator==(generate_until_iterator const &, generate_until_sentinel<UntilFunction> const rhs) -> bool {
58+
return rhs.is_done();
59+
}
60+
61+
friend constexpr auto operator+(generate_until_iterator it, bounded::constant_t<1>) -> generate_until_iterator {
62+
return it;
63+
}
64+
private:
65+
[[no_unique_address]] stored_function<Function> m_generator;
66+
};
67+
68+
export template<std::invocable Function, bounded::invocable_r<bool> UntilFunction>
69+
struct generate_until {
70+
constexpr generate_until(Function generator, UntilFunction until):
71+
m_generator(std::move(generator)),
72+
m_until(std::move(until))
73+
{
74+
}
75+
76+
constexpr auto begin() const requires std::invocable<Function const &> {
77+
return generate_until_iterator(m_generator);
78+
}
79+
constexpr auto begin() {
80+
return generate_until_iterator(m_generator);
81+
}
82+
constexpr auto end() const requires std::invocable<UntilFunction const &> {
83+
return generate_until_sentinel(m_until);
84+
}
85+
constexpr auto end() {
86+
return generate_until_sentinel(m_until);
87+
}
88+
private:
89+
[[no_unique_address]] Function m_generator;
90+
[[no_unique_address]] UntilFunction m_until;
91+
};
92+
93+
} // namespace containers
94+
95+
constexpr auto empty_generator = containers::generate_until(
96+
[] -> int { std::unreachable(); },
97+
[] { return true; }
98+
);
99+
static_assert(empty_generator.begin() == empty_generator.end());
100+
101+
static_assert([] {
102+
for ([[maybe_unused]] auto const _ : empty_generator) {
103+
}
104+
return true;
105+
}());
106+
107+
static_assert([] {
108+
int x = 2;
109+
auto const g = containers::generate_until(
110+
[&] { return x *= 2; },
111+
[&] { return x > 4; }
112+
);
113+
for ([[maybe_unused]] auto const _ : g) {
114+
}
115+
return x == 8;
116+
}());
117+

source/containers/containers.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export import containers.algorithms.erase;
2727
export import containers.algorithms.filter;
2828
export import containers.algorithms.find;
2929
export import containers.algorithms.generate;
30+
export import containers.algorithms.generate_until;
3031
export import containers.algorithms.keyed_binary_search;
3132
export import containers.algorithms.keyed_erase;
3233
export import containers.algorithms.keyed_insert;

0 commit comments

Comments
 (0)