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.hpp"
3
4#include <iostream>
5#include <set>
6#include <string>
7#include <vector>
8
9TEST_CASE("erase") {
10 const auto equal = [](auto a, auto b) {
11 return std::equal(std::begin(a), std::end(a), std::begin(b), std::end(b));
12 };
13 SECTION("erase and erase_if") {
14 const std::vector<unsigned> erase_test{2, 2, 3, 4, 5, 7, 8, 11};
15 const std::vector<unsigned> no_2s = {3, 4, 5, 7, 8, 11};
16 auto erase_copy = erase_test;
17 kblib::erase(erase_copy, 2);
18 CHECK(equal(no_2s, erase_copy));
19 erase_copy = erase_test;
20 const std::vector<unsigned> no_evens = {3, 5, 7, 11};
21 kblib::erase_if(erase_copy, [](unsigned x) { return (~x) & 1u; });
22 CHECK(equal(no_evens, erase_copy));
23 }
24}
25
26TEST_CASE("find family") {
27 // 0 1 2 3 4 5 6 7 8 9 e
28 int vec[] = {0, 3, 4, 5, 6, 1, 2, 4, 4, 5};
29 auto begin = std::begin(vec);
30 auto end = std::end(vec);
31 CHECK(kblib::find(begin, end, 4) == begin + 2);
32 CHECK(kblib::find(begin, end, 10) == end);
33 CHECK(kblib::find(begin, end, 0) == begin);
34 CHECK(kblib::find(begin, end, 10) == end);
35
36 CHECK(kblib::find_last(begin, end, 10) == end);
37 CHECK(kblib::find_last(begin, end, 0) == begin);
38 CHECK(kblib::find_last(begin, end, 4) == begin + 8);
39
40 CHECK(kblib::find_if(begin, end, [](int i) { return i == 2; }) == begin + 6);
41 CHECK(kblib::find_if_not(begin, end, [](int i) { return i == 2; }) == begin);
42 CHECK(kblib::find_if(begin, end, [](int) { return false; }) == end);
43 CHECK(kblib::find_if_not(begin, end, [](int) { return true; }) == end);
44
45 CHECK(kblib::find_last_if(begin, end, [](int i) { return i == 2; })
46 == begin + 6);
47 CHECK(kblib::find_last_if_not(begin, end, [](int i) { return i == 2; })
48 == begin + 9);
49 CHECK(kblib::find_last_if(begin, end, [](int) { return false; }) == end);
50 CHECK(kblib::find_last_if_not(begin, end, [](int) { return true; }) == end);
51
52 CHECK(kblib::contains(vec, 0));
53 CHECK(kblib::contains(vec, 1));
54 CHECK(kblib::contains(vec, 2));
55 CHECK(kblib::contains(vec, 3));
56 CHECK(kblib::contains(vec, 4));
57 CHECK(kblib::contains(vec, 5));
58 CHECK(kblib::contains(vec, 6));
59 CHECK(not kblib::contains(vec, 7));
60 CHECK(not kblib::contains(vec, 8));
61 CHECK(not kblib::contains(vec, -1));
62
63 CHECK(kblib::contains_any(vec, vec));
64 int none[] = {7, 8, -1};
65 CHECK(not kblib::contains_any(vec, none));
66}
67TEST_CASE("find_in") {
68 // 0 1 2 3 4 5 6 7 8 9 e
69 int vec[] = {0, 3, 4, 5, 6, 1, 2, 4, 4, 5};
70 auto begin = std::begin(vec);
71 auto end = std::end(vec);
72 auto size = kblib::fakestd::size(vec);
73 CHECK(kblib::find_in(begin, end, 4) == 2);
74 CHECK(kblib::find_in(begin, end, 10) == size);
75 CHECK(kblib::find_in(begin, end, 0) == 0);
76 CHECK(kblib::find_in(begin, end, 10) == size);
77
78 CHECK(kblib::find_last_in(begin, end, 10) == size);
79 CHECK(kblib::find_last_in(begin, end, 0) == 0);
80 CHECK(kblib::find_last_in(begin, end, 4) == 8);
81
82 CHECK(kblib::find_in_if(begin, end, [](int i) { return i == 2; }) == 6);
83 CHECK(kblib::find_in_if_not(begin, end, [](int i) { return i == 2; }) == 0);
84 CHECK(kblib::find_in_if(begin, end, [](int) { return false; }) == size);
85 CHECK(kblib::find_in_if_not(begin, end, [](int) { return true; }) == size);
86
87 CHECK(kblib::find_last_in_if(begin, end, [](int i) { return i == 2; }) == 6);
88 CHECK(kblib::find_last_in_if_not(begin, end, [](int i) { return i == 2; })
89 == 9);
90 CHECK(kblib::find_last_in_if(begin, end, [](int) { return false; }) == size);
91 CHECK(kblib::find_last_in_if_not(begin, end, [](int) { return true; })
92 == size);
93}
94
95TEST_CASE("search_replace") {
96 using namespace std::literals;
97 using std::begin;
98 using std::end;
99 SECTION("search_replace_copy_1") {
100 const auto haystack = "a string with words"s;
101 const auto needle = "with"s;
102 const auto replace = "comprising"s;
103 std::string result;
104 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
105 end(needle), begin(replace), end(replace),
106 std::back_inserter(result));
107 CHECK(result == "a string comprising words");
108 }
109 SECTION("search_replace_copy_2(no match)") {
110 const auto haystack = "a string with words"s;
111 const auto needle = "without"s;
112 const auto replace = "comprising"s;
113 std::string result;
114 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
115 end(needle), begin(replace), end(replace),
116 std::back_inserter(result));
117 CHECK(result == haystack);
118 }
119 SECTION("search_replace_copy_3(multiple matches)") {
120 const auto haystack = "a string with multiple 'with's"s;
121 const auto needle = "with"s;
122 const auto replace = "containing"s;
123 std::string result;
124 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
125 end(needle), begin(replace), end(replace),
126 std::back_inserter(result));
127 CHECK(result == "a string containing multiple 'containing's");
128 }
129 SECTION("search_replace_copy_4(empty match)") {
130 const auto haystack = "a string with words"s;
131 const auto needle = ""s;
132 const auto replace = "comprising"s;
133 std::string result;
134 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
135 end(needle), begin(replace), end(replace),
136 std::back_inserter(result));
137 CHECK(result == haystack);
138 }
139 SECTION("search_replace_copy_5(match at beginning)") {
140 const auto haystack = "a string with words"s;
141 const auto needle = "a"s;
142 const auto replace = "another"s;
143 std::string result;
144 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
145 end(needle), begin(replace), end(replace),
146 std::back_inserter(result));
147 CHECK(result == "another string with words");
148 }
149 SECTION("search_replace_copy_6(match at end)") {
150 const auto haystack = "a string with words"s;
151 const auto needle = "words"s;
152 const auto replace = "letters"s;
153 std::string result;
154 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
155 end(needle), begin(replace), end(replace),
156 std::back_inserter(result));
157 CHECK(result == "a string with letters");
158 }
159 SECTION("search_replace_copy_7(only matches)") {
160 const auto haystack = "abababababab"s;
161 const auto needle = "ab"s;
162 const auto replace = "ba"s;
163 std::string result;
164 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
165 end(needle), begin(replace), end(replace),
166 std::back_inserter(result));
167 CHECK(result == "babababababa");
168 }
169 SECTION("search_replace_copy_8(match is whole string)") {
170 const auto haystack = "string"s;
171 const auto& needle = haystack;
172 const auto replace = "replace"s;
173 std::string result;
174 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
175 end(needle), begin(replace), end(replace),
176 std::back_inserter(result));
177 CHECK(result == replace);
178 }
179 SECTION("search_replace_copy_9(overlap)") {
180 const auto haystack = "abcabcab"s;
181 const auto needle = "abcab"s;
182 const auto replace = "a"s;
183 std::string result;
184 kblib::search_replace_copy(begin(haystack), end(haystack), begin(needle),
185 end(needle), begin(replace), end(replace),
186 std::back_inserter(result));
187 CHECK(result == "acab");
188 }
189}
190
191TEST_CASE("get_max family") {
193 std::array<int, 11> arr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
194 {
195 auto max_two
196 = kblib::get_max_n_old<std::vector<int>>(arr.begin(), arr.end(), 2);
197 CHECK(max_two.size() == 2);
198 CHECK(std::max(max_two[0], max_two[1]) == 10);
199 CHECK(std::min(max_two[0], max_two[1]) == 9);
200 }
201 {
202 auto max_two
203 = kblib::get_max_n_old<std::set<int>>(arr.begin(), arr.end(), 2);
204 CHECK(max_two.size() == 2);
205 CHECK(max_two.find(10) != max_two.end());
206 CHECK(max_two.find(9) != max_two.end());
207 }
208 {
209 auto max_two
210 = kblib::get_max_n<std::vector<int>>(arr.begin(), arr.end(), 2);
211 CHECK(max_two.size() == 2);
212 CHECK(std::max(max_two[0], max_two[1]) == 10);
213 CHECK(std::min(max_two[0], max_two[1]) == 9);
214 }
215 {
216 auto max_two = kblib::get_max_n<std::set<int>>(arr.begin(), arr.end(), 2);
217 CHECK(max_two.size() == 2);
218 CHECK(max_two.find(10) != max_two.end());
219 CHECK(max_two.find(9) != max_two.end());
220 }
221}
222
223TEST_CASE("general algorithms") {
225}
226
227TEST_CASE("assorted algorithms") {
228 auto equal = [](auto r1, auto r2) {
229 auto r1b = r1.begin();
230 auto r1e = r1.end();
231 auto r2b = r2.begin();
232 auto r2e = r2.end();
233 return (std::distance(r1b, r1e) == std::distance(r2b, r2e))
234 and kblib::equal(r1b, r1e, r2b);
235 };
236 std::array<int, 10> haystack{1, 1, 2, 5, 6, 2, 4, 7, 0, 6};
237 const int N = 5;
238 std::array<int, N> maxN_target{7, 6, 6, 5, 4};
239
240 CHECK(equal(maxN_target, kblib::get_max_n<std::vector<int>>(
241 haystack.begin(), haystack.end(), N)));
242 std::vector<int> maxN_copy;
243 kblib::get_max_n(haystack.begin(), haystack.end(),
244 std::back_inserter(maxN_copy), 5);
245 CHECK(equal(maxN_target, maxN_copy));
246
247 CHECK(
248 equal(maxN_target, kblib::get_max_n<std::multiset<int, std::greater<>>>(
249 haystack.begin(), haystack.end(), N)));
250
251 std::vector<int> maxN_psc(N);
252 std::partial_sort_copy(haystack.begin(), haystack.end(), maxN_psc.begin(),
253 maxN_psc.end(), std::greater<>{});
254 CHECK(equal(maxN_target, maxN_psc));
255
256 // SFINAE prevents get_max_n from being called with invalid arguments,
257 // even though count has moved from third to fourth on this overload.
258 // It will also fail when the output range is not assignable.
259
260 // kblib::get_max_n(haystack.begin(), haystack.end(), maxN.cbegin(),
261 // 1); kblib::get_max_n(haystack.begin(), haystack.end(), 1,
262 // maxN.begin());
263
264 auto range = kblib::range(0, 50, 3);
265 CHECK(equal(range, std::vector<int>{0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30,
266 33, 36, 39, 42, 45, 48}));
267 auto maxN_range
268 = kblib::get_max_n<std::vector<int>>(range.begin(), range.end(), 5);
269 CHECK(maxN_range == std::vector<int>{48, 45, 42, 39, 36});
270}
271
272TEST_CASE("zip") {
273 SECTION("non-overlapping") {
274 std::vector<int> input1{1, 2, 3, 4, 5, 6};
275 std::vector<short> input2{2, 3, 4, 5, 6, 7};
276
277 for (auto t : kblib::zip(input1.begin(), input1.end(), input2.begin())) {
278 auto& a = std::get<0>(t);
279 auto& b = std::get<1>(t);
280 CHECK(a + 1 == b);
281 }
282 }
283 SECTION("identical") {
284 std::vector<int> input{1, 2, 3, 4, 5, 6, 7, 8};
285 for (auto t : kblib::zip(input.begin(), input.end(), input.begin())) {
286 auto& a = std::get<0>(t);
287 auto& b = std::get<1>(t);
288 CHECK(&a == &b);
289 }
290 }
291 SECTION("overlapping") {
292 std::vector<int> input{1, 2, 3, 4, 5, 6, 7, 8};
293 for (auto t :
294 kblib::zip(input.begin(), input.end() - 1, input.begin() + 1)) {
295 auto& a = std::get<0>(t);
296 auto& b = std::get<1>(t);
297 CHECK(a + 1 == b);
298 }
299 }
300}
TEST_CASE("erase")
Definition: algorithm.cpp:9
Provides general-purpose algorithms, similar to the <algorithms> header.
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:373
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:255
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:966
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