mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
Add experimental iterkeys(), itervalues(), iteritems() to dict
objects. Tests show that iteritems() is 5-10% faster than iterating over the dict and extracting the value with dict[key].
This commit is contained in:
parent
82c690f11a
commit
09e563abb4
1 changed files with 85 additions and 11 deletions
|
@ -1231,6 +1231,61 @@ dict_tp_clear(PyObject *op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
staticforward PyObject *dictiter_new(dictobject *, binaryfunc);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
select_key(PyObject *key, PyObject *value)
|
||||||
|
{
|
||||||
|
Py_INCREF(key);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
select_value(PyObject *key, PyObject *value)
|
||||||
|
{
|
||||||
|
Py_INCREF(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
select_item(PyObject *key, PyObject *value)
|
||||||
|
{
|
||||||
|
PyObject *res = PyTuple_New(2);
|
||||||
|
|
||||||
|
if (res != NULL) {
|
||||||
|
Py_INCREF(key);
|
||||||
|
Py_INCREF(value);
|
||||||
|
PyTuple_SET_ITEM(res, 0, key);
|
||||||
|
PyTuple_SET_ITEM(res, 1, value);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
dict_iterkeys(dictobject *dict, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
return dictiter_new(dict, select_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
dict_itervalues(dictobject *dict, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
return dictiter_new(dict, select_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
dict_iteritems(dictobject *dict, PyObject *args)
|
||||||
|
{
|
||||||
|
if (!PyArg_ParseTuple(args, ""))
|
||||||
|
return NULL;
|
||||||
|
return dictiter_new(dict, select_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static char has_key__doc__[] =
|
static char has_key__doc__[] =
|
||||||
"D.has_key(k) -> 1 if D has a key k, else 0";
|
"D.has_key(k) -> 1 if D has a key k, else 0";
|
||||||
|
|
||||||
|
@ -1262,6 +1317,15 @@ static char clear__doc__[] =
|
||||||
static char copy__doc__[] =
|
static char copy__doc__[] =
|
||||||
"D.copy() -> a shallow copy of D";
|
"D.copy() -> a shallow copy of D";
|
||||||
|
|
||||||
|
static char iterkeys__doc__[] =
|
||||||
|
"D.iterkeys() -> an iterator over the keys of D";
|
||||||
|
|
||||||
|
static char itervalues__doc__[] =
|
||||||
|
"D.itervalues() -> an iterator over the values of D";
|
||||||
|
|
||||||
|
static char iteritems__doc__[] =
|
||||||
|
"D.iteritems() -> an iterator over the (key, value) items of D";
|
||||||
|
|
||||||
static PyMethodDef mapp_methods[] = {
|
static PyMethodDef mapp_methods[] = {
|
||||||
{"has_key", (PyCFunction)dict_has_key, METH_VARARGS,
|
{"has_key", (PyCFunction)dict_has_key, METH_VARARGS,
|
||||||
has_key__doc__},
|
has_key__doc__},
|
||||||
|
@ -1283,6 +1347,12 @@ static PyMethodDef mapp_methods[] = {
|
||||||
clear__doc__},
|
clear__doc__},
|
||||||
{"copy", (PyCFunction)dict_copy, METH_OLDARGS,
|
{"copy", (PyCFunction)dict_copy, METH_OLDARGS,
|
||||||
copy__doc__},
|
copy__doc__},
|
||||||
|
{"iterkeys", (PyCFunction)dict_iterkeys, METH_VARARGS,
|
||||||
|
iterkeys__doc__},
|
||||||
|
{"itervalues", (PyCFunction)dict_itervalues, METH_VARARGS,
|
||||||
|
itervalues__doc__},
|
||||||
|
{"iteritems", (PyCFunction)dict_iteritems, METH_VARARGS,
|
||||||
|
iteritems__doc__},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1324,7 +1394,11 @@ static PySequenceMethods dict_as_sequence = {
|
||||||
0, /* sq_inplace_repeat */
|
0, /* sq_inplace_repeat */
|
||||||
};
|
};
|
||||||
|
|
||||||
staticforward PyObject *dictiter_new(dictobject *);
|
static PyObject *
|
||||||
|
dict_iter(dictobject *dict)
|
||||||
|
{
|
||||||
|
return dictiter_new(dict, select_key);
|
||||||
|
}
|
||||||
|
|
||||||
PyTypeObject PyDict_Type = {
|
PyTypeObject PyDict_Type = {
|
||||||
PyObject_HEAD_INIT(&PyType_Type)
|
PyObject_HEAD_INIT(&PyType_Type)
|
||||||
|
@ -1353,7 +1427,7 @@ PyTypeObject PyDict_Type = {
|
||||||
(inquiry)dict_tp_clear, /* tp_clear */
|
(inquiry)dict_tp_clear, /* tp_clear */
|
||||||
0, /* tp_richcompare */
|
0, /* tp_richcompare */
|
||||||
0, /* tp_weaklistoffset */
|
0, /* tp_weaklistoffset */
|
||||||
(getiterfunc)dictiter_new, /* tp_iter */
|
(getiterfunc)dict_iter, /* tp_iter */
|
||||||
0, /* tp_iternext */
|
0, /* tp_iternext */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1407,10 +1481,11 @@ typedef struct {
|
||||||
dictobject *di_dict;
|
dictobject *di_dict;
|
||||||
int di_size;
|
int di_size;
|
||||||
int di_pos;
|
int di_pos;
|
||||||
|
binaryfunc di_select;
|
||||||
} dictiterobject;
|
} dictiterobject;
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictiter_new(dictobject *dict)
|
dictiter_new(dictobject *dict, binaryfunc select)
|
||||||
{
|
{
|
||||||
dictiterobject *di;
|
dictiterobject *di;
|
||||||
di = PyObject_NEW(dictiterobject, &PyDictIter_Type);
|
di = PyObject_NEW(dictiterobject, &PyDictIter_Type);
|
||||||
|
@ -1420,6 +1495,7 @@ dictiter_new(dictobject *dict)
|
||||||
di->di_dict = dict;
|
di->di_dict = dict;
|
||||||
di->di_size = dict->ma_size;
|
di->di_size = dict->ma_size;
|
||||||
di->di_pos = 0;
|
di->di_pos = 0;
|
||||||
|
di->di_select = select;
|
||||||
return (PyObject *)di;
|
return (PyObject *)di;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,16 +1509,15 @@ dictiter_dealloc(dictiterobject *di)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
dictiter_next(dictiterobject *di, PyObject *args)
|
dictiter_next(dictiterobject *di, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *key;
|
PyObject *key, *value;
|
||||||
|
|
||||||
if (di->di_size != di->di_dict->ma_size) {
|
if (di->di_size != di->di_dict->ma_size) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
"dictionary changed size during iteration");
|
"dictionary changed size during iteration");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, NULL)) {
|
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, &value)) {
|
||||||
Py_INCREF(key);
|
return (*di->di_select)(key, value);
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
PyErr_SetObject(PyExc_StopIteration, Py_None);
|
PyErr_SetObject(PyExc_StopIteration, Py_None);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1469,16 +1544,15 @@ dictiter_getattr(dictiterobject *di, char *name)
|
||||||
|
|
||||||
static PyObject *dictiter_iternext(dictiterobject *di)
|
static PyObject *dictiter_iternext(dictiterobject *di)
|
||||||
{
|
{
|
||||||
PyObject *key;
|
PyObject *key, *value;
|
||||||
|
|
||||||
if (di->di_size != di->di_dict->ma_size) {
|
if (di->di_size != di->di_dict->ma_size) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
"dictionary changed size during iteration");
|
"dictionary changed size during iteration");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, NULL)) {
|
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, &value)) {
|
||||||
Py_INCREF(key);
|
return (*di->di_select)(key, value);
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue