Commit d6e3f63f authored by Armin Rigo's avatar Armin Rigo
Browse files

Add _PySet_Next{,Entry}. Based on the _PySet_NextEntry branch but for pypy2

parent 28382af84334
......@@ -267,14 +267,15 @@ def PyDict_Next(space, w_dict, ppos, pkey, pvalue):
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
......
......@@ -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"
......
/* 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 */
......@@ -359,11 +359,11 @@ def PyObject_Hash(space, w_obj):
"""
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):
......
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 @@ def PyAnySet_CheckExact(space, w_obj):
"""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 @@ def PyFrozenSet_New(space, w_iterable):
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)
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 @@ class TestTupleObject(BaseApiTest):
""")
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', [
......
......@@ -22,7 +22,7 @@ def slot_sq_length(space, w_obj):
@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):
......
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