Skip to content

Commit

Permalink
Optimize iter
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Dec 28, 2023
1 parent 84f0b2d commit bfe59ea
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 26 deletions.
25 changes: 25 additions & 0 deletions include/phpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ PyObject *array2set(zend_array *ht);
static inline PyObject *array2set(zval *zv) {
return array2set(Z_ARRVAL_P(zv));
}
PyObject *array2tuple(zend_array *ht);
static inline PyObject *array2tuple(zval *zv) {
return array2tuple(Z_ARRVAL_P(zv));
}
PyObject *resource2py(zval *zres);
PyObject *reference2py(zval *zv);
PyObject *array2dict(zend_array *ht);
Expand Down Expand Up @@ -245,6 +249,22 @@ static inline bool is_null(zval *zv) {
return zv == NULL || ZVAL_IS_NULL(zv);
}

static inline bool is_array(zval *zv) {
return Z_TYPE_P(zv) == IS_ARRAY;
}

static inline bool is_string(zval *zv) {
return Z_TYPE_P(zv) == IS_STRING;
}

static inline bool is_object(zval *zv) {
return Z_TYPE_P(zv) == IS_OBJECT;
}

static inline bool is_pyobject(zval *zv) {
return is_object(zv) && instanceof_function(Z_OBJCE_P(zv), phpy_object_get_ce());
}

/**
* Return value: Borrowed reference.
*/
Expand All @@ -270,9 +290,14 @@ PyObject *arg_1(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce);
std::tuple<PyObject *, PyObject *> arg_2(INTERNAL_FUNCTION_PARAMETERS);
std::tuple<PyObject *, PyObject *> arg_2(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce);

static inline uint32_t array_count(zend_array *ht) {
return zend_array_count(ht);
}

static inline uint32_t array_count(zval *zv) {
return zend_array_count(Z_ARRVAL_P(zv));
}

/**
* Return value: New reference.
*/
Expand Down
11 changes: 11 additions & 0 deletions src/bridge/core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ PyObject *array2list(zend_array *ht) {
return list;
}

PyObject *array2tuple(zend_array *ht) {
zval *current;
PyObject *tuple = PyTuple_New(phpy::php::array_count(ht));
Py_ssize_t index = 0;
ZEND_HASH_FOREACH_VAL(ht, current) {
PyTuple_SetItem(tuple, index++, php2py(current));
}
ZEND_HASH_FOREACH_END();
return tuple;
}

PyObject *array2set(zend_array *ht) {
zval *current;
PyObject *pset = PySet_New(0);
Expand Down
6 changes: 3 additions & 3 deletions src/php/core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,11 @@ ZEND_METHOD(PyCore, bytes) {
ZEND_PARSE_PARAMETERS_END_EX(return );

PyObject *pv;
if (zv == NULL || ZVAL_IS_NULL(zv)) {
if (phpy::php::is_null(zv)) {
pv = PyBytes_FromStringAndSize("", 0);
} else if (Z_TYPE_P(zv) == IS_STRING) {
} else if (phpy::php::is_string(zv)) {
pv = PyBytes_FromStringAndSize(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
} else if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), phpy_object_get_ce())) {
} else if (phpy::php::is_pyobject(zv)) {
auto pyobj = phpy_object_get_handle(zv);
pv = PyBytes_FromObject(pyobj);
} else {
Expand Down
21 changes: 21 additions & 0 deletions src/php/object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,28 @@ PyObject *phpy_object_get_iterator(zval *object) {

void phpy_object_iterator_reset(zval *object) {
auto oo = phpy_object_get_object(object);
// Return value: New reference
if (oo->iterator != NULL) {
Py_DECREF(oo->iterator);
}
oo->iterator = PyObject_GetIter(oo->object);
// Return value: New reference
if (oo->current != NULL) {
Py_DECREF(oo->current);
}
oo->current = PyIter_Next(oo->iterator);
oo->index = 0;
}

PyObject *phpy_object_iterator_next(zval *object) {
auto oo = phpy_object_get_object(object);
if (oo->iterator == NULL) {
return NULL;
}
// Return value: New reference
if (oo->current != NULL) {
Py_DECREF(oo->current);
}
oo->current = PyIter_Next(oo->iterator);
oo->index++;
return oo->current;
Expand Down Expand Up @@ -101,6 +116,12 @@ static void phpy_object_free_object(zend_object *object) {
if (object_object->object != NULL) {
Py_DECREF(object_object->object);
}
if (object_object->iterator != NULL) {
Py_DECREF(object_object->iterator);
}
if (object_object->current != NULL) {
Py_DECREF(object_object->current);
}
zend_object_std_dtor(&object_object->std);
}

Expand Down
3 changes: 3 additions & 0 deletions src/php/sequence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ ZEND_METHOD(PySequence, key) {

ZEND_METHOD(PySequence, current) {
auto current = phpy_object_iterator_current(ZEND_THIS);
if (current == NULL) {
return;
}
py2php(current, return_value);
}

Expand Down
19 changes: 17 additions & 2 deletions src/php/tuple.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,23 @@ static ssize_t get_key(INTERNAL_FUNCTION_PARAMETERS) {
}

ZEND_METHOD(PyTuple, __construct) {
auto pyobj = arg_1(INTERNAL_FUNCTION_PARAM_PASSTHRU, phpy_object_get_ce());
phpy_object_ctor(ZEND_THIS, PySequence_Tuple(pyobj));
zval *ztuple;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ZVAL(ztuple)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

PyObject *ptuple;
if (phpy::php::is_null(ztuple)) {
ptuple = PyTuple_New(0);
} else if (phpy::php::is_array(ztuple)) {
ptuple = array2tuple(ztuple);
} else if (phpy::php::is_pyobject(ztuple)) {
ptuple = PySequence_Tuple(phpy_object_get_handle(ztuple));
} else {
zend_throw_error(NULL, "PyTuple: unsupported type");
return;
}
phpy_object_ctor(ZEND_THIS, ptuple);
}

ZEND_METHOD(PyTuple, offsetGet) {
Expand Down
2 changes: 1 addition & 1 deletion stubs/phpy_dict.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class PyDict extends PyObject implements \ArrayAccess, \Iterator, \Countable
{
public function __construct(mixed $value = null)
public function __construct(array $value = null)
{

}
Expand Down
4 changes: 2 additions & 2 deletions stubs/phpy_dict_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: a56d4e29144a4ebe28a2d287f32e54d21209101b */
* Stub hash: 0e78fd074e533c6da7aa9580fd68a38adb1b07d4 */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PyDict___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_MIXED, 0, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_ARRAY, 0, "null")
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PyDict_offsetGet, 0, 1, IS_MIXED, 0)
Expand Down
2 changes: 1 addition & 1 deletion stubs/phpy_set.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class PySet extends PyObject implements \Iterator, \Countable
{
public function __construct()
public function __construct(array $data = null)
{

}
Expand Down
3 changes: 2 additions & 1 deletion stubs/phpy_set_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 27c4e73a924d3fb097336fed9f14b646712a3ce0 */
* Stub hash: cf5bf8017d5b71cae005534cc88f718b113589b0 */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PySet___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, data, IS_ARRAY, 0, "null")
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PySet_key, 0, 0, IS_MIXED, 0)
Expand Down
18 changes: 18 additions & 0 deletions tests/phpunit/ListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,22 @@ public function testCtor()
$this->assertEquals($list->count(), 5);
$this->assertEquals($list->index(9), 4);
}

function testUb1()
{
$list = new PyList([1, 2, 3, 4]);
$this->assertEmpty($list->current());
}

function testUb2()
{
$list = new PyList([1, 2, 3, 4]);
$this->assertEmpty($list->next());

foreach ($list as $l) {
$this->assertEquals($l, $list->current());
$list->next();
$this->assertNotEquals($l, $list->current());
}
}
}
31 changes: 25 additions & 6 deletions tests/phpunit/SetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@

class SetTest extends TestCase
{
private function test($set, $v1, $v2)
{
$this->assertEquals($set->count(), 3);
$array = PyCore::scalar($set);
$this->assertTrue($set->contains($v1));
$this->assertTrue($set->contains($v2));
$this->assertContains($v1, $array);
$this->assertContains($v2, $array);
}

public function testSet()
{
$set = new PySet();
Expand All @@ -15,11 +25,20 @@ public function testSet()
$set->add($v2);
$set->add(2);

$this->assertEquals($set->count(), 3);
$array = PyCore::scalar($set);
$this->assertTrue($set->contains($v1));
$this->assertTrue($set->contains($v2));
$this->assertContains($v1, $array);
$this->assertContains($v2, $array);
$this->test($set, $v1, $v2);
}

public function testSetCtor()
{
$list = [];
$v1 = random_int(1000, 99999);
$v2 = random_int(1000, 99999);
$list[] = 2;
$list[] = $v1;
$list[] = $v2;
$list[] = 2;

$set = new PySet($list);
$this->test($set, $v1, $v2);
}
}
39 changes: 29 additions & 10 deletions tests/phpunit/TupleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,8 @@

class TupleTest extends TestCase
{
public function testList()
private function test($list, $v1, $v2)
{
$list = new PyList();
$v1 = random_int(1000, 99999);
$v2 = random_int(1000, 99999);

$list[] = 2;
$list[] = $v1;
$list[] = $v2;
$list[] = 12345;

$tuple = new PyTuple($list);

$this->assertEquals($tuple->count(), 4);
Expand All @@ -32,4 +23,32 @@ public function testList()
$slice = $tuple->slice(1, 3);
$this->assertEquals(PyCore::scalar($slice), [$v1, $v2]);
}

public function testList()
{
$list = new PyList();
$v1 = random_int(1000, 99999);
$v2 = random_int(1000, 99999);

$list[] = 2;
$list[] = $v1;
$list[] = $v2;
$list[] = 12345;

$this->test($list, $v1, $v2);
}

function testArray()
{
$list = [];
$v1 = random_int(1000, 99999);
$v2 = random_int(1000, 99999);

$list[] = 2;
$list[] = $v1;
$list[] = $v2;
$list[] = 12345;

$this->test($list, $v1, $v2);
}
}

0 comments on commit bfe59ea

Please sign in to comment.