Skip to content

Commit

Permalink
Added zend_array::iter/next/collect
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Dec 25, 2023
1 parent 66f0521 commit 5633191
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 2 deletions.
43 changes: 41 additions & 2 deletions src/python/array.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ static int Array_init(ZendArray *self, PyObject *args, PyObject *kwds);
static PyObject *Array_get(ZendArray *self, PyObject *args);
static PyObject *Array_set(ZendArray *self, PyObject *args);
static PyObject *Array_unset(ZendArray *self, PyObject *args);
static PyObject *Array_count(ZendArray *self, PyObject *args);
static PyObject *Array_count(ZendArray *self);
static PyObject *Array_collect(ZendArray *self);
static void Array_destroy(ZendArray *self);

// clang-format off
struct ZendArray {
PyObject_HEAD
zval array;
HashPosition pos;
};

static PyMappingMethods Array_mp_methods = {};
Expand All @@ -38,6 +40,7 @@ static PyMethodDef Array_methods[] = {
{"set", (PyCFunction) Array_set, METH_VARARGS, "Set array item value" },
{"unset", (PyCFunction) Array_unset, METH_VARARGS, "Set array item value" },
{"count", (PyCFunction) Array_count, METH_NOARGS, "Get array length" },
{"collect", (PyCFunction) Array_collect, METH_NOARGS, "Convert array to dict/list" },
{NULL} /* Sentinel */
};

Expand Down Expand Up @@ -143,14 +146,48 @@ static PyObject *Array_unset(ZendArray *self, PyObject *args) {
}
}

static PyObject *Array_count(ZendArray *self, PyObject *args) {
static PyObject *Array_count(ZendArray *self) {
return PyLong_FromLong(phpy::php::array_count(&self->array));
}

static Py_ssize_t Array_len(ZendArray *self) {
return phpy::php::array_count(&self->array);
}

static PyObject *Array_collect(ZendArray *self) {
if (zend_array_is_list(Z_ARRVAL(self->array))) {
return array2list(Z_ARRVAL(self->array));
} else {
return array2dict(Z_ARRVAL(self->array));
}
}

static PyObject *Array_iter(ZendArray *self) {
zend_hash_internal_pointer_reset_ex(Z_ARRVAL(self->array), &self->pos);
Py_INCREF(self);
return (PyObject *) self;
}

static PyObject *Array_next(ZendArray *self) {
int keytype;
zend_string *sval;
zend_ulong lval = 0;

keytype = zend_hash_get_current_key_ex(Z_ARRVAL(self->array), &sval, &lval, &self->pos);
zend_hash_move_forward_ex(Z_ARRVAL(self->array), &self->pos);

if (HASH_KEY_IS_STRING == keytype) {
return PyUnicode_FromStringAndSize(ZSTR_VAL(sval), ZSTR_LEN(sval));
} else if (HASH_KEY_IS_LONG == keytype) {
return PyLong_FromLong(lval);
} else if (HASH_KEY_NON_EXISTENT == keytype) {
return NULL;
} else {
PyErr_SetString(PyExc_RuntimeError, "zend_array iterator error");
return NULL;
}
}

static void Array_destroy(ZendArray *self) {
zval_ptr_dtor(&self->array);
Py_TYPE(self)->tp_free((PyObject *) self);
Expand All @@ -172,6 +209,8 @@ bool py_module_array_init(PyObject *m) {
ZendArrayType.tp_methods = Array_methods;
ZendArrayType.tp_init = (initproc) Array_init;
ZendArrayType.tp_new = PyType_GenericNew;
ZendArrayType.tp_iter = (getiterfunc) Array_iter;
ZendArrayType.tp_iternext = (iternextfunc) Array_next;

if (PyType_Ready(&ZendArrayType) < 0) {
return false;
Expand Down
14 changes: 14 additions & 0 deletions tests/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,17 @@ def test_mp_protocol():

del d['test']
assert d['test'] is None

assert 'uuid' in d


def test_iter():
uuid = phpy.call("uniqid")
d = phpy.Array({"hello": "world", "php": "swoole", "uuid": uuid})
keys = phpy.call('array_keys', d).collect()
keys2 = []

for k in d:
keys2.append(k)

assert keys == keys2

0 comments on commit 5633191

Please sign in to comment.