Source code

Revision control

Copy as Markdown

Other Tools

#include "Python.h"
#include "structmember.h"
// Include order important
#include "_multilib/defs.h"
#include "_multilib/istr.h"
#include "_multilib/pair_list.h"
#include "_multilib/dict.h"
#include "_multilib/iter.h"
#include "_multilib/views.h"
static PyObject *collections_abc_mapping;
static PyObject *collections_abc_mut_mapping;
static PyObject *collections_abc_mut_multi_mapping;
static PyTypeObject multidict_type;
static PyTypeObject cimultidict_type;
static PyTypeObject multidict_proxy_type;
static PyTypeObject cimultidict_proxy_type;
static PyObject *repr_func;
#define MultiDict_CheckExact(o) (Py_TYPE(o) == &multidict_type)
#define CIMultiDict_CheckExact(o) (Py_TYPE(o) == &cimultidict_type)
#define MultiDictProxy_CheckExact(o) (Py_TYPE(o) == &multidict_proxy_type)
#define CIMultiDictProxy_CheckExact(o) (Py_TYPE(o) == &cimultidict_proxy_type)
/* Helper macro for something like isinstance(obj, Base) */
#define _MultiDict_Check(o) \
((MultiDict_CheckExact(o)) || \
(CIMultiDict_CheckExact(o)) || \
(MultiDictProxy_CheckExact(o)) || \
(CIMultiDictProxy_CheckExact(o)))
/******************** Internal Methods ********************/
/* Forward declaration */
static PyObject *multidict_items(MultiDictObject *self);
static inline PyObject *
_multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default)
{
PyObject *val = pair_list_get_one(&self->pairs, key);
if (val == NULL &&
PyErr_ExceptionMatches(PyExc_KeyError) &&
_default != NULL)
{
PyErr_Clear();
Py_INCREF(_default);
return _default;
}
return val;
}
static inline int
_multidict_eq(MultiDictObject *self, MultiDictObject *other)
{
Py_ssize_t pos1 = 0,
pos2 = 0;
Py_hash_t h1 = 0,
h2 = 0;
PyObject *identity1 = NULL,
*identity2 = NULL,
*value1 = NULL,
*value2 = NULL;
int cmp_identity = 0,
cmp_value = 0;
if (self == other) {
return 1;
}
if (pair_list_len(&self->pairs) != pair_list_len(&other->pairs)) {
return 0;
}
while (_pair_list_next(&self->pairs, &pos1, &identity1, NULL, &value1, &h1) &&
_pair_list_next(&other->pairs, &pos2, &identity2, NULL, &value2, &h2))
{
if (h1 != h2) {
return 0;
}
cmp_identity = PyObject_RichCompareBool(identity1, identity2, Py_NE);
if (cmp_identity < 0) {
return -1;
}
cmp_value = PyObject_RichCompareBool(value1, value2, Py_NE);
if (cmp_value < 0) {
return -1;
}
if (cmp_identity || cmp_value) {
return 0;
}
}
return 1;
}
static inline int
_multidict_update_items(MultiDictObject *self, pair_list_t *pairs)
{
return pair_list_update(&self->pairs, pairs);
}
static inline int
_multidict_append_items(MultiDictObject *self, pair_list_t *pairs)
{
PyObject *key = NULL,
*value = NULL;
Py_ssize_t pos = 0;
while (_pair_list_next(pairs, &pos, NULL, &key, &value, NULL)) {
if (pair_list_add(&self->pairs, key, value) < 0) {
return -1;
}
}
return 0;
}
static inline int
_multidict_append_items_seq(MultiDictObject *self, PyObject *arg,
const char *name)
{
PyObject *key = NULL,
*value = NULL,
*item = NULL,
*iter = PyObject_GetIter(arg);
if (iter == NULL) {
return -1;
}
while ((item = PyIter_Next(iter)) != NULL) {
if (PyTuple_CheckExact(item)) {
if (PyTuple_GET_SIZE(item) != 2) {
goto invalid_type;
}
key = PyTuple_GET_ITEM(item, 0);
Py_INCREF(key);
value = PyTuple_GET_ITEM(item, 1);
Py_INCREF(value);
}
else if (PyList_CheckExact(item)) {
if (PyList_GET_SIZE(item) != 2) {
goto invalid_type;
}
key = PyList_GET_ITEM(item, 0);
Py_INCREF(key);
value = PyList_GET_ITEM(item, 1);
Py_INCREF(value);
}
else if (PySequence_Check(item)) {
if (PySequence_Size(item) != 2) {
goto invalid_type;
}
key = PySequence_GetItem(item, 0);
value = PySequence_GetItem(item, 1);
} else {
goto invalid_type;
}
if (pair_list_add(&self->pairs, key, value) < 0) {
goto fail;
}
Py_CLEAR(key);
Py_CLEAR(value);
Py_CLEAR(item);
}
Py_DECREF(iter);
if (PyErr_Occurred()) {
return -1;
}
return 0;
invalid_type:
PyErr_Format(
PyExc_TypeError,
"%s takes either dict or list of (key, value) pairs",
name,
NULL
);
goto fail;
fail:
Py_XDECREF(key);
Py_XDECREF(value);
Py_XDECREF(item);
Py_DECREF(iter);
return -1;
}
static inline int
_multidict_list_extend(PyObject *list, PyObject *target_list)
{
PyObject *item = NULL,
*iter = PyObject_GetIter(target_list);
if (iter == NULL) {
return -1;
}
while ((item = PyIter_Next(iter)) != NULL) {
if (PyList_Append(list, item) < 0) {
Py_DECREF(item);
Py_DECREF(iter);
return -1;
}
Py_DECREF(item);
}
Py_DECREF(iter);
if (PyErr_Occurred()) {
return -1;
}
return 0;
}
static inline int
_multidict_extend_with_args(MultiDictObject *self, PyObject *arg,
PyObject *kwds, const char *name, int do_add)
{
PyObject *arg_items = NULL, /* tracked by GC */
*kwds_items = NULL; /* new reference */
pair_list_t *pairs = NULL;
int err = 0;
if (kwds && !PyArg_ValidateKeywordArguments(kwds)) {
return -1;
}
// TODO: mb can be refactored more clear
if (_MultiDict_Check(arg) && kwds == NULL) {
if (MultiDict_CheckExact(arg) || CIMultiDict_CheckExact(arg)) {
pairs = &((MultiDictObject*)arg)->pairs;
} else if (MultiDictProxy_CheckExact(arg) || CIMultiDictProxy_CheckExact(arg)) {
pairs = &((MultiDictProxyObject*)arg)->md->pairs;
}
if (do_add) {
return _multidict_append_items(self, pairs);
}
return _multidict_update_items(self, pairs);
}
if (PyObject_HasAttrString(arg, "items")) {
if (_MultiDict_Check(arg)) {
arg_items = multidict_items((MultiDictObject*)arg);
} else {
arg_items = PyMapping_Items(arg);
}
if (arg_items == NULL) {
return -1;
}
} else {
arg_items = arg;
Py_INCREF(arg_items);
}
if (kwds) {
PyObject *tmp = PySequence_List(arg_items);
Py_DECREF(arg_items);
arg_items = tmp;
if (arg_items == NULL) {
return -1;
}
kwds_items = PyDict_Items(kwds);
if (kwds_items == NULL) {
Py_DECREF(arg_items);
return -1;
}
err = _multidict_list_extend(arg_items, kwds_items);
Py_DECREF(kwds_items);
if (err < 0) {
Py_DECREF(arg_items);
return -1;
}
}
if (do_add) {
err = _multidict_append_items_seq(self, arg_items, name);
} else {
err = pair_list_update_from_seq(&self->pairs, arg_items);
}
Py_DECREF(arg_items);
return err;
}
static inline int
_multidict_extend_with_kwds(MultiDictObject *self, PyObject *kwds,
const char *name, int do_add)
{
PyObject *arg = NULL;
int err = 0;
if (!PyArg_ValidateKeywordArguments(kwds)) {
return -1;
}
arg = PyDict_Items(kwds);
if (do_add) {
err = _multidict_append_items_seq(self, arg, name);
} else {
err = pair_list_update_from_seq(&self->pairs, arg);
}
Py_DECREF(arg);
return err;
}
static inline int
_multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds,
const char *name, int do_add)
{
PyObject *arg = NULL;
if (args && PyObject_Length(args) > 1) {
PyErr_Format(
PyExc_TypeError,
"%s takes at most 1 positional argument (%zd given)",
name, PyObject_Length(args), NULL
);
return -1;
}
if (args && PyObject_Length(args) > 0) {
if (!PyArg_UnpackTuple(args, name, 0, 1, &arg)) {
return -1;
}
if (_multidict_extend_with_args(self, arg, kwds, name, do_add) < 0) {
return -1;
}
} else if (kwds && PyObject_Length(kwds) > 0) {
if (_multidict_extend_with_kwds(self, kwds, name, do_add) < 0) {
return -1;
}
}
return 0;
}
static inline PyObject *
_multidict_copy(MultiDictObject *self, PyTypeObject *multidict_tp_object)
{
MultiDictObject *new_multidict = NULL;
PyObject *arg_items = NULL,
*items = NULL;
new_multidict = (MultiDictObject*)PyType_GenericNew(
multidict_tp_object, NULL, NULL);
if (new_multidict == NULL) {
return NULL;
}
if (multidict_tp_object->tp_init(
(PyObject*)new_multidict, NULL, NULL) < 0)
{
return NULL;
}
items = multidict_items(self);
if (items == NULL) {
goto fail;
}
// TODO: "Implementation looks as slow as possible ..."
arg_items = PyTuple_New(1);
if (arg_items == NULL) {
goto fail;
}
Py_INCREF(items);
PyTuple_SET_ITEM(arg_items, 0, items);
if (_multidict_extend(
new_multidict, arg_items, NULL, "copy", 1) < 0)
{
goto fail;
}
Py_DECREF(items);
Py_DECREF(arg_items);
return (PyObject*)new_multidict;
fail:
Py_XDECREF(items);
Py_XDECREF(arg_items);
Py_DECREF(new_multidict);
return NULL;
}
static inline PyObject *
_multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type)
{
PyObject *new_multidict = PyType_GenericNew(type, NULL, NULL);
if (new_multidict == NULL) {
goto fail;
}
if (type->tp_init(new_multidict, NULL, NULL) < 0) {
goto fail;
}
if (_multidict_extend_with_args(
(MultiDictObject*)new_multidict, (PyObject*)self, NULL, "copy", 1) < 0)
{
goto fail;
}
return new_multidict;
fail:
Py_XDECREF(new_multidict);
return NULL;
}
/******************** Base Methods ********************/
static inline PyObject *
multidict_getall(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *list = NULL,
*key = NULL,
*_default = NULL;
static char *getall_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getall",
getall_keywords, &key, &_default))
{
return NULL;
}
list = pair_list_get_all(&self->pairs, key);
if (list == NULL &&
PyErr_ExceptionMatches(PyExc_KeyError) &&
_default != NULL)
{
PyErr_Clear();
Py_INCREF(_default);
return _default;
}
return list;
}
static inline PyObject *
multidict_getone(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*_default = NULL;
static char *getone_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
getone_keywords, &key, &_default))
{
return NULL;
}
return _multidict_getone(self, key, _default);
}
static inline PyObject *
multidict_get(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*_default = Py_None,
*ret;
static char *getone_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
getone_keywords, &key, &_default))
{
return NULL;
}
ret = _multidict_getone(self, key, _default);
return ret;
}
static inline PyObject *
multidict_keys(MultiDictObject *self)
{
return multidict_keysview_new((PyObject*)self);
}
static inline PyObject *
multidict_items(MultiDictObject *self)
{
return multidict_itemsview_new((PyObject*)self);
}
static inline PyObject *
multidict_values(MultiDictObject *self)
{
return multidict_valuesview_new((PyObject*)self);
}
static inline PyObject *
multidict_reduce(MultiDictObject *self)
{
PyObject *items = NULL,
*items_list = NULL,
*args = NULL,
*result = NULL;
items = multidict_items(self);
if (items == NULL) {
goto ret;
}
items_list = PySequence_List(items);
if (items_list == NULL) {
goto ret;
}
args = PyTuple_Pack(1, items_list);
if (args == NULL) {
goto ret;
}
result = PyTuple_Pack(2, Py_TYPE(self), args);
ret:
Py_XDECREF(args);
Py_XDECREF(items_list);
Py_XDECREF(items);
return result;
}
static inline PyObject *
multidict_repr(PyObject *self)
{
return PyObject_CallFunctionObjArgs(
repr_func, self, NULL);
}
static inline Py_ssize_t
multidict_mp_len(MultiDictObject *self)
{
return pair_list_len(&self->pairs);
}
static inline PyObject *
multidict_mp_subscript(MultiDictObject *self, PyObject *key)
{
return _multidict_getone(self, key, NULL);
}
static inline int
multidict_mp_as_subscript(MultiDictObject *self, PyObject *key, PyObject *val)
{
if (val == NULL) {
return pair_list_del(&self->pairs, key);
} else {
return pair_list_replace(&self->pairs, key, val);
}
}
static inline int
multidict_sq_contains(MultiDictObject *self, PyObject *key)
{
return pair_list_contains(&self->pairs, key);
}
static inline PyObject *
multidict_tp_iter(MultiDictObject *self)
{
return multidict_keys_iter_new(self);
}
static inline PyObject *
multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
{
// TODO: refactoring me with love
int cmp = 0;
if (op != Py_EQ && op != Py_NE) {
Py_RETURN_NOTIMPLEMENTED;
}
if (MultiDict_CheckExact(other) || CIMultiDict_CheckExact(other)) {
cmp = _multidict_eq(
(MultiDictObject*)self,
(MultiDictObject*)other
);
if (cmp < 0) {
return NULL;
}
if (op == Py_NE) {
cmp = !cmp;
}
return PyBool_FromLong(cmp);
}
if (MultiDictProxy_CheckExact(other) || CIMultiDictProxy_CheckExact(other)) {
cmp = _multidict_eq(
(MultiDictObject*)self,
((MultiDictProxyObject*)other)->md
);
if (cmp < 0) {
return NULL;
}
if (op == Py_NE) {
cmp = !cmp;
}
return PyBool_FromLong(cmp);
}
cmp = PyObject_IsInstance(other, (PyObject*)collections_abc_mapping);
if (cmp < 0) {
return NULL;
}
if (cmp) {
cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs, other);
if (cmp < 0) {
return NULL;
}
if (op == Py_NE) {
cmp = !cmp;
}
return PyBool_FromLong(cmp);
}
Py_RETURN_NOTIMPLEMENTED;
}
static inline void
multidict_tp_dealloc(MultiDictObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_SAFE_BEGIN(self);
if (self->weaklist != NULL) {
PyObject_ClearWeakRefs((PyObject *)self);
};
pair_list_dealloc(&self->pairs);
Py_TYPE(self)->tp_free((PyObject *)self);
Py_TRASHCAN_SAFE_END(self);
}
static inline int
multidict_tp_traverse(MultiDictObject *self, visitproc visit, void *arg)
{
return pair_list_traverse(&self->pairs, visit, arg);
}
static inline int
multidict_tp_clear(MultiDictObject *self)
{
return pair_list_clear(&self->pairs);
}
PyDoc_STRVAR(multidict_getall_doc,
"Return a list of all values matching the key.");
PyDoc_STRVAR(multidict_getone_doc,
"Get first value matching the key.");
PyDoc_STRVAR(multidict_get_doc,
"Get first value matching the key.\n\nThe method is alias for .getone().");
PyDoc_STRVAR(multidict_keys_doc,
"Return a new view of the dictionary's keys.");
PyDoc_STRVAR(multidict_items_doc,
"Return a new view of the dictionary's items *(key, value) pairs).");
PyDoc_STRVAR(multidict_values_doc,
"Return a new view of the dictionary's values.");
/******************** MultiDict ********************/
static inline int
multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
if (pair_list_init(&self->pairs) < 0) {
return -1;
}
if (_multidict_extend(self, args, kwds, "MultiDict", 1) < 0) {
return -1;
}
return 0;
}
static inline PyObject *
multidict_add(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*val = NULL;
static char *kwlist[] = {"key", "value", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:add",
kwlist, &key, &val))
{
return NULL;
}
if (pair_list_add(&self->pairs, key, val) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static inline PyObject *
multidict_copy(MultiDictObject *self)
{
return _multidict_copy(self, &multidict_type);
}
static inline PyObject *
multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
if (_multidict_extend(self, args, kwds, "extend", 1) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static inline PyObject *
multidict_clear(MultiDictObject *self)
{
if (pair_list_clear(&self->pairs) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static inline PyObject *
multidict_setdefault(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*_default = NULL;
static char *setdefault_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setdefault",
setdefault_keywords, &key, &_default))
{
return NULL;
}
return pair_list_set_default(&self->pairs, key, _default);
}
static inline PyObject *
multidict_popone(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
static char *popone_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone",
popone_keywords, &key, &_default))
{
return NULL;
}
ret_val = pair_list_pop_one(&self->pairs, key);
if (ret_val == NULL &&
PyErr_ExceptionMatches(PyExc_KeyError) &&
_default != NULL)
{
PyErr_Clear();
Py_INCREF(_default);
return _default;
}
return ret_val;
}
static inline PyObject *
multidict_popall(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
static char *popall_keywords[] = {"key", "default", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popall",
popall_keywords, &key, &_default))
{
return NULL;
}
ret_val = pair_list_pop_all(&self->pairs, key);
if (ret_val == NULL &&
PyErr_ExceptionMatches(PyExc_KeyError) &&
_default != NULL)
{
PyErr_Clear();
Py_INCREF(_default);
return _default;
}
return ret_val;
}
static inline PyObject *
multidict_popitem(MultiDictObject *self)
{
return pair_list_pop_item(&self->pairs);
}
static inline PyObject *
multidict_update(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
if (_multidict_extend(self, args, kwds, "update", 0) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(multidict_add_doc,
"Add the key and value, not overwriting any previous value.");
PyDoc_STRVAR(multidict_copy_doc,
"Return a copy of itself.");
PyDoc_STRVAR(multdicit_method_extend_doc,
"Extend current MultiDict with more values.\n\
This method must be used instead of update.");
PyDoc_STRVAR(multidict_clear_doc,
"Remove all items from MultiDict");
PyDoc_STRVAR(multidict_setdefault_doc,
"Return value for key, set value to default if key is not present.");
PyDoc_STRVAR(multidict_popone_doc,
"Remove the last occurrence of key and return the corresponding value.\n\n\
If key is not found, default is returned if given, otherwise KeyError is \
raised.\n");
PyDoc_STRVAR(multidict_popall_doc,
"Remove all occurrences of key and return the list of corresponding values.\n\n\
If key is not found, default is returned if given, otherwise KeyError is \
raised.\n");
PyDoc_STRVAR(multidict_popitem_doc,
"Remove and return an arbitrary (key, value) pair.");
PyDoc_STRVAR(multidict_update_doc,
"Update the dictionary from *other*, overwriting existing keys.");
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
#define multidict_class_getitem Py_GenericAlias
#else
static inline PyObject *
multidict_class_getitem(PyObject *self, PyObject *arg)
{
Py_INCREF(self);
return self;
}
#endif
PyDoc_STRVAR(sizeof__doc__,
"D.__sizeof__() -> size of D in memory, in bytes");
static inline PyObject *
_multidict_sizeof(MultiDictObject *self)
{
Py_ssize_t size = sizeof(MultiDictObject);
if (self->pairs.pairs != self->pairs.buffer) {
size += (Py_ssize_t)sizeof(pair_t) * self->pairs.capacity;
}
return PyLong_FromSsize_t(size);
}
static PySequenceMethods multidict_sequence = {
.sq_contains = (objobjproc)multidict_sq_contains,
};
static PyMappingMethods multidict_mapping = {
.mp_length = (lenfunc)multidict_mp_len,
.mp_subscript = (binaryfunc)multidict_mp_subscript,
.mp_ass_subscript = (objobjargproc)multidict_mp_as_subscript,
};
static PyMethodDef multidict_methods[] = {
{
"getall",
(PyCFunction)multidict_getall,
METH_VARARGS | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_getone,
METH_VARARGS | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_get,
METH_VARARGS | METH_KEYWORDS,
multidict_get_doc
},
{
"keys",
(PyCFunction)multidict_keys,
METH_NOARGS,
multidict_keys_doc
},
{
"items",
(PyCFunction)multidict_items,
METH_NOARGS,
multidict_items_doc
},
{
"values",
(PyCFunction)multidict_values,
METH_NOARGS,
multidict_values_doc
},
{
"add",
(PyCFunction)multidict_add,
METH_VARARGS | METH_KEYWORDS,
multidict_add_doc
},
{
"copy",
(PyCFunction)multidict_copy,
METH_NOARGS,
multidict_copy_doc
},
{
"extend",
(PyCFunction)multidict_extend,
METH_VARARGS | METH_KEYWORDS,
multdicit_method_extend_doc
},
{
"clear",
(PyCFunction)multidict_clear,
METH_NOARGS,
multidict_clear_doc
},
{
"setdefault",
(PyCFunction)multidict_setdefault,
METH_VARARGS | METH_KEYWORDS,
multidict_setdefault_doc
},
{
"popone",
(PyCFunction)multidict_popone,
METH_VARARGS | METH_KEYWORDS,
multidict_popone_doc
},
{
"pop",
(PyCFunction)multidict_popone,
METH_VARARGS | METH_KEYWORDS,
multidict_popone_doc
},
{
"popall",
(PyCFunction)multidict_popall,
METH_VARARGS | METH_KEYWORDS,
multidict_popall_doc
},
{
"popitem",
(PyCFunction)multidict_popitem,
METH_NOARGS,
multidict_popitem_doc
},
{
"update",
(PyCFunction)multidict_update,
METH_VARARGS | METH_KEYWORDS,
multidict_update_doc
},
{
"__reduce__",
(PyCFunction)multidict_reduce,
METH_NOARGS,
NULL,
},
{
"__class_getitem__",
(PyCFunction)multidict_class_getitem,
METH_O | METH_CLASS,
NULL
},
{
"__sizeof__",
(PyCFunction)_multidict_sizeof,
METH_NOARGS,
sizeof__doc__,
},
{
NULL,
NULL
} /* sentinel */
};
PyDoc_STRVAR(MultDict_doc,
"Dictionary with the support for duplicate keys.");
static PyTypeObject multidict_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"multidict._multidict.MultiDict", /* tp_name */
sizeof(MultiDictObject), /* tp_basicsize */
.tp_dealloc = (destructor)multidict_tp_dealloc,
.tp_repr = (reprfunc)multidict_repr,
.tp_as_sequence = &multidict_sequence,
.tp_as_mapping = &multidict_mapping,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_doc = MultDict_doc,
.tp_traverse = (traverseproc)multidict_tp_traverse,
.tp_clear = (inquiry)multidict_tp_clear,
.tp_richcompare = (richcmpfunc)multidict_tp_richcompare,
.tp_weaklistoffset = offsetof(MultiDictObject, weaklist),
.tp_iter = (getiterfunc)multidict_tp_iter,
.tp_methods = multidict_methods,
.tp_init = (initproc)multidict_tp_init,
.tp_alloc = PyType_GenericAlloc,
.tp_new = PyType_GenericNew,
.tp_free = PyObject_GC_Del,
};
/******************** CIMultiDict ********************/
static inline int
cimultidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
if (ci_pair_list_init(&self->pairs) < 0) {
return -1;
}
if (_multidict_extend(self, args, kwds, "CIMultiDict", 1) < 0) {
return -1;
}
return 0;
}
static inline PyObject *
cimultidict_copy(MultiDictObject *self)
{
return _multidict_copy(self, &cimultidict_type);
}
PyDoc_STRVAR(cimultidict_copy_doc,
"Return a copy of itself.");
static PyMethodDef cimultidict_methods[] = {
{
"copy",
(PyCFunction)cimultidict_copy,
METH_NOARGS,
cimultidict_copy_doc
},
{
NULL,
NULL
} /* sentinel */
};
PyDoc_STRVAR(CIMultDict_doc,
"Dictionary with the support for duplicate case-insensitive keys.");
static PyTypeObject cimultidict_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"multidict._multidict.CIMultiDict", /* tp_name */
sizeof(MultiDictObject), /* tp_basicsize */
.tp_dealloc = (destructor)multidict_tp_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_doc = CIMultDict_doc,
.tp_traverse = (traverseproc)multidict_tp_traverse,
.tp_clear = (inquiry)multidict_tp_clear,
.tp_weaklistoffset = offsetof(MultiDictObject, weaklist),
.tp_methods = cimultidict_methods,
.tp_base = &multidict_type,
.tp_init = (initproc)cimultidict_tp_init,
.tp_alloc = PyType_GenericAlloc,
.tp_new = PyType_GenericNew,
.tp_free = PyObject_GC_Del,
};
/******************** MultiDictProxy ********************/
static inline int
multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
PyObject *arg = NULL;
MultiDictObject *md = NULL;
if (!PyArg_UnpackTuple(args, "multidict._multidict.MultiDictProxy",
0, 1, &arg))
{
return -1;
}
if (arg == NULL) {
PyErr_Format(
PyExc_TypeError,
"__init__() missing 1 required positional argument: 'arg'"
);
return -1;
}
if (!MultiDictProxy_CheckExact(arg) &&
!CIMultiDict_CheckExact(arg) &&
!MultiDict_CheckExact(arg))
{
PyErr_Format(
PyExc_TypeError,
"ctor requires MultiDict or MultiDictProxy instance, "
"not <classs '%s'>",
Py_TYPE(arg)->tp_name
);
return -1;
}
md = (MultiDictObject*)arg;
if (MultiDictProxy_CheckExact(arg)) {
md = ((MultiDictProxyObject*)arg)->md;
}
Py_INCREF(md);
self->md = md;
return 0;
}
static inline PyObject *
multidict_proxy_getall(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
return multidict_getall(self->md, args, kwds);
}
static inline PyObject *
multidict_proxy_getone(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
return multidict_getone(self->md, args, kwds);
}
static inline PyObject *
multidict_proxy_get(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
return multidict_get(self->md, args, kwds);
}
static inline PyObject *
multidict_proxy_keys(MultiDictProxyObject *self)
{
return multidict_keys(self->md);
}
static inline PyObject *
multidict_proxy_items(MultiDictProxyObject *self)
{
return multidict_items(self->md);
}
static inline PyObject *
multidict_proxy_values(MultiDictProxyObject *self)
{
return multidict_values(self->md);
}
static inline PyObject *
multidict_proxy_copy(MultiDictProxyObject *self)
{
return _multidict_proxy_copy(self, &multidict_type);
}
static inline PyObject *
multidict_proxy_reduce(MultiDictProxyObject *self)
{
PyErr_Format(
PyExc_TypeError,
"can't pickle %s objects", Py_TYPE(self)->tp_name
);
return NULL;
}
static inline Py_ssize_t
multidict_proxy_mp_len(MultiDictProxyObject *self)
{
return multidict_mp_len(self->md);
}
static inline PyObject *
multidict_proxy_mp_subscript(MultiDictProxyObject *self, PyObject *key)
{
return multidict_mp_subscript(self->md, key);
}
static inline int
multidict_proxy_sq_contains(MultiDictProxyObject *self, PyObject *key)
{
return multidict_sq_contains(self->md, key);
}
static inline PyObject *
multidict_proxy_tp_iter(MultiDictProxyObject *self)
{
return multidict_tp_iter(self->md);
}
static inline PyObject *
multidict_proxy_tp_richcompare(MultiDictProxyObject *self, PyObject *other,
int op)
{
return multidict_tp_richcompare((PyObject*)self->md, other, op);
}
static inline void
multidict_proxy_tp_dealloc(MultiDictProxyObject *self)
{
PyObject_GC_UnTrack(self);
if (self->weaklist != NULL) {
PyObject_ClearWeakRefs((PyObject *)self);
};
Py_XDECREF(self->md);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static inline int
multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit,
void *arg)
{
Py_VISIT(self->md);
return 0;
}
static inline int
multidict_proxy_tp_clear(MultiDictProxyObject *self)
{
Py_CLEAR(self->md);
return 0;
}
static PySequenceMethods multidict_proxy_sequence = {
.sq_contains = (objobjproc)multidict_proxy_sq_contains,
};
static PyMappingMethods multidict_proxy_mapping = {
.mp_length = (lenfunc)multidict_proxy_mp_len,
.mp_subscript = (binaryfunc)multidict_proxy_mp_subscript,
};
static PyMethodDef multidict_proxy_methods[] = {
{
"getall",
(PyCFunction)multidict_proxy_getall,
METH_VARARGS | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_proxy_getone,
METH_VARARGS | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_proxy_get,
METH_VARARGS | METH_KEYWORDS,
multidict_get_doc
},
{
"keys",
(PyCFunction)multidict_proxy_keys,
METH_NOARGS,
multidict_keys_doc
},
{
"items",
(PyCFunction)multidict_proxy_items,
METH_NOARGS,
multidict_items_doc
},
{
"values",
(PyCFunction)multidict_proxy_values,
METH_NOARGS,
multidict_values_doc
},
{
"copy",
(PyCFunction)multidict_proxy_copy,
METH_NOARGS,
multidict_copy_doc
},
{
"__reduce__",
(PyCFunction)multidict_proxy_reduce,
METH_NOARGS,
NULL
},
{
"__class_getitem__",
(PyCFunction)multidict_class_getitem,
METH_O | METH_CLASS,
NULL
},
{
NULL,
NULL
} /* sentinel */
};
PyDoc_STRVAR(MultDictProxy_doc,
"Read-only proxy for MultiDict instance.");
static PyTypeObject multidict_proxy_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"multidict._multidict.MultiDictProxy", /* tp_name */
sizeof(MultiDictProxyObject), /* tp_basicsize */
.tp_dealloc = (destructor)multidict_proxy_tp_dealloc,
.tp_repr = (reprfunc)multidict_repr,
.tp_as_sequence = &multidict_proxy_sequence,
.tp_as_mapping = &multidict_proxy_mapping,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_doc = MultDictProxy_doc,
.tp_traverse = (traverseproc)multidict_proxy_tp_traverse,
.tp_clear = (inquiry)multidict_proxy_tp_clear,
.tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare,
.tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist),
.tp_iter = (getiterfunc)multidict_proxy_tp_iter,
.tp_methods = multidict_proxy_methods,
.tp_init = (initproc)multidict_proxy_tp_init,
.tp_alloc = PyType_GenericAlloc,
.tp_new = PyType_GenericNew,
.tp_free = PyObject_GC_Del,
};
/******************** CIMultiDictProxy ********************/
static inline int
cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
PyObject *arg = NULL;
MultiDictObject *md = NULL;
if (!PyArg_UnpackTuple(args, "multidict._multidict.CIMultiDictProxy",
1, 1, &arg))
{
return -1;
}
if (arg == NULL) {
PyErr_Format(
PyExc_TypeError,
"__init__() missing 1 required positional argument: 'arg'"
);
return -1;
}
if (!CIMultiDictProxy_CheckExact(arg) && !CIMultiDict_CheckExact(arg)) {
PyErr_Format(
PyExc_TypeError,
"ctor requires CIMultiDict or CIMultiDictProxy instance, "
"not <class '%s'>",
Py_TYPE(arg)->tp_name
);
return -1;
}
md = (MultiDictObject*)arg;
if (CIMultiDictProxy_CheckExact(arg)) {
md = ((MultiDictProxyObject*)arg)->md;
}
Py_INCREF(md);
self->md = md;
return 0;
}
static inline PyObject *
cimultidict_proxy_copy(MultiDictProxyObject *self)
{
return _multidict_proxy_copy(self, &cimultidict_type);
}
PyDoc_STRVAR(CIMultDictProxy_doc,
"Read-only proxy for CIMultiDict instance.");
PyDoc_STRVAR(cimultidict_proxy_copy_doc,
"Return copy of itself");
static PyMethodDef cimultidict_proxy_methods[] = {
{
"copy",
(PyCFunction)cimultidict_proxy_copy,
METH_NOARGS,
cimultidict_proxy_copy_doc
},
{
NULL,
NULL
} /* sentinel */
};
static PyTypeObject cimultidict_proxy_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"multidict._multidict.CIMultiDictProxy", /* tp_name */
sizeof(MultiDictProxyObject), /* tp_basicsize */
.tp_dealloc = (destructor)multidict_proxy_tp_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_doc = CIMultDictProxy_doc,
.tp_traverse = (traverseproc)multidict_proxy_tp_traverse,
.tp_clear = (inquiry)multidict_proxy_tp_clear,
.tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare,
.tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist),
.tp_methods = cimultidict_proxy_methods,
.tp_base = &multidict_proxy_type,
.tp_init = (initproc)cimultidict_proxy_tp_init,
.tp_alloc = PyType_GenericAlloc,
.tp_new = PyType_GenericNew,
.tp_free = PyObject_GC_Del,
};
/******************** Other functions ********************/
static inline PyObject *
getversion(PyObject *self, PyObject *md)
{
pair_list_t *pairs = NULL;
if (MultiDict_CheckExact(md) || CIMultiDict_CheckExact(md)) {
pairs = &((MultiDictObject*)md)->pairs;
} else if (MultiDictProxy_CheckExact(md) || CIMultiDictProxy_CheckExact(md)) {
pairs = &((MultiDictProxyObject*)md)->md->pairs;
} else {
PyErr_Format(PyExc_TypeError, "unexpected type");
return NULL;
}
return PyLong_FromUnsignedLong(pair_list_version(pairs));
}
/******************** Module ********************/
static inline void
module_free(void *m)
{
Py_CLEAR(collections_abc_mapping);
Py_CLEAR(collections_abc_mut_mapping);
Py_CLEAR(collections_abc_mut_multi_mapping);
}
static PyMethodDef multidict_module_methods[] = {
{
"getversion",
(PyCFunction)getversion,
METH_O
},
{
NULL,
NULL
} /* sentinel */
};
static PyModuleDef multidict_module = {
PyModuleDef_HEAD_INIT, /* m_base */
"_multidict", /* m_name */
.m_size = -1,
.m_methods = multidict_module_methods,
.m_free = (freefunc)module_free,
};
PyMODINIT_FUNC
PyInit__multidict()
{
PyObject *module = NULL,
*reg_func_call_result = NULL;
#define WITH_MOD(NAME) \
Py_CLEAR(module); \
module = PyImport_ImportModule(NAME); \
if (module == NULL) { \
goto fail; \
}
#define GET_MOD_ATTR(VAR, NAME) \
VAR = PyObject_GetAttrString(module, NAME); \
if (VAR == NULL) { \
goto fail; \
}
if (multidict_views_init() < 0) {
goto fail;
}
if (multidict_iter_init() < 0) {
goto fail;
}
if (istr_init() < 0) {
goto fail;
}
if (PyType_Ready(&multidict_type) < 0 ||
PyType_Ready(&cimultidict_type) < 0 ||
PyType_Ready(&multidict_proxy_type) < 0 ||
PyType_Ready(&cimultidict_proxy_type) < 0)
{
goto fail;
}
WITH_MOD("collections.abc");
GET_MOD_ATTR(collections_abc_mapping, "Mapping");
WITH_MOD("multidict._abc");
GET_MOD_ATTR(collections_abc_mut_mapping, "MultiMapping");
WITH_MOD("multidict._abc");
GET_MOD_ATTR(collections_abc_mut_multi_mapping, "MutableMultiMapping");
WITH_MOD("multidict._multidict_base");
GET_MOD_ATTR(repr_func, "_mdrepr");
/* Register in _abc mappings (CI)MultiDict and (CI)MultiDictProxy */
reg_func_call_result = PyObject_CallMethod(
collections_abc_mut_mapping,
"register", "O",
(PyObject*)&multidict_proxy_type
);
if (reg_func_call_result == NULL) {
goto fail;
}
Py_DECREF(reg_func_call_result);
reg_func_call_result = PyObject_CallMethod(
collections_abc_mut_mapping,
"register", "O",
(PyObject*)&cimultidict_proxy_type
);
if (reg_func_call_result == NULL) {
goto fail;
}
Py_DECREF(reg_func_call_result);
reg_func_call_result = PyObject_CallMethod(
collections_abc_mut_multi_mapping,
"register", "O",
(PyObject*)&multidict_type
);
if (reg_func_call_result == NULL) {
goto fail;
}
Py_DECREF(reg_func_call_result);
reg_func_call_result = PyObject_CallMethod(
collections_abc_mut_multi_mapping,
"register", "O",
(PyObject*)&cimultidict_type
);
if (reg_func_call_result == NULL) {
goto fail;
}
Py_DECREF(reg_func_call_result);
/* Instantiate this module */
module = PyModule_Create(&multidict_module);
Py_INCREF(&istr_type);
if (PyModule_AddObject(
module, "istr", (PyObject*)&istr_type) < 0)
{
goto fail;
}
Py_INCREF(&multidict_type);
if (PyModule_AddObject(
module, "MultiDict", (PyObject*)&multidict_type) < 0)
{
goto fail;
}
Py_INCREF(&cimultidict_type);
if (PyModule_AddObject(
module, "CIMultiDict", (PyObject*)&cimultidict_type) < 0)
{
goto fail;
}
Py_INCREF(&multidict_proxy_type);
if (PyModule_AddObject(
module, "MultiDictProxy", (PyObject*)&multidict_proxy_type) < 0)
{
goto fail;
}
Py_INCREF(&cimultidict_proxy_type);
if (PyModule_AddObject(
module, "CIMultiDictProxy", (PyObject*)&cimultidict_proxy_type) < 0)
{
goto fail;
}
return module;
fail:
Py_XDECREF(collections_abc_mapping);
Py_XDECREF(collections_abc_mut_mapping);
Py_XDECREF(collections_abc_mut_multi_mapping);
return NULL;
#undef WITH_MOD
#undef GET_MOD_ATTR
}