mirror of
https://github.com/python/cpython.git
synced 2025-08-03 08:34:29 +00:00
Issue #16991: Add a C implementation of collections.OrderedDict.
This commit is contained in:
parent
3979323ca3
commit
47db71756d
12 changed files with 2860 additions and 195 deletions
22
Objects/dict-common.h
Normal file
22
Objects/dict-common.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef Py_DICT_COMMON_H
|
||||
#define Py_DICT_COMMON_H
|
||||
|
||||
typedef struct {
|
||||
/* Cached hash code of me_key. */
|
||||
Py_hash_t me_hash;
|
||||
PyObject *me_key;
|
||||
PyObject *me_value; /* This field is only meaningful for combined tables */
|
||||
} PyDictKeyEntry;
|
||||
|
||||
typedef PyDictKeyEntry *(*dict_lookup_func)
|
||||
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr);
|
||||
|
||||
struct _dictkeysobject {
|
||||
Py_ssize_t dk_refcnt;
|
||||
Py_ssize_t dk_size;
|
||||
dict_lookup_func dk_lookup;
|
||||
Py_ssize_t dk_usable;
|
||||
PyDictKeyEntry dk_entries[1];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -67,6 +67,7 @@ to the combined-table form.
|
|||
#define PyDict_MINSIZE_COMBINED 8
|
||||
|
||||
#include "Python.h"
|
||||
#include "dict-common.h"
|
||||
#include "stringlib/eq.h"
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -74,24 +75,6 @@ class dict "PyDictObject *" "&PyDict_Type"
|
|||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/
|
||||
|
||||
typedef struct {
|
||||
/* Cached hash code of me_key. */
|
||||
Py_hash_t me_hash;
|
||||
PyObject *me_key;
|
||||
PyObject *me_value; /* This field is only meaningful for combined tables */
|
||||
} PyDictKeyEntry;
|
||||
|
||||
typedef PyDictKeyEntry *(*dict_lookup_func)
|
||||
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr);
|
||||
|
||||
struct _dictkeysobject {
|
||||
Py_ssize_t dk_refcnt;
|
||||
Py_ssize_t dk_size;
|
||||
dict_lookup_func dk_lookup;
|
||||
Py_ssize_t dk_usable;
|
||||
PyDictKeyEntry dk_entries[1];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
To ensure the lookup algorithm terminates, there must be at least one Unused
|
||||
|
@ -1425,6 +1408,141 @@ _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Internal version of dict.pop(). */
|
||||
PyObject *
|
||||
_PyDict_Pop(PyDictObject *mp, PyObject *key, PyObject *deflt)
|
||||
{
|
||||
Py_hash_t hash;
|
||||
PyObject *old_value, *old_key;
|
||||
PyDictKeyEntry *ep;
|
||||
PyObject **value_addr;
|
||||
|
||||
if (mp->ma_used == 0) {
|
||||
if (deflt) {
|
||||
Py_INCREF(deflt);
|
||||
return deflt;
|
||||
}
|
||||
_PyErr_SetKeyError(key);
|
||||
return NULL;
|
||||
}
|
||||
if (!PyUnicode_CheckExact(key) ||
|
||||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
|
||||
hash = PyObject_Hash(key);
|
||||
if (hash == -1)
|
||||
return NULL;
|
||||
}
|
||||
ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
|
||||
if (ep == NULL)
|
||||
return NULL;
|
||||
old_value = *value_addr;
|
||||
if (old_value == NULL) {
|
||||
if (deflt) {
|
||||
Py_INCREF(deflt);
|
||||
return deflt;
|
||||
}
|
||||
_PyErr_SetKeyError(key);
|
||||
return NULL;
|
||||
}
|
||||
*value_addr = NULL;
|
||||
mp->ma_used--;
|
||||
if (!_PyDict_HasSplitTable(mp)) {
|
||||
ENSURE_ALLOWS_DELETIONS(mp);
|
||||
old_key = ep->me_key;
|
||||
Py_INCREF(dummy);
|
||||
ep->me_key = dummy;
|
||||
Py_DECREF(old_key);
|
||||
}
|
||||
return old_value;
|
||||
}
|
||||
|
||||
/* Internal version of dict.from_keys(). It is subclass-friendly. */
|
||||
PyObject *
|
||||
_PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
|
||||
{
|
||||
PyObject *it; /* iter(iterable) */
|
||||
PyObject *key;
|
||||
PyObject *d;
|
||||
int status;
|
||||
|
||||
d = PyObject_CallObject(cls, NULL);
|
||||
if (d == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) {
|
||||
if (PyDict_CheckExact(iterable)) {
|
||||
PyDictObject *mp = (PyDictObject *)d;
|
||||
PyObject *oldvalue;
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key;
|
||||
Py_hash_t hash;
|
||||
|
||||
if (dictresize(mp, Py_SIZE(iterable))) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
|
||||
if (insertdict(mp, key, hash, value)) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
if (PyAnySet_CheckExact(iterable)) {
|
||||
PyDictObject *mp = (PyDictObject *)d;
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key;
|
||||
Py_hash_t hash;
|
||||
|
||||
if (dictresize(mp, PySet_GET_SIZE(iterable))) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
|
||||
if (insertdict(mp, key, hash, value)) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
it = PyObject_GetIter(iterable);
|
||||
if (it == NULL){
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyDict_CheckExact(d)) {
|
||||
while ((key = PyIter_Next(it)) != NULL) {
|
||||
status = PyDict_SetItem(d, key, value);
|
||||
Py_DECREF(key);
|
||||
if (status < 0)
|
||||
goto Fail;
|
||||
}
|
||||
} else {
|
||||
while ((key = PyIter_Next(it)) != NULL) {
|
||||
status = PyObject_SetItem(d, key, value);
|
||||
Py_DECREF(key);
|
||||
if (status < 0)
|
||||
goto Fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (PyErr_Occurred())
|
||||
goto Fail;
|
||||
Py_DECREF(it);
|
||||
return d;
|
||||
|
||||
Fail:
|
||||
Py_DECREF(it);
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Methods */
|
||||
|
||||
static void
|
||||
|
@ -1763,88 +1881,7 @@ static PyObject *
|
|||
dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value)
|
||||
/*[clinic end generated code: output=8fb98e4b10384999 input=b85a667f9bf4669d]*/
|
||||
{
|
||||
PyObject *it; /* iter(seq) */
|
||||
PyObject *key;
|
||||
PyObject *d;
|
||||
int status;
|
||||
|
||||
d = PyObject_CallObject((PyObject *)type, NULL);
|
||||
if (d == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) {
|
||||
if (PyDict_CheckExact(iterable)) {
|
||||
PyDictObject *mp = (PyDictObject *)d;
|
||||
PyObject *oldvalue;
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key;
|
||||
Py_hash_t hash;
|
||||
|
||||
if (dictresize(mp, Py_SIZE(iterable))) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
|
||||
if (insertdict(mp, key, hash, value)) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
if (PyAnySet_CheckExact(iterable)) {
|
||||
PyDictObject *mp = (PyDictObject *)d;
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key;
|
||||
Py_hash_t hash;
|
||||
|
||||
if (dictresize(mp, PySet_GET_SIZE(iterable))) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
|
||||
if (insertdict(mp, key, hash, value)) {
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
it = PyObject_GetIter(iterable);
|
||||
if (it == NULL){
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyDict_CheckExact(d)) {
|
||||
while ((key = PyIter_Next(it)) != NULL) {
|
||||
status = PyDict_SetItem(d, key, value);
|
||||
Py_DECREF(key);
|
||||
if (status < 0)
|
||||
goto Fail;
|
||||
}
|
||||
} else {
|
||||
while ((key = PyIter_Next(it)) != NULL) {
|
||||
status = PyObject_SetItem(d, key, value);
|
||||
Py_DECREF(key);
|
||||
if (status < 0)
|
||||
goto Fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (PyErr_Occurred())
|
||||
goto Fail;
|
||||
Py_DECREF(it);
|
||||
return d;
|
||||
|
||||
Fail:
|
||||
Py_DECREF(it);
|
||||
Py_DECREF(d);
|
||||
return NULL;
|
||||
return _PyDict_FromKeys((PyObject *)type, iterable, value);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2356,50 +2393,12 @@ dict_clear(PyDictObject *mp)
|
|||
static PyObject *
|
||||
dict_pop(PyDictObject *mp, PyObject *args)
|
||||
{
|
||||
Py_hash_t hash;
|
||||
PyObject *old_value, *old_key;
|
||||
PyObject *key, *deflt = NULL;
|
||||
PyDictKeyEntry *ep;
|
||||
PyObject **value_addr;
|
||||
|
||||
if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt))
|
||||
return NULL;
|
||||
if (mp->ma_used == 0) {
|
||||
if (deflt) {
|
||||
Py_INCREF(deflt);
|
||||
return deflt;
|
||||
}
|
||||
_PyErr_SetKeyError(key);
|
||||
return NULL;
|
||||
}
|
||||
if (!PyUnicode_CheckExact(key) ||
|
||||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
|
||||
hash = PyObject_Hash(key);
|
||||
if (hash == -1)
|
||||
return NULL;
|
||||
}
|
||||
ep = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr);
|
||||
if (ep == NULL)
|
||||
return NULL;
|
||||
old_value = *value_addr;
|
||||
if (old_value == NULL) {
|
||||
if (deflt) {
|
||||
Py_INCREF(deflt);
|
||||
return deflt;
|
||||
}
|
||||
_PyErr_SetKeyError(key);
|
||||
return NULL;
|
||||
}
|
||||
*value_addr = NULL;
|
||||
mp->ma_used--;
|
||||
if (!_PyDict_HasSplitTable(mp)) {
|
||||
ENSURE_ALLOWS_DELETIONS(mp);
|
||||
old_key = ep->me_key;
|
||||
Py_INCREF(dummy);
|
||||
ep->me_key = dummy;
|
||||
Py_DECREF(old_key);
|
||||
}
|
||||
return old_value;
|
||||
|
||||
return _PyDict_Pop(mp, key, deflt);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
|
@ -2506,8 +2505,8 @@ dict_tp_clear(PyObject *op)
|
|||
|
||||
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
|
||||
|
||||
static PyObject *
|
||||
dict_sizeof(PyDictObject *mp)
|
||||
PyObject *
|
||||
_PyDict_SizeOf(PyDictObject *mp)
|
||||
{
|
||||
Py_ssize_t size, res;
|
||||
|
||||
|
@ -2575,7 +2574,7 @@ static PyMethodDef mapp_methods[] = {
|
|||
DICT___CONTAINS___METHODDEF
|
||||
{"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST,
|
||||
getitem__doc__},
|
||||
{"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS,
|
||||
{"__sizeof__", (PyCFunction)_PyDict_SizeOf, METH_NOARGS,
|
||||
sizeof__doc__},
|
||||
{"get", (PyCFunction)dict_get, METH_VARARGS,
|
||||
get__doc__},
|
||||
|
@ -3104,8 +3103,8 @@ static PyObject *dictiter_iternextitem(dictiterobject *di)
|
|||
value = *value_ptr;
|
||||
Py_INCREF(key);
|
||||
Py_INCREF(value);
|
||||
PyTuple_SET_ITEM(result, 0, key);
|
||||
PyTuple_SET_ITEM(result, 1, value);
|
||||
PyTuple_SET_ITEM(result, 0, key); /* steals reference */
|
||||
PyTuple_SET_ITEM(result, 1, value); /* steals reference */
|
||||
return result;
|
||||
|
||||
fail:
|
||||
|
@ -3200,28 +3199,22 @@ dictiter_reduce(dictiterobject *di)
|
|||
|
||||
/* The instance lay-out is the same for all three; but the type differs. */
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyDictObject *dv_dict;
|
||||
} dictviewobject;
|
||||
|
||||
|
||||
static void
|
||||
dictview_dealloc(dictviewobject *dv)
|
||||
dictview_dealloc(_PyDictViewObject *dv)
|
||||
{
|
||||
Py_XDECREF(dv->dv_dict);
|
||||
PyObject_GC_Del(dv);
|
||||
}
|
||||
|
||||
static int
|
||||
dictview_traverse(dictviewobject *dv, visitproc visit, void *arg)
|
||||
dictview_traverse(_PyDictViewObject *dv, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(dv->dv_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Py_ssize_t
|
||||
dictview_len(dictviewobject *dv)
|
||||
dictview_len(_PyDictViewObject *dv)
|
||||
{
|
||||
Py_ssize_t len = 0;
|
||||
if (dv->dv_dict != NULL)
|
||||
|
@ -3229,10 +3222,10 @@ dictview_len(dictviewobject *dv)
|
|||
return len;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
dictview_new(PyObject *dict, PyTypeObject *type)
|
||||
PyObject *
|
||||
_PyDictView_New(PyObject *dict, PyTypeObject *type)
|
||||
{
|
||||
dictviewobject *dv;
|
||||
_PyDictViewObject *dv;
|
||||
if (dict == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return NULL;
|
||||
|
@ -3244,7 +3237,7 @@ dictview_new(PyObject *dict, PyTypeObject *type)
|
|||
type->tp_name, dict->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
dv = PyObject_GC_New(dictviewobject, type);
|
||||
dv = PyObject_GC_New(_PyDictViewObject, type);
|
||||
if (dv == NULL)
|
||||
return NULL;
|
||||
Py_INCREF(dict);
|
||||
|
@ -3348,7 +3341,7 @@ dictview_richcompare(PyObject *self, PyObject *other, int op)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
dictview_repr(dictviewobject *dv)
|
||||
dictview_repr(_PyDictViewObject *dv)
|
||||
{
|
||||
PyObject *seq;
|
||||
PyObject *result;
|
||||
|
@ -3365,7 +3358,7 @@ dictview_repr(dictviewobject *dv)
|
|||
/*** dict_keys ***/
|
||||
|
||||
static PyObject *
|
||||
dictkeys_iter(dictviewobject *dv)
|
||||
dictkeys_iter(_PyDictViewObject *dv)
|
||||
{
|
||||
if (dv->dv_dict == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
|
@ -3374,7 +3367,7 @@ dictkeys_iter(dictviewobject *dv)
|
|||
}
|
||||
|
||||
static int
|
||||
dictkeys_contains(dictviewobject *dv, PyObject *obj)
|
||||
dictkeys_contains(_PyDictViewObject *dv, PyObject *obj)
|
||||
{
|
||||
if (dv->dv_dict == NULL)
|
||||
return 0;
|
||||
|
@ -3499,7 +3492,7 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
|
|||
PyObject *item = NULL;
|
||||
|
||||
if (self == other) {
|
||||
if (dictview_len((dictviewobject *)self) == 0)
|
||||
if (dictview_len((_PyDictViewObject *)self) == 0)
|
||||
Py_RETURN_TRUE;
|
||||
else
|
||||
Py_RETURN_FALSE;
|
||||
|
@ -3508,7 +3501,7 @@ dictviews_isdisjoint(PyObject *self, PyObject *other)
|
|||
/* Iterate over the shorter object (only if other is a set,
|
||||
* because PySequence_Contains may be expensive otherwise): */
|
||||
if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
|
||||
Py_ssize_t len_self = dictview_len((dictviewobject *)self);
|
||||
Py_ssize_t len_self = dictview_len((_PyDictViewObject *)self);
|
||||
Py_ssize_t len_other = PyObject_Size(other);
|
||||
if (len_other == -1)
|
||||
return NULL;
|
||||
|
@ -3555,7 +3548,7 @@ static PyMethodDef dictkeys_methods[] = {
|
|||
PyTypeObject PyDictKeys_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"dict_keys", /* tp_name */
|
||||
sizeof(dictviewobject), /* tp_basicsize */
|
||||
sizeof(_PyDictViewObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)dictview_dealloc, /* tp_dealloc */
|
||||
|
@ -3588,13 +3581,13 @@ PyTypeObject PyDictKeys_Type = {
|
|||
static PyObject *
|
||||
dictkeys_new(PyObject *dict)
|
||||
{
|
||||
return dictview_new(dict, &PyDictKeys_Type);
|
||||
return _PyDictView_New(dict, &PyDictKeys_Type);
|
||||
}
|
||||
|
||||
/*** dict_items ***/
|
||||
|
||||
static PyObject *
|
||||
dictitems_iter(dictviewobject *dv)
|
||||
dictitems_iter(_PyDictViewObject *dv)
|
||||
{
|
||||
if (dv->dv_dict == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
|
@ -3603,7 +3596,7 @@ dictitems_iter(dictviewobject *dv)
|
|||
}
|
||||
|
||||
static int
|
||||
dictitems_contains(dictviewobject *dv, PyObject *obj)
|
||||
dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
|
||||
{
|
||||
PyObject *key, *value, *found;
|
||||
if (dv->dv_dict == NULL)
|
||||
|
@ -3641,7 +3634,7 @@ static PyMethodDef dictitems_methods[] = {
|
|||
PyTypeObject PyDictItems_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"dict_items", /* tp_name */
|
||||
sizeof(dictviewobject), /* tp_basicsize */
|
||||
sizeof(_PyDictViewObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)dictview_dealloc, /* tp_dealloc */
|
||||
|
@ -3674,13 +3667,13 @@ PyTypeObject PyDictItems_Type = {
|
|||
static PyObject *
|
||||
dictitems_new(PyObject *dict)
|
||||
{
|
||||
return dictview_new(dict, &PyDictItems_Type);
|
||||
return _PyDictView_New(dict, &PyDictItems_Type);
|
||||
}
|
||||
|
||||
/*** dict_values ***/
|
||||
|
||||
static PyObject *
|
||||
dictvalues_iter(dictviewobject *dv)
|
||||
dictvalues_iter(_PyDictViewObject *dv)
|
||||
{
|
||||
if (dv->dv_dict == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
|
@ -3706,7 +3699,7 @@ static PyMethodDef dictvalues_methods[] = {
|
|||
PyTypeObject PyDictValues_Type = {
|
||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||
"dict_values", /* tp_name */
|
||||
sizeof(dictviewobject), /* tp_basicsize */
|
||||
sizeof(_PyDictViewObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
(destructor)dictview_dealloc, /* tp_dealloc */
|
||||
|
@ -3739,7 +3732,7 @@ PyTypeObject PyDictValues_Type = {
|
|||
static PyObject *
|
||||
dictvalues_new(PyObject *dict)
|
||||
{
|
||||
return dictview_new(dict, &PyDictValues_Type);
|
||||
return _PyDictView_New(dict, &PyDictValues_Type);
|
||||
}
|
||||
|
||||
/* Returns NULL if cannot allocate a new PyDictKeysObject,
|
||||
|
|
|
@ -1607,6 +1607,21 @@ _Py_ReadyTypes(void)
|
|||
if (PyType_Ready(&PyDict_Type) < 0)
|
||||
Py_FatalError("Can't initialize dict type");
|
||||
|
||||
if (PyType_Ready(&PyODict_Type) < 0)
|
||||
Py_FatalError("Can't initialize OrderedDict type");
|
||||
|
||||
if (PyType_Ready(&PyODictKeys_Type) < 0)
|
||||
Py_FatalError("Can't initialize odict_keys type");
|
||||
|
||||
if (PyType_Ready(&PyODictItems_Type) < 0)
|
||||
Py_FatalError("Can't initialize odict_items type");
|
||||
|
||||
if (PyType_Ready(&PyODictValues_Type) < 0)
|
||||
Py_FatalError("Can't initialize odict_values type");
|
||||
|
||||
if (PyType_Ready(&PyODictIter_Type) < 0)
|
||||
Py_FatalError("Can't initialize odict_keyiterator type");
|
||||
|
||||
if (PyType_Ready(&PySet_Type) < 0)
|
||||
Py_FatalError("Can't initialize set type");
|
||||
|
||||
|
|
2394
Objects/odictobject.c
Normal file
2394
Objects/odictobject.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue