Skip to content

Commit

Permalink
Added Thread\Map::sort() & Thread\ArrayList::sort() --filter=[thread]
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Jan 7, 2025
1 parent 28c2d15 commit 016bec5
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 4 deletions.
3 changes: 3 additions & 0 deletions ext-src/php_swoole_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ struct ArrayItem {
void release();
bool equals(zval *zvalue);

static int compare(Bucket *a, Bucket *b);

~ArrayItem() {
if (value.str) {
release();
Expand Down Expand Up @@ -257,6 +259,7 @@ class ZendArray : public ThreadResource {
void values(zval *return_value);
void to_array(zval *return_value);
void find(zval *search, zval *return_value);
void sort(bool renumber);

void intkey_offsetGet(zend_long index, zval *return_value) {
lock_.lock_rd();
Expand Down
1 change: 1 addition & 0 deletions ext-src/stubs/php_swoole_thread_arraylist.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public function incr(mixed $key, mixed $value = 1): mixed {}
public function decr(mixed $key, mixed $value = 1): mixed {}
public function clean(): void {}
public function toArray(): array {}
public function sort(): void {}
}
}
4 changes: 3 additions & 1 deletion ext-src/stubs/php_swoole_thread_arraylist_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 1ca9dca970881ea647b0ebc5431e857cdb973eb8 */
* Stub hash: f9c390449be28ec68af8381a013572dde33448c8 */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Thread_ArrayList___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, array, IS_ARRAY, 1, "null")
Expand Down Expand Up @@ -41,3 +41,5 @@ ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_ArrayList_toArray, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()

#define arginfo_class_Swoole_Thread_ArrayList_sort arginfo_class_Swoole_Thread_ArrayList_clean
1 change: 1 addition & 0 deletions ext-src/stubs/php_swoole_thread_map.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ public function add(mixed $key, mixed $value): bool {}
public function update(mixed $key, mixed $value): bool {}
public function clean(): void {}
public function toArray(): array {}
public function sort(): void {}
}
}
4 changes: 3 additions & 1 deletion ext-src/stubs/php_swoole_thread_map_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 39226ea3aff361cc9530c65fe7de5a0e276a65fe */
* Stub hash: 4bc51546a707aba5df4b09a506e67dcc90b30d9f */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Thread_Map___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, array, IS_ARRAY, 1, "null")
Expand Down Expand Up @@ -52,3 +52,5 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Thread_Map_clean, 0
ZEND_END_ARG_INFO()

#define arginfo_class_Swoole_Thread_Map_toArray arginfo_class_Swoole_Thread_Map_keys

#define arginfo_class_Swoole_Thread_Map_sort arginfo_class_Swoole_Thread_Map_clean
138 changes: 136 additions & 2 deletions ext-src/swoole_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,7 @@ void php_swoole_thread_rshutdown() {
return;
}
if (sw_active_thread_count() > 1) {
swoole_warning("Fatal Error: %zu active threads are running, cannot exit safely.",
sw_active_thread_count());
swoole_warning("Fatal Error: %zu active threads are running, cannot exit safely.", sw_active_thread_count());
exit(200);
}
if (request_info.path_translated) {
Expand Down Expand Up @@ -672,6 +671,135 @@ bool ArrayItem::equals(zval *zvalue) {
}
}

#define TYPE_PAIR(t1, t2) (((t1) << 4) | (t2))
#define ITEM_TYPE(item) (item->type)
#define ITEM_LVAL(item) (item->value.lval)
#define ITEM_DVAL(item) (item->value.dval)
#define ITEM_STR(item) (item->value.str)

static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
{
zend_long str_lval;
double str_dval;
zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);

if (type == IS_LONG) {
return lval > str_lval ? 1 : lval < str_lval ? -1 : 0;
}

if (type == IS_DOUBLE) {
double diff = (double) lval - str_dval;
return ZEND_NORMALIZE_BOOL(diff);
}

zend_string *lval_as_str = zend_long_to_str(lval);
int cmp_result = zend_binary_strcmp(ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
zend_string_release(lval_as_str);
return ZEND_NORMALIZE_BOOL(cmp_result);
}
/* }}} */

static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
{
zend_long str_lval;
double str_dval;
zend_uchar type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);

if (type == IS_LONG) {
double diff = dval - (double) str_lval;
return ZEND_NORMALIZE_BOOL(diff);
}

if (type == IS_DOUBLE) {
if (dval == str_dval) {
return 0;
}
return ZEND_NORMALIZE_BOOL(dval - str_dval);
}

zend_string *dval_as_str = zend_double_to_str(dval);
int cmp_result = zend_binary_strcmp(ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
zend_string_release(dval_as_str);
return ZEND_NORMALIZE_BOOL(cmp_result);
}
/* }}} */

int ArrayItem::compare(Bucket *a, Bucket *b) {
ArrayItem *op1 = static_cast<ArrayItem *>(Z_PTR(a->val));
ArrayItem *op2 = static_cast<ArrayItem *>(Z_PTR(b->val));

switch (TYPE_PAIR(ITEM_TYPE(op1), ITEM_TYPE(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG):
return ITEM_LVAL(op1) > ITEM_LVAL(op2) ? 1 : (ITEM_LVAL(op1) < ITEM_LVAL(op2) ? -1 : 0);

case TYPE_PAIR(IS_DOUBLE, IS_LONG):
return ZEND_NORMALIZE_BOOL(ITEM_DVAL(op1) - (double) ITEM_LVAL(op2));

case TYPE_PAIR(IS_LONG, IS_DOUBLE):
return ZEND_NORMALIZE_BOOL((double) ITEM_LVAL(op1) - ITEM_DVAL(op2));

case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
if (ITEM_DVAL(op1) == ITEM_DVAL(op2)) {
return 0;
} else {
return ZEND_NORMALIZE_BOOL(ITEM_DVAL(op1) - ITEM_DVAL(op2));
}

case TYPE_PAIR(IS_NULL, IS_NULL):
case TYPE_PAIR(IS_NULL, IS_FALSE):
case TYPE_PAIR(IS_FALSE, IS_NULL):
case TYPE_PAIR(IS_FALSE, IS_FALSE):
case TYPE_PAIR(IS_TRUE, IS_TRUE):
return 0;

case TYPE_PAIR(IS_NULL, IS_TRUE):
return -1;

case TYPE_PAIR(IS_TRUE, IS_NULL):
return 1;

case TYPE_PAIR(IS_STRING, IS_STRING):
if (ITEM_STR(op1) == ITEM_STR(op2)) {
return 0;
}
return zendi_smart_strcmp(ITEM_STR(op1), ITEM_STR(op2));

case TYPE_PAIR(IS_NULL, IS_STRING):
return Z_STRLEN_P(op2) == 0 ? 0 : -1;

case TYPE_PAIR(IS_STRING, IS_NULL):
return Z_STRLEN_P(op1) == 0 ? 0 : 1;

case TYPE_PAIR(IS_LONG, IS_STRING):
return compare_long_to_string(ITEM_LVAL(op1), ITEM_STR(op2));

case TYPE_PAIR(IS_STRING, IS_LONG):
return -compare_long_to_string(ITEM_LVAL(op2), ITEM_STR(op1));

case TYPE_PAIR(IS_DOUBLE, IS_STRING):
if (zend_isnan(ITEM_DVAL(op1))) {
return 1;
}
return compare_double_to_string(ITEM_DVAL(op1), ITEM_STR(op2));

case TYPE_PAIR(IS_STRING, IS_DOUBLE):
if (zend_isnan(ITEM_DVAL(op2))) {
return 1;
}
return -compare_double_to_string(ITEM_DVAL(op2), ITEM_STR(op1));

case TYPE_PAIR(IS_OBJECT, IS_NULL):
return 1;

case TYPE_PAIR(IS_NULL, IS_OBJECT):
return -1;

default:
zend_throw_error(NULL, "Unsupported operand types");
return 1;
}
}

void ArrayItem::fetch(zval *return_value) {
switch (type) {
case IS_LONG:
Expand Down Expand Up @@ -1045,6 +1173,12 @@ void ZendArray::find(zval *search, zval *return_value) {
lock_.unlock();
}

void ZendArray::sort(bool renumber) {
lock_.lock();
zend_hash_sort(&ht, ArrayItem::compare, renumber);
lock_.unlock();
}

ZendArray *ZendArray::from(zend_array *src) {
zend_string *key;
zend_ulong index;
Expand Down
7 changes: 7 additions & 0 deletions ext-src/swoole_thread_arraylist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static PHP_METHOD(swoole_thread_arraylist, incr);
static PHP_METHOD(swoole_thread_arraylist, decr);
static PHP_METHOD(swoole_thread_arraylist, clean);
static PHP_METHOD(swoole_thread_arraylist, toArray);
static PHP_METHOD(swoole_thread_arraylist, sort);
SW_EXTERN_C_END

static sw_inline ThreadArrayListObject *arraylist_fetch_object(zend_object *obj) {
Expand Down Expand Up @@ -98,6 +99,7 @@ static const zend_function_entry swoole_thread_arraylist_methods[] = {
PHP_ME(swoole_thread_arraylist, clean, arginfo_class_Swoole_Thread_ArrayList_clean, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_arraylist, count, arginfo_class_Swoole_Thread_ArrayList_count, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_arraylist, toArray, arginfo_class_Swoole_Thread_ArrayList_toArray, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_arraylist, sort, arginfo_class_Swoole_Thread_ArrayList_sort, ZEND_ACC_PUBLIC)
PHP_FE_END
};
// clang-format on
Expand Down Expand Up @@ -230,4 +232,9 @@ static PHP_METHOD(swoole_thread_arraylist, toArray) {
auto ao = arraylist_fetch_object_check(ZEND_THIS);
ao->list->to_array(return_value);
}

static PHP_METHOD(swoole_thread_arraylist, sort) {
auto ao = arraylist_fetch_object_check(ZEND_THIS);
ao->list->sort(true);
}
#endif
6 changes: 6 additions & 0 deletions ext-src/swoole_thread_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static PHP_METHOD(swoole_thread_map, add);
static PHP_METHOD(swoole_thread_map, update);
static PHP_METHOD(swoole_thread_map, clean);
static PHP_METHOD(swoole_thread_map, toArray);
static PHP_METHOD(swoole_thread_map, sort);
SW_EXTERN_C_END

// clang-format off
Expand All @@ -106,6 +107,7 @@ static const zend_function_entry swoole_thread_map_methods[] = {
PHP_ME(swoole_thread_map, keys, arginfo_class_Swoole_Thread_Map_keys, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_map, values, arginfo_class_Swoole_Thread_Map_values, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_map, toArray, arginfo_class_Swoole_Thread_Map_toArray, ZEND_ACC_PUBLIC)
PHP_ME(swoole_thread_map, sort, arginfo_class_Swoole_Thread_Map_sort, ZEND_ACC_PUBLIC)
PHP_FE_END
};
// clang-format on
Expand Down Expand Up @@ -303,4 +305,8 @@ static PHP_METHOD(swoole_thread_map, clean) {
mo->map->clean();
}

static PHP_METHOD(swoole_thread_map, sort) {
auto mo = map_fetch_object_check(ZEND_THIS);
mo->map->sort(false);
}
#endif
37 changes: 37 additions & 0 deletions tests/swoole_thread/sort.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
swoole_thread: sort
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';

use Swoole\Thread\Map;
use Swoole\Thread\ArrayList;

$original_map = array(
"l" => "lemon",
"o" => "orange",
"O" => "Orange",
"O1" => "Orange1",
"o2" => "orange2",
"O3" => "Orange3",
"o20" => "orange20",
"b" => "banana",
);

$unsorted_map = new Map($original_map);
$unsorted_map->sort();

$copied_map = $original_map;
asort($copied_map);
Assert::eq($unsorted_map->toArray(), $copied_map);

$original_list = array( 100, 33, 555, 22 );
$copied_list = $original_list;

$unsorted_list = new ArrayList($original_list);
$unsorted_list->sort();
sort($copied_list);
Assert::eq($unsorted_list->toArray(), $copied_list);
?>
--EXPECT--

0 comments on commit 016bec5

Please sign in to comment.