Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[k2] make sort functions implementation runtime specific #1208

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
19 changes: 18 additions & 1 deletion builtin-functions/kphp-light/array.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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;



4 changes: 0 additions & 4 deletions builtin-functions/kphp-light/unsupported/arrays.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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[*];

22 changes: 15 additions & 7 deletions runtime-common/core/core-types/decl/array_decl.inl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,15 @@ struct array_size {

namespace dl {
template<class T, class TT, class T1>
void sort(TT *begin_init, TT *end_init, const T1 &compare);
void sort(TT *begin_init, TT *end_init, T1 compare) noexcept;
}

namespace array_functions_impl_ {
template<typename Result, typename U, typename Comparator>
Result sort(array<U> & arr, Comparator comparator, bool renumber) noexcept;

template<typename Result, typename U, typename Comparator>
Result ksort(array<U> & arr, Comparator comparator) noexcept;
}

enum class overwrite_element { YES, NO };
Expand Down Expand Up @@ -377,12 +385,6 @@ public:
inline iterator middle(int64_t n) __attribute__ ((always_inline));
inline iterator end() __attribute__ ((always_inline));

template<class T1>
void sort(const T1 &compare, bool renumber);

template<class T1>
void ksort(const T1 &compare);

inline void swap(array &other) __attribute__ ((always_inline));


Expand Down Expand Up @@ -438,6 +440,12 @@ private:

template<class T1>
friend class array;

template<typename Result, typename U, typename Comparator>
friend Result array_functions_impl_::sort(array<U> & arr, Comparator comparator, bool renumber) noexcept;

template<typename Result, typename U, typename Comparator>
friend Result array_functions_impl_::ksort(array<U> & arr, Comparator comparator) noexcept;
};

template<class T>
Expand Down
180 changes: 0 additions & 180 deletions runtime-common/core/core-types/definition/array.inl
Original file line number Diff line number Diff line change
Expand Up @@ -36,62 +36,6 @@ array_size &array_size::min(const array_size &other) noexcept {
return *this;
}

namespace dl {

template<class T, class T1>
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<class T>
typename array<T>::key_type array<T>::array_bucket::get_key() const {
Expand Down Expand Up @@ -1884,130 +1828,6 @@ int64_t array<T>::get_next_key() const {
}


template<class T>
template<class T1>
void array<T>::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<T *>(p->entries());
dl::sort<T, decltype(elements_cmp)>(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<array_bucket *, decltype(hash_entry_cmp)>(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<class T>
template<class T1>
void array<T>::ksort(const T1 &compare) {
int64_t n = count();
if (n <= 1) {
return;
}

if (is_vector()) {
convert_to_map();
} else {
mutate_if_map_shared();
}

array<key_type> 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<key_type, T1>(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<class T>
void array<T>::swap(array<T> &other) {
array_inner *tmp = p;
Expand Down
89 changes: 0 additions & 89 deletions runtime-common/stdlib/array/array-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -639,93 +639,4 @@ bool f$array_is_list(const array<T> &a) noexcept {
return a.is_vector() || a.is_pseudo_vector();
}

template<class T>
void f$sort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.sort(array_functions_impl_::sort_compare<T>(), true);
case SORT_NUMERIC:
return a.sort(array_functions_impl_::sort_compare_numeric<T>(), true);
case SORT_STRING:
return a.sort(array_functions_impl_::sort_compare_string<T>(), true);
default:
php_warning("Unsupported sort_flag in function sort");
}
}

template<class T>
void f$rsort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.sort(array_functions_impl_::rsort_compare<T>(), true);
case SORT_NUMERIC:
return a.sort(array_functions_impl_::rsort_compare_numeric<T>(), true);
case SORT_STRING:
return a.sort(array_functions_impl_::rsort_compare_string<T>(), true);
default:
php_warning("Unsupported sort_flag in function rsort");
}
}

template<class T>
void f$arsort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.sort(array_functions_impl_::rsort_compare<T>(), false);
case SORT_NUMERIC:
return a.sort(array_functions_impl_::rsort_compare_numeric<T>(), false);
case SORT_STRING:
return a.sort(array_functions_impl_::rsort_compare_string<T>(), false);
default:
php_warning("Unsupported sort_flag in function arsort");
}
}

template<class T>
void f$ksort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.ksort(array_functions_impl_::sort_compare<typename array<T>::key_type>());
case SORT_NUMERIC:
return a.ksort(array_functions_impl_::sort_compare_numeric<typename array<T>::key_type>());
case SORT_STRING:
return a.ksort(array_functions_impl_::sort_compare_string<typename array<T>::key_type>());
default:
php_warning("Unsupported sort_flag in function ksort");
}
}

template<class T>
void f$krsort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.ksort(array_functions_impl_::rsort_compare<typename array<T>::key_type>());
case SORT_NUMERIC:
return a.ksort(array_functions_impl_::rsort_compare_numeric<typename array<T>::key_type>());
case SORT_STRING:
return a.ksort(array_functions_impl_::rsort_compare_string<typename array<T>::key_type>());
default:
php_warning("Unsupported sort_flag in function krsort");
}
}

template<class T>
void f$asort(array<T> &a, int64_t flag = SORT_REGULAR) {
switch (flag) {
case SORT_REGULAR:
return a.sort(array_functions_impl_::sort_compare<T>(), false);
case SORT_NUMERIC:
return a.sort(array_functions_impl_::sort_compare_numeric<T>(), false);
case SORT_STRING:
return a.sort(array_functions_impl_::sort_compare_string<T>(), false);
default:
php_warning("Unsupported sort_flag in function asort");
}
}

template<class T>
void f$natsort(array<T> &a) {
return a.sort(array_functions_impl_::sort_compare_natural<typename array<T>::key_type>(), false);
}

array<mixed> f$range(const mixed &from, const mixed &to, int64_t step = 1);
Loading
Loading