2#include "gaia/config/config.h"
10#if GAIA_PLATFORM_WINDOWS
16#include "gaia/core/iterator.h"
20 constexpr uint32_t BadIndex = uint32_t(-1);
22#if GAIA_COMPILER_MSVC || GAIA_PLATFORM_WINDOWS
23 #define GAIA_STRCPY(var, max_len, text) \
24 strncpy_s((var), (text), (max_len)); \
25 (var)[(max_len) - 1] = 0;
26 #define GAIA_STRFMT(var, max_len, fmt, ...) sprintf_s((var), (max_len), fmt, __VA_ARGS__)
27 #define GAIA_STRLEN(var, max_len) strnlen_s((var), (max_len))
29 #define GAIA_STRCPY(var, max_len, text) \
31 strncpy((var), (text), (max_len)); \
32 (var)[(max_len) - 1] = 0; \
34 #define GAIA_STRFMT(var, max_len, fmt, ...) snprintf((var), (max_len), fmt, __VA_ARGS__)
35 #define GAIA_STRLEN(var, max_len) strnlen((var), (max_len))
53 using type = std::remove_reference_t<std::remove_pointer_t<T>>;
61 !std::is_const_v<typename rem_rp<T>::type> &&
62 (std::is_pointer<T>::value || std::is_reference<T>::value)> {};
67 template <
typename Type,
typename SizeProbe =
size_t>
68 struct is_complete: std::false_type {};
73 struct is_complete<T, decltype(sizeof(T))>: std::true_type {};
80 constexpr auto size(C& c)
noexcept ->
decltype(c.size()) {
88 constexpr auto size(
const C& c)
noexcept ->
decltype(c.size()) {
95 template <
typename T, auto N>
96 constexpr auto size(
const T (&)[N])
noexcept {
104 template <
typename C>
105 constexpr auto data(C& c)
noexcept ->
decltype(c.data()) {
112 template <
typename C>
113 constexpr auto data(
const C& c)
noexcept ->
decltype(c.data()) {
121 template <
typename T, auto N>
122 constexpr T* data(T (&array)[N])
noexcept {
130 explicit constexpr zero_t() =
default;
134 inline constexpr zero_t zero{};
138 template <
typename T>
139 using rem_rp_t =
typename detail::rem_rp<T>::type;
143 template <
typename T>
144 inline constexpr bool is_mut_v = detail::is_mut<T>::value;
148 template <
typename T>
149 using raw_t =
typename std::decay_t<std::remove_pointer_t<T>>;
153 template <
typename T>
154 inline constexpr bool is_raw_v = std::is_same_v<T, raw_t<T>> && !std::is_array_v<T>;
158 template <
typename T>
159 inline constexpr bool is_complete_v = detail::is_complete<T>::value;
165 template <
typename T>
166 constexpr T* addressof(T& obj)
noexcept {
172 template <
typename T>
173 const T* addressof(
const T&&) =
delete;
179 template <
typename T>
180 constexpr bool check_alignment(
const T* ptr)
noexcept {
181 return (
reinterpret_cast<uintptr_t
>(ptr)) %
alignof(T) == 0;
186 template <
typename T>
218 template <
typename T,
typename Probe =
void>
223 template <
typename T>
226 decltype(detail::data(std::declval<T>())),
227 decltype(detail::size(std::declval<T>()))
228 >>: std::true_type {};
233 template <
typename T,
typename Probe =
void>
238 template <
typename T>
241 decltype(std::declval<T>().begin()),
242 decltype(std::declval<T>().end()),
243 decltype(detail::size(std::declval<T>()))
244 >>: std::true_type {};
254 template <
typename T>
255 constexpr T as_bits(T value) {
256 static_assert(std::is_integral_v<T>);
264 template <
typename T>
265 constexpr T as_bytes(T value) {
266 static_assert(std::is_integral_v<T>);
278 template <
typename T>
279 constexpr uint32_t count_bits(T number) {
280 uint32_t bits_needed = 0;
281 while (number > 0U) {
292 template <
typename T>
293 constexpr bool is_pow2(T number) {
294 static_assert(std::is_integral<T>::value,
"is_pow2 must be used with integer types");
296 return (number & (number - 1)) == 0;
303 template <
typename T>
304 constexpr T closest_pow2(T number) {
305 static_assert(std::is_integral<T>::value,
"closest_pow2 must be used with integer types");
311 number |= number >> 1;
312 number |= number >> 2;
313 number |= number >> 4;
314 if constexpr (
sizeof(T) > 1)
315 number |= number >> 8;
316 if constexpr (
sizeof(T) > 2)
317 number |= number >> 16;
318 if constexpr (
sizeof(T) > 4)
319 number |= number >> 32;
322 return number - (number >> 1);
332 template <
typename T>
333 void call_ctor_raw(T* pData) {
334 GAIA_ASSERT(pData !=
nullptr);
335 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*pData)))) T;
342 template <
typename T>
343 void call_ctor_raw_n(T* pData,
size_t cnt) {
344 GAIA_ASSERT(pData !=
nullptr);
345 for (
size_t i = 0; i < cnt; ++i) {
346 auto* ptr = pData + i;
347 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*ptr)))) T;
354 template <
typename T>
355 void call_ctor_val(T* pData) {
356 GAIA_ASSERT(pData !=
nullptr);
357 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*pData)))) T();
364 template <
typename T>
365 void call_ctor_val_n(T* pData,
size_t cnt) {
366 GAIA_ASSERT(pData !=
nullptr);
367 for (
size_t i = 0; i < cnt; ++i) {
368 auto* ptr = pData + i;
369 (void)::new (
const_cast<void*
>(
static_cast<const volatile void*
>(core::addressof(*ptr)))) T();
377 template <
typename T>
378 void call_ctor([[maybe_unused]] T* pData) {
379 GAIA_ASSERT(pData !=
nullptr);
380 if constexpr (!std::is_trivially_constructible_v<T>) {
381 (void)::new (pData) T();
389 template <
typename T>
390 void call_ctor_n([[maybe_unused]] T* pData, [[maybe_unused]]
size_t cnt) {
391 GAIA_ASSERT(pData !=
nullptr);
392 if constexpr (!std::is_trivially_constructible_v<T>) {
393 for (
size_t i = 0; i < cnt; ++i)
394 (
void)::new (pData + i) T();
403 template <
typename T,
typename... Args>
404 void call_ctor(T* pData, Args&&... args) {
405 GAIA_ASSERT(pData !=
nullptr);
406 if constexpr (std::is_constructible_v<T, Args...>)
407 (
void)::new (pData) T(GAIA_FWD(args)...);
409 (
void)::new (pData) T{GAIA_FWD(args)...};
416 template <
typename T>
417 void call_dtor([[maybe_unused]] T* pData) {
418 GAIA_ASSERT(pData !=
nullptr);
419 if constexpr (!std::is_trivially_destructible_v<T>) {
428 template <
typename T>
429 void call_dtor_n([[maybe_unused]] T* pData, [[maybe_unused]]
size_t cnt) {
430 GAIA_ASSERT(pData !=
nullptr);
431 if constexpr (!std::is_trivially_destructible_v<T>) {
432 for (
size_t i = 0; i < cnt; ++i)
445 template <
typename T>
446 constexpr void swap(T& left, T& right) {
447 T tmp = GAIA_MOV(left);
448 left = GAIA_MOV(right);
449 right = GAIA_MOV(tmp);
459 template <
typename T,
typename TCmpFunc>
460 constexpr void swap_if(T* c,
size_t lhs,
size_t rhs, TCmpFunc cmpFunc)
noexcept {
461 if (!cmpFunc(c[lhs], c[rhs]))
462 core::swap(c[lhs], c[rhs]);
471 template <
typename T,
typename TCmpFunc>
472 constexpr void swap_if(T& lhs, T& rhs, TCmpFunc cmpFunc)
noexcept {
473 if (!cmpFunc(lhs, rhs))
474 core::swap(lhs, rhs);
483 template <
typename T,
typename TCmpFunc>
484 constexpr void swap_if_not(T& lhs, T& rhs, TCmpFunc cmpFunc)
noexcept {
485 if (cmpFunc(lhs, rhs))
486 core::swap(lhs, rhs);
498 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
499 constexpr void try_swap_if(T* c, uint32_t lhs, uint32_t rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
500 if (!cmpFunc(c[lhs], c[rhs]))
513 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
514 constexpr void try_swap_if(
515 C& c,
typename C::size_type lhs,
typename C::size_type rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
516 if (!cmpFunc(c[lhs], c[rhs]))
529 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
530 constexpr void try_swap_if_not(
531 C& c,
typename C::size_type lhs,
typename C::size_type rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc)
noexcept {
532 if (cmpFunc(c[lhs], c[rhs]))
546 template <
class ForwardIt,
class T>
547 constexpr void fill(ForwardIt first, ForwardIt last,
const T& value) {
548 for (; first != last; ++first) {
563 constexpr const T& get_min(
const T& a,
const T& b) {
564 return (b < a) ? b : a;
573 constexpr const T& get_max(
const T& a,
const T& b) {
574 return (b > a) ? b : a;
583 template <
typename... Types>
584 inline constexpr auto is_unique = std::true_type{};
589 template <
typename T,
typename... Rest>
590 inline constexpr auto is_unique<T, Rest...> =
591 std::bool_constant<(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>>{};
597 template <
typename T>
598 struct type_identity {
608 template <
typename T,
typename... Ts>
609 struct unique: detail::type_identity<T> {};
615 template <
typename... Ts,
typename U,
typename... Us>
616 struct unique<std::tuple<Ts...>, U, Us...>:
618 (std::is_same_v<U, Ts> || ...), unique<std::tuple<Ts...>, Us...>, unique<std::tuple<Ts..., U>, Us...>> {};
622 template <
typename... Ts>
633 template <
typename... Args>
634 constexpr unsigned get_args_size(std::tuple<Args...>
const& tuple) {
636 return (
sizeof(Args) + ...);
645 template <
typename... Type>
653 template <
typename Class,
typename Ret,
typename... Args>
661 #define GAIA_DEFINE_HAS_MEMBER_FUNC(function_name) \
662 template <typename T, typename... Args> \
663 concept has_mfunc_check_##function_name = requires(T&& t, Args&&... args) { t.function_name(GAIA_FWD(args)...); }; \
665 template <typename T, typename... Args> \
666 struct has_func_##function_name { \
667 static constexpr bool value = has_mfunc_check_##function_name<T, Args...>; \
677 template <
class Default,
class AlwaysVoid,
template <
class...>
class Op,
class... Args>
678 struct member_func_checker {
680 using value_t = std::false_type;
682 using type = Default;
689 template <
class Default,
template <
class...>
class Op,
class... Args>
690 struct member_func_checker<Default, std::void_t<Op<Args...>>, Op, Args...> {
692 using value_t = std::true_type;
694 using type = Op<Args...>;
698 struct member_func_none {
699 ~member_func_none() =
delete;
700 member_func_none(member_func_none
const&) =
delete;
701 member_func_none(member_func_none&&) =
delete;
702 void operator=(member_func_none
const&) =
delete;
703 void operator=(member_func_none&&) =
delete;
711 template <
template <
class...>
class Op,
typename... Args>
712 using has_mfunc =
typename detail::member_func_checker<detail::member_func_none, void, Op, Args...>::value_t;
714 #define GAIA_DEFINE_HAS_MEMBER_FUNC(function_name) \
715 template <typename T, typename... Args> \
716 using has_mfunc_check_##function_name = decltype(std::declval<T>().function_name(std::declval<Args>()...)); \
718 template <typename T, typename... Args> \
719 struct has_func_##function_name { \
720 static constexpr bool value = gaia::core::has_mfunc<has_mfunc_check_##function_name, T, Args...>::value; \
725 GAIA_DEFINE_HAS_MEMBER_FUNC(find);
726 GAIA_DEFINE_HAS_MEMBER_FUNC(find_if);
727 GAIA_DEFINE_HAS_MEMBER_FUNC(find_if_not);
739 template <
typename T>
740 constexpr auto has_mfunc_equals_check(
int)
741 ->
decltype(std::declval<T>().operator==(std::declval<T>()), std::true_type{});
746 template <
typename T,
typename... Args>
747 constexpr std::false_type has_mfunc_equals_check(...);
752 template <
typename T>
753 constexpr auto has_ffunc_equals_check(
int)
754 ->
decltype(operator==(std::declval<T>(), std::declval<T>()), std::true_type{});
759 template <
typename T,
typename... Args>
760 constexpr std::false_type has_ffunc_equals_check(...);
766 template <
typename T>
769 static constexpr bool value =
decltype(detail::has_mfunc_equals_check<T>(0))
::value;
774 template <
typename T>
777 static constexpr bool value =
decltype(detail::has_ffunc_equals_check<T>(0))
::value;
786 template <
typename... Type>
791 static constexpr auto size =
sizeof...(Type);
797 template <
typename TypesA,
typename TypesB>
803 template <
typename... TypesA,
typename... TypesB>
821 template <
auto FirstIdx,
auto Iters,
typename Func,
auto... Is>
822 constexpr void each_impl(Func func, std::integer_sequence<
decltype(Iters), Is...> ) {
823 if constexpr ((std::is_invocable_v<Func&&, std::integral_constant<
decltype(Is), Is>> && ...))
824 (func(std::integral_constant<
decltype(Is), FirstIdx + Is>{}), ...);
826 (((
void)Is, func()), ...);
835 template <
auto FirstIdx,
typename Tuple,
typename Func,
auto... Is>
836 void each_tuple_impl(Func func, std::integer_sequence<
decltype(FirstIdx), Is...> ) {
838 (std::is_invocable_v<
839 Func&&,
decltype(std::tuple_element_t<FirstIdx + Is, Tuple>{}),
840 std::integral_constant<
decltype(FirstIdx), Is>> &&
844 std::tuple_element_t<FirstIdx + Is, Tuple>{},
845 std::integral_constant<
decltype(FirstIdx), FirstIdx + Is>{}),
849 (func(std::tuple_element_t<FirstIdx + Is, Tuple>{}), ...);
859 template <
auto FirstIdx,
typename Tuple,
typename Func,
auto... Is>
860 void each_tuple_impl(Tuple&& tuple, Func func, std::integer_sequence<
decltype(FirstIdx), Is...> ) {
862 (std::is_invocable_v<
863 Func&&,
decltype(std::get<FirstIdx + Is>(tuple)), std::integral_constant<
decltype(FirstIdx), Is>> &&
866 (func(std::get<FirstIdx + Is>(tuple), std::integral_constant<
decltype(FirstIdx), FirstIdx + Is>{}), ...);
869 (func(std::get<FirstIdx + Is>(tuple)), ...);
890 template <auto Iters,
typename Func>
891 constexpr void each(Func func) {
892 using TIters =
decltype(Iters);
893 constexpr TIters First = 0;
894 detail::each_impl<First, Iters, Func>(func, std::make_integer_sequence<TIters, Iters>());
915 template <auto FirstIdx, auto LastIdx,
typename Func>
916 constexpr void each_ext(Func func) {
917 static_assert(LastIdx >= FirstIdx);
918 const auto Iters = LastIdx - FirstIdx;
919 detail::each_impl<FirstIdx, Iters, Func>(func, std::make_integer_sequence<
decltype(Iters), Iters>());
941 template <auto FirstIdx, auto LastIdx, auto Inc,
typename Func>
942 constexpr void each_ext(Func func) {
943 if constexpr (FirstIdx < LastIdx) {
944 if constexpr (std::is_invocable_v<Func&&, std::integral_constant<
decltype(FirstIdx), FirstIdx>>)
945 func(std::integral_constant<
decltype(FirstIdx), FirstIdx>());
949 each_ext<FirstIdx + Inc, LastIdx, Inc>(func);
967 template <
typename Func,
typename... Args>
968 constexpr void each_pack(Func func, Args&&... args) {
969 (func(GAIA_FWD(args)), ...);
989 template <
typename Tuple,
typename Func>
990 constexpr void each_tuple(Tuple&& tuple, Func func) {
991 using TTSize = uint32_t;
992 constexpr auto TSize = (TTSize)std::tuple_size<std::remove_reference_t<Tuple>>::value;
993 detail::each_tuple_impl<(TTSize)0>(GAIA_FWD(tuple), func, std::make_integer_sequence<TTSize, TSize>{});
1014 template <
typename Tuple,
typename Func>
1015 constexpr void each_tuple(Func func) {
1016 using TTSize = uint32_t;
1017 constexpr auto TSize = (TTSize)std::tuple_size<std::remove_reference_t<Tuple>>::value;
1018 detail::each_tuple_impl<(TTSize)0, Tuple>(func, std::make_integer_sequence<TTSize, TSize>{});
1040 template <auto FirstIdx, auto LastIdx,
typename Tuple,
typename Func>
1041 constexpr void each_tuple_ext(Tuple&& tuple, Func func) {
1042 constexpr auto TSize = std::tuple_size<std::remove_reference_t<Tuple>>::value;
1043 static_assert(LastIdx >= FirstIdx);
1044 static_assert(LastIdx <= TSize);
1045 constexpr auto Iters = LastIdx - FirstIdx;
1046 detail::each_tuple_impl<FirstIdx>(GAIA_FWD(tuple), func, std::make_integer_sequence<
decltype(FirstIdx), Iters>{});
1069 template <auto FirstIdx, auto LastIdx,
typename Tuple,
typename Func>
1070 constexpr void each_tuple_ext(Func func) {
1071 constexpr auto TSize = std::tuple_size<std::remove_reference_t<Tuple>>::value;
1072 static_assert(LastIdx >= FirstIdx);
1073 static_assert(LastIdx <= TSize);
1074 constexpr auto Iters = LastIdx - FirstIdx;
1075 detail::each_tuple_impl<FirstIdx, Tuple>(func, std::make_integer_sequence<
decltype(FirstIdx), Iters>{});
1085 template <
typename InputIt,
typename Func>
1086 constexpr Func each(InputIt first, InputIt last, Func func) {
1087 for (; first != last; ++first)
1098 template <
typename C,
typename Func>
1099 constexpr auto each(
const C& arr, Func func) {
1100 return each(arr.begin(), arr.end(), func);
1114 template <
typename InputIt,
typename T>
1115 constexpr InputIt find(InputIt first, InputIt last,
const T& value) {
1116 if constexpr (std::is_pointer_v<InputIt>) {
1117 auto size = distance(first, last);
1119 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1123 }
else if constexpr (is_random_iter_v<InputIt>) {
1124 auto size = distance(first, last);
1126 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1131 for (; first != last; ++first) {
1132 if (*first == value)
1145 template <
typename C,
typename V>
1146 constexpr auto find(
const C& arr,
const V& item) {
1147 if constexpr (has_func_find<C>::value)
1148 return arr.find(item);
1150 return core::find(arr.begin(), arr.end(), item);
1160 template <
typename InputIt,
typename Func>
1161 constexpr InputIt find_if(InputIt first, InputIt last, Func func) {
1162 if constexpr (std::is_pointer_v<InputIt>) {
1163 auto size = distance(first, last);
1165 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1169 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
1170 auto size = distance(first, last);
1172 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1177 for (; first != last; ++first) {
1191 template <
typename UnaryPredicate,
typename C>
1192 constexpr auto find_if(
const C& arr, UnaryPredicate predicate) {
1193 if constexpr (has_func_find_if<C, UnaryPredicate>::value)
1194 return arr.find_id(predicate);
1196 return core::find_if(arr.begin(), arr.end(), predicate);
1206 template <
typename InputIt,
typename Func>
1207 constexpr InputIt find_if_not(InputIt first, InputIt last, Func func) {
1208 if constexpr (std::is_pointer_v<InputIt>) {
1209 auto size = distance(first, last);
1211 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1215 }
else if constexpr (std::is_same_v<typename InputIt::iterator_category, core::random_access_iterator_tag>) {
1216 auto size = distance(first, last);
1218 for (
decltype(size) i = 0; i < size; ++i, ++it) {
1223 for (; first != last; ++first) {
1237 template <
typename UnaryPredicate,
typename C>
1238 constexpr auto find_if_not(
const C& arr, UnaryPredicate predicate) {
1239 if constexpr (has_func_find_if_not<C, UnaryPredicate>::value)
1240 return arr.find_if_not(predicate);
1242 return core::find_if_not(arr.begin(), arr.end(), predicate);
1253 template <
typename C,
typename V>
1254 constexpr bool has(
const C& arr,
const V& item) {
1255 const auto it = find(arr, item);
1256 return it != arr.end();
1265 template <
typename UnaryPredicate,
typename C>
1266 constexpr bool has_if(
const C& arr, UnaryPredicate predicate) {
1267 const auto it = find_if(arr, predicate);
1268 return it != arr.end();
1278 template <
typename C>
1279 constexpr auto get_index(
const C& arr,
typename C::const_reference item) {
1280 const auto it = find(arr, item);
1281 if (it == arr.end())
1284 return (
decltype(BadIndex))core::distance(arr.begin(), it);
1293 template <
typename C>
1294 constexpr auto get_index_unsafe(
const C& arr,
typename C::const_reference item) {
1295 return (
decltype(BadIndex))core::distance(arr.begin(), find(arr, item));
1304 template <
typename UnaryPredicate,
typename C>
1305 constexpr auto get_index_if(
const C& arr, UnaryPredicate predicate) {
1306 const auto it = find_if(arr, predicate);
1307 if (it == arr.end())
1310 return (
decltype(BadIndex))core::distance(arr.begin(), it);
1320 template <
typename UnaryPredicate,
typename C>
1321 constexpr auto get_index_if_unsafe(
const C& arr, UnaryPredicate predicate) {
1322 return (
decltype(BadIndex))core::distance(arr.begin(), find_if(arr, predicate));
1337 template <
typename C>
1338 void swap_erase_unsafe(C& arr,
typename C::size_type idx) {
1339 GAIA_ASSERT(idx < arr.size());
1341 if (idx + 1 != arr.size())
1342 arr[idx] = arr[arr.size() - 1];
1354 template <
typename C>
1355 void swap_erase(C& arr,
typename C::size_type idx) {
1356 if (idx >= arr.size())
1359 if (idx + 1 != arr.size())
1360 arr[idx] = arr[arr.size() - 1];
1371 template <
typename T>
1384 template <
typename T>
1397 template <
typename T>
1410 template <
typename T>
1436 template <
typename Container,
typename TCmpFunc>
1437 int sort_median_of_three(Container& arr,
int low,
int mid,
int high, TCmpFunc cmpFunc) {
1438 if (cmpFunc(arr[(uint32_t)low], arr[(uint32_t)mid])) {
1439 if (cmpFunc(arr[(uint32_t)mid], arr[(uint32_t)high]))
1441 return cmpFunc(arr[(uint32_t)low], arr[(uint32_t)high]) ? high : low;
1444 if (cmpFunc(arr[(uint32_t)low], arr[(uint32_t)high]))
1446 return cmpFunc(arr[(uint32_t)mid], arr[(uint32_t)high]) ? high : mid;
1457 template <
typename Container,
typename TCmpFunc>
1458 int sort_choose_pivot(Container& arr,
int low,
int high, TCmpFunc cmpFunc) {
1459 const int size = high - low + 1;
1460 const int mid = low + (size >> 1);
1462 const int step = size >> 3;
1463 const int lowMed = sort_median_of_three(arr, low, low + step, low + step + step, cmpFunc);
1464 const int midMed = sort_median_of_three(arr, mid - step, mid, mid + step, cmpFunc);
1465 const int highMed = sort_median_of_three(arr, high - step - step, high - step, high, cmpFunc);
1466 return sort_median_of_three(arr, lowMed, midMed, highMed, cmpFunc);
1469 return sort_median_of_three(arr, low, mid, high, cmpFunc);
1481 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1482 void insertion_sort_range(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1483 for (
int i = low + 1; i <= high; ++i) {
1484 for (
int j = i; j > low && cmpFunc(arr[(uint32_t)j], arr[(uint32_t)(j - 1)]); --j)
1485 swapFunc((uint32_t)(j - 1), (uint32_t)j);
1498 template <
typename Container,
typename TCmpFunc>
1499 void insertion_sort_range(Container& arr,
int low,
int high, TCmpFunc cmpFunc) {
1500 for (
int i = low + 1; i <= high; ++i) {
1501 if (cmpFunc(arr[(uint32_t)i], arr[(uint32_t)(i - 1)])) {
1502 auto tmp = GAIA_MOV(arr[(uint32_t)i]);
1505 arr[(uint32_t)j] = GAIA_MOV(arr[(uint32_t)(j - 1)]);
1507 }
while (j > low && cmpFunc(tmp, arr[(uint32_t)(j - 1)]));
1508 arr[(uint32_t)j] = GAIA_MOV(tmp);
1523 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1524 void sort_order_three(Container& arr,
int lhs,
int mid,
int rhs, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1525 if (cmpFunc(arr[(uint32_t)mid], arr[(uint32_t)lhs]))
1526 swapFunc((uint32_t)lhs, (uint32_t)mid);
1527 if (cmpFunc(arr[(uint32_t)rhs], arr[(uint32_t)mid])) {
1528 swapFunc((uint32_t)mid, (uint32_t)rhs);
1529 if (cmpFunc(arr[(uint32_t)mid], arr[(uint32_t)lhs]))
1530 swapFunc((uint32_t)lhs, (uint32_t)mid);
1544 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1545 void sort_prepare_pivot_first(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1546 constexpr int NintherThreshold = 128;
1547 const int size = high - low + 1;
1548 const int mid = low + (size >> 1);
1550 if (size > NintherThreshold) {
1551 sort_order_three(arr, low, mid, high, cmpFunc, swapFunc);
1552 sort_order_three(arr, low + 1, mid - 1, high - 1, cmpFunc, swapFunc);
1553 sort_order_three(arr, low + 2, mid + 1, high - 2, cmpFunc, swapFunc);
1554 sort_order_three(arr, mid - 1, mid, mid + 1, cmpFunc, swapFunc);
1555 swapFunc((uint32_t)low, (uint32_t)mid);
1557 sort_order_three(arr, mid, low, high, cmpFunc, swapFunc);
1571 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1572 int quick_sort_partition_pivot_first(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1573 const int begin = low;
1575 int last = high + 1;
1576 const int end = last;
1577 auto pivot = GAIA_MOV(arr[(uint32_t)first]);
1581 }
while (first != end && cmpFunc(arr[(uint32_t)first], pivot));
1583 if (begin == first - 1) {
1584 while (first < last && !cmpFunc(arr[(uint32_t)(--last)], pivot)) {
1589 }
while (!cmpFunc(arr[(uint32_t)last], pivot));
1592 while (first < last) {
1593 swapFunc((uint32_t)first, (uint32_t)last);
1596 }
while (cmpFunc(arr[(uint32_t)first], pivot));
1599 }
while (!cmpFunc(arr[(uint32_t)last], pivot));
1602 const int pivotPos = first - 1;
1603 if (begin != pivotPos)
1604 arr[(uint32_t)begin] = GAIA_MOV(arr[(uint32_t)pivotPos]);
1605 arr[(uint32_t)pivotPos] = GAIA_MOV(pivot);
1618 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
1619 bool try_sorted_or_reversed(T* beg, uint32_t n, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1624 for (uint32_t i = 1; i < n; ++i) {
1625 if (cmpFunc(beg[i], beg[i - 1])) {
1633 bool reversed =
true;
1634 for (uint32_t i = 1; i < n; ++i) {
1635 if (cmpFunc(beg[i - 1], beg[i])) {
1643 for (uint32_t i = 0, j = n - 1; i < j; ++i, --j)
1658 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1659 int quick_sort_partition_hoare(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1660 const int pivotIdx = sort_choose_pivot(arr, low, high, cmpFunc);
1661 const auto pivot = arr[(uint32_t)pivotIdx];
1669 }
while (cmpFunc(arr[(uint32_t)i], pivot));
1673 }
while (cmpFunc(pivot, arr[(uint32_t)j]));
1678 swapFunc((uint32_t)i, (uint32_t)j);
1692 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1693 void heap_sift_down(Container& arr,
int low,
int root,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1695 const int left = low + ((root - low) << 1) + 1;
1700 const int right = left + 1;
1701 if (right <= high && cmpFunc(arr[(uint32_t)child], arr[(uint32_t)right]))
1704 if (!cmpFunc(arr[(uint32_t)root], arr[(uint32_t)child]))
1707 swapFunc((uint32_t)root, (uint32_t)child);
1721 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1722 void heap_sort_range(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
1723 for (
int start = low + ((high - low - 1) >> 1); start >= low; --start)
1724 heap_sift_down(arr, low, start, high, cmpFunc, swapFunc);
1726 for (
int end = high; end > low; --end) {
1727 swapFunc((uint32_t)low, (uint32_t)end);
1728 heap_sift_down(arr, low, low, end - 1, cmpFunc, swapFunc);
1735 inline uint32_t sort_depth_limit(uint32_t n) {
1754 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
1756 quick_sort_impl(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc, uint32_t depthLimit) {
1757 constexpr int InsertionSortThreshold = 24;
1759 while (high - low > InsertionSortThreshold) {
1760 if (depthLimit == 0) {
1761 heap_sort_range(arr, low, high, cmpFunc, swapFunc);
1766 const int split = quick_sort_partition_hoare(arr, low, high, cmpFunc, swapFunc);
1767 const int leftSize = split - low + 1;
1768 const int rightSize = high - split;
1770 if (leftSize < rightSize) {
1771 quick_sort_impl(arr, low, split, cmpFunc, swapFunc, depthLimit);
1774 quick_sort_impl(arr, split + 1, high, cmpFunc, swapFunc, depthLimit);
1780 insertion_sort_range(arr, low, high, cmpFunc, swapFunc);
1793 template <
typename Container,
typename TCmpFunc>
1794 void quick_sort_impl(Container& arr,
int low,
int high, TCmpFunc cmpFunc, uint32_t depthLimit) {
1795 constexpr int InsertionSortThreshold = 24;
1796 auto swapFunc = [&arr](uint32_t a, uint32_t b) {
1797 core::swap(arr[a], arr[b]);
1800 while (high - low > InsertionSortThreshold) {
1801 if (depthLimit == 0) {
1802 heap_sort_range(arr, low, high, cmpFunc, swapFunc);
1807 sort_prepare_pivot_first(arr, low, high, cmpFunc, swapFunc);
1808 const int pivot = quick_sort_partition_pivot_first(arr, low, high, cmpFunc, swapFunc);
1809 const int leftSize = pivot - low;
1810 const int rightSize = high - pivot;
1812 if (leftSize < rightSize) {
1813 quick_sort_impl(arr, low, pivot - 1, cmpFunc, depthLimit);
1816 quick_sort_impl(arr, pivot + 1, high, cmpFunc, depthLimit);
1822 insertion_sort_range(arr, low, high, cmpFunc);
1826 inline constexpr uint32_t SortNetworkMaxN = 17;
1828 inline constexpr uint32_t SortSmallMaxN = 32;
1834 template <u
int32_t N>
1835 struct sort_network;
1837 struct sort_network<2> {
1839 static constexpr uint8_t pairs[][2] = {{0, 1}};
1842 struct sort_network<3> {
1844 static constexpr uint8_t pairs[][2] = {{1, 2}, {0, 2}, {0, 1}};
1847 struct sort_network<4> {
1849 static constexpr uint8_t pairs[][2] = {{0, 1}, {2, 3}, {0, 2}, {1, 3}, {1, 2}};
1852 struct sort_network<5> {
1854 static constexpr uint8_t pairs[][2] = {{0, 1}, {3, 4}, {2, 4}, {2, 3}, {1, 4}, {0, 3}, {0, 2}, {1, 3}, {1, 2}};
1857 struct sort_network<6> {
1859 static constexpr uint8_t pairs[][2] = {{1, 2}, {4, 5}, {0, 2}, {3, 5}, {0, 1}, {3, 4},
1860 {2, 5}, {0, 3}, {1, 4}, {2, 4}, {1, 3}, {2, 3}};
1863 struct sort_network<7> {
1865 static constexpr uint8_t pairs[][2] = {{1, 2}, {3, 4}, {5, 6}, {0, 2}, {3, 5}, {4, 6}, {0, 1}, {4, 5},
1866 {2, 6}, {0, 4}, {1, 5}, {0, 3}, {2, 5}, {1, 3}, {2, 4}, {2, 3}};
1869 struct sort_network<8> {
1871 static constexpr uint8_t pairs[][2] = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {0, 2}, {1, 3}, {4, 6},
1872 {5, 7}, {1, 2}, {5, 6}, {0, 4}, {3, 7}, {1, 5}, {2, 6},
1873 {1, 4}, {3, 6}, {2, 4}, {3, 5}, {3, 4}};
1876 struct sort_network<9> {
1878 static constexpr uint8_t pairs[][2] = {{0, 1}, {3, 4}, {6, 7}, {1, 2}, {4, 5}, {7, 8}, {0, 1}, {3, 4}, {6, 7},
1879 {0, 3}, {3, 6}, {0, 3}, {1, 4}, {4, 7}, {1, 4}, {2, 5}, {5, 8}, {2, 5},
1880 {1, 3}, {5, 7}, {2, 6}, {4, 6}, {2, 4}, {2, 3}, {5, 6}};
1883 struct sort_network<10> {
1885 static constexpr uint8_t pairs[][2] = {{0, 8}, {1, 9}, {2, 7}, {3, 5}, {4, 6}, {0, 2}, {1, 4}, {5, 8},
1886 {7, 9}, {0, 3}, {2, 4}, {5, 7}, {6, 9}, {0, 1}, {3, 6}, {8, 9},
1887 {1, 5}, {2, 3}, {4, 8}, {6, 7}, {1, 2}, {3, 5}, {4, 6}, {7, 8},
1888 {2, 3}, {4, 5}, {6, 7}, {3, 4}, {5, 6}};
1891 struct sort_network<11> {
1893 static constexpr uint8_t pairs[][2] = {
1894 {0, 9}, {1, 6}, {2, 4}, {3, 7}, {5, 8}, {0, 1}, {3, 5}, {4, 10}, {6, 9}, {7, 8}, {1, 3}, {2, 5},
1895 {4, 7}, {8, 10}, {0, 4}, {1, 2}, {3, 7}, {5, 9}, {6, 8}, {0, 1}, {2, 6}, {4, 5}, {7, 8}, {9, 10},
1896 {2, 4}, {3, 6}, {5, 7}, {8, 9}, {1, 2}, {3, 4}, {5, 6}, {7, 8}, {2, 3}, {4, 5}, {6, 7}};
1899 struct sort_network<12> {
1901 static constexpr uint8_t pairs[][2] = {{0, 8}, {1, 7}, {2, 6}, {3, 11}, {4, 10}, {5, 9}, {0, 1}, {2, 5},
1902 {3, 4}, {6, 9}, {7, 8}, {10, 11}, {0, 2}, {1, 6}, {5, 10}, {9, 11},
1903 {0, 3}, {1, 2}, {4, 6}, {5, 7}, {8, 11}, {9, 10}, {1, 4}, {3, 5},
1904 {6, 8}, {7, 10}, {1, 3}, {2, 5}, {6, 9}, {8, 10}, {2, 3}, {4, 5},
1905 {6, 7}, {8, 9}, {4, 6}, {5, 7}, {3, 4}, {5, 6}, {7, 8}};
1908 struct sort_network<13> {
1910 static constexpr uint8_t pairs[][2] = {
1911 {0, 12}, {1, 10}, {2, 9}, {3, 7}, {5, 11}, {6, 8}, {1, 6}, {2, 3}, {4, 11}, {7, 9}, {8, 10}, {0, 4},
1912 {1, 2}, {3, 6}, {7, 8}, {9, 10}, {11, 12}, {4, 6}, {5, 9}, {8, 11}, {10, 12}, {0, 5}, {3, 8}, {4, 7},
1913 {6, 11}, {9, 10}, {0, 1}, {2, 5}, {6, 9}, {7, 8}, {10, 11}, {1, 3}, {2, 4}, {5, 6}, {9, 10}, {1, 2},
1914 {3, 4}, {5, 7}, {6, 8}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {3, 4}, {5, 6}};
1917 struct sort_network<14> {
1919 static constexpr uint8_t pairs[][2] = {
1920 {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}, {0, 2}, {1, 3}, {4, 8}, {5, 9},
1921 {10, 12}, {11, 13}, {0, 4}, {1, 2}, {3, 7}, {5, 8}, {6, 10}, {9, 13}, {11, 12}, {0, 6}, {1, 5},
1922 {3, 9}, {4, 10}, {7, 13}, {8, 12}, {2, 10}, {3, 11}, {4, 6}, {7, 9}, {1, 3}, {2, 8}, {5, 11},
1923 {6, 7}, {10, 12}, {1, 4}, {2, 6}, {3, 5}, {7, 11}, {8, 10}, {9, 12}, {2, 4}, {3, 6}, {5, 8},
1924 {7, 10}, {9, 11}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {6, 7}};
1927 struct sort_network<15> {
1929 static constexpr uint8_t pairs[][2] = {
1930 {1, 2}, {3, 10}, {4, 14}, {5, 8}, {6, 13}, {7, 12}, {9, 11}, {0, 14}, {1, 5}, {2, 8},
1931 {3, 7}, {6, 9}, {10, 12}, {11, 13}, {0, 7}, {1, 6}, {2, 9}, {4, 10}, {5, 11}, {8, 13},
1932 {12, 14}, {0, 6}, {2, 4}, {3, 5}, {7, 11}, {8, 10}, {9, 12}, {13, 14}, {0, 3}, {1, 2},
1933 {4, 7}, {5, 9}, {6, 8}, {10, 11}, {12, 13}, {0, 1}, {2, 3}, {4, 6}, {7, 9}, {10, 12},
1934 {11, 13}, {1, 2}, {3, 5}, {8, 10}, {11, 12}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {2, 3},
1935 {4, 5}, {6, 7}, {8, 9}, {10, 11}, {5, 6}, {7, 8}};
1938 struct sort_network<16> {
1940 static constexpr uint8_t pairs[][2] = {
1941 {0, 13}, {1, 12}, {2, 15}, {3, 14}, {4, 8}, {5, 6}, {7, 11}, {9, 10}, {0, 5}, {1, 7},
1942 {2, 9}, {3, 4}, {6, 13}, {8, 14}, {10, 15}, {11, 12}, {0, 1}, {2, 3}, {4, 5}, {6, 8},
1943 {7, 9}, {10, 11}, {12, 13}, {14, 15}, {0, 2}, {1, 3}, {4, 10}, {5, 11}, {6, 7}, {8, 9},
1944 {12, 14}, {13, 15}, {1, 2}, {3, 12}, {4, 6}, {5, 7}, {8, 10}, {9, 11}, {13, 14}, {1, 4},
1945 {2, 6}, {5, 8}, {7, 10}, {9, 13}, {11, 14}, {2, 4}, {3, 6}, {9, 12}, {11, 13}, {3, 5},
1946 {6, 8}, {7, 9}, {10, 12}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, {6, 7}, {8, 9}};
1949 struct sort_network<17> {
1951 static constexpr uint8_t pairs[][2] = {
1952 {0, 11}, {1, 15}, {2, 10}, {3, 5}, {4, 6}, {8, 12}, {9, 16}, {13, 14}, {0, 6},
1953 {1, 13}, {2, 8}, {4, 14}, {5, 15}, {7, 11}, {0, 8}, {3, 7}, {4, 9}, {6, 16},
1954 {10, 11}, {12, 14}, {0, 2}, {1, 4}, {5, 6}, {7, 13}, {8, 9}, {10, 12}, {11, 14},
1955 {15, 16}, {0, 3}, {2, 5}, {6, 11}, {7, 10}, {9, 13}, {12, 15}, {14, 16}, {0, 1},
1956 {3, 4}, {5, 10}, {6, 9}, {7, 8}, {11, 15}, {13, 14}, {1, 2}, {3, 7}, {4, 8},
1957 {6, 12}, {11, 13}, {14, 15}, {1, 3}, {2, 7}, {4, 5}, {9, 11}, {10, 12}, {13, 14},
1958 {2, 3}, {4, 6}, {5, 7}, {8, 10}, {3, 4}, {6, 8}, {7, 9}, {10, 12}, {5, 6},
1959 {7, 8}, {9, 10}, {11, 12}, {4, 5}, {6, 7}, {8, 9}, {10, 11}, {12, 13}};
1967 template <uint32_t N,
typename TCompareExchange,
size_t... I>
1968 void sort_network_run(TCompareExchange& cex, std::index_sequence<I...>) {
1969 (cex(sort_network<N>::pairs[I][0], sort_network<N>::pairs[I][1]), ...);
1979 template <u
int32_t N, u
int32_t Last,
typename TCompareExchange>
1980 void sort_network_dispatch(uint32_t n, TCompareExchange& cex) {
1982 constexpr size_t Pairs =
sizeof(sort_network<N>::pairs) /
sizeof(sort_network<N>::pairs[0]);
1983 sort_network_run<N>(cex, std::make_index_sequence<Pairs>{});
1986 if constexpr (N < Last)
1987 sort_network_dispatch<N + 1, Last>(n, cex);
1994 template <
typename T>
1995 inline constexpr bool sort_uses_network = std::is_trivially_copyable_v<T> &&
sizeof(T) <= 8;
2002 template <
typename T,
typename TCmpFunc>
2003 struct sort_cex_select {
2012 void operator()(uint32_t lhs, uint32_t rhs)
const {
2013 const T a = beg[lhs];
2014 const T b = beg[rhs];
2015 const bool swap = cmpFunc(b, a);
2016 beg[lhs] = swap ? b : a;
2017 beg[rhs] = swap ? a : b;
2027 template <
typename T,
typename TCmpFunc,
typename TSwapFunc>
2028 struct sort_cex_swap {
2034 TSwapFunc& swapFunc;
2039 void operator()(uint32_t lhs, uint32_t rhs)
const {
2040 if (cmpFunc(beg[rhs], beg[lhs]))
2055 template <u
int32_t MaxN,
typename T,
typename TCmpFunc>
2056 bool sort_small(T* beg, uint32_t n, TCmpFunc& cmpFunc) {
2057 if constexpr (MaxN > SortSmallMaxN) {
2058 if (n > SortSmallMaxN)
2062 if constexpr (sort_uses_network<T>) {
2063 constexpr uint32_t Last = MaxN < SortNetworkMaxN ? MaxN : SortNetworkMaxN;
2064 if constexpr (Last >= 2) {
2066 sort_cex_select<T, TCmpFunc> cex{beg, cmpFunc};
2067 sort_network_dispatch<2, Last>(n, cex);
2074 insertion_sort_range(arr, 0, (
int)n - 1, cmpFunc);
2089 template <u
int32_t MaxN,
typename T,
typename TCmpFunc,
typename TSwapFunc>
2090 bool sort_small(T* beg, uint32_t n, TCmpFunc& cmpFunc, TSwapFunc& swapFunc) {
2091 if constexpr (MaxN > SortSmallMaxN) {
2092 if (n > SortSmallMaxN)
2096 constexpr uint32_t Last = MaxN < SortNetworkMaxN ? MaxN : SortNetworkMaxN;
2097 if constexpr (Last >= 2) {
2099 sort_cex_swap<T, TCmpFunc, TSwapFunc> cex{beg, cmpFunc, swapFunc};
2100 sort_network_dispatch<2, Last>(n, cex);
2105 insertion_sort_range(beg, 0, (
int)n - 1, cmpFunc, swapFunc);
2112 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
2113 void quick_sort(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc);
2122 template <
typename Container,
typename TCmpFunc>
2123 void quick_sort(Container& arr,
int low,
int high, TCmpFunc cmpFunc) {
2126 detail::quick_sort_impl(arr, low, high, cmpFunc, detail::sort_depth_limit((uint32_t)(high - low + 1)));
2138 template <
typename Container,
typename TCmpFunc,
typename TSwapFunc>
2139 void quick_sort(Container& arr,
int low,
int high, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
2142 detail::quick_sort_impl(arr, low, high, cmpFunc, swapFunc, detail::sort_depth_limit((uint32_t)(high - low + 1)));
2153 template <u
int32_t MaxN,
typename T,
typename TCmpFunc>
2154 void sort_bounded(T* beg, T* end, TCmpFunc cmpFunc) {
2155 const auto n = (uint32_t)(end - beg);
2156 if (try_sorted_or_reversed(beg, n, cmpFunc, [beg](uint32_t lhs, uint32_t rhs) {
2157 core::swap(beg[lhs], beg[rhs]);
2160 if (sort_small<MaxN>(beg, n, cmpFunc))
2163 if constexpr (MaxN > SortSmallMaxN)
2164 core::quick_sort(beg, 0, (
int)n - 1, cmpFunc);
2176 template <u
int32_t MaxN,
typename T,
typename TCmpFunc,
typename TSwapFunc>
2177 void sort_bounded(T* beg, T* end, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
2178 const auto n = (uint32_t)(end - beg);
2179 if (try_sorted_or_reversed(beg, n, cmpFunc, swapFunc))
2181 if (sort_small<MaxN>(beg, n, cmpFunc, swapFunc))
2184 if constexpr (MaxN > SortSmallMaxN)
2185 core::quick_sort(beg, 0, (
int)n - 1, cmpFunc, swapFunc);
2200 template <uint32_t MaxN = (uint32_t)-1,
typename T,
typename TCmpFunc>
2201 void sort(T* beg, T* end, TCmpFunc cmpFunc) {
2202 GAIA_ASSERT((uintptr_t)(end - beg) <= MaxN);
2203 detail::sort_bounded<MaxN>(beg, end, cmpFunc);
2211 template <
typename C,
typename TCmpFunc>
2212 void sort(C& c, TCmpFunc cmpFunc) {
2213 constexpr uint32_t Cap = fixed_capacity<std::remove_cv_t<C>>::value;
2214 detail::sort_bounded<Cap != 0 ? Cap : (uint32_t)-1>(c.begin(), c.end(), cmpFunc);
2231 template <uint32_t MaxN = (uint32_t)-1,
typename T,
typename TCmpFunc,
typename TSwapFunc>
2232 void sort(T* beg, T* end, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
2233 GAIA_ASSERT((uintptr_t)(end - beg) <= MaxN);
2234 detail::sort_bounded<MaxN>(beg, end, cmpFunc, swapFunc);
2244 template <
typename C,
typename TCmpFunc,
typename TSwapFunc>
2245 void sort(C& c, TCmpFunc cmpFunc, TSwapFunc swapFunc) {
2246 constexpr uint32_t Cap = fixed_capacity<std::remove_cv_t<C>>::value;
2247 detail::sort_bounded<Cap != 0 ? Cap : (uint32_t)-1>(c.begin(), c.end(), cmpFunc, swapFunc);
Equality comparison functor using operator==.
Definition utility.h:1372
constexpr bool operator()(const T &lhs, const T &rhs) const
Compares two values for equality.
Definition utility.h:1377
Compile-time capacity of a container that can never grow. Zero for containers that can....
Definition utility.h:44
Lightweight carrier for a function argument type pack.
Definition utility.h:646
Detects containers exposing both data() and size().
Definition utility.h:219
Detects whether T supports a free operator==.
Definition utility.h:775
static constexpr bool value
True when the free equality operator probe succeeds.
Definition utility.h:777
Detects whether T defines operator== as a member function.
Definition utility.h:767
static constexpr bool value
True when the member equality operator probe succeeds.
Definition utility.h:769
Detects containers exposing begin(), end(), and size().
Definition utility.h:234
Strict weak ordering functor using operator>.
Definition utility.h:1411
constexpr bool operator()(const T &lhs, const T &rhs) const
Compares whether the left value is greater than the right value.
Definition utility.h:1416
Comparison functor using operator<=.
Definition utility.h:1398
constexpr bool operator()(const T &lhs, const T &rhs) const
Compares whether the left value is smaller than or equal to the right value.
Definition utility.h:1403
Strict weak ordering functor using operator<.
Definition utility.h:1385
constexpr bool operator()(const T &lhs, const T &rhs) const
Compares whether the left value is smaller than the right value.
Definition utility.h:1390
RAII helper that calls lock() on construction and unlock() on destruction.
Definition utility.h:187
T & m_ctx
Guarded lockable object.
Definition utility.h:189
lock_scope & operator=(const lock_scope &)=delete
Copy assignment is disabled because the lock ownership is scoped.
lock_scope(lock_scope &&)=delete
Move construction is disabled because the lock ownership is scoped.
lock_scope(T &ctx)
Acquires the lock represented by ctx.
Definition utility.h:193
lock_scope(const lock_scope &)=delete
Copy construction is disabled because the lock ownership is scoped.
~lock_scope()
Releases the guarded lock.
Definition utility.h:197
lock_scope & operator=(lock_scope &&)=delete
Move assignment is disabled because the lock ownership is scoped.
Concatenates two type_list instances.
Definition utility.h:798
Compile-time list of types.
Definition utility.h:787
static constexpr auto size
Number of stored types.
Definition utility.h:791
Builds a tuple type from the first occurrence of each type in a parameter pack.
Definition utility.h:609
Tag type used to request zero-initialization in APIs that accept marker objects.
Definition utility.h:129