IceShard 1
A personal game engine project, with development focused on 2D/2.5D games.
Loading...
Searching...
No Matches
sort.hxx
Go to the documentation of this file.
1
3
4#pragma once
5#include <ice/base.hxx>
6#include <ice/span.hxx>
7#include <algorithm>
8
9namespace ice
10{
11
12 template<typename Type, typename Fn>
13 inline auto accumulate_over(ice::Span<Type> objects, Fn&& fn) noexcept -> ice::u32
14 {
15 ice::u32 result = 0;
16 for (Type const& object : objects)
17 {
18 result += ice::forward<Fn>(fn)(object);
19 }
20 return result;
21 }
22
23 template<typename T, typename U = T> requires (std::convertible_to<T, U>)
24 constexpr auto lower_bound(ice::Span<T> values, U const& value) noexcept -> ice::u32;
25
26 template<typename T, typename Comp, typename U = T> requires (std::convertible_to<T, U>)
27 constexpr auto lower_bound(ice::Span<T> values, U const& value, Comp&& comp) noexcept -> ice::u32;
28
29 template<typename T, typename U = T> requires (std::convertible_to<T, U>)
30 constexpr auto upper_bound(ice::Span<T> values, U const& value) noexcept -> ice::u32;
31
32 template<typename T, typename Comp, typename U = T> requires (std::convertible_to<T, U>)
33 constexpr auto upper_bound(ice::Span<T> values, U const& value, Comp&& comp) noexcept -> ice::u32;
34
35 template<typename T, typename U = T> requires (std::convertible_to<T, U>)
36 constexpr bool binary_search(ice::Span<T> values, U const& value, ice::u32& out_index) noexcept;
37
38 template<typename T, typename Comp, typename U = T> requires (std::convertible_to<T, U>)
39 constexpr bool binary_search(ice::Span<T> values, U const& value, Comp&& comp, ice::u32& out_index) noexcept;
40
41 template<typename T, typename U = T> requires (std::convertible_to<T, U>)
42 constexpr bool search(ice::Span<T> values, U const& value, ice::u32& out_index) noexcept;
43
44 template<typename T, typename Comp, typename U = T>
45 constexpr bool search(ice::Span<T> values, U const& value, Comp&& comp, ice::u32& out_index) noexcept;
46
47 template<typename T>
48 inline void sort(ice::Span<T> span) noexcept;
49
50 template<typename T, typename Pred>
51 inline void sort(ice::Span<T> span, Pred&& pred) noexcept;
52
53 template<typename K, typename V, typename Pred>
54 inline void sort(ice::Span<K> keys, ice::Span<V> values, Pred&& pred) noexcept;
55
56 template<typename T>
57 constexpr auto constexpr_sort_stdarray(T const& arr, ice::u32 start_offset = 0) noexcept -> T;
58
59
60 template<typename K, typename Pred>
61 inline void sort_indices(ice::Span<K> keys, ice::Span<ice::u32> indices, Pred&& pred) noexcept;
62
63 template<typename Node, typename Pred>
64 inline auto sort_linked_list(Node* left_list, ice::u32 size, Pred&& pred) noexcept -> Node*;
65
66
67 template<typename T, typename U> requires (std::convertible_to<T, U>)
68 constexpr auto lower_bound(ice::Span<T> values, U const& value) noexcept -> ice::u32
69 {
70 return static_cast<ice::u32>(std::lower_bound(values.begin(), values.end(), value) - values.begin());
71 }
72
73 template<typename T, typename Comp, typename U> requires (std::convertible_to<T, U>)
74 constexpr auto lower_bound(ice::Span<T> values, U const& value, Comp&& comp) noexcept -> ice::u32
75 {
76 return static_cast<ice::u32>(std::lower_bound(values.begin(), values.end(), value, ice::forward<Comp>(comp)) - values.begin());
77 }
78
79 template<typename T, typename U> requires (std::convertible_to<T, U>)
80 constexpr auto upper_bound(ice::Span<T> values, U const& value) noexcept -> ice::u32
81 {
82 return static_cast<ice::u32>(std::upper_bound(values.begin(), values.end(), value) - values.begin());
83 }
84
85 template<typename T, typename Comp, typename U> requires (std::convertible_to<T, U>)
86 constexpr auto upper_bound(ice::Span<T> values, U const& value, Comp&& comp) noexcept -> ice::u32
87 {
88 return static_cast<ice::u32>(std::upper_bound(values.begin(), values.end(), value, ice::forward<Comp>(comp)) - values.begin());
89 }
90
91 template<typename T, typename U> requires (std::convertible_to<T, U>)
92 constexpr bool binary_search(ice::Span<T> values, U const& predicate, ice::u32& out_index) noexcept
93 {
94 out_index = ice::lower_bound(values, predicate);
95 return (values.size() != out_index) && (values[out_index] == predicate);
96 }
97
98 template<typename T, typename Comp, typename U> requires (std::convertible_to<T, U>)
99 constexpr bool binary_search(ice::Span<T> values, U const& predicate, Comp&& comp, ice::u32& out_index) noexcept
100 {
101 out_index = ice::lower_bound(values, predicate, ice::forward<Comp>(comp));
102 return (values.size() != out_index) && (values[out_index] == predicate);
103 }
104
105 template<typename T, typename U> requires (std::convertible_to<T, U>)
106 constexpr bool search(ice::Span<T> values, U const& value, ice::u32& out_index) noexcept
107 {
108 return search(values, value, [](auto const& l, auto const& r) noexcept { return l == r; }, out_index);
109 }
110
111 template<typename T, typename Comp, typename U>
112 constexpr bool search(ice::Span<T> values, U const& value, Comp&& comp, ice::u32& out_index) noexcept
113 {
114 for (ice::nindex idx = 0; idx < values.size(); ++idx)
115 {
116 if (ice::forward<Comp>(comp)(values[idx], value))
117 {
118 out_index = idx.u32();
119 return true;
120 }
121 }
122 return false;
123 }
124
125 template<typename T, typename Comp, typename... U>
126 constexpr bool search_with(ice::Span<T> values, Comp&& comp, ice::u32& out_index, U const&... params) noexcept
127 {
128 for (ice::u32 idx = 0; idx < values.size(); ++idx)
129 {
130 if (ice::forward<Comp>(comp)(values[idx], idx, params...))
131 {
132 out_index = idx;
133 return true;
134 }
135 }
136 return false;
137 }
138
139 namespace detail
140 {
141
142 template<typename K, typename V, typename Pred>
143 inline auto qsort_partition(ice::Span<K> keys, ice::Span<V>& values, Pred&& pred, ice::i32 left, ice::i32 right) noexcept -> ice::i32
144 {
145 K* pivot = &keys[right];
146
147 ice::i32 i = left - 1;
148 ice::i32 j = left;
149
150 while (j < right)
151 {
152 if (ice::forward<Pred>(pred)(keys[j], *pivot))
153 {
154 ++i;
155 ice::swap(keys[i], keys[j]);
156 ice::swap(values[i], values[j]);
157 }
158 ++j;
159 }
160 ice::swap(keys[i + 1], keys[right]);
161 ice::swap(values[i + 1], values[right]);
162 return i + 1;
163 }
164
165 template<typename Pred, typename Key, typename... Values>
167 Pred&& pred,
168 ice::i32 left,
169 ice::i32 right,
170 ice::Span<Key> keys,
171 ice::Span<Values>... values
172 ) noexcept -> ice::i32
173 {
174 Key* pivot = &keys[right];
175
176 ice::i32 i = left - 1;
177 ice::i32 j = left;
178
179 while (j < right)
180 {
181 if (ice::forward<Pred>(pred)(keys[j], *pivot))
182 {
183 ++i;
184 ice::swap(keys[i], keys[j]);
185 (ice::swap(values[i], values[j]), ...);
186 }
187 ++j;
188 }
189 ice::swap(keys[i + 1], keys[right]);
190 (ice::swap(values[i + 1], values[right]), ...);
191 return i + 1;
192 }
193
194 template<typename K, typename Pred>
195 inline auto qsort_partition_indices(ice::Span<K> keys, ice::Span<ice::u32>& indices, Pred&& pred, ice::i32 left, ice::i32 right) noexcept -> ice::i32
196 {
197 K* pivot = &keys[indices[right]];
198
199 ice::i32 i = left - 1;
200 ice::i32 j = left;
201
202 while (j < right)
203 {
204 if (ice::forward<Pred>(pred)(keys[indices[j]], *pivot))
205 {
206 ++i;
207 ice::swap(indices[i], indices[j]);
208 }
209 ++j;
210 }
211 ice::swap(indices[i + 1], indices[right]);
212 return i + 1;
213 }
214
219 template<typename K, typename V, typename Pred>
220 inline void qsort(ice::Span<K> keys, ice::Span<V> values, Pred&& pred, ice::i32 left, ice::i32 right) noexcept
221 {
222 while (left < right)
223 {
224 ice::i32 const pi = qsort_partition(keys, values, ice::forward<Pred>(pred), left, right);
225
226 ice::detail::qsort(keys, values, ice::forward<Pred>(pred), left, pi - 1);
227
228 left = pi + 1;
229 }
230 }
231
232 template<typename Pred, typename Key, typename... Values>
233 inline void qsort_many(
234 Pred&& pred,
235 ice::i32 left,
236 ice::i32 right,
237 ice::Span<Key> keys,
238 ice::Span<Values>... values
239 ) noexcept
240 {
241 while (left < right)
242 {
243 ice::i32 const pi = qsort_partition_many<Pred, Key, Values...>(
244 ice::forward<Pred>(pred), left, right, keys, values...
245 );
246
247 ice::detail::qsort_many(ice::forward<Pred>(pred), left, pi - 1, keys, values...);
248
249 left = pi + 1;
250 }
251 }
252
253 template<typename K, typename Pred>
254 inline void qsort_indices(ice::Span<K> keys, ice::Span<ice::u32> indices, Pred&& pred, ice::i32 left, ice::i32 right) noexcept
255 {
256 while (left < right)
257 {
258 ice::i32 const pi = qsort_partition_indices(keys, indices, ice::forward<Pred>(pred), left, right);
259
260 ice::detail::qsort_indices(keys, indices, ice::forward<Pred>(pred), left, pi - 1);
261
262 left = pi + 1;
263 }
264 }
265
266 } // namespace detail
267
268 template<typename T>
269 inline void sort(ice::Span<T> span) noexcept
270 {
271 std::sort(span.begin(), span.end());
272 }
273
274 template<typename T, typename Pred>
275 inline void sort(ice::Span<T> span, Pred&& pred) noexcept
276 {
277 std::sort(span.begin(), span.end(), ice::forward<Pred>(pred));
278 }
279
280 template<typename K, typename V, typename Pred>
281 inline void sort(ice::Span<K> keys, ice::Span<V> values, Pred&& pred) noexcept
282 {
283 ice::i32 const first_index = 0;
284 ice::i32 const last_index = ice::count(keys) - 1;
285
286 ice::detail::qsort(keys, values, std::forward<Pred>(pred), first_index, last_index);
287 }
288
289 template<typename Key, typename Pred, typename... Values>
291 inline void sort_many(ice::Span<Key> keys, Pred&& pred, ice::Span<Values>... values) noexcept
292 {
293 ice::i32 const first_index = 0;
294 ice::i32 const last_index = keys.size().u32() - 1;
295
296 ice::detail::qsort_many(std::forward<Pred>(pred), first_index, last_index, keys, values...);
297 }
298
299 template<typename K, typename Pred>
300 inline void sort_indices(ice::Span<K> keys, ice::Span<ice::u32> indices, Pred&& pred) noexcept
301 {
302 ice::i32 const first_index = 0;
303 ice::i32 const last_index = keys.size().u32() - 1;
304
305 ice::detail::qsort_indices(keys, indices, std::forward<Pred>(pred), first_index, last_index);
306 }
307
308 template<typename Node, typename Pred>
309 inline auto sort_linked_list(Node* left_list, ice::u32 size, Pred&& pred) noexcept -> Node*
310 {
311 Node* right_list = left_list;
312 if (size == 1)
313 {
314 left_list->_next = nullptr;
315 return left_list;
316 }
317 else if (size == 2)
318 {
319 right_list = right_list->_next;
320 right_list->_next = nullptr;
321 left_list->_next = nullptr;
322 }
323 else
324 {
325 uint32_t const half_size = size / 2;
326 for (uint32_t idx = half_size; idx > 0; --idx)
327 {
328 right_list = right_list->_next;
329 }
330
331 Node* next = right_list->_next;
332 right_list->_next = nullptr;
333 right_list = next;
334
335 left_list = ice::sort_linked_list(left_list, half_size + 1, pred);
336 right_list = ice::sort_linked_list(right_list, size - (half_size + 1), pred);
337 }
338
339 Node result{ ._next = left_list }; // Keep the head of the list
340 left_list = &result;
341 while (left_list->_next != nullptr && right_list != nullptr)
342 {
343 Node* temp = left_list->_next;
344 if (pred(*temp, *right_list) == false) // TRUE == IS OKAY, FALSE == NEEDS SWAP
345 {
346 // We swapped the whole lists...
347 left_list->_next = right_list;
348 right_list = temp;
349 }
350
351 // We can advance the left list
352 left_list = left_list->_next;
353 }
354
355 // Attach the rest of the right list
356 left_list->_next = right_list;
357
358 // Return the 'next' element of the result.
359 return result._next;
360 }
361
362 template<typename T>
363 constexpr auto constexpr_sort_stdarray(T const& arr, ice::u32 start_offset) noexcept -> T
364 {
365 T result = arr;
366 std::sort(std::next(std::begin(result), start_offset), std::end(result));
367 return result;
368 }
369
370} // namespace ice
Definition utility.hxx:80
void qsort_many(Pred &&pred, ice::i32 left, ice::i32 right, ice::Span< Key > keys, ice::Span< Values >... values) noexcept
Definition sort.hxx:233
auto qsort_partition_indices(ice::Span< K > keys, ice::Span< ice::u32 > &indices, Pred &&pred, ice::i32 left, ice::i32 right) noexcept -> ice::i32
Definition sort.hxx:195
auto qsort_partition_many(Pred &&pred, ice::i32 left, ice::i32 right, ice::Span< Key > keys, ice::Span< Values >... values) noexcept -> ice::i32
Definition sort.hxx:166
auto qsort_partition(ice::Span< K > keys, ice::Span< V > &values, Pred &&pred, ice::i32 left, ice::i32 right) noexcept -> ice::i32
Definition sort.hxx:143
void qsort(ice::Span< K > keys, ice::Span< V > values, Pred &&pred, ice::i32 left, ice::i32 right) noexcept
Definition sort.hxx:220
void qsort_indices(ice::Span< K > keys, ice::Span< ice::u32 > indices, Pred &&pred, ice::i32 left, ice::i32 right) noexcept
Definition sort.hxx:254
arr_t< Size, T > arr
Definition array.hxx:178
SPDX-License-Identifier: MIT.
Definition array.hxx:12
Span(ice::Span< T > &&) noexcept -> Span< T >
constexpr bool search(ice::Span< T > values, U const &value, ice::u32 &out_index) noexcept
Definition sort.hxx:106
constexpr bool binary_search(ice::Span< T > values, U const &value, ice::u32 &out_index) noexcept
Definition sort.hxx:92
void sort(ice::Span< T > span) noexcept
Definition sort.hxx:269
constexpr auto lower_bound(ice::Span< T > values, U const &value) noexcept -> ice::u32
Definition sort.hxx:68
auto sort_linked_list(Node *left_list, ice::u32 size, Pred &&pred) noexcept -> Node *
Definition sort.hxx:309
constexpr auto upper_bound(ice::Span< T > values, U const &value) noexcept -> ice::u32
Definition sort.hxx:80
std::int32_t i32
Definition types.hxx:21
void sort_many(ice::Span< Key > keys, Pred &&pred, ice::Span< Values >... values) noexcept
Definition sort.hxx:291
constexpr auto count(T const (&)[Size]) noexcept -> ice::u32
Definition base.hxx:43
constexpr bool search_with(ice::Span< T > values, Comp &&comp, ice::u32 &out_index, U const &... params) noexcept
Definition sort.hxx:126
std::uint32_t u32
Definition types.hxx:26
auto accumulate_over(ice::Span< Type > objects, Fn &&fn) noexcept -> ice::u32
Definition sort.hxx:13
void sort_indices(ice::Span< K > keys, ice::Span< ice::u32 > indices, Pred &&pred) noexcept
Definition sort.hxx:300
constexpr auto constexpr_sort_stdarray(T const &arr, ice::u32 start_offset=0) noexcept -> T
Definition sort.hxx:363
A view into an array of objects laid out in contiguous memory.
Definition span.hxx:17
constexpr auto size(this Span const &self) noexcept -> ice::ncount
Definition span.hxx:45
constexpr auto begin(this Self &&self) noexcept -> ice::container::Iterator< Self >
Definition contiguous_container.hxx:75
constexpr auto end(this Self &&self) noexcept -> ice::container::Iterator< Self >
Definition contiguous_container.hxx:81
Definition nindex.hxx:13