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.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
57template<typename It>
58constexpr It unordered_remove(It first, It last, It element)
59{
60 hi_axiom(first != last);
61
62 using std::swap;
63
64 auto new_last = last - 1;
65 swap(*element, *new_last);
66 return new_last;
67}
68
69template<typename It, typename UnaryPredicate>
70constexpr It rfind_if(It const first, It const last, UnaryPredicate predicate)
71{
72 auto i = last;
73 do {
74 i--;
75 if (predicate(*i)) {
76 return i;
77 }
78 } while (i != first);
79 return last;
80}
81
82template<typename It, typename UnaryPredicate>
83constexpr It rfind_if_not(It const first, It const last, UnaryPredicate predicate)
84{
85 return rfind_if(first, last, [&](hilet &x) {
86 return !predicate(x);
87 });
88}
89
90template<typename It, typename T>
91constexpr It rfind(It const first, It const last, T const &value)
92{
93 return rfind_if(first, last, [&](hilet &x) {
94 return x == value;
95 });
96}
97
105template<typename It, typename ItAny>
106[[nodiscard]] constexpr It find_any(It data_first, It data_last, ItAny value_first, ItAny value_last) noexcept
107{
108 return std::find_if(data_first, data_last, [value_first, value_last](hilet &data) {
109 return std::any_of(value_first, value_last, [&data](hilet &value) {
110 return data == value;
111 });
112 });
113}
114
121template<typename ConstIt, typename It, typename UnaryPredicate>
122constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
123{
124 hilet cluster_id = predicate(*start);
125
126 for (auto i = start + 1; i != last; ++i) {
127 if (predicate(*i) != cluster_id) {
128 return i;
129 }
130 }
131 return last;
132}
133
140template<typename ConstIt, typename It, typename UnaryPredicate>
141constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
142{
143 hilet cluster_id = predicate(*start);
144
145 if (start == first) {
146 return first;
147 }
148
149 auto i = start - 1;
150 while (true) {
151 if (predicate(*i) != cluster_id) {
152 return (i + 1);
153 }
154
155 if (i == first) {
156 return i;
157 }
158 --i;
159 }
160 hi_unreachable();
161}
162
170template<typename ConstIt, typename It, typename UnaryPredicate>
171constexpr std::pair<It, It> bifind_cluster(ConstIt first, ConstIt last, It start, UnaryPredicate predicate)
172{
173 return {rfind_cluster(first, start, predicate), find_cluster(last, start, predicate)};
174}
175
181template<typename It, typename S, typename F>
182inline void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
183{
184 if (first == last) {
185 return;
186 }
187
188 // If the first item is a cluster separator skip over it.
189 if (IsClusterSeperator(*first)) {
190 first++;
191 }
192
193 for (auto i = first; i != last;) {
194 auto j = std::find_if(i, last, IsClusterSeperator);
195 Function(i, j);
196
197 auto skipOverSeperator = (j == last) ? 0 : 1;
198 i = j + skipOverSeperator;
199 }
200}
201
202template<typename InputIt1, typename InputIt2, typename BinaryPredicate>
204rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate predicate) noexcept
205{
206 auto i1 = last1;
207 auto i2 = last2;
208
209 while (true) {
210 if (i1 == first1 && i2 == first2) {
211 return {last1, last2};
212 } else if (i1 == first1) {
213 return {last1, --i2};
214 } else if (i2 == first2) {
215 return {--i1, last2};
216 }
217
218 if (!predicate(*(--i1), *(--i2))) {
219 return {i1, i2};
220 }
221 }
222}
223
224template<typename InputIt1, typename InputIt2>
225inline std::pair<InputIt1, InputIt2> rmismatch(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) noexcept
226{
227 return rmismatch(first1, last1, first2, last2, [&](auto a, auto b) {
228 return a == b;
229 });
230}
231
232template<typename T>
233T smoothstep(T x) noexcept
234{
235 x = std::clamp(x, T{0.0}, T{1.0});
236 return x * x * (3 - 2 * x);
237}
238
239template<typename T>
240T inverse_smoothstep(T x)
241{
242 return T{0.5} - std::sin(std::asin(T{1.0} - T{2.0} * x) / T{3.0});
243}
244
260auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last, auto index_op) noexcept
261{
262 std::size_t src_size = std::distance(first, last);
263
264 // Keep track of index locations during shuffling of items.
265 auto src_indices = std::vector<std::size_t>{};
266 src_indices.reserve(src_size);
267 for (std::size_t i = 0; i != src_size; ++i) {
268 src_indices.push_back(i);
269 }
270
271 std::size_t dst = 0;
272 for (auto it = indices_first; it != indices_last; ++it, ++dst) {
273 hilet index = index_op(*it);
274 hi_axiom(index < size(src_indices));
275
276 auto src = [&src_indices, index]() {
277 auto src = index;
278 do {
279 src = src_indices[src];
280 } while (src_indices[src] != index);
281 return src;
282 }();
283
284 if (src != dst) {
285 std::iter_swap(first + src, first + dst);
286 std::iter_swap(begin(src_indices) + src, begin(src_indices) + dst);
287 }
288 }
289
290 return first + dst;
291}
292
306auto shuffle_by_index(auto first, auto last, auto indices_first, auto indices_last) noexcept
307{
308 return shuffle_by_index(first, last, indices_first, indices_last, [](hilet &x) {
309 return narrow_cast<std::size_t>(x);
310 });
311}
312
321template<typename DataIt, typename ValueIt>
322DataIt front_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
323{
324 for (auto it = data_first; it != data_last; ++it) {
325 if (std::find(value_first, value_last, *it) == value_last) {
326 // Return the iterator pointing to the data that is not part of the value set.
327 return it;
328 }
329 }
330
331 return data_last;
332}
333
342template<typename DataIt, typename ValueIt>
343DataIt back_strip(DataIt data_first, DataIt data_last, ValueIt value_first, ValueIt value_last) noexcept
344{
345 auto it = data_last;
346 while (it != data_first) {
347 if (std::find(value_first, value_last, *(--it)) == value_last) {
348 // Return an iterator one beyond the data that is not part of the value set.
349 return it + 1;
350 }
351 }
352
353 return data_first;
354}
355
356} // namespace hi::inline v1
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
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:106
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:260
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:322
constexpr It unordered_remove(It first, It last, It element)
Remove element from a container.
Definition algorithm.hpp:58
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:171
constexpr It rfind_cluster(ConstIt first, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:141
constexpr It find_cluster(ConstIt last, It start, UnaryPredicate predicate)
Find the start of the current cluster.
Definition algorithm.hpp:122
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:343
constexpr std::array< T, N > generate_array(F operation)
Generate data in an array.
Definition algorithm.hpp:37
void for_each_cluster(It first, It last, S IsClusterSeperator, F Function)
Definition algorithm.hpp:182
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)