HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
algorithm.hpp
1// Copyright Take Vos 2019-2021.
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 "required.hpp"
8#include "assert.hpp"
9#include "cast.hpp"
10#include <algorithm>
11#include <tuple>
12#include <cmath>
13#include <iterator>
14
15namespace hi::inline v1 {
16
22template<typename T, typename U, typename F>
23inline T transform(const U &input, F operation)
24{
25 T result = {};
26 result.reserve(input.size());
27 std::transform(input.begin(), input.end(), std::back_inserter(result), operation);
28 return result;
29}
30
36template<typename T, std::size_t N, typename F>
37constexpr std::array<T, N> generate_array(F operation)
38{
40
41 for (std::size_t i = 0; i < N; i++) {
42 a.at(i) = operation(i);
43 }
44
45 return a;
46}
47
52template<typename T, typename F>
53inline void erase_if(T &v, F predicate)
54{
55 while (true) {
56 hilet i = std::find_if(v.begin(), v.end(), predicate);
57 if (i == v.end()) {
58 return;
59 }
60 v.erase(i);
61 }
62}
63
64template<typename It, typename UnaryPredicate>
65constexpr It rfind_if(It const first, It const last, UnaryPredicate predicate)
66{
67 auto i = last;
68 do {
69 i--;
70 if (predicate(*i)) {
71 return i;
72 }
73 } while (i != first);
74 return last;
75}
76
77template<typename It, typename UnaryPredicate>
78constexpr It rfind_if_not(It const first, It const last, UnaryPredicate predicate)
79{
80 return rfind_if(first, last, [&](hilet &x) {
81 return !predicate(x);
82 });
83}
84
85template<typename It, typename T>
86constexpr It rfind(It const first, It const last, T const &value)
87{
88 return rfind_if(first, last, [&](hilet &x) {
89 return x == value;
90 });
91}
92
100template<typename It, typename ItAny>
101[[nodiscard]] constexpr It find_any(It data_first, It data_last, ItAny value_first, ItAny value_last) noexcept
102{
103 return std::find_if(data_first, data_last, [value_first, value_last](hilet &data) {
104 return std::any_of(value_first, value_last, [&data](hilet &value) {
105 return data == value;
106 });
107 });
108}
109
116template<typename ConstIt, typename It, typename UnaryPredicate>
117constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
118{
119 hilet cluster_id = predicate(*start);
120
121 for (auto i = start + 1; i != last; ++i) {
122 if (predicate(*i) != cluster_id) {
123 return i;
124 }
125 }
126 return last;
127}
128
135template<typename ConstIt, typename It, typename UnaryPredicate>
136constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
137{
138 hilet cluster_id = predicate(*start);
139
140 if (start == first) {
141 return first;
142 }
143
144 auto i = start - 1;
145 while (true) {
146 if (predicate(*i) != cluster_id) {
147 return (i + 1);
148 }
149
150 if (i == first) {
151 return i;
152 }
153 --i;
154 }
156}
157
165template<typename ConstIt, typename It, typename UnaryPredicate>
166constexpr std::pair<It, It> bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
167{
168 return {rfind_cluster(first, start, predicate), find_cluster(last, start, predicate)};
169}
170
176template<typename It, typename S, typename F>
177inline void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
178{
179 if (first == last) {
180 return;
181 }
182
183 // If the first item is a cluster seperator skip over it.
184 if (IsClusterSeperator(*first)) {
185 first++;
186 }
187
188 for (auto i = first; i != last;) {
189 auto j = std::find_if(i, last, IsClusterSeperator);
190 Function(i, j);
191
192 auto skipOverSeperator = (j == last) ? 0 : 1;
193 i = j + skipOverSeperator;
194 }
195}
196
197template<typename InputIt1, typename InputIt2, typename BinaryPredicate>
199rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate) noexcept
200{
201 auto i1 = last1;
202 auto i2 = last2;
203
204 while (true) {
205 if (i1 == first1 && i2 == first2) {
206 return {last1, last2};
207 } else if (i1 == first1) {
208 return {last1, --i2};
209 } else if (i2 == first2) {
210 return {--i1, last2};
211 }
212
213 if (!predicate(*(--i1), *(--i2))) {
214 return {i1, i2};
215 }
216 }
217}
218
219template<typename InputIt1, typename InputIt2>
220inline std::pair<InputIt1, InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) noexcept
221{
222 return rmismatch(first1, last1, first2, last2, [&](auto a, auto b) {
223 return a == b;
224 });
225}
226
227template<typename T>
228T smoothstep(T x) noexcept
229{
230 x = std::clamp(x, T{0.0}, T{1.0});
231 return x * x * (3 - 2 * x);
232}
233
234template<typename T>
235T inverse_smoothstep(T x)
236{
237 return T{0.5} - std::sin(std::asin(T{1.0} - T{2.0} * x) / T{3.0});
238}
239
255auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
256{
257 std::size_t src_size = std::distance(first, last);
258
259 // Keep track of index locations during shuffling of items.
260 auto src_indices = std::vector<std::size_t>{};
261 src_indices.reserve(src_size);
262 for (std::size_t i = 0; i != src_size; ++i) {
263 src_indices.push_back(i);
264 }
265
266 std::size_t dst = 0;
267 for (auto it = indices_first; it != indices_last; ++it, ++dst) {
268 hilet index = index_op(*it);
269 hi_axiom(index < size(src_indices));
270
271 auto src = [&src_indices, index]() {
272 auto src = index;
273 do {
274 src = src_indices[src];
275 } while (src_indices[src] != index);
276 return src;
277 }();
278
279 if (src != dst) {
280 std::iter_swap(first + src, first + dst);
281 std::iter_swap(begin(src_indices) + src, begin(src_indices) + dst);
282 }
283 }
284
285 return first + dst;
286}
287
301auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last) noexcept
302{
303 return shuffle_by_index(first, last, indices_first, indices_last, [](hilet &x) {
304 return narrow_cast<std::size_t>(x);
305 });
306}
307
316template<typename DataIt, typename ValueIt>
317DataIt front_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
318{
319 for (auto it = data_first; it != data_last; ++it) {
320 if (std::find(value_first, value_last, *it) == value_last) {
321 // Return the iterator pointing to the data that is not part of the value set.
322 return it;
323 }
324 }
325
326 return data_last;
327}
328
337template<typename DataIt, typename ValueIt>
338DataIt back_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
339{
340 auto it = data_last;
341 while (it != data_first) {
342 if (std::find(value_first, value_last, *(--it)) == value_last) {
343 // Return an iterator one beyond the data that is not part of the value set.
344 return it + 1;
345 }
346 }
347
348 return data_first;
349}
350
351} // namespace hi::inline v1
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
#define hi_unreachable()
Marker to tell the compiler that this line will never be executed.
Definition architecture.hpp:214
T any_of(T... args)
T asin(T... args)
T at(T... args)
T back_inserter(T... args)
T begin(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 transform(T... args)