Skip to content

Commit

Permalink
Fixed #5560, Allow the keys of a map to be boolean, resource, or floa…
Browse files Browse the repository at this point in the history
…t types. When the key is of string type, determine whether it represents a number.
  • Loading branch information
matyhtf committed Nov 12, 2024
1 parent 48d7851 commit c9d297a
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 29 deletions.
25 changes: 9 additions & 16 deletions ext-src/php_swoole_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ struct ArrayItem {
};

class ZendArray : public ThreadResource {
protected:
protected:
swoole::RWLock lock_;
zend_array ht;

Expand All @@ -158,7 +158,7 @@ class ZendArray : public ThreadResource {
delete item;
}

public:
public:
ZendArray() : ThreadResource(), lock_(0) {
zend_hash_init(&ht, 0, NULL, item_dtor, 1);
}
Expand Down Expand Up @@ -238,16 +238,16 @@ class ZendArray : public ThreadResource {
}

void strkey_incr(zval *zkey, zval *zvalue, zval *return_value);
void intkey_incr(zval *zkey, zval *zvalue, zval *return_value);
void intkey_incr(zend_long index, zval *zvalue, zval *return_value);
void strkey_decr(zval *zkey, zval *zvalue, zval *return_value);
void intkey_decr(zval *zkey, zval *zvalue, zval *return_value);
void intkey_decr(zend_long index, zval *zvalue, zval *return_value);
bool index_incr(zval *zkey, zval *zvalue, zval *return_value);
bool index_decr(zval *zkey, zval *zvalue, zval *return_value);

void strkey_add(zval *zkey, zval *zvalue, zval *return_value);
void intkey_add(zval *zkey, zval *zvalue, zval *return_value);
void intkey_add(zend_long index, zval *zvalue, zval *return_value);
void strkey_update(zval *zkey, zval *zvalue, zval *return_value);
void intkey_update(zval *zkey, zval *zvalue, zval *return_value);
void intkey_update(zend_long index, zval *zvalue, zval *return_value);

void count(zval *return_value) {
lock_.lock_rd();
Expand All @@ -269,26 +269,19 @@ class ZendArray : public ThreadResource {
lock_.unlock();
}

void intkey_offsetGet(zval *zkey, zval *return_value) {
intkey_offsetGet(zval_get_long(zkey), return_value);
}

void intkey_offsetExists(zval *zkey, zval *return_value) {
zend_long index = zval_get_long(zkey);
void intkey_offsetExists(zend_long index, zval *return_value) {
lock_.lock_rd();
RETVAL_BOOL(intkey_exists(index));
lock_.unlock();
}

void intkey_offsetUnset(zval *zkey) {
zend_long index = zval_get_long(zkey);
void intkey_offsetUnset(zend_long index) {
lock_.lock();
zend_hash_index_del(&ht, index);
lock_.unlock();
}

void intkey_offsetSet(zval *zkey, zval *zvalue) {
zend_long index = zval_get_long(zkey);
void intkey_offsetSet(zend_long index, zval *zvalue) {
auto item = new ArrayItem(zvalue);
lock_.lock();
zend_hash_index_update_ptr(&ht, index, item);
Expand Down
13 changes: 5 additions & 8 deletions ext-src/swoole_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -824,9 +824,8 @@ void ZendArray::strkey_incr(zval *zkey, zval *zvalue, zval *return_value) {
lock_.unlock();
}

void ZendArray::intkey_incr(zval *zkey, zval *zvalue, zval *return_value) {
void ZendArray::intkey_incr(zend_long index, zval *zvalue, zval *return_value) {
ArrayItem *item;
zend_long index = zval_get_long(zkey);
lock_.lock();
item = (ArrayItem *) (ArrayItem *) zend_hash_index_find_ptr(&ht, index);
if (item) {
Expand All @@ -844,9 +843,9 @@ void ZendArray::strkey_decr(zval *zkey, zval *zvalue, zval *return_value) {
strkey_incr(zkey, &rvalue, return_value);
}

void ZendArray::intkey_decr(zval *zkey, zval *zvalue, zval *return_value) {
void ZendArray::intkey_decr(zend_long index, zval *zvalue, zval *return_value) {
INIT_DECR_VALUE(zvalue);
intkey_incr(zkey, &rvalue, return_value);
intkey_incr(index, &rvalue, return_value);
}

void ZendArray::strkey_add(zval *zkey, zval *zvalue, zval *return_value) {
Expand All @@ -861,8 +860,7 @@ void ZendArray::strkey_add(zval *zkey, zval *zvalue, zval *return_value) {
lock_.unlock();
}

void ZendArray::intkey_add(zval *zkey, zval *zvalue, zval *return_value) {
zend_long index = zval_get_long(zkey);
void ZendArray::intkey_add(zend_long index, zval *zvalue, zval *return_value) {
lock_.lock();
if (intkey_exists(index)) {
RETVAL_FALSE;
Expand All @@ -887,8 +885,7 @@ void ZendArray::strkey_update(zval *zkey, zval *zvalue, zval *return_value) {
lock_.unlock();
}

void ZendArray::intkey_update(zval *zkey, zval *zvalue, zval *return_value) {
zend_long index = zval_get_long(zkey);
void ZendArray::intkey_update(zend_long index, zval *zvalue, zval *return_value) {
lock_.lock();
if (!intkey_exists(index)) {
RETVAL_FALSE;
Expand Down
45 changes: 40 additions & 5 deletions ext-src/swoole_thread_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ void php_swoole_thread_map_minit(int module_number) {
swoole_thread_map_ce->ce_flags |= ZEND_ACC_FINAL | ZEND_ACC_NOT_SERIALIZABLE;
SW_SET_CLASS_CLONEABLE(swoole_thread_map, sw_zend_class_clone_deny);
SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_thread_map, sw_zend_class_unset_property_deny);
SW_SET_CLASS_CUSTOM_OBJECT(
swoole_thread_map, map_create_object, map_free_object, ThreadMapObject, std);
SW_SET_CLASS_CUSTOM_OBJECT(swoole_thread_map, map_create_object, map_free_object, ThreadMapObject, std);

zend_class_implements(swoole_thread_map_ce, 2, zend_ce_arrayaccess, zend_ce_countable);
}
Expand All @@ -141,11 +140,47 @@ static PHP_METHOD(swoole_thread_map, __construct) {
}
}

static int handle_array_key(zval *key, zend_ulong *idx) {
switch (Z_TYPE_P(key)) {
case IS_STRING:
return _zend_handle_numeric_str(Z_STRVAL_P(key), Z_STRLEN_P(key), idx) ? IS_LONG : IS_STRING;
case IS_LONG:
*idx = Z_LVAL_P(key);
return IS_LONG;
case IS_NULL:
return IS_NULL;
case IS_DOUBLE:
*idx = Z_DVAL_P(key);
return IS_LONG;
case IS_FALSE:
*idx = 0;
return IS_LONG;
case IS_TRUE:
*idx = 1;
return IS_LONG;
case IS_RESOURCE:
zend_use_resource_as_offset(key);
*idx = Z_RES_HANDLE_P(key);
return IS_LONG;
default:
zend_argument_type_error(1, "Illegal offset type");
return IS_UNDEF;
}
}

#define ZEND_ARRAY_CALL_METHOD(array, method, zkey, ...) \
if (ZVAL_IS_LONG(zkey)) { \
array->intkey_##method(zkey, ##__VA_ARGS__); \
} else { \
zend_ulong idx; \
int type_of_key = handle_array_key(zkey, &idx); \
if (type_of_key == IS_LONG) { \
array->intkey_##method(idx, ##__VA_ARGS__); \
} else if (type_of_key == IS_STRING) { \
array->strkey_##method(zkey, ##__VA_ARGS__); \
} else if (type_of_key == IS_NULL) { \
zval empty_str; \
ZVAL_EMPTY_STRING(&empty_str); \
array->strkey_##method(&empty_str, ##__VA_ARGS__); \
} else { \
zend_type_error("Illegal offset type"); \
}

static PHP_METHOD(swoole_thread_map, offsetGet) {
Expand Down
46 changes: 46 additions & 0 deletions tests/swoole_thread/numeric_strkey.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
swoole_thread: numeric key
--SKIPIF--
<?php
require __DIR__ . '/../include/skipif.inc';
skip_if_nts();
?>
--FILE--
<?php

use Swoole\Thread\Map;

require __DIR__ . '/../include/bootstrap.php';
$uuid = uniqid();

const I_KEY = 6666;
const S_KEY = '6666';

$arr = new Map([S_KEY => 2222, 'test' => $uuid]);
Assert::eq($arr[S_KEY], 2222);
Assert::eq($arr[6666], 2222);
Assert::eq($arr['test'], $uuid);

unset($arr[S_KEY]);
Assert::false(isset($arr[S_KEY]));
Assert::keyNotExists($arr->toArray(), I_KEY);

$uuid2 = uniqid();
$arr[6666.66] = $uuid2;
$arr['6666.66'] = $uuid2;
Assert::eq($arr[6666], $uuid2);

$arr[true] = $uuid2;
$arr[false] = $uuid2;
$arr[null] = $uuid2;

$stream = fopen('php://stdin', 'r+');
@$arr[$stream] = $uuid2;

Assert::eq($arr[true], $uuid2);
Assert::eq($arr[false], $uuid2);
Assert::eq($arr[null], $uuid2);
Assert::eq(@$arr[$stream], $uuid2);

?>
--EXPECTF--

0 comments on commit c9d297a

Please sign in to comment.