[pypy-commit] pypy default: Add _PySet_Next{, Entry}. Based on the _PySet_NextEntry branch but for pypy2

arigo pypy.commits at gmail.com
Thu Oct 31 12:13:32 EDT 2019


Author: Armin Rigo <arigo at 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)
+
+ at 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)
+
+ at 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)
 
+ at 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
 
+ at 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):


More information about the pypy-commit mailing list