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/utility.hpp"
8#include "../macros.hpp"
9#include <algorithm>
10#include <tuple>
11#include <cmath>
12#include <iterator>
13
14
15
16namespace hi::inline v1 {
17
23template<typename T, typename U, typename F>
24inline T transform(const U& input, F operation)
25{
26 T result = {};
27 result.reserve(input.size());
28 std::transform(input.begin(), input.end(), std::back_inserter(result), operation);
29 return result;
30}
31
37template<typename T, std::size_t N, typename F>
38constexpr std::array<T, N> generate_array(F operation)
39{
41
42 for (std::size_t i = 0; i < N; i++) {
43 a.at(i) = operation(i);
44 }
45
46 return a;
47}
48
58template<typename It>
59constexpr It unordered_remove(It first, It last, It element)
60{
61 hi_axiom(first != last);
62
63 using std::swap;
64
65 auto new_last = last - 1;
66 swap(*element, *new_last);
67 return new_last;
68}
69
70template<typename It, typename UnaryPredicate>
71constexpr It rfind_if(It const first, It const last, UnaryPredicate predicate)
72{
73 auto i = last;
74 do {
75 i--;
76 if (predicate(*i)) {
77 return i;
78 }
79 } while (i != first);
80 return last;
81}
82
83template<typename It, typename UnaryPredicate>
84constexpr It rfind_if_not(It const first, It const last, UnaryPredicate predicate)
85{
86 return rfind_if(first, last, [&](hilet& x) {
87 return !predicate(x);
88 });
89}
90
91template<typename It, typename T>
92constexpr It rfind(It const first, It const last, T const& value)
93{
94 return rfind_if(first, last, [&](hilet& x) {
95 return x == value;
96 });
97}
98
106template<typename It, typename ItAny>
107[[nodiscard]] constexpr It find_any(It data_first, It data_last, ItAny value_first, ItAny value_last) noexcept
108{
109 return std::find_if(data_first, data_last, [value_first, value_last](hilet& data) {
110 return std::any_of(value_first, value_last, [&data](hilet& value) {
111 return data == value;
112 });
113 });
114}
115
122template<typename ConstIt, typename It, typename UnaryPredicate>
123constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
124{
125 hilet cluster_id = predicate(*start);
126
127 for (auto i = start + 1; i != last; ++i) {
128 if (predicate(*i) != cluster_id) {
129 return i;
130 }
131 }
132 return last;
133}
134
141template<typename ConstIt, typename It, typename UnaryPredicate>
142constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
143{
144 hilet cluster_id = predicate(*start);
145
146 if (start == first) {
147 return first;
148 }
149
150 auto i = start - 1;
151 while (true) {
152 if (predicate(*i) != cluster_id) {
153 return (i + 1);
154 }
155
156 if (i == first) {
157 return i;
158 }
159 --i;
160 }
161 std::unreachable();
162}
163
171template<typename ConstIt, typename It, typename UnaryPredicate>
172constexpr std::pair<It, It> bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
173{
174 return {rfind_cluster(first, start, predicate), find_cluster(last, start, predicate)};
175}
176
182template<typename It, typename S, typename F>
183inline void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
184{
185 if (first == last) {
186 return;
187 }
188
189 // If the first item is a cluster separator skip over it.
190 if (IsClusterSeperator(*first)) {
191 first++;
192 }
193
194 for (auto i = first; i != last;) {
195 auto j = std::find_if(i, last, IsClusterSeperator);
196 Function(i, j);
197
198 auto skipOverSeperator = (j == last) ? 0 : 1;
199 i = j + skipOverSeperator;
200 }
201}
202
203template<typename InputIt1, typename InputIt2, typename BinaryPredicate>
205rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate) noexcept
206{
207 auto i1 = last1;
208 auto i2 = last2;
209
210 while (true) {
211 if (i1 == first1 && i2 == first2) {
212 return {last1, last2};
213 } else if (i1 == first1) {
214 return {last1, --i2};
215 } else if (i2 == first2) {
216 return {--i1, last2};
217 }
218
219 if (!predicate(*(--i1), *(--i2))) {
220 return {i1, i2};
221 }
222 }
223}
224
225template<typename InputIt1, typename InputIt2>
226inline std::pair<InputIt1, InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) noexcept
227{
228 return rmismatch(first1, last1, first2, last2, [&](auto a, auto b) {
229 return a == b;
230 });
231}
232
233template<typename T>
234T smoothstep(T x) noexcept
235{
236 x = std::clamp(x, T{0.0}, T{1.0});
237 return x * x * (3 - 2 * x);
238}
239
240template<typename T>
241T inverse_smoothstep(T x)
242{
243 return T{0.5} - std::sin(std::asin(T{1.0} - T{2.0} * x) / T{3.0});
244}
245
261auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
262{
263 std::size_t src_size = std::distance(first, last);
264
265 // Keep track of index locations during shuffling of items.
266 auto src_indices = std::vector<std::size_t>{};
267 src_indices.reserve(src_size);
268 for (std::size_t i = 0; i != src_size; ++i) {
269 src_indices.push_back(i);
270 }
271
272 std::size_t dst = 0;
273 for (auto it = indices_first; it != indices_last; ++it, ++dst) {
274 hilet index = index_op(*it);
275 hi_assert_bounds(index, src_indices);
276
277 auto src = [&src_indices, index]() {
278 auto src = index;
279 do {
280 src = src_indices[src];
281 } while (src_indices[src] != index);
282 return src;
283 }();
284
285 if (src != dst) {
286 std::iter_swap(first + src, first + dst);
287 std::iter_swap(begin(src_indices) + src, begin(src_indices) + dst);
288 }
289 }
290
291 return first + dst;
292}
293
307auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last) noexcept
308{
309 return shuffle_by_index(first, last, indices_first, indices_last, [](hilet& x) {
310 return narrow_cast<std::size_t>(x);
311 });
312}
313
322template<typename DataIt, typename ValueIt>
324{
325 for (auto it = data_first; it != data_last; ++it) {
327 // Return the iterator pointing to the data that is not part of the value set.
328 return it;
329 }
330 }
331
332 return data_last;
333}
334
343template<typename DataIt, typename ValueIt>
345{
346 auto it = data_last;
347 while (it != data_first) {
349 // Return an iterator one beyond the data that is not part of the value set.
350 return it + 1;
351 }
352 }
353
354 return data_first;
355}
356
366template<std::endian Endian = std::endian::native, typename T, std::unsigned_integral Key>
367[[nodiscard]] constexpr T *fast_lower_bound(std::span<T> table, Key const& key) noexcept
368{
369 auto base = table.data();
370 auto len = table.size();
371
372 // A faster lower-bound search with less branches that are more predictable.
373 while (len > 1) {
374 hi_axiom_not_null(base);
375
376 hilet half = len / 2;
377
378 if (load<Key, Endian>(base + half - 1) < key) {
379 base += half;
380 }
381 len -= half;
382 }
383 if (load<Key, Endian>(base) < key) {
384 return nullptr;
385 }
386 return base;
387}
388
391template<std::endian Endian = std::endian::native, typename T, std::unsigned_integral Key>
392[[nodiscard]] constexpr T *fast_binary_search_eq(std::span<T> table, Key const& key) noexcept
393{
394 hilet ptr = fast_lower_bound<Endian>(table, key);
395 if (ptr == nullptr) {
396 return nullptr;
397 }
398
399 if (load<Key, Endian>(ptr) != key) {
400 return nullptr;
401 }
402
403 return ptr;
404}
405
406} // namespace hi::inline v1
DOXYGEN BUG.
Definition algorithm.hpp:16
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:107
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:261
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:323
constexpr It unordered_remove(It first, It last, It element)
Remove element from a container.
Definition algorithm.hpp:59
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:172
constexpr T * fast_lower_bound(std::span< T > table, Key const &key) noexcept
The fast lower bound algorithm.
Definition algorithm.hpp:367
constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:142
constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:123
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:344
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:392
constexpr std::array< T, N > generate_array(F operation)
Generate data in an array.
Definition algorithm.hpp:38
void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
Definition algorithm.hpp:183
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
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)