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 tt {
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, size_t N, typename F>
37constexpr std::array<T, N> generate_array(F operation)
38{
40
41 for (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 ttlet 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, [&](ttlet &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, [&](ttlet &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](ttlet &data) {
104 return std::any_of(value_first, value_last, [&data](ttlet &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 ttlet 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 ttlet 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 }
155 tt_unreachable();
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
245template<typename T, typename MixType, std::enable_if_t<std::is_floating_point_v<MixType>, int> = 0>
246T mix(MixType mix_value, T const &lhs, T const &rhs) noexcept
247{
248 if (mix_value >= MixType(1.0)) {
249 return rhs;
250 } else if (mix_value <= MixType(0.0)) {
251 return lhs;
252 } else {
253 return lhs + (rhs - lhs) * mix_value;
254 }
255}
256
272auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
273{
274 size_t size = std::distance(first, last);
275
276 // Keep track of index locations during shuffling of items.
277 auto src_indices = std::vector<size_t>{};
278 src_indices.reserve(size);
279 for (size_t i = 0; i != size; ++i) {
280 src_indices.push_back(i);
281 }
282
283 size_t dst = 0;
284 for (auto it = indices_first; it != indices_last; ++it, ++dst) {
285 ttlet index = index_op(*it);
286 tt_axiom(index < std::size(src_indices));
287
288 auto src = [&src_indices,index]() {
289 auto src = index;
290 do {
291 src = src_indices[src];
292 } while (src_indices[src] != index);
293 return src;
294 }();
295
296 if (src != dst) {
297 std::iter_swap(first + src, first + dst);
298 std::iter_swap(std::begin(src_indices) + src, std::begin(src_indices) + dst);
299 }
300 }
301
302 return first + dst;
303}
304
318auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last) noexcept
319{
320 return shuffle_by_index(first, last, indices_first, indices_last, [](ttlet &x) {
321 return narrow_cast<size_t>(x);
322 });
323}
324
333template<typename DataIt, typename ValueIt>
334DataIt front_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
335{
336 for (auto it = data_first; it != data_last; ++it) {
337 ttlet &data = *it;
338 if (!std::any_of(value_first, value_last, [&data](ttlet &value) {
339 return data == value;
340 })) {
341 return it;
342 }
343 }
344
345 return data_last;
346}
347
356template<typename DataIt, typename ValueIt>
357DataIt back_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
358{
359 for (auto it = data_last - 1; it >= data_first; ++it) {
360 ttlet &data = *it;
361 if (!std::any_of(value_first, value_last, [&data](ttlet &value) {
362 return data == value;
363 })) {
364 return it + 1;
365 }
366 }
367
368 return data_first;
369}
370
371} // namespace tt
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)