HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
algorithm.hpp
1// Copyright Take Vos 2019-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "utility/module.hpp"
8#include <algorithm>
9#include <tuple>
10#include <cmath>
11#include <iterator>
12
13namespace hi::inline v1 {
14
20template<typename T, typename U, typename F>
21inline T transform(const U& input, F operation)
22{
23 T result = {};
24 result.reserve(input.size());
25 std::transform(input.begin(), input.end(), std::back_inserter(result), operation);
26 return result;
27}
28
34template<typename T, std::size_t N, typename F>
35constexpr std::array<T, N> generate_array(F operation)
36{
38
39 for (std::size_t i = 0; i < N; i++) {
40 a.at(i) = operation(i);
41 }
42
43 return a;
44}
45
55template<typename It>
56constexpr It unordered_remove(It first, It last, It element)
57{
58 hi_axiom(first != last);
59
60 using std::swap;
61
62 auto new_last = last - 1;
63 swap(*element, *new_last);
64 return new_last;
65}
66
67template<typename It, typename UnaryPredicate>
68constexpr It rfind_if(It const first, It const last, UnaryPredicate predicate)
69{
70 auto i = last;
71 do {
72 i--;
73 if (predicate(*i)) {
74 return i;
75 }
76 } while (i != first);
77 return last;
78}
79
80template<typename It, typename UnaryPredicate>
81constexpr It rfind_if_not(It const first, It const last, UnaryPredicate predicate)
82{
83 return rfind_if(first, last, [&](hilet& x) {
84 return !predicate(x);
85 });
86}
87
88template<typename It, typename T>
89constexpr It rfind(It const first, It const last, T const& value)
90{
91 return rfind_if(first, last, [&](hilet& x) {
92 return x == value;
93 });
94}
95
103template<typename It, typename ItAny>
104[[nodiscard]] constexpr It find_any(It data_first, It data_last, ItAny value_first, ItAny value_last) noexcept
105{
106 return std::find_if(data_first, data_last, [value_first, value_last](hilet& data) {
107 return std::any_of(value_first, value_last, [&data](hilet& value) {
108 return data == value;
109 });
110 });
111}
112
119template<typename ConstIt, typename It, typename UnaryPredicate>
120constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
121{
122 hilet cluster_id = predicate(*start);
123
124 for (auto i = start + 1; i != last; ++i) {
125 if (predicate(*i) != cluster_id) {
126 return i;
127 }
128 }
129 return last;
130}
131
138template<typename ConstIt, typename It, typename UnaryPredicate>
139constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
140{
141 hilet cluster_id = predicate(*start);
142
143 if (start == first) {
144 return first;
145 }
146
147 auto i = start - 1;
148 while (true) {
149 if (predicate(*i) != cluster_id) {
150 return (i + 1);
151 }
152
153 if (i == first) {
154 return i;
155 }
156 --i;
157 }
158 hi_unreachable();
159}
160
168template<typename ConstIt, typename It, typename UnaryPredicate>
169constexpr std::pair<It, It> bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
170{
171 return {rfind_cluster(first, start, predicate), find_cluster(last, start, predicate)};
172}
173
174template<typename InputIt1, typename InputIt2, typename BinaryPredicate>
176rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate) noexcept
177{
178 auto i1 = last1;
179 auto i2 = last2;
180
181 while (true) {
182 if (i1 == first1 && i2 == first2) {
183 return {last1, last2};
184 } else if (i1 == first1) {
185 return {last1, --i2};
186 } else if (i2 == first2) {
187 return {--i1, last2};
188 }
189
190 if (!predicate(*(--i1), *(--i2))) {
191 return {i1, i2};
192 }
193 }
194}
195
196template<typename InputIt1, typename InputIt2>
197inline std::pair<InputIt1, InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) noexcept
198{
199 return rmismatch(first1, last1, first2, last2, [&](auto a, auto b) {
200 return a == b;
201 });
202}
203
204template<typename T>
205T smoothstep(T x) noexcept
206{
207 x = std::clamp(x, T{0.0}, T{1.0});
208 return x * x * (3 - 2 * x);
209}
210
211template<typename T>
212T inverse_smoothstep(T x)
213{
214 return T{0.5} - std::sin(std::asin(T{1.0} - T{2.0} * x) / T{3.0});
215}
216
232auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
233{
234 std::size_t src_size = std::distance(first, last);
235
236 // Keep track of index locations during shuffling of items.
237 auto src_indices = std::vector<std::size_t>{};
238 src_indices.reserve(src_size);
239 for (std::size_t i = 0; i != src_size; ++i) {
240 src_indices.push_back(i);
241 }
242
243 std::size_t dst = 0;
244 for (auto it = indices_first; it != indices_last; ++it, ++dst) {
245 hilet index = index_op(*it);
246 hi_assert_bounds(index, src_indices);
247
248 auto src = [&src_indices, index]() {
249 auto src = index;
250 do {
251 src = src_indices[src];
252 } while (src_indices[src] != index);
253 return src;
254 }();
255
256 if (src != dst) {
257 std::iter_swap(first + src, first + dst);
258 std::iter_swap(begin(src_indices) + src, begin(src_indices) + dst);
259 }
260 }
261
262 return first + dst;
263}
264
278auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last) noexcept
279{
280 return shuffle_by_index(first, last, indices_first, indices_last, [](hilet& x) {
281 return narrow_cast<std::size_t>(x);
282 });
283}
284
293template<typename DataIt, typename ValueIt>
294DataIt front_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
295{
296 for (auto it = data_first; it != data_last; ++it) {
297 if (std::find(value_first, value_last, *it) == value_last) {
298 // Return the iterator pointing to the data that is not part of the value set.
299 return it;
300 }
301 }
302
303 return data_last;
304}
305
314template<typename DataIt, typename ValueIt>
315DataIt back_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
316{
317 auto it = data_last;
318 while (it != data_first) {
319 if (std::find(value_first, value_last, *(--it)) == value_last) {
320 // Return an iterator one beyond the data that is not part of the value set.
321 return it + 1;
322 }
323 }
324
325 return data_first;
326}
327
337template<std::endian Endian = std::endian::native, typename T, std::unsigned_integral Key>
338[[nodiscard]] constexpr T *fast_lower_bound(std::span<T> table, Key const& key) noexcept
339{
340 auto base = table.data();
341 auto len = table.size();
342
343 // A faster lower-bound search with less branches that are more predictable.
344 while (len > 1) {
345 hi_axiom_not_null(base);
346
347 hilet half = len / 2;
348
349 if (load<Key, Endian>(base + half - 1) < key) {
350 base += half;
351 }
352 len -= half;
353 }
354 if (load<Key, Endian>(base) < key) {
355 return nullptr;
356 }
357 return base;
358}
359
362template<std::endian Endian = std::endian::native, typename T, std::unsigned_integral Key>
363[[nodiscard]] constexpr T *fast_binary_search_eq(std::span<T> table, Key const& key) noexcept
364{
365 hilet ptr = fast_lower_bound<Endian>(table, key);
366 if (ptr == nullptr) {
367 return nullptr;
368 }
369
370 if (load<Key, Endian>(ptr) != key) {
371 return nullptr;
372 }
373
374 return ptr;
375}
376
377} // namespace hi::inline v1
#define hi_assert_bounds(x,...)
Assert if a value is within bounds.
Definition assert.hpp:225
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:272
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
constexpr It find_any(It data_first, It data_last, ItAny value_first, ItAny value_last) noexcept
Find the first occurrence of an value in a data.
Definition algorithm.hpp:104
auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
Shuffle a container based on a list of indices.
Definition algorithm.hpp:232
DataIt front_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
Strip data from the front side.
Definition algorithm.hpp:294
constexpr It unordered_remove(It first, It last, It element)
Remove element from a container.
Definition algorithm.hpp:56
constexpr std::pair< It, It > bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
Find the begin and end of the current cluster.
Definition algorithm.hpp:169
constexpr T * fast_lower_bound(std::span< T > table, Key const &key) noexcept
The fast lower bound algorithm.
Definition algorithm.hpp:338
constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:139
constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:120
DataIt back_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
Strip data from the back side.
Definition algorithm.hpp:315
constexpr T * fast_binary_search_eq(std::span< T > table, Key const &key) noexcept
Search for the item that is equal to the key.
Definition algorithm.hpp:363
constexpr std::array< T, N > generate_array(F operation)
Generate data in an array.
Definition algorithm.hpp:35
T any_of(T... args)
T asin(T... args)
T at(T... args)
T back_inserter(T... args)
T distance(T... args)
T find_if(T... args)
T iter_swap(T... args)
T reserve(T... args)
T sin(T... args)
T swap(T... args)
T transform(T... args)