Commit 3a0382e9 authored by Paul Yang's avatar Paul Yang Committed by GitHub

Add map iterator for c extension (#3350)

parent d3bbf1c8
...@@ -143,6 +143,7 @@ static zend_function_entry map_field_methods[] = { ...@@ -143,6 +143,7 @@ static zend_function_entry map_field_methods[] = {
PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC)
PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(MapField, getIterator, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END ZEND_FE_END
}; };
...@@ -156,7 +157,10 @@ static void map_field_write_dimension(zval *object, zval *key, ...@@ -156,7 +157,10 @@ static void map_field_write_dimension(zval *object, zval *key,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
zend_class_entry* map_field_type; zend_class_entry* map_field_type;
zend_class_entry* map_field_iter_type;
zend_object_handlers* map_field_handlers; zend_object_handlers* map_field_handlers;
zend_object_handlers* map_field_iter_handlers;
static void map_begin_internal(Map *map, MapIter *iter) { static void map_begin_internal(Map *map, MapIter *iter) {
iter->self = map; iter->self = map;
...@@ -231,8 +235,8 @@ PHP_PROTO_OBJECT_CREATE_END(Map, map_field) ...@@ -231,8 +235,8 @@ PHP_PROTO_OBJECT_CREATE_END(Map, map_field)
// Init class entry. // Init class entry.
PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapField", Map, PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapField", Map,
map_field) map_field)
zend_class_implements(map_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess, zend_class_implements(map_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
spl_ce_Countable); zend_ce_aggregate, spl_ce_Countable);
map_field_handlers->write_dimension = map_field_write_dimension; map_field_handlers->write_dimension = map_field_write_dimension;
map_field_handlers->get_gc = map_field_get_gc; map_field_handlers->get_gc = map_field_get_gc;
PHP_PROTO_INIT_CLASS_END PHP_PROTO_INIT_CLASS_END
...@@ -444,6 +448,15 @@ PHP_METHOD(MapField, count) { ...@@ -444,6 +448,15 @@ PHP_METHOD(MapField, count) {
RETURN_LONG(upb_strtable_count(&intern->table)); RETURN_LONG(upb_strtable_count(&intern->table));
} }
PHP_METHOD(MapField, getIterator) {
CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value,
map_field_iter_type);
Map *intern = UNBOX(Map, getThis());
MapIter *iter = UNBOX(MapIter, return_value);
map_begin(getThis(), iter TSRMLS_CC);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Map Iterator // Map Iterator
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -470,3 +483,79 @@ upb_value map_iter_value(MapIter *iter, int *len) { ...@@ -470,3 +483,79 @@ upb_value map_iter_value(MapIter *iter, int *len) {
*len = native_slot_size(iter->self->value_type); *len = native_slot_size(iter->self->value_type);
return upb_strtable_iter_value(&iter->it); return upb_strtable_iter_value(&iter->it);
} }
// -----------------------------------------------------------------------------
// MapFieldIter methods
// -----------------------------------------------------------------------------
static zend_function_entry map_field_iter_methods[] = {
PHP_ME(MapFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(MapFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(MapFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(MapFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(MapFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
// -----------------------------------------------------------------------------
// MapFieldIter creation/desctruction
// -----------------------------------------------------------------------------
// Define object free method.
PHP_PROTO_OBJECT_FREE_START(MapIter, map_field_iter)
PHP_PROTO_OBJECT_FREE_END
PHP_PROTO_OBJECT_DTOR_START(MapIter, map_field_iter)
PHP_PROTO_OBJECT_DTOR_END
// Define object create method.
PHP_PROTO_OBJECT_CREATE_START(MapIter, map_field_iter)
intern->self = NULL;
PHP_PROTO_OBJECT_CREATE_END(MapIter, map_field_iter)
// Init class entry.
PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapFieldIter",
MapIter, map_field_iter)
zend_class_implements(map_field_iter_type TSRMLS_CC, 1, zend_ce_iterator);
PHP_PROTO_INIT_CLASS_END
// -----------------------------------------------------------------------------
// PHP MapFieldIter Methods
// -----------------------------------------------------------------------------
PHP_METHOD(MapFieldIter, rewind) {
MapIter *intern = UNBOX(MapIter, getThis());
map_begin_internal(intern->self, intern);
}
PHP_METHOD(MapFieldIter, current) {
MapIter *intern = UNBOX(MapIter, getThis());
Map *map_field = intern->self;
int value_length = 0;
upb_value value = map_iter_value(intern, &value_length);
void* mem = upb_value_memory(&value);
native_slot_get_by_array(map_field->value_type, mem,
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
}
PHP_METHOD(MapFieldIter, key) {
MapIter *intern = UNBOX(MapIter, getThis());
Map *map_field = intern->self;
int key_length = 0;
const char* key = map_iter_key(intern, &key_length);
native_slot_get_by_map_key(map_field->key_type, key, key_length,
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
}
PHP_METHOD(MapFieldIter, next) {
MapIter *intern = UNBOX(MapIter, getThis());
map_next(intern);
}
PHP_METHOD(MapFieldIter, valid) {
MapIter *intern = UNBOX(MapIter, getThis());
RETURN_BOOL(!map_done(intern));
}
...@@ -189,6 +189,7 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) { ...@@ -189,6 +189,7 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) {
static PHP_MINIT_FUNCTION(protobuf) { static PHP_MINIT_FUNCTION(protobuf) {
map_field_init(TSRMLS_C); map_field_init(TSRMLS_C);
map_field_iter_init(TSRMLS_C);
repeated_field_init(TSRMLS_C); repeated_field_init(TSRMLS_C);
repeated_field_iter_init(TSRMLS_C); repeated_field_iter_init(TSRMLS_C);
gpb_type_init(TSRMLS_C); gpb_type_init(TSRMLS_C);
...@@ -206,6 +207,7 @@ static PHP_MSHUTDOWN_FUNCTION(protobuf) { ...@@ -206,6 +207,7 @@ static PHP_MSHUTDOWN_FUNCTION(protobuf) {
PEFREE(repeated_field_handlers); PEFREE(repeated_field_handlers);
PEFREE(repeated_field_iter_handlers); PEFREE(repeated_field_iter_handlers);
PEFREE(map_field_handlers); PEFREE(map_field_handlers);
PEFREE(map_field_iter_handlers);
return 0; return 0;
} }
...@@ -373,6 +373,7 @@ struct MessageLayout; ...@@ -373,6 +373,7 @@ struct MessageLayout;
struct RepeatedField; struct RepeatedField;
struct RepeatedFieldIter; struct RepeatedFieldIter;
struct Map; struct Map;
struct MapIter;
struct Oneof; struct Oneof;
typedef struct DescriptorPool DescriptorPool; typedef struct DescriptorPool DescriptorPool;
...@@ -385,6 +386,7 @@ typedef struct MessageLayout MessageLayout; ...@@ -385,6 +386,7 @@ typedef struct MessageLayout MessageLayout;
typedef struct RepeatedField RepeatedField; typedef struct RepeatedField RepeatedField;
typedef struct RepeatedFieldIter RepeatedFieldIter; typedef struct RepeatedFieldIter RepeatedFieldIter;
typedef struct Map Map; typedef struct Map Map;
typedef struct MapIter MapIter;
typedef struct Oneof Oneof; typedef struct Oneof Oneof;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -400,6 +402,7 @@ void enum_descriptor_init(TSRMLS_D); ...@@ -400,6 +402,7 @@ void enum_descriptor_init(TSRMLS_D);
void descriptor_pool_init(TSRMLS_D); void descriptor_pool_init(TSRMLS_D);
void gpb_type_init(TSRMLS_D); void gpb_type_init(TSRMLS_D);
void map_field_init(TSRMLS_D); void map_field_init(TSRMLS_D);
void map_field_iter_init(TSRMLS_D);
void repeated_field_init(TSRMLS_D); void repeated_field_init(TSRMLS_D);
void repeated_field_iter_init(TSRMLS_D); void repeated_field_iter_init(TSRMLS_D);
void util_init(TSRMLS_D); void util_init(TSRMLS_D);
...@@ -659,6 +662,7 @@ void native_slot_get_default(upb_fieldtype_t type, ...@@ -659,6 +662,7 @@ void native_slot_get_default(upb_fieldtype_t type,
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
extern zend_object_handlers* map_field_handlers; extern zend_object_handlers* map_field_handlers;
extern zend_object_handlers* map_field_iter_handlers;
PHP_PROTO_WRAP_OBJECT_START(Map) PHP_PROTO_WRAP_OBJECT_START(Map)
upb_fieldtype_t key_type; upb_fieldtype_t key_type;
...@@ -667,10 +671,10 @@ PHP_PROTO_WRAP_OBJECT_START(Map) ...@@ -667,10 +671,10 @@ PHP_PROTO_WRAP_OBJECT_START(Map)
upb_strtable table; upb_strtable table;
PHP_PROTO_WRAP_OBJECT_END PHP_PROTO_WRAP_OBJECT_END
typedef struct { PHP_PROTO_WRAP_OBJECT_START(MapIter)
Map* self; Map* self;
upb_strtable_iter it; upb_strtable_iter it;
} MapIter; PHP_PROTO_WRAP_OBJECT_END
void map_begin(zval* self, MapIter* iter TSRMLS_DC); void map_begin(zval* self, MapIter* iter TSRMLS_DC);
void map_next(MapIter* iter); void map_next(MapIter* iter);
...@@ -709,6 +713,13 @@ PHP_METHOD(MapField, offsetGet); ...@@ -709,6 +713,13 @@ PHP_METHOD(MapField, offsetGet);
PHP_METHOD(MapField, offsetSet); PHP_METHOD(MapField, offsetSet);
PHP_METHOD(MapField, offsetUnset); PHP_METHOD(MapField, offsetUnset);
PHP_METHOD(MapField, count); PHP_METHOD(MapField, count);
PHP_METHOD(MapField, getIterator);
PHP_METHOD(MapFieldIter, rewind);
PHP_METHOD(MapFieldIter, current);
PHP_METHOD(MapFieldIter, key);
PHP_METHOD(MapFieldIter, next);
PHP_METHOD(MapFieldIter, valid);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Repeated Field. // Repeated Field.
......
...@@ -355,6 +355,19 @@ void native_slot_get_by_array(upb_fieldtype_t type, const void* memory, ...@@ -355,6 +355,19 @@ void native_slot_get_by_array(upb_fieldtype_t type, const void* memory,
} }
} }
void native_slot_get_by_map_key(upb_fieldtype_t type, const void* memory,
int length, CACHED_VALUE* cache TSRMLS_DC) {
switch (type) {
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES: {
PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), memory, length, 1);
return;
}
default:
native_slot_get(type, memory, cache TSRMLS_CC);
}
}
void native_slot_get_default(upb_fieldtype_t type, void native_slot_get_default(upb_fieldtype_t type,
CACHED_VALUE* cache TSRMLS_DC) { CACHED_VALUE* cache TSRMLS_DC) {
switch (type) { switch (type) {
......
...@@ -91,9 +91,12 @@ class MapFieldIter implements \Iterator ...@@ -91,9 +91,12 @@ class MapFieldIter implements \Iterator
public function key() public function key()
{ {
$key = key($this->container); $key = key($this->container);
// PHP associative array stores bool as integer for key.
if ($this->key_type === GPBType::BOOL) { if ($this->key_type === GPBType::BOOL) {
// PHP associative array stores bool as integer for key.
return boolval($key); return boolval($key);
} elseif ($this->key_type === GPBType::STRING) {
// PHP associative array stores int string as int for key.
return strval($key);
} else { } else {
return $key; return $key;
} }
......
...@@ -56,6 +56,23 @@ class MapFieldTest extends PHPUnit_Framework_TestCase { ...@@ -56,6 +56,23 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
unset($arr['3.1']); unset($arr['3.1']);
unset($arr[MAX_INT32_STRING]); unset($arr[MAX_INT32_STRING]);
$this->assertEquals(0, count($arr)); $this->assertEquals(0, count($arr));
// Test foreach.
$arr = new MapField(GPBType::INT32, GPBType::INT32);
for ($i = 0; $i < 3; $i++) {
$arr[$i] = $i;
}
$i = 0;
$arr_test = [];
foreach ($arr as $key => $val) {
$this->assertSame($key, $val);
$arr_test[] = $key;
$i++;
}
$this->assertTrue(isset($arr_test[0]));
$this->assertTrue(isset($arr_test[1]));
$this->assertTrue(isset($arr_test[2]));
$this->assertSame(3, $i);
} }
######################################################### #########################################################
...@@ -366,6 +383,23 @@ class MapFieldTest extends PHPUnit_Framework_TestCase { ...@@ -366,6 +383,23 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
$this->assertEquals(1, count($arr)); $this->assertEquals(1, count($arr));
unset($arr[True]); unset($arr[True]);
$this->assertEquals(0, count($arr)); $this->assertEquals(0, count($arr));
// Test foreach.
$arr = new MapField(GPBType::STRING, GPBType::STRING);
for ($i = 0; $i < 3; $i++) {
$arr[$i] = $i;
}
$i = 0;
$arr_test = [];
foreach ($arr as $key => $val) {
$this->assertSame($key, $val);
$arr_test[] = $key;
$i++;
}
$this->assertTrue(isset($arr_test['0']));
$this->assertTrue(isset($arr_test['1']));
$this->assertTrue(isset($arr_test['2']));
$this->assertSame(3, $i);
} }
######################################################### #########################################################
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment