kblib 0.2.3
General utilities library for modern C++
algorithm.cpp
Go to the documentation of this file.
1#include "kblib/algorithm.h"
2#include "catch/catch.hpp"
3
4#include <set>
5#include <string>
6#include <vector>
7
8TEST_CASE("erase") {
9 const auto equal = [](auto a, auto b) {
10 return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b));
11 };
12 SECTION("erase and erase_if") {
13 const std::vector<unsigned> erase_test{2, 2, 3, 4, 5, 7, 8, 11};
14 const std::vector<unsigned> no_2s = {3, 4, 5, 7, 8, 11};
15 auto erase_copy = erase_test;
16 kblib::erase(erase_copy, 2);
17 CHECK(equal(no_2s, erase_copy));
18 erase_copy = erase_test;
19 const std::vector<unsigned> no_evens = {3, 5, 7, 11};
20 kblib::erase_if(erase_copy, [](unsigned x) { return (~x) & 1u; });
21 CHECK(equal(no_evens, erase_copy));
22 }
23}
24
25TEST_CASE("find family") {
26 // 0 1 2 3 4 5 6 7 8 9 e
27 int vec[] = {0, 3, 4, 5, 6, 1, 2, 4, 4, 5};
28 auto begin = std::begin(vec);
29 auto end = std::end(vec);
30 CHECK(kblib::find(begin, end, 4) == begin + 2);
31 CHECK(kblib::find(begin, end, 10) == end);
32 CHECK(kblib::find(begin, end, 0) == begin);
33 CHECK(kblib::find(begin, end, 10) == end);
34
35 CHECK(kblib::find_last(begin, end, 10) == end);
36 CHECK(kblib::find_last(begin, end, 0) == begin);
37 CHECK(kblib::find_last(begin, end, 4) == begin + 8);
38
39 CHECK(kblib::find_if(begin, end, [](int i) { return i == 2; }) == begin + 6);
40 CHECK(kblib::find_if_not(begin, end, [](int i) { return i == 2; }) == begin);
41 CHECK(kblib::find_if(begin, end, [](int) { return false; }) == end);
42 CHECK(kblib::find_if_not(begin, end, [](int) { return true; }) == end);
43
44 CHECK(kblib::find_last_if(begin, end, [](int i) { return i == 2; })
45 == begin + 6);
46 CHECK(kblib::find_last_if_not(begin, end, [](int i) { return i == 2; })
47 == begin + 9);
48 CHECK(kblib::find_last_if(begin, end, [](int) { return false; }) == end);
49 CHECK(kblib::find_last_if_not(begin, end, [](int) { return true; }) == end);
50
51 CHECK(kblib::contains(vec, 0));
52 CHECK(kblib::contains(vec, 1));
53 CHECK(kblib::contains(vec, 2));
54 CHECK(kblib::contains(vec, 3));
55 CHECK(kblib::contains(vec, 4));
56 CHECK(kblib::contains(vec, 5));
57 CHECK(kblib::contains(vec, 6));
58 CHECK(not kblib::contains(vec, 7));
59 CHECK(not kblib::contains(vec, 8));
60 CHECK(not kblib::contains(vec, -1));
61
62 CHECK(kblib::contains_any(vec, vec));
63 int none[] = {7, 8, -1};
64 CHECK(not kblib::contains_any(vec, none));
65}
66TEST_CASE("find_in") {
67 // 0 1 2 3 4 5 6 7 8 9 e
68 int vec[] = {0, 3, 4, 5, 6, 1, 2, 4, 4, 5};
69 auto begin = std::begin(vec);
70 auto end = std::end(vec);
71 auto size = kblib::fakestd::size(vec);
72 CHECK(kblib::find_in(begin, end, 4) == 2);
73 CHECK(kblib::find_in(begin, end, 10) == size);
74 CHECK(kblib::find_in(begin, end, 0) == 0);
75 CHECK(kblib::find_in(begin, end, 10) == size);
76
77 CHECK(kblib::find_last_in(begin, end, 10) == size);
78 CHECK(kblib::find_last_in(begin, end, 0) == 0);
79 CHECK(kblib::find_last_in(begin, end, 4) == 8);
80
81 CHECK(kblib::find_in_if(begin, end, [](int i) { return i == 2; }) == 6);
82 CHECK(kblib::find_in_if_not(begin, end, [](int i) { return i == 2; }) == 0);
83 CHECK(kblib::find_in_if(begin, end, [](int) { return false; }) == size);
84 CHECK(kblib::find_in_if_not(begin, end, [](int) { return true; }) == size);
85
86 CHECK(kblib::find_last_in_if(begin, end, [](int i) { return i == 2; }) == 6);
87 CHECK(kblib::find_last_in_if_not(begin, end, [](int i) { return i == 2; })
88 == 9);
89 CHECK(kblib::find_last_in_if(begin, end, [](int) { return false; }) == size);
90 CHECK(kblib::find_last_in_if_not(begin, end, [](int) { return true; })
91 == size);
92}
93
94TEST_CASE("search_replace") {
95 using namespace std::literals;
96 using std::begin;
97 using std::end;
98 SECTION("search_replace_copy_1") {
99 const auto haystack = "a string with words"s;
100 const auto needle = "with"s;
101 const auto replace = "comprising"s;
102 std::string result;
103 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
104 end(needle), begin(replace), end(replace),
105 std::back_inserter(result));
106 CHECK(result == "a string comprising words");
107 }
108 SECTION("search_replace_copy_2(no match)") {
109 const auto haystack = "a string with words"s;
110 const auto needle = "without"s;
111 const auto replace = "comprising"s;
112 std::string result;
113 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
114 end(needle), begin(replace), end(replace),
115 std::back_inserter(result));
116 CHECK(result == haystack);
117 }
118 SECTION("search_replace_copy_3(multiple matches)") {
119 const auto haystack = "a string with multiple 'with's"s;
120 const auto needle = "with"s;
121 const auto replace = "containing"s;
122 std::string result;
123 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
124 end(needle), begin(replace), end(replace),
125 std::back_inserter(result));
126 CHECK(result == "a string containing multiple 'containing's");
127 }
128 SECTION("search_replace_copy_4(empty match)") {
129 const auto haystack = "a string with words"s;
130 const auto needle = ""s;
131 const auto replace = "comprising"s;
132 std::string result;
133 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
134 end(needle), begin(replace), end(replace),
135 std::back_inserter(result));
136 CHECK(result == haystack);
137 }
138 SECTION("search_replace_copy_5(match at beginning)") {
139 const auto haystack = "a string with words"s;
140 const auto needle = "a"s;
141 const auto replace = "another"s;
142 std::string result;
143 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
144 end(needle), begin(replace), end(replace),
145 std::back_inserter(result));
146 CHECK(result == "another string with words");
147 }
148 SECTION("search_replace_copy_6(match at end)") {
149 const auto haystack = "a string with words"s;
150 const auto needle = "words"s;
151 const auto replace = "letters"s;
152 std::string result;
153 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
154 end(needle), begin(replace), end(replace),
155 std::back_inserter(result));
156 CHECK(result == "a string with letters");
157 }
158 SECTION("search_replace_copy_7(only matches)") {
159 const auto haystack = "abababababab"s;
160 const auto needle = "ab"s;
161 const auto replace = "ba"s;
162 std::string result;
163 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
164 end(needle), begin(replace), end(replace),
165 std::back_inserter(result));
166 CHECK(result == "babababababa");
167 }
168 SECTION("search_replace_copy_8(match is whole string)") {
169 const auto haystack = "string"s;
170 const auto& needle = haystack;
171 const auto replace = "replace"s;
172 std::string result;
173 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
174 end(needle), begin(replace), end(replace),
175 std::back_inserter(result));
176 CHECK(result == replace);
177 }
178 SECTION("search_replace_copy_9(overlap)") {
179 const auto haystack = "abcabcab"s;
180 const auto needle = "abcab"s;
181 const auto replace = "a"s;
182 std::string result;
183 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
184 end(needle), begin(replace), end(replace),
185 std::back_inserter(result));
186 CHECK(result == "acab");
187 }
188}
189
190TEST_CASE("get_max family") {
192 std::array<int, 11> arr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
193 {
194 auto max_two
195 = kblib::get_max_n_old<std::vector<int>>(arr.begin(), arr.end(), 2);
196 CHECK(max_two.size() == 2);
197 CHECK(std::max(max_two[0], max_two[1]) == 10);
198 CHECK(std::min(max_two[0], max_two[1]) == 9);
199 }
200 {
201 auto max_two
202 = kblib::get_max_n_old<std::set<int>>(arr.begin(), arr.end(), 2);
203 CHECK(max_two.size() == 2);
204 CHECK(max_two.find(10) != max_two.end());
205 CHECK(max_two.find(9) != max_two.end());
206 }
207 {
208 auto max_two
209 = kblib::get_max_n<std::vector<int>>(arr.begin(), arr.end(), 2);
210 CHECK(max_two.size() == 2);
211 CHECK(std::max(max_two[0], max_two[1]) == 10);
212 CHECK(std::min(max_two[0], max_two[1]) == 9);
213 }
214 {
215 auto max_two = kblib::get_max_n<std::set<int>>(arr.begin(), arr.end(), 2);
216 CHECK(max_two.size() == 2);
217 CHECK(max_two.find(10) != max_two.end());
218 CHECK(max_two.find(9) != max_two.end());
219 }
220}
221
222TEST_CASE("general algorithms") {
224}
225
226TEST_CASE("assorted algorithms") {
227 auto equal = [](auto r1, auto r2) {
228 auto r1b = r1.begin();
229 auto r1e = r1.end();
230 auto r2b = r2.begin();
231 auto r2e = r2.end();
232 return (std::distance(r1b, r1e) == std::distance(r2b, r2e))
233 and kblib::equal(r1b, r1e, r2b);
234 };
235 std::array<int, 10> haystack{1, 1, 2, 5, 6, 2, 4, 7, 0, 6};
236 const int N = 5;
237 std::array<int, N> maxN_target{7, 6, 6, 5, 4};
238
239 CHECK(equal(maxN_target, kblib::get_max_n<std::vector<int>>(
240 haystack.begin(), haystack.end(), N)));
241 std::vector<int> maxN_copy;
242 kblib::get_max_n(haystack.begin(), haystack.end(),
243 std::back_inserter(maxN_copy), 5);
244 CHECK(equal(maxN_target, maxN_copy));
245
246 CHECK(
247 equal(maxN_target, kblib::get_max_n<std::multiset<int, std::greater<>>>(
248 haystack.begin(), haystack.end(), N)));
249
250 std::vector<int> maxN_psc(N);
251 std::partial_sort_copy(haystack.begin(), haystack.end(), maxN_psc.begin(),
252 maxN_psc.end(), std::greater<>{});
253 CHECK(equal(maxN_target, maxN_psc));
254
255 // SFINAE prevents get_max_n from being called with invalid arguments,
256 // even though count has moved from third to fourth on this overload.
257 // It will also fail when the output range is not assignable.
258
259 // kblib::get_max_n(haystack.begin(), haystack.end(), maxN.cbegin(),
260 // 1); kblib::get_max_n(haystack.begin(), haystack.end(), 1,
261 // maxN.begin());
262
263 auto range = kblib::range(0, 50, 3);
264 CHECK(equal(range, std::vector<int>{0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30,
265 33, 36, 39, 42, 45, 48}));
266 auto maxN_range
267 = kblib::get_max_n<std::vector<int>>(range.begin(), range.end(), 5);
268 CHECK(maxN_range == std::vector<int>{48, 45, 42, 39, 36});
269}
270
271TEST_CASE("zip") {
272 SECTION("non-overlapping") {
273 std::vector<int> input1{1, 2, 3, 4, 5, 6};
274 std::vector<short> input2{2, 3, 4, 5, 6, 7};
275
276 for (auto t : kblib::zip(input1.begin(), input1.end(), input2.begin())) {
277 auto& a = std::get<0>(t);
278 auto& b = std::get<1>(t);
279 CHECK(a + 1 == b);
280 }
281 }
282 SECTION("identical") {
283 std::vector<int> input{1, 2, 3, 4, 5, 6, 7, 8};
284 for (auto t : kblib::zip(input.begin(), input.end(), input.begin())) {
285 auto& a = std::get<0>(t);
286 auto& b = std::get<1>(t);
287 CHECK(&a == &b);
288 }
289 }
290 SECTION("overlapping") {
291 std::vector<int> input{1, 2, 3, 4, 5, 6, 7, 8};
292 for (auto t :
293 kblib::zip(input.begin(), input.end() - 1, input.begin() + 1)) {
294 auto& a = std::get<0>(t);
295 auto& b = std::get<1>(t);
296 CHECK(a + 1 == b);
297 }
298 }
299}
TEST_CASE("erase")
Definition: algorithm.cpp:8
Provides general-purpose algorithms, similar to the <algorithms> header.
#define CHECK(...)
Definition: catch.hpp:17687
#define SECTION(...)
Definition: catch.hpp:17716
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:383
constexpr struct kblib::nums::min_t min
constexpr struct kblib::nums::max_t max
constexpr auto contains(InputIt begin, InputIt end, const Value &val) noexcept(noexcept(*begin==val)) -> enable_if_t< is_input_iterator< InputIt >::value, bool >
Determine if a range contains a value.
Definition: algorithm.h:1052
auto zip(InputIt1 begin1, EndIt end1, InputIt2 begin2) noexcept(zip_iterator< InputIt1, EndIt, InputIt2 >::is_nothrow_copyable) -> zip_iterator< InputIt1, EndIt, InputIt2 >
Iterate over two ranges in lockstep, like Python's zip.
Definition: iterators.h:1454
constexpr auto find_in_if_not(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> size_t
Find the offset of the first element for which p returns false. It also allows for a sentinel end ite...
Definition: algorithm.h:490
constexpr auto find_last_if_not(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> ForwardIt
Searches a range for the last element on which a predicate returns false. It also allows for a sentin...
Definition: algorithm.h:427
constexpr auto a(const std::initializer_list< T > &a) -> auto
Index an array literal without naming its type.
Definition: simple.h:256
constexpr auto find_last_in_if(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> size_t
Definition: algorithm.h:525
constexpr auto find_if(ForwardIt begin, EndIt end, UnaryPredicate &&pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> ForwardIt
Finds the first value in range [begin, end) for which pred returns true. If not found,...
Definition: algorithm.h:327
constexpr auto find_in(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> size_t
Find the offset of the first ocurrence of v in a range from the beginning. It also allows for a senti...
Definition: algorithm.h:458
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
Definition: iterators.h:621
constexpr auto get_max_n(It first, It last, std::size_t count, Comp cmp={}) -> SequenceContainer
Returns a container of the greatest count elements according to cmp of the range [first,...
Definition: algorithm.h:1203
constexpr auto contains_any(InputIt1 begin, InputIt1 end, InputIt2 n_begin, InputIt2 n_end) -> enable_if_t< is_input_iterator< InputIt1 >::value and is_input_iterator< InputIt2 >::value, bool >
Definition: algorithm.h:1076
constexpr auto find_last(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> ForwardIt
Searches a range for the last occurence of a match, and returns an iterator to it....
Definition: algorithm.h:366
constexpr auto find_last_in_if_not(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> size_t
Find the offset of the last element for which p returns false. It also allows for a sentinel end iter...
Definition: algorithm.h:541
constexpr auto erase_if(Container &c, UnaryPredicate p) noexcept(noexcept(c.erase(std::remove_if(c.begin(), c.end(), std::ref(p)), c.end()))) -> void
Abbreviation of the erase-remove idiom as a free function.
Definition: algorithm.h:81
constexpr auto erase(Container &c, const Elem &val) noexcept(noexcept(c.erase(std::remove(c.begin(), c.end(), val), c.end()))) -> void
Abbreviation of the erase-remove idiom as a free function.
Definition: algorithm.h:68
constexpr auto find(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> ForwardIt
Finds a value in range [begin, end). If not found, returns end. It also allows for a sentinel end ite...
Definition: algorithm.h:290
constexpr auto search_replace_copy(ForwardIt1 h_begin, ForwardIt1 h_end, ForwardIt2 n_begin, ForwardIt2 n_end, ForwardIt3 r_begin, ForwardIt3 r_end, OutputIt d_begin, BinaryPredicate Compare={}) -> OutputIt
Definition: algorithm.h:1462
constexpr auto find_if_not(ForwardIt begin, EndIt end, UnaryPredicate &&pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> ForwardIt
Finds the first value in range [begin, end) for which pred returns false. If not found,...
Definition: algorithm.h:346
constexpr auto find_last_in(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> size_t
Find the offset of the last ocurrence of v in a range from the beginning. It also allows for a sentin...
Definition: algorithm.h:510
constexpr auto find_in_if(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> size_t
Find the offset of the first element for which p returns true. It also allows for a sentinel end iter...
Definition: algorithm.h:474
constexpr auto equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) -> bool
Definition: fakestd.h:982
constexpr auto find_last_if(ForwardIt begin, EndIt end, UnaryPredicate pred) noexcept(noexcept(kblib::invoke(pred, *begin))) -> ForwardIt
Searches a range for the last element on which a predicate returns true. It also allows for a sentine...
Definition: algorithm.h:396