HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
algorithm.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/required.hpp"
7#include <algorithm>
8#include <tuple>
9#include <cmath>
10
11namespace tt {
12
18template<typename T, typename U, typename F>
19inline T transform(const U &input, F operation)
20{
21 T result = {};
22 result.reserve(input.size());
23 std::transform(input.begin(), input.end(), std::back_inserter(result), operation);
24 return result;
25}
26
32template<typename T, size_t N, typename F>
33constexpr std::array<T, N> generate_array(F operation)
34{
36
37 for (size_t i = 0; i < N; i++) {
38 a.at(i) = operation(i);
39 }
40
41 return a;
42}
43
48template<typename T, typename F>
49inline void erase_if(T &v, F predicate)
50{
51 while (true) {
52 ttlet i = std::find_if(v.begin(), v.end(), predicate);
53 if (i == v.end()) {
54 return;
55 }
56 v.erase(i);
57 }
58}
59
60
61template<typename It, typename UnaryPredicate>
62constexpr It rfind_if(It const first, It const last, UnaryPredicate predicate)
63{
64 auto i = last;
65 do {
66 i--;
67 if (predicate(*i)) {
68 return i;
69 }
70 } while (i != first);
71 return last;
72}
73
74template<typename It, typename UnaryPredicate>
75constexpr It rfind_if_not(It const first, It const last, UnaryPredicate predicate)
76{
77 return rfind_if(first, last, [&](ttlet &x) { return !predicate(x); });
78}
79
80template<typename It, typename T>
81constexpr It rfind(It const first, It const last, T const &value)
82{
83 return rfind_if(first, last, [&](ttlet &x) { return x == value; });
84}
85
92template<typename ConstIt, typename It, typename UnaryPredicate>
93constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
94{
95 ttlet cluster_id = predicate(*start);
96
97 for (auto i = start + 1; i != last; ++i) {
98 if (predicate(*i) != cluster_id) {
99 return i;
100 }
101 }
102 return last;
103}
104
111template<typename ConstIt, typename It, typename UnaryPredicate>
112constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
113{
114 ttlet cluster_id = predicate(*start);
115
116 if (start == first) {
117 return first;
118 }
119
120 auto i = start - 1;
121 while (true) {
122 if (predicate(*i) != cluster_id) {
123 return (i + 1);
124 }
125
126 if (i == first) {
127 return i;
128 }
129 --i;
130 }
131 tt_unreachable();
132}
133
141template<typename ConstIt, typename It, typename UnaryPredicate>
142constexpr std::pair<It,It> bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
143{
144 return {
145 rfind_cluster(first, start, predicate),
146 find_cluster(last, start, predicate)
147 };
148}
149
155template<typename It, typename S, typename F>
156inline void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
157{
158 if (first == last) {
159 return;
160 }
161
162 // If the first item is a cluster seperator skip over it.
163 if (IsClusterSeperator(*first)) {
164 first++;
165 }
166
167 for (auto i = first; i != last;) {
168 auto j = std::find_if(i, last, IsClusterSeperator);
169 Function(i, j);
170
171 auto skipOverSeperator = (j == last) ? 0 : 1;
172 i = j + skipOverSeperator;
173 }
174}
175
176template<typename InputIt1, typename InputIt2>
177inline bool starts_with(InputIt1 haystack_first, InputIt1 haystack_last, InputIt2 needle_first, InputIt2 needle_last) noexcept
178{
179 ttlet [haystack_result, needle_result] = std::mismatch(haystack_first, haystack_last, needle_first, needle_last);
180 return needle_result == needle_last;
181}
182
183template<typename Container1, typename Container2>
184inline bool starts_with(Container1 haystack, Container2 needle) noexcept
185{
186 return starts_with(haystack.begin(), haystack.end(), needle.begin(), needle.end());
187}
188
189template<typename InputIt1, typename InputIt2, typename BinaryPredicate>
190inline std::pair<InputIt1,InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate) noexcept
191{
192 auto i1 = last1;
193 auto i2 = last2;
194
195 while (true) {
196 if (i1 == first1 && i2 == first2) {
197 return {last1, last2};
198 } else if (i1 == first1) {
199 return {last1, --i2};
200 } else if (i2 == first2) {
201 return {--i1, last2};
202 }
203
204 if (!predicate(*(--i1), *(--i2))) {
205 return {i1, i2};
206 }
207 }
208}
209
210template<typename InputIt1, typename InputIt2>
211inline std::pair<InputIt1,InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) noexcept
212{
213 return rmismatch(first1, last1, first2, last2, [&](auto a, auto b) { return a == b; });
214}
215
216template<typename InputIt1, typename InputIt2>
217inline bool ends_with(InputIt1 haystack_first, InputIt1 haystack_last, InputIt2 needle_first, InputIt2 needle_last) noexcept
218{
219 ttlet [haystack_result, needle_result] = rmismatch(haystack_first, haystack_last, needle_first, needle_last);
220 return needle_result == needle_last;
221}
222
223template<typename Container1, typename Container2>
224inline bool ends_with(Container1 haystack, Container2 needle) noexcept
225{
226 return ends_with(haystack.begin(), haystack.end(), needle.begin(), needle.end());
227}
228
229template<typename T>
230T smoothstep(T x) noexcept {
231 x = std::clamp(x, T{0.0}, T{1.0});
232 return x * x * (3 - 2 * x);
233}
234
235template<typename T>
236T inverse_smoothstep(T x) {
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
257
258}
259
T asin(T... args)
T at(T... args)
T back_inserter(T... args)
T find_if(T... args)
T mismatch(T... args)
T sin(T... args)
T transform(T... args)