2#include "gaia/config/config.h"
10#if GAIA_PLATFORM_WINDOWS
16#include "gaia/core/iterator.h"
19 constexpr uint32_t BadIndex = uint32_t(-1);
21#if GAIA_COMPILER_MSVC || GAIA_PLATFORM_WINDOWS
22 #define GAIA_STRCPY(var, max_len, text) \
23 strncpy_s((var), (text), (size_t)-1); \
25 #define GAIA_STRFMT(var, max_len, fmt, ...) sprintf_s((var), (max_len), fmt, __VA_ARGS__)
26 #define GAIA_STRLEN(var, max_len) strnlen_s((var), (max_len))
28 #define GAIA_STRCPY(var, max_len, text) \
30 strncpy((var), (text), (max_len)); \
31 (var)[(max_len) - 1] = 0; \
33 #define GAIA_STRFMT(var, max_len, fmt, ...) snprintf((var), (max_len), fmt, __VA_ARGS__)
34 #define GAIA_STRLEN(var, max_len) strnlen((var), (max_len))
41 using type = std::remove_reference_t<std::remove_pointer_t<T>>;
47 !std::is_const_v<typename rem_rp<T>::type> &&
48 (std::is_pointer<T>::value || std::is_reference<T>::value)> {};
50 template <
typename,
typename =
size_t>
54 struct is_complete<T, decltype(sizeof(T))>: std::true_type {};
57 constexpr auto size(C& c)
noexcept ->
decltype(c.size()) {
61 constexpr auto size(
const C& c)
noexcept ->
decltype(c.size()) {
64 template <
typename T, auto N>
65 constexpr auto size(
const T (&)[N])
noexcept {
70 constexpr auto data(C& c)
noexcept ->
decltype(c.data()) {
74 constexpr auto data(
const C& c)
noexcept ->
decltype(c.data()) {
77 template <
typename T, auto N>
78 constexpr T* data(T (&array)[N])
noexcept {
82 constexpr const E* data(std::initializer_list<E> il)
noexcept {
88 explicit constexpr zero_t() =
default;
90 inline constexpr zero_t zero{};
93 using rem_rp_t =
typename detail::rem_rp<T>::type;
96 inline constexpr bool is_mut_v = detail::is_mut<T>::value;
99 using raw_t =
typename std::decay_t<std::remove_pointer_t<T>>;
101 template <
typename T>
102 inline constexpr bool is_raw_v = std::is_same_v<T, raw_t<T>> && !std::is_array_v<T>;
104 template <
typename T>
105 inline constexpr bool is_complete_v = detail::is_complete<T>::value;
108 template <
typename T>
109 constexpr T* addressof(T& obj)
noexcept {
114 template <
typename T>
115 const T* addressof(
const T&&) =
delete;
117 template <
typename T>
118 constexpr bool check_alignment(
const T* ptr)
noexcept {
119 return (
reinterpret_cast<uintptr_t
>(ptr)) %
alignof(T) == 0;
122 template <
typename T>
143 template <
typename,
typename =
void>
145 template <
typename T>
148 decltype(detail::data(std::declval<T>())),
149 decltype(detail::size(std::declval<T>()))
150 >>: std::true_type {};
152 template <
typename,
typename =
void>
154 template <
typename T>
157 decltype(std::declval<T>().begin()),
158 decltype(std::declval<T>().end()),
159 decltype(detail::size(std::declval<T>()))
160 >>: std::true_type {};
166 template <
typename T>
167 constexpr T as_bits(T value) {
168 static_assert(std::is_integral_v<T>);
172 template <
typename T>
173 constexpr T as_bytes(T value) {
174 static_assert(std::is_integral_v<T>);
182 template <
typename T>
183 constexpr uint32_t count_bits(T number) {
184 uint32_t bits_needed = 0;
185 while (number > 0U) {
192 template <
typename T>
193 constexpr bool is_pow2(T number) {
194 static_assert(std::is_integral<T>::value,
"is_pow2 must be used with integer types");
196 return (number & (number - 1)) == 0;
199 template <
typename T>
200 constexpr T closest_pow2(T number) {
201 static_assert(std::is_integral<T>::value,
"closest_pow2 must be used with integer types");
207 number |= number >> 1;
208 number |= number >> 2;
209 number |= number >> 4;
210 if constexpr (
sizeof(T) > 1)
211 number |= number >> 8;
212 if constexpr (
sizeof(T) > 2)
213 number |= number >> 16;
214 if constexpr (
sizeof(T) > 4)
215 number |= number >> 32;
218 return number - (number >> 1);
228 template <
typename T>
229 void call_ctor_raw(T* pData) {
230 GAIA_ASSERT(pData !=
nullptr);
231 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*pData)))) T;
238 template <
typename T>
239 void call_ctor_raw_n(T* pData,
size_t cnt) {
240 GAIA_ASSERT(pData !=
nullptr);
241 for (
size_t i = 0; i < cnt; ++i) {
242 auto* ptr = pData + i;
243 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*ptr)))) T;
250 template <
typename T>
251 void call_ctor_val(T* pData) {
252 GAIA_ASSERT(pData !=
nullptr);
253 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*pData)))) T();
260 template <
typename T>
261 void call_ctor_val_n(T* pData,
size_t cnt) {
262 GAIA_ASSERT(pData !=
nullptr);
263 for (
size_t i = 0; i < cnt; ++i) {
264 auto* ptr = pData + i;
265 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*ptr)))) T();
273 template <
typename T>
274 void call_ctor([[maybe_unused]] T* pData) {
275 GAIA_ASSERT(pData !=
nullptr);
276 if constexpr (!std::is_trivially_constructible_v<T>) {
277 (void)::new (pData) T();
285 template <
typename T>
286 void call_ctor_n([[maybe_unused]] T* pData, [[maybe_unused]]
size_t cnt) {
287 GAIA_ASSERT(pData !=
nullptr);
288 if constexpr (!std::is_trivially_constructible_v<T>) {
289 for (
size_t i = 0; i < cnt; ++i)
290 (
void)::new (pData + i) T();
294 template <
typename T,
typename... Args>
295 void call_ctor(T* pData, Args&&... args) {
296 GAIA_ASSERT(pData !=
nullptr);
297 if constexpr (std::is_constructible_v<T, Args...>)
298 (
void)::new (pData) T(GAIA_FWD(args)...);
300 (
void)::new (pData) T{GAIA_FWD(args)...};
307 template <
typename T>
308 void call_dtor([[maybe_unused]] T* pData) {
309 GAIA_ASSERT(pData !=
nullptr);
310 if constexpr (!std::is_trivially_destructible_v<T>) {
319 template <
typename T>
320 void call_dtor_n([[maybe_unused]] T* pData, [[maybe_unused]]
size_t cnt) {
321 GAIA_ASSERT(pData !=
nullptr);
322 if constexpr (!std::is_trivially_destructible_v<T>) {
323 for (
size_t i = 0; i < cnt; ++i)
332 template <
typename T>
333 constexpr void swap(T& left, T& right) {
334 T tmp = GAIA_MOV(left);
335 left = GAIA_MOV(right);
336 right = GAIA_MOV(tmp);
339 template <
typename T,
typename TCmpFunc>
340 constexpr void swap_if(T* c,
size_t lhs,
size_t rhs, TCmpFunc cmpFunc)
noexcept {
341 if (!cmpFunc(c[lhs], c[rhs]))
342 core::swap(c[lhs], c[rhs]);
345 template <
typename T,
typename TCmpFunc>
346 constexpr void swap_if(T& lhs, T& rhs, TCmpFunc cmpFunc)
noexcept {
347 if (!cmpFunc(lhs, rhs))
348 core::swap(lhs, rhs);
351 template <
typename T,
typename TCmpFunc>
352 constexpr void swap_if_not(T& lhs, T& rhs, TCmpFunc cmpFunc)
noexcept {
353 if (cmpFunc(lhs, rhs))
354 core::swap(lhs, rhs);
357 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
358 constexpr void try_swap_if(T* c, uint32_t lhs, uint32_t rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
359 if (!cmpFunc(c[lhs], c[rhs]))
363 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
364 constexpr void try_swap_if(
365 C& c,
typename C::size_type lhs,
typename C::size_type rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
366 if (!cmpFunc(c[lhs], c[rhs]))
370 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
371 constexpr void try_swap_if_not(
372 C& c,
typename C::size_type lhs,
typename C::size_type rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
373 if (cmpFunc(c[lhs], c[rhs]))
381 template <
class ForwardIt,
class T>
382 constexpr void fill(ForwardIt first, ForwardIt last,
const T& value) {
383 for (; first != last; ++first) {
393 constexpr const T& get_min(
const T& a,
const T& b) {
394 return (b < a) ? b : a;
398 constexpr const T& get_max(
const T& a,
const T& b) {
399 return (b > a) ? b : a;
406 template <
typename...>
407 inline constexpr auto is_unique = std::true_type{};
409 template <
typename T,
typename... Rest>
410 inline constexpr auto is_unique<T, Rest...> =
411 std::bool_constant<(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>>{};
414 template <
typename T>
420 template <
typename T,
typename... Ts>
423 template <
typename... Ts,
typename U,
typename... Us>
424 struct unique<std::tuple<Ts...>, U, Us...>:
426 (std::is_same_v<U, Ts> || ...), unique<std::tuple<Ts...>, Us...>, unique<std::tuple<Ts..., U>, Us...>> {};
428 template <
typename... Ts>
435 template <
typename... Args>
436 constexpr unsigned get_args_size(std::tuple<Args...>
const& ) {
437 return (
sizeof(Args) + ...);
444 template <
typename... Type>
447 template <
typename Class,
typename Ret,
typename... Args>
455 #define GAIA_DEFINE_HAS_MEMBER_FUNC(function_name) \
456 template <typename T, typename... Args> \
457 concept has_mfunc_check_##function_name = requires(T&& t, Args&&... args) { t.function_name(GAIA_FWD(args)...); }; \
459 template <typename T, typename... Args> \
460 struct has_func_##function_name { \
461 static constexpr bool value = has_mfunc_check_##function_name<T, Args...>; \
465 template <
class Default,
class AlwaysVoid,
template <
class...>
class Op,
class... Args>
467 using value_t = std::false_type;
468 using type = Default;
471 template <
class Default,
template <
class...>
class Op,
class... Args>
473 using value_t = std::true_type;
474 using type = Op<Args...>;
486 template <
template <
class...>
class Op,
typename... Args>
489 #define GAIA_DEFINE_HAS_MEMBER_FUNC(function_name) \
490 template <typename T, typename... Args> \
491 using has_mfunc_check_##function_name = decltype(std::declval<T>().function_name(std::declval<Args>()...)); \
493 template <typename T, typename... Args> \
494 struct has_func_##function_name { \
495 static constexpr bool value = gaia::core::has_mfunc<has_mfunc_check_##function_name, T, Args...>::value; \
499 GAIA_DEFINE_HAS_MEMBER_FUNC(find);
500 GAIA_DEFINE_HAS_MEMBER_FUNC(find_if);
501 GAIA_DEFINE_HAS_MEMBER_FUNC(find_if_not);
508 template <
typename T>
509 constexpr auto has_mfunc_equals_check(
int)
510 ->
decltype(std::declval<T>().operator==(std::declval<T>()), std::true_type{});
511 template <
typename T,
typename... Args>
512 constexpr std::false_type has_mfunc_equals_check(...);
514 template <
typename T>
515 constexpr auto has_ffunc_equals_check(
int)
516 ->
decltype(operator==(std::declval<T>(), std::declval<T>()), std::true_type{});
517 template <
typename T,
typename... Args>
518 constexpr std::false_type has_ffunc_equals_check(...);
521 template <
typename T>
523 static constexpr bool value =
decltype(detail::has_mfunc_equals_check<T>(0))::value;
526 template <
typename T>
528 static constexpr bool value =
decltype(detail::has_ffunc_equals_check<T>(0))::value;
535 template <
typename... Type>
538 static constexpr auto size =
sizeof...(Type);
541 template <
typename TypesA,
typename TypesB>
544 template <
typename... TypesA,
typename... TypesB>
554 template <
auto FirstIdx,
auto Iters,
typename Func,
auto... Is>
555 constexpr void each_impl(Func func, std::integer_sequence<
decltype(Iters), Is...> ) {
556 if constexpr ((std::is_invocable_v<Func&&, std::integral_constant<
decltype(Is), Is>> && ...))
557 (func(std::integral_constant<
decltype(Is), FirstIdx + Is>{}), ...);
559 (((
void)Is, func()), ...);
562 template <
auto FirstIdx,
typename Tuple,
typename Func,
auto... Is>
563 void each_tuple_impl(Func func, std::integer_sequence<
decltype(FirstIdx), Is...> ) {
564 if constexpr ((std::is_invocable_v<
565 Func&&,
decltype(std::tuple_element_t<FirstIdx + Is, Tuple>{}),
566 std::integral_constant<
decltype(FirstIdx), Is>> &&
570 std::tuple_element_t<FirstIdx + Is, Tuple>{},
571 std::integral_constant<
decltype(FirstIdx), FirstIdx + Is>{}),
575 (func(std::tuple_element_t<FirstIdx + Is, Tuple>{}), ...);
578 template <
auto FirstIdx,
typename Tuple,
typename Func,
auto... Is>
579 void each_tuple_impl(Tuple&& tuple, Func func, std::integer_sequence<
decltype(FirstIdx), Is...> ) {
580 if constexpr ((std::is_invocable_v<
581 Func&&,
decltype(std::get<FirstIdx + Is>(tuple)),
582 std::integral_constant<
decltype(FirstIdx), Is>> &&
585 (func(std::get<FirstIdx + Is>(tuple), std::integral_constant<
decltype(FirstIdx), FirstIdx + Is>{}), ...);
588 (func(std::get<FirstIdx + Is>(tuple)), ...);
605 template <auto Iters,
typename Func>
606 constexpr void each(Func func) {
607 using TIters =
decltype(Iters);
608 constexpr TIters First = 0;
609 detail::each_impl<First, Iters, Func>(func, std::make_integer_sequence<TIters, Iters>());
626 template <auto FirstIdx, auto LastIdx,
typename Func>
627 constexpr void each_ext(Func func) {
628 static_assert(LastIdx >= FirstIdx);
629 const auto Iters = LastIdx - FirstIdx;
630 detail::each_impl<FirstIdx, Iters, Func>(func, std::make_integer_sequence<
decltype(Iters), Iters>());
648 template <auto FirstIdx, auto LastIdx, auto Inc,
typename Func>
649 constexpr void each_ext(Func func) {
650 if constexpr (FirstIdx < LastIdx) {
651 if constexpr (std::is_invocable_v<Func&&, std::integral_constant<
decltype(FirstIdx), FirstIdx>>)
652 func(std::integral_constant<
decltype(FirstIdx), FirstIdx>());
656 each_ext<FirstIdx + Inc, LastIdx, Inc>(func);
670 template <
typename Func,
typename... Args>
671 constexpr void each_pack(Func func, Args&&... args) {
672 (func(GAIA_FWD(args)), ...);
688 template <
typename Tuple,
typename Func>
689 constexpr void each_tuple(Tuple&& tuple, Func func) {
690 using TTSize = uint32_t;
691 constexpr auto TSize = (TTSize)std::tuple_size<std::remove_reference_t<Tuple>>::value;
692 detail::each_tuple_impl<(TTSize)0>(GAIA_FWD(tuple), func, std::make_integer_sequence<TTSize, TSize>{});
710 template <
typename Tuple,
typename Func>
711 constexpr void each_tuple(Func func) {
712 using TTSize = uint32_t;
713 constexpr auto TSize = (TTSize)std::tuple_size<std::remove_reference_t<Tuple>>::value;
714 detail::each_tuple_impl<(TTSize)0, Tuple>(func, std::make_integer_sequence<TTSize, TSize>{});
730 template <auto FirstIdx, auto LastIdx,
typename Tuple,
typename Func>
731 constexpr void each_tuple_ext(Tuple&& tuple, Func func) {
732 constexpr auto TSize = std::tuple_size<std::remove_reference_t<Tuple>>::value;
733 static_assert(LastIdx >= FirstIdx);
734 static_assert(LastIdx <= TSize);
735 constexpr auto Iters = LastIdx - FirstIdx;
736 detail::each_tuple_impl<FirstIdx>(GAIA_FWD(tuple), func, std::make_integer_sequence<
decltype(FirstIdx), Iters>{});
754 template <auto FirstIdx, auto LastIdx,
typename Tuple,
typename Func>
755 constexpr void each_tuple_ext(Func func) {
756 constexpr auto TSize = std::tuple_size<std::remove_reference_t<Tuple>>::value;
757 static_assert(LastIdx >= FirstIdx);
758 static_assert(LastIdx <= TSize);
759 constexpr auto Iters = LastIdx - FirstIdx;
760 detail::each_tuple_impl<FirstIdx, Tuple>(func, std::make_integer_sequence<
decltype(FirstIdx), Iters>{});
763 template <
typename InputIt,
typename Func>
764 constexpr Func each(InputIt first, InputIt last, Func func) {
765 for (; first != last; ++first)
770 template <
typename C,
typename Func>
771 constexpr auto each(
const C& arr, Func func) {
772 return each(arr.begin(), arr.end(), func);
779 template <
typename InputIt,
typename T>
780 constexpr InputIt find(InputIt first, InputIt last,
const T& value) {
781 if constexpr (std::is_pointer_v<InputIt>) {
782 auto size = distance(first, last);
783 for (
decltype(size) i = 0; i < size; ++i) {
784 if (first[i] == value)
787 }
else if constexpr (is_random_iter_v<InputIt>) {
788 auto size = distance(first, last);
789 for (
decltype(size) i = 0; i < size; ++i) {
790 if (*(first[i]) == value)
794 for (; first != last; ++first) {
802 template <
typename C,
typename V>
803 constexpr auto find(
const C& arr,
const V& item) {
804 if constexpr (has_func_find<C>::value)
805 return arr.find(item);
807 return core::find(arr.begin(), arr.end(), item);
810 template <
typename InputIt,
typename Func>
811 constexpr InputIt find_if(InputIt first, InputIt last, Func func) {
812 if constexpr (std::is_pointer_v<InputIt>) {
813 auto size = distance(first, last);
814 for (
decltype(size) i = 0; i < size; ++i) {
818 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
819 auto size = distance(first, last);
820 for (
decltype(size) i = 0; i < size; ++i) {
821 if (func(*(first[i])))
825 for (; first != last; ++first) {
833 template <
typename UnaryPredicate,
typename C>
834 constexpr auto find_if(
const C& arr, UnaryPredicate predicate) {
835 if constexpr (has_func_find_if<C, UnaryPredicate>::value)
836 return arr.find_id(predicate);
838 return core::find_if(arr.begin(), arr.end(), predicate);
841 template <
typename InputIt,
typename Func>
842 constexpr InputIt find_if_not(InputIt first, InputIt last, Func func) {
843 if constexpr (std::is_pointer_v<InputIt>) {
844 auto size = distance(first, last);
845 for (
decltype(size) i = 0; i < size; ++i) {
849 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
850 auto size = distance(first, last);
851 for (
decltype(size) i = 0; i < size; ++i) {
852 if (!func(*(first[i])))
856 for (; first != last; ++first) {
864 template <
typename UnaryPredicate,
typename C>
865 constexpr auto find_if_not(
const C& arr, UnaryPredicate predicate) {
866 if constexpr (has_func_find_if_not<C, UnaryPredicate>::value)
867 return arr.find_if_not(predicate);
869 return core::find_if_not(arr.begin(), arr.end(), predicate);
874 template <
typename C,
typename V>
875 constexpr bool has(
const C& arr,
const V& item) {
876 const auto it = find(arr, item);
877 return it != arr.end();
880 template <
typename UnaryPredicate,
typename C>
881 constexpr bool has_if(
const C& arr, UnaryPredicate predicate) {
882 const auto it = find_if(arr, predicate);
883 return it != arr.end();
888 template <
typename C>
889 constexpr auto get_index(
const C& arr,
typename C::const_reference item) {
890 const auto it = find(arr, item);
894 return (
decltype(BadIndex))core::distance(arr.begin(), it);
897 template <
typename C>
898 constexpr auto get_index_unsafe(
const C& arr,
typename C::const_reference item) {
899 return (
decltype(BadIndex))core::distance(arr.begin(), find(arr, item));
902 template <
typename UnaryPredicate,
typename C>
903 constexpr auto get_index_if(
const C& arr, UnaryPredicate predicate) {
904 const auto it = find_if(arr, predicate);
908 return (
decltype(BadIndex))core::distance(arr.begin(), it);
911 template <
typename UnaryPredicate,
typename C>
912 constexpr auto get_index_if_unsafe(
const C& arr, UnaryPredicate predicate) {
913 return (
decltype(BadIndex))core::distance(arr.begin(), find_if(arr, predicate));
927 template <
typename C>
928 void swap_erase_unsafe(C& arr,
typename C::size_type idx) {
929 GAIA_ASSERT(idx < arr.size());
931 if (idx + 1 != arr.size())
932 arr[idx] = arr[arr.size() - 1];
943 template <
typename C>
944 void swap_erase(C& arr,
typename C::size_type idx) {
945 if (idx >= arr.size())
948 if (idx + 1 != arr.size())
949 arr[idx] = arr[arr.size() - 1];
958 template <
typename T>
960 constexpr bool operator()(
const T& lhs,
const T& rhs)
const {
965 template <
typename T>
967 constexpr bool operator()(
const T& lhs,
const T& rhs)
const {
972 template <
typename T>
974 constexpr bool operator()(
const T& lhs,
const T& rhs)
const {
979 template <
typename T>
981 constexpr bool operator()(
const T& lhs,
const T& rhs)
const {
991 template <
typename Container,
typename TCmpFunc>
992 int quick_sort_partition(Container& arr,
int low,
int high, TCmpFunc cmpFunc) {
993 const auto& pivot = arr[(uint32_t)high];
995 for (
int j = low; j <= high - 1; ++j) {
996 if (cmpFunc(arr[(uint32_t)j], pivot))
997 core::swap(arr[(uint32_t)++i], arr[(uint32_t)j]);
999 core::swap(arr[(uint32_t)++i], arr[(uint32_t)high]);
1003 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1004 int quick_sort_partition(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1005 const auto& pivot = arr[(uint32_t)high];
1007 for (
int j = low; j <= high - 1; ++j) {
1008 if (cmpFunc(arr[(uint32_t)j], pivot))
1009 swapFunc((uint32_t)++i, (uint32_t)j);
1011 swapFunc((uint32_t)++i, (uint32_t)high);
1015 template <
typename T,
typename TCmpFunc>
1016 bool sort_nwk(T* beg, T* end, TCmpFunc cmpFunc) {
1017 const auto n = (uint32_t)(end - beg);
1020 }
else if (n == 2) {
1021 swap_if(beg, 0, 1, cmpFunc);
1022 }
else if (n == 3) {
1023 swap_if(beg, 1, 2, cmpFunc);
1024 swap_if(beg, 0, 2, cmpFunc);
1025 swap_if(beg, 0, 1, cmpFunc);
1026 }
else if (n == 4) {
1027 swap_if(beg, 0, 1, cmpFunc);
1028 swap_if(beg, 2, 3, cmpFunc);
1030 swap_if(beg, 0, 2, cmpFunc);
1031 swap_if(beg, 1, 3, cmpFunc);
1033 swap_if(beg, 1, 2, cmpFunc);
1034 }
else if (n == 5) {
1035 swap_if(beg, 0, 1, cmpFunc);
1036 swap_if(beg, 3, 4, cmpFunc);
1038 swap_if(beg, 2, 4, cmpFunc);
1040 swap_if(beg, 2, 3, cmpFunc);
1041 swap_if(beg, 1, 4, cmpFunc);
1043 swap_if(beg, 0, 3, cmpFunc);
1045 swap_if(beg, 0, 2, cmpFunc);
1046 swap_if(beg, 1, 3, cmpFunc);
1048 swap_if(beg, 1, 2, cmpFunc);
1049 }
else if (n == 6) {
1050 swap_if(beg, 1, 2, cmpFunc);
1051 swap_if(beg, 4, 5, cmpFunc);
1053 swap_if(beg, 0, 2, cmpFunc);
1054 swap_if(beg, 3, 5, cmpFunc);
1056 swap_if(beg, 0, 1, cmpFunc);
1057 swap_if(beg, 3, 4, cmpFunc);
1058 swap_if(beg, 2, 5, cmpFunc);
1060 swap_if(beg, 0, 3, cmpFunc);
1061 swap_if(beg, 1, 4, cmpFunc);
1063 swap_if(beg, 2, 4, cmpFunc);
1064 swap_if(beg, 1, 3, cmpFunc);
1066 swap_if(beg, 2, 3, cmpFunc);
1067 }
else if (n == 7) {
1068 swap_if(beg, 1, 2, cmpFunc);
1069 swap_if(beg, 3, 4, cmpFunc);
1070 swap_if(beg, 5, 6, cmpFunc);
1072 swap_if(beg, 0, 2, cmpFunc);
1073 swap_if(beg, 3, 5, cmpFunc);
1074 swap_if(beg, 4, 6, cmpFunc);
1076 swap_if(beg, 0, 1, cmpFunc);
1077 swap_if(beg, 4, 5, cmpFunc);
1078 swap_if(beg, 2, 6, cmpFunc);
1080 swap_if(beg, 0, 4, cmpFunc);
1081 swap_if(beg, 1, 5, cmpFunc);
1083 swap_if(beg, 0, 3, cmpFunc);
1084 swap_if(beg, 2, 5, cmpFunc);
1086 swap_if(beg, 1, 3, cmpFunc);
1087 swap_if(beg, 2, 4, cmpFunc);
1089 swap_if(beg, 2, 3, cmpFunc);
1090 }
else if (n == 8) {
1091 swap_if(beg, 0, 1, cmpFunc);
1092 swap_if(beg, 2, 3, cmpFunc);
1093 swap_if(beg, 4, 5, cmpFunc);
1094 swap_if(beg, 6, 7, cmpFunc);
1096 swap_if(beg, 0, 2, cmpFunc);
1097 swap_if(beg, 1, 3, cmpFunc);
1098 swap_if(beg, 4, 6, cmpFunc);
1099 swap_if(beg, 5, 7, cmpFunc);
1101 swap_if(beg, 1, 2, cmpFunc);
1102 swap_if(beg, 5, 6, cmpFunc);
1103 swap_if(beg, 0, 4, cmpFunc);
1104 swap_if(beg, 3, 7, cmpFunc);
1106 swap_if(beg, 1, 5, cmpFunc);
1107 swap_if(beg, 2, 6, cmpFunc);
1109 swap_if(beg, 1, 4, cmpFunc);
1110 swap_if(beg, 3, 6, cmpFunc);
1112 swap_if(beg, 2, 4, cmpFunc);
1113 swap_if(beg, 3, 5, cmpFunc);
1115 swap_if(beg, 3, 4, cmpFunc);
1116 }
else if (n == 9) {
1117 swap_if(beg, 0, 1, cmpFunc);
1118 swap_if(beg, 3, 4, cmpFunc);
1119 swap_if(beg, 6, 7, cmpFunc);
1120 swap_if(beg, 1, 2, cmpFunc);
1121 swap_if(beg, 4, 5, cmpFunc);
1122 swap_if(beg, 7, 8, cmpFunc);
1123 swap_if(beg, 0, 1, cmpFunc);
1124 swap_if(beg, 3, 4, cmpFunc);
1125 swap_if(beg, 6, 7, cmpFunc);
1126 swap_if(beg, 0, 3, cmpFunc);
1127 swap_if(beg, 3, 6, cmpFunc);
1128 swap_if(beg, 0, 3, cmpFunc);
1129 swap_if(beg, 1, 4, cmpFunc);
1130 swap_if(beg, 4, 7, cmpFunc);
1131 swap_if(beg, 1, 4, cmpFunc);
1132 swap_if(beg, 2, 5, cmpFunc);
1133 swap_if(beg, 5, 8, cmpFunc);
1134 swap_if(beg, 2, 5, cmpFunc);
1135 swap_if(beg, 1, 3, cmpFunc);
1136 swap_if(beg, 5, 7, cmpFunc);
1137 swap_if(beg, 2, 6, cmpFunc);
1138 swap_if(beg, 4, 6, cmpFunc);
1139 swap_if(beg, 2, 4, cmpFunc);
1140 swap_if(beg, 2, 3, cmpFunc);
1141 swap_if(beg, 5, 6, cmpFunc);
1142 }
else if (n == 10) {
1143 swap_if(beg, 0, 8, cmpFunc);
1144 swap_if(beg, 1, 9, cmpFunc);
1145 swap_if(beg, 2, 7, cmpFunc);
1146 swap_if(beg, 3, 6, cmpFunc);
1147 swap_if(beg, 4, 5, cmpFunc);
1149 swap_if(beg, 0, 2, cmpFunc);
1150 swap_if(beg, 1, 3, cmpFunc);
1151 swap_if(beg, 4, 8, cmpFunc);
1152 swap_if(beg, 5, 7, cmpFunc);
1153 swap_if(beg, 6, 9, cmpFunc);
1155 swap_if(beg, 0, 4, cmpFunc);
1156 swap_if(beg, 1, 5, cmpFunc);
1157 swap_if(beg, 2, 6, cmpFunc);
1158 swap_if(beg, 3, 7, cmpFunc);
1160 swap_if(beg, 0, 1, cmpFunc);
1161 swap_if(beg, 2, 3, cmpFunc);
1162 swap_if(beg, 4, 6, cmpFunc);
1163 swap_if(beg, 5, 9, cmpFunc);
1164 swap_if(beg, 7, 8, cmpFunc);
1166 swap_if(beg, 1, 2, cmpFunc);
1167 swap_if(beg, 3, 5, cmpFunc);
1168 swap_if(beg, 6, 7, cmpFunc);
1169 swap_if(beg, 8, 9, cmpFunc);
1171 swap_if(beg, 2, 4, cmpFunc);
1172 swap_if(beg, 3, 6, cmpFunc);
1173 swap_if(beg, 5, 8, cmpFunc);
1175 swap_if(beg, 1, 2, cmpFunc);
1176 swap_if(beg, 3, 4, cmpFunc);
1177 swap_if(beg, 5, 6, cmpFunc);
1178 swap_if(beg, 7, 8, cmpFunc);
1179 }
else if (n <= 32) {
1180 for (uint32_t i = 0; i < n - 1; ++i)
1181 for (uint32_t j = 0; j < n - i - 1; ++j)
1182 swap_if(beg, j, j + 1, cmpFunc);
1188 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
1189 bool sort_nwk(T* beg, T* end, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1190 const auto n = (uint32_t)(end - beg);
1193 }
else if (n == 2) {
1194 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1195 }
else if (n == 3) {
1196 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1197 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1198 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1199 }
else if (n == 4) {
1200 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1201 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1203 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1204 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1206 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1207 }
else if (n == 5) {
1208 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1209 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1211 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1213 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1214 try_swap_if(beg, 1, 4, cmpFunc, swapFunc);
1216 try_swap_if(beg, 0, 3, cmpFunc, swapFunc);
1218 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1219 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1221 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1222 }
else if (n == 6) {
1223 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1224 try_swap_if(beg, 4, 5, cmpFunc, swapFunc);
1226 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1227 try_swap_if(beg, 3, 5, cmpFunc, swapFunc);
1229 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1230 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1231 try_swap_if(beg, 2, 5, cmpFunc, swapFunc);
1233 try_swap_if(beg, 0, 3, cmpFunc, swapFunc);
1234 try_swap_if(beg, 1, 4, cmpFunc, swapFunc);
1236 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1237 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1239 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1240 }
else if (n == 7) {
1241 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1242 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1243 try_swap_if(beg, 5, 6, cmpFunc, swapFunc);
1245 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1246 try_swap_if(beg, 3, 5, cmpFunc, swapFunc);
1247 try_swap_if(beg, 4, 6, cmpFunc, swapFunc);
1249 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1250 try_swap_if(beg, 4, 5, cmpFunc, swapFunc);
1251 try_swap_if(beg, 2, 6, cmpFunc, swapFunc);
1253 try_swap_if(beg, 0, 4, cmpFunc, swapFunc);
1254 try_swap_if(beg, 1, 5, cmpFunc, swapFunc);
1256 try_swap_if(beg, 0, 3, cmpFunc, swapFunc);
1257 try_swap_if(beg, 2, 5, cmpFunc, swapFunc);
1259 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1260 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1262 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1263 }
else if (n == 8) {
1264 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1265 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1266 try_swap_if(beg, 4, 5, cmpFunc, swapFunc);
1267 try_swap_if(beg, 6, 7, cmpFunc, swapFunc);
1269 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1270 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1271 try_swap_if(beg, 4, 6, cmpFunc, swapFunc);
1272 try_swap_if(beg, 5, 7, cmpFunc, swapFunc);
1274 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1275 try_swap_if(beg, 5, 6, cmpFunc, swapFunc);
1276 try_swap_if(beg, 0, 4, cmpFunc, swapFunc);
1277 try_swap_if(beg, 3, 7, cmpFunc, swapFunc);
1279 try_swap_if(beg, 1, 5, cmpFunc, swapFunc);
1280 try_swap_if(beg, 2, 6, cmpFunc, swapFunc);
1282 try_swap_if(beg, 1, 4, cmpFunc, swapFunc);
1283 try_swap_if(beg, 3, 6, cmpFunc, swapFunc);
1285 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1286 try_swap_if(beg, 3, 5, cmpFunc, swapFunc);
1288 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1289 }
else if (n == 9) {
1290 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1291 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1292 try_swap_if(beg, 6, 7, cmpFunc, swapFunc);
1293 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1294 try_swap_if(beg, 4, 5, cmpFunc, swapFunc);
1295 try_swap_if(beg, 7, 8, cmpFunc, swapFunc);
1296 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1297 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1298 try_swap_if(beg, 6, 7, cmpFunc, swapFunc);
1299 try_swap_if(beg, 0, 3, cmpFunc, swapFunc);
1300 try_swap_if(beg, 3, 6, cmpFunc, swapFunc);
1301 try_swap_if(beg, 0, 3, cmpFunc, swapFunc);
1302 try_swap_if(beg, 1, 4, cmpFunc, swapFunc);
1303 try_swap_if(beg, 4, 7, cmpFunc, swapFunc);
1304 try_swap_if(beg, 1, 4, cmpFunc, swapFunc);
1305 try_swap_if(beg, 2, 5, cmpFunc, swapFunc);
1306 try_swap_if(beg, 5, 8, cmpFunc, swapFunc);
1307 try_swap_if(beg, 2, 5, cmpFunc, swapFunc);
1308 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1309 try_swap_if(beg, 5, 7, cmpFunc, swapFunc);
1310 try_swap_if(beg, 2, 6, cmpFunc, swapFunc);
1311 try_swap_if(beg, 4, 6, cmpFunc, swapFunc);
1312 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1313 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1314 try_swap_if(beg, 5, 6, cmpFunc, swapFunc);
1315 }
else if (n == 10) {
1316 try_swap_if(beg, 0, 8, cmpFunc, swapFunc);
1317 try_swap_if(beg, 1, 9, cmpFunc, swapFunc);
1318 try_swap_if(beg, 2, 7, cmpFunc, swapFunc);
1319 try_swap_if(beg, 3, 6, cmpFunc, swapFunc);
1320 try_swap_if(beg, 4, 5, cmpFunc, swapFunc);
1322 try_swap_if(beg, 0, 2, cmpFunc, swapFunc);
1323 try_swap_if(beg, 1, 3, cmpFunc, swapFunc);
1324 try_swap_if(beg, 4, 8, cmpFunc, swapFunc);
1325 try_swap_if(beg, 5, 7, cmpFunc, swapFunc);
1326 try_swap_if(beg, 6, 9, cmpFunc, swapFunc);
1328 try_swap_if(beg, 0, 4, cmpFunc, swapFunc);
1329 try_swap_if(beg, 1, 5, cmpFunc, swapFunc);
1330 try_swap_if(beg, 2, 6, cmpFunc, swapFunc);
1331 try_swap_if(beg, 3, 7, cmpFunc, swapFunc);
1333 try_swap_if(beg, 0, 1, cmpFunc, swapFunc);
1334 try_swap_if(beg, 2, 3, cmpFunc, swapFunc);
1335 try_swap_if(beg, 4, 6, cmpFunc, swapFunc);
1336 try_swap_if(beg, 5, 9, cmpFunc, swapFunc);
1337 try_swap_if(beg, 7, 8, cmpFunc, swapFunc);
1339 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1340 try_swap_if(beg, 3, 5, cmpFunc, swapFunc);
1341 try_swap_if(beg, 6, 7, cmpFunc, swapFunc);
1342 try_swap_if(beg, 8, 9, cmpFunc, swapFunc);
1344 try_swap_if(beg, 2, 4, cmpFunc, swapFunc);
1345 try_swap_if(beg, 3, 6, cmpFunc, swapFunc);
1346 try_swap_if(beg, 5, 8, cmpFunc, swapFunc);
1348 try_swap_if(beg, 1, 2, cmpFunc, swapFunc);
1349 try_swap_if(beg, 3, 4, cmpFunc, swapFunc);
1350 try_swap_if(beg, 5, 6, cmpFunc, swapFunc);
1351 try_swap_if(beg, 7, 8, cmpFunc, swapFunc);
1352 }
else if (n <= 32) {
1353 for (uint32_t i = 0; i < n - 1; ++i)
1354 for (uint32_t j = 0; j < n - i - 1; ++j)
1355 try_swap_if(beg, j, j + 1, cmpFunc, swapFunc);
1362 template <
typename Container,
typename TCmpFunc>
1363 void quick_sort(Container& arr,
int low,
int high, TCmpFunc cmpFunc) {
1366 auto pos = detail::quick_sort_partition(arr, low, high, cmpFunc);
1367 quick_sort(arr, low, pos - 1, cmpFunc);
1368 quick_sort(arr, pos + 1, high, cmpFunc);
1371 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1372 void quick_sort(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1375 auto pos = detail::quick_sort_partition(arr, low, high, cmpFunc, swapFunc);
1376 quick_sort(arr, low, pos - 1, cmpFunc, swapFunc);
1377 quick_sort(arr, pos + 1, high, cmpFunc, swapFunc);
1394 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1396 quick_sort_stack(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc, uint32_t maxStackSize) {
1397 GAIA_ASSERT(high < (
int)arr.size() &&
"quick_sort_stack: 'high' has to be smaller than the container size.");
1399 (uint32_t)arr.size() <= maxStackSize &&
"quick_sort_stack: used with too large input array. Stack overflow.");
1405 auto* stack = (Range*)alloca(
sizeof(Range) * maxStackSize);
1406 GAIA_ASSERT(stack !=
nullptr &&
"quick_sort_stack: failed to allocate stack memory.");
1408 stack[sp++] = {low, high};
1410 auto median_of_three = [&](
int a,
int b,
int c) {
1411 if (cmpFunc(arr[a], arr[b])) {
1412 if (cmpFunc(arr[b], arr[c]))
1414 if (cmpFunc(arr[a], arr[c]))
1419 if (cmpFunc(arr[a], arr[c]))
1421 if (cmpFunc(arr[b], arr[c]))
1427 const Range r = stack[--sp];
1428 if (r.low >= r.high)
1432 const auto size = r.high - r.low + 1;
1434 auto* base = &arr[r.low];
1435 detail::sort_nwk(base, base + size, cmpFunc, [&](uint32_t i, uint32_t j) {
1436 swapFunc(r.low + i, r.low + j);
1442 int mid = r.low + ((r.high - r.low) >> 1);
1443 int pivotIdx = median_of_three(r.low, mid, r.high);
1444 swapFunc(pivotIdx, r.high);
1446 const auto& pivot = arr[r.high];
1448 for (
int j = r.low; j < r.high; ++j) {
1449 if (cmpFunc(arr[j], pivot))
1452 swapFunc(++i, r.high);
1455 if (i - 1 - r.low > r.high - (i + 1)) {
1457 stack[sp++] = {r.low, i - 1};
1459 stack[sp++] = {i + 1, r.high};
1462 stack[sp++] = {i + 1, r.high};
1464 stack[sp++] = {r.low, i - 1};
1482 template <
typename Container,
typename TCmpFunc>
1483 void quick_sort_stack(Container& arr,
int low,
int high, TCmpFunc cmpFunc, uint32_t maxStackSize) {
1485 arr, low, high, cmpFunc,
1486 [&arr](uint32_t a, uint32_t b) {
1487 core::swap(arr[a], arr[b]);
1501 template <
typename T,
typename TCmpFunc>
1502 void sort(T* beg, T* end, TCmpFunc cmpFunc) {
1503 const auto n = (uintptr_t)(end - beg);
1504 if (detail::sort_nwk(beg, end, cmpFunc))
1507 quick_sort(beg, 0, (
int)n - 1, cmpFunc);
1510 template <
typename C,
typename TCmpFunc>
1511 void sort(C& c, TCmpFunc cmpFunc) {
1512 sort(c.begin(), c.end(), cmpFunc);
1527 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
1528 void sort(T* beg, T* end, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1529 const auto n = (uintptr_t)(end - beg);
1530 if (detail::sort_nwk(beg, end, cmpFunc, swapFunc))
1533 quick_sort(beg, 0, (
int)n - 1, cmpFunc, swapFunc);
1536 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
1537 void sort(C& c, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1538 sort(c.begin(), c.end(), cmpFunc, swapFunc);
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9