Skip to content

Commit 64cd52a

Browse files
committed
Implement iterate algorithms
Problem: - There is no algorithm that generalizes `std::iota`. Filling a range 2 elements at a time is hard, more complex patterns are increasingly difficult. Solution: - Implement `iterate` and `iterate_n` which fill a range based on the execution of a binary operation which takes the previous value.
1 parent dbf91f4 commit 64cd52a

File tree

4 files changed

+173
-0
lines changed

4 files changed

+173
-0
lines changed

doc/algorithm.qbk

+10
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,16 @@ Write a sequence of n increasing values to an output iterator
224224
Raise a value to an integral power ([^constexpr] since C++14)
225225
[endsect:power]
226226

227+
[section:iterate iterate ]
228+
[*[^[link header.boost.algorithm.iterate_hpp iterate] ] ]
229+
Store the result of a unary function to each element of a range. This is a generalization of iota.
230+
[endsect:iterate]
231+
232+
[section:iterate iterate ]
233+
[*[^[link header.boost.algorithm.iterate_hpp iterate] ] ]
234+
Store the result of a unary function to n element of a range. This is a generalization of iota.
235+
[endsect:iterate]
236+
227237
[endsect:misc_inner_algorithms]
228238

229239
[endsect:Misc]

include/boost/algorithm/iterate.hpp

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright (c) Jonathan Gopel 2022.
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
*/
7+
8+
#ifndef BOOST_ALGORITHM_ITERATE_HPP
9+
#define BOOST_ALGORITHM_ITERATE_HPP
10+
11+
#include <boost/config.hpp>
12+
13+
#include <utility>
14+
15+
namespace boost {
16+
namespace algorithm {
17+
18+
template <class OutputIterator, class TInit, class UnaryOperation>
19+
BOOST_CXX14_CONSTEXPR TInit iterate(OutputIterator first, OutputIterator last,
20+
TInit init,
21+
UnaryOperation op) // TODO: BOOST_NOEXCEPT?
22+
{
23+
for (; first != last; ++first, init = op(std::move(init))) {
24+
*first = init;
25+
}
26+
return init;
27+
}
28+
29+
template <class OutputIterator, class Size, class TInit, class UnaryOperation>
30+
BOOST_CXX14_CONSTEXPR std::pair<OutputIterator, TInit>
31+
iterate(OutputIterator first, Size n, TInit init,
32+
UnaryOperation op) // TODO: BOOST_NOEXCEPT?
33+
{
34+
for (; n > 0; n -= 1, ++first, init = op(std::move(init))) {
35+
*first = init;
36+
}
37+
return std::make_pair(std::move(first), std::move(init));
38+
}
39+
40+
} // namespace algorithm
41+
} // namespace boost
42+
43+
#endif // BOOST_ALGORITHM_ITERATE_HPP

test/Jamfile.v2

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ alias unit_test_framework
9090
# Find tests
9191
[ run find_not_test.cpp unit_test_framework : : : : find_not_test ]
9292
[ run find_backward_test.cpp unit_test_framework : : : : find_backward_test ]
93+
# Iterate tests
94+
[ run iterate_test.cpp unit_test_framework : : : : iterate_test ]
9395
;
9496
}
9597

test/iterate_test.cpp

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
Copyright (c) Jonathan Gopel 2022.
3+
4+
Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
*/
7+
8+
#include <boost/algorithm/iterate.hpp>
9+
10+
#include <boost/config.hpp>
11+
12+
#define BOOST_TEST_MAIN
13+
#include <boost/test/unit_test.hpp>
14+
15+
#include <boost/algorithm/cxx14/equal.hpp>
16+
17+
#include <algorithm>
18+
#include <array>
19+
#include <functional>
20+
21+
using data_t = int;
22+
23+
static const int NUM_ELEMENTS = 4;
24+
25+
void test_iterate() {
26+
{ // iota
27+
std::array<data_t, NUM_ELEMENTS> actual{};
28+
29+
boost::algorithm::iterate(
30+
std::begin(actual), std::end(actual), 15,
31+
[](const data_t value) -> data_t { return value + 1; });
32+
33+
std::array<data_t, NUM_ELEMENTS> expected{15, 16, 17, 18};
34+
BOOST_CHECK(std::size(actual) == std::size(expected));
35+
BOOST_CHECK(
36+
std::equal(std::begin(actual), std::end(actual), std::begin(expected)));
37+
}
38+
{ // striding
39+
std::array<data_t, NUM_ELEMENTS> actual{};
40+
41+
boost::algorithm::iterate(
42+
std::begin(actual), std::end(actual), 15,
43+
[](const data_t value) -> data_t { return value + 2; });
44+
45+
std::array<data_t, NUM_ELEMENTS> expected{15, 17, 19, 21};
46+
BOOST_CHECK(std::size(actual) == std::size(expected));
47+
BOOST_CHECK(
48+
std::equal(std::begin(actual), std::end(actual), std::begin(expected)));
49+
}
50+
}
51+
52+
void test_iterate_n() {
53+
{ // iota
54+
std::array<data_t, NUM_ELEMENTS> actual{};
55+
56+
boost::algorithm::iterate(
57+
std::begin(actual), std::size(actual), 15,
58+
[](const data_t value) -> data_t { return value + 1; });
59+
60+
std::array<data_t, NUM_ELEMENTS> expected{15, 16, 17, 18};
61+
BOOST_CHECK(std::size(actual) == std::size(expected));
62+
BOOST_CHECK(
63+
std::equal(std::begin(actual), std::end(actual), std::begin(expected)));
64+
}
65+
{ // striding
66+
std::array<data_t, NUM_ELEMENTS> actual{};
67+
68+
boost::algorithm::iterate(
69+
std::begin(actual), std::size(actual), 15,
70+
[](const data_t value) -> data_t { return value + 2; });
71+
72+
std::array<data_t, NUM_ELEMENTS> expected{15, 17, 19, 21};
73+
BOOST_CHECK(std::size(actual) == std::size(expected));
74+
BOOST_CHECK(
75+
std::equal(std::begin(actual), std::end(actual), std::begin(expected)));
76+
}
77+
}
78+
79+
BOOST_CXX14_CONSTEXPR inline bool constexpr_test_iterate() {
80+
std::array<data_t, NUM_ELEMENTS> actual{};
81+
82+
boost::algorithm::iterate(
83+
std::begin(actual), std::end(actual), 15,
84+
[](const data_t value) -> data_t { return value + 1; });
85+
86+
std::array<data_t, NUM_ELEMENTS> expected{15, 16, 17, 18};
87+
return (std::size(actual) == std::size(expected)) and
88+
boost::algorithm::equal(std::begin(actual), std::end(actual),
89+
std::begin(expected), std::end(expected));
90+
}
91+
92+
BOOST_CXX14_CONSTEXPR inline bool constexpr_test_iterate_n() {
93+
std::array<data_t, NUM_ELEMENTS> actual{};
94+
95+
boost::algorithm::iterate(
96+
std::begin(actual), std::size(actual), 15,
97+
[](const data_t value) -> data_t { return value + 1; });
98+
99+
std::array<data_t, NUM_ELEMENTS> expected{15, 16, 17, 18};
100+
return (std::size(actual) == std::size(expected)) and
101+
boost::algorithm::equal(std::begin(actual), std::end(actual),
102+
std::begin(expected), std::end(expected));
103+
}
104+
105+
BOOST_AUTO_TEST_CASE(test_main) {
106+
test_iterate();
107+
test_iterate_n();
108+
109+
{
110+
BOOST_CXX14_CONSTEXPR bool result = constexpr_test_iterate();
111+
BOOST_CHECK(result);
112+
}
113+
114+
{
115+
BOOST_CXX14_CONSTEXPR bool result = constexpr_test_iterate_n();
116+
BOOST_CHECK(result);
117+
}
118+
}

0 commit comments

Comments
 (0)