📄 dictobject.c
字号:
* insert new keys or remove them.
*/
DL_EXPORT(int)
PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)
{
register dictobject *mp;
register long hash;
register int n_used;
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
mp = (dictobject *)op;
#ifdef CACHE_HASH
if (PyString_CheckExact(key)) {
#ifdef INTERN_STRINGS
if (((PyStringObject *)key)->ob_sinterned != NULL) {
key = ((PyStringObject *)key)->ob_sinterned;
hash = ((PyStringObject *)key)->ob_shash;
}
else
#endif
{
hash = ((PyStringObject *)key)->ob_shash;
if (hash == -1)
hash = PyObject_Hash(key);
}
}
else
#endif
{
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */
n_used = mp->ma_used;
Py_INCREF(value);
Py_INCREF(key);
insertdict(mp, key, hash, value);
/* If we added a key, we can safely resize. Otherwise skip this!
* If fill >= 2/3 size, adjust size. Normally, this doubles the
* size, but it's also possible for the dict to shrink (if ma_fill is
* much larger than ma_used, meaning a lot of dict keys have been
* deleted).
*/
if (mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2) {
if (dictresize(mp, mp->ma_used*2) != 0)
return -1;
}
return 0;
}
DL_EXPORT(int)
PyDict_DelItem(PyObject *op, PyObject *key)
{
register dictobject *mp;
register long hash;
register dictentry *ep;
PyObject *old_value, *old_key;
#ifdef SYMBIAN
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
#ifdef CACHE_HASH
if (!PyString_CheckExact(key) ||
(hash = ((PyStringObject *) key)->ob_shash) == -1)
#endif
{
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
mp = (dictobject *)op;
ep = (mp->ma_lookup)(mp, key, hash);
if (ep->me_value == NULL) {
PyErr_SetObject(PyExc_KeyError, key);
return -1;
}
old_key = ep->me_key;
Py_INCREF(dummy);
ep->me_key = dummy;
old_value = ep->me_value;
ep->me_value = NULL;
mp->ma_used--;
Py_DECREF(old_value);
Py_DECREF(old_key);
return 0;
}
DL_EXPORT(void)
PyDict_Clear(PyObject *op)
{
dictobject *mp;
dictentry *ep, *table;
int table_is_malloced;
int fill;
dictentry small_copy[PyDict_MINSIZE];
#ifdef Py_DEBUG
int i, n;
#endif
if (!PyDict_Check(op))
return;
mp = (dictobject *)op;
#ifdef Py_DEBUG
n = mp->ma_mask + 1;
i = 0;
#endif
table = mp->ma_table;
assert(table != NULL);
table_is_malloced = table != mp->ma_smalltable;
/* This is delicate. During the process of clearing the dict,
* decrefs can cause the dict to mutate. To avoid fatal confusion
* (voice of experience), we have to make the dict empty before
* clearing the slots, and never refer to anything via mp->xxx while
* clearing.
*/
fill = mp->ma_fill;
if (table_is_malloced)
EMPTY_TO_MINSIZE(mp);
else if (fill > 0) {
/* It's a small table with something that needs to be cleared.
* Afraid the only safe way is to copy the dict entries into
* another small table first.
*/
memcpy(small_copy, table, sizeof(small_copy));
table = small_copy;
EMPTY_TO_MINSIZE(mp);
}
/* else it's a small table that's already empty */
/* Now we can finally clear things. If C had refcounts, we could
* assert that the refcount on table is 1 now, i.e. that this function
* has unique access to it, so decref side-effects can't alter it.
*/
for (ep = table; fill > 0; ++ep) {
#ifdef Py_DEBUG
assert(i < n);
++i;
#endif
if (ep->me_key) {
--fill;
Py_DECREF(ep->me_key);
Py_XDECREF(ep->me_value);
}
#ifdef Py_DEBUG
else
assert(ep->me_value == NULL);
#endif
}
if (table_is_malloced)
PyMem_DEL(table);
}
/* CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
* mutates the dict. One exception: it is safe if the loop merely changes
* the values associated with the keys (but doesn't insert new keys or
* delete keys), via PyDict_SetItem().
*/
DL_EXPORT(int)
PyDict_Next(PyObject *op, int *ppos, PyObject **pkey, PyObject **pvalue)
{
int i;
register dictobject *mp;
if (!PyDict_Check(op))
return 0;
mp = (dictobject *)op;
i = *ppos;
if (i < 0)
return 0;
while (i <= mp->ma_mask && mp->ma_table[i].me_value == NULL)
i++;
*ppos = i+1;
if (i > mp->ma_mask)
return 0;
if (pkey)
*pkey = mp->ma_table[i].me_key;
if (pvalue)
*pvalue = mp->ma_table[i].me_value;
return 1;
}
/* Methods */
static void
dict_dealloc(register dictobject *mp)
{
register dictentry *ep;
int fill = mp->ma_fill;
PyObject_GC_UnTrack(mp);
Py_TRASHCAN_SAFE_BEGIN(mp)
for (ep = mp->ma_table; fill > 0; ep++) {
if (ep->me_key) {
--fill;
Py_DECREF(ep->me_key);
Py_XDECREF(ep->me_value);
}
}
if (mp->ma_table != mp->ma_smalltable)
PyMem_DEL(mp->ma_table);
mp->ob_type->tp_free((PyObject *)mp);
Py_TRASHCAN_SAFE_END(mp)
}
static int
dict_print(register dictobject *mp, register FILE *fp, register int flags)
{
register int i;
register int any;
i = Py_ReprEnter((PyObject*)mp);
if (i != 0) {
if (i < 0)
return i;
fprintf(fp, "{...}");
return 0;
}
fprintf(fp, "{");
any = 0;
for (i = 0; i <= mp->ma_mask; i++) {
dictentry *ep = mp->ma_table + i;
PyObject *pvalue = ep->me_value;
if (pvalue != NULL) {
/* Prevent PyObject_Repr from deleting value during
key format */
Py_INCREF(pvalue);
if (any++ > 0)
fprintf(fp, ", ");
if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) {
Py_DECREF(pvalue);
Py_ReprLeave((PyObject*)mp);
return -1;
}
fprintf(fp, ": ");
if (PyObject_Print(pvalue, fp, 0) != 0) {
Py_DECREF(pvalue);
Py_ReprLeave((PyObject*)mp);
return -1;
}
Py_DECREF(pvalue);
}
}
fprintf(fp, "}");
Py_ReprLeave((PyObject*)mp);
return 0;
}
static PyObject *
dict_repr(dictobject *mp)
{
int i;
PyObject *s, *temp, *colon = NULL;
PyObject *pieces = NULL, *result = NULL;
PyObject *key, *value;
i = Py_ReprEnter((PyObject *)mp);
if (i != 0) {
return i > 0 ? PyString_FromString("{...}") : NULL;
}
if (mp->ma_used == 0) {
result = PyString_FromString("{}");
goto Done;
}
pieces = PyList_New(0);
if (pieces == NULL)
goto Done;
colon = PyString_FromString(": ");
if (colon == NULL)
goto Done;
/* Do repr() on each key+value pair, and insert ": " between them.
Note that repr may mutate the dict. */
i = 0;
while (PyDict_Next((PyObject *)mp, &i, &key, &value)) {
int status;
/* Prevent repr from deleting value during key format. */
Py_INCREF(value);
s = PyObject_Repr(key);
PyString_Concat(&s, colon);
PyString_ConcatAndDel(&s, PyObject_Repr(value));
Py_DECREF(value);
if (s == NULL)
goto Done;
status = PyList_Append(pieces, s);
Py_DECREF(s); /* append created a new ref */
if (status < 0)
goto Done;
}
/* Add "{}" decorations to the first and last items. */
assert(PyList_GET_SIZE(pieces) > 0);
s = PyString_FromString("{");
if (s == NULL)
goto Done;
temp = PyList_GET_ITEM(pieces, 0);
PyString_ConcatAndDel(&s, temp);
PyList_SET_ITEM(pieces, 0, s);
if (s == NULL)
goto Done;
s = PyString_FromString("}");
if (s == NULL)
goto Done;
temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1);
PyString_ConcatAndDel(&temp, s);
PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp);
if (temp == NULL)
goto Done;
/* Paste them all together with ", " between. */
s = PyString_FromString(", ");
if (s == NULL)
goto Done;
result = _PyString_Join(s, pieces);
Py_DECREF(s);
Done:
Py_XDECREF(pieces);
Py_XDECREF(colon);
Py_ReprLeave((PyObject *)mp);
return result;
}
static int
dict_length(dictobject *mp)
{
return mp->ma_used;
}
static PyObject *
dict_subscript(dictobject *mp, register PyObject *key)
{
PyObject *v;
long hash;
assert(mp->ma_table != NULL);
#ifdef CACHE_HASH
if (!PyString_CheckExact(key) ||
(hash = ((PyStringObject *) key)->ob_shash) == -1)
#endif
{
hash = PyObject_Hash(key);
if (hash == -1)
return NULL;
}
v = (mp->ma_lookup)(mp, key, hash) -> me_value;
if (v == NULL)
PyErr_SetObject(PyExc_KeyError, key);
else
Py_INCREF(v);
return v;
}
static int
dict_ass_sub(dictobject *mp, PyObject *v, PyObject *w)
{
if (w == NULL)
return PyDict_DelItem((PyObject *)mp, v);
else
return PyDict_SetItem((PyObject *)mp, v, w);
}
static const PyMappingMethods dict_as_mapping = {
(inquiry)dict_length, /*mp_length*/
(binaryfunc)dict_subscript, /*mp_subscript*/
(objobjargproc)dict_ass_sub, /*mp_ass_subscript*/
};
static PyObject *
dict_keys(register dictobject *mp)
{
register PyObject *v;
register int i, j, n;
again:
n = mp->ma_used;
v = PyList_New(n);
if (v == NULL)
return NULL;
if (n != mp->ma_used) {
/* Durnit. The allocations caused the dict to resize.
* Just start over, this shouldn't normally happen.
*/
Py_DECREF(v);
goto again;
}
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) {
PyObject *key = mp->ma_table[i].me_key;
Py_INCREF(key);
PyList_SET_ITEM(v, j, key);
j++;
}
}
return v;
}
static PyObject *
dict_values(register dictobject *mp)
{
register PyObject *v;
register int i, j, n;
again:
n = mp->ma_used;
v = PyList_New(n);
if (v == NULL)
return NULL;
if (n != mp->ma_used) {
/* Durnit. The allocations caused the dict to resize.
* Just start over, this shouldn't normally happen.
*/
Py_DECREF(v);
goto again;
}
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) {
PyObject *value = mp->ma_table[i].me_value;
Py_INCREF(value);
PyList_SET_ITEM(v, j, value);
j++;
}
}
return v;
}
static PyObject *
dict_items(register dictobject *mp)
{
register PyObject *v;
register int i, j, n;
PyObject *item, *key, *value;
/* Preallocate the list of tuples, to avoid allocations during
* the loop over the items, which could trigger GC, which
* could resize the dict. :-(
*/
again:
n = mp->ma_used;
v = PyList_New(n);
if (v == NULL)
return NULL;
for (i = 0; i < n; i++) {
item = PyTuple_New(2);
if (item == NULL) {
Py_DECREF(v);
return NULL;
}
PyList_SET_ITEM(v, i, item);
}
if (n != mp->ma_used) {
/* Durnit. The allocations caused the dict to resize.
* Just start over, this shouldn't normally happen.
*/
Py_DECREF(v);
goto again;
}
/* Nothing we do below makes any function calls. */
for (i = 0, j = 0; i <= mp->ma_mask; i++) {
if (mp->ma_table[i].me_value != NULL) {
key = mp->ma_table[i].me_key;
value = mp->ma_table[i].me_value;
item = PyList_GET_ITEM(v, j);
Py_INCREF(key);
PyTuple_SET_ITEM(item, 0, key);
Py_INCREF(value);
PyTuple_SET_ITEM(item, 1, value);
j++;
}
}
assert(j == n);
return v;
}
static PyObject *
dict_update(PyObject *mp, PyObject *other)
{
if (PyDict_Update(mp, other) < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
}
/* Update unconditionally replaces existing items.
Merge has a 3rd argument 'override'; if set, it acts like Update,
otherwise it leaves existing items unchanged.
PyDict_{Update,Merge} update/merge from a mapping object.
PyDict_MergeFromSeq2 updates/merges from any iterable object
producing iterable objects of length 2.
*/
DL_EXPORT(int)
PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
{
PyObject *it; /* iter(seq2) */
int i; /* index into seq2 of current element */
PyObject *item; /* seq2[i] */
PyObject *fast; /* item as a 2-tuple or 2-list */
assert(d != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -