📄 dictobject.c
字号:
#ifdef SYMBIAN
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
/* Allocate the result tuple before checking the size. Believe it
* or not, this allocation could trigger a garbage collection which
* could empty the dict, so if we checked the size first and that
* happened, the result would be an infinite loop (searching for an
* entry that no longer exists). Note that the usual popitem()
* idiom is "while d: k, v = d.popitem()". so needing to throw the
* tuple away if the dict *is* empty isn't a significant
* inefficiency -- possible, but unlikely in practice.
*/
res = PyTuple_New(2);
if (res == NULL)
return NULL;
if (mp->ma_used == 0) {
Py_DECREF(res);
PyErr_SetString(PyExc_KeyError,
"popitem(): dictionary is empty");
return NULL;
}
/* Set ep to "the first" dict entry with a value. We abuse the hash
* field of slot 0 to hold a search finger:
* If slot 0 has a value, use slot 0.
* Else slot 0 is being used to hold a search finger,
* and we use its hash value as the first index to look.
*/
ep = &mp->ma_table[0];
if (ep->me_value == NULL) {
i = (int)ep->me_hash;
/* The hash field may be a real hash value, or it may be a
* legit search finger, or it may be a once-legit search
* finger that's out of bounds now because it wrapped around
* or the table shrunk -- simply make sure it's in bounds now.
*/
if (i > mp->ma_mask || i < 1)
i = 1; /* skip slot 0 */
while ((ep = &mp->ma_table[i])->me_value == NULL) {
i++;
if (i > mp->ma_mask)
i = 1;
}
}
PyTuple_SET_ITEM(res, 0, ep->me_key);
PyTuple_SET_ITEM(res, 1, ep->me_value);
Py_INCREF(dummy);
ep->me_key = dummy;
ep->me_value = NULL;
mp->ma_used--;
assert(mp->ma_table[0].me_value == NULL);
mp->ma_table[0].me_hash = i + 1; /* next place to start */
return res;
}
static int
dict_traverse(PyObject *op, visitproc visit, void *arg)
{
int i = 0, err;
PyObject *pk;
PyObject *pv;
while (PyDict_Next(op, &i, &pk, &pv)) {
err = visit(pk, arg);
if (err)
return err;
err = visit(pv, arg);
if (err)
return err;
}
return 0;
}
static int
dict_tp_clear(PyObject *op)
{
PyDict_Clear(op);
return 0;
}
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)
{
return dictiter_new(dict, select_key);
}
static PyObject *
dict_itervalues(dictobject *dict)
{
return dictiter_new(dict, select_value);
}
static PyObject *
dict_iteritems(dictobject *dict)
{
return dictiter_new(dict, select_item);
}
static const char has_key__doc__[] =
"D.has_key(k) -> 1 if D has a key k, else 0";
static const char get__doc__[] =
"D.get(k[,d]) -> D[k] if D.has_key(k), else d. d defaults to None.";
static const char setdefault_doc__[] =
"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if not D.has_key(k)";
static const char popitem__doc__[] =
"D.popitem() -> (k, v), remove and return some (key, value) pair as a\n\
2-tuple; but raise KeyError if D is empty";
static const char keys__doc__[] =
"D.keys() -> list of D's keys";
static const char items__doc__[] =
"D.items() -> list of D's (key, value) pairs, as 2-tuples";
static const char values__doc__[] =
"D.values() -> list of D's values";
static const char update__doc__[] =
"D.update(E) -> None. Update D from E: for k in E.keys(): D[k] = E[k]";
static const char clear__doc__[] =
"D.clear() -> None. Remove all items from D.";
static const char copy__doc__[] =
"D.copy() -> a shallow copy of D";
static const char iterkeys__doc__[] =
"D.iterkeys() -> an iterator over the keys of D";
static const char itervalues__doc__[] =
"D.itervalues() -> an iterator over the values of D";
static const char iteritems__doc__[] =
"D.iteritems() -> an iterator over the (key, value) items of D";
static const PyMethodDef mapp_methods[] = {
{"has_key", (PyCFunction)dict_has_key, METH_O,
has_key__doc__},
{"get", (PyCFunction)dict_get, METH_VARARGS,
get__doc__},
{"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS,
setdefault_doc__},
{"popitem", (PyCFunction)dict_popitem, METH_NOARGS,
popitem__doc__},
{"keys", (PyCFunction)dict_keys, METH_NOARGS,
keys__doc__},
{"items", (PyCFunction)dict_items, METH_NOARGS,
items__doc__},
{"values", (PyCFunction)dict_values, METH_NOARGS,
values__doc__},
{"update", (PyCFunction)dict_update, METH_O,
update__doc__},
{"clear", (PyCFunction)dict_clear, METH_NOARGS,
clear__doc__},
{"copy", (PyCFunction)dict_copy, METH_NOARGS,
copy__doc__},
{"iterkeys", (PyCFunction)dict_iterkeys, METH_NOARGS,
iterkeys__doc__},
{"itervalues", (PyCFunction)dict_itervalues, METH_NOARGS,
itervalues__doc__},
{"iteritems", (PyCFunction)dict_iteritems, METH_NOARGS,
iteritems__doc__},
{NULL, NULL} /* sentinel */
};
static int
dict_contains(dictobject *mp, PyObject *key)
{
long hash;
#ifdef CACHE_HASH
if (!PyString_CheckExact(key) ||
(hash = ((PyStringObject *) key)->ob_shash) == -1)
#endif
{
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
return (mp->ma_lookup)(mp, key, hash)->me_value != NULL;
}
/* Hack to implement "key in dict" */
const static PySequenceMethods dict_as_sequence = {
0, /* sq_length */
0, /* sq_concat */
0, /* sq_repeat */
0, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
(objobjproc)dict_contains, /* sq_contains */
0, /* sq_inplace_concat */
0, /* sq_inplace_repeat */
};
static PyObject *
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *self;
assert(type != NULL && type->tp_alloc != NULL);
self = type->tp_alloc(type, 0);
if (self != NULL) {
PyDictObject *d = (PyDictObject *)self;
/* It's guaranteed that tp->alloc zeroed out the struct. */
assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0);
INIT_NONZERO_DICT_SLOTS(d);
d->ma_lookup = lookdict_string;
#ifdef SHOW_CONVERSION_COUNTS
++created;
#endif
}
return self;
}
static int
dict_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
static const char *const kwlist[] = {"items", 0};
int result = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:dict",
kwlist, &arg))
result = -1;
else if (arg != NULL) {
if (PyObject_HasAttrString(arg, "keys"))
result = PyDict_Merge(self, arg, 1);
else
result = PyDict_MergeFromSeq2(self, arg, 1);
}
return result;
}
static long
dict_nohash(PyObject *self)
{
PyErr_SetString(PyExc_TypeError, "dict objects are unhashable");
return -1;
}
static PyObject *
dict_iter(dictobject *dict)
{
return dictiter_new(dict, select_key);
}
const static char dictionary_doc[] =
#ifdef SYMBIAN
"";
#else
"dict() -> new empty dictionary.\n"
"dict(mapping) -> new dictionary initialized from a mapping object's\n"
" (key, value) pairs.\n"
"dict(seq) -> new dictionary initialized as if via:\n"
" d = {}\n"
" for k, v in seq:\n"
" d[k] = v";
#endif
#ifndef SYMBIAN
PyTypeObject PyDict_Type = {
PyObject_HEAD_INIT(&PyType_Type)
#else
const PyTypeObject c_PyDict_Type = {
PyObject_HEAD_INIT(NULL)
#endif
0,
"dict",
sizeof(dictobject),
0,
(destructor)dict_dealloc, /* tp_dealloc */
(printfunc)dict_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
(cmpfunc)dict_compare, /* tp_compare */
(reprfunc)dict_repr, /* tp_repr */
0, /* tp_as_number */
&dict_as_sequence, /* tp_as_sequence */
&dict_as_mapping, /* tp_as_mapping */
dict_nohash, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE, /* tp_flags */
dictionary_doc, /* tp_doc */
(traverseproc)dict_traverse, /* tp_traverse */
(inquiry)dict_tp_clear, /* tp_clear */
dict_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)dict_iter, /* tp_iter */
0, /* tp_iternext */
mapp_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)dict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
dict_new, /* tp_new */
_PyObject_GC_Del, /* tp_free */
};
/* For backward compatibility with old dictionary interface */
// XXX:CW32
DL_EXPORT(PyObject *)
PyDict_GetItemString(PyObject *v, const char *key)
{
PyObject *kv, *rv;
kv = PyString_FromString(key);
if (kv == NULL)
return NULL;
rv = PyDict_GetItem(v, kv);
Py_DECREF(kv);
return rv;
}
// XXX:CW32
DL_EXPORT(int)
PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
{
PyObject *kv;
int err;
kv = PyString_FromString(key);
if (kv == NULL)
return -1;
PyString_InternInPlace(&kv); /* XXX Should we really? */
err = PyDict_SetItem(v, kv, item);
Py_DECREF(kv);
return err;
}
DL_EXPORT(int)
PyDict_DelItemString(PyObject *v, char *key)
{
PyObject *kv;
int err;
kv = PyString_FromString(key);
if (kv == NULL)
return -1;
err = PyDict_DelItem(v, kv);
Py_DECREF(kv);
return err;
}
/* Dictionary iterator type */
#ifndef SYMBIAN
extern const PyTypeObject PyDictIter_Type; /* Forward */
#endif
typedef struct {
PyObject_HEAD
dictobject *di_dict;
int di_used;
int di_pos;
binaryfunc di_select;
} dictiterobject;
static PyObject *
dictiter_new(dictobject *dict, binaryfunc select)
{
dictiterobject *di;
di = PyObject_NEW(dictiterobject, &PyDictIter_Type);
if (di == NULL)
return NULL;
Py_INCREF(dict);
di->di_dict = dict;
di->di_used = dict->ma_used;
di->di_pos = 0;
di->di_select = select;
return (PyObject *)di;
}
static void
dictiter_dealloc(dictiterobject *di)
{
Py_DECREF(di->di_dict);
PyObject_DEL(di);
}
static PyObject *
dictiter_next(dictiterobject *di, PyObject *args)
{
PyObject *key, *value;
if (di->di_used != di->di_dict->ma_used) {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during iteration");
return NULL;
}
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, &value)) {
return (*di->di_select)(key, value);
}
PyErr_SetObject(PyExc_StopIteration, Py_None);
return NULL;
}
static PyObject *
dictiter_getiter(PyObject *it)
{
Py_INCREF(it);
return it;
}
const static PyMethodDef dictiter_methods[] = {
{"next", (PyCFunction)dictiter_next, METH_VARARGS,
"it.next() -- get the next value, or raise StopIteration"},
{NULL, NULL} /* sentinel */
};
static PyObject *dictiter_iternext(dictiterobject *di)
{
PyObject *key, *value;
if (di->di_used != di->di_dict->ma_used) {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during iteration");
return NULL;
}
if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, &value)) {
return (*di->di_select)(key, value);
}
return NULL;
}
#ifndef SYMBIAN
PyTypeObject PyDictIter_Type = {
PyObject_HEAD_INIT(&PyType_Type)
#else
const PyTypeObject c_PyDictIter_Type = {
PyObject_HEAD_INIT(NULL)
#endif
0, /* ob_size */
"dictionary-iterator", /* tp_name */
sizeof(dictiterobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)dictiter_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)dictiter_getiter, /* tp_iter */
(iternextfunc)dictiter_iternext, /* tp_iternext */
dictiter_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -