From 97e2e7e94d645a8a74972a8948b43f382540586b Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 15 Jan 2025 14:51:07 +0300 Subject: [PATCH 01/17] move sort and ksort from common --- builtin-functions/kphp-light/array.txt | 19 +- .../kphp-light/unsupported/arrays.txt | 4 - .../core/core-types/decl/array_decl.inl | 20 +- .../core/core-types/definition/array.inl | 180 ---------- runtime-common/stdlib/array/array-functions.h | 89 ----- runtime-light/stdlib/array/array-functions.h | 312 +++++++++++++++++- runtime/array_functions.h | 280 +++++++++++++++- tests/phpt/dl/495_sort.php | 2 +- tests/phpt/nn/010_natsort.php | 2 +- 9 files changed, 612 insertions(+), 296 deletions(-) diff --git a/builtin-functions/kphp-light/array.txt b/builtin-functions/kphp-light/array.txt index c761056875..06e8acd42e 100644 --- a/builtin-functions/kphp-light/array.txt +++ b/builtin-functions/kphp-light/array.txt @@ -92,18 +92,35 @@ function array_map (callable(^2[*] $x):any $callback, $a ::: array) ::: ^1() []; function to_array_debug(any $instance, bool $with_class_names = false) ::: mixed[]; function instance_to_array(object $instance, $with_class_names ::: bool = false) ::: mixed[]; - +/** @kphp-extern-func-info interruptible */ function asort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ function arsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ function ksort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ function krsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ function natsort (&$a ::: array) ::: void; +/** @kphp-extern-func-info interruptible */ function rsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ function sort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; +/** @kphp-extern-func-info interruptible */ +function uksort (&$a ::: array, callable(mixed $x, mixed $y):int $callback) ::: void; + +/** @kphp-extern-func-info interruptible */ +function usort (&$a ::: array, callable(^1[*] $x, ^1[*] $y):int $callback) ::: void; + +/** @kphp-extern-func-info interruptible */ +function uasort (&$a ::: array, callable(^1[*] $x, ^1[*] $y):int $callback) ::: void; + + + diff --git a/builtin-functions/kphp-light/unsupported/arrays.txt b/builtin-functions/kphp-light/unsupported/arrays.txt index a1fdee0cb5..6d8a78de70 100644 --- a/builtin-functions/kphp-light/unsupported/arrays.txt +++ b/builtin-functions/kphp-light/unsupported/arrays.txt @@ -46,10 +46,6 @@ function array_is_vector ($a ::: array) ::: bool; function array_is_list ($a ::: array) ::: bool; -function uasort (&$a ::: array, callable(^1[*] $x, ^1[*] $y):int $callback) ::: void; -function uksort (&$a ::: array, callable(mixed $x, mixed $y):int $callback) ::: void; -function usort (&$a ::: array, callable(^1[*] $x, ^1[*] $y):int $callback) ::: void; - /** @kphp-extern-func-info cpp_template_call */ function vk_dot_product ($a ::: array, $b ::: array) ::: ^1[*] | ^2[*]; diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 893616334e..80e2541546 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -32,6 +32,14 @@ template void sort(TT *begin_init, TT *end_init, const T1 &compare); } +namespace array_functions_impl_ { +template +Result sort(array & arr, const Comparator &comparator, bool renumber); + +template +Result ksort(array & arr, const Comparator &comparator); +} + enum class overwrite_element { YES, NO }; enum class merge_recursive { YES, NO }; @@ -377,12 +385,6 @@ public: inline iterator middle(int64_t n) __attribute__ ((always_inline)); inline iterator end() __attribute__ ((always_inline)); - template - void sort(const T1 &compare, bool renumber); - - template - void ksort(const T1 &compare); - inline void swap(array &other) __attribute__ ((always_inline)); @@ -438,6 +440,12 @@ private: template friend class array; + + template + friend Result array_functions_impl_::sort(array & arr, const Comparator &comparator, bool renumber); + + template + friend Result array_functions_impl_::ksort(array & arr, const Comparator &comparator); }; template diff --git a/runtime-common/core/core-types/definition/array.inl b/runtime-common/core/core-types/definition/array.inl index 7bae3dbc9e..3a7481349e 100644 --- a/runtime-common/core/core-types/definition/array.inl +++ b/runtime-common/core/core-types/definition/array.inl @@ -36,62 +36,6 @@ array_size &array_size::min(const array_size &other) noexcept { return *this; } -namespace dl { - -template -void sort(T *begin_init, T *end_init, const T1 &compare) { - T *begin_stack[32]; - T *end_stack[32]; - - begin_stack[0] = begin_init; - end_stack[0] = end_init - 1; - - for (int depth = 0; depth >= 0; --depth) { - T *begin = begin_stack[depth]; - T *end = end_stack[depth]; - - while (begin < end) { - const auto offset = (end - begin) >> 1; - swap(*begin, begin[offset]); - - T *i = begin + 1, *j = end; - - while (1) { - while (i < j && compare(*begin, *i) > 0) { - i++; - } - - while (i <= j && compare(*j, *begin) > 0) { - j--; - } - - if (i >= j) { - break; - } - - swap(*i++, *j--); - } - - swap(*begin, *j); - - if (j - begin <= end - j) { - if (j + 1 < end) { - begin_stack[depth] = j + 1; - end_stack[depth++] = end; - } - end = j - 1; - } else { - if (begin < j - 1) { - begin_stack[depth] = begin; - end_stack[depth++] = j - 1; - } - begin = j + 1; - } - } - } -} - -} // namespace dl template typename array::key_type array::array_bucket::get_key() const { @@ -1884,130 +1828,6 @@ int64_t array::get_next_key() const { } -template -template -void array::sort(const T1 &compare, bool renumber) { - int64_t n = count(); - - if (renumber) { - if (n == 0) { - return; - } - - if (!is_vector()) { - array_inner *res = array_inner::create(n, true); - for (array_bucket *it = p->begin(); it != p->end(); it = p->next(it)) { - res->push_back_vector_value(it->value); - } - - p->dispose(); - p = res; - } else { - mutate_if_vector_shared(); - } - - const auto elements_cmp = - [&compare](const T &lhs, const T &rhs) { - return compare(lhs, rhs) > 0; - }; - T *begin = reinterpret_cast(p->entries()); - dl::sort(begin, begin + n, elements_cmp); - return; - } - - if (n <= 1) { - return; - } - - if (is_vector()) { - convert_to_map(); - } else { - mutate_if_map_shared(); - } - - array_bucket **arTmp = (array_bucket **)RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket * )); - uint32_t i = 0; - for (array_bucket *it = p->begin(); it != p->end(); it = p->next(it)) { - arTmp[i++] = it; - } - php_assert (i == n); - - const auto hash_entry_cmp = - [&compare](const array_bucket *lhs, const array_bucket *rhs) { - return compare(lhs->value, rhs->value) > 0; - }; - dl::sort(arTmp, arTmp + n, hash_entry_cmp); - - arTmp[0]->prev = p->get_pointer(p->end()); - p->end()->next = p->get_pointer(arTmp[0]); - for (uint32_t j = 1; j < n; j++) { - arTmp[j]->prev = p->get_pointer(arTmp[j - 1]); - arTmp[j - 1]->next = p->get_pointer(arTmp[j]); - } - arTmp[n - 1]->next = p->get_pointer(p->end()); - p->end()->prev = p->get_pointer(arTmp[n - 1]); - - RuntimeAllocator::get().free_script_memory(arTmp, n * sizeof(array_bucket * )); -} - - -template -template -void array::ksort(const T1 &compare) { - int64_t n = count(); - if (n <= 1) { - return; - } - - if (is_vector()) { - convert_to_map(); - } else { - mutate_if_map_shared(); - } - - array keys(array_size(n, true)); - for (auto *it = p->begin(); it != p->end(); it = p->next(it)) { - keys.p->push_back_vector_value(it->get_key()); - } - - key_type *keysp = (key_type *)keys.p->entries(); - dl::sort(keysp, keysp + n, compare); - - list_hash_entry *prev = (list_hash_entry *)p->end(); - for (uint32_t j = 0; j < n; j++) { - list_hash_entry *cur; - if (is_int_key(keysp[j])) { - int64_t int_key = keysp[j].to_int(); - uint32_t bucket = p->choose_bucket(int_key); - while (p->entries()[bucket].int_key != int_key || !p->entries()[bucket].string_key.is_dummy_string()) { - if (unlikely (++bucket == p->buf_size)) { - bucket = 0; - } - } - cur = (list_hash_entry * ) &p->entries()[bucket]; - } else { - string string_key = keysp[j].to_string(); - int64_t int_key = string_key.hash(); - array_bucket *string_entries = p->entries(); - uint32_t bucket = p->choose_bucket(int_key); - while ((string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { - if (unlikely (++bucket == p->buf_size)) { - bucket = 0; - } - } - cur = (list_hash_entry * ) & string_entries[bucket]; - } - - cur->prev = p->get_pointer(prev); - prev->next = p->get_pointer(cur); - - prev = cur; - } - prev->next = p->get_pointer(p->end()); - p->end()->prev = p->get_pointer(prev); -} - - template void array::swap(array &other) { array_inner *tmp = p; diff --git a/runtime-common/stdlib/array/array-functions.h b/runtime-common/stdlib/array/array-functions.h index 6ff9812214..a424e9681a 100644 --- a/runtime-common/stdlib/array/array-functions.h +++ b/runtime-common/stdlib/array/array-functions.h @@ -639,93 +639,4 @@ bool f$array_is_list(const array &a) noexcept { return a.is_vector() || a.is_pseudo_vector(); } -template -void f$sort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.sort(array_functions_impl_::sort_compare(), true); - case SORT_NUMERIC: - return a.sort(array_functions_impl_::sort_compare_numeric(), true); - case SORT_STRING: - return a.sort(array_functions_impl_::sort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function sort"); - } -} - -template -void f$rsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.sort(array_functions_impl_::rsort_compare(), true); - case SORT_NUMERIC: - return a.sort(array_functions_impl_::rsort_compare_numeric(), true); - case SORT_STRING: - return a.sort(array_functions_impl_::rsort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function rsort"); - } -} - -template -void f$arsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.sort(array_functions_impl_::rsort_compare(), false); - case SORT_NUMERIC: - return a.sort(array_functions_impl_::rsort_compare_numeric(), false); - case SORT_STRING: - return a.sort(array_functions_impl_::rsort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function arsort"); - } -} - -template -void f$ksort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.ksort(array_functions_impl_::sort_compare::key_type>()); - case SORT_NUMERIC: - return a.ksort(array_functions_impl_::sort_compare_numeric::key_type>()); - case SORT_STRING: - return a.ksort(array_functions_impl_::sort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function ksort"); - } -} - -template -void f$krsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.ksort(array_functions_impl_::rsort_compare::key_type>()); - case SORT_NUMERIC: - return a.ksort(array_functions_impl_::rsort_compare_numeric::key_type>()); - case SORT_STRING: - return a.ksort(array_functions_impl_::rsort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function krsort"); - } -} - -template -void f$asort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return a.sort(array_functions_impl_::sort_compare(), false); - case SORT_NUMERIC: - return a.sort(array_functions_impl_::sort_compare_numeric(), false); - case SORT_STRING: - return a.sort(array_functions_impl_::sort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function asort"); - } -} - -template -void f$natsort(array &a) { - return a.sort(array_functions_impl_::sort_compare_natural::key_type>(), false); -} - array f$range(const mixed &from, const mixed &to, int64_t step = 1); diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index cde085d5a7..f4eae4def0 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -5,16 +5,218 @@ #pragma once #include +#include #include #include #include "runtime-common/core/runtime-core.h" +#include "runtime-common/stdlib/array/array-functions.h" #include "runtime-light/coroutine/task.h" #include "runtime-light/stdlib/math/random-functions.h" #include "runtime-light/utils/concepts.h" +namespace dl { + +template +requires(std::invocable) +task_t sort(T *begin_init, T *end_init, const Comparator &compare) { + auto compare_call = [&compare](U&& lhs, U&& rhs) -> task_t { + if constexpr (is_async_function_v) { + co_return co_await std::invoke(compare, std::forward(lhs), std::forward(rhs)); + } else { + co_return std::invoke(compare, std::forward(lhs), std::forward(rhs)); + } + }; + T *begin_stack[32]; + T *end_stack[32]; + + begin_stack[0] = begin_init; + end_stack[0] = end_init - 1; + + for (int depth = 0; depth >= 0; --depth) { + T *begin = begin_stack[depth]; + T *end = end_stack[depth]; + + while (begin < end) { + const auto offset = (end - begin) >> 1; + swap(*begin, begin[offset]); + + T *i = begin + 1, *j = end; + + while (1) { + while (i < j && (co_await compare_call(*begin, *i)) > 0) { + i++; + } + + while (i <= j && (co_await compare_call(*j, *begin)) > 0) { + j--; + } + + if (i >= j) { + break; + } + + swap(*i++, *j--); + } + + swap(*begin, *j); + + if (j - begin <= end - j) { + if (j + 1 < end) { + begin_stack[depth] = j + 1; + end_stack[depth++] = end; + } + end = j - 1; + } else { + if (begin < j - 1) { + begin_stack[depth] = begin; + end_stack[depth++] = j - 1; + } + begin = j + 1; + } + } + } + co_return; +} + +} // namespace dl + namespace array_functions_impl_ { +template +Result sort(array &arr, const Comparator &comparator, bool renumber) { + using array_inner = typename array::array_inner; + using array_bucket = typename array::array_bucket; + int64_t n = arr.count(); + + if (renumber) { + if (n == 0) { + co_return; + } + + if (!arr.is_vector()) { + array_inner *res = array_inner::create(n, true); + for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + res->push_back_vector_value(it->value); + } + + arr.p->dispose(); + arr.p = res; + } else { + arr.mutate_if_vector_shared(); + } + + const auto elements_cmp = [&comparator](const U &lhs, const U &rhs) -> task_t { + if constexpr (is_async_function_v) { + co_return(co_await std::invoke(comparator, lhs, rhs)) > 0; + } else { + co_return std::invoke(comparator, lhs, rhs) > 0; + } + }; + + U *begin = reinterpret_cast(arr.p->entries()); + co_await dl::sort(begin, begin + n, elements_cmp); + co_return; + } + + if (n <= 1) { + co_return; + } + + if (arr.is_vector()) { + arr.convert_to_map(); + } else { + arr.mutate_if_map_shared(); + } + + array_bucket **arTmp = static_cast(RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket *))); + uint32_t i = 0; + for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + arTmp[i++] = it; + } + php_assert(i == n); + + const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) -> task_t { + if constexpr (is_async_function_v) { + co_return(co_await std::invoke(comparator, lhs->value, rhs->value)) > 0; + } else { + co_return std::invoke(comparator, lhs->value, rhs->value) > 0; + } + }; + co_await dl::sort(arTmp, arTmp + n, hash_entry_cmp); + + arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); + arr.p->end()->next = arr.p->get_pointer(arTmp[0]); + for (uint32_t j = 1; j < n; j++) { + arTmp[j]->prev = arr.p->get_pointer(arTmp[j - 1]); + arTmp[j - 1]->next = arr.p->get_pointer(arTmp[j]); + } + arTmp[n - 1]->next = arr.p->get_pointer(arr.p->end()); + arr.p->end()->prev = arr.p->get_pointer(arTmp[n - 1]); + + RuntimeAllocator::get().free_script_memory(arTmp, n * sizeof(array_bucket *)); +} + +template +Result ksort(array &arr, const Comparator &comparator) { + using array_bucket = typename array::array_bucket; + using key_type = typename array::key_type; + using list_hash_entry = typename array::list_hash_entry; + + int64_t n = arr.count(); + if (n <= 1) { + co_return; + } + + if (arr.is_vector()) { + arr.convert_to_map(); + } else { + arr.mutate_if_map_shared(); + } + + array keys(array_size(n, true)); + for (auto *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + keys.p->push_back_vector_value(it->get_key()); + } + + key_type *keysp = reinterpret_cast(keys.p->entries()); + co_await dl::sort(keysp, keysp + n, comparator); + + list_hash_entry *prev = static_cast(arr.p->end()); + for (uint32_t j = 0; j < n; j++) { + list_hash_entry *cur; + if (arr.is_int_key(keysp[j])) { + int64_t int_key = keysp[j].to_int(); + uint32_t bucket = arr.p->choose_bucket(int_key); + while (arr.p->entries()[bucket].int_key != int_key || !arr.p->entries()[bucket].string_key.is_dummy_string()) { + if (unlikely(++bucket == arr.p->buf_size)) { + bucket = 0; + } + } + cur = static_cast(&arr.p->entries()[bucket]); + } else { + string string_key = keysp[j].to_string(); + int64_t int_key = string_key.hash(); + array_bucket *string_entries = arr.p->entries(); + uint32_t bucket = arr.p->choose_bucket(int_key); + while ( + (string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { + if (unlikely(++bucket == arr.p->buf_size)) { + bucket = 0; + } + } + cur = static_cast(&string_entries[bucket]); + } + + cur->prev = arr.p->get_pointer(prev); + prev->next = arr.p->get_pointer(cur); + + prev = cur; + } + prev->next = arr.p->get_pointer(arr.p->end()); + arr.p->end()->prev = arr.p->get_pointer(prev); +} + template concept convertible_to_php_bool = requires(T t) { { f$boolval(t) } -> std::convertible_to; @@ -223,19 +425,111 @@ array f$array_combine(const array &keys, const array &values) { php_critical_error("call to unsupported function"); } -template -void f$usort(array &a, const T1 &compare) { - php_critical_error("call to unsupported function"); +template +task_t f$sort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare(), true); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_numeric(), true); + case SORT_STRING: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function sort"); + } } -template -void f$uasort(array &a, const T1 &compare) { - php_critical_error("call to unsupported function"); +template +task_t f$rsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare(), true); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_numeric(), true); + case SORT_STRING: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function rsort"); + } } -template -void f$uksort(array &a, const T1 &compare) { - php_critical_error("call to unsupported function"); +template +task_t f$arsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare(), false); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_numeric(), false); + case SORT_STRING: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function arsort"); + } +} + +template +task_t f$ksort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare::key_type>()); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare_numeric::key_type>()); + case SORT_STRING: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function ksort"); + } +} + +template +task_t f$krsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare::key_type>()); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare_numeric::key_type>()); + case SORT_STRING: + co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function krsort"); + } +} + +template +task_t f$asort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare(), false); + case SORT_NUMERIC: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_numeric(), false); + case SORT_STRING: + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function asort"); + } +} + +template +task_t f$natsort(array &a) { + co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_natural::key_type>(), false); +} + +template +requires(std::invocable) +task_t f$usort(array &a, const Comparator &compare) { + co_return co_await array_functions_impl_::sort>(a, compare, true); +} + +template +requires(std::invocable) +task_t f$uasort(array &a, const Comparator &compare) { + co_return co_await array_functions_impl_::sort>(a, compare, false); +} + +template +requires(std::invocable::key_type, typename array::key_type>) +task_t f$uksort(array &a, const Comparator &compare) { + co_return co_await array_functions_impl_::ksort>(a, compare); } template diff --git a/runtime/array_functions.h b/runtime/array_functions.h index e1d9fba1c2..368808e129 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -12,6 +12,187 @@ #include "runtime-common/stdlib/array/array-functions.h" #include "runtime/math_functions.h" +namespace dl { + +template +void sort(T *begin_init, T *end_init, const T1 &compare) { + T *begin_stack[32]; + T *end_stack[32]; + + begin_stack[0] = begin_init; + end_stack[0] = end_init - 1; + + for (int depth = 0; depth >= 0; --depth) { + T *begin = begin_stack[depth]; + T *end = end_stack[depth]; + + while (begin < end) { + const auto offset = (end - begin) >> 1; + swap(*begin, begin[offset]); + + T *i = begin + 1, *j = end; + + while (1) { + while (i < j && compare(*begin, *i) > 0) { + i++; + } + + while (i <= j && compare(*j, *begin) > 0) { + j--; + } + + if (i >= j) { + break; + } + + swap(*i++, *j--); + } + + swap(*begin, *j); + + if (j - begin <= end - j) { + if (j + 1 < end) { + begin_stack[depth] = j + 1; + end_stack[depth++] = end; + } + end = j - 1; + } else { + if (begin < j - 1) { + begin_stack[depth] = begin; + end_stack[depth++] = j - 1; + } + begin = j + 1; + } + } + } +} + +} // namespace dl + +namespace array_functions_impl_ { + +template +Result sort(array &arr, const Comparator &comparator, bool renumber) { + using array_inner = typename array::array_inner; + using array_bucket = typename array::array_bucket; + int64_t n = arr.count(); + + if (renumber) { + if (n == 0) { + return; + } + + if (!arr.is_vector()) { + array_inner *res = array_inner::create(n, true); + for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + res->push_back_vector_value(it->value); + } + + arr.p->dispose(); + arr.p = res; + } else { + arr.mutate_if_vector_shared(); + } + + const auto elements_cmp = [&comparator, &arr](const U &lhs, const U &rhs) { return comparator(lhs, rhs) > 0; }; + U *begin = reinterpret_cast(arr.p->entries()); + dl::sort(begin, begin + n, elements_cmp); + return; + } + + if (n <= 1) { + return; + } + + if (arr.is_vector()) { + arr.convert_to_map(); + } else { + arr.mutate_if_map_shared(); + } + + array_bucket **arTmp = (array_bucket **)RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket *)); + uint32_t i = 0; + for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + arTmp[i++] = it; + } + php_assert(i == n); + + const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) { return comparator(lhs->value, rhs->value) > 0; }; + dl::sort(arTmp, arTmp + n, hash_entry_cmp); + + arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); + arr.p->end()->next = arr.p->get_pointer(arTmp[0]); + for (uint32_t j = 1; j < n; j++) { + arTmp[j]->prev = arr.p->get_pointer(arTmp[j - 1]); + arTmp[j - 1]->next = arr.p->get_pointer(arTmp[j]); + } + arTmp[n - 1]->next = arr.p->get_pointer(arr.p->end()); + arr.p->end()->prev = arr.p->get_pointer(arTmp[n - 1]); + + RuntimeAllocator::get().free_script_memory(arTmp, n * sizeof(array_bucket *)); +} + +template +Result ksort(array &arr, const Comparator &comparator) { + using array_bucket = typename array::array_bucket; + using key_type = typename array::key_type; + using list_hash_entry = typename array::list_hash_entry; + + int64_t n = arr.count(); + if (n <= 1) { + return; + } + + if (arr.is_vector()) { + arr.convert_to_map(); + } else { + arr.mutate_if_map_shared(); + } + + array keys(array_size(n, true)); + for (auto *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { + keys.p->push_back_vector_value(it->get_key()); + } + + key_type *keysp = (key_type *)keys.p->entries(); + dl::sort(keysp, keysp + n, comparator); + + list_hash_entry *prev = (list_hash_entry *)arr.p->end(); + for (uint32_t j = 0; j < n; j++) { + list_hash_entry *cur; + if (arr.is_int_key(keysp[j])) { + int64_t int_key = keysp[j].to_int(); + uint32_t bucket = arr.p->choose_bucket(int_key); + while (arr.p->entries()[bucket].int_key != int_key || !arr.p->entries()[bucket].string_key.is_dummy_string()) { + if (unlikely(++bucket == arr.p->buf_size)) { + bucket = 0; + } + } + cur = (list_hash_entry *)&arr.p->entries()[bucket]; + } else { + string string_key = keysp[j].to_string(); + int64_t int_key = string_key.hash(); + array_bucket *string_entries = arr.p->entries(); + uint32_t bucket = arr.p->choose_bucket(int_key); + while ( + (string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { + if (unlikely(++bucket == arr.p->buf_size)) { + bucket = 0; + } + } + cur = (list_hash_entry *)&string_entries[bucket]; + } + + cur->prev = arr.p->get_pointer(prev); + prev->next = arr.p->get_pointer(cur); + + prev = cur; + } + prev->next = arr.p->get_pointer(arr.p->end()); + arr.p->end()->prev = arr.p->get_pointer(prev); +} +} + template array f$array_splice(array &a, int64_t offset, int64_t length, const array &); @@ -81,17 +262,17 @@ void f$shuffle(array &a); template void f$usort(array &a, const T1 &compare) { - return a.sort(compare, true); + return array_functions_impl_::sort(a, compare, true); } template void f$uasort(array &a, const T1 &compare) { - return a.sort(compare, false); + return array_functions_impl_::sort(a, compare, false); } template void f$uksort(array &a, const T1 &compare) { - return a.ksort(compare); + return array_functions_impl_::ksort(a, compare); } template @@ -335,8 +516,8 @@ inline Optional> f$array_column(const array &a, const mixed } template -inline auto f$array_column(const Optional &a, const mixed &column_key, - const mixed &index_key = {}) -> decltype(f$array_column(std::declval(), column_key, index_key)) { +inline auto f$array_column(const Optional &a, const mixed &column_key, const mixed &index_key = {}) + -> decltype(f$array_column(std::declval(), column_key, index_key)) { if (!a.has_value()) { php_warning("first parameter of array_column must be array"); return false; @@ -673,6 +854,95 @@ void f$array_swap_int_keys(array &a, int64_t idx1, int64_t idx2) noexcept { a.swap_int_keys(idx1, idx2); } +template +void f$sort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare(), true); + case SORT_NUMERIC: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_numeric(), true); + case SORT_STRING: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function sort"); + } +} + +template +void f$rsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare(), true); + case SORT_NUMERIC: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_numeric(), true); + case SORT_STRING: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function rsort"); + } +} + +template +void f$arsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare(), false); + case SORT_NUMERIC: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_numeric(), false); + case SORT_STRING: + return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function arsort"); + } +} + +template +void f$ksort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare::key_type>()); + case SORT_NUMERIC: + return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare_numeric::key_type>()); + case SORT_STRING: + return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function ksort"); + } +} + +template +void f$krsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare::key_type>()); + case SORT_NUMERIC: + return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare_numeric::key_type>()); + case SORT_STRING: + return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function krsort"); + } +} + +template +void f$asort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare(), false); + case SORT_NUMERIC: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_numeric(), false); + case SORT_STRING: + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function asort"); + } +} + +template +void f$natsort(array &a) { + return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_natural::key_type>(), false); +} + template T vk_dot_product_sparse(const array &a, const array &b) { T result = T(); diff --git a/tests/phpt/dl/495_sort.php b/tests/phpt/dl/495_sort.php index 1035a64378..040b8cd398 100644 --- a/tests/phpt/dl/495_sort.php +++ b/tests/phpt/dl/495_sort.php @@ -1,4 +1,4 @@ -@ok benchmark callback k2_skip +@ok benchmark callback Date: Wed, 15 Jan 2025 16:37:31 +0300 Subject: [PATCH 02/17] fix build --- runtime/array_functions.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/array_functions.h b/runtime/array_functions.h index 368808e129..0eb6bdba85 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -94,7 +94,7 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { arr.mutate_if_vector_shared(); } - const auto elements_cmp = [&comparator, &arr](const U &lhs, const U &rhs) { return comparator(lhs, rhs) > 0; }; + const auto elements_cmp = [&comparator](const U &lhs, const U &rhs) { return std::invoke(comparator, lhs, rhs) > 0; }; U *begin = reinterpret_cast(arr.p->entries()); dl::sort(begin, begin + n, elements_cmp); return; @@ -117,7 +117,7 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { } php_assert(i == n); - const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) { return comparator(lhs->value, rhs->value) > 0; }; + const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) { return std::invoke(comparator, lhs->value, rhs->value) > 0; }; dl::sort(arTmp, arTmp + n, hash_entry_cmp); arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); From 8ccc8016f89cfcf55ccc7f07faf46e307ad9b693 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 15 Jan 2025 17:42:04 +0300 Subject: [PATCH 03/17] fix comparator type --- .../core/core-types/decl/array_decl.inl | 10 +++--- runtime-light/stdlib/array/array-functions.h | 34 ++++++++----------- runtime/array_functions.h | 24 +++++++------ 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 80e2541546..35b282d047 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -29,15 +29,15 @@ struct array_size { namespace dl { template -void sort(TT *begin_init, TT *end_init, const T1 &compare); +void sort(TT *begin_init, TT *end_init, T1 &&compare); } namespace array_functions_impl_ { template -Result sort(array & arr, const Comparator &comparator, bool renumber); +Result sort(array & arr, Comparator &&comparator, bool renumber); template -Result ksort(array & arr, const Comparator &comparator); +Result ksort(array & arr, Comparator &&comparator); } enum class overwrite_element { YES, NO }; @@ -442,10 +442,10 @@ private: friend class array; template - friend Result array_functions_impl_::sort(array & arr, const Comparator &comparator, bool renumber); + friend Result array_functions_impl_::sort(array & arr, Comparator &&comparator, bool renumber); template - friend Result array_functions_impl_::ksort(array & arr, const Comparator &comparator); + friend Result array_functions_impl_::ksort(array & arr, Comparator &&comparator); }; template diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index f4eae4def0..9c58b3cf36 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,13 +18,12 @@ namespace dl { template -requires(std::invocable) -task_t sort(T *begin_init, T *end_init, const Comparator &compare) { - auto compare_call = [&compare](U&& lhs, U&& rhs) -> task_t { +requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) { + auto compare_call = [&compare](U &&lhs, U &&rhs) -> task_t { if constexpr (is_async_function_v) { - co_return co_await std::invoke(compare, std::forward(lhs), std::forward(rhs)); + co_return co_await std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); } else { - co_return std::invoke(compare, std::forward(lhs), std::forward(rhs)); + co_return std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); } }; T *begin_stack[32]; @@ -84,7 +83,7 @@ task_t sort(T *begin_init, T *end_init, const Comparator &compare) { namespace array_functions_impl_ { template -Result sort(array &arr, const Comparator &comparator, bool renumber) { +Result sort(array &arr, Comparator &&comparator, bool renumber) { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -108,9 +107,9 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { const auto elements_cmp = [&comparator](const U &lhs, const U &rhs) -> task_t { if constexpr (is_async_function_v) { - co_return(co_await std::invoke(comparator, lhs, rhs)) > 0; + co_return(co_await std::invoke(std::forward(comparator), lhs, rhs)) > 0; } else { - co_return std::invoke(comparator, lhs, rhs) > 0; + co_return std::invoke(std::forward(comparator), lhs, rhs) > 0; } }; @@ -158,7 +157,7 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { } template -Result ksort(array &arr, const Comparator &comparator) { +Result ksort(array &arr, Comparator &&comparator) { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; @@ -180,7 +179,7 @@ Result ksort(array &arr, const Comparator &comparator) { } key_type *keysp = reinterpret_cast(keys.p->entries()); - co_await dl::sort(keysp, keysp + n, comparator); + co_await dl::sort(keysp, keysp + n, std::forward(comparator)); list_hash_entry *prev = static_cast(arr.p->end()); for (uint32_t j = 0; j < n; j++) { @@ -515,21 +514,18 @@ task_t f$natsort(array &a) { } template -requires(std::invocable) -task_t f$usort(array &a, const Comparator &compare) { - co_return co_await array_functions_impl_::sort>(a, compare, true); +requires(std::invocable) task_t f$usort(array &a, Comparator &&compare) { + co_return co_await array_functions_impl_::sort>(a, std::forward(compare), true); } template -requires(std::invocable) -task_t f$uasort(array &a, const Comparator &compare) { - co_return co_await array_functions_impl_::sort>(a, compare, false); +requires(std::invocable) task_t f$uasort(array &a, Comparator &&compare) { + co_return co_await array_functions_impl_::sort>(a, std::forward(compare), false); } template -requires(std::invocable::key_type, typename array::key_type>) -task_t f$uksort(array &a, const Comparator &compare) { - co_return co_await array_functions_impl_::ksort>(a, compare); +requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator &&compare) { + co_return co_await array_functions_impl_::ksort>(a, std::forward(compare)); } template diff --git a/runtime/array_functions.h b/runtime/array_functions.h index 0eb6bdba85..378fc6c009 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -14,8 +14,8 @@ namespace dl { -template -void sort(T *begin_init, T *end_init, const T1 &compare) { +template +void sort(T *begin_init, T *end_init, Comparator &&compare) { T *begin_stack[32]; T *end_stack[32]; @@ -33,11 +33,11 @@ void sort(T *begin_init, T *end_init, const T1 &compare) { T *i = begin + 1, *j = end; while (1) { - while (i < j && compare(*begin, *i) > 0) { + while (i < j && std::invoke(std::forward(compare), *begin, *i) > 0) { i++; } - while (i <= j && compare(*j, *begin) > 0) { + while (i <= j && std::invoke(std::forward(compare), *j, *begin) > 0) { j--; } @@ -72,7 +72,7 @@ void sort(T *begin_init, T *end_init, const T1 &compare) { namespace array_functions_impl_ { template -Result sort(array &arr, const Comparator &comparator, bool renumber) { +Result sort(array &arr, Comparator &&comparator, bool renumber) { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -94,9 +94,10 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { arr.mutate_if_vector_shared(); } - const auto elements_cmp = [&comparator](const U &lhs, const U &rhs) { return std::invoke(comparator, lhs, rhs) > 0; }; + auto elements_cmp = [&comparator](const U &lhs, const U &rhs) + { return std::invoke(std::forward(comparator), lhs, rhs) > 0; }; U *begin = reinterpret_cast(arr.p->entries()); - dl::sort(begin, begin + n, elements_cmp); + dl::sort(begin, begin + n, std::move(elements_cmp)); return; } @@ -117,8 +118,9 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { } php_assert(i == n); - const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) { return std::invoke(comparator, lhs->value, rhs->value) > 0; }; - dl::sort(arTmp, arTmp + n, hash_entry_cmp); + auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) + { return std::invoke(std::forward(comparator), lhs->value, rhs->value) > 0; }; + dl::sort(arTmp, arTmp + n, std::move(hash_entry_cmp)); arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); arr.p->end()->next = arr.p->get_pointer(arTmp[0]); @@ -133,7 +135,7 @@ Result sort(array &arr, const Comparator &comparator, bool renumber) { } template -Result ksort(array &arr, const Comparator &comparator) { +Result ksort(array &arr, Comparator &&comparator) { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; @@ -155,7 +157,7 @@ Result ksort(array &arr, const Comparator &comparator) { } key_type *keysp = (key_type *)keys.p->entries(); - dl::sort(keysp, keysp + n, comparator); + dl::sort(keysp, keysp + n, std::forward(comparator)); list_hash_entry *prev = (list_hash_entry *)arr.p->end(); for (uint32_t j = 0; j < n; j++) { From ca0ac00c667560cab99b61de1921d70f8283499c Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 15 Jan 2025 18:38:11 +0300 Subject: [PATCH 04/17] add noexcept --- runtime-common/core/core-types/decl/array_decl.inl | 6 +++--- runtime-light/stdlib/array/array-functions.h | 6 +++--- runtime/array_functions.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 35b282d047..78be823c7b 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -29,15 +29,15 @@ struct array_size { namespace dl { template -void sort(TT *begin_init, TT *end_init, T1 &&compare); +void sort(TT *begin_init, TT *end_init, T1 &&compare) noexcept; } namespace array_functions_impl_ { template -Result sort(array & arr, Comparator &&comparator, bool renumber); +Result sort(array & arr, Comparator &&comparator, bool renumber) noexcept; template -Result ksort(array & arr, Comparator &&comparator); +Result ksort(array & arr, Comparator &&comparator) noexcept; } enum class overwrite_element { YES, NO }; diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 9c58b3cf36..bdf02abc13 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,7 +18,7 @@ namespace dl { template -requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) { +requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept{ auto compare_call = [&compare](U &&lhs, U &&rhs) -> task_t { if constexpr (is_async_function_v) { co_return co_await std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); @@ -83,7 +83,7 @@ requires(std::invocable) task_t sort(T *begin_init, T *e namespace array_functions_impl_ { template -Result sort(array &arr, Comparator &&comparator, bool renumber) { +Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -157,7 +157,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) { } template -Result ksort(array &arr, Comparator &&comparator) { +Result ksort(array &arr, Comparator &&comparator) noexcept { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; diff --git a/runtime/array_functions.h b/runtime/array_functions.h index 378fc6c009..e5b7d6c65a 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -15,7 +15,7 @@ namespace dl { template -void sort(T *begin_init, T *end_init, Comparator &&compare) { +void sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { T *begin_stack[32]; T *end_stack[32]; @@ -72,7 +72,7 @@ void sort(T *begin_init, T *end_init, Comparator &&compare) { namespace array_functions_impl_ { template -Result sort(array &arr, Comparator &&comparator, bool renumber) { +Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -135,7 +135,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) { } template -Result ksort(array &arr, Comparator &&comparator) { +Result ksort(array &arr, Comparator &&comparator) noexcept { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; From 3c0cf123cfe2564c7eb8d8bc67c2a1caff0acf87 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Thu, 16 Jan 2025 12:27:37 +0300 Subject: [PATCH 05/17] fix compilation --- runtime-common/core/core-types/decl/array_decl.inl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 78be823c7b..5de68acc45 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -442,10 +442,10 @@ private: friend class array; template - friend Result array_functions_impl_::sort(array & arr, Comparator &&comparator, bool renumber); + friend Result array_functions_impl_::sort(array & arr, Comparator &&comparator, bool renumber) noexcept; template - friend Result array_functions_impl_::ksort(array & arr, Comparator &&comparator); + friend Result array_functions_impl_::ksort(array & arr, Comparator &&comparator) noexcept; }; template From d58703e45525be9345282884e8287c1b4f000984 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Mon, 20 Jan 2025 17:16:57 +0300 Subject: [PATCH 06/17] small fixes --- runtime-light/stdlib/array/array-functions.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index bdf02abc13..f6437254f8 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,8 +18,8 @@ namespace dl { template -requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept{ - auto compare_call = [&compare](U &&lhs, U &&rhs) -> task_t { +requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { + auto compare_call = [compare](U &&lhs, U &&rhs) -> task_t { if constexpr (is_async_function_v) { co_return co_await std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); } else { @@ -105,7 +105,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { arr.mutate_if_vector_shared(); } - const auto elements_cmp = [&comparator](const U &lhs, const U &rhs) -> task_t { + const auto elements_cmp = [comparator](const U &lhs, const U &rhs) -> task_t { if constexpr (is_async_function_v) { co_return(co_await std::invoke(std::forward(comparator), lhs, rhs)) > 0; } else { @@ -135,7 +135,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { } php_assert(i == n); - const auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) -> task_t { + const auto hash_entry_cmp = [comparator](const array_bucket *lhs, const array_bucket *rhs) -> task_t { if constexpr (is_async_function_v) { co_return(co_await std::invoke(comparator, lhs->value, rhs->value)) > 0; } else { From a0fa137384293660fe11a38386825814c0781960 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Tue, 21 Jan 2025 14:12:51 +0300 Subject: [PATCH 07/17] small fixes --- runtime-light/stdlib/array/array-functions.h | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index f6437254f8..108f6d5bc1 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -19,7 +19,7 @@ namespace dl { template requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { - auto compare_call = [compare](U &&lhs, U &&rhs) -> task_t { + auto compare_call = [compare](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { co_return co_await std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); } else { @@ -40,9 +40,10 @@ requires(std::invocable) task_t sort(T *begin_init, T *e const auto offset = (end - begin) >> 1; swap(*begin, begin[offset]); - T *i = begin + 1, *j = end; + T *i = begin + 1; + T *j = end; - while (1) { + while (true) { while (i < j && (co_await compare_call(*begin, *i)) > 0) { i++; } @@ -83,7 +84,7 @@ requires(std::invocable) task_t sort(T *begin_init, T *e namespace array_functions_impl_ { template -Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { +Result sort(array &arr, Comparator comparator, bool renumber) noexcept { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -105,7 +106,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { arr.mutate_if_vector_shared(); } - const auto elements_cmp = [comparator](const U &lhs, const U &rhs) -> task_t { + const auto elements_cmp = [comparator](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { co_return(co_await std::invoke(std::forward(comparator), lhs, rhs)) > 0; } else { @@ -128,7 +129,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { arr.mutate_if_map_shared(); } - array_bucket **arTmp = static_cast(RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket *))); + auto **arTmp = static_cast(RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket *))); uint32_t i = 0; for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { arTmp[i++] = it; @@ -178,17 +179,17 @@ Result ksort(array &arr, Comparator &&comparator) noexcept { keys.p->push_back_vector_value(it->get_key()); } - key_type *keysp = reinterpret_cast(keys.p->entries()); + auto *keysp = reinterpret_cast(keys.p->entries()); co_await dl::sort(keysp, keysp + n, std::forward(comparator)); - list_hash_entry *prev = static_cast(arr.p->end()); + auto *prev = static_cast(arr.p->end()); for (uint32_t j = 0; j < n; j++) { - list_hash_entry *cur; + list_hash_entry *cur = nullptr; if (arr.is_int_key(keysp[j])) { int64_t int_key = keysp[j].to_int(); uint32_t bucket = arr.p->choose_bucket(int_key); while (arr.p->entries()[bucket].int_key != int_key || !arr.p->entries()[bucket].string_key.is_dummy_string()) { - if (unlikely(++bucket == arr.p->buf_size)) { + if (++bucket == arr.p->buf_size) [[unlikely]] { bucket = 0; } } @@ -200,7 +201,7 @@ Result ksort(array &arr, Comparator &&comparator) noexcept { uint32_t bucket = arr.p->choose_bucket(int_key); while ( (string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { - if (unlikely(++bucket == arr.p->buf_size)) { + if (++bucket == arr.p->buf_size) [[unlikely]] { bucket = 0; } } From 01a0899f604bd604dca6dabc9dcf2e4b8ef34648 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 22 Jan 2025 15:29:31 +0300 Subject: [PATCH 08/17] forward to move --- runtime-light/stdlib/array/array-functions.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 108f6d5bc1..0b75a4fdcd 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -21,9 +21,9 @@ template requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { auto compare_call = [compare](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { - co_return co_await std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); + co_return co_await std::invoke(std::forward(compare), std::move(lhs), std::move(rhs)); } else { - co_return std::invoke(std::forward(compare), std::forward(lhs), std::forward(rhs)); + co_return std::invoke(std::forward(compare), std::move(lhs), std::move(rhs)); } }; T *begin_stack[32]; @@ -108,9 +108,9 @@ Result sort(array &arr, Comparator comparator, bool renumber) noexcept { const auto elements_cmp = [comparator](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { - co_return(co_await std::invoke(std::forward(comparator), lhs, rhs)) > 0; + co_return(co_await std::invoke(std::forward(comparator), std::move(lhs), std::move(rhs))) > 0; } else { - co_return std::invoke(std::forward(comparator), lhs, rhs) > 0; + co_return std::invoke(std::forward(comparator), std::move(lhs), std::move(rhs)) > 0; } }; From e5506aee5f59a1c367fad69834ab5bc612ba6a9f Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Fri, 24 Jan 2025 16:12:41 +0300 Subject: [PATCH 09/17] fix same arg type --- .../core/core-types/decl/array_decl.inl | 10 +++---- runtime-light/stdlib/array/array-functions.h | 30 +++++++++---------- runtime/array_functions.h | 20 ++++++------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 5de68acc45..2d9569e0df 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -29,15 +29,15 @@ struct array_size { namespace dl { template -void sort(TT *begin_init, TT *end_init, T1 &&compare) noexcept; +void sort(TT *begin_init, TT *end_init, T1 compare) noexcept; } namespace array_functions_impl_ { template -Result sort(array & arr, Comparator &&comparator, bool renumber) noexcept; +Result sort(array & arr, Comparator comparator, bool renumber) noexcept; template -Result ksort(array & arr, Comparator &&comparator) noexcept; +Result ksort(array & arr, Comparator comparator) noexcept; } enum class overwrite_element { YES, NO }; @@ -442,10 +442,10 @@ private: friend class array; template - friend Result array_functions_impl_::sort(array & arr, Comparator &&comparator, bool renumber) noexcept; + friend Result array_functions_impl_::sort(array & arr, Comparator comparator, bool renumber) noexcept; template - friend Result array_functions_impl_::ksort(array & arr, Comparator &&comparator) noexcept; + friend Result array_functions_impl_::ksort(array & arr, Comparator comparator) noexcept; }; template diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 0b75a4fdcd..8defb95ab6 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,12 +18,12 @@ namespace dl { template -requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { +requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator compare) noexcept { auto compare_call = [compare](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { - co_return co_await std::invoke(std::forward(compare), std::move(lhs), std::move(rhs)); + co_return co_await std::invoke(std::move(compare), std::move(lhs), std::move(rhs)); } else { - co_return std::invoke(std::forward(compare), std::move(lhs), std::move(rhs)); + co_return std::invoke(std::move(compare), std::move(lhs), std::move(rhs)); } }; T *begin_stack[32]; @@ -108,9 +108,9 @@ Result sort(array &arr, Comparator comparator, bool renumber) noexcept { const auto elements_cmp = [comparator](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { - co_return(co_await std::invoke(std::forward(comparator), std::move(lhs), std::move(rhs))) > 0; + co_return(co_await std::invoke(std::move(comparator), std::move(lhs), std::move(rhs))) > 0; } else { - co_return std::invoke(std::forward(comparator), std::move(lhs), std::move(rhs)) > 0; + co_return std::invoke(std::move(comparator), std::move(lhs), std::move(rhs)) > 0; } }; @@ -138,9 +138,9 @@ Result sort(array &arr, Comparator comparator, bool renumber) noexcept { const auto hash_entry_cmp = [comparator](const array_bucket *lhs, const array_bucket *rhs) -> task_t { if constexpr (is_async_function_v) { - co_return(co_await std::invoke(comparator, lhs->value, rhs->value)) > 0; + co_return(co_await std::invoke(std::move(comparator), lhs->value, rhs->value)) > 0; } else { - co_return std::invoke(comparator, lhs->value, rhs->value) > 0; + co_return std::invoke(std::move(comparator), lhs->value, rhs->value) > 0; } }; co_await dl::sort(arTmp, arTmp + n, hash_entry_cmp); @@ -158,7 +158,7 @@ Result sort(array &arr, Comparator comparator, bool renumber) noexcept { } template -Result ksort(array &arr, Comparator &&comparator) noexcept { +Result ksort(array &arr, Comparator comparator) noexcept { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; @@ -180,7 +180,7 @@ Result ksort(array &arr, Comparator &&comparator) noexcept { } auto *keysp = reinterpret_cast(keys.p->entries()); - co_await dl::sort(keysp, keysp + n, std::forward(comparator)); + co_await dl::sort(keysp, keysp + n, std::move(comparator)); auto *prev = static_cast(arr.p->end()); for (uint32_t j = 0; j < n; j++) { @@ -515,18 +515,18 @@ task_t f$natsort(array &a) { } template -requires(std::invocable) task_t f$usort(array &a, Comparator &&compare) { - co_return co_await array_functions_impl_::sort>(a, std::forward(compare), true); +requires(std::invocable) task_t f$usort(array &a, Comparator compare) { + co_return co_await array_functions_impl_::sort>(a, std::move(compare), true); } template -requires(std::invocable) task_t f$uasort(array &a, Comparator &&compare) { - co_return co_await array_functions_impl_::sort>(a, std::forward(compare), false); +requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { + co_return co_await array_functions_impl_::sort>(a, std::move(compare), false); } template -requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator &&compare) { - co_return co_await array_functions_impl_::ksort>(a, std::forward(compare)); +requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { + co_return co_await array_functions_impl_::ksort>(a, std::move(compare)); } template diff --git a/runtime/array_functions.h b/runtime/array_functions.h index e5b7d6c65a..7ebd201f8f 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -15,7 +15,7 @@ namespace dl { template -void sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { +void sort(T *begin_init, T *end_init, Comparator compare) noexcept { T *begin_stack[32]; T *end_stack[32]; @@ -33,11 +33,11 @@ void sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { T *i = begin + 1, *j = end; while (1) { - while (i < j && std::invoke(std::forward(compare), *begin, *i) > 0) { + while (i < j && std::invoke(std::move(compare), *begin, *i) > 0) { i++; } - while (i <= j && std::invoke(std::forward(compare), *j, *begin) > 0) { + while (i <= j && std::invoke(std::move(compare), *j, *begin) > 0) { j--; } @@ -72,7 +72,7 @@ void sort(T *begin_init, T *end_init, Comparator &&compare) noexcept { namespace array_functions_impl_ { template -Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { +Result sort(array &arr, Comparator comparator, bool renumber) noexcept { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -94,8 +94,8 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { arr.mutate_if_vector_shared(); } - auto elements_cmp = [&comparator](const U &lhs, const U &rhs) - { return std::invoke(std::forward(comparator), lhs, rhs) > 0; }; + auto elements_cmp = [comparator](const U &lhs, const U &rhs) + { return std::invoke(std::move(comparator), lhs, rhs) > 0; }; U *begin = reinterpret_cast(arr.p->entries()); dl::sort(begin, begin + n, std::move(elements_cmp)); return; @@ -118,8 +118,8 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { } php_assert(i == n); - auto hash_entry_cmp = [&comparator](const array_bucket *lhs, const array_bucket *rhs) - { return std::invoke(std::forward(comparator), lhs->value, rhs->value) > 0; }; + auto hash_entry_cmp = [comparator](const array_bucket *lhs, const array_bucket *rhs) + { return std::invoke(std::move(comparator), lhs->value, rhs->value) > 0; }; dl::sort(arTmp, arTmp + n, std::move(hash_entry_cmp)); arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); @@ -135,7 +135,7 @@ Result sort(array &arr, Comparator &&comparator, bool renumber) noexcept { } template -Result ksort(array &arr, Comparator &&comparator) noexcept { +Result ksort(array &arr, Comparator comparator) noexcept { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; @@ -157,7 +157,7 @@ Result ksort(array &arr, Comparator &&comparator) noexcept { } key_type *keysp = (key_type *)keys.p->entries(); - dl::sort(keysp, keysp + n, std::forward(comparator)); + dl::sort(keysp, keysp + n, std::move(comparator)); list_hash_entry *prev = (list_hash_entry *)arr.p->end(); for (uint32_t j = 0; j < n; j++) { From dec99718b5f756910b0c04a45709266207c0fd5a Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 15:32:05 +0300 Subject: [PATCH 10/17] wip --- builtin-functions/kphp-light/array.txt | 8 +- .../core/core-types/decl/array_decl.inl | 14 +- .../core/core-types/definition/array.inl | 180 +++++++++++ runtime-common/stdlib/array/array-functions.h | 88 ++++++ runtime-light/stdlib/array/array-functions.h | 113 ++----- runtime/array_functions.h | 290 +----------------- 6 files changed, 312 insertions(+), 381 deletions(-) diff --git a/builtin-functions/kphp-light/array.txt b/builtin-functions/kphp-light/array.txt index 06e8acd42e..f88badd317 100644 --- a/builtin-functions/kphp-light/array.txt +++ b/builtin-functions/kphp-light/array.txt @@ -92,25 +92,19 @@ function array_map (callable(^2[*] $x):any $callback, $a ::: array) ::: ^1() []; function to_array_debug(any $instance, bool $with_class_names = false) ::: mixed[]; function instance_to_array(object $instance, $with_class_names ::: bool = false) ::: mixed[]; -/** @kphp-extern-func-info interruptible */ + function asort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; -/** @kphp-extern-func-info interruptible */ function arsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; -/** @kphp-extern-func-info interruptible */ function ksort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; -/** @kphp-extern-func-info interruptible */ function krsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; -/** @kphp-extern-func-info interruptible */ function natsort (&$a ::: array) ::: void; -/** @kphp-extern-func-info interruptible */ function rsort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; -/** @kphp-extern-func-info interruptible */ function sort (&$a ::: array, $flag ::: int = SORT_REGULAR) ::: void; /** @kphp-extern-func-info interruptible */ diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 2d9569e0df..33f9164524 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -34,10 +34,10 @@ void sort(TT *begin_init, TT *end_init, T1 compare) noexcept; namespace array_functions_impl_ { template -Result sort(array & arr, Comparator comparator, bool renumber) noexcept; +Result async_sort(array & arr, Comparator comparator, bool renumber) noexcept; template -Result ksort(array & arr, Comparator comparator) noexcept; +Result async_ksort(array & arr, Comparator comparator) noexcept; } enum class overwrite_element { YES, NO }; @@ -385,6 +385,12 @@ public: inline iterator middle(int64_t n) __attribute__ ((always_inline)); inline iterator end() __attribute__ ((always_inline)); + template + void sort(const T1 &compare, bool renumber); + + template + void ksort(const T1 &compare); + inline void swap(array &other) __attribute__ ((always_inline)); @@ -442,10 +448,10 @@ private: friend class array; template - friend Result array_functions_impl_::sort(array & arr, Comparator comparator, bool renumber) noexcept; + friend Result array_functions_impl_::async_sort(array & arr, Comparator comparator, bool renumber) noexcept; template - friend Result array_functions_impl_::ksort(array & arr, Comparator comparator) noexcept; + friend Result array_functions_impl_::async_ksort(array & arr, Comparator comparator) noexcept; }; template diff --git a/runtime-common/core/core-types/definition/array.inl b/runtime-common/core/core-types/definition/array.inl index 3a7481349e..7bae3dbc9e 100644 --- a/runtime-common/core/core-types/definition/array.inl +++ b/runtime-common/core/core-types/definition/array.inl @@ -36,6 +36,62 @@ array_size &array_size::min(const array_size &other) noexcept { return *this; } +namespace dl { + +template +void sort(T *begin_init, T *end_init, const T1 &compare) { + T *begin_stack[32]; + T *end_stack[32]; + + begin_stack[0] = begin_init; + end_stack[0] = end_init - 1; + + for (int depth = 0; depth >= 0; --depth) { + T *begin = begin_stack[depth]; + T *end = end_stack[depth]; + + while (begin < end) { + const auto offset = (end - begin) >> 1; + swap(*begin, begin[offset]); + + T *i = begin + 1, *j = end; + + while (1) { + while (i < j && compare(*begin, *i) > 0) { + i++; + } + + while (i <= j && compare(*j, *begin) > 0) { + j--; + } + + if (i >= j) { + break; + } + + swap(*i++, *j--); + } + + swap(*begin, *j); + + if (j - begin <= end - j) { + if (j + 1 < end) { + begin_stack[depth] = j + 1; + end_stack[depth++] = end; + } + end = j - 1; + } else { + if (begin < j - 1) { + begin_stack[depth] = begin; + end_stack[depth++] = j - 1; + } + begin = j + 1; + } + } + } +} + +} // namespace dl template typename array::key_type array::array_bucket::get_key() const { @@ -1828,6 +1884,130 @@ int64_t array::get_next_key() const { } +template +template +void array::sort(const T1 &compare, bool renumber) { + int64_t n = count(); + + if (renumber) { + if (n == 0) { + return; + } + + if (!is_vector()) { + array_inner *res = array_inner::create(n, true); + for (array_bucket *it = p->begin(); it != p->end(); it = p->next(it)) { + res->push_back_vector_value(it->value); + } + + p->dispose(); + p = res; + } else { + mutate_if_vector_shared(); + } + + const auto elements_cmp = + [&compare](const T &lhs, const T &rhs) { + return compare(lhs, rhs) > 0; + }; + T *begin = reinterpret_cast(p->entries()); + dl::sort(begin, begin + n, elements_cmp); + return; + } + + if (n <= 1) { + return; + } + + if (is_vector()) { + convert_to_map(); + } else { + mutate_if_map_shared(); + } + + array_bucket **arTmp = (array_bucket **)RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket * )); + uint32_t i = 0; + for (array_bucket *it = p->begin(); it != p->end(); it = p->next(it)) { + arTmp[i++] = it; + } + php_assert (i == n); + + const auto hash_entry_cmp = + [&compare](const array_bucket *lhs, const array_bucket *rhs) { + return compare(lhs->value, rhs->value) > 0; + }; + dl::sort(arTmp, arTmp + n, hash_entry_cmp); + + arTmp[0]->prev = p->get_pointer(p->end()); + p->end()->next = p->get_pointer(arTmp[0]); + for (uint32_t j = 1; j < n; j++) { + arTmp[j]->prev = p->get_pointer(arTmp[j - 1]); + arTmp[j - 1]->next = p->get_pointer(arTmp[j]); + } + arTmp[n - 1]->next = p->get_pointer(p->end()); + p->end()->prev = p->get_pointer(arTmp[n - 1]); + + RuntimeAllocator::get().free_script_memory(arTmp, n * sizeof(array_bucket * )); +} + + +template +template +void array::ksort(const T1 &compare) { + int64_t n = count(); + if (n <= 1) { + return; + } + + if (is_vector()) { + convert_to_map(); + } else { + mutate_if_map_shared(); + } + + array keys(array_size(n, true)); + for (auto *it = p->begin(); it != p->end(); it = p->next(it)) { + keys.p->push_back_vector_value(it->get_key()); + } + + key_type *keysp = (key_type *)keys.p->entries(); + dl::sort(keysp, keysp + n, compare); + + list_hash_entry *prev = (list_hash_entry *)p->end(); + for (uint32_t j = 0; j < n; j++) { + list_hash_entry *cur; + if (is_int_key(keysp[j])) { + int64_t int_key = keysp[j].to_int(); + uint32_t bucket = p->choose_bucket(int_key); + while (p->entries()[bucket].int_key != int_key || !p->entries()[bucket].string_key.is_dummy_string()) { + if (unlikely (++bucket == p->buf_size)) { + bucket = 0; + } + } + cur = (list_hash_entry * ) &p->entries()[bucket]; + } else { + string string_key = keysp[j].to_string(); + int64_t int_key = string_key.hash(); + array_bucket *string_entries = p->entries(); + uint32_t bucket = p->choose_bucket(int_key); + while ((string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { + if (unlikely (++bucket == p->buf_size)) { + bucket = 0; + } + } + cur = (list_hash_entry * ) & string_entries[bucket]; + } + + cur->prev = p->get_pointer(prev); + prev->next = p->get_pointer(cur); + + prev = cur; + } + prev->next = p->get_pointer(p->end()); + p->end()->prev = p->get_pointer(prev); +} + + template void array::swap(array &other) { array_inner *tmp = p; diff --git a/runtime-common/stdlib/array/array-functions.h b/runtime-common/stdlib/array/array-functions.h index a424e9681a..0a7248f643 100644 --- a/runtime-common/stdlib/array/array-functions.h +++ b/runtime-common/stdlib/array/array-functions.h @@ -638,5 +638,93 @@ bool f$array_is_list(const array &a) noexcept { // so we need to call both of them to get the precise and PHP-compatible answer return a.is_vector() || a.is_pseudo_vector(); } +template +void f$sort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.sort(array_functions_impl_::sort_compare(), true); + case SORT_NUMERIC: + return a.sort(array_functions_impl_::sort_compare_numeric(), true); + case SORT_STRING: + return a.sort(array_functions_impl_::sort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function sort"); + } +} + +template +void f$rsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.sort(array_functions_impl_::rsort_compare(), true); + case SORT_NUMERIC: + return a.sort(array_functions_impl_::rsort_compare_numeric(), true); + case SORT_STRING: + return a.sort(array_functions_impl_::rsort_compare_string(), true); + default: + php_warning("Unsupported sort_flag in function rsort"); + } +} + +template +void f$arsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.sort(array_functions_impl_::rsort_compare(), false); + case SORT_NUMERIC: + return a.sort(array_functions_impl_::rsort_compare_numeric(), false); + case SORT_STRING: + return a.sort(array_functions_impl_::rsort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function arsort"); + } +} + +template +void f$ksort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.ksort(array_functions_impl_::sort_compare::key_type>()); + case SORT_NUMERIC: + return a.ksort(array_functions_impl_::sort_compare_numeric::key_type>()); + case SORT_STRING: + return a.ksort(array_functions_impl_::sort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function ksort"); + } +} + +template +void f$krsort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.ksort(array_functions_impl_::rsort_compare::key_type>()); + case SORT_NUMERIC: + return a.ksort(array_functions_impl_::rsort_compare_numeric::key_type>()); + case SORT_STRING: + return a.ksort(array_functions_impl_::rsort_compare_string::key_type>()); + default: + php_warning("Unsupported sort_flag in function krsort"); + } +} + +template +void f$asort(array &a, int64_t flag = SORT_REGULAR) { + switch (flag) { + case SORT_REGULAR: + return a.sort(array_functions_impl_::sort_compare(), false); + case SORT_NUMERIC: + return a.sort(array_functions_impl_::sort_compare_numeric(), false); + case SORT_STRING: + return a.sort(array_functions_impl_::sort_compare_string(), false); + default: + php_warning("Unsupported sort_flag in function asort"); + } +} + +template +void f$natsort(array &a) { + return a.sort(array_functions_impl_::sort_compare_natural::key_type>(), false); +} array f$range(const mixed &from, const mixed &to, int64_t step = 1); diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 8defb95ab6..20eafefca8 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,7 +18,7 @@ namespace dl { template -requires(std::invocable) task_t sort(T *begin_init, T *end_init, Comparator compare) noexcept { +requires(std::invocable) task_t async_sort(T *begin_init, T *end_init, Comparator compare) noexcept { auto compare_call = [compare](U lhs, U rhs) -> task_t { if constexpr (is_async_function_v) { co_return co_await std::invoke(std::move(compare), std::move(lhs), std::move(rhs)); @@ -84,7 +84,7 @@ requires(std::invocable) task_t sort(T *begin_init, T *e namespace array_functions_impl_ { template -Result sort(array &arr, Comparator comparator, bool renumber) noexcept { +Result async_sort(array &arr, Comparator comparator, bool renumber) noexcept { using array_inner = typename array::array_inner; using array_bucket = typename array::array_bucket; int64_t n = arr.count(); @@ -158,7 +158,7 @@ Result sort(array &arr, Comparator comparator, bool renumber) noexcept { } template -Result ksort(array &arr, Comparator comparator) noexcept { +Result async_ksort(array &arr, Comparator comparator) noexcept { using array_bucket = typename array::array_bucket; using key_type = typename array::key_type; using list_hash_entry = typename array::list_hash_entry; @@ -425,108 +425,31 @@ array f$array_combine(const array &keys, const array &values) { php_critical_error("call to unsupported function"); } -template -task_t f$sort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare(), true); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_numeric(), true); - case SORT_STRING: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function sort"); - } -} - -template -task_t f$rsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare(), true); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_numeric(), true); - case SORT_STRING: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function rsort"); - } -} - -template -task_t f$arsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare(), false); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_numeric(), false); - case SORT_STRING: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::rsort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function arsort"); - } -} - -template -task_t f$ksort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare::key_type>()); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare_numeric::key_type>()); - case SORT_STRING: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::sort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function ksort"); - } -} - -template -task_t f$krsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare::key_type>()); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare_numeric::key_type>()); - case SORT_STRING: - co_return co_await array_functions_impl_::ksort>(a, array_functions_impl_::rsort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function krsort"); - } -} - -template -task_t f$asort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare(), false); - case SORT_NUMERIC: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_numeric(), false); - case SORT_STRING: - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function asort"); - } -} - -template -task_t f$natsort(array &a) { - co_return co_await array_functions_impl_::sort>(a, array_functions_impl_::sort_compare_natural::key_type>(), false); -} - template requires(std::invocable) task_t f$usort(array &a, Comparator compare) { - co_return co_await array_functions_impl_::sort>(a, std::move(compare), true); + if constexpr (is_async_function_v) { + co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), true); + } else { + co_return a.sort(std::move(compare), true); + } } template requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { - co_return co_await array_functions_impl_::sort>(a, std::move(compare), false); + if constexpr (is_async_function_v) { + co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), false); + } else { + co_return a.sort(std::move(compare), false); + } } template requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { - co_return co_await array_functions_impl_::ksort>(a, std::move(compare)); + if constexpr (is_async_function_v) { + co_return co_await array_functions_impl_::async_ksort>(a, std::move(compare)); + } else { + co_return a.ksort(std::move(compare)); + } } template diff --git a/runtime/array_functions.h b/runtime/array_functions.h index 7ebd201f8f..e0049fce60 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -12,189 +12,6 @@ #include "runtime-common/stdlib/array/array-functions.h" #include "runtime/math_functions.h" -namespace dl { - -template -void sort(T *begin_init, T *end_init, Comparator compare) noexcept { - T *begin_stack[32]; - T *end_stack[32]; - - begin_stack[0] = begin_init; - end_stack[0] = end_init - 1; - - for (int depth = 0; depth >= 0; --depth) { - T *begin = begin_stack[depth]; - T *end = end_stack[depth]; - - while (begin < end) { - const auto offset = (end - begin) >> 1; - swap(*begin, begin[offset]); - - T *i = begin + 1, *j = end; - - while (1) { - while (i < j && std::invoke(std::move(compare), *begin, *i) > 0) { - i++; - } - - while (i <= j && std::invoke(std::move(compare), *j, *begin) > 0) { - j--; - } - - if (i >= j) { - break; - } - - swap(*i++, *j--); - } - - swap(*begin, *j); - - if (j - begin <= end - j) { - if (j + 1 < end) { - begin_stack[depth] = j + 1; - end_stack[depth++] = end; - } - end = j - 1; - } else { - if (begin < j - 1) { - begin_stack[depth] = begin; - end_stack[depth++] = j - 1; - } - begin = j + 1; - } - } - } -} - -} // namespace dl - -namespace array_functions_impl_ { - -template -Result sort(array &arr, Comparator comparator, bool renumber) noexcept { - using array_inner = typename array::array_inner; - using array_bucket = typename array::array_bucket; - int64_t n = arr.count(); - - if (renumber) { - if (n == 0) { - return; - } - - if (!arr.is_vector()) { - array_inner *res = array_inner::create(n, true); - for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { - res->push_back_vector_value(it->value); - } - - arr.p->dispose(); - arr.p = res; - } else { - arr.mutate_if_vector_shared(); - } - - auto elements_cmp = [comparator](const U &lhs, const U &rhs) - { return std::invoke(std::move(comparator), lhs, rhs) > 0; }; - U *begin = reinterpret_cast(arr.p->entries()); - dl::sort(begin, begin + n, std::move(elements_cmp)); - return; - } - - if (n <= 1) { - return; - } - - if (arr.is_vector()) { - arr.convert_to_map(); - } else { - arr.mutate_if_map_shared(); - } - - array_bucket **arTmp = (array_bucket **)RuntimeAllocator::get().alloc_script_memory(n * sizeof(array_bucket *)); - uint32_t i = 0; - for (array_bucket *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { - arTmp[i++] = it; - } - php_assert(i == n); - - auto hash_entry_cmp = [comparator](const array_bucket *lhs, const array_bucket *rhs) - { return std::invoke(std::move(comparator), lhs->value, rhs->value) > 0; }; - dl::sort(arTmp, arTmp + n, std::move(hash_entry_cmp)); - - arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); - arr.p->end()->next = arr.p->get_pointer(arTmp[0]); - for (uint32_t j = 1; j < n; j++) { - arTmp[j]->prev = arr.p->get_pointer(arTmp[j - 1]); - arTmp[j - 1]->next = arr.p->get_pointer(arTmp[j]); - } - arTmp[n - 1]->next = arr.p->get_pointer(arr.p->end()); - arr.p->end()->prev = arr.p->get_pointer(arTmp[n - 1]); - - RuntimeAllocator::get().free_script_memory(arTmp, n * sizeof(array_bucket *)); -} - -template -Result ksort(array &arr, Comparator comparator) noexcept { - using array_bucket = typename array::array_bucket; - using key_type = typename array::key_type; - using list_hash_entry = typename array::list_hash_entry; - - int64_t n = arr.count(); - if (n <= 1) { - return; - } - - if (arr.is_vector()) { - arr.convert_to_map(); - } else { - arr.mutate_if_map_shared(); - } - - array keys(array_size(n, true)); - for (auto *it = arr.p->begin(); it != arr.p->end(); it = arr.p->next(it)) { - keys.p->push_back_vector_value(it->get_key()); - } - - key_type *keysp = (key_type *)keys.p->entries(); - dl::sort(keysp, keysp + n, std::move(comparator)); - - list_hash_entry *prev = (list_hash_entry *)arr.p->end(); - for (uint32_t j = 0; j < n; j++) { - list_hash_entry *cur; - if (arr.is_int_key(keysp[j])) { - int64_t int_key = keysp[j].to_int(); - uint32_t bucket = arr.p->choose_bucket(int_key); - while (arr.p->entries()[bucket].int_key != int_key || !arr.p->entries()[bucket].string_key.is_dummy_string()) { - if (unlikely(++bucket == arr.p->buf_size)) { - bucket = 0; - } - } - cur = (list_hash_entry *)&arr.p->entries()[bucket]; - } else { - string string_key = keysp[j].to_string(); - int64_t int_key = string_key.hash(); - array_bucket *string_entries = arr.p->entries(); - uint32_t bucket = arr.p->choose_bucket(int_key); - while ( - (string_entries[bucket].int_key != int_key || string_entries[bucket].string_key.is_dummy_string() || string_entries[bucket].string_key != string_key)) { - if (unlikely(++bucket == arr.p->buf_size)) { - bucket = 0; - } - } - cur = (list_hash_entry *)&string_entries[bucket]; - } - - cur->prev = arr.p->get_pointer(prev); - prev->next = arr.p->get_pointer(cur); - - prev = cur; - } - prev->next = arr.p->get_pointer(arr.p->end()); - arr.p->end()->prev = arr.p->get_pointer(prev); -} -} - template array f$array_splice(array &a, int64_t offset, int64_t length, const array &); @@ -264,17 +81,17 @@ void f$shuffle(array &a); template void f$usort(array &a, const T1 &compare) { - return array_functions_impl_::sort(a, compare, true); + a.sort(compare, true); } template void f$uasort(array &a, const T1 &compare) { - return array_functions_impl_::sort(a, compare, false); + a.sort(compare, false); } template void f$uksort(array &a, const T1 &compare) { - return array_functions_impl_::ksort(a, compare); + a.ksort(compare); } template @@ -856,95 +673,6 @@ void f$array_swap_int_keys(array &a, int64_t idx1, int64_t idx2) noexcept { a.swap_int_keys(idx1, idx2); } -template -void f$sort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare(), true); - case SORT_NUMERIC: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_numeric(), true); - case SORT_STRING: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function sort"); - } -} - -template -void f$rsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare(), true); - case SORT_NUMERIC: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_numeric(), true); - case SORT_STRING: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_string(), true); - default: - php_warning("Unsupported sort_flag in function rsort"); - } -} - -template -void f$arsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare(), false); - case SORT_NUMERIC: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_numeric(), false); - case SORT_STRING: - return array_functions_impl_::sort(a, array_functions_impl_::rsort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function arsort"); - } -} - -template -void f$ksort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare::key_type>()); - case SORT_NUMERIC: - return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare_numeric::key_type>()); - case SORT_STRING: - return array_functions_impl_::ksort(a, array_functions_impl_::sort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function ksort"); - } -} - -template -void f$krsort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare::key_type>()); - case SORT_NUMERIC: - return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare_numeric::key_type>()); - case SORT_STRING: - return array_functions_impl_::ksort(a, array_functions_impl_::rsort_compare_string::key_type>()); - default: - php_warning("Unsupported sort_flag in function krsort"); - } -} - -template -void f$asort(array &a, int64_t flag = SORT_REGULAR) { - switch (flag) { - case SORT_REGULAR: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare(), false); - case SORT_NUMERIC: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_numeric(), false); - case SORT_STRING: - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_string(), false); - default: - php_warning("Unsupported sort_flag in function asort"); - } -} - -template -void f$natsort(array &a) { - return array_functions_impl_::sort(a, array_functions_impl_::sort_compare_natural::key_type>(), false); -} - template T vk_dot_product_sparse(const array &a, const array &b) { T result = T(); @@ -992,3 +720,15 @@ T f$vk_dot_product(const array &a, const array &b) { } return vk_dot_product_sparse(a, b); } + +template +Result array_functions_impl_::async_sort(__attribute__((unused)) array & arr, __attribute__((unused)) Comparator comparator, __attribute__((unused)) bool renumber) noexcept { + struct async_sort_stub_class {}; + static_assert(std::is_same_v, "array async sort functions supported only in runtime light "); +} + +template +Result array_functions_impl_::async_ksort(__attribute__((unused)) array & arr, __attribute__((unused)) Comparator comparator) noexcept { + struct async_ksort_stub_class {}; + static_assert(std::is_same_v, "array async sort functions supported only in runtime light "); +} From 459922a09ceb29b2797c389c64848d819aca7e47 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 15:36:47 +0300 Subject: [PATCH 11/17] wip --- runtime-common/stdlib/array/array-functions.h | 1 + runtime/array_functions.h | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/runtime-common/stdlib/array/array-functions.h b/runtime-common/stdlib/array/array-functions.h index 0a7248f643..6ff9812214 100644 --- a/runtime-common/stdlib/array/array-functions.h +++ b/runtime-common/stdlib/array/array-functions.h @@ -638,6 +638,7 @@ bool f$array_is_list(const array &a) noexcept { // so we need to call both of them to get the precise and PHP-compatible answer return a.is_vector() || a.is_pseudo_vector(); } + template void f$sort(array &a, int64_t flag = SORT_REGULAR) { switch (flag) { diff --git a/runtime/array_functions.h b/runtime/array_functions.h index e0049fce60..2b2a00d08f 100644 --- a/runtime/array_functions.h +++ b/runtime/array_functions.h @@ -81,17 +81,17 @@ void f$shuffle(array &a); template void f$usort(array &a, const T1 &compare) { - a.sort(compare, true); + return a.sort(compare, true); } template void f$uasort(array &a, const T1 &compare) { - a.sort(compare, false); + return a.sort(compare, false); } template void f$uksort(array &a, const T1 &compare) { - a.ksort(compare); + return a.ksort(compare); } template @@ -335,8 +335,8 @@ inline Optional> f$array_column(const array &a, const mixed } template -inline auto f$array_column(const Optional &a, const mixed &column_key, const mixed &index_key = {}) - -> decltype(f$array_column(std::declval(), column_key, index_key)) { +inline auto f$array_column(const Optional &a, const mixed &column_key, + const mixed &index_key = {}) -> decltype(f$array_column(std::declval(), column_key, index_key)) { if (!a.has_value()) { php_warning("first parameter of array_column must be array"); return false; From a6dfdc1a4e43bc156d0e80ab196609b252bdf7d1 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 16:09:43 +0300 Subject: [PATCH 12/17] wip --- .../core/core-types/decl/array_decl.inl | 3 ++ runtime-light/stdlib/array/array-functions.h | 45 ++++++++----------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/runtime-common/core/core-types/decl/array_decl.inl b/runtime-common/core/core-types/decl/array_decl.inl index 33f9164524..fcf7cdc0a3 100644 --- a/runtime-common/core/core-types/decl/array_decl.inl +++ b/runtime-common/core/core-types/decl/array_decl.inl @@ -33,6 +33,9 @@ void sort(TT *begin_init, TT *end_init, T1 compare) noexcept; } namespace array_functions_impl_ { +/* + * async analog of array::sort and array::ksort since in runtime-light comparator can be coroutine + * */ template Result async_sort(array & arr, Comparator comparator, bool renumber) noexcept; diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 20eafefca8..54d0b5baf9 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -18,14 +18,8 @@ namespace dl { template -requires(std::invocable) task_t async_sort(T *begin_init, T *end_init, Comparator compare) noexcept { - auto compare_call = [compare](U lhs, U rhs) -> task_t { - if constexpr (is_async_function_v) { - co_return co_await std::invoke(std::move(compare), std::move(lhs), std::move(rhs)); - } else { - co_return std::invoke(std::move(compare), std::move(lhs), std::move(rhs)); - } - }; +requires(std::invocable && is_async_function_v) +task_t async_sort(T *begin_init, T *end_init, Comparator compare) noexcept { T *begin_stack[32]; T *end_stack[32]; @@ -44,11 +38,11 @@ requires(std::invocable) task_t async_sort(T *begin_init T *j = end; while (true) { - while (i < j && (co_await compare_call(*begin, *i)) > 0) { + while (i < j && (co_await std::invoke(compare, *begin, *i)) > 0) { i++; } - while (i <= j && (co_await compare_call(*j, *begin)) > 0) { + while (i <= j && (co_await std::invoke(compare, *j, *begin)) > 0) { j--; } @@ -106,16 +100,8 @@ Result async_sort(array &arr, Comparator comparator, bool renumber) noexcept arr.mutate_if_vector_shared(); } - const auto elements_cmp = [comparator](U lhs, U rhs) -> task_t { - if constexpr (is_async_function_v) { - co_return(co_await std::invoke(std::move(comparator), std::move(lhs), std::move(rhs))) > 0; - } else { - co_return std::invoke(std::move(comparator), std::move(lhs), std::move(rhs)) > 0; - } - }; - U *begin = reinterpret_cast(arr.p->entries()); - co_await dl::sort(begin, begin + n, elements_cmp); + co_await dl::async_sort(begin, begin + n, comparator); co_return; } @@ -136,14 +122,13 @@ Result async_sort(array &arr, Comparator comparator, bool renumber) noexcept } php_assert(i == n); - const auto hash_entry_cmp = [comparator](const array_bucket *lhs, const array_bucket *rhs) -> task_t { - if constexpr (is_async_function_v) { - co_return(co_await std::invoke(std::move(comparator), lhs->value, rhs->value)) > 0; - } else { - co_return std::invoke(std::move(comparator), lhs->value, rhs->value) > 0; - } + const auto hash_entry_cmp = [](Compare compare, const array_bucket *lhs, const array_bucket *rhs) -> task_t { + co_return(co_await std::invoke(std::move(compare), lhs->value, rhs->value)) > 0; }; - co_await dl::sort(arTmp, arTmp + n, hash_entry_cmp); + + const auto partial_hash_entry_cmp = std::bind_front(hash_entry_cmp, comparator); + + co_await dl::async_sort(arTmp, arTmp + n, partial_hash_entry_cmp); arTmp[0]->prev = arr.p->get_pointer(arr.p->end()); arr.p->end()->next = arr.p->get_pointer(arTmp[0]); @@ -180,7 +165,7 @@ Result async_ksort(array &arr, Comparator comparator) noexcept { } auto *keysp = reinterpret_cast(keys.p->entries()); - co_await dl::sort(keysp, keysp + n, std::move(comparator)); + co_await dl::async_sort(keysp, keysp + n, std::move(comparator)); auto *prev = static_cast(arr.p->end()); for (uint32_t j = 0; j < n; j++) { @@ -428,6 +413,8 @@ array f$array_combine(const array &keys, const array &values) { template requires(std::invocable) task_t f$usort(array &a, Comparator compare) { if constexpr (is_async_function_v) { + /* make copy temporary since functions is coroutine and sort is inplace */ + array tmp = a; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), true); } else { co_return a.sort(std::move(compare), true); @@ -437,6 +424,8 @@ requires(std::invocable) task_t f$usort(array &a, Com template requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { if constexpr (is_async_function_v) { + /* make copy temporary since functions is coroutine and sort is inplace */ + array tmp = a; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), false); } else { co_return a.sort(std::move(compare), false); @@ -446,6 +435,8 @@ requires(std::invocable) task_t f$uasort(array &a, Co template requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { if constexpr (is_async_function_v) { + /* make copy temporary since functions is coroutine and sort is inplace */ + array tmp = a; co_return co_await array_functions_impl_::async_ksort>(a, std::move(compare)); } else { co_return a.ksort(std::move(compare)); From 65b43a38529d944649136f407e62149d208abee8 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 16:12:32 +0300 Subject: [PATCH 13/17] fix message --- runtime-light/stdlib/array/array-functions.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 54d0b5baf9..cb4147ef31 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -413,7 +413,7 @@ array f$array_combine(const array &keys, const array &values) { template requires(std::invocable) task_t f$usort(array &a, Comparator compare) { if constexpr (is_async_function_v) { - /* make copy temporary since functions is coroutine and sort is inplace */ + /* make temporary copy since functions is coroutine and sort is inplace */ array tmp = a; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), true); } else { @@ -424,7 +424,7 @@ requires(std::invocable) task_t f$usort(array &a, Com template requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { if constexpr (is_async_function_v) { - /* make copy temporary since functions is coroutine and sort is inplace */ + /* make temporary copy since functions is coroutine and sort is inplace */ array tmp = a; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), false); } else { @@ -435,7 +435,7 @@ requires(std::invocable) task_t f$uasort(array &a, Co template requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { if constexpr (is_async_function_v) { - /* make copy temporary since functions is coroutine and sort is inplace */ + /* make temporary copy since functions is coroutine and sort is inplace */ array tmp = a; co_return co_await array_functions_impl_::async_ksort>(a, std::move(compare)); } else { From 32e77df19a51745d171de0c4c6dc892673886d6d Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 16:22:15 +0300 Subject: [PATCH 14/17] wip --- runtime-light/stdlib/array/array-functions.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index cb4147ef31..529748f045 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -72,7 +72,6 @@ task_t async_sort(T *begin_init, T *end_init, Comparator compare) noexcept } co_return; } - } // namespace dl namespace array_functions_impl_ { @@ -414,7 +413,7 @@ template requires(std::invocable) task_t f$usort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp = a; + array tmp{a}; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), true); } else { co_return a.sort(std::move(compare), true); @@ -425,7 +424,7 @@ template requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp = a; + array tmp{a}; co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), false); } else { co_return a.sort(std::move(compare), false); @@ -436,7 +435,7 @@ template requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp = a; + array tmp{a}; co_return co_await array_functions_impl_::async_ksort>(a, std::move(compare)); } else { co_return a.ksort(std::move(compare)); From ca575a4e125e06e84a075403ec14fd68f651dbcc Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Wed, 5 Feb 2025 16:46:46 +0300 Subject: [PATCH 15/17] wip --- runtime-light/stdlib/array/array-functions.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index 529748f045..bf167f391b 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -100,7 +100,7 @@ Result async_sort(array &arr, Comparator comparator, bool renumber) noexcept } U *begin = reinterpret_cast(arr.p->entries()); - co_await dl::async_sort(begin, begin + n, comparator); + co_await dl::async_sort(begin, begin + n, std::move(comparator)); co_return; } @@ -122,10 +122,10 @@ Result async_sort(array &arr, Comparator comparator, bool renumber) noexcept php_assert(i == n); const auto hash_entry_cmp = [](Compare compare, const array_bucket *lhs, const array_bucket *rhs) -> task_t { - co_return(co_await std::invoke(std::move(compare), lhs->value, rhs->value)) > 0; + co_return(co_await std::invoke(compare, lhs->value, rhs->value)) > 0; }; - const auto partial_hash_entry_cmp = std::bind_front(hash_entry_cmp, comparator); + const auto partial_hash_entry_cmp = std::bind_front(hash_entry_cmp, std::move(comparator)); co_await dl::async_sort(arTmp, arTmp + n, partial_hash_entry_cmp); From e7f597fda12d231297a11bd5462035f0dc6e5b40 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Thu, 6 Feb 2025 12:33:19 +0300 Subject: [PATCH 16/17] add tmp copy --- runtime-light/stdlib/array/array-functions.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/runtime-light/stdlib/array/array-functions.h b/runtime-light/stdlib/array/array-functions.h index bf167f391b..b514298a4c 100644 --- a/runtime-light/stdlib/array/array-functions.h +++ b/runtime-light/stdlib/array/array-functions.h @@ -413,8 +413,10 @@ template requires(std::invocable) task_t f$usort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp{a}; - co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), true); + array tmp = a; + co_await array_functions_impl_::async_sort>(tmp, std::move(compare), true); + a = tmp; + co_return; } else { co_return a.sort(std::move(compare), true); } @@ -424,8 +426,9 @@ template requires(std::invocable) task_t f$uasort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp{a}; - co_return co_await array_functions_impl_::async_sort>(a, std::move(compare), false); + array tmp = a; + co_await array_functions_impl_::async_sort>(tmp, std::move(compare), false); + a = tmp; } else { co_return a.sort(std::move(compare), false); } @@ -435,8 +438,9 @@ template requires(std::invocable::key_type, typename array::key_type>) task_t f$uksort(array &a, Comparator compare) { if constexpr (is_async_function_v) { /* make temporary copy since functions is coroutine and sort is inplace */ - array tmp{a}; - co_return co_await array_functions_impl_::async_ksort>(a, std::move(compare)); + array tmp = a; + co_await array_functions_impl_::async_ksort>(tmp, std::move(compare), false); + a = tmp; } else { co_return a.ksort(std::move(compare)); } From 87e05b92e69a01ee6332ff010d7a1f801c24c3c1 Mon Sep 17 00:00:00 2001 From: Vadim Sadokhov Date: Thu, 6 Feb 2025 12:42:06 +0300 Subject: [PATCH 17/17] rewrite func params --- compiler/code-gen/declarations.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/code-gen/declarations.cpp b/compiler/code-gen/declarations.cpp index e1218376c5..be6c236fbc 100644 --- a/compiler/code-gen/declarations.cpp +++ b/compiler/code-gen/declarations.cpp @@ -115,8 +115,8 @@ void FunctionParams::declare_cpp_param(CodeGenerator &W, VertexAdaptor v auto var_ptr = var->var_id; if (var->ref_flag) { W << "&"; - } else if (!function->is_k2_fork && (var_ptr->marked_as_const || (!function->has_variadic_param && var_ptr->is_read_only))) { - // the top of k2 fork must take arguments by value (see C++ avoid reference parameters in coroutines) + } else if (!function->is_interruptible && (var_ptr->marked_as_const || (!function->has_variadic_param && var_ptr->is_read_only))) { + // interruptible function must take arguments by value (see C++ avoid reference parameters in coroutines) W << (!type.type->is_primitive_type() ? "const &" : ""); } W << VarName(var_ptr);