[pypy-commit] pypy better-PyDict_Next: pass tests, except for test_typedict
mattip
pypy.commits at gmail.com
Thu Nov 24 07:37:03 EST 2016
Author: Matti Picus <matti.picus at gmail.com>
Branch: better-PyDict_Next
Changeset: r88635:f2c9d8b8ab2a
Date: 2016-11-24 14:36 +0200
http://bitbucket.org/pypy/pypy/changeset/f2c9d8b8ab2a/
Log: pass tests, except for test_typedict
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -610,7 +610,7 @@
GLOBALS['%s#%s' % (cpyname, pypy_decl)] = ('PyTypeObject*', pypyexpr)
for cpyname in '''PyMethodObject PyListObject PyLongObject
- PyDictObject PyClassObject'''.split():
+ PyClassObject'''.split():
FORWARD_DECLS.append('typedef struct { PyObject_HEAD } %s'
% (cpyname, ))
build_exported_objects()
diff --git a/pypy/module/cpyext/bytearrayobject.py b/pypy/module/cpyext/bytearrayobject.py
--- a/pypy/module/cpyext/bytearrayobject.py
+++ b/pypy/module/cpyext/bytearrayobject.py
@@ -7,7 +7,7 @@
PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
from pypy.module.cpyext.pyerrors import PyErr_BadArgument
from pypy.module.cpyext.pyobject import (
- PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
+ PyObject, PyObjectP, Py_DecRef, make_ref, from_ref,
make_typedescr, get_typedescr, Py_IncRef)
# Type PyByteArrayObject represents a mutable array of bytes.
# The Python API is that of a sequence;
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
@@ -1,12 +1,51 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, build_type_checkers, Py_ssize_t,
- Py_ssize_tP, CONST_STRING)
-from pypy.module.cpyext.pyobject import PyObject, PyObjectP, as_pyobj
+ Py_ssize_tP, CONST_STRING, PyObjectFields, cpython_struct,
+ bootstrap_function)
+from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj,
+ make_typedescr, track_reference, create_ref, from_ref, Py_DecRef,
+ Py_IncRef)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.interpreter.error import OperationError
from rpython.rlib.objectmodel import specialize
+PyDictObjectStruct = lltype.ForwardReference()
+PyDictObject = lltype.Ptr(PyDictObjectStruct)
+PyDictObjectFields = PyObjectFields + \
+ (("ob_keys", PyObject),)
+cpython_struct("PyDictObject", PyDictObjectFields, PyDictObjectStruct)
+
+ at bootstrap_function
+def init_dictobject(space):
+ "Type description of PyDictObject"
+ make_typedescr(space.w_dict.layout.typedef,
+ basestruct=PyDictObject.TO,
+ attach=dict_attach,
+ dealloc=dict_dealloc,
+ realize=dict_realize)
+
+def dict_attach(space, py_obj, w_obj):
+ """
+ Fills a newly allocated PyDictObject with the given dict object.
+ """
+ py_dict = rffi.cast(PyDictObject, py_obj)
+ py_dict.c_ob_keys = lltype.nullptr(PyObject.TO)
+
+def dict_realize(space, py_obj):
+ """
+ Creates the dict in the interpreter
+ """
+ w_obj = space.newdict()
+ track_reference(space, py_obj, w_obj)
+
+ at cpython_api([PyObject], lltype.Void, header=None)
+def dict_dealloc(space, py_obj):
+ py_dict = rffi.cast(PyDictObject, py_obj)
+ Py_DecRef(space, py_dict.c_ob_keys)
+ from pypy.module.cpyext.object import _dealloc
+ _dealloc(space, py_obj)
+
@cpython_api([], PyObject)
def PyDict_New(space):
return space.newdict()
@@ -181,9 +220,9 @@
}
The dictionary p should not be mutated during iteration. It is safe
- (since Python 2.1) to modify the values of the keys as you iterate over the
- dictionary, but only so long as the set of keys does not change. For
- example:
+ (since Python 2.1) to modify the values but not the keys as you iterate
+ over the dictionary, the keys must not change.
+ For example:
PyObject *key, *value;
Py_ssize_t pos = 0;
@@ -199,34 +238,30 @@
}
Py_DECREF(o);
}"""
+
if w_dict is None:
return 0
- # XXX XXX PyDict_Next is not efficient. Storing an iterator would probably
- # work, but we can't work out how to not leak it if iteration does
- # not complete. Alternatively, we could add some RPython-only
- # dict-iterator method to move forward by N steps.
-
- w_dict.ensure_object_strategy() # make sure both keys and values can
- # be borrwed
- try:
- w_iter = space.call_method(space.w_dict, "iteritems", w_dict)
- pos = ppos[0]
- while pos:
- space.call_method(w_iter, "next")
- pos -= 1
-
- w_item = space.call_method(w_iter, "next")
- w_key, w_value = space.fixedview(w_item, 2)
- if pkey:
- pkey[0] = as_pyobj(space, w_key)
- if pvalue:
- pvalue[0] = as_pyobj(space, w_value)
- ppos[0] += 1
- except OperationError as e:
- if not e.match(space, space.w_StopIteration):
- raise
+ pos = ppos[0]
+ py_obj = as_pyobj(space, w_dict)
+ py_dict = rffi.cast(PyDictObject, py_obj)
+ if pos == 0:
+ # Store the current keys in the PyDictObject.
+ Py_DecRef(space, py_dict.c_ob_keys)
+ w_keys = space.call_method(space.w_dict, "keys", w_dict)
+ py_dict.c_ob_keys = create_ref(space, w_keys)
+ Py_IncRef(space, py_dict.c_ob_keys)
+ else:
+ w_keys = from_ref(space, py_dict.c_ob_keys)
+ ppos[0] += 1
+ if pos >= space.len_w(w_keys):
return 0
+ w_key = space.listview(w_keys)[pos]
+ w_value = space.getitem(w_dict, w_key)
+ if pkey:
+ pkey[0] = as_pyobj(space, w_key)
+ if pvalue:
+ pvalue[0] = as_pyobj(space, w_value)
return 1
@specialize.memo()
diff --git a/pypy/module/cpyext/include/dictobject.h b/pypy/module/cpyext/include/dictobject.h
--- a/pypy/module/cpyext/include/dictobject.h
+++ b/pypy/module/cpyext/include/dictobject.h
@@ -7,6 +7,10 @@
extern "C" {
#endif
+typedef struct {
+ PyObject_HEAD
+ PyObject *ob_keys; /* a private place to put keys during PyDict_Next */
+} PyDictObject;
#ifdef __cplusplus
}
More information about the pypy-commit
mailing list