Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r97908:4748c02be810 Date: 2019-10-31 17:09 +0100 http://bitbucket.org/pypy/pypy/changeset/4748c02be810/
Log: Add _PySet_Next{,Entry}. Based on the _PySet_NextEntry branch but for pypy2 diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -267,14 +267,15 @@ if pos == 0: # Store the current keys in the PyDictObject. from pypy.objspace.std.listobject import W_ListObject - decref(space, py_dict.c__tmpkeys) w_keys = space.call_method(space.w_dict, "keys", w_dict) # w_keys must use the object strategy in order to keep the keys alive if not isinstance(w_keys, W_ListObject): return 0 # XXX should not call keys() above w_keys.switch_to_object_strategy() + oldkeys = py_dict.c__tmpkeys py_dict.c__tmpkeys = create_ref(space, w_keys) incref(space, py_dict.c__tmpkeys) + decref(space, oldkeys) else: if not py_dict.c__tmpkeys: # pos should have been 0, cannot fail so return 0 diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h --- a/pypy/module/cpyext/include/Python.h +++ b/pypy/module/cpyext/include/Python.h @@ -107,6 +107,7 @@ #include "descrobject.h" #include "tupleobject.h" #include "dictobject.h" +#include "setobject.h" #include "intobject.h" #include "listobject.h" #include "longobject.h" diff --git a/pypy/module/cpyext/include/setobject.h b/pypy/module/cpyext/include/setobject.h new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/include/setobject.h @@ -0,0 +1,19 @@ + +/* set object interface */ + +#ifndef Py_SETOBJECT_H +#define Py_SETOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + PyObject *_tmplist; /* a private place to put values during _PySet_Next */ +} PySetObject; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SETOBJECT_H */ + diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py --- a/pypy/module/cpyext/object.py +++ b/pypy/module/cpyext/object.py @@ -359,11 +359,11 @@ """ Compute and return the hash value of an object o. On failure, return -1. This is the equivalent of the Python expression hash(o).""" - return space.int_w(space.hash(w_obj)) + return space.hash_w(w_obj) @cpython_api([rffi.DOUBLE], rffi.LONG, error=-1) def _Py_HashDouble(space, v): - return space.int_w(space.hash(space.newfloat(v))) + return space.hash_w(space.newfloat(v)) @cpython_api([PyObject], lltype.Signed, error=-1) def PyObject_HashNotImplemented(space, o): diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -1,12 +1,45 @@ from pypy.interpreter.error import OperationError, oefmt from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL, - build_type_checkers) +from pypy.module.cpyext.api import ( + cpython_api, Py_ssize_t, Py_ssize_tP, CANNOT_FAIL, build_type_checkers, + PyObjectFields, cpython_struct, bootstrap_function, slot_function) from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, - make_ref, from_ref) + make_ref, from_ref, as_pyobj, create_ref, make_typedescr, incref, decref) +from pypy.module.cpyext.object import _dealloc from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, newset +PySetObjectStruct = lltype.ForwardReference() +PySetObject = lltype.Ptr(PySetObjectStruct) +PySetObjectFields = PyObjectFields + \ + (("_tmplist", PyObject),) +cpython_struct("PySetObject", PySetObjectFields, PySetObjectStruct) + +@bootstrap_function +def init_setobject(space): + "Type description of PySetObject" + make_typedescr(space.w_set.layout.typedef, + basestruct=PySetObject.TO, + attach=set_attach, + dealloc=set_dealloc) + make_typedescr(space.w_frozenset.layout.typedef, # same as 'set' + basestruct=PySetObject.TO, + attach=set_attach, + dealloc=set_dealloc) + +def set_attach(space, py_obj, w_obj, w_userdata=None): + """ + Fills a newly allocated PySetObject with the given set object. + """ + py_set = rffi.cast(PySetObject, py_obj) + py_set.c__tmplist = lltype.nullptr(PyObject.TO) + +@slot_function([PyObject], lltype.Void) +def set_dealloc(space, py_obj): + py_set = rffi.cast(PySetObject, py_obj) + decref(space, py_set.c__tmplist) + py_set.c__tmplist = lltype.nullptr(PyObject.TO) + _dealloc(space, py_obj) PySet_Check, PySet_CheckExact = build_type_checkers("Set") PyFrozenSet_Check, PyFrozenSet_CheckExact = build_type_checkers("FrozenSet") @@ -23,7 +56,7 @@ """Return true if obj is a set object or a frozenset object but not an instance of a subtype.""" w_obj_type = space.type(w_obj) - return (space.is_w(w_obj_type, space.gettypefor(W_SetObject)) or + return (space.is_w(w_obj_type, space.gettypefor(W_SetObject)) or space.is_w(w_obj_type, space.gettypefor(W_FrozensetObject))) @cpython_api([PyObject], PyObject) @@ -126,4 +159,43 @@ else: return space.call_function(space.w_frozenset, w_iterable) +@cpython_api([PyObject, Py_ssize_tP, PyObjectP, Py_ssize_tP], rffi.INT_real, error=-1) +def _PySet_NextEntry(space, w_set, ppos, pkey, phash): + if w_set is None or not PyAnySet_Check(space, w_set): + PyErr_BadInternalCall(space) + return -1 + if not pkey: + PyErr_BadInternalCall(space) + return -1 + pos = ppos[0] + py_obj = as_pyobj(space, w_set) + py_set = rffi.cast(PySetObject, py_obj) + if pos == 0: + # Store the current item list in the PySetObject. + # w_keys must use the object strategy in order to keep the keys alive + w_keys = space.newlist(space.listview(w_set)) + w_keys.switch_to_object_strategy() + oldlist = py_set.c__tmplist + py_set.c__tmplist = create_ref(space, w_keys) + incref(space, py_set.c__tmplist) + decref(space, oldlist) + else: + if not py_set.c__tmplist: + # pos should have been 0, cannot fail so return 0 + return 0; + w_keys = from_ref(space, py_set.c__tmplist) + ppos[0] += 1 + if pos >= space.len_w(w_keys): + decref(space, py_set.c__tmplist) + py_set.c__tmplist = lltype.nullptr(PyObject.TO) + return 0 + w_key = space.listview(w_keys)[pos] + pkey[0] = as_pyobj(space, w_key) + if phash: + phash[0] = space.hash_w(w_key) + return 1 +@cpython_api([PyObject, Py_ssize_tP, PyObjectP], rffi.INT_real, error=-1) +def _PySet_Next(space, w_set, ppos, pkey): + null = lltype.nullptr(Py_ssize_tP.TO) + return _PySet_NextEntry(space, w_set, ppos, pkey, null) diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py --- a/pypy/module/cpyext/test/test_setobject.py +++ b/pypy/module/cpyext/test/test_setobject.py @@ -1,8 +1,11 @@ +from rpython.rtyper.lltypesystem import lltype from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from pypy.module.cpyext.setobject import ( PySet_Check, PyFrozenSet_Check, PyFrozenSet_CheckExact, PySet_Add, PySet_Size, PySet_GET_SIZE) +from pypy.module.cpyext.api import Py_ssize_tP, PyObjectP +from pypy.module.cpyext.pyobject import from_ref class TestTupleObject(BaseApiTest): @@ -62,6 +65,42 @@ """) assert api.PyAnySet_Check(w_instance) + def test_pyset_next(self, space, api): + w_set = space.call_function(space.w_set, space.newtext("ab")) + with lltype.scoped_alloc(Py_ssize_tP.TO, 1) as pos_p: + with lltype.scoped_alloc(PyObjectP.TO, 1) as result_p: + pos_p[0] = 0 + res = api._PySet_Next(w_set, pos_p, result_p) + assert res == 1 + letter1 = space.text_w(from_ref(space, result_p[0])) + res = api._PySet_Next(w_set, pos_p, result_p) + assert res == 1 + letter2 = space.text_w(from_ref(space, result_p[0])) + res = api._PySet_Next(w_set, pos_p, result_p) + assert res == 0 + assert set([letter1, letter2]) == set("ab") + + def test_pyset_nextentry(self, space, api): + w_set = space.call_function(space.w_set, space.newtext("ab")) + with lltype.scoped_alloc(Py_ssize_tP.TO, 1) as pos_p: + with lltype.scoped_alloc(PyObjectP.TO, 1) as result_p: + with lltype.scoped_alloc(Py_ssize_tP.TO, 1) as hash_p: + pos_p[0] = 0 + res = api._PySet_NextEntry(w_set, pos_p, result_p, hash_p) + assert res == 1 + w_obj = from_ref(space, result_p[0]) + letter1 = space.text_w(w_obj) + assert hash_p[0] == space.hash_w(w_obj) + res = api._PySet_NextEntry(w_set, pos_p, result_p, hash_p) + assert res == 1 + w_obj = from_ref(space, result_p[0]) + letter2 = space.text_w(w_obj) + assert hash_p[0] == space.hash_w(w_obj) + res = api._PySet_NextEntry(w_set, pos_p, result_p, hash_p) + assert res == 0 + assert set([letter1, letter2]) == set("ab") + + class AppTestSetObject(AppTestCpythonExtensionBase): def test_set_macro_cast(self): module = self.import_extension('foo', [ diff --git a/pypy/module/cpyext/userslot.py b/pypy/module/cpyext/userslot.py --- a/pypy/module/cpyext/userslot.py +++ b/pypy/module/cpyext/userslot.py @@ -22,7 +22,7 @@ @slot_function([PyObject], lltype.Signed, error=-1) def slot_tp_hash(space, w_obj): - return space.int_w(space.hash(w_obj)) + return space.hash_w(w_obj) @slot_function([PyObject, Py_ssize_t], PyObject) def slot_sq_item(space, w_obj, index): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit