summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-07-09 10:22:03 +0300
committerrobot-piglet <[email protected]>2025-07-09 10:41:10 +0300
commitf91edcd669b2b4e97378bae7b57f6589e68a538f (patch)
treec76a2875faa0ec6ab7d4cfe245ba138114447041 /contrib/python
parentf979375c0346ff1acee7005d4c0d22d954d4dfa3 (diff)
Intermediate changes
commit_hash:d8fa10d7fba592f861e1470374c72cf22f0d5a2b
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/multidict/.dist-info/METADATA2
-rw-r--r--contrib/python/multidict/multidict/__init__.py2
-rw-r--r--contrib/python/multidict/multidict/_multidict.c1121
-rw-r--r--contrib/python/multidict/multidict/_multidict_py.py659
-rw-r--r--contrib/python/multidict/multidict/_multilib/dict.h17
-rw-r--r--contrib/python/multidict/multidict/_multilib/hashtable.h1890
-rw-r--r--contrib/python/multidict/multidict/_multilib/htkeys.h414
-rw-r--r--contrib/python/multidict/multidict/_multilib/istr.h23
-rw-r--r--contrib/python/multidict/multidict/_multilib/iter.h47
-rw-r--r--contrib/python/multidict/multidict/_multilib/pair_list.h1633
-rw-r--r--contrib/python/multidict/multidict/_multilib/parser.h48
-rw-r--r--contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h747
-rw-r--r--contrib/python/multidict/multidict/_multilib/state.h17
-rw-r--r--contrib/python/multidict/multidict/_multilib/views.h485
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.0 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.1 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.1)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.2 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.2)bin70 -> 70 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.3 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.3)bin70 -> 70 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.4 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.4)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c.pickle.5 (renamed from contrib/python/multidict/tests/cimultidict-c-extension.pickle.5)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.0 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.1 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.1)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.2 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.2)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.3 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.3)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.4 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.4)bin76 -> 76 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-py.pickle.5 (renamed from contrib/python/multidict/tests/cimultidict-pure-python.pickle.5)bin76 -> 76 bytes
-rw-r--r--contrib/python/multidict/tests/conftest.py6
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.0 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.1 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.1)bin47 -> 47 bytes
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.2 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.2)bin48 -> 48 bytes
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.3 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.3)bin48 -> 48 bytes
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.4 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.4)bin54 -> 54 bytes
-rw-r--r--contrib/python/multidict/tests/istr-c.pickle.5 (renamed from contrib/python/multidict/tests/istr-c-extension.pickle.5)bin54 -> 54 bytes
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.0 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.1 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.1)bin100 -> 100 bytes
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.2 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.2)bin51 -> 51 bytes
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.3 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.3)bin51 -> 51 bytes
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.4 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.4)bin57 -> 57 bytes
-rw-r--r--contrib/python/multidict/tests/istr-py.pickle.5 (renamed from contrib/python/multidict/tests/istr-pure-python.pickle.5)bin57 -> 57 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.0 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.1 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.1)bin69 -> 69 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.2 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.2)bin68 -> 68 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.3 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.3)bin68 -> 68 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.4 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.4)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c.pickle.5 (renamed from contrib/python/multidict/tests/multidict-c-extension.pickle.5)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.0 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.1 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.1)bin72 -> 72 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.2 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.2)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.3 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.3)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.4 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.4)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-py.pickle.5 (renamed from contrib/python/multidict/tests/multidict-pure-python.pickle.5)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/test_circular_imports.py12
-rw-r--r--contrib/python/multidict/tests/test_multidict.py24
-rw-r--r--contrib/python/multidict/tests/test_multidict_benchmarks.py12
-rw-r--r--contrib/python/multidict/tests/test_mutable_multidict.py91
-rw-r--r--contrib/python/multidict/tests/test_types.py3
-rw-r--r--contrib/python/multidict/tests/test_update.py29
-rw-r--r--contrib/python/multidict/ya.make2
58 files changed, 4213 insertions, 3071 deletions
diff --git a/contrib/python/multidict/.dist-info/METADATA b/contrib/python/multidict/.dist-info/METADATA
index a6ee0d00f6a..4c018b118d2 100644
--- a/contrib/python/multidict/.dist-info/METADATA
+++ b/contrib/python/multidict/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: multidict
-Version: 6.4.4
+Version: 6.5.1
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
diff --git a/contrib/python/multidict/multidict/__init__.py b/contrib/python/multidict/multidict/__init__.py
index 28d72cb79c1..1d8a2ae54c5 100644
--- a/contrib/python/multidict/multidict/__init__.py
+++ b/contrib/python/multidict/multidict/__init__.py
@@ -22,7 +22,7 @@ __all__ = (
"getversion",
)
-__version__ = "6.4.4"
+__version__ = "6.5.1"
if TYPE_CHECKING or not USE_EXTENSIONS:
diff --git a/contrib/python/multidict/multidict/_multidict.c b/contrib/python/multidict/multidict/_multidict.c
index f31a7881000..cd958931153 100644
--- a/contrib/python/multidict/multidict/_multidict.c
+++ b/contrib/python/multidict/multidict/_multidict.c
@@ -1,42 +1,42 @@
-#include "Python.h"
-#include "structmember.h"
-
-#include "_multilib/pythoncapi_compat.h"
+#include <Python.h>
+#include <structmember.h>
#include "_multilib/dict.h"
+#include "_multilib/hashtable.h"
#include "_multilib/istr.h"
#include "_multilib/iter.h"
-#include "_multilib/pair_list.h"
#include "_multilib/parser.h"
+#include "_multilib/pythoncapi_compat.h"
#include "_multilib/state.h"
#include "_multilib/views.h"
-
#define MultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictType)
-#define MultiDict_Check(state, obj) \
- (MultiDict_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->MultiDictType))
-#define CIMultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->CIMultiDictType)
-#define CIMultiDict_Check(state, obj) \
- (CIMultiDict_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->CIMultiDictType))
-#define AnyMultiDict_Check(state, obj) \
- (MultiDict_CheckExact(state, obj) \
- || CIMultiDict_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->MultiDictType))
-#define MultiDictProxy_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictProxyType)
-#define MultiDictProxy_Check(state, obj) \
- (MultiDictProxy_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->MultiDictProxyType))
+#define MultiDict_Check(state, obj) \
+ (MultiDict_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->MultiDictType))
+#define CIMultiDict_CheckExact(state, obj) \
+ Py_IS_TYPE(obj, state->CIMultiDictType)
+#define CIMultiDict_Check(state, obj) \
+ (CIMultiDict_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->CIMultiDictType))
+#define AnyMultiDict_Check(state, obj) \
+ (MultiDict_CheckExact(state, obj) || \
+ CIMultiDict_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->MultiDictType))
+#define MultiDictProxy_CheckExact(state, obj) \
+ Py_IS_TYPE(obj, state->MultiDictProxyType)
+#define MultiDictProxy_Check(state, obj) \
+ (MultiDictProxy_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->MultiDictProxyType))
#define CIMultiDictProxy_CheckExact(state, obj) \
Py_IS_TYPE(obj, state->CIMultiDictProxyType)
-#define CIMultiDictProxy_Check(state, obj) \
- (CIMultiDictProxy_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->CIMultiDictProxyType))
-#define AnyMultiDictProxy_Check(state, obj) \
- (MultiDictProxy_CheckExact(state, obj) \
- || CIMultiDictProxy_CheckExact(state, obj) \
- || PyObject_TypeCheck(obj, state->MultiDictProxyType))
+#define CIMultiDictProxy_Check(state, obj) \
+ (CIMultiDictProxy_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->CIMultiDictProxyType))
+#define AnyMultiDictProxy_Check(state, obj) \
+ (MultiDictProxy_CheckExact(state, obj) || \
+ CIMultiDictProxy_CheckExact(state, obj) || \
+ PyObject_TypeCheck(obj, state->MultiDictProxyType))
/******************** Internal Methods ********************/
@@ -45,10 +45,12 @@ _multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default)
{
PyObject *val = NULL;
- if (pair_list_get_one(&self->pairs, key, &val) <0) {
+ if (md_get_one(self, key, &val) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
+
if (val == NULL) {
if (_default != NULL) {
Py_INCREF(_default);
@@ -62,22 +64,12 @@ _multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default)
}
}
-
static inline int
-_multidict_extend(MultiDictObject *self, PyObject *arg,
- PyObject *kwds, const char *name, int do_add)
+_multidict_extend(MultiDictObject *self, PyObject *arg, PyObject *kwds,
+ const char *name, bool update)
{
- mod_state *state = self->pairs.state;
- PyObject *used = NULL;
- PyObject *seq = NULL;
- pair_list_t *list;
-
- if (!do_add) {
- used = PyDict_New();
- if (used == NULL) {
- goto fail;
- }
- }
+ mod_state *state = self->state;
+ PyObject *seq = NULL;
if (kwds && !PyArg_ValidateKeywordArguments(kwds)) {
goto fail;
@@ -85,17 +77,25 @@ _multidict_extend(MultiDictObject *self, PyObject *arg,
if (arg != NULL) {
if (AnyMultiDict_Check(state, arg)) {
- list = &((MultiDictObject*)arg)->pairs;
- if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) {
+ MultiDictObject *other = (MultiDictObject *)arg;
+ if (md_update_from_ht(self, other, update) < 0) {
goto fail;
}
} else if (AnyMultiDictProxy_Check(state, arg)) {
- list = &((MultiDictProxyObject*)arg)->md->pairs;
- if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) {
+ MultiDictObject *other = ((MultiDictProxyObject *)arg)->md;
+ if (md_update_from_ht(self, other, update) < 0) {
goto fail;
}
} else if (PyDict_CheckExact(arg)) {
- if (pair_list_update_from_dict(&self->pairs, used, arg) < 0) {
+ if (md_update_from_dict(self, arg, update) < 0) {
+ goto fail;
+ }
+ } else if (PyList_CheckExact(arg)) {
+ if (md_update_from_seq(self, arg, update) < 0) {
+ goto fail;
+ }
+ } else if (PyTuple_CheckExact(arg)) {
+ if (md_update_from_seq(self, arg, update) < 0) {
goto fail;
}
} else {
@@ -105,67 +105,84 @@ _multidict_extend(MultiDictObject *self, PyObject *arg,
seq = Py_NewRef(arg);
}
- if (pair_list_update_from_seq(&self->pairs, used, seq) < 0) {
+ if (md_update_from_seq(self, seq, update) < 0) {
goto fail;
}
}
}
if (kwds != NULL) {
- if (pair_list_update_from_dict(&self->pairs, used, kwds) < 0) {
+ if (md_update_from_dict(self, kwds, update) < 0) {
goto fail;
}
}
- if (!do_add) {
- if (pair_list_post_update(&self->pairs, used) < 0) {
+ if (update) {
+ if (md_post_update(self) < 0) {
goto fail;
}
}
+
+ ASSERT_CONSISTENT(self, false);
Py_CLEAR(seq);
- Py_CLEAR(used);
return 0;
fail:
Py_CLEAR(seq);
- Py_CLEAR(used);
return -1;
}
-
static inline Py_ssize_t
-_multidict_extend_parse_args(PyObject *args, PyObject *kwds,
+_multidict_extend_parse_args(mod_state *state, PyObject *args, PyObject *kwds,
const char *name, PyObject **parg)
{
Py_ssize_t size = 0;
Py_ssize_t s;
if (args) {
- size = PyTuple_GET_SIZE(args);
- if (size > 1) {
+ s = PyTuple_GET_SIZE(args);
+ if (s > 1) {
PyErr_Format(
- PyExc_TypeError,
- "%s takes from 1 to 2 positional arguments but %zd were given",
- name, size + 1, NULL
- );
+ PyExc_TypeError,
+ "%s takes from 1 to 2 positional arguments but %zd were given",
+ name,
+ s + 1,
+ NULL);
*parg = NULL;
return -1;
}
}
- if (size == 1) {
+ if (s == 1) {
*parg = Py_NewRef(PyTuple_GET_ITEM(args, 0));
- s = PyObject_Length(*parg);
- if (s < 0) {
- // e.g. cannot calc size of generator object
- PyErr_Clear();
+ if (PyTuple_CheckExact(*parg)) {
+ size += PyTuple_GET_SIZE(*parg);
+ } else if (PyList_CheckExact(*parg)) {
+ size += PyList_GET_SIZE(*parg);
+ } else if (PyDict_CheckExact(*parg)) {
+ size += PyDict_GET_SIZE(*parg);
+ } else if (MultiDict_CheckExact(state, *parg) ||
+ CIMultiDict_CheckExact(state, *parg)) {
+ MultiDictObject *md = (MultiDictObject *)*parg;
+ size += md_len(md);
+ } else if (MultiDictProxy_CheckExact(state, *parg) ||
+ CIMultiDictProxy_CheckExact(state, *parg)) {
+ MultiDictObject *md = ((MultiDictProxyObject *)*parg)->md;
+ size += md_len(md);
} else {
- size += s;
+ s = PyObject_LengthHint(*parg, 0);
+ if (s < 0) {
+ // e.g. cannot calc size of generator object
+ PyErr_Clear();
+ } else {
+ size += s;
+ }
}
} else {
*parg = NULL;
}
if (kwds != NULL) {
- s = PyDict_Size(kwds);
+ assert((PyDict_CheckExact(kwds)));
+ s = PyDict_GET_SIZE(kwds);
if (s < 0) {
return -1;
}
@@ -175,71 +192,81 @@ _multidict_extend_parse_args(PyObject *args, PyObject *kwds,
return size;
}
-static inline PyObject *
-multidict_copy(MultiDictObject *self)
+static inline int
+_multidict_clone_fast(mod_state *state, MultiDictObject *self, bool is_ci,
+ PyObject *arg, PyObject *kwds)
{
- MultiDictObject *new_multidict = NULL;
-
- new_multidict = (MultiDictObject*)PyType_GenericNew(
- Py_TYPE(self), NULL, NULL);
- if (new_multidict == NULL) {
- goto fail;
+ int ret = 0;
+ if (arg != NULL && kwds == NULL) {
+ MultiDictObject *other = NULL;
+ if (AnyMultiDict_Check(state, arg)) {
+ other = (MultiDictObject *)arg;
+ } else if (AnyMultiDictProxy_Check(state, arg)) {
+ other = ((MultiDictProxyObject *)arg)->md;
+ }
+ if (other != NULL && other->is_ci == is_ci) {
+ if (md_clone_from_ht(self, other) < 0) {
+ ret = -1;
+ goto done;
+ }
+ ret = 1;
+ goto done;
+ }
}
+done:
+ return ret;
+}
- if (Py_TYPE(self)->tp_init((PyObject*)new_multidict, NULL, NULL) < 0) {
+static inline PyObject *
+multidict_copy(MultiDictObject *self)
+{
+ PyObject *ret = PyType_GenericNew(Py_TYPE(self), NULL, NULL);
+ if (ret == NULL) {
goto fail;
}
- if (pair_list_update_from_pair_list(&new_multidict->pairs,
- NULL, &self->pairs) < 0) {
+ MultiDictObject *new_md = (MultiDictObject *)ret;
+ if (md_clone_from_ht(new_md, self) < 0) {
goto fail;
}
- return (PyObject*)new_multidict;
+ ASSERT_CONSISTENT(new_md, false);
+ return ret;
fail:
- Py_CLEAR(new_multidict);
+ Py_XDECREF(ret);
return NULL;
}
static inline PyObject *
_multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type)
{
- MultiDictObject *new_multidict = NULL;
- new_multidict = (MultiDictObject*)PyType_GenericNew(type, NULL, NULL);
- if (new_multidict == NULL) {
- goto fail;
- }
- if (type->tp_init((PyObject*)new_multidict, NULL, NULL) < 0) {
- goto fail;
- }
- if (pair_list_update_from_pair_list(&new_multidict->pairs,
- NULL, &self->md->pairs) < 0) {
- goto fail;
- }
- return (PyObject*)new_multidict;
-fail:
- Py_CLEAR(new_multidict);
- return NULL;
+ return multidict_copy(self->md);
}
-
/******************** Base Methods ********************/
static inline PyObject *
multidict_getall(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *list = NULL,
- *key = NULL,
- *_default = NULL;
-
- if (parse2("getall", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *list = NULL, *key = NULL, *_default = NULL;
+
+ if (parse2("getall",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
- if (pair_list_get_all(&self->pairs, key, &list) <0) {
+ if (md_get_all(self, key, &list) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
+
if (list == NULL) {
if (_default != NULL) {
Py_INCREF(_default);
@@ -257,61 +284,78 @@ static inline PyObject *
multidict_getone(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL;
-
- if (parse2("getone", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL, *_default = NULL;
+
+ if (parse2("getone",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
return _multidict_getone(self, key, _default);
}
static inline PyObject *
-multidict_get(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_get(MultiDictObject *self, PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL,
- *ret;
-
- if (parse2("get", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL;
+ PyObject *_default = NULL;
+ bool decref_default = false;
+
+ if (parse2("get",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
if (_default == NULL) {
- // fixme, _default is potentially dangerous borrowed ref here
- _default = Py_None;
+ _default = Py_GetConstant(Py_CONSTANT_NONE);
+ if (_default == NULL) {
+ return NULL;
+ }
+ decref_default = true;
+ }
+ ASSERT_CONSISTENT(self, false);
+ PyObject *ret = _multidict_getone(self, key, _default);
+ if (decref_default) {
+ Py_CLEAR(_default);
}
- ret = _multidict_getone(self, key, _default);
return ret;
}
-static inline PyObject *
+static PyObject *
multidict_keys(MultiDictObject *self)
{
return multidict_keysview_new(self);
}
-static inline PyObject *
+static PyObject *
multidict_items(MultiDictObject *self)
{
return multidict_itemsview_new(self);
}
-static inline PyObject *
+static PyObject *
multidict_values(MultiDictObject *self)
{
return multidict_valuesview_new(self);
}
-static inline PyObject *
+static PyObject *
multidict_reduce(MultiDictObject *self)
{
- PyObject *items = NULL,
- *items_list = NULL,
- *args = NULL,
- *result = NULL;
+ PyObject *items = NULL, *items_list = NULL, *args = NULL, *result = NULL;
items = multidict_itemsview_new(self);
if (items == NULL) {
@@ -337,7 +381,7 @@ ret:
return result;
}
-static inline PyObject *
+static PyObject *
multidict_repr(MultiDictObject *self)
{
int tmp = Py_ReprEnter((PyObject *)self);
@@ -347,53 +391,54 @@ multidict_repr(MultiDictObject *self)
if (tmp > 0) {
return PyUnicode_FromString("...");
}
- PyObject *name = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
+ PyObject *name =
+ PyObject_GetAttr((PyObject *)Py_TYPE(self), self->state->str_name);
if (name == NULL) {
Py_ReprLeave((PyObject *)self);
return NULL;
}
- PyObject *ret = pair_list_repr(&self->pairs, name, true, true);
+ PyObject *ret = md_repr(self, name, true, true);
Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
}
-static inline Py_ssize_t
+static Py_ssize_t
multidict_mp_len(MultiDictObject *self)
{
- return pair_list_len(&self->pairs);
+ return md_len(self);
}
-static inline PyObject *
+static PyObject *
multidict_mp_subscript(MultiDictObject *self, PyObject *key)
{
return _multidict_getone(self, key, NULL);
}
-static inline int
+static int
multidict_mp_as_subscript(MultiDictObject *self, PyObject *key, PyObject *val)
{
if (val == NULL) {
- return pair_list_del(&self->pairs, key);
+ return md_del(self, key);
} else {
- return pair_list_replace(&self->pairs, key, val);
+ return md_replace(self, key, val);
}
}
-static inline int
+static int
multidict_sq_contains(MultiDictObject *self, PyObject *key)
{
- return pair_list_contains(&self->pairs, key, NULL);
+ return md_contains(self, key, NULL);
}
-static inline PyObject *
+static PyObject *
multidict_tp_iter(MultiDictObject *self)
{
return multidict_keys_iter_new(self);
}
-static inline PyObject *
-multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
+static PyObject *
+multidict_tp_richcompare(MultiDictObject *self, PyObject *other, int op)
{
int cmp;
@@ -401,7 +446,7 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
Py_RETURN_NOTIMPLEMENTED;
}
- if (self == other) {
+ if ((PyObject *)self == other) {
cmp = 1;
if (op == Py_NE) {
cmp = !cmp;
@@ -409,17 +454,11 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
return PyBool_FromLong(cmp);
}
- mod_state *state = ((MultiDictObject*)self)->pairs.state;
+ mod_state *state = self->state;
if (AnyMultiDict_Check(state, other)) {
- cmp = pair_list_eq(
- &((MultiDictObject*)self)->pairs,
- &((MultiDictObject*)other)->pairs
- );
+ cmp = md_eq(self, (MultiDictObject *)other);
} else if (AnyMultiDictProxy_Check(state, other)) {
- cmp = pair_list_eq(
- &((MultiDictObject*)self)->pairs,
- &((MultiDictProxyObject*)other)->md->pairs
- );
+ cmp = md_eq(self, ((MultiDictProxyObject *)other)->md);
} else {
bool fits = false;
fits = PyDict_Check(other);
@@ -434,10 +473,9 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
Py_CLEAR(keys);
}
if (fits) {
- cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs,
- other);
+ cmp = md_eq_to_mapping(self, other);
} else {
- cmp = 0; // e.g., multidict is not equal to a list
+ cmp = 0; // e.g., multidict is not equal to a list
}
}
if (cmp < 0) {
@@ -449,153 +487,192 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
return PyBool_FromLong(cmp);
}
-static inline void
+static void
multidict_tp_dealloc(MultiDictObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_BEGIN(self, multidict_tp_dealloc)
- PyObject_ClearWeakRefs((PyObject *)self);
- pair_list_dealloc(&self->pairs);
+ PyObject_ClearWeakRefs((PyObject *)self);
+ md_clear(self);
Py_TYPE(self)->tp_free((PyObject *)self);
- Py_TRASHCAN_END // there should be no code after this
+ Py_TRASHCAN_END // there should be no code after this
}
-static inline int
+static int
multidict_tp_traverse(MultiDictObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
- return pair_list_traverse(&self->pairs, visit, arg);
+ return md_traverse(self, visit, arg);
}
-static inline int
+static int
multidict_tp_clear(MultiDictObject *self)
{
- return pair_list_clear(&self->pairs);
+ return md_clear(self);
}
PyDoc_STRVAR(multidict_getall_doc,
-"Return a list of all values matching the key.");
+ "Return a list of all values matching the key.");
-PyDoc_STRVAR(multidict_getone_doc,
-"Get first value 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_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.");
+ "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_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.");
+ "Return a new view of the dictionary's values.");
/******************** MultiDict ********************/
-static inline int
+static int
multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
- Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "MultiDict", &arg);
+ Py_ssize_t size =
+ _multidict_extend_parse_args(state, args, kwds, "MultiDict", &arg);
if (size < 0) {
goto fail;
}
- if (pair_list_init(&self->pairs, state, size) < 0) {
+ int tmp = _multidict_clone_fast(state, self, false, args, kwds);
+ if (tmp < 0) {
goto fail;
+ } else if (tmp == 1) {
+ goto done;
}
- if (_multidict_extend(self, arg, kwds, "MultiDict", 1) < 0) {
+ if (md_init(self, state, false, size) < 0) {
goto fail;
}
+ if (_multidict_extend(self, arg, kwds, "MultiDict", false) < 0) {
+ goto fail;
+ }
+done:
Py_CLEAR(arg);
+ ASSERT_CONSISTENT(self, false);
return 0;
fail:
Py_CLEAR(arg);
return -1;
}
-static inline PyObject *
-multidict_add(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+static PyObject *
+multidict_add(MultiDictObject *self, PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames)
{
- PyObject *key = NULL,
- *val = NULL;
+ PyObject *key = NULL, *val = NULL;
- if (parse2("add", args, nargs, kwnames, 2,
- "key", &key, "value", &val) < 0) {
+ if (parse2("add", args, nargs, kwnames, 2, "key", &key, "value", &val) <
+ 0) {
return NULL;
}
- if (pair_list_add(&self->pairs, key, val) < 0) {
+ if (md_add(self, key, val) < 0) {
return NULL;
}
-
+ ASSERT_CONSISTENT(self, false);
Py_RETURN_NONE;
}
-static inline PyObject *
+static PyObject *
multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
- Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "extend", &arg);
+ Py_ssize_t size =
+ _multidict_extend_parse_args(self->state, args, kwds, "extend", &arg);
if (size < 0) {
goto fail;
}
- pair_list_grow(&self->pairs, size);
- if (_multidict_extend(self, arg, kwds, "extend", 1) < 0) {
+ if (md_reserve(self, size) < 0) {
+ goto fail;
+ }
+ if (_multidict_extend(self, arg, kwds, "extend", false) < 0) {
goto fail;
}
Py_CLEAR(arg);
+ ASSERT_CONSISTENT(self, false);
Py_RETURN_NONE;
fail:
Py_CLEAR(arg);
return NULL;
}
-static inline PyObject *
+static PyObject *
multidict_clear(MultiDictObject *self)
{
- if (pair_list_clear(&self->pairs) < 0) {
+ if (md_clear(self) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
Py_RETURN_NONE;
}
-static inline PyObject *
+static PyObject *
multidict_setdefault(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL;
-
- if (parse2("setdefault", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL;
+ PyObject *_default = NULL;
+ bool decref_default = false;
+ PyObject *ret = NULL;
+
+ if (parse2("setdefault",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
if (_default == NULL) {
- // fixme, _default is potentially dangerous borrowed ref here
- _default = Py_None;
+ _default = Py_GetConstant(Py_CONSTANT_NONE);
+ if (_default == NULL) {
+ return NULL;
+ }
+ decref_default = true;
+ }
+ ASSERT_CONSISTENT(self, false);
+ if (md_set_default(self, key, _default, &ret) < 0) {
+ return NULL;
+ }
+ if (decref_default) {
+ Py_CLEAR(_default);
}
- return pair_list_set_default(&self->pairs, key, _default);
+ return ret;
}
-static inline PyObject *
+static PyObject *
multidict_popone(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL,
- *ret_val = NULL;
-
- if (parse2("popone", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL, *_default = NULL, *ret_val = NULL;
+
+ if (parse2("popone",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
- if (pair_list_pop_one(&self->pairs, key, &ret_val) < 0) {
+ if (md_pop_one(self, key, &ret_val) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
if (ret_val == NULL) {
if (_default != NULL) {
Py_INCREF(_default);
@@ -609,26 +686,28 @@ multidict_popone(MultiDictObject *self, PyObject *const *args,
}
}
-static inline PyObject *
-multidict_pop(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+static PyObject *
+multidict_pop(MultiDictObject *self, PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL,
- *ret_val = NULL;
-
- if (parse2("pop", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL, *_default = NULL, *ret_val = NULL;
+
+ if (parse2("pop",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
- if (pair_list_pop_one(&self->pairs, key, &ret_val) < 0) {
+ if (md_pop_one(self, key, &ret_val) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
if (ret_val == NULL) {
if (_default != NULL) {
Py_INCREF(_default);
@@ -642,22 +721,28 @@ multidict_pop(
}
}
-static inline PyObject *
+static PyObject *
multidict_popall(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *key = NULL,
- *_default = NULL,
- *ret_val = NULL;
-
- if (parse2("popall", args, nargs, kwnames, 1,
- "key", &key, "default", &_default) < 0) {
+ PyObject *key = NULL, *_default = NULL, *ret_val = NULL;
+
+ if (parse2("popall",
+ args,
+ nargs,
+ kwnames,
+ 1,
+ "key",
+ &key,
+ "default",
+ &_default) < 0) {
return NULL;
}
- if (pair_list_pop_all(&self->pairs, key, &ret_val) < 0) {
+ if (md_pop_all(self, key, &ret_val) < 0) {
return NULL;
}
+ ASSERT_CONSISTENT(self, false);
if (ret_val == NULL) {
if (_default != NULL) {
Py_INCREF(_default);
@@ -671,23 +756,29 @@ multidict_popall(MultiDictObject *self, PyObject *const *args,
}
}
-static inline PyObject *
+static PyObject *
multidict_popitem(MultiDictObject *self)
{
- return pair_list_pop_item(&self->pairs);
+ return md_pop_item(self);
}
-static inline PyObject *
+static PyObject *
multidict_update(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
- if (_multidict_extend_parse_args(args, kwds, "update", &arg) < 0) {
+ Py_ssize_t size =
+ _multidict_extend_parse_args(self->state, args, kwds, "update", &arg);
+ if (size < 0) {
goto fail;
}
- if (_multidict_extend(self, arg, kwds, "update", 0) < 0) {
+ if (md_reserve(self, size) < 0) {
+ goto fail;
+ }
+ if (_multidict_extend(self, arg, kwds, "update", true) < 0) {
goto fail;
}
Py_CLEAR(arg);
+ ASSERT_CONSISTENT(self, false);
Py_RETURN_NONE;
fail:
Py_CLEAR(arg);
@@ -695,186 +786,135 @@ fail:
}
PyDoc_STRVAR(multidict_add_doc,
-"Add the key and value, not overwriting any previous value.");
+ "Add the key and value, not overwriting any previous value.");
-PyDoc_STRVAR(multidict_copy_doc,
-"Return a copy of itself.");
+PyDoc_STRVAR(multidict_copy_doc, "Return a copy of itself.");
PyDoc_STRVAR(multdicit_method_extend_doc,
-"Extend current MultiDict with more values.\n\
+ "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_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_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\
+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_pop_doc,
-"Remove the last occurrence of key and return the corresponding value.\n\n\
+PyDoc_STRVAR(
+ multidict_pop_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\
+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.");
+ "Remove and return an arbitrary (key, value) pair.");
PyDoc_STRVAR(multidict_update_doc,
-"Update the dictionary from *other*, overwriting existing keys.");
+ "Update the dictionary from *other*, overwriting existing keys.");
-PyDoc_STRVAR(sizeof__doc__,
-"D.__sizeof__() -> size of D in memory, in bytes");
+PyDoc_STRVAR(sizeof__doc__, "D.__sizeof__() -> size of D in memory, in bytes");
-static inline PyObject *
-_multidict_sizeof(MultiDictObject *self)
+static 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;
- }
+ if (self->keys != &empty_htkeys) size += htkeys_sizeof(self->keys);
return PyLong_FromSsize_t(size);
}
-
static PyMethodDef multidict_methods[] = {
- {
- "getall",
- (PyCFunction)multidict_getall,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_getall_doc
- },
- {
- "getone",
- (PyCFunction)multidict_getone,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_getone_doc
- },
- {
- "get",
- (PyCFunction)multidict_get,
- METH_FASTCALL | 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_FASTCALL | 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_FASTCALL | METH_KEYWORDS,
- multidict_setdefault_doc
- },
- {
- "popone",
- (PyCFunction)multidict_popone,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_popone_doc
- },
- {
- "pop",
- (PyCFunction)multidict_pop,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_pop_doc
- },
- {
- "popall",
- (PyCFunction)multidict_popall,
- METH_FASTCALL | 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
- },
+ {"getall",
+ (PyCFunction)multidict_getall,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_getall_doc},
+ {"getone",
+ (PyCFunction)multidict_getone,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_getone_doc},
+ {"get",
+ (PyCFunction)multidict_get,
+ METH_FASTCALL | 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_FASTCALL | 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_FASTCALL | METH_KEYWORDS,
+ multidict_setdefault_doc},
+ {"popone",
+ (PyCFunction)multidict_popone,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_popone_doc},
+ {"pop",
+ (PyCFunction)multidict_pop,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_pop_doc},
+ {"popall",
+ (PyCFunction)multidict_popall,
+ METH_FASTCALL | 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)Py_GenericAlias,
- METH_O | METH_CLASS,
- NULL
- },
+ {"__class_getitem__",
+ (PyCFunction)Py_GenericAlias,
+ METH_O | METH_CLASS,
+ NULL},
{
"__sizeof__",
- (PyCFunction)_multidict_sizeof,
+ (PyCFunction)multidict_sizeof,
METH_NOARGS,
sizeof__doc__,
},
- {
- NULL,
- NULL
- } /* sentinel */
+ {NULL, NULL} /* sentinel */
};
-
-PyDoc_STRVAR(MultDict_doc,
-"Dictionary with the support for duplicate keys.");
+PyDoc_STRVAR(MultDict_doc, "Dictionary with the support for duplicate keys.");
#ifndef MANAGED_WEAKREFS
static PyMemberDef multidict_members[] = {
- {"__weaklistoffset__", Py_T_PYSSIZET,
- offsetof(MultiDictObject, weaklist), Py_READONLY},
- {NULL} /* Sentinel */
+ {"__weaklistoffset__",
+ Py_T_PYSSIZET,
+ offsetof(MultiDictObject, weaklist),
+ Py_READONLY},
+ {NULL} /* Sentinel */
};
#endif
@@ -907,7 +947,7 @@ static PyType_Slot multidict_slots[] = {
static PyType_Spec multidict_spec = {
.name = "multidict._multidict.MultiDict",
.basicsize = sizeof(MultiDictObject),
- .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
#if PY_VERSION_HEX >= 0x030a00f0
| Py_TPFLAGS_IMMUTABLETYPE
#endif
@@ -918,36 +958,42 @@ static PyType_Spec multidict_spec = {
.slots = multidict_slots,
};
-
/******************** CIMultiDict ********************/
-static inline int
+static int
cimultidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
- Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "CIMultiDict", &arg);
+ Py_ssize_t size =
+ _multidict_extend_parse_args(state, args, kwds, "CIMultiDict", &arg);
if (size < 0) {
goto fail;
}
-
- if (ci_pair_list_init(&self->pairs, state, size) < 0) {
+ int tmp = _multidict_clone_fast(state, self, true, args, kwds);
+ if (tmp < 0) {
goto fail;
+ } else if (tmp == 1) {
+ goto done;
}
-
- if (_multidict_extend(self, arg, kwds, "CIMultiDict", 1) < 0) {
+ if (md_init(self, state, true, size) < 0) {
+ goto fail;
+ }
+ if (_multidict_extend(self, arg, kwds, "CIMultiDict", false) < 0) {
goto fail;
}
+done:
Py_CLEAR(arg);
+ ASSERT_CONSISTENT(self, false);
return 0;
fail:
Py_CLEAR(arg);
return -1;
}
-
-PyDoc_STRVAR(CIMultDict_doc,
-"Dictionary with the support for duplicate case-insensitive keys.");
+PyDoc_STRVAR(
+ CIMultDict_doc,
+ "Dictionary with the support for duplicate case-insensitive keys.");
static PyType_Slot cimultidict_slots[] = {
{Py_tp_doc, (void *)CIMultDict_doc},
@@ -968,42 +1014,42 @@ static PyType_Spec cimultidict_spec = {
/******************** MultiDictProxy ********************/
-static inline int
+static int
multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
mod_state *state = get_mod_state_by_def((PyObject *)self);
- PyObject *arg = NULL;
- MultiDictObject *md = NULL;
+ PyObject *arg = NULL;
+ MultiDictObject *md = NULL;
- if (!PyArg_UnpackTuple(args, "multidict._multidict.MultiDictProxy",
- 0, 1, &arg))
- {
+ 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'"
- );
+ "__init__() missing 1 required positional argument: 'arg'");
+ return -1;
+ }
+ if (kwds != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "__init__() doesn't accept keyword arguments");
return -1;
}
if (!AnyMultiDictProxy_Check(state, arg) &&
- !AnyMultiDict_Check(state, arg))
- {
- PyErr_Format(
- PyExc_TypeError,
- "ctor requires MultiDict or MultiDictProxy instance, "
- "not <class '%s'>",
- Py_TYPE(arg)->tp_name
- );
+ !AnyMultiDict_Check(state, arg)) {
+ PyErr_Format(PyExc_TypeError,
+ "ctor requires MultiDict or MultiDictProxy instance, "
+ "not <class '%s'>",
+ Py_TYPE(arg)->tp_name);
return -1;
}
if (AnyMultiDictProxy_Check(state, arg)) {
- md = ((MultiDictProxyObject*)arg)->md;
+ md = ((MultiDictProxyObject *)arg)->md;
} else {
- md = (MultiDictObject*)arg;
+ md = (MultiDictObject *)arg;
}
Py_INCREF(md);
self->md = md;
@@ -1011,94 +1057,92 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
return 0;
}
-static inline PyObject *
+static PyObject *
multidict_proxy_getall(MultiDictProxyObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_getall(self->md, args, nargs, kwnames);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_getone(self->md, args, nargs, kwnames);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+ Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_get(self->md, args, nargs, kwnames);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_keys(MultiDictProxyObject *self)
{
- return multidict_keys(self->md);
+ return multidict_keysview_new(self->md);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_items(MultiDictProxyObject *self)
{
- return multidict_items(self->md);
+ return multidict_itemsview_new(self->md);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_values(MultiDictProxyObject *self)
{
- return multidict_values(self->md);
+ return multidict_valuesview_new(self->md);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_copy(MultiDictProxyObject *self)
{
- return _multidict_proxy_copy(self, self->md->pairs.state->MultiDictType);
+ return _multidict_proxy_copy(self, self->md->state->MultiDictType);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_reduce(MultiDictProxyObject *self)
{
PyErr_Format(
- PyExc_TypeError,
- "can't pickle %s objects", Py_TYPE(self)->tp_name
- );
+ PyExc_TypeError, "can't pickle %s objects", Py_TYPE(self)->tp_name);
return NULL;
}
-static inline Py_ssize_t
+static Py_ssize_t
multidict_proxy_mp_len(MultiDictProxyObject *self)
{
- return multidict_mp_len(self->md);
+ return md_len(self->md);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_mp_subscript(MultiDictProxyObject *self, PyObject *key)
{
- return multidict_mp_subscript(self->md, key);
+ return _multidict_getone(self->md, key, NULL);
}
-static inline int
+static int
multidict_proxy_sq_contains(MultiDictProxyObject *self, PyObject *key)
{
- return multidict_sq_contains(self->md, key);
+ return md_contains(self->md, key, NULL);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_tp_iter(MultiDictProxyObject *self)
{
- return multidict_tp_iter(self->md);
+ return multidict_keys_iter_new(self->md);
}
-static inline PyObject *
+static PyObject *
multidict_proxy_tp_richcompare(MultiDictProxyObject *self, PyObject *other,
int op)
{
- return multidict_tp_richcompare((PyObject*)self->md, other, op);
+ return multidict_tp_richcompare(self->md, other, op);
}
-static inline void
+static void
multidict_proxy_tp_dealloc(MultiDictProxyObject *self)
{
PyObject_GC_UnTrack(self);
@@ -1107,7 +1151,7 @@ multidict_proxy_tp_dealloc(MultiDictProxyObject *self)
Py_TYPE(self)->tp_free((PyObject *)self);
}
-static inline int
+static int
multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit,
void *arg)
{
@@ -1116,95 +1160,70 @@ multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit,
return 0;
}
-static inline int
+static int
multidict_proxy_tp_clear(MultiDictProxyObject *self)
{
Py_CLEAR(self->md);
return 0;
}
-static inline PyObject *
+static PyObject *
multidict_proxy_repr(MultiDictProxyObject *self)
{
- PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
- if (name == NULL)
- return NULL;
- PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true);
+ PyObject *name =
+ PyObject_GetAttr((PyObject *)Py_TYPE(self), self->md->state->str_name);
+ if (name == NULL) return NULL;
+ PyObject *ret = md_repr(self->md, name, true, true);
Py_CLEAR(name);
return ret;
}
-
static PyMethodDef multidict_proxy_methods[] = {
- {
- "getall",
- (PyCFunction)multidict_proxy_getall,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_getall_doc
- },
- {
- "getone",
- (PyCFunction)multidict_proxy_getone,
- METH_FASTCALL | METH_KEYWORDS,
- multidict_getone_doc
- },
- {
- "get",
- (PyCFunction)multidict_proxy_get,
- METH_FASTCALL | 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)Py_GenericAlias,
- METH_O | METH_CLASS,
- NULL
- },
- {
- NULL,
- NULL
- } /* sentinel */
+ {"getall",
+ (PyCFunction)multidict_proxy_getall,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_getall_doc},
+ {"getone",
+ (PyCFunction)multidict_proxy_getone,
+ METH_FASTCALL | METH_KEYWORDS,
+ multidict_getone_doc},
+ {"get",
+ (PyCFunction)multidict_proxy_get,
+ METH_FASTCALL | 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)Py_GenericAlias,
+ METH_O | METH_CLASS,
+ NULL},
+ {NULL, NULL} /* sentinel */
};
-
-PyDoc_STRVAR(MultDictProxy_doc,
-"Read-only proxy for MultiDict instance.");
+PyDoc_STRVAR(MultDictProxy_doc, "Read-only proxy for MultiDict instance.");
#ifndef MANAGED_WEAKREFS
static PyMemberDef multidict_proxy_members[] = {
- {"__weaklistoffset__", Py_T_PYSSIZET,
- offsetof(MultiDictProxyObject, weaklist), Py_READONLY},
- {NULL} /* Sentinel */
+ {"__weaklistoffset__",
+ Py_T_PYSSIZET,
+ offsetof(MultiDictProxyObject, weaklist),
+ Py_READONLY},
+ {NULL} /* Sentinel */
};
#endif
@@ -1236,7 +1255,7 @@ static PyType_Slot multidict_proxy_slots[] = {
static PyType_Spec multidict_proxy_spec = {
.name = "multidict._multidict.MultiDictProxy",
.basicsize = sizeof(MultiDictProxyObject),
- .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
#if PY_VERSION_HEX >= 0x030a00f0
| Py_TPFLAGS_IMMUTABLETYPE
#endif
@@ -1249,41 +1268,42 @@ static PyType_Spec multidict_proxy_spec = {
/******************** CIMultiDictProxy ********************/
-static inline int
+static int
cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
mod_state *state = get_mod_state_by_def((PyObject *)self);
- PyObject *arg = NULL;
- MultiDictObject *md = NULL;
+ PyObject *arg = NULL;
+ MultiDictObject *md = NULL;
- if (!PyArg_UnpackTuple(args, "multidict._multidict.CIMultiDictProxy",
- 1, 1, &arg))
- {
+ 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'"
- );
+ "__init__() missing 1 required positional argument: 'arg'");
return -1;
}
- if (!CIMultiDictProxy_Check(state, arg)
- && !CIMultiDict_Check(state, arg)) {
- PyErr_Format(
- PyExc_TypeError,
- "ctor requires CIMultiDict or CIMultiDictProxy instance, "
- "not <class '%s'>",
- Py_TYPE(arg)->tp_name
- );
+ if (kwds != NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "__init__() doesn't accept keyword arguments");
+ return -1;
+ }
+ if (!CIMultiDictProxy_Check(state, arg) &&
+ !CIMultiDict_Check(state, arg)) {
+ PyErr_Format(PyExc_TypeError,
+ "ctor requires CIMultiDict or CIMultiDictProxy instance, "
+ "not <class '%s'>",
+ Py_TYPE(arg)->tp_name);
return -1;
}
if (CIMultiDictProxy_Check(state, arg)) {
- md = ((MultiDictProxyObject*)arg)->md;
+ md = ((MultiDictProxyObject *)arg)->md;
} else {
- md = (MultiDictObject*)arg;
+ md = (MultiDictObject *)arg;
}
Py_INCREF(md);
self->md = md;
@@ -1291,30 +1311,22 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
return 0;
}
-static inline PyObject *
+static PyObject *
cimultidict_proxy_copy(MultiDictProxyObject *self)
{
- return _multidict_proxy_copy(self, self->md->pairs.state->CIMultiDictType);
+ return _multidict_proxy_copy(self, self->md->state->CIMultiDictType);
}
+PyDoc_STRVAR(CIMultDictProxy_doc, "Read-only proxy for CIMultiDict instance.");
-PyDoc_STRVAR(CIMultDictProxy_doc,
-"Read-only proxy for CIMultiDict instance.");
-
-PyDoc_STRVAR(cimultidict_proxy_copy_doc,
-"Return copy of itself");
+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 */
+ {"copy",
+ (PyCFunction)cimultidict_proxy_copy,
+ METH_NOARGS,
+ cimultidict_proxy_copy_doc},
+ {NULL, NULL} /* sentinel */
};
static PyType_Slot cimultidict_proxy_slots[] = {
@@ -1337,20 +1349,20 @@ static PyType_Spec cimultidict_proxy_spec = {
/******************** Other functions ********************/
-static inline PyObject *
-getversion(PyObject *self, PyObject *md)
+static PyObject *
+getversion(PyObject *self, PyObject *arg)
{
mod_state *state = get_mod_state(self);
- pair_list_t *pairs = NULL;
- if (AnyMultiDict_Check(state, md)) {
- pairs = &((MultiDictObject*)md)->pairs;
- } else if (AnyMultiDictProxy_Check(state, md)) {
- pairs = &((MultiDictProxyObject*)md)->md->pairs;
+ MultiDictObject *md;
+ if (AnyMultiDict_Check(state, arg)) {
+ md = (MultiDictObject *)arg;
+ } else if (AnyMultiDictProxy_Check(state, arg)) {
+ md = ((MultiDictProxyObject *)arg)->md;
} else {
PyErr_Format(PyExc_TypeError, "unexpected type");
return NULL;
}
- return PyLong_FromUnsignedLong(pair_list_version(pairs));
+ return PyLong_FromUnsignedLong(md_version(md));
}
/******************** Module ********************/
@@ -1375,8 +1387,9 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
Py_VISIT(state->ItemsIterType);
Py_VISIT(state->ValuesIterType);
- Py_VISIT(state->str_lower);
Py_VISIT(state->str_canonical);
+ Py_VISIT(state->str_lower);
+ Py_VISIT(state->str_name);
return 0;
}
@@ -1401,13 +1414,14 @@ module_clear(PyObject *mod)
Py_CLEAR(state->ItemsIterType);
Py_CLEAR(state->ValuesIterType);
- Py_CLEAR(state->str_lower);
Py_CLEAR(state->str_canonical);
+ Py_CLEAR(state->str_lower);
+ Py_CLEAR(state->str_name);
return 0;
}
-static inline void
+static void
module_free(void *mod)
{
(void)module_clear((PyObject *)mod);
@@ -1415,10 +1429,9 @@ module_free(void *mod)
static PyMethodDef module_methods[] = {
{"getversion", (PyCFunction)getversion, METH_O},
- {NULL, NULL} /* sentinel */
+ {NULL, NULL} /* sentinel */
};
-
static int
module_exec(PyObject *mod)
{
@@ -1434,6 +1447,10 @@ module_exec(PyObject *mod)
if (state->str_canonical == NULL) {
goto fail;
}
+ state->str_name = PyUnicode_InternFromString("__name__");
+ if (state->str_name == NULL) {
+ goto fail;
+ }
if (multidict_views_init(mod, state) < 0) {
goto fail;
@@ -1512,7 +1529,6 @@ fail:
return -1;
}
-
static struct PyModuleDef_Slot module_slots[] = {
{Py_mod_exec, module_exec},
#if PY_VERSION_HEX >= 0x030c00f0
@@ -1524,7 +1540,6 @@ static struct PyModuleDef_Slot module_slots[] = {
{0, NULL},
};
-
static PyModuleDef multidict_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_multidict",
diff --git a/contrib/python/multidict/multidict/_multidict_py.py b/contrib/python/multidict/multidict/_multidict_py.py
index 4a24ff41bd1..f9fa25671a0 100644
--- a/contrib/python/multidict/multidict/_multidict_py.py
+++ b/contrib/python/multidict/multidict/_multidict_py.py
@@ -1,9 +1,9 @@
import enum
+import functools
import reprlib
import sys
from array import array
from collections.abc import (
- Callable,
ItemsView,
Iterable,
Iterator,
@@ -11,9 +11,11 @@ from collections.abc import (
Mapping,
ValuesView,
)
+from dataclasses import dataclass
from typing import (
TYPE_CHECKING,
Any,
+ ClassVar,
Generic,
NoReturn,
Optional,
@@ -81,11 +83,12 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
return False
key, value = item
try:
- ident = self._md._identity(key)
+ identity = self._md._identity(key)
except TypeError:
return False
- for i, k, v in self._md._items:
- if ident == i and value == v:
+ hash_ = hash(identity)
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity and value == e.value:
return True
return False
@@ -93,28 +96,29 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
return _Iter(len(self), self._iter(self._md._version))
def _iter(self, version: int) -> Iterator[tuple[str, _V]]:
- for i, k, v in self._md._items:
+ for e in self._md._keys.iter_entries():
if version != self._md._version:
raise RuntimeError("Dictionary changed during iteration")
- yield self._md._key(k), v
+ yield self._md._key(e.key), e.value
@reprlib.recursive_repr()
def __repr__(self) -> str:
lst = []
- for i, k, v in self._md._items:
- lst.append(f"'{k}': {v!r}")
+ for e in self._md._keys.iter_entries():
+ lst.append(f"'{e.key}': {e.value!r}")
body = ", ".join(lst)
return f"<{self.__class__.__name__}({body})>"
def _parse_item(
self, arg: Union[tuple[str, _V], _T]
- ) -> Optional[tuple[str, str, _V]]:
+ ) -> Optional[tuple[int, str, str, _V]]:
if not isinstance(arg, tuple):
return None
if len(arg) != 2:
return None
try:
- return (self._md._identity(arg[0]), arg[0], arg[1])
+ identity = self._md._identity(arg[0])
+ return (hash(identity), identity, arg[0], arg[1])
except TypeError:
return None
@@ -125,7 +129,7 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
if item is None:
continue
else:
- tmp.add((item[0], item[2]))
+ tmp.add((item[1], item[3]))
return tmp
def __and__(self, other: Iterable[Any]) -> set[tuple[str, _V]]:
@@ -138,10 +142,12 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
item = self._parse_item(arg)
if item is None:
continue
- identity, key, value = item
- for i, k, v in self._md._items:
- if i == identity and v == value:
- ret.add((k, v))
+ hash_, identity, key, value = item
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ e.hash = -1
+ if e.identity == identity and e.value == value:
+ ret.add((e.key, e.value))
+ self._md._keys.restore_hash(hash_)
return ret
def __rand__(self, other: Iterable[_T]) -> set[_T]:
@@ -154,9 +160,9 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
item = self._parse_item(arg)
if item is None:
continue
- identity, key, value = item
- for i, k, v in self._md._items:
- if i == identity and v == value:
+ hash_, identity, key, value = item
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity and e.value == value:
ret.add(arg)
break
return ret
@@ -168,13 +174,13 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
except TypeError:
return NotImplemented
for arg in it:
- item: Optional[tuple[str, str, _V]] = self._parse_item(arg)
+ item: Optional[tuple[int, str, str, _V]] = self._parse_item(arg)
if item is None:
ret.add(arg)
continue
- identity, key, value = item
- for i, k, v in self._md._items:
- if i == identity and v == value:
+ hash_, identity, key, value = item
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity and e.value == value: # pragma: no branch
break
else:
ret.add(arg)
@@ -187,9 +193,9 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
return NotImplemented
tmp = self._tmp_set(ret)
- for i, k, v in self._md._items:
- if (i, v) not in tmp:
- ret.add((k, v))
+ for e in self._md._keys.iter_entries():
+ if (e.identity, e.value) not in tmp:
+ ret.add((e.key, e.value))
return ret
def __sub__(self, other: Iterable[_T]) -> set[Union[tuple[str, _V], _T]]:
@@ -200,9 +206,9 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
return NotImplemented
tmp = self._tmp_set(it)
- for i, k, v in self._md._items:
- if (i, v) not in tmp:
- ret.add((k, v))
+ for e in self._md._keys.iter_entries():
+ if (e.identity, e.value) not in tmp:
+ ret.add((e.key, e.value))
return ret
@@ -218,9 +224,9 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
ret.add(arg)
continue
- identity, key, value = item
- for i, k, v in self._md._items:
- if i == identity and v == value:
+ hash_, identity, key, value = item
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity and e.value == value: # pragma: no branch
break
else:
ret.add(arg)
@@ -243,17 +249,17 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
if item is None:
continue
- identity, key, value = item
- for i, k, v in self._md._items:
- if i == identity and v == value:
+ hash_, identity, key, value = item
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity and e.value == value: # pragma: no branch
return False
return True
class _ValuesView(_ViewBase[_V], ValuesView[_V]):
def __contains__(self, value: object) -> bool:
- for i, k, v in self._md._items:
- if v == value:
+ for e in self._md._keys.iter_entries():
+ if e.value == value:
return True
return False
@@ -261,16 +267,16 @@ class _ValuesView(_ViewBase[_V], ValuesView[_V]):
return _Iter(len(self), self._iter(self._md._version))
def _iter(self, version: int) -> Iterator[_V]:
- for i, k, v in self._md._items:
+ for e in self._md._keys.iter_entries():
if version != self._md._version:
raise RuntimeError("Dictionary changed during iteration")
- yield v
+ yield e.value
@reprlib.recursive_repr()
def __repr__(self) -> str:
lst = []
- for i, k, v in self._md._items:
- lst.append(repr(v))
+ for e in self._md._keys.iter_entries():
+ lst.append(repr(e.value))
body = ", ".join(lst)
return f"<{self.__class__.__name__}({body})>"
@@ -280,8 +286,9 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
if not isinstance(key, str):
return False
identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
+ hash_ = hash(identity)
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
return True
return False
@@ -289,15 +296,15 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
return _Iter(len(self), self._iter(self._md._version))
def _iter(self, version: int) -> Iterator[str]:
- for i, k, v in self._md._items:
+ for e in self._md._keys.iter_entries():
if version != self._md._version:
raise RuntimeError("Dictionary changed during iteration")
- yield self._md._key(k)
+ yield self._md._key(e.key)
def __repr__(self) -> str:
lst = []
- for i, k, v in self._md._items:
- lst.append(f"'{k}'")
+ for e in self._md._keys.iter_entries():
+ lst.append(f"'{e.key}'")
body = ", ".join(lst)
return f"<{self.__class__.__name__}({body})>"
@@ -311,9 +318,11 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
if not isinstance(key, str):
continue
identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- ret.add(k)
+ hash_ = hash(identity)
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ ret.add(e.key)
+ break
return ret
def __rand__(self, other: Iterable[_T]) -> set[_T]:
@@ -325,10 +334,8 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
for key in it:
if not isinstance(key, str):
continue
- identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- ret.add(key)
+ if key in self._md:
+ ret.add(key)
return cast(set[_T], ret)
def __or__(self, other: Iterable[_T]) -> set[Union[str, _T]]:
@@ -341,11 +348,7 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
if not isinstance(key, str):
ret.add(key)
continue
- identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- break
- else:
+ if key not in self._md:
ret.add(key)
return ret
@@ -362,9 +365,9 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
identity = self._md._identity(key)
tmp.add(identity)
- for i, k, v in self._md._items:
- if i not in tmp:
- ret.add(k)
+ for e in self._md._keys.iter_entries():
+ if e.identity not in tmp:
+ ret.add(e.key)
return ret
def __sub__(self, other: Iterable[object]) -> set[str]:
@@ -377,9 +380,10 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
if not isinstance(key, str):
continue
identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- ret.discard(k)
+ hash_ = hash(identity)
+ for slot, idx, e in self._md._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ ret.discard(e.key)
break
return ret
@@ -391,11 +395,8 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
for key in other:
if not isinstance(key, str):
continue
- identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- ret.discard(key) # type: ignore[arg-type]
- break
+ if key in self._md:
+ ret.discard(key) # type: ignore[arg-type]
return ret
def __xor__(self, other: Iterable[_T]) -> set[Union[str, _T]]:
@@ -413,15 +414,13 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
for key in other:
if not isinstance(key, str):
continue
- identity = self._md._identity(key)
- for i, k, v in self._md._items:
- if i == identity:
- return False
+ if key in self._md:
+ return False
return True
class _CSMixin:
- _ci: bool = False
+ _ci: ClassVar[bool] = False
def _key(self, key: str) -> str:
return key
@@ -434,7 +433,7 @@ class _CSMixin:
class _CIMixin:
- _ci: bool = True
+ _ci: ClassVar[bool] = True
def _key(self, key: str) -> str:
if type(key) is istr:
@@ -455,15 +454,197 @@ class _CIMixin:
raise TypeError("MultiDict keys should be either str or subclasses of str")
+def estimate_log2_keysize(n: int) -> int:
+ # 7 == HT_MINSIZE - 1
+ return (((n * 3 + 1) // 2) | 7).bit_length()
+
+
+@dataclass
+class _Entry(Generic[_V]):
+ hash: int
+ identity: str
+ key: str
+ value: _V
+
+
+@dataclass
+class _HtKeys(Generic[_V]): # type: ignore[misc]
+ LOG_MINSIZE: ClassVar[int] = 3
+ MINSIZE: ClassVar[int] = 8
+ PREALLOCATED_INDICES: ClassVar[dict[int, array]] = { # type: ignore[type-arg]
+ log2_size: array(
+ "b" if log2_size < 8 else "h", (-1 for i in range(1 << log2_size))
+ )
+ for log2_size in range(3, 10)
+ }
+
+ log2_size: int
+ usable: int
+
+ indices: array # type: ignore[type-arg] # in py3.9 array is not generic
+ entries: list[Optional[_Entry[_V]]]
+
+ @functools.cached_property
+ def nslots(self) -> int:
+ return 1 << self.log2_size
+
+ @functools.cached_property
+ def mask(self) -> int:
+ return self.nslots - 1
+
+ if sys.implementation.name != "pypy":
+
+ def __sizeof__(self) -> int:
+ return (
+ object.__sizeof__(self)
+ + sys.getsizeof(self.indices)
+ + sys.getsizeof(self.entries)
+ )
+
+ @classmethod
+ def new(cls, log2_size: int, entries: list[Optional[_Entry[_V]]]) -> Self:
+ size = 1 << log2_size
+ usable = (size << 1) // 3
+ if log2_size < 10:
+ indices = cls.PREALLOCATED_INDICES[log2_size].__copy__()
+ elif log2_size < 16:
+ indices = array("h", (-1 for i in range(size)))
+ elif log2_size < 32:
+ indices = array("l", (-1 for i in range(size)))
+ else: # pragma: no cover # don't test huge multidicts
+ indices = array("q", (-1 for i in range(size)))
+ ret = cls(
+ log2_size=log2_size,
+ usable=usable,
+ indices=indices,
+ entries=entries,
+ )
+ return ret
+
+ def clone(self) -> "_HtKeys[_V]":
+ entries = [
+ _Entry(e.hash, e.identity, e.key, e.value) if e is not None else None
+ for e in self.entries
+ ]
+
+ return _HtKeys(
+ log2_size=self.log2_size,
+ usable=self.usable,
+ indices=self.indices.__copy__(),
+ entries=entries,
+ )
+
+ def build_indices(self, update: bool) -> None:
+ mask = self.mask
+ indices = self.indices
+ for idx, e in enumerate(self.entries):
+ assert e is not None
+ hash_ = e.hash
+ if update:
+ if hash_ == -1:
+ hash_ = hash(e.identity)
+ else:
+ assert hash_ != -1
+ i = hash_ & mask
+ perturb = hash_ & sys.maxsize
+ while indices[i] != -1:
+ perturb >>= 5
+ i = mask & (i * 5 + perturb + 1)
+ indices[i] = idx
+
+ def find_empty_slot(self, hash_: int) -> int:
+ mask = self.mask
+ indices = self.indices
+ i = hash_ & mask
+ perturb = hash_ & sys.maxsize
+ ix = indices[i]
+ while ix != -1:
+ perturb >>= 5
+ i = (i * 5 + perturb + 1) & mask
+ ix = indices[i]
+ return i
+
+ def iter_hash(self, hash_: int) -> Iterator[tuple[int, int, _Entry[_V]]]:
+ mask = self.mask
+ indices = self.indices
+ entries = self.entries
+ i = hash_ & mask
+ perturb = hash_ & sys.maxsize
+ ix = indices[i]
+ while ix != -1:
+ if ix != -2:
+ e = entries[ix]
+ if e.hash == hash_:
+ yield i, ix, e
+ perturb >>= 5
+ i = (i * 5 + perturb + 1) & mask
+ ix = indices[i]
+
+ def del_idx(self, hash_: int, idx: int) -> None:
+ mask = self.mask
+ indices = self.indices
+ i = hash_ & mask
+ perturb = hash_ & sys.maxsize
+ ix = indices[i]
+ while ix != idx:
+ perturb >>= 5
+ i = (i * 5 + perturb + 1) & mask
+ ix = indices[i]
+ indices[i] = -2
+
+ def iter_entries(self) -> Iterator[_Entry[_V]]:
+ return filter(None, self.entries)
+
+ def restore_hash(self, hash_: int) -> None:
+ mask = self.mask
+ indices = self.indices
+ entries = self.entries
+ i = hash_ & mask
+ perturb = hash_ & sys.maxsize
+ ix = indices[i]
+ while ix != -1:
+ if ix != -2:
+ entry = entries[ix]
+ if entry.hash == -1:
+ entry.hash = hash_
+ perturb >>= 5
+ i = (i * 5 + perturb + 1) & mask
+ ix = indices[i]
+
+
class MultiDict(_CSMixin, MutableMultiMapping[_V]):
"""Dictionary with the support for duplicate keys."""
+ __slots__ = ("_keys", "_used", "_version")
+
def __init__(self, arg: MDArg[_V] = None, /, **kwargs: _V):
- self._items: list[tuple[str, str, _V]] = []
+ self._used = 0
v = _version
v[0] += 1
self._version = v[0]
- self._extend(arg, kwargs, self.__class__.__name__, self._extend_items)
+ if not kwargs:
+ md = None
+ if isinstance(arg, MultiDictProxy):
+ md = arg._md
+ elif isinstance(arg, MultiDict):
+ md = arg
+ if md is not None and md._ci is self._ci:
+ self._from_md(md)
+ return
+
+ items = self._parse_args(arg, kwargs)
+ log2_size = estimate_log2_keysize(len(items))
+ if log2_size > 17: # pragma: no cover
+ # Don't overallocate really huge keys space in init
+ log2_size = 17
+ self._keys: _HtKeys[_V] = _HtKeys.new(log2_size, [])
+ self._extend_items(items)
+
+ def _from_md(self, md: "MultiDict[_V]") -> None:
+ # Copy everything as-is without compacting the new multidict,
+ # otherwise it requires reindexing
+ self._keys = md._keys.clone()
+ self._used = md._used
@overload
def getall(self, key: str) -> list[_V]: ...
@@ -474,7 +655,15 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
) -> Union[list[_V], _T]:
"""Return a list of all values matching the key."""
identity = self._identity(key)
- res = [v for i, k, v in self._items if i == identity]
+ hash_ = hash(identity)
+ res = []
+
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ res.append(e.value)
+ e.hash = -1
+ self._keys.restore_hash(hash_)
+
if res:
return res
if not res and default is not sentinel:
@@ -493,9 +682,10 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
Raises KeyError if the key is not found and no default is provided.
"""
identity = self._identity(key)
- for i, k, v in self._items:
- if i == identity:
- return v
+ hash_ = hash(identity)
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ return e.value
if default is not sentinel:
return default
raise KeyError("Key not found: %r" % key)
@@ -520,7 +710,7 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
return iter(self.keys())
def __len__(self) -> int:
- return len(self._items)
+ return self._used
def keys(self) -> KeysView[str]:
"""Return a new view of the dictionary's keys."""
@@ -540,15 +730,15 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
if isinstance(other, MultiDictProxy):
return self == other._md
if isinstance(other, MultiDict):
- lft = self._items
- rht = other._items
- if len(lft) != len(rht):
+ lft = self._keys
+ rht = other._keys
+ if self._used != other._used:
return False
- for (i1, k2, v1), (i2, k2, v2) in zip(lft, rht):
- if i1 != i2 or v1 != v2:
+ for e1, e2 in zip(lft.iter_entries(), rht.iter_entries()):
+ if e1.identity != e2.identity or e1.value != e2.value:
return False
return True
- if len(self._items) != len(other):
+ if self._used != len(other):
return False
for k, v in self.items():
nv = other.get(k, sentinel)
@@ -560,33 +750,35 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
if not isinstance(key, str):
return False
identity = self._identity(key)
- for i, k, v in self._items:
- if i == identity:
+ hash_ = hash(identity)
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
return True
return False
@reprlib.recursive_repr()
def __repr__(self) -> str:
- body = ", ".join(f"'{k}': {v!r}" for i, k, v in self._items)
+ body = ", ".join(f"'{e.key}': {e.value!r}" for e in self._keys.iter_entries())
return f"<{self.__class__.__name__}({body})>"
if sys.implementation.name != "pypy":
def __sizeof__(self) -> int:
- return object.__sizeof__(self) + sys.getsizeof(self._items)
+ return object.__sizeof__(self) + sys.getsizeof(self._keys)
def __reduce__(self) -> tuple[type[Self], tuple[list[tuple[str, _V]]]]:
return (self.__class__, (list(self.items()),))
def add(self, key: str, value: _V) -> None:
identity = self._identity(key)
- self._items.append((identity, key, value))
+ hash_ = hash(identity)
+ self._add_with_hash(_Entry(hash_, identity, key, value))
self._incr_version()
def copy(self) -> Self:
"""Return a copy of itself."""
cls = self.__class__
- return cls(self.items())
+ return cls(self)
__copy__ = copy
@@ -595,28 +787,35 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
This method must be used instead of update.
"""
- self._extend(arg, kwargs, "extend", self._extend_items)
+ items = self._parse_args(arg, kwargs)
+ newsize = self._used + len(items)
+ self._resize(estimate_log2_keysize(newsize), False)
+ self._extend_items(items)
- def _extend(
+ def _parse_args(
self,
arg: MDArg[_V],
kwargs: Mapping[str, _V],
- name: str,
- method: Callable[[list[tuple[str, str, _V]]], None],
- ) -> None:
+ ) -> list[_Entry[_V]]:
+ identity_func = self._identity
if arg:
if isinstance(arg, MultiDictProxy):
arg = arg._md
if isinstance(arg, MultiDict):
if self._ci is not arg._ci:
- items = [(self._identity(k), k, v) for _, k, v in arg._items]
+ items = []
+ for e in arg._keys.iter_entries():
+ identity = identity_func(e.key)
+ items.append(_Entry(hash(identity), identity, e.key, e.value))
else:
- items = arg._items
- if kwargs:
- items = items.copy()
+ items = [
+ _Entry(e.hash, e.identity, e.key, e.value)
+ for e in arg._keys.iter_entries()
+ ]
if kwargs:
for key, value in kwargs.items():
- items.append((self._identity(key), key, value))
+ identity = identity_func(key)
+ items.append(_Entry(hash(identity), identity, key, value))
else:
if hasattr(arg, "keys"):
arg = cast(SupportsKeys[_V], arg)
@@ -631,34 +830,57 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
f"multidict update sequence element #{pos}"
f"has length {len(item)}; 2 is required"
)
- items.append((self._identity(item[0]), item[0], item[1]))
-
- method(items)
+ identity = identity_func(item[0])
+ items.append(_Entry(hash(identity), identity, item[0], item[1]))
else:
- method([(self._identity(key), key, value) for key, value in kwargs.items()])
+ items = []
+ for key, value in kwargs.items():
+ identity = identity_func(key)
+ items.append(_Entry(hash(identity), identity, key, value))
+
+ return items
- def _extend_items(self, items: Iterable[tuple[str, str, _V]]) -> None:
- for identity, key, value in items:
- self._items.append((identity, key, value))
+ def _extend_items(self, items: Iterable[_Entry[_V]]) -> None:
+ for e in items:
+ self._add_with_hash(e)
self._incr_version()
def clear(self) -> None:
"""Remove all items from MultiDict."""
- self._items.clear()
+ self._used = 0
+ self._keys = _HtKeys.new(_HtKeys.LOG_MINSIZE, [])
self._incr_version()
# Mapping interface #
def __setitem__(self, key: str, value: _V) -> None:
- self._replace(key, value)
+ identity = self._identity(key)
+ hash_ = hash(identity)
+ found = False
+
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ if not found:
+ e.key = key
+ e.value = value
+ e.hash = -1
+ found = True
+ self._incr_version()
+ elif e.hash != -1: # pragma: no branch
+ self._del_at(slot, idx)
+
+ if not found:
+ self._add_with_hash(_Entry(hash_, identity, key, value))
+ else:
+ self._keys.restore_hash(hash_)
def __delitem__(self, key: str) -> None:
- identity = self._identity(key)
- items = self._items
found = False
- for i in range(len(items) - 1, -1, -1):
- if items[i][0] == identity:
- del items[i]
+ identity = self._identity(key)
+ hash_ = hash(identity)
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ self._del_at(slot, idx)
found = True
if not found:
raise KeyError(key)
@@ -674,9 +896,10 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
def setdefault(self, key: str, default: Union[_V, None] = None) -> Union[_V, None]: # type: ignore[misc]
"""Return value for key, set value to default if key is not present."""
identity = self._identity(key)
- for i, k, v in self._items:
- if i == identity:
- return v
+ hash_ = hash(identity)
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ return e.value
self.add(key, default) # type: ignore[arg-type]
return default
@@ -694,10 +917,11 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
"""
identity = self._identity(key)
- for i in range(len(self._items)):
- if self._items[i][0] == identity:
- value = self._items[i][2]
- del self._items[i]
+ hash_ = hash(identity)
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ value = e.value
+ self._del_at(slot, idx)
self._incr_version()
return value
if default is sentinel:
@@ -725,100 +949,140 @@ class MultiDict(_CSMixin, MutableMultiMapping[_V]):
"""
found = False
identity = self._identity(key)
+ hash_ = hash(identity)
ret = []
- for i in range(len(self._items) - 1, -1, -1):
- item = self._items[i]
- if item[0] == identity:
- ret.append(item[2])
- del self._items[i]
- self._incr_version()
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
found = True
+ ret.append(e.value)
+ self._del_at(slot, idx)
+ self._incr_version()
+
if not found:
if default is sentinel:
raise KeyError(key)
else:
return default
else:
- ret.reverse()
return ret
def popitem(self) -> tuple[str, _V]:
"""Remove and return an arbitrary (key, value) pair."""
- if self._items:
- i, k, v = self._items.pop()
- self._incr_version()
- return self._key(k), v
- else:
+ if self._used <= 0:
raise KeyError("empty multidict")
- def update(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None:
- """Update the dictionary from *other*, overwriting existing keys."""
- self._extend(arg, kwargs, "update", self._update_items)
+ pos = len(self._keys.entries) - 1
+ entry = self._keys.entries.pop()
- def _update_items(self, items: list[tuple[str, str, _V]]) -> None:
- if not items:
- return
- used_keys: dict[str, int] = {}
- for identity, key, value in items:
- start = used_keys.get(identity, 0)
- for i in range(start, len(self._items)):
- item = self._items[i]
- if item[0] == identity:
- used_keys[identity] = i + 1
- self._items[i] = (identity, key, value)
- break
- else:
- self._items.append((identity, key, value))
- used_keys[identity] = len(self._items)
-
- # drop tails
- i = 0
- while i < len(self._items):
- item = self._items[i]
- identity = item[0]
- pos = used_keys.get(identity)
- if pos is None:
- i += 1
- continue
- if i >= pos:
- del self._items[i]
- else:
- i += 1
+ while entry is None:
+ pos -= 1
+ entry = self._keys.entries.pop()
+ ret = self._key(entry.key), entry.value
+ self._keys.del_idx(entry.hash, pos)
+ self._used -= 1
self._incr_version()
+ return ret
- def _replace(self, key: str, value: _V) -> None:
- identity = self._identity(key)
- items = self._items
-
- for i in range(len(items)):
- item = items[i]
- if item[0] == identity:
- items[i] = (identity, key, value)
- # i points to last found item
- rgt = i
- self._incr_version()
- break
- else:
- self._items.append((identity, key, value))
- self._incr_version()
+ def update(self, arg: MDArg[_V] = None, /, **kwargs: _V) -> None:
+ """Update the dictionary from *other*, overwriting existing keys."""
+ items = self._parse_args(arg, kwargs)
+ newsize = self._used + len(items)
+ log2_size = estimate_log2_keysize(newsize)
+ if log2_size > 17: # pragma: no cover
+ # Don't overallocate really huge keys space in update,
+ # duplicate keys could reduce the resulting anount of entries
+ log2_size = 17
+ if log2_size > self._keys.log2_size:
+ self._resize(log2_size, False)
+ self._update_items(items)
+
+ def _update_items(self, items: list[_Entry[_V]]) -> None:
+ if not items:
return
+ for entry in items:
+ found = False
+ hash_ = entry.hash
+ identity = entry.identity
+ for slot, idx, e in self._keys.iter_hash(hash_):
+ if e.identity == identity: # pragma: no branch
+ if not found:
+ found = True
+ e.key = entry.key
+ e.value = entry.value
+ e.hash = -1
+ else:
+ self._del_at_for_upd(e)
+ if not found:
+ self._add_with_hash_for_upd(entry)
+
+ keys = self._keys
+ indices = keys.indices
+ entries = keys.entries
+ for slot in range(keys.nslots):
+ idx = indices[slot]
+ if idx >= 0:
+ e2 = entries[idx]
+ assert e2 is not None
+ if e2.key is None:
+ entries[idx] = None # type: ignore[unreachable]
+ indices[slot] = -2
+ self._used -= 1
+ if e2.hash == -1:
+ e2.hash = hash(e2.identity)
- # remove all tail items
- # Mypy bug: https://github.com/python/mypy/issues/14209
- i = rgt + 1 # type: ignore[possibly-undefined]
- while i < len(items):
- item = items[i]
- if item[0] == identity:
- del items[i]
- else:
- i += 1
+ self._incr_version()
def _incr_version(self) -> None:
v = _version
v[0] += 1
self._version = v[0]
+ def _resize(self, log2_newsize: int, update: bool) -> None:
+ oldkeys = self._keys
+ newentries = self._used
+
+ if len(oldkeys.entries) == newentries:
+ entries = oldkeys.entries
+ else:
+ entries = [e for e in oldkeys.entries if e is not None]
+ newkeys: _HtKeys[_V] = _HtKeys.new(log2_newsize, entries)
+ newkeys.usable -= newentries
+ newkeys.build_indices(update)
+ self._keys = newkeys
+
+ def _add_with_hash(self, entry: _Entry[_V]) -> None:
+ if self._keys.usable <= 0:
+ self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), False)
+ keys = self._keys
+ slot = keys.find_empty_slot(entry.hash)
+ keys.indices[slot] = len(keys.entries)
+ keys.entries.append(entry)
+ self._incr_version()
+ self._used += 1
+ keys.usable -= 1
+
+ def _add_with_hash_for_upd(self, entry: _Entry[_V]) -> None:
+ if self._keys.usable <= 0:
+ self._resize((self._used * 3 | _HtKeys.MINSIZE - 1).bit_length(), True)
+ keys = self._keys
+ slot = keys.find_empty_slot(entry.hash)
+ keys.indices[slot] = len(keys.entries)
+ entry.hash = -1
+ keys.entries.append(entry)
+ self._incr_version()
+ self._used += 1
+ keys.usable -= 1
+
+ def _del_at(self, slot: int, idx: int) -> None:
+ self._keys.entries[idx] = None
+ self._keys.indices[slot] = -2
+ self._used -= 1
+
+ def _del_at_for_upd(self, entry: _Entry[_V]) -> None:
+ entry.key = None # type: ignore[assignment]
+ entry.value = None # type: ignore[assignment]
+
class CIMultiDict(_CIMixin, MultiDict[_V]):
"""Dictionary with the support for duplicate case-insensitive keys."""
@@ -827,13 +1091,14 @@ class CIMultiDict(_CIMixin, MultiDict[_V]):
class MultiDictProxy(_CSMixin, MultiMapping[_V]):
"""Read-only proxy for MultiDict instance."""
+ __slots__ = ("_md",)
+
_md: MultiDict[_V]
def __init__(self, arg: Union[MultiDict[_V], "MultiDictProxy[_V]"]):
if not isinstance(arg, (MultiDict, MultiDictProxy)):
raise TypeError(
- "ctor requires MultiDict or MultiDictProxy instance"
- f", not {type(arg)}"
+ f"ctor requires MultiDict or MultiDictProxy instance, not {type(arg)}"
)
if isinstance(arg, MultiDictProxy):
self._md = arg._md
@@ -919,7 +1184,7 @@ class MultiDictProxy(_CSMixin, MultiMapping[_V]):
def copy(self) -> MultiDict[_V]:
"""Return a copy of itself."""
- return MultiDict(self.items())
+ return MultiDict(self._md)
class CIMultiDictProxy(_CIMixin, MultiDictProxy[_V]):
@@ -936,7 +1201,7 @@ class CIMultiDictProxy(_CIMixin, MultiDictProxy[_V]):
def copy(self) -> CIMultiDict[_V]:
"""Return a copy of itself."""
- return CIMultiDict(self.items())
+ return CIMultiDict(self._md)
def getversion(md: Union[MultiDict[object], MultiDictProxy[object]]) -> int:
diff --git a/contrib/python/multidict/multidict/_multilib/dict.h b/contrib/python/multidict/multidict/_multilib/dict.h
index fa07fdf4ac3..2f7c83be2e2 100644
--- a/contrib/python/multidict/multidict/_multilib/dict.h
+++ b/contrib/python/multidict/multidict/_multilib/dict.h
@@ -5,20 +5,26 @@
extern "C" {
#endif
+#include "htkeys.h"
#include "pythoncapi_compat.h"
-#include "pair_list.h"
+#include "state.h"
#if PY_VERSION_HEX >= 0x030c00f0
#define MANAGED_WEAKREFS
#endif
-
-typedef struct { // 16 or 24 for GC prefix
- PyObject_HEAD // 16
+typedef struct {
+ PyObject_HEAD
#ifndef MANAGED_WEAKREFS
PyObject *weaklist;
#endif
- pair_list_t pairs;
+ mod_state *state;
+ Py_ssize_t used;
+
+ uint64_t version;
+ bool is_ci;
+
+ htkeys_t *keys;
} MultiDictObject;
typedef struct {
@@ -29,7 +35,6 @@ typedef struct {
MultiDictObject *md;
} MultiDictProxyObject;
-
#ifdef __cplusplus
}
#endif
diff --git a/contrib/python/multidict/multidict/_multilib/hashtable.h b/contrib/python/multidict/multidict/_multilib/hashtable.h
new file mode 100644
index 00000000000..53d39a58cda
--- /dev/null
+++ b/contrib/python/multidict/multidict/_multilib/hashtable.h
@@ -0,0 +1,1890 @@
+#include "pythoncapi_compat.h"
+
+#ifndef _MULTIDICT_HASHTABLE_H
+#define _MULTIDICT_HASHTABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "dict.h"
+#include "htkeys.h"
+#include "istr.h"
+#include "state.h"
+
+typedef struct _md_pos {
+ Py_ssize_t pos;
+ uint64_t version;
+} md_pos_t;
+
+typedef struct _md_finder {
+ MultiDictObject *md;
+ htkeysiter_t iter;
+ uint64_t version;
+ Py_hash_t hash;
+ PyObject *identity; // borrowed ref
+} md_finder_t;
+
+/*
+The multidict's implementation is close to Python's dict except for multiple
+keys.
+
+It starts from the empty hashtable, which grows by a power of 2 starting from
+8: 8, 16, 32, 64, 128, ... The amount of items is 2/3 of the hashtable size
+(1/3 of the table is never allocated).
+
+The table is resized if needed, and bulk updates (extend(), update(), and
+constructor calls) pre-allocate many items at once, reducing the amount of
+potential hashtable resizes.
+
+Item deletion puts DKIX_DUMMY special index in the hashtable. In opposite to
+the standard dict, DKIX_DUMMY is never replaced with an index of the new entry
+except by hashtable indices rebuild. It allows to keep the insertion order for
+multiple equal keys. The index table rebuild happens on the keys table size
+changeing and if the number of DKIX_DUMMY slots grows to 1/4 of the total
+amount.
+
+The iteration for operations like getall() is a little tricky. The next index
+calculation could return the already visited index before reaching the end. To
+eliminate duplicates, the code marks already visited entries by entry->hash =
+-1. -1 hash is an invalid hash value that could be used as a marker. After the
+iteration finishes, all marked entries are restored. Double iteration over the
+indices still has O(1) amortized time, it is ok.
+
+`.add()`, `val = md[key]`, `md[key] = val`, `md.setdefault()` all have O(1).
+`.getall()` / `.popall()` have O(N) where N is the amount of returned items.
+`.update()` / `extend()` have O(N+M) where N and M are amount of items
+in the left and right arguments.
+
+`.copy()` and constuction from multidict is super fast.
+*/
+
+/* GROWTH_RATE. Growth rate upon hitting maximum load.
+ * Currently set to used*3.
+ * This means that dicts double in size when growing without deletions,
+ * but have more head room when the number of deletions is on a par with the
+ * number of insertions. See also bpo-17563 and bpo-33205.
+ *
+ * GROWTH_RATE was set to used*4 up to version 3.2.
+ * GROWTH_RATE was set to used*2 in version 3.3.0
+ * GROWTH_RATE was set to used*2 + capacity/2 in 3.4.0-3.6.0.
+ */
+static inline Py_ssize_t
+GROWTH_RATE(MultiDictObject *md)
+{
+ return md->used * 3;
+}
+
+static inline int
+_md_check_consistency(MultiDictObject *md, bool update);
+static inline int
+_md_dump(MultiDictObject *md);
+
+#ifndef NDEBUG
+#define ASSERT_CONSISTENT(md, update) assert(_md_check_consistency(md, update))
+#else
+#define ASSERT_CONSISTENT(md, update) assert(1)
+#endif
+
+static inline int
+_str_cmp(PyObject *s1, PyObject *s2)
+{
+ PyObject *ret = PyUnicode_RichCompare(s1, s2, Py_EQ);
+ if (Py_IsTrue(ret)) {
+ Py_DECREF(ret);
+ return 1;
+ } else if (ret == NULL) {
+ return -1;
+ } else {
+ Py_DECREF(ret);
+ return 0;
+ }
+}
+
+static inline PyObject *
+_key_to_identity(mod_state *state, PyObject *key)
+{
+ if (IStr_Check(state, key)) {
+ return Py_NewRef(((istrobject *)key)->canonical);
+ }
+ if (PyUnicode_CheckExact(key)) {
+ return Py_NewRef(key);
+ }
+ if (PyUnicode_Check(key)) {
+ return PyUnicode_FromObject(key);
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "MultiDict keys should be either str "
+ "or subclasses of str");
+ return NULL;
+}
+
+static inline PyObject *
+_ci_key_to_identity(mod_state *state, PyObject *key)
+{
+ if (IStr_Check(state, key)) {
+ return Py_NewRef(((istrobject *)key)->canonical);
+ }
+ if (PyUnicode_Check(key)) {
+ PyObject *ret = PyObject_CallMethodNoArgs(key, state->str_lower);
+ if (ret == NULL) {
+ goto fail;
+ }
+ if (!PyUnicode_CheckExact(ret)) {
+ PyObject *tmp = PyUnicode_FromObject(ret);
+ Py_CLEAR(ret);
+ if (tmp == NULL) {
+ return NULL;
+ }
+ ret = tmp;
+ }
+ return ret;
+ }
+fail:
+ PyErr_SetString(PyExc_TypeError,
+ "CIMultiDict keys should be either str "
+ "or subclasses of str");
+ return NULL;
+}
+
+static inline PyObject *
+_arg_to_key(mod_state *state, PyObject *key, PyObject *identity)
+{
+ if (PyUnicode_Check(key)) {
+ return Py_NewRef(key);
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "MultiDict keys should be either str "
+ "or subclasses of str");
+ return NULL;
+}
+
+static inline PyObject *
+_ci_arg_to_key(mod_state *state, PyObject *key, PyObject *identity)
+{
+ if (IStr_Check(state, key)) {
+ return Py_NewRef(key);
+ }
+ if (PyUnicode_Check(key)) {
+ return IStr_New(state, key, identity);
+ }
+ PyErr_SetString(PyExc_TypeError,
+ "CIMultiDict keys should be either str "
+ "or subclasses of str");
+ return NULL;
+}
+
+static inline int
+_md_resize(MultiDictObject *md, uint8_t log2_newsize, bool update)
+{
+ htkeys_t *oldkeys, *newkeys;
+
+ if (log2_newsize >= SIZEOF_SIZE_T * 8) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ assert(log2_newsize >= HT_LOG_MINSIZE);
+
+ oldkeys = md->keys;
+
+ /* Allocate a new table. */
+ newkeys = htkeys_new(log2_newsize);
+ assert(newkeys);
+ if (newkeys == NULL) {
+ return -1;
+ }
+ // New table must be large enough.
+ assert(newkeys->usable >= md->used);
+
+ Py_ssize_t numentries = md->used;
+ entry_t *oldentries = htkeys_entries(oldkeys);
+ entry_t *newentries = htkeys_entries(newkeys);
+ if (oldkeys->nentries == numentries) {
+ memcpy(newentries, oldentries, numentries * sizeof(entry_t));
+ } else {
+ entry_t *new_ep = newentries;
+ entry_t *old_ep = oldentries;
+ for (Py_ssize_t i = 0; i < oldkeys->nentries; ++i, ++old_ep) {
+ if (old_ep->identity != NULL) {
+ *new_ep++ = *old_ep;
+ }
+ }
+ }
+
+ if (htkeys_build_indices(newkeys, newentries, numentries, update) < 0) {
+ return -1;
+ }
+
+ md->keys = newkeys;
+
+ if (oldkeys != &empty_htkeys) {
+ htkeys_free(oldkeys);
+ }
+
+ md->keys->usable = md->keys->usable - numentries;
+ md->keys->nentries = numentries;
+ ASSERT_CONSISTENT(md, update);
+ return 0;
+}
+
+static inline int
+_md_resize_for_insert(MultiDictObject *md)
+{
+ return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), false);
+}
+
+static inline int
+_md_resize_for_update(MultiDictObject *md)
+{
+ return _md_resize(md, calculate_log2_keysize(GROWTH_RATE(md)), true);
+}
+
+static inline int
+_md_reserve(MultiDictObject *md, Py_ssize_t extra_size, bool update)
+{
+ uint8_t new_size = estimate_log2_keysize(extra_size + md->used);
+ if (new_size > md->keys->log2_size) {
+ return _md_resize(md, new_size, update);
+ }
+ return 0;
+}
+
+static inline int
+md_reserve(MultiDictObject *md, Py_ssize_t extra_size)
+{
+ return _md_reserve(md, extra_size, false);
+}
+
+static inline int
+md_init(MultiDictObject *md, mod_state *state, bool is_ci, Py_ssize_t minused)
+{
+ md->state = state;
+ md->is_ci = is_ci;
+ md->used = 0;
+ md->version = NEXT_VERSION(md->state);
+
+ const uint8_t log2_max_presize = 17;
+ const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize;
+ uint8_t log2_newsize;
+ htkeys_t *new_keys;
+
+ if (minused <= USABLE_FRACTION(HT_MINSIZE)) {
+ md->keys = &empty_htkeys;
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+ }
+ /* There are no strict guarantee that returned dict can contain minused
+ * items without resize. So we create medium size dict instead of very
+ * large dict or MemoryError.
+ */
+ if (minused > USABLE_FRACTION(max_presize)) {
+ log2_newsize = log2_max_presize;
+ } else {
+ log2_newsize = estimate_log2_keysize(minused);
+ }
+
+ new_keys = htkeys_new(log2_newsize);
+ if (new_keys == NULL) return -1;
+ md->keys = new_keys;
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+}
+
+static inline int
+md_clone_from_ht(MultiDictObject *md, MultiDictObject *other)
+{
+ ASSERT_CONSISTENT(other, false);
+ md->state = other->state;
+ md->used = other->used;
+ md->version = other->version;
+ md->is_ci = other->is_ci;
+ if (other->keys != &empty_htkeys) {
+ size_t size = htkeys_sizeof(other->keys);
+ htkeys_t *keys = PyMem_Malloc(size);
+ if (keys == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ memcpy(keys, other->keys, size);
+ entry_t *entry = htkeys_entries(keys);
+ for (Py_ssize_t idx = 0; idx < keys->nentries; idx++, entry++) {
+ Py_XINCREF(entry->identity);
+ Py_XINCREF(entry->key);
+ Py_XINCREF(entry->value);
+ }
+ md->keys = keys;
+ } else {
+ md->keys = &empty_htkeys;
+ }
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+}
+
+static inline PyObject *
+md_calc_identity(MultiDictObject *md, PyObject *key)
+{
+ if (md->is_ci) return _ci_key_to_identity(md->state, key);
+ return _key_to_identity(md->state, key);
+}
+
+static inline PyObject *
+md_calc_key(MultiDictObject *md, PyObject *key, PyObject *identity)
+{
+ if (md->is_ci) return _ci_arg_to_key(md->state, key, identity);
+ return _arg_to_key(md->state, key, identity);
+}
+
+static inline Py_ssize_t
+md_len(MultiDictObject *md)
+{
+ return md->used;
+}
+
+static inline PyObject *
+_md_ensure_key(MultiDictObject *md, entry_t *entry)
+{
+ assert(entry >= htkeys_entries(md->keys));
+ assert(entry < htkeys_entries(md->keys) + md->keys->nentries);
+ PyObject *key = md_calc_key(md, entry->key, entry->identity);
+ if (key == NULL) {
+ return NULL;
+ }
+ if (key != entry->key) {
+ Py_SETREF(entry->key, key);
+ } else {
+ Py_CLEAR(key);
+ }
+ return Py_NewRef(entry->key);
+}
+
+static inline int
+_md_add_with_hash_steal_refs(MultiDictObject *md, Py_hash_t hash,
+ PyObject *identity, PyObject *key,
+ PyObject *value)
+{
+ htkeys_t *keys = md->keys;
+ if (keys->usable <= 0 || keys == &empty_htkeys) {
+ /* Need to resize. */
+ if (_md_resize_for_insert(md) < 0) {
+ return -1;
+ }
+ keys = md->keys; // updated by resizing
+ }
+
+ Py_ssize_t hashpos = htkeys_find_empty_slot(keys, hash);
+ htkeys_set_index(keys, hashpos, keys->nentries);
+
+ entry_t *entry = htkeys_entries(keys) + keys->nentries;
+
+ entry->identity = identity;
+ entry->key = key;
+ entry->value = value;
+ entry->hash = hash;
+
+ md->version = NEXT_VERSION(md->state);
+ md->used += 1;
+ keys->usable -= 1;
+ keys->nentries += 1;
+ return 0;
+}
+
+static inline int
+_md_add_with_hash(MultiDictObject *md, Py_hash_t hash, PyObject *identity,
+ PyObject *key, PyObject *value)
+{
+ Py_INCREF(identity);
+ Py_INCREF(key);
+ Py_INCREF(value);
+ return _md_add_with_hash_steal_refs(md, hash, identity, key, value);
+}
+
+static inline int
+_md_add_for_upd_steal_refs(MultiDictObject *md, Py_hash_t hash,
+ PyObject *identity, PyObject *key, PyObject *value)
+{
+ htkeys_t *keys = md->keys;
+ if (keys->usable <= 0 || keys == &empty_htkeys) {
+ /* Need to resize. */
+ if (_md_resize_for_update(md) < 0) {
+ return -1;
+ }
+ keys = md->keys; // updated by resizing
+ }
+ Py_ssize_t hashpos = htkeys_find_empty_slot(keys, hash);
+ htkeys_set_index(keys, hashpos, keys->nentries);
+
+ entry_t *entry = htkeys_entries(keys) + keys->nentries;
+
+ entry->identity = identity;
+ entry->key = key;
+ entry->value = value;
+ entry->hash = -1;
+
+ md->version = NEXT_VERSION(md->state);
+ md->used += 1;
+ keys->usable -= 1;
+ keys->nentries += 1;
+ return 0;
+}
+
+static inline int
+_md_add_for_upd(MultiDictObject *md, Py_hash_t hash, PyObject *identity,
+ PyObject *key, PyObject *value)
+{
+ Py_INCREF(identity);
+ Py_INCREF(key);
+ Py_INCREF(value);
+ return _md_add_for_upd_steal_refs(md, hash, identity, key, value);
+}
+
+static inline int
+md_add(MultiDictObject *md, PyObject *key, PyObject *value)
+{
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+ int ret = _md_add_with_hash(md, hash, identity, key, value);
+ ASSERT_CONSISTENT(md, false);
+ Py_DECREF(identity);
+ return ret;
+fail:
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline int
+_md_del_at(MultiDictObject *md, size_t slot, entry_t *entry)
+{
+ htkeys_t *keys = md->keys;
+ assert(keys != &empty_htkeys);
+ Py_CLEAR(entry->identity);
+ Py_CLEAR(entry->key);
+ Py_CLEAR(entry->value);
+ htkeys_set_index(keys, slot, DKIX_DUMMY);
+ md->used -= 1;
+ return 0;
+}
+
+static inline int
+_md_del_at_for_upd(MultiDictObject *md, size_t slot, entry_t *entry)
+{
+ /* half deletion,
+ the entry could be replaced later with key and value set
+ or it will be finally cleaned up with identity=NULL,
+ used -= 1, and setting the hash to DKIX_DUMMY
+ in md_post_update()
+ */
+ assert(md->keys != &empty_htkeys);
+ Py_CLEAR(entry->key);
+ Py_CLEAR(entry->value);
+ return 0;
+}
+
+static inline int
+md_del(MultiDictObject *md, PyObject *key)
+{
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ bool found = false;
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(entry->identity, identity);
+ if (tmp < 0) {
+ goto fail;
+ }
+ if (tmp == 0) {
+ continue;
+ }
+
+ found = true;
+ if (_md_del_at(md, iter.slot, entry) < 0) {
+ goto fail;
+ }
+ }
+
+ if (!found) {
+ PyErr_SetObject(PyExc_KeyError, key);
+ goto fail;
+ } else {
+ md->version = NEXT_VERSION(md->state);
+ }
+ Py_DECREF(identity);
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+fail:
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline uint64_t
+md_version(MultiDictObject *md)
+{
+ return md->version;
+}
+
+static inline void
+md_init_pos(MultiDictObject *md, md_pos_t *pos)
+{
+ pos->pos = 0;
+ pos->version = md->version;
+}
+
+static inline int
+md_next(MultiDictObject *md, md_pos_t *pos, PyObject **pidentity,
+ PyObject **pkey, PyObject **pvalue)
+{
+ int ret = 0;
+
+ if (pos->version != md->version) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "MultiDict is changed during iteration");
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (pos->pos >= md->keys->nentries) {
+ goto cleanup;
+ }
+
+ entry_t *entries = htkeys_entries(md->keys);
+ entry_t *entry = entries + pos->pos;
+
+ while (entry->identity == NULL) {
+ pos->pos += 1;
+ if (pos->pos >= md->keys->nentries) {
+ goto cleanup;
+ }
+ entry += 1;
+ }
+
+ if (pidentity) {
+ *pidentity = Py_NewRef(entry->identity);
+ }
+
+ if (pkey) {
+ assert(entry->key != NULL);
+ *pkey = _md_ensure_key(md, entry);
+ if (*pkey == NULL) {
+ assert(PyErr_Occurred());
+ ret = -1;
+ goto cleanup;
+ }
+ }
+ if (pvalue) {
+ *pvalue = Py_NewRef(entry->value);
+ }
+
+ ++pos->pos;
+ return 1;
+cleanup:
+ if (pidentity) {
+ *pidentity = NULL;
+ }
+ if (pkey) {
+ *pkey = NULL;
+ }
+ if (pvalue) {
+ *pvalue = NULL;
+ }
+ return ret;
+}
+
+static inline int
+md_init_finder(MultiDictObject *md, PyObject *identity, md_finder_t *finder)
+{
+ finder->version = md->version;
+ finder->md = md;
+ finder->identity = identity;
+ finder->hash = _unicode_hash(identity);
+ if (finder->hash == -1) {
+ return -1;
+ }
+ htkeysiter_init(&finder->iter, finder->md->keys, finder->hash);
+ return 0;
+}
+
+static inline Py_ssize_t
+md_finder_slot(md_finder_t *finder)
+{
+ assert(finder->md != NULL);
+ return finder->iter.slot;
+}
+
+static inline Py_ssize_t
+md_finder_index(md_finder_t *finder)
+{
+ assert(finder->md != NULL);
+ assert(finder->iter.index >= 0);
+ return finder->iter.index;
+}
+
+static inline int
+md_find_next(md_finder_t *finder, PyObject **pkey, PyObject **pvalue)
+{
+ int ret = 0;
+ assert(finder->iter.keys == finder->md->keys);
+ if (finder->iter.keys != finder->md->keys ||
+ finder->version != finder->md->version) {
+ ret = -1;
+ PyErr_SetString(PyExc_RuntimeError,
+ "MultiDict is changed during iteration");
+ goto cleanup;
+ }
+
+ entry_t *entries = htkeys_entries(finder->md->keys);
+
+ for (; finder->iter.index != DKIX_EMPTY; htkeysiter_next(&finder->iter)) {
+ if (finder->iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + finder->iter.index;
+ if (entry->hash != finder->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(finder->identity, entry->identity);
+ if (tmp < 0) {
+ ret = -1;
+ goto cleanup;
+ }
+ if (tmp == 0) {
+ continue;
+ }
+
+ /* found, mark the entry as visited */
+ entry->hash = -1;
+
+ if (pkey) {
+ *pkey = _md_ensure_key(finder->md, entry);
+ if (*pkey == NULL) {
+ ret = -1;
+ goto cleanup;
+ }
+ }
+ if (pvalue) {
+ *pvalue = Py_NewRef(entry->value);
+ }
+ return 1;
+ }
+ ret = 0;
+cleanup:
+ if (pkey) {
+ *pkey = NULL;
+ }
+ if (pvalue) {
+ *pvalue = NULL;
+ }
+ return ret;
+}
+
+static inline void
+md_finder_cleanup(md_finder_t *finder)
+{
+ if (finder->md == NULL) {
+ return;
+ }
+
+ htkeysiter_init(&finder->iter, finder->md->keys, finder->hash);
+ entry_t *entries = htkeys_entries(finder->md->keys);
+ for (; finder->iter.index != DKIX_EMPTY; htkeysiter_next(&finder->iter)) {
+ if (finder->iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + finder->iter.index;
+ if (entry->hash == -1) {
+ entry->hash = finder->hash;
+ }
+ }
+ ASSERT_CONSISTENT(finder->md, false);
+ finder->md = NULL;
+}
+
+static inline int
+md_contains(MultiDictObject *md, PyObject *key, PyObject **pret)
+{
+ if (!PyUnicode_Check(key)) {
+ return 0;
+ }
+
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ Py_DECREF(identity);
+ if (pret != NULL) {
+ *pret = _md_ensure_key(md, entry);
+ if (*pret == NULL) {
+ goto fail;
+ }
+ }
+ return 1;
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ Py_DECREF(identity);
+ if (pret != NULL) {
+ *pret = NULL;
+ }
+ return 0;
+fail:
+ Py_XDECREF(identity);
+ if (pret != NULL) {
+ *pret = NULL;
+ }
+ return -1;
+}
+
+static inline int
+md_get_one(MultiDictObject *md, PyObject *key, PyObject **ret)
+{
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ Py_DECREF(identity);
+ *ret = Py_NewRef(entry->value);
+ return 1;
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ Py_DECREF(identity);
+ return 0;
+fail:
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline int
+md_get_all(MultiDictObject *md, PyObject *key, PyObject **ret)
+{
+ *ret = NULL;
+
+ md_finder_t finder = {0};
+
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ if (md_init_finder(md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
+
+ int tmp;
+ PyObject *value = NULL;
+
+ while ((tmp = md_find_next(&finder, NULL, &value)) > 0) {
+ if (*ret == NULL) {
+ *ret = PyList_New(1);
+ if (*ret == NULL) {
+ goto fail;
+ }
+ PyList_SET_ITEM(*ret, 0, value);
+ value = NULL; // stealed by PyList_SET_ITEM
+ } else {
+ if (PyList_Append(*ret, value) < 0) {
+ goto fail;
+ }
+ Py_CLEAR(value);
+ }
+ }
+ if (tmp < 0) {
+ goto fail;
+ }
+
+ md_finder_cleanup(&finder);
+ Py_DECREF(identity);
+ return *ret != NULL;
+fail:
+ md_finder_cleanup(&finder);
+ Py_XDECREF(identity);
+ Py_XDECREF(value);
+ Py_CLEAR(*ret);
+ return -1;
+}
+
+static inline int
+md_set_default(MultiDictObject *md, PyObject *key, PyObject *value,
+ PyObject **result)
+{
+ *result = NULL;
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ Py_DECREF(identity);
+ ASSERT_CONSISTENT(md, false);
+ *result = Py_NewRef(entry->value);
+ return 1;
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ if (_md_add_with_hash(md, hash, identity, key, value) < 0) {
+ goto fail;
+ }
+
+ Py_DECREF(identity);
+ ASSERT_CONSISTENT(md, false);
+ *result = Py_NewRef(value);
+ return 0;
+fail:
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline int
+md_pop_one(MultiDictObject *md, PyObject *key, PyObject **ret)
+{
+ PyObject *value = NULL;
+
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ value = Py_NewRef(entry->value);
+ if (_md_del_at(md, iter.slot, entry) < 0) {
+ goto fail;
+ }
+ Py_DECREF(identity);
+ *ret = value;
+ md->version = NEXT_VERSION(md->state);
+ ASSERT_CONSISTENT(md, false);
+ return 1;
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+fail:
+ Py_XDECREF(value);
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline int
+md_pop_all(MultiDictObject *md, PyObject *key, PyObject **ret)
+{
+ PyObject *lst = NULL;
+
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ if (md_len(md) == 0) {
+ Py_DECREF(identity);
+ return 0;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index < 0) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ if (lst == NULL) {
+ lst = PyList_New(1);
+ if (lst == NULL) {
+ goto fail;
+ }
+ if (PyList_SetItem(lst, 0, Py_NewRef(entry->value)) < 0) {
+ goto fail;
+ }
+ } else if (PyList_Append(lst, entry->value) < 0) {
+ goto fail;
+ }
+ if (_md_del_at(md, iter.slot, entry) < 0) {
+ goto fail;
+ }
+ md->version = NEXT_VERSION(md->state);
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ *ret = lst;
+ Py_DECREF(identity);
+ ASSERT_CONSISTENT(md, false);
+ return lst != NULL;
+fail:
+ Py_XDECREF(identity);
+ Py_XDECREF(lst);
+ return -1;
+}
+
+static inline PyObject *
+md_pop_item(MultiDictObject *md)
+{
+ if (md->used == 0) {
+ PyErr_SetString(PyExc_KeyError, "empty multidict");
+ return NULL;
+ }
+
+ entry_t *entries = htkeys_entries(md->keys);
+
+ Py_ssize_t pos = md->keys->nentries - 1;
+ entry_t *entry = entries + pos;
+ while (pos >= 0 && entry->identity == NULL) {
+ pos--;
+ entry--;
+ }
+ assert(pos >= 0);
+
+ PyObject *key = md_calc_key(md, entry->key, entry->identity);
+ if (key == NULL) {
+ return NULL;
+ }
+ PyObject *ret = PyTuple_Pack(2, key, entry->value);
+ Py_CLEAR(key);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, entry->hash);
+
+ for (; iter.index != pos; htkeysiter_next(&iter)) {
+ }
+ if (_md_del_at(md, iter.slot, entry) < 0) {
+ return NULL;
+ }
+ md->version = NEXT_VERSION(md->state);
+ ASSERT_CONSISTENT(md, false);
+ return ret;
+}
+
+static inline int
+_md_replace(MultiDictObject *md, PyObject *key, PyObject *value,
+ PyObject *identity, Py_hash_t hash)
+{
+ int found = 0;
+ md_finder_t finder = {0};
+ if (md_init_finder(md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
+ entry_t *entries = htkeys_entries(md->keys);
+
+ int tmp;
+
+ // don't grab neither key nor value but use the calculated index
+ while ((tmp = md_find_next(&finder, NULL, NULL)) > 0) {
+ entry_t *entry = entries + md_finder_index(&finder);
+ if (!found) {
+ found = 1;
+ Py_SETREF(entry->key, Py_NewRef(key));
+ Py_SETREF(entry->value, Py_NewRef(value));
+ entry->hash = -1;
+ } else {
+ if (_md_del_at(md, md_finder_slot(&finder), entry) < 0) {
+ goto fail;
+ }
+ }
+ }
+ if (tmp < 0) {
+ goto fail;
+ }
+
+ md_finder_cleanup(&finder);
+ if (!found) {
+ if (_md_add_with_hash(md, hash, identity, key, value) < 0) {
+ goto fail;
+ }
+ return 0;
+ } else {
+ md->version = NEXT_VERSION(md->state);
+ return 0;
+ }
+fail:
+ md_finder_cleanup(&finder);
+ return -1;
+}
+
+static inline int
+md_replace(MultiDictObject *md, PyObject *key, PyObject *value)
+{
+ PyObject *identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ int ret = _md_replace(md, key, value, identity, hash);
+ Py_DECREF(identity);
+ ASSERT_CONSISTENT(md, false);
+ return ret;
+fail:
+ Py_XDECREF(identity);
+ return -1;
+}
+
+static inline int
+_md_update(MultiDictObject *md, Py_hash_t hash, PyObject *identity,
+ PyObject *key, PyObject *value)
+{
+ htkeysiter_t iter;
+ htkeysiter_init(&iter, md->keys, hash);
+ entry_t *entries = htkeys_entries(md->keys);
+ bool found = false;
+
+ for (; iter.index != DKIX_EMPTY; htkeysiter_next(&iter)) {
+ if (iter.index == DKIX_DUMMY) {
+ continue;
+ }
+ entry_t *entry = entries + iter.index;
+ if (hash != entry->hash) {
+ continue;
+ }
+ int tmp = _str_cmp(identity, entry->identity);
+ if (tmp > 0) {
+ if (!found) {
+ found = true;
+ if (entry->key == NULL) {
+ /* entry->key could be NULL if it was deleted
+ by the previous _md_update call during the iteration
+ in md_update_from* functions. */
+ assert(entry->value == NULL);
+ entry->key = Py_NewRef(key);
+ entry->value = Py_NewRef(value);
+ } else {
+ Py_SETREF(entry->key, Py_NewRef(key));
+ Py_SETREF(entry->value, Py_NewRef(value));
+ }
+ entry->hash = -1;
+ } else {
+ if (_md_del_at_for_upd(md, iter.slot, entry) < 0) {
+ goto fail;
+ }
+ }
+ } else if (tmp < 0) {
+ goto fail;
+ }
+ }
+
+ if (!found) {
+ if (_md_add_for_upd(md, hash, identity, key, value) < 0) {
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ return -1;
+}
+
+static inline int
+md_post_update(MultiDictObject *md)
+{
+ htkeys_t *keys = md->keys;
+ size_t num_slots = htkeys_nslots(keys);
+ entry_t *entries = htkeys_entries(keys);
+ for (size_t slot = 0; slot < num_slots; slot++) {
+ Py_ssize_t index = htkeys_get_index(keys, slot);
+ if (index >= 0) {
+ entry_t *entry = entries + index;
+ if (entry->key == NULL) {
+ /* the entry is marked for deletion during .update() call
+ and not replaced with a new value */
+ Py_CLEAR(entry->identity);
+ htkeys_set_index(keys, slot, DKIX_DUMMY);
+ md->used -= 1;
+ }
+ if (entry->hash == -1) {
+ entry->hash = _unicode_hash(entry->identity);
+ if (entry->hash == -1) {
+ // hash of string always exists but still
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static inline int
+md_update_from_ht(MultiDictObject *md, MultiDictObject *other, bool update)
+{
+ Py_ssize_t pos;
+ Py_hash_t hash;
+ PyObject *identity = NULL;
+ PyObject *key = NULL;
+ bool recalc_identity = md->is_ci != other->is_ci;
+
+ if (other->used == 0) {
+ return 0;
+ }
+
+ entry_t *entries = htkeys_entries(other->keys);
+
+ for (pos = 0; pos < other->keys->nentries; pos++) {
+ entry_t *entry = entries + pos;
+ if (entry->identity == NULL) {
+ continue;
+ }
+ if (recalc_identity) {
+ identity = md_calc_identity(md, entry->key);
+ if (identity == NULL) {
+ goto fail;
+ }
+ hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+ /* materialize key */
+ key = md_calc_key(other, entry->key, identity);
+ if (key == NULL) {
+ goto fail;
+ }
+ } else {
+ identity = entry->identity;
+ hash = entry->hash;
+ key = entry->key;
+ }
+ if (update) {
+ if (_md_update(md, hash, identity, key, entry->value) < 0) {
+ goto fail;
+ }
+ } else {
+ if (_md_add_with_hash(md, hash, identity, key, entry->value) < 0) {
+ goto fail;
+ }
+ }
+ if (recalc_identity) {
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ }
+ }
+ return 0;
+fail:
+ if (recalc_identity) {
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ }
+ return -1;
+}
+
+static inline int
+md_update_from_dict(MultiDictObject *md, PyObject *kwds, bool update)
+{
+ Py_ssize_t pos = 0;
+ PyObject *identity = NULL;
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+
+ assert(PyDict_CheckExact(kwds));
+
+ // PyDict_Next returns borrowed refs
+ while (PyDict_Next(kwds, &pos, &key, &value)) {
+ Py_INCREF(key);
+ identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+ if (update) {
+ if (_md_update(md, hash, identity, key, value) < 0) {
+ goto fail;
+ }
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ } else {
+ int tmp = _md_add_with_hash_steal_refs(
+ md, hash, identity, key, Py_NewRef(value));
+ if (tmp < 0) {
+ Py_DECREF(value);
+ goto fail;
+ }
+ identity = NULL;
+ key = NULL;
+ value = NULL;
+ }
+ }
+ return 0;
+fail:
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ return -1;
+}
+
+static inline void
+_err_not_sequence(Py_ssize_t i)
+{
+ PyErr_Format(PyExc_TypeError,
+ "multidict cannot convert sequence element #%zd"
+ " to a sequence",
+ i);
+}
+
+static inline void
+_err_bad_length(Py_ssize_t i, Py_ssize_t n)
+{
+ PyErr_Format(PyExc_ValueError,
+ "multidict update sequence element #%zd "
+ "has length %zd; 2 is required",
+ i,
+ n);
+}
+
+static inline void
+_err_cannot_fetch(Py_ssize_t i, const char *name)
+{
+ PyErr_Format(PyExc_ValueError,
+ "multidict update sequence element #%zd's "
+ "%s could not be fetched",
+ name,
+ i);
+}
+
+static int
+_md_parse_item(Py_ssize_t i, PyObject *item, PyObject **pkey,
+ PyObject **pvalue)
+{
+ Py_ssize_t n;
+
+ if (PyTuple_CheckExact(item)) {
+ n = PyTuple_GET_SIZE(item);
+ if (n != 2) {
+ _err_bad_length(i, n);
+ goto fail;
+ }
+ *pkey = Py_NewRef(PyTuple_GET_ITEM(item, 0));
+ *pvalue = Py_NewRef(PyTuple_GET_ITEM(item, 1));
+ } else if (PyList_CheckExact(item)) {
+ n = PyList_GET_SIZE(item);
+ if (n != 2) {
+ _err_bad_length(i, n);
+ goto fail;
+ }
+ *pkey = Py_NewRef(PyList_GET_ITEM(item, 0));
+ *pvalue = Py_NewRef(PyList_GET_ITEM(item, 1));
+ } else {
+ if (!PySequence_Check(item)) {
+ _err_not_sequence(i);
+ goto fail;
+ }
+ n = PySequence_Size(item);
+ if (n != 2) {
+ _err_bad_length(i, n);
+ goto fail;
+ }
+ *pkey = PySequence_ITEM(item, 0);
+ *pvalue = PySequence_ITEM(item, 1);
+ if (*pkey == NULL) {
+ _err_cannot_fetch(i, "key");
+ goto fail;
+ }
+ if (*pvalue == NULL) {
+ _err_cannot_fetch(i, "value");
+ goto fail;
+ }
+ }
+ return 0;
+fail:
+ Py_CLEAR(*pkey);
+ Py_CLEAR(*pvalue);
+ return -1;
+}
+
+static inline int
+md_update_from_seq(MultiDictObject *md, PyObject *seq, bool update)
+{
+ PyObject *it = NULL;
+ PyObject *item = NULL; // seq[i]
+
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+ PyObject *identity = NULL;
+
+ Py_ssize_t i;
+ Py_ssize_t size = -1;
+
+ enum { LIST, TUPLE, ITER } kind;
+
+ if (PyList_CheckExact(seq)) {
+ kind = LIST;
+ size = PyList_GET_SIZE(seq);
+ if (size == 0) {
+ return 0;
+ }
+ } else if (PyTuple_CheckExact(seq)) {
+ kind = TUPLE;
+ size = PyTuple_GET_SIZE(seq);
+ if (size == 0) {
+ return 0;
+ }
+ } else {
+ kind = ITER;
+ it = PyObject_GetIter(seq);
+ if (it == NULL) {
+ goto fail;
+ }
+ }
+
+ for (i = 0;; ++i) { // i - index into seq of current element
+ switch (kind) {
+ case LIST:
+ if (i >= size) {
+ goto exit;
+ }
+ item = PyList_GET_ITEM(seq, i);
+ if (item == NULL) {
+ goto fail;
+ }
+ Py_INCREF(item);
+ break;
+ case TUPLE:
+ if (i >= size) {
+ goto exit;
+ }
+ item = PyTuple_GET_ITEM(seq, i);
+ if (item == NULL) {
+ goto fail;
+ }
+ Py_INCREF(item);
+ break;
+ case ITER:
+ item = PyIter_Next(it);
+ if (item == NULL) {
+ if (PyErr_Occurred()) {
+ goto fail;
+ }
+ goto exit;
+ }
+ }
+
+ if (_md_parse_item(i, item, &key, &value) < 0) {
+ goto fail;
+ }
+
+ identity = md_calc_identity(md, key);
+ if (identity == NULL) {
+ goto fail;
+ }
+
+ Py_hash_t hash = _unicode_hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+
+ if (update) {
+ if (_md_update(md, hash, identity, key, value) < 0) {
+ goto fail;
+ }
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ } else {
+ if (_md_add_with_hash_steal_refs(md, hash, identity, key, value) <
+ 0) {
+ goto fail;
+ }
+ identity = NULL;
+ key = NULL;
+ value = NULL;
+ }
+ Py_CLEAR(item);
+ }
+
+exit:
+ Py_CLEAR(it);
+ return 0;
+
+fail:
+ Py_CLEAR(identity);
+ Py_CLEAR(it);
+ Py_CLEAR(item);
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ return -1;
+}
+
+static inline int
+md_eq(MultiDictObject *md, MultiDictObject *other)
+{
+ if (md == other) {
+ return 1;
+ }
+
+ if (md_len(md) != md_len(other)) {
+ return 0;
+ }
+
+ Py_ssize_t pos1 = 0;
+ Py_ssize_t pos2 = 0;
+
+ entry_t *lft_entries = htkeys_entries(md->keys);
+ entry_t *rht_entries = htkeys_entries(other->keys);
+ for (;;) {
+ if (pos1 >= md->keys->nentries || pos2 >= other->keys->nentries) {
+ return 1;
+ }
+ entry_t *entry1 = lft_entries + pos1;
+ if (entry1->identity == NULL) {
+ pos1++;
+ continue;
+ }
+ entry_t *entry2 = rht_entries + pos2;
+ if (entry2->identity == NULL) {
+ pos2++;
+ continue;
+ }
+
+ if (entry1->hash != entry2->hash) {
+ return 0;
+ }
+
+ int cmp = _str_cmp(entry1->identity, entry2->identity);
+ if (cmp < 0) {
+ return -1;
+ };
+ if (cmp == 0) {
+ return 0;
+ }
+
+ cmp = PyObject_RichCompareBool(entry1->value, entry2->value, Py_EQ);
+ if (cmp < 0) {
+ return -1;
+ };
+ if (cmp == 0) {
+ return 0;
+ }
+ pos1++;
+ pos2++;
+ }
+ return 1;
+}
+
+static inline int
+md_eq_to_mapping(MultiDictObject *md, PyObject *other)
+{
+ PyObject *key = NULL;
+ PyObject *avalue = NULL;
+ PyObject *bvalue;
+
+ Py_ssize_t other_len;
+
+ if (!PyMapping_Check(other)) {
+ PyErr_Format(PyExc_TypeError,
+ "other argument must be a mapping, not %s",
+ Py_TYPE(other)->tp_name);
+ return -1;
+ }
+
+ other_len = PyMapping_Size(other);
+ if (other_len < 0) {
+ return -1;
+ }
+ if (md_len(md) != other_len) {
+ return 0;
+ }
+
+ md_pos_t pos;
+ md_init_pos(md, &pos);
+
+ for (;;) {
+ int ret = md_next(md, &pos, NULL, &key, &avalue);
+ if (ret < 0) {
+ return -1;
+ }
+ if (ret == 0) {
+ break;
+ }
+ ret = PyMapping_GetOptionalItem(other, key, &bvalue);
+ Py_CLEAR(key);
+ if (ret < 0) {
+ Py_CLEAR(avalue);
+ return -1;
+ }
+
+ if (bvalue == NULL) {
+ Py_CLEAR(avalue);
+ return 0;
+ }
+
+ int eq = PyObject_RichCompareBool(avalue, bvalue, Py_EQ);
+ Py_CLEAR(bvalue);
+ Py_CLEAR(avalue);
+
+ if (eq <= 0) {
+ return eq;
+ }
+ }
+
+ return 1;
+}
+
+static inline PyObject *
+md_repr(MultiDictObject *md, PyObject *name, bool show_keys, bool show_values)
+{
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+
+ bool comma = false;
+ uint64_t version = md->version;
+
+ PyUnicodeWriter *writer = PyUnicodeWriter_Create(1024);
+ if (writer == NULL) return NULL;
+
+ if (PyUnicodeWriter_WriteChar(writer, '<') < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteStr(writer, name) < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteChar(writer, '(') < 0) {
+ goto fail;
+ }
+
+ entry_t *entries = htkeys_entries(md->keys);
+
+ for (Py_ssize_t pos = 0; pos < md->keys->nentries; ++pos) {
+ if (version != md->version) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "MultiDict changed during iteration");
+ return NULL;
+ }
+ entry_t *entry = entries + pos;
+ if (entry->identity == NULL) {
+ continue;
+ }
+ key = Py_NewRef(entry->key);
+ value = Py_NewRef(entry->value);
+
+ if (comma) {
+ if (PyUnicodeWriter_WriteChar(writer, ',') < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) {
+ goto fail;
+ }
+ }
+ if (show_keys) {
+ if (PyUnicodeWriter_WriteChar(writer, '\'') < 0) {
+ goto fail;
+ }
+ /* Don't need to convert key to istr, the text is the same*/
+ if (PyUnicodeWriter_WriteStr(writer, key) < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteChar(writer, '\'') < 0) {
+ goto fail;
+ }
+ }
+ if (show_keys && show_values) {
+ if (PyUnicodeWriter_WriteChar(writer, ':') < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteChar(writer, ' ') < 0) {
+ goto fail;
+ }
+ }
+ if (show_values) {
+ if (PyUnicodeWriter_WriteRepr(writer, value) < 0) {
+ goto fail;
+ }
+ }
+
+ comma = true;
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ }
+
+ if (PyUnicodeWriter_WriteChar(writer, ')') < 0) {
+ goto fail;
+ }
+ if (PyUnicodeWriter_WriteChar(writer, '>') < 0) {
+ goto fail;
+ }
+ return PyUnicodeWriter_Finish(writer);
+fail:
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ PyUnicodeWriter_Discard(writer);
+ return NULL;
+}
+
+/***********************************************************************/
+
+static inline int
+md_traverse(MultiDictObject *md, visitproc visit, void *arg)
+{
+ if (md->used == 0) {
+ return 0;
+ }
+
+ entry_t *entries = htkeys_entries(md->keys);
+ for (Py_ssize_t pos = 0; pos < md->keys->nentries; pos++) {
+ entry_t *entry = entries + pos;
+ if (entry->identity != NULL) {
+ Py_VISIT(entry->key);
+ Py_VISIT(entry->value);
+ }
+ }
+
+ return 0;
+}
+
+static inline int
+md_clear(MultiDictObject *md)
+{
+ if (md->used == 0) {
+ return 0;
+ }
+ md->version = NEXT_VERSION(md->state);
+
+ entry_t *entries = htkeys_entries(md->keys);
+ for (Py_ssize_t pos = 0; pos < md->keys->nentries; pos++) {
+ entry_t *entry = entries + pos;
+ if (entry->identity != NULL) {
+ Py_CLEAR(entry->identity);
+ Py_CLEAR(entry->key);
+ Py_CLEAR(entry->value);
+ }
+ }
+
+ md->used = 0;
+ if (md->keys != &empty_htkeys) {
+ htkeys_free(md->keys);
+ md->keys = &empty_htkeys;
+ }
+ ASSERT_CONSISTENT(md, false);
+ return 0;
+}
+
+static inline int
+_md_check_consistency(MultiDictObject *md, bool update)
+{
+ // ASSERT_WORLD_STOPPED_OR_DICT_LOCKED(op);
+
+#define CHECK(expr) assert(expr)
+ // do { if (!(expr)) { assert(0 && Py_STRINGIFY(expr)); } } while (0)
+
+ htkeys_t *keys = md->keys;
+ CHECK(keys != NULL);
+ Py_ssize_t calc_usable = USABLE_FRACTION(htkeys_nslots(keys));
+
+ // In the free-threaded build, shared keys may be concurrently modified,
+ // so use atomic loads.
+ Py_ssize_t usable = keys->usable;
+ Py_ssize_t nentries = keys->nentries;
+
+ CHECK(0 <= md->used && md->used <= calc_usable);
+ CHECK(0 <= usable && usable <= calc_usable);
+ CHECK(0 <= nentries && nentries <= calc_usable);
+ CHECK(usable + nentries <= calc_usable);
+
+ for (Py_ssize_t i = 0; i < htkeys_nslots(keys); i++) {
+ Py_ssize_t ix = htkeys_get_index(keys, i);
+ CHECK(DKIX_DUMMY <= ix && ix <= calc_usable);
+ }
+
+ entry_t *entries = htkeys_entries(keys);
+ for (Py_ssize_t i = 0; i < calc_usable; i++) {
+ entry_t *entry = &entries[i];
+ PyObject *identity = entry->identity;
+
+ if (identity != NULL) {
+ if (!update) {
+ CHECK(entry->hash != -1);
+ CHECK(entry->key != NULL);
+ CHECK(entry->value != NULL);
+ } else {
+ if (entry->key == NULL) {
+ CHECK(entry->value == NULL);
+ } else {
+ CHECK(entry->value != NULL);
+ }
+ }
+
+ CHECK(PyUnicode_CheckExact(identity));
+ if (entry->hash != -1) {
+ Py_hash_t hash = _unicode_hash(identity);
+ CHECK(entry->hash == hash);
+ }
+ }
+ }
+ return 1;
+
+#undef CHECK
+}
+
+static inline int
+_md_dump(MultiDictObject *md)
+{
+ htkeys_t *keys = md->keys;
+ printf("Dump %p [%ld from %ld usable %ld nentries %ld]\n",
+ (void *)md,
+ md->used,
+ htkeys_nslots(keys),
+ keys->usable,
+ keys->nentries);
+ for (Py_ssize_t i = 0; i < htkeys_nslots(keys); i++) {
+ Py_ssize_t ix = htkeys_get_index(keys, i);
+ printf(" %ld -> %ld\n", i, ix);
+ }
+ printf(" --------\n");
+ entry_t *entries = htkeys_entries(keys);
+ for (Py_ssize_t i = 0; i < keys->nentries; i++) {
+ entry_t *entry = &entries[i];
+ PyObject *identity = entry->identity;
+
+ if (identity == NULL) {
+ printf(" %ld [deleted]\n", i);
+ } else {
+ printf(" %ld h=%20ld, i=\'", i, entry->hash);
+ PyObject_Print(entry->identity, stdout, Py_PRINT_RAW);
+ printf("\', k=\'");
+ PyObject_Print(entry->key, stdout, Py_PRINT_RAW);
+ printf("\', v=\'");
+ PyObject_Print(entry->value, stdout, Py_PRINT_RAW);
+ printf("\'\n");
+ }
+ }
+ printf("\n");
+ return 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/contrib/python/multidict/multidict/_multilib/htkeys.h b/contrib/python/multidict/multidict/_multilib/htkeys.h
new file mode 100644
index 00000000000..a13d5fb41b0
--- /dev/null
+++ b/contrib/python/multidict/multidict/_multilib/htkeys.h
@@ -0,0 +1,414 @@
+#include "pythoncapi_compat.h"
+
+#ifndef _MULTIDICT_HTKEYS_H
+#define _MULTIDICT_HTKEYS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+#include <stdbool.h>
+
+/* Implementation note.
+identity always has exact PyUnicode_Type type, not a subclass.
+It guarantees that identity hashing and comparison never calls
+Python code back, and these operations has no weird side effects,
+e.g. deletion the key from multidict.
+
+Taking into account the fact that all multidict operations except
+repr(md), repr(md_proxy), or repr(view) never access to the key
+itself but identity instead, borrowed references during iteration
+over pair_list for, e.g., md.get() or md.pop() is safe.
+*/
+
+typedef struct entry {
+ Py_hash_t hash;
+ PyObject *identity;
+ PyObject *key;
+ PyObject *value;
+} entry_t;
+
+#define DKIX_EMPTY (-1) /* empty (never used) slot */
+#define DKIX_DUMMY (-2) /* deleted slot */
+
+#define HT_LOG_MINSIZE 3
+#define HT_MINSIZE 8
+#define HT_PERTURB_SHIFT 5
+
+typedef struct _htkeys {
+ /* Size of the hash table (indices). It must be a power of 2. */
+ uint8_t log2_size;
+
+ /* Size of the hash table (indices) by bytes. */
+ uint8_t log2_index_bytes;
+
+ /* Number of usable entries in dk_entries. */
+ Py_ssize_t usable;
+
+ /* Number of used entries in dk_entries. */
+ Py_ssize_t nentries;
+
+ /* Actual hash table of dk_size entries. It holds indices in dk_entries,
+ or DKIX_EMPTY(-1) or DKIX_DUMMY(-2).
+
+ Indices must be: 0 <= indice < USABLE_FRACTION(dk_size).
+
+ The size in bytes of an indice depends on dk_size:
+
+ - 1 byte if htkeys_nslots() <= 0xff (char*)
+ - 2 bytes if htkeys_nslots() <= 0xffff (int16_t*)
+ - 4 bytes if htkeys_nslots() <= 0xffffffff (int32_t*)
+ - 8 bytes otherwise (int64_t*)
+
+ Dynamically sized, SIZEOF_VOID_P is minimum. */
+ char indices[]; /* char is required to avoid strict aliasing. */
+
+} htkeys_t;
+
+#if SIZEOF_VOID_P > 4
+static inline Py_ssize_t
+htkeys_nslots(const htkeys_t *keys)
+{
+ return ((int64_t)1) << keys->log2_size;
+}
+#else
+static inline Py_ssize_t
+htkeys_nslots(const htkeys_t *keys)
+{
+ return 1 << keys->log2_size;
+}
+#endif
+
+static inline Py_ssize_t
+htkeys_mask(const htkeys_t *keys)
+{
+ return htkeys_nslots(keys) - 1;
+}
+
+static inline entry_t *
+htkeys_entries(const htkeys_t *dk)
+{
+ int8_t *indices = (int8_t *)(dk->indices);
+ size_t index = (size_t)1 << dk->log2_index_bytes;
+ return (entry_t *)(&indices[index]);
+}
+
+#define LOAD_INDEX(keys, size, idx) \
+ ((const int##size##_t *)(keys->indices))[idx]
+#define STORE_INDEX(keys, size, idx, value) \
+ ((int##size##_t *)(keys->indices))[idx] = (int##size##_t)value
+
+/* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
+static inline Py_ssize_t
+htkeys_get_index(const htkeys_t *keys, Py_ssize_t i)
+{
+ uint8_t log2size = keys->log2_size;
+ Py_ssize_t ix;
+
+ if (log2size < 8) {
+ ix = LOAD_INDEX(keys, 8, i);
+ } else if (log2size < 16) {
+ ix = LOAD_INDEX(keys, 16, i);
+ }
+#if SIZEOF_VOID_P > 4
+ else if (log2size >= 32) {
+ ix = LOAD_INDEX(keys, 64, i);
+ }
+#endif
+ else {
+ ix = LOAD_INDEX(keys, 32, i);
+ }
+ assert(ix >= DKIX_DUMMY);
+ return ix;
+}
+
+/* write to indices. */
+static inline void
+htkeys_set_index(htkeys_t *keys, Py_ssize_t i, Py_ssize_t ix)
+{
+ uint8_t log2size = keys->log2_size;
+
+ assert(ix >= DKIX_DUMMY);
+
+ if (log2size < 8) {
+ assert(ix <= 0x7f);
+ STORE_INDEX(keys, 8, i, ix);
+ } else if (log2size < 16) {
+ assert(ix <= 0x7fff);
+ STORE_INDEX(keys, 16, i, ix);
+ }
+#if SIZEOF_VOID_P > 4
+ else if (log2size >= 32) {
+ STORE_INDEX(keys, 64, i, ix);
+ }
+#endif
+ else {
+ assert(ix <= 0x7fffffff);
+ STORE_INDEX(keys, 32, i, ix);
+ }
+}
+
+/* USABLE_FRACTION is the maximum dictionary load.
+ * Increasing this ratio makes dictionaries more dense resulting in more
+ * collisions. Decreasing it improves sparseness at the expense of spreading
+ * indices over more cache lines and at the cost of total memory consumed.
+ *
+ * USABLE_FRACTION must obey the following:
+ * (0 < USABLE_FRACTION(n) < n) for all n >= 2
+ *
+ * USABLE_FRACTION should be quick to calculate.
+ * Fractions around 1/2 to 2/3 seem to work well in practice.
+ */
+static inline Py_ssize_t
+USABLE_FRACTION(Py_ssize_t n)
+{
+ return (n << 1) / 3;
+}
+
+// Return the index of the most significant 1 bit in 'x'. This is the smallest
+// integer k such that x < 2**k. Equivalent to floor(log2(x)) + 1 for x != 0.
+static inline int
+_ht_bit_length(unsigned long x)
+{
+#if (defined(__clang__) || defined(__GNUC__))
+ if (x != 0) {
+ // __builtin_clzl() is available since GCC 3.4.
+ // Undefined behavior for x == 0.
+ return (int)sizeof(unsigned long) * 8 - __builtin_clzl(x);
+ } else {
+ return 0;
+ }
+#elif defined(_MSC_VER)
+ // _BitScanReverse() is documented to search 32 bits.
+ Py_BUILD_ASSERT(sizeof(unsigned long) <= 4);
+ unsigned long msb;
+ if (_BitScanReverse(&msb, x)) {
+ return (int)msb + 1;
+ } else {
+ return 0;
+ }
+#else
+ const int BIT_LENGTH_TABLE[32] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
+ int msb = 0;
+ while (x >= 32) {
+ msb += 6;
+ x >>= 6;
+ }
+ msb += BIT_LENGTH_TABLE[x];
+ return msb;
+#endif
+}
+
+/* Find the smallest dk_size >= minsize. */
+static inline uint8_t
+calculate_log2_keysize(Py_ssize_t minsize)
+{
+#if SIZEOF_LONG == SIZEOF_SIZE_T
+ minsize = (minsize | HT_MINSIZE) - 1;
+ return _ht_bit_length(minsize | (HT_MINSIZE - 1));
+#elif defined(_MSC_VER)
+ // On 64bit Windows, sizeof(long) == 4.
+ minsize = (minsize | HT_MINSIZE) - 1;
+ unsigned long msb;
+ _BitScanReverse64(&msb, (uint64_t)minsize);
+ return (uint8_t)(msb + 1);
+#else
+ uint8_t log2_size;
+ for (log2_size = HT_LOG_MINSIZE; (((Py_ssize_t)1) << log2_size) < minsize;
+ log2_size++)
+ ;
+ return log2_size;
+#endif
+}
+
+/* estimate_keysize is reverse function of USABLE_FRACTION.
+ *
+ * This can be used to reserve enough size to insert n entries without
+ * resizing.
+ */
+static inline uint8_t
+estimate_log2_keysize(Py_ssize_t n)
+{
+ return calculate_log2_keysize((n * 3 + 1) / 2);
+}
+
+/* This immutable, empty PyDictKeysObject is used for PyDict_Clear()
+ * (which cannot fail and thus can do no allocation).
+ *
+ * See https://github.com/python/cpython/pull/127568#discussion_r1868070614
+ * for the rationale of using log2_index_bytes=3 instead of 0.
+ */
+static htkeys_t empty_htkeys = {
+ 0, /* log2_size */
+ 3, /* log2_index_bytes */
+ 0, /* usable (immutable) */
+ 0, /* nentries */
+ {DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY,
+ DKIX_EMPTY}, /* indices */
+};
+
+static inline Py_ssize_t
+htkeys_sizeof(htkeys_t *keys)
+{
+ Py_ssize_t usable = USABLE_FRACTION((size_t)1 << keys->log2_size);
+ return (sizeof(htkeys_t) + ((size_t)1 << keys->log2_index_bytes) +
+ sizeof(entry_t) * usable);
+}
+
+static inline htkeys_t *
+htkeys_new(uint8_t log2_size)
+{
+ assert(log2_size >= HT_LOG_MINSIZE);
+
+ Py_ssize_t usable = USABLE_FRACTION(((size_t)1) << log2_size);
+ uint8_t log2_bytes;
+
+ if (log2_size < 8) {
+ log2_bytes = log2_size;
+ } else if (log2_size < 16) {
+ log2_bytes = log2_size + 1;
+ }
+#if SIZEOF_VOID_P > 4
+ else if (log2_size >= 32) {
+ log2_bytes = log2_size + 3;
+ }
+#endif
+ else {
+ log2_bytes = log2_size + 2;
+ }
+
+ htkeys_t *keys = NULL;
+ /* TODO: CPython uses freelist of key objects with unicode type
+ and log2_size == PyDict_LOG_MINSIZE */
+ keys = PyMem_Malloc(sizeof(htkeys_t) + ((size_t)1 << log2_bytes) +
+ sizeof(entry_t) * usable);
+ if (keys == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ keys->log2_size = log2_size;
+ keys->log2_index_bytes = log2_bytes;
+ keys->nentries = 0;
+ keys->usable = usable;
+ memset(&keys->indices[0], 0xff, ((size_t)1 << log2_bytes));
+ memset(
+ &keys->indices[(size_t)1 << log2_bytes], 0, sizeof(entry_t) * usable);
+ return keys;
+}
+
+static inline void
+htkeys_free(htkeys_t *dk)
+{
+ /* TODO: CPython uses freelist of key objects with unicode type
+ and log2_size == PyDict_LOG_MINSIZE */
+ PyMem_Free(dk);
+}
+
+static inline Py_hash_t
+_unicode_hash(PyObject *o)
+{
+ assert(PyUnicode_CheckExact(o));
+ PyASCIIObject *ascii = (PyASCIIObject *)o;
+ if (ascii->hash != -1) {
+ return ascii->hash;
+ }
+ return PyUnicode_Type.tp_hash(o);
+}
+
+/*
+Internal routine used by ht_resize() to build a hashtable of entries.
+*/
+static inline int
+htkeys_build_indices(htkeys_t *keys, entry_t *ep, Py_ssize_t n, bool update)
+{
+ size_t mask = htkeys_mask(keys);
+ for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
+ Py_hash_t hash = ep->hash;
+ if (update) {
+ if (hash == -1) {
+ hash = _unicode_hash(ep->identity);
+ if (hash == -1) {
+ return -1;
+ }
+ }
+ } else {
+ assert(hash != -1);
+ }
+ size_t i = hash & mask;
+ for (size_t perturb = hash; htkeys_get_index(keys, i) != DKIX_EMPTY;) {
+ perturb >>= HT_PERTURB_SHIFT;
+ i = mask & (i * 5 + perturb + 1);
+ }
+ htkeys_set_index(keys, i, ix);
+ }
+ return 0;
+}
+
+/* Internal function to find slot for an item from its hash
+ when it is known that the key is not present in the dict.
+ */
+static inline Py_ssize_t
+htkeys_find_empty_slot(htkeys_t *keys, Py_hash_t hash)
+{
+ const size_t mask = htkeys_mask(keys);
+ size_t i = hash & mask;
+ Py_ssize_t ix = htkeys_get_index(keys, i);
+ for (size_t perturb = hash; ix >= 0 || ix == DKIX_DUMMY;) {
+ perturb >>= HT_PERTURB_SHIFT;
+ i = (i * 5 + perturb + 1) & mask;
+ ix = htkeys_get_index(keys, i);
+ }
+ return i;
+}
+
+/* Iterator over slots/indexes for given hash.
+ N.B. The iterator MIGHT return the same slot
+ multiple times, eiter consequently (1, 2, 2, 3)
+ or with different slots in the middle (1, 2, 3, 1).
+
+ The caller is responsible to mark visited slots
+ and cleanup the mark after the iteration finish.
+
+ See ht_finder_t for an object designed for such operations.
+*/
+
+typedef struct _htkeysiter {
+ htkeys_t *keys;
+ size_t mask; // htkeys_mask(keys)
+ size_t slot; // masked hash, Py_hash_t h & mask;
+ size_t perturb;
+ Py_ssize_t index;
+} htkeysiter_t;
+
+static inline void
+htkeysiter_init(htkeysiter_t *iter, htkeys_t *keys, Py_hash_t hash)
+{
+ iter->keys = keys;
+ iter->mask = htkeys_mask(keys);
+ iter->perturb = (size_t)hash;
+ iter->slot = hash & iter->mask;
+ iter->index = htkeys_get_index(iter->keys, iter->slot);
+}
+
+static inline void
+htkeysiter_next(htkeysiter_t *iter)
+{
+ iter->perturb >>= HT_PERTURB_SHIFT;
+ iter->slot = (iter->slot * 5 + iter->perturb + 1) & iter->mask;
+ iter->index = htkeys_get_index(iter->keys, iter->slot);
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/contrib/python/multidict/multidict/_multilib/istr.h b/contrib/python/multidict/multidict/_multilib/istr.h
index 156b0dc04a3..4805849f3fe 100644
--- a/contrib/python/multidict/multidict/_multilib/istr.h
+++ b/contrib/python/multidict/multidict/_multilib/istr.h
@@ -9,7 +9,7 @@ extern "C" {
typedef struct {
PyUnicodeObject str;
- PyObject * canonical;
+ PyObject *canonical;
mod_state *state;
} istrobject;
@@ -23,7 +23,7 @@ static inline void
istr_dealloc(istrobject *self)
{
Py_XDECREF(self->canonical);
- PyUnicode_Type.tp_dealloc((PyObject*)self);
+ PyUnicode_Type.tp_dealloc((PyObject *)self);
}
static inline PyObject *
@@ -42,8 +42,8 @@ istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject *canonical = NULL;
PyObject *ret = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:str",
- kwlist, &x, &encoding, &errors)) {
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|OOO:str", kwlist, &x, &encoding, &errors)) {
return NULL;
}
if (x != NULL && IStr_Check(state, x)) {
@@ -58,8 +58,8 @@ istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (!canonical) {
goto fail;
}
- ((istrobject*)ret)->canonical = canonical;
- ((istrobject*)ret)->state = state;
+ ((istrobject *)ret)->canonical = canonical;
+ ((istrobject *)ret)->state = state;
return ret;
fail:
Py_XDECREF(ret);
@@ -88,10 +88,9 @@ ret:
return result;
}
-
static PyMethodDef istr_methods[] = {
{"__reduce__", (PyCFunction)istr_reduce, METH_NOARGS, NULL},
- {NULL, NULL} /* sentinel */
+ {NULL, NULL} /* sentinel */
};
static PyType_Slot istr_slots[] = {
@@ -105,8 +104,7 @@ static PyType_Slot istr_slots[] = {
static PyType_Spec istr_spec = {
.name = "multidict._multidict.istr",
.basicsize = sizeof(istrobject),
- .flags = (Py_TPFLAGS_DEFAULT
- | Py_TPFLAGS_BASETYPE
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
#if PY_VERSION_HEX >= 0x030a00f0
| Py_TPFLAGS_IMMUTABLETYPE
#endif
@@ -114,7 +112,6 @@ static PyType_Spec istr_spec = {
.slots = istr_slots,
};
-
static inline PyObject *
IStr_New(mod_state *state, PyObject *str, PyObject *canonical)
{
@@ -129,8 +126,8 @@ IStr_New(mod_state *state, PyObject *str, PyObject *canonical)
goto ret;
}
Py_INCREF(canonical);
- ((istrobject*)res)->canonical = canonical;
- ((istrobject*)res)->state = state;
+ ((istrobject *)res)->canonical = canonical;
+ ((istrobject *)res)->state = state;
ret:
Py_CLEAR(args);
return res;
diff --git a/contrib/python/multidict/multidict/_multilib/iter.h b/contrib/python/multidict/multidict/_multilib/iter.h
index 2f3ca9de84c..10460bf2756 100644
--- a/contrib/python/multidict/multidict/_multilib/iter.h
+++ b/contrib/python/multidict/multidict/_multilib/iter.h
@@ -6,13 +6,13 @@ extern "C" {
#endif
#include "dict.h"
-#include "pair_list.h"
+#include "hashtable.h"
#include "state.h"
typedef struct multidict_iter {
PyObject_HEAD
MultiDictObject *md; // MultiDict or CIMultiDict
- pair_list_pos_t current;
+ md_pos_t current;
} MultidictIter;
static inline void
@@ -21,14 +21,14 @@ _init_iter(MultidictIter *it, MultiDictObject *md)
Py_INCREF(md);
it->md = md;
- pair_list_init_pos(&md->pairs, &it->current);
+ md_init_pos(md, &it->current);
}
static inline PyObject *
multidict_items_iter_new(MultiDictObject *md)
{
- MultidictIter *it = PyObject_GC_New(
- MultidictIter, md->pairs.state->ItemsIterType);
+ MultidictIter *it =
+ PyObject_GC_New(MultidictIter, md->state->ItemsIterType);
if (it == NULL) {
return NULL;
}
@@ -42,8 +42,8 @@ multidict_items_iter_new(MultiDictObject *md)
static inline PyObject *
multidict_keys_iter_new(MultiDictObject *md)
{
- MultidictIter *it = PyObject_GC_New(
- MultidictIter, md->pairs.state->KeysIterType);
+ MultidictIter *it =
+ PyObject_GC_New(MultidictIter, md->state->KeysIterType);
if (it == NULL) {
return NULL;
}
@@ -57,8 +57,8 @@ multidict_keys_iter_new(MultiDictObject *md)
static inline PyObject *
multidict_values_iter_new(MultiDictObject *md)
{
- MultidictIter *it = PyObject_GC_New(
- MultidictIter, md->pairs.state->ValuesIterType);
+ MultidictIter *it =
+ PyObject_GC_New(MultidictIter, md->state->ValuesIterType);
if (it == NULL) {
return NULL;
}
@@ -76,8 +76,7 @@ multidict_items_iter_iternext(MultidictIter *self)
PyObject *value = NULL;
PyObject *ret = NULL;
- int res = pair_list_next(&self->md->pairs, &self->current,
- NULL, &key, &value);
+ int res = md_next(self->md, &self->current, NULL, &key, &value);
if (res < 0) {
return NULL;
}
@@ -103,8 +102,7 @@ multidict_values_iter_iternext(MultidictIter *self)
{
PyObject *value = NULL;
- int res = pair_list_next(&self->md->pairs, &self->current,
- NULL, NULL, &value);
+ int res = md_next(self->md, &self->current, NULL, NULL, &value);
if (res < 0) {
return NULL;
}
@@ -121,8 +119,7 @@ multidict_keys_iter_iternext(MultidictIter *self)
{
PyObject *key = NULL;
- int res = pair_list_next(&self->md->pairs, &self->current,
- NULL, &key, NULL);
+ int res = md_next(self->md, &self->current, NULL, &key, NULL);
if (res < 0) {
return NULL;
}
@@ -159,23 +156,18 @@ multidict_iter_clear(MultidictIter *self)
static inline PyObject *
multidict_iter_len(MultidictIter *self)
{
- return PyLong_FromLong(pair_list_len(&self->md->pairs));
+ return PyLong_FromLong(md_len(self->md));
}
PyDoc_STRVAR(length_hint_doc,
"Private method returning an estimate of len(list(it)).");
static PyMethodDef multidict_iter_methods[] = {
- {
- "__length_hint__",
- (PyCFunction)(void(*)(void))multidict_iter_len,
- METH_NOARGS,
- length_hint_doc
- },
- {
- NULL,
- NULL
- } /* sentinel */
+ {"__length_hint__",
+ (PyCFunction)(void (*)(void))multidict_iter_len,
+ METH_NOARGS,
+ length_hint_doc},
+ {NULL, NULL} /* sentinel */
};
/***********************************************************************/
@@ -222,7 +214,6 @@ static PyType_Spec multidict_values_iter_spec = {
.slots = multidict_values_iter_slots,
};
-
static PyType_Slot multidict_keys_iter_slots[] = {
{Py_tp_dealloc, multidict_iter_dealloc},
{Py_tp_methods, multidict_iter_methods},
@@ -247,7 +238,7 @@ static PyType_Spec multidict_keys_iter_spec = {
static inline int
multidict_iter_init(PyObject *module, mod_state *state)
{
- PyObject * tmp;
+ PyObject *tmp;
tmp = PyType_FromModuleAndSpec(module, &multidict_items_iter_spec, NULL);
if (tmp == NULL) {
return -1;
diff --git a/contrib/python/multidict/multidict/_multilib/pair_list.h b/contrib/python/multidict/multidict/_multilib/pair_list.h
deleted file mode 100644
index 6c45673b73f..00000000000
--- a/contrib/python/multidict/multidict/_multilib/pair_list.h
+++ /dev/null
@@ -1,1633 +0,0 @@
-#include "pythoncapi_compat.h"
-
-#ifndef _MULTIDICT_PAIR_LIST_H
-#define _MULTIDICT_PAIR_LIST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <string.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#include "istr.h"
-#include "state.h"
-
-/* Implementation note.
-identity always has exact PyUnicode_Type type, not a subclass.
-It guarantees that identity hashing and comparison never calls
-Python code back, and these operations has no weird side effects,
-e.g. deletion the key from multidict.
-
-Taking into account the fact that all multidict operations except
-repr(md), repr(md_proxy), or repr(view) never access to the key
-itself but identity instead, borrowed references during iteration
-over pair_list for, e.g., md.get() or md.pop() is safe.
-*/
-
-typedef struct pair {
- PyObject *identity; // 8
- PyObject *key; // 8
- PyObject *value; // 8
- Py_hash_t hash; // 8
-} pair_t;
-
-/* Note about the structure size
-With 28 pairs the MultiDict object size is slightly less than 1KiB
-
-To fit into 512 bytes, the structure can contain only 13 pairs
-which is too small, e.g. https://www.python.org returns 16 headers
-(9 of them are caching proxy information though).
-
-The embedded buffer intention is to fit the vast majority of possible
-HTTP headers into the buffer without allocating an extra memory block.
-*/
-
-#define EMBEDDED_CAPACITY 28
-
-typedef struct pair_list {
- mod_state *state;
- Py_ssize_t capacity;
- Py_ssize_t size;
- uint64_t version;
- bool calc_ci_indentity;
- pair_t *pairs;
- pair_t buffer[EMBEDDED_CAPACITY];
-} pair_list_t;
-
-#define MIN_CAPACITY 64
-#define CAPACITY_STEP MIN_CAPACITY
-
-/* Global counter used to set ma_version_tag field of dictionary.
- * It is incremented each time that a dictionary is created and each
- * time that a dictionary is modified. */
-static uint64_t pair_list_global_version = 0;
-
-#define NEXT_VERSION() (++pair_list_global_version)
-
-
-typedef struct pair_list_pos {
- Py_ssize_t pos;
- uint64_t version;
-} pair_list_pos_t;
-
-
-static inline int
-str_cmp(PyObject *s1, PyObject *s2)
-{
- PyObject *ret = PyUnicode_RichCompare(s1, s2, Py_EQ);
- if (Py_IsTrue(ret)) {
- Py_DECREF(ret);
- return 1;
- }
- else if (ret == NULL) {
- return -1;
- }
- else {
- Py_DECREF(ret);
- return 0;
- }
-}
-
-
-static inline PyObject *
-_key_to_ident(mod_state *state, PyObject *key)
-{
- if (IStr_Check(state, key)) {
- return Py_NewRef(((istrobject*)key)->canonical);
- }
- if (PyUnicode_CheckExact(key)) {
- return Py_NewRef(key);
- }
- if (PyUnicode_Check(key)) {
- return PyUnicode_FromObject(key);
- }
- PyErr_SetString(PyExc_TypeError,
- "MultiDict keys should be either str "
- "or subclasses of str");
- return NULL;
-}
-
-
-static inline PyObject *
-_ci_key_to_ident(mod_state *state, PyObject *key)
-{
- if (IStr_Check(state, key)) {
- return Py_NewRef(((istrobject*)key)->canonical);
- }
- if (PyUnicode_Check(key)) {
- PyObject *ret = PyObject_CallMethodNoArgs(key, state->str_lower);
- if (!PyUnicode_CheckExact(ret)) {
- PyObject *tmp = PyUnicode_FromObject(ret);
- Py_CLEAR(ret);
- if (tmp == NULL) {
- return NULL;
- }
- ret = tmp;
- }
- return ret;
- }
- PyErr_SetString(PyExc_TypeError,
- "CIMultiDict keys should be either str "
- "or subclasses of str");
- return NULL;
-}
-
-
-static inline PyObject *
-_arg_to_key(mod_state *state, PyObject *key, PyObject *ident)
-{
- if (PyUnicode_Check(key)) {
- return Py_NewRef(key);
- }
- PyErr_SetString(PyExc_TypeError,
- "MultiDict keys should be either str "
- "or subclasses of str");
- return NULL;
-}
-
-
-static inline PyObject *
-_ci_arg_to_key(mod_state *state, PyObject *key, PyObject *ident)
-{
- if (IStr_Check(state, key)) {
- return Py_NewRef(key);
- }
- if (PyUnicode_Check(key)) {
- return IStr_New(state, key, ident);
- }
- PyErr_SetString(PyExc_TypeError,
- "CIMultiDict keys should be either str "
- "or subclasses of str");
- return NULL;
-}
-
-
-static inline int
-pair_list_grow(pair_list_t *list, Py_ssize_t amount)
-{
- // Grow by one element if needed
- Py_ssize_t capacity = ((Py_ssize_t)((list->size + amount)
- / CAPACITY_STEP) + 1) * CAPACITY_STEP;
-
- pair_t *new_pairs;
-
- if (list->size + amount -1 < list->capacity) {
- return 0;
- }
-
- if (list->pairs == list->buffer) {
- new_pairs = PyMem_New(pair_t, (size_t)capacity);
- memcpy(new_pairs, list->buffer, (size_t)list->capacity * sizeof(pair_t));
-
- list->pairs = new_pairs;
- list->capacity = capacity;
- return 0;
- } else {
- new_pairs = PyMem_Resize(list->pairs, pair_t, (size_t)capacity);
-
- if (NULL == new_pairs) {
- // Resizing error
- return -1;
- }
-
- list->pairs = new_pairs;
- list->capacity = capacity;
- return 0;
- }
-}
-
-
-static inline int
-pair_list_shrink(pair_list_t *list)
-{
- // Shrink by one element if needed.
- // Optimization is applied to prevent jitter
- // (grow-shrink-grow-shrink on adding-removing the single element
- // when the buffer is full).
- // To prevent this, the buffer is resized if the size is less than the capacity
- // by 2*CAPACITY_STEP factor.
- // The switch back to embedded buffer is never performed for both reasons:
- // the code simplicity and the jitter prevention.
-
- pair_t *new_pairs;
- Py_ssize_t new_capacity;
-
- if (list->capacity - list->size < 2 * CAPACITY_STEP) {
- return 0;
- }
- new_capacity = list->capacity - CAPACITY_STEP;
- if (new_capacity < MIN_CAPACITY) {
- return 0;
- }
-
- new_pairs = PyMem_Resize(list->pairs, pair_t, (size_t)new_capacity);
-
- if (NULL == new_pairs) {
- // Resizing error
- return -1;
- }
-
- list->pairs = new_pairs;
- list->capacity = new_capacity;
-
- return 0;
-}
-
-
-static inline int
-_pair_list_init(pair_list_t *list, mod_state *state,
- bool calc_ci_identity, Py_ssize_t preallocate)
-{
- list->state = state;
- list->calc_ci_indentity = calc_ci_identity;
- Py_ssize_t capacity = EMBEDDED_CAPACITY;
- if (preallocate >= capacity) {
- capacity = ((Py_ssize_t)(preallocate / CAPACITY_STEP) + 1) * CAPACITY_STEP;
- list->pairs = PyMem_New(pair_t, (size_t)capacity);
- } else {
- list->pairs = list->buffer;
- }
- list->capacity = capacity;
- list->size = 0;
- list->version = NEXT_VERSION();
- return 0;
-}
-
-static inline int
-pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size)
-{
- return _pair_list_init(list, state, /* calc_ci_identity = */ false, size);
-}
-
-
-static inline int
-ci_pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size)
-{
- return _pair_list_init(list, state, /* calc_ci_identity = */ true, size);
-}
-
-
-static inline PyObject *
-pair_list_calc_identity(pair_list_t *list, PyObject *key)
-{
- if (list->calc_ci_indentity)
- return _ci_key_to_ident(list->state, key);
- return _key_to_ident(list->state, key);
-}
-
-static inline PyObject *
-pair_list_calc_key(pair_list_t *list, PyObject *key, PyObject *ident)
-{
- if (list->calc_ci_indentity)
- return _ci_arg_to_key(list->state, key, ident);
- return _arg_to_key(list->state, key, ident);
-}
-
-static inline void
-pair_list_dealloc(pair_list_t *list)
-{
- Py_ssize_t pos;
-
- for (pos = 0; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
-
- Py_CLEAR(pair->identity);
- Py_CLEAR(pair->key);
- Py_CLEAR(pair->value);
- }
-
- /*
- Strictly speaking, resetting size and capacity and
- assigning pairs to buffer is not necessary.
- Do it to consistency and idemotency.
- The cleanup doesn't hurt performance.
- !!!
- !!! The buffer deletion is crucial though.
- !!!
- */
- list->size = 0;
- if (list->pairs != list->buffer) {
- PyMem_Free(list->pairs);
- list->pairs = list->buffer;
- list->capacity = EMBEDDED_CAPACITY;
- }
-}
-
-
-static inline Py_ssize_t
-pair_list_len(pair_list_t *list)
-{
- return list->size;
-}
-
-
-static inline int
-_pair_list_add_with_hash_steal_refs(pair_list_t *list,
- PyObject *identity,
- PyObject *key,
- PyObject *value,
- Py_hash_t hash)
-{
- if (pair_list_grow(list, 1) < 0) {
- return -1;
- }
-
- pair_t *pair = list->pairs + list->size;
-
- pair->identity = identity;
- pair->key = key;
- pair->value = value;
- pair->hash = hash;
-
- list->version = NEXT_VERSION();
- list->size += 1;
-
- return 0;
-}
-
-static inline int
-_pair_list_add_with_hash(pair_list_t *list,
- PyObject *identity,
- PyObject *key,
- PyObject *value,
- Py_hash_t hash)
-{
- Py_INCREF(identity);
- Py_INCREF(key);
- Py_INCREF(value);
- return _pair_list_add_with_hash_steal_refs(list, identity, key, value, hash);
-}
-
-
-static inline int
-pair_list_add(pair_list_t *list, PyObject *key, PyObject *value)
-{
- PyObject *identity = pair_list_calc_identity(list, key);
- if (identity == NULL) {
- goto fail;
- }
- Py_hash_t hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
- int ret = _pair_list_add_with_hash(list, identity, key, value, hash);
- Py_DECREF(identity);
- return ret;
-fail:
- Py_XDECREF(identity);
- return -1;
-}
-
-
-static inline int
-pair_list_del_at(pair_list_t *list, Py_ssize_t pos)
-{
- // return 1 on success, -1 on failure
- pair_t *pair = list->pairs + pos;
- Py_DECREF(pair->identity);
- Py_DECREF(pair->key);
- Py_DECREF(pair->value);
-
- list->size -= 1;
- list->version = NEXT_VERSION();
-
- if (list->size == pos) {
- // remove from tail, no need to shift body
- return 0;
- }
-
- Py_ssize_t tail = list->size - pos;
- // TODO: raise an error if tail < 0
- memmove((void *)(list->pairs + pos),
- (void *)(list->pairs + pos + 1),
- sizeof(pair_t) * (size_t)tail);
-
- return pair_list_shrink(list);
-}
-
-
-static inline int
-_pair_list_drop_tail(pair_list_t *list, PyObject *identity, Py_hash_t hash,
- Py_ssize_t pos)
-{
- // return 1 if deleted, 0 if not found
- int found = 0;
-
- if (pos >= list->size) {
- return 0;
- }
-
- for (; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
- if (pair->hash != hash) {
- continue;
- }
- int ret = str_cmp(pair->identity, identity);
- if (ret > 0) {
- if (pair_list_del_at(list, pos) < 0) {
- return -1;
- }
- found = 1;
- pos--;
- }
- else if (ret == -1) {
- return -1;
- }
- }
-
- return found;
-}
-
-
-static inline int
-pair_list_del(pair_list_t *list, PyObject *key)
-{
- PyObject *identity = pair_list_calc_identity(list, key);
- if (identity == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
-
- int ret = _pair_list_drop_tail(list, identity, hash, 0);
-
- if (ret < 0) {
- goto fail;
- }
- else if (ret == 0) {
- PyErr_SetObject(PyExc_KeyError, key);
- goto fail;
- }
- else {
- list->version = NEXT_VERSION();
- }
- Py_DECREF(identity);
- return 0;
-fail:
- Py_XDECREF(identity);
- return -1;
-}
-
-
-static inline uint64_t
-pair_list_version(pair_list_t *list)
-{
- return list->version;
-}
-
-
-static inline void
-pair_list_init_pos(pair_list_t *list, pair_list_pos_t *pos)
-{
- pos->pos = 0;
- pos->version = list->version;
-}
-
-static inline int
-pair_list_next(pair_list_t *list, pair_list_pos_t *pos,
- PyObject **pidentity,
- PyObject **pkey, PyObject **pvalue)
-{
- if (pos->pos >= list->size) {
- if (pidentity) {
- *pidentity = NULL;
- }
- if (pkey) {
- *pkey = NULL;
- }
- if (pvalue) {
- *pvalue = NULL;
- }
- return 0;
- }
-
- if (pos->version != list->version) {
- if (pidentity) {
- *pidentity = NULL;
- }
- if (pkey) {
- *pkey = NULL;
- }
- if (pvalue) {
- *pvalue = NULL;
- }
- PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration");
- return -1;
- }
-
-
- pair_t *pair = list->pairs + pos->pos;
-
- if (pidentity) {
- *pidentity = Py_NewRef(pair->identity);;
- }
-
- if (pkey) {
- PyObject *key = pair_list_calc_key(list, pair->key, pair->identity);
- if (key == NULL) {
- return -1;
- }
- if (key != pair->key) {
- Py_SETREF(pair->key, key);
- } else {
- Py_CLEAR(key);
- }
- *pkey = Py_NewRef(pair->key);
- }
- if (pvalue) {
- *pvalue = Py_NewRef(pair->value);
- }
-
- ++pos->pos;
- return 1;
-}
-
-
-static inline int
-pair_list_next_by_identity(pair_list_t *list, pair_list_pos_t *pos,
- PyObject *identity,
- PyObject **pkey, PyObject **pvalue)
-{
- if (pos->pos >= list->size) {
- if (pkey) {
- *pkey = NULL;
- }
- if (pvalue) {
- *pvalue = NULL;
- }
- return 0;
- }
-
- if (pos->version != list->version) {
- if (pkey) {
- *pkey = NULL;
- }
- if (pvalue) {
- *pvalue = NULL;
- }
- PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration");
- return -1;
- }
-
-
- for (; pos->pos < list->size; ++pos->pos) {
- pair_t *pair = list->pairs + pos->pos;
- PyObject *ret = PyUnicode_RichCompare(identity, pair->identity, Py_EQ);
- if (Py_IsFalse(ret)) {
- Py_DECREF(ret);
- continue;
- } else if (ret == NULL) {
- return -1;
- } else {
- // equals
- Py_DECREF(ret);
- }
-
- if (pkey) {
- PyObject *key = pair_list_calc_key(list, pair->key, pair->identity);
- if (key == NULL) {
- return -1;
- }
- if (key != pair->key) {
- Py_SETREF(pair->key, key);
- } else {
- Py_CLEAR(key);
- }
- *pkey = Py_NewRef(pair->key);
- }
- if (pvalue) {
- *pvalue = Py_NewRef(pair->value);
- }
- ++pos->pos;
- return 1;
- }
- if (pkey) {
- *pkey = NULL;
- }
- if (pvalue) {
- *pvalue = NULL;
- }
- return 0;
-}
-
-
-static inline int
-pair_list_contains(pair_list_t *list, PyObject *key, PyObject **pret)
-{
- Py_ssize_t pos;
-
- if (!PyUnicode_Check(key)) {
- return 0;
- }
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
-
- Py_ssize_t size = pair_list_len(list);
-
- for(pos = 0; pos < size; ++pos) {
- pair_t * pair = list->pairs + pos;
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- Py_DECREF(ident);
- if (pret != NULL) {
- *pret = Py_NewRef(pair->key);
- }
- return 1;
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- Py_DECREF(ident);
- if (pret != NULL) {
- *pret = NULL;
- }
- return 0;
-fail:
- Py_XDECREF(ident);
- if (pret != NULL) {
- *pret = NULL;
- }
- return -1;
-}
-
-
-static inline int
-pair_list_get_one(pair_list_t *list, PyObject *key, PyObject **ret)
-{
- Py_ssize_t pos;
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
-
- Py_ssize_t size = pair_list_len(list);
-
- for(pos = 0; pos < size; ++pos) {
- pair_t *pair = list->pairs + pos;
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- Py_DECREF(ident);
- *ret = Py_NewRef(pair->value);
- return 0;
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- Py_DECREF(ident);
- return 0;
-fail:
- Py_XDECREF(ident);
- return -1;
-}
-
-
-static inline int
-pair_list_get_all(pair_list_t *list, PyObject *key, PyObject **ret)
-{
- Py_ssize_t pos;
- PyObject *res = NULL;
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
-
- Py_ssize_t size = pair_list_len(list);
- for(pos = 0; pos < size; ++pos) {
- pair_t *pair = list->pairs + pos;
-
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- if (res == NULL) {
- res = PyList_New(1);
- if (res == NULL) {
- goto fail;
- }
- if (PyList_SetItem(res, 0, Py_NewRef(pair->value)) < 0) {
- goto fail;
- }
- }
- else if (PyList_Append(res, pair->value) < 0) {
- goto fail;
- }
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- if (res != NULL) {
- *ret = res;
- }
- Py_DECREF(ident);
- return 0;
-
-fail:
- Py_XDECREF(ident);
- Py_XDECREF(res);
- return -1;
-}
-
-
-static inline PyObject *
-pair_list_set_default(pair_list_t *list, PyObject *key, PyObject *value)
-{
- Py_ssize_t pos;
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
- Py_ssize_t size = pair_list_len(list);
-
- for(pos = 0; pos < size; ++pos) {
- pair_t * pair = list->pairs + pos;
-
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- Py_DECREF(ident);
- return Py_NewRef(pair->value);
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- if (_pair_list_add_with_hash(list, ident, key, value, hash) < 0) {
- goto fail;
- }
-
- Py_DECREF(ident);
- return Py_NewRef(value);
-fail:
- Py_XDECREF(ident);
- return NULL;
-}
-
-
-static inline int
-pair_list_pop_one(pair_list_t *list, PyObject *key, PyObject **ret)
-{
- Py_ssize_t pos;
- PyObject *value = NULL;
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
-
- for (pos=0; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
- if (pair->hash != hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- value = Py_NewRef(pair->value);
- if (pair_list_del_at(list, pos) < 0) {
- goto fail;
- }
- Py_DECREF(ident);
- *ret = value;
- return 0;
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- return 0;
-fail:
- Py_XDECREF(value);
- Py_XDECREF(ident);
- return -1;
-}
-
-
-static inline int
-pair_list_pop_all(pair_list_t *list, PyObject *key, PyObject ** ret)
-{
- Py_ssize_t pos;
- PyObject *lst = NULL;
-
- PyObject *ident = pair_list_calc_identity(list, key);
- if (ident == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(ident);
- if (hash == -1) {
- goto fail;
- }
-
- if (list->size == 0) {
- Py_DECREF(ident);
- return 0;
- }
-
- for (pos = list->size - 1; pos >= 0; pos--) {
- pair_t *pair = list->pairs + pos;
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(ident, pair->identity);
- if (tmp > 0) {
- if (lst == NULL) {
- lst = PyList_New(1);
- if (lst == NULL) {
- goto fail;
- }
- if (PyList_SetItem(lst, 0, Py_NewRef(pair->value)) < 0) {
- goto fail;
- }
- } else if (PyList_Append(lst, pair->value) < 0) {
- goto fail;
- }
- if (pair_list_del_at(list, pos) < 0) {
- goto fail;
- }
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- if (lst != NULL) {
- if (PyList_Reverse(lst) < 0) {
- goto fail;
- }
- }
- *ret = lst;
- Py_DECREF(ident);
- return 0;
-fail:
- Py_XDECREF(ident);
- Py_XDECREF(lst);
- return -1;
-}
-
-
-static inline PyObject *
-pair_list_pop_item(pair_list_t *list)
-{
- if (list->size == 0) {
- PyErr_SetString(PyExc_KeyError, "empty multidict");
- return NULL;
- }
-
- Py_ssize_t pos = list->size - 1;
- pair_t *pair = list->pairs + pos;
- PyObject *key = pair_list_calc_key(list, pair->key, pair->identity);
- if (key == NULL) {
- return NULL;
- }
- PyObject *ret = PyTuple_Pack(2, key, pair->value);
- Py_CLEAR(key);
- if (ret == NULL) {
- return NULL;
- }
-
- if (pair_list_del_at(list, pos) < 0) {
- Py_DECREF(ret);
- return NULL;
- }
-
- return ret;
-}
-
-
-static inline int
-pair_list_replace(pair_list_t *list, PyObject * key, PyObject *value)
-{
- Py_ssize_t pos;
- int found = 0;
-
- PyObject *identity = pair_list_calc_identity(list, key);
- if (identity == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
-
-
- for (pos = 0; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
- if (hash != pair->hash) {
- continue;
- }
- int tmp = str_cmp(identity, pair->identity);
- if (tmp > 0) {
- found = 1;
- Py_SETREF(pair->key, Py_NewRef(key));
- Py_SETREF(pair->value, Py_NewRef(value));
- break;
- }
- else if (tmp < 0) {
- goto fail;
- }
- }
-
- if (!found) {
- if (_pair_list_add_with_hash(list, identity, key, value, hash) < 0) {
- goto fail;
- }
- Py_DECREF(identity);
- return 0;
- }
- else {
- list->version = NEXT_VERSION();
- if (_pair_list_drop_tail(list, identity, hash, pos+1) < 0) {
- goto fail;
- }
- Py_DECREF(identity);
- return 0;
- }
-fail:
- Py_XDECREF(identity);
- return -1;
-}
-
-
-static inline int
-_dict_set_number(PyObject *dict, PyObject *key, Py_ssize_t num)
-{
- PyObject *tmp = PyLong_FromSsize_t(num);
- if (tmp == NULL) {
- return -1;
- }
-
- if (PyDict_SetItem(dict, key, tmp) < 0) {
- Py_DECREF(tmp);
- return -1;
- }
-
- Py_DECREF(tmp);
- return 0;
-}
-
-
-static inline int
-pair_list_post_update(pair_list_t *list, PyObject* used)
-{
- PyObject *tmp = NULL;
- Py_ssize_t pos;
-
- for (pos = 0; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
- int status = PyDict_GetItemRef(used, pair->identity, &tmp);
- if (status == -1) {
- // exception set
- return -1;
- }
- else if (status == 0) {
- // not found
- continue;
- }
-
- Py_ssize_t num = PyLong_AsSsize_t(tmp);
- Py_DECREF(tmp);
- if (num == -1) {
- if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_RuntimeError, "invalid internal state");
- }
- return -1;
- }
-
- if (pos >= num) {
- // del self[pos]
- if (pair_list_del_at(list, pos) < 0) {
- return -1;
- }
- pos--;
- }
- }
-
- list->version = NEXT_VERSION();
- return 0;
-}
-
-// TODO: need refactoring function name
-static inline int
-_pair_list_update(pair_list_t *list, PyObject *key,
- PyObject *value, PyObject *used,
- PyObject *identity, Py_hash_t hash)
-{
- PyObject *item = NULL;
- Py_ssize_t pos;
- int found;
-
- int status = PyDict_GetItemRef(used, identity, &item);
- if (status == -1) {
- // exception set
- return -1;
- }
- else if (status == 0) {
- // not found
- pos = 0;
- }
- else {
- pos = PyLong_AsSsize_t(item);
- Py_DECREF(item);
- if (pos == -1) {
- if (!PyErr_Occurred()) {
- PyErr_SetString(PyExc_RuntimeError, "invalid internal state");
- }
- return -1;
- }
- }
-
- found = 0;
- for (; pos < list->size; pos++) {
- pair_t *pair = list->pairs + pos;
- if (pair->hash != hash) {
- continue;
- }
-
- int ident_cmp_res = str_cmp(pair->identity, identity);
- if (ident_cmp_res > 0) {
- Py_SETREF(pair->key, Py_NewRef(key));
- Py_SETREF(pair->value, Py_NewRef(value));
-
- if (_dict_set_number(used, pair->identity, pos + 1) < 0) {
- return -1;
- }
-
- found = 1;
- break;
- }
- else if (ident_cmp_res < 0) {
- return -1;
- }
- }
-
- if (!found) {
- if (_pair_list_add_with_hash(list, identity, key, value, hash) < 0) {
- return -1;
- }
- if (_dict_set_number(used, identity, list->size) < 0) {
- return -1;
- }
- }
-
- return 0;
-}
-
-
-static inline int
-pair_list_update_from_pair_list(pair_list_t *list,
- PyObject* used, pair_list_t *other)
-{
- Py_ssize_t pos;
- Py_hash_t hash;
- PyObject *identity = NULL;
- PyObject *key = NULL;
- bool recalc_identity = list->calc_ci_indentity != other->calc_ci_indentity;
-
- for (pos = 0; pos < other->size; pos++) {
- pair_t *pair = other->pairs + pos;
- if (recalc_identity) {
- identity = pair_list_calc_identity(list, pair->key);
- if (identity == NULL) {
- goto fail;
- }
- hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
- /* materialize key */
- key = pair_list_calc_key(other, pair->key, identity);
- if (key == NULL) {
- goto fail;
- }
- } else {
- identity = pair->identity;
- hash = pair->hash;
- key = pair->key;
- }
- if (used != NULL) {
- if (_pair_list_update(list, key, pair->value, used,
- identity, hash) < 0) {
- goto fail;
- }
- } else {
- if (_pair_list_add_with_hash(list, identity, key,
- pair->value, hash) < 0) {
- goto fail;
- }
- }
- if (recalc_identity) {
- Py_CLEAR(identity);
- Py_CLEAR(key);
- }
- }
- return 0;
-fail:
- if (recalc_identity) {
- Py_CLEAR(identity);
- Py_CLEAR(key);
- }
- return -1;
-}
-
-static inline int
-pair_list_update_from_dict(pair_list_t *list, PyObject* used, PyObject *kwds)
-{
- Py_ssize_t pos = 0;
- PyObject *identity = NULL;
- PyObject *key = NULL;
- PyObject *value = NULL;
-
- while(PyDict_Next(kwds, &pos, &key, &value)) {
- Py_INCREF(key);
- identity = pair_list_calc_identity(list, key);
- if (identity == NULL) {
- goto fail;
- }
- Py_hash_t hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
- if (used != NULL) {
- if (_pair_list_update(list, key, value, used, identity, hash) < 0) {
- goto fail;
- }
- } else {
- if (_pair_list_add_with_hash(list, identity, key, value, hash) < 0) {
- goto fail;
- }
- }
- Py_CLEAR(identity);
- Py_CLEAR(key);
- }
- return 0;
-fail:
- Py_CLEAR(identity);
- Py_CLEAR(key);
- return -1;
-}
-
-static inline void _err_not_sequence(Py_ssize_t i)
-{
- PyErr_Format(PyExc_TypeError,
- "multidict cannot convert sequence element #%zd"
- " to a sequence",
- i);
-}
-
-static inline void _err_bad_length(Py_ssize_t i, Py_ssize_t n)
-{
- PyErr_Format(PyExc_ValueError,
- "multidict update sequence element #%zd "
- "has length %zd; 2 is required",
- i, n);
-}
-
-static inline void _err_cannot_fetch(Py_ssize_t i, const char * name)
-{
- PyErr_Format(PyExc_ValueError,
- "multidict update sequence element #%zd's "
- "%s could not be fetched", name, i);
-}
-
-
-static int _pair_list_parse_item(Py_ssize_t i, PyObject *item,
- PyObject **pkey, PyObject **pvalue)
-{
- Py_ssize_t n;
-
- if (PyList_CheckExact(item)) {
- n = PyList_GET_SIZE(item);
- if (n != 2) {
- _err_bad_length(i, n);
- goto fail;
- }
- *pkey = Py_NewRef(PyList_GET_ITEM(item, 0));
- *pvalue = Py_NewRef(PyList_GET_ITEM(item, 1));
- } else if (PyTuple_CheckExact(item)) {
- n = PyTuple_GET_SIZE(item);
- if (n != 2) {
- _err_bad_length(i, n);
- goto fail;
- }
- *pkey = Py_NewRef(PyTuple_GET_ITEM(item, 0));
- *pvalue = Py_NewRef(PyTuple_GET_ITEM(item, 1));
- } else {
- if (!PySequence_Check(item)) {
- _err_not_sequence(i);
- goto fail;
- }
- n = PySequence_Size(item);
- if (n != 2) {
- _err_bad_length(i, n);
- goto fail;
- }
- *pkey = PySequence_ITEM(item, 0);
- *pvalue = PySequence_ITEM(item, 1);
- if (*pkey == NULL) {
- _err_cannot_fetch(i, "key");
- goto fail;
- }
- if (*pvalue == NULL) {
- _err_cannot_fetch(i, "value");
- goto fail;
- }
- }
- return 0;
-fail:
- Py_CLEAR(*pkey);
- Py_CLEAR(*pvalue);
- return -1;
-}
-
-
-static inline int
-pair_list_update_from_seq(pair_list_t *list, PyObject *used, PyObject *seq)
-{
- PyObject *it = NULL;
- PyObject *item = NULL; // seq[i]
-
- PyObject *key = NULL;
- PyObject *value = NULL;
- PyObject *identity = NULL;
-
- Py_ssize_t i;
- Py_ssize_t size = -1;
-
- enum {LIST, TUPLE, ITER} kind;
-
- if (PyList_CheckExact(seq)) {
- kind = LIST;
- size = PyList_GET_SIZE(seq);
- } else if (PyTuple_CheckExact(seq)) {
- kind = TUPLE;
- size = PyTuple_GET_SIZE(seq);
- } else {
- kind = ITER;
- it = PyObject_GetIter(seq);
- if (it == NULL) {
- goto fail;
- }
- }
-
- for (i = 0; ; ++i) { // i - index into seq of current element
- switch (kind) {
- case LIST:
- if (i >= size) {
- goto exit;
- }
- item = PyList_GET_ITEM(seq, i);
- if (item == NULL) {
- goto fail;
- }
- Py_INCREF(item);
- break;
- case TUPLE:
- if (i >= size) {
- goto exit;
- }
- item = PyTuple_GET_ITEM(seq, i);
- if (item == NULL) {
- goto fail;
- }
- Py_INCREF(item);
- break;
- case ITER:
- item = PyIter_Next(it);
- if (item == NULL) {
- if (PyErr_Occurred()) {
- goto fail;
- }
- goto exit;
- }
- }
-
- if (_pair_list_parse_item(i, item, &key, &value) < 0) {
- goto fail;
- }
-
- identity = pair_list_calc_identity(list, key);
- if (identity == NULL) {
- goto fail;
- }
-
- Py_hash_t hash = PyObject_Hash(identity);
- if (hash == -1) {
- goto fail;
- }
-
- if (used) {
- if (_pair_list_update(list, key, value, used, identity, hash) < 0) {
- goto fail;
- }
- Py_CLEAR(identity);
- Py_CLEAR(key);
- Py_CLEAR(value);
- } else {
- if (_pair_list_add_with_hash_steal_refs(list, identity,
- key, value, hash) < 0) {
- goto fail;
- }
- identity = NULL;
- key = NULL;
- value = NULL;
- }
- Py_CLEAR(item);
- }
-
-exit:
- Py_CLEAR(it);
- return 0;
-
-fail:
- Py_CLEAR(identity);
- Py_CLEAR(it);
- Py_CLEAR(item);
- Py_CLEAR(key);
- Py_CLEAR(value);
- return -1;
-}
-
-
-static inline int
-pair_list_eq(pair_list_t *list, pair_list_t *other)
-{
- Py_ssize_t pos;
-
- if (list == other) {
- return 1;
- }
-
- Py_ssize_t size = pair_list_len(list);
-
- if (size != pair_list_len(other)) {
- return 0;
- }
-
- for(pos = 0; pos < size; ++pos) {
- pair_t *pair1 = list->pairs + pos;
- pair_t *pair2 = other->pairs +pos;
-
- if (pair1->hash != pair2->hash) {
- return 0;
- }
-
- int cmp = PyObject_RichCompareBool(pair1->identity, pair2->identity, Py_EQ);
- if (cmp < 0) {
- return -1;
- };
- if (cmp == 0) {
- return 0;
- }
-
- cmp = PyObject_RichCompareBool(pair1->value, pair2->value, Py_EQ);
- if (cmp < 0) {
- return -1;
- };
- if (cmp == 0) {
- return 0;
- }
- }
-
- return 1;
-}
-
-static inline int
-pair_list_eq_to_mapping(pair_list_t *list, PyObject *other)
-{
- PyObject *key = NULL;
- PyObject *avalue = NULL;
- PyObject *bvalue;
-
- Py_ssize_t other_len;
-
- if (!PyMapping_Check(other)) {
- PyErr_Format(PyExc_TypeError,
- "other argument must be a mapping, not %s",
- Py_TYPE(other)->tp_name);
- return -1;
- }
-
- other_len = PyMapping_Size(other);
- if (other_len < 0) {
- return -1;
- }
- if (pair_list_len(list) != other_len) {
- return 0;
- }
-
- pair_list_pos_t pos;
- pair_list_init_pos(list, &pos);
-
- for(;;) {
- int ret = pair_list_next(list, &pos, NULL, &key, &avalue);
- if (ret < 0) {
- return -1;
- }
- if (ret == 0) {
- break;
- }
- ret = PyMapping_GetOptionalItem(other, key, &bvalue);
- Py_CLEAR(key);
- if (ret < 0) {
- Py_CLEAR(avalue);
- return -1;
- }
-
- if (bvalue == NULL) {
- Py_CLEAR(avalue);
- return 0;
- }
-
- int eq = PyObject_RichCompareBool(avalue, bvalue, Py_EQ);
- Py_CLEAR(bvalue);
- Py_CLEAR(avalue);
-
- if (eq <= 0) {
- return eq;
- }
- }
-
- return 1;
-}
-
-
-static inline PyObject *
-pair_list_repr(pair_list_t *list, PyObject *name,
- bool show_keys, bool show_values)
-{
- PyObject *key = NULL;
- PyObject *value = NULL;
-
- bool comma = false;
- Py_ssize_t pos;
- uint64_t version = list->version;
-
- PyUnicodeWriter *writer = PyUnicodeWriter_Create(1024);
- if (writer == NULL)
- return NULL;
-
- if (PyUnicodeWriter_WriteChar(writer, '<') <0)
- goto fail;
- if (PyUnicodeWriter_WriteStr(writer, name) <0)
- goto fail;
- if (PyUnicodeWriter_WriteChar(writer, '(') <0)
- goto fail;
-
- for (pos = 0; pos < list->size; ++pos) {
- if (version != list->version) {
- PyErr_SetString(PyExc_RuntimeError, "MultiDict changed during iteration");
- return NULL;
- }
- pair_t *pair = list->pairs + pos;
- key = Py_NewRef(pair->key);
- value = Py_NewRef(pair->value);
-
- if (comma) {
- if (PyUnicodeWriter_WriteChar(writer, ',') <0)
- goto fail;
- if (PyUnicodeWriter_WriteChar(writer, ' ') <0)
- goto fail;
- }
- if (show_keys) {
- if (PyUnicodeWriter_WriteChar(writer, '\'') <0)
- goto fail;
- /* Don't need to convert key to istr, the text is the same*/
- if (PyUnicodeWriter_WriteStr(writer, key) <0)
- goto fail;
- if (PyUnicodeWriter_WriteChar(writer, '\'') <0)
- goto fail;
- }
- if (show_keys && show_values) {
- if (PyUnicodeWriter_WriteChar(writer, ':') <0)
- goto fail;
- if (PyUnicodeWriter_WriteChar(writer, ' ') <0)
- goto fail;
- }
- if (show_values) {
- if (PyUnicodeWriter_WriteRepr(writer, value) <0)
- goto fail;
- }
-
- comma = true;
- Py_CLEAR(key);
- Py_CLEAR(value);
- }
-
- if (PyUnicodeWriter_WriteChar(writer, ')') <0)
- goto fail;
- if (PyUnicodeWriter_WriteChar(writer, '>') <0)
- goto fail;
- return PyUnicodeWriter_Finish(writer);
-fail:
- Py_CLEAR(key);
- Py_CLEAR(value);
- PyUnicodeWriter_Discard(writer);
- return NULL;
-}
-
-
-
-/***********************************************************************/
-
-static inline int
-pair_list_traverse(pair_list_t *list, visitproc visit, void *arg)
-{
- pair_t *pair = NULL;
- Py_ssize_t pos;
-
- for (pos = 0; pos < list->size; pos++) {
- pair = list->pairs + pos;
- // Don't need traverse the identity: it is a terminal
- Py_VISIT(pair->key);
- Py_VISIT(pair->value);
- }
-
- return 0;
-}
-
-
-static inline int
-pair_list_clear(pair_list_t *list)
-{
- pair_t *pair = NULL;
- Py_ssize_t pos;
-
- if (list->size == 0) {
- return 0;
- }
-
- list->version = NEXT_VERSION();
- for (pos = 0; pos < list->size; pos++) {
- pair = list->pairs + pos;
- Py_CLEAR(pair->key);
- Py_CLEAR(pair->identity);
- Py_CLEAR(pair->value);
- }
- list->size = 0;
- if (list->pairs != list->buffer) {
- PyMem_Free(list->pairs);
- list->pairs = list->buffer;
- }
-
- return 0;
-}
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/contrib/python/multidict/multidict/_multilib/parser.h b/contrib/python/multidict/multidict/_multilib/parser.h
index 074f6fa7d9e..1ff3b33d37e 100644
--- a/contrib/python/multidict/multidict/_multilib/parser.h
+++ b/contrib/python/multidict/multidict/_multilib/parser.h
@@ -5,23 +5,26 @@
extern "C" {
#endif
-static int raise_unexpected_kwarg(const char *fname, PyObject* argname)
+static inline int
+raise_unexpected_kwarg(const char *fname, PyObject *argname)
{
PyErr_Format(PyExc_TypeError,
"%.150s() got an unexpected keyword argument '%.150U'",
- fname, argname);
+ fname,
+ argname);
return -1;
}
-static int raise_missing_posarg(const char *fname, const char* argname)
+static inline int
+raise_missing_posarg(const char *fname, const char *argname)
{
PyErr_Format(PyExc_TypeError,
"%.150s() missing 1 required positional argument: '%.150s'",
- fname, argname);
+ fname,
+ argname);
return -1;
}
-
/* Parse FASTCALL|METH_KEYWORDS arguments as two args,
the first arg is mandatory and the second one is optional.
If the second arg is not passed it remains NULL pointer.
@@ -32,19 +35,13 @@ The parser accepts three forms:
3. all named keyword args.
*/
-static int parse2(const char* fname,
- PyObject*const *args,
- Py_ssize_t nargs,
- PyObject *kwnames,
- Py_ssize_t minargs,
- const char* arg1name,
- PyObject **arg1,
- const char* arg2name,
- PyObject **arg2
-)
+static inline int
+parse2(const char *fname, PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames, Py_ssize_t minargs, const char *arg1name,
+ PyObject **arg1, const char *arg2name, PyObject **arg2)
{
- assert(minargs>=1);
- assert(minargs<=2);
+ assert(minargs >= 1);
+ assert(minargs <= 2);
if (kwnames != NULL) {
Py_ssize_t kwsize = PyTuple_Size(kwnames);
@@ -71,7 +68,8 @@ static int parse2(const char* fname,
} else {
return raise_unexpected_kwarg(fname, argname);
}
- } else if (PyUnicode_CompareWithASCIIString(argname, arg2name) == 0) {
+ } else if (PyUnicode_CompareWithASCIIString(argname, arg2name) ==
+ 0) {
argname = PyTuple_GetItem(kwnames, 1);
if (argname == NULL) {
return -1;
@@ -113,13 +111,15 @@ static int parse2(const char* fname,
}
} else {
if (nargs < 1) {
- PyErr_Format(PyExc_TypeError,
- "%.150s() missing 1 required positional argument: '%s'",
- fname, arg1name);
+ PyErr_Format(
+ PyExc_TypeError,
+ "%.150s() missing 1 required positional argument: '%s'",
+ fname,
+ arg1name);
return -1;
}
if (nargs < minargs || nargs > 2) {
- const char* txt;
+ const char *txt;
if (minargs == 2) {
txt = "from 1 to 2 positional arguments";
} else {
@@ -127,7 +127,9 @@ static int parse2(const char* fname,
}
PyErr_Format(PyExc_TypeError,
"%.150s() takes %s but %zd were given",
- fname, txt, nargs);
+ fname,
+ txt,
+ nargs);
return -1;
}
*arg1 = args[0];
diff --git a/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h b/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h
index 4b179e49319..1ab42c8fa57 100644
--- a/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h
+++ b/contrib/python/multidict/multidict/_multilib/pythoncapi_compat.h
@@ -19,49 +19,48 @@ extern "C" {
#endif
#include <Python.h>
-#include <stddef.h> // offsetof()
+#include <stddef.h> // offsetof()
// Python 3.11.0b4 added PyFrame_Back() to Python.h
#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
-# include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
+#include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
#endif
#if PY_VERSION_HEX < 0x030C00A3
-# include <structmember.h> // T_SHORT, READONLY
+#include <structmember.h> // T_SHORT, READONLY
#endif
-
#ifndef _Py_CAST
-# define _Py_CAST(type, expr) ((type)(expr))
+#define _Py_CAST(type, expr) ((type)(expr))
#endif
// Static inline functions should use _Py_NULL rather than using directly NULL
// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
// _Py_NULL is defined as nullptr.
#ifndef _Py_NULL
-# if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \
- || (defined(__cplusplus) && __cplusplus >= 201103)
-# define _Py_NULL nullptr
-# else
-# define _Py_NULL NULL
-# endif
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103)
+#define _Py_NULL nullptr
+#else
+#define _Py_NULL NULL
+#endif
#endif
// Cast argument to PyObject* type.
#ifndef _PyObject_CAST
-# define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
+#define _PyObject_CAST(op) _Py_CAST(PyObject *, op)
#endif
#ifndef Py_BUILD_ASSERT
-# define Py_BUILD_ASSERT(cond) \
- do { \
- (void)sizeof(char [1 - 2 * !(cond)]); \
- } while(0)
+#define Py_BUILD_ASSERT(cond) \
+ do { \
+ (void)sizeof(char[1 - 2 * !(cond)]); \
+ } while (0)
#endif
-
// bpo-42262 added Py_NewRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
-static inline PyObject* _Py_NewRef(PyObject *obj)
+static inline PyObject *
+_Py_NewRef(PyObject *obj)
{
Py_INCREF(obj);
return obj;
@@ -69,10 +68,10 @@ static inline PyObject* _Py_NewRef(PyObject *obj)
#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
#endif
-
// bpo-42262 added Py_XNewRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef)
-static inline PyObject* _Py_XNewRef(PyObject *obj)
+static inline PyObject *
+_Py_XNewRef(PyObject *obj)
{
Py_XINCREF(obj);
return obj;
@@ -80,103 +79,106 @@ static inline PyObject* _Py_XNewRef(PyObject *obj)
#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
#endif
-
// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
-static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
+static inline void
+_Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
{
ob->ob_refcnt = refcnt;
}
#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
#endif
-
// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2.
// It is excluded from the limited C API.
-#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API)
-#define Py_SETREF(dst, src) \
- do { \
- PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
- PyObject *_tmp_dst = (*_tmp_dst_ptr); \
- *_tmp_dst_ptr = _PyObject_CAST(src); \
- Py_DECREF(_tmp_dst); \
+#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && \
+ !defined(Py_LIMITED_API)
+#define Py_SETREF(dst, src) \
+ do { \
+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject **, &(dst)); \
+ PyObject *_tmp_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = _PyObject_CAST(src); \
+ Py_DECREF(_tmp_dst); \
} while (0)
-#define Py_XSETREF(dst, src) \
- do { \
- PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \
- PyObject *_tmp_dst = (*_tmp_dst_ptr); \
- *_tmp_dst_ptr = _PyObject_CAST(src); \
- Py_XDECREF(_tmp_dst); \
+#define Py_XSETREF(dst, src) \
+ do { \
+ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject **, &(dst)); \
+ PyObject *_tmp_dst = (*_tmp_dst_ptr); \
+ *_tmp_dst_ptr = _PyObject_CAST(src); \
+ Py_XDECREF(_tmp_dst); \
} while (0)
#endif
-
// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse()
// to Python 3.10.0b1.
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is)
-# define Py_Is(x, y) ((x) == (y))
+#define Py_Is(x, y) ((x) == (y))
#endif
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone)
-# define Py_IsNone(x) Py_Is(x, Py_None)
+#define Py_IsNone(x) Py_Is(x, Py_None)
#endif
-#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsTrue)
-# define Py_IsTrue(x) Py_Is(x, Py_True)
+#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && \
+ !defined(Py_IsTrue)
+#define Py_IsTrue(x) Py_Is(x, Py_True)
#endif
-#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !defined(Py_IsFalse)
-# define Py_IsFalse(x) Py_Is(x, Py_False)
+#if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && \
+ !defined(Py_IsFalse)
+#define Py_IsFalse(x) Py_Is(x, Py_False)
#endif
-
// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
-static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
+static inline void
+_Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
{
ob->ob_type = type;
}
#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
#endif
-
// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
-static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
+static inline void
+_Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
{
ob->ob_size = size;
}
-#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
+#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size)
#endif
-
// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 || defined(PYPY_VERSION)
-static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame)
+static inline PyCodeObject *
+PyFrame_GetCode(PyFrameObject *frame)
{
assert(frame != _Py_NULL);
assert(frame->f_code != _Py_NULL);
- return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
+ return _Py_CAST(PyCodeObject *, Py_NewRef(frame->f_code));
}
#endif
-static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame)
+static inline PyCodeObject *
+_PyFrame_GetCodeBorrow(PyFrameObject *frame)
{
PyCodeObject *code = PyFrame_GetCode(frame);
Py_DECREF(code);
return code;
}
-
// bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
-static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame)
+static inline PyFrameObject *
+PyFrame_GetBack(PyFrameObject *frame)
{
assert(frame != _Py_NULL);
- return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
+ return _Py_CAST(PyFrameObject *, Py_XNewRef(frame->f_back));
}
#endif
#if !defined(PYPY_VERSION)
-static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
+static inline PyFrameObject *
+_PyFrame_GetBackBorrow(PyFrameObject *frame)
{
PyFrameObject *back = PyFrame_GetBack(frame);
Py_XDECREF(back);
@@ -184,10 +186,10 @@ static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
}
#endif
-
// bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
-static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
+static inline PyObject *
+PyFrame_GetLocals(PyFrameObject *frame)
{
#if PY_VERSION_HEX >= 0x030400B1
if (PyFrame_FastToLocalsWithError(frame) < 0) {
@@ -200,28 +202,28 @@ static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame)
}
#endif
-
// bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
-static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame)
+static inline PyObject *
+PyFrame_GetGlobals(PyFrameObject *frame)
{
return Py_NewRef(frame->f_globals);
}
#endif
-
// bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7
#if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION)
-static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame)
+static inline PyObject *
+PyFrame_GetBuiltins(PyFrameObject *frame)
{
return Py_NewRef(frame->f_builtins);
}
#endif
-
// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
-static inline int PyFrame_GetLasti(PyFrameObject *frame)
+static inline int
+PyFrame_GetLasti(PyFrameObject *frame)
{
#if PY_VERSION_HEX >= 0x030A00A7
// bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset,
@@ -237,10 +239,10 @@ static inline int PyFrame_GetLasti(PyFrameObject *frame)
}
#endif
-
// gh-91248 added PyFrame_GetVar() to Python 3.12.0a2
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
-static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
+static inline PyObject *
+PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
{
PyObject *locals, *value;
@@ -270,10 +272,9 @@ static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name)
}
#endif
-
// gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2
#if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION)
-static inline PyObject*
+static inline PyObject *
PyFrame_GetVarString(PyFrameObject *frame, const char *name)
{
PyObject *name_obj, *value;
@@ -291,9 +292,9 @@ PyFrame_GetVarString(PyFrameObject *frame, const char *name)
}
#endif
-
// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
-#if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000)
+#if PY_VERSION_HEX < 0x030900A5 || \
+ (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000)
static inline PyInterpreterState *
PyThreadState_GetInterpreter(PyThreadState *tstate)
{
@@ -302,10 +303,10 @@ PyThreadState_GetInterpreter(PyThreadState *tstate)
}
#endif
-
// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
-static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
+static inline PyFrameObject *
+PyThreadState_GetFrame(PyThreadState *tstate)
{
assert(tstate != _Py_NULL);
return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
@@ -313,7 +314,7 @@ static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate)
#endif
#if !defined(PYPY_VERSION)
-static inline PyFrameObject*
+static inline PyFrameObject *
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
{
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
@@ -322,10 +323,10 @@ _PyThreadState_GetFrameBorrow(PyThreadState *tstate)
}
#endif
-
// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5
#if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION)
-static inline PyInterpreterState* PyInterpreterState_Get(void)
+static inline PyInterpreterState *
+PyInterpreterState_Get(void)
{
PyThreadState *tstate;
PyInterpreterState *interp;
@@ -342,10 +343,11 @@ static inline PyInterpreterState* PyInterpreterState_Get(void)
}
#endif
-
// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6
-#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
-static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
+#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && \
+ !defined(PYPY_VERSION)
+static inline uint64_t
+PyThreadState_GetID(PyThreadState *tstate)
{
assert(tstate != _Py_NULL);
return tstate->id;
@@ -354,7 +356,8 @@ static inline uint64_t PyThreadState_GetID(PyThreadState *tstate)
// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
-static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
+static inline void
+PyThreadState_EnterTracing(PyThreadState *tstate)
{
tstate->tracing++;
#if PY_VERSION_HEX >= 0x030A00A1
@@ -367,10 +370,11 @@ static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
-static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
+static inline void
+PyThreadState_LeaveTracing(PyThreadState *tstate)
{
- int use_tracing = (tstate->c_tracefunc != _Py_NULL
- || tstate->c_profilefunc != _Py_NULL);
+ int use_tracing =
+ (tstate->c_tracefunc != _Py_NULL || tstate->c_profilefunc != _Py_NULL);
tstate->tracing--;
#if PY_VERSION_HEX >= 0x030A00A1
tstate->cframe->use_tracing = use_tracing;
@@ -380,28 +384,27 @@ static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
}
#endif
-
// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1
// PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11
#if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1
-static inline PyObject* PyObject_CallNoArgs(PyObject *func)
+static inline PyObject *
+PyObject_CallNoArgs(PyObject *func)
{
return PyObject_CallFunctionObjArgs(func, NULL);
}
#endif
-
// bpo-39245 made PyObject_CallOneArg() public (previously called
// _PyObject_CallOneArg) in Python 3.9.0a4
// PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11
#if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4
-static inline PyObject* PyObject_CallOneArg(PyObject *func, PyObject *arg)
+static inline PyObject *
+PyObject_CallOneArg(PyObject *func, PyObject *arg)
{
return PyObject_CallFunctionObjArgs(func, arg, NULL);
}
#endif
-
// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
#if PY_VERSION_HEX < 0x030A00A3
static inline int
@@ -426,10 +429,10 @@ PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value)
}
#endif
-
// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
#if PY_VERSION_HEX < 0x030900A5
-static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
+static inline int
+PyModule_AddType(PyObject *module, PyTypeObject *type)
{
const char *name, *dot;
@@ -449,11 +452,11 @@ static inline int PyModule_AddType(PyObject *module, PyTypeObject *type)
}
#endif
-
// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6.
// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2.
#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
-static inline int PyObject_GC_IsTracked(PyObject* obj)
+static inline int
+PyObject_GC_IsTracked(PyObject *obj)
{
return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj));
}
@@ -461,69 +464,89 @@ static inline int PyObject_GC_IsTracked(PyObject* obj)
// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6.
// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final.
-#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION)
-static inline int PyObject_GC_IsFinalized(PyObject *obj)
+#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && \
+ !defined(PYPY_VERSION)
+static inline int
+PyObject_GC_IsFinalized(PyObject *obj)
{
- PyGC_Head *gc = _Py_CAST(PyGC_Head*, obj) - 1;
+ PyGC_Head *gc = _Py_CAST(PyGC_Head *, obj) - 1;
return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc));
}
#endif
-
// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
-static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
+static inline int
+_Py_IS_TYPE(PyObject *ob, PyTypeObject *type)
+{
return Py_TYPE(ob) == type;
}
#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type)
#endif
-
// bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7.
// bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1.
// Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal
// C API: Python 3.11a2-3.11a6 versions are not supported.
-#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
-static inline int PyFloat_Pack2(double x, char *p, int le)
-{ return _PyFloat_Pack2(x, (unsigned char*)p, le); }
+#if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && \
+ !defined(PYPY_VERSION)
+static inline int
+PyFloat_Pack2(double x, char *p, int le)
+{
+ return _PyFloat_Pack2(x, (unsigned char *)p, le);
+}
-static inline double PyFloat_Unpack2(const char *p, int le)
-{ return _PyFloat_Unpack2((const unsigned char *)p, le); }
+static inline double
+PyFloat_Unpack2(const char *p, int le)
+{
+ return _PyFloat_Unpack2((const unsigned char *)p, le);
+}
#endif
-
// bpo-46906 added PyFloat_Pack4(), PyFloat_Pack8(), PyFloat_Unpack4() and
// PyFloat_Unpack8() to Python 3.11a7.
// Python 3.11a2 moved _PyFloat_Pack4(), _PyFloat_Pack8(), _PyFloat_Unpack4()
// and _PyFloat_Unpack8() to the internal C API: Python 3.11a2-3.11a6 versions
// are not supported.
#if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION)
-static inline int PyFloat_Pack4(double x, char *p, int le)
-{ return _PyFloat_Pack4(x, (unsigned char*)p, le); }
+static inline int
+PyFloat_Pack4(double x, char *p, int le)
+{
+ return _PyFloat_Pack4(x, (unsigned char *)p, le);
+}
-static inline int PyFloat_Pack8(double x, char *p, int le)
-{ return _PyFloat_Pack8(x, (unsigned char*)p, le); }
+static inline int
+PyFloat_Pack8(double x, char *p, int le)
+{
+ return _PyFloat_Pack8(x, (unsigned char *)p, le);
+}
-static inline double PyFloat_Unpack4(const char *p, int le)
-{ return _PyFloat_Unpack4((const unsigned char *)p, le); }
+static inline double
+PyFloat_Unpack4(const char *p, int le)
+{
+ return _PyFloat_Unpack4((const unsigned char *)p, le);
+}
-static inline double PyFloat_Unpack8(const char *p, int le)
-{ return _PyFloat_Unpack8((const unsigned char *)p, le); }
+static inline double
+PyFloat_Unpack8(const char *p, int le)
+{
+ return _PyFloat_Unpack8((const unsigned char *)p, le);
+}
#endif
-
// gh-92154 added PyCode_GetCode() to Python 3.11.0b1
#if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION)
-static inline PyObject* PyCode_GetCode(PyCodeObject *code)
+static inline PyObject *
+PyCode_GetCode(PyCodeObject *code)
{
return Py_NewRef(code->co_code);
}
#endif
-
// gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
-static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
+static inline PyObject *
+PyCode_GetVarnames(PyCodeObject *code)
{
return Py_NewRef(code->co_varnames);
}
@@ -531,7 +554,8 @@ static inline PyObject* PyCode_GetVarnames(PyCodeObject *code)
// gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
-static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
+static inline PyObject *
+PyCode_GetFreevars(PyCodeObject *code)
{
return Py_NewRef(code->co_freevars);
}
@@ -539,35 +563,35 @@ static inline PyObject* PyCode_GetFreevars(PyCodeObject *code)
// gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1
#if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION)
-static inline PyObject* PyCode_GetCellvars(PyCodeObject *code)
+static inline PyObject *
+PyCode_GetCellvars(PyCodeObject *code)
{
return Py_NewRef(code->co_cellvars);
}
#endif
-
// Py_UNUSED() was added to Python 3.4.0b2.
#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
-# if defined(__GNUC__) || defined(__clang__)
-# define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
-# else
-# define Py_UNUSED(name) _unused_ ## name
-# endif
+#if defined(__GNUC__) || defined(__clang__)
+#define Py_UNUSED(name) _unused_##name __attribute__((unused))
+#else
+#define Py_UNUSED(name) _unused_##name
+#endif
#endif
-
// gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A0
-static inline PyObject* PyImport_AddModuleRef(const char *name)
+static inline PyObject *
+PyImport_AddModuleRef(const char *name)
{
return Py_XNewRef(PyImport_AddModule(name));
}
#endif
-
// gh-105927 added PyWeakref_GetRef() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D0000
-static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
+static inline int
+PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
{
PyObject *obj;
if (ref != NULL && !PyWeakref_Check(ref)) {
@@ -590,26 +614,26 @@ static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
}
#endif
-
// bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1
#ifndef PY_VECTORCALL_ARGUMENTS_OFFSET
-# define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1))
+#define PY_VECTORCALL_ARGUMENTS_OFFSET \
+ (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1))
#endif
// bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1
#if PY_VERSION_HEX < 0x030800B1
-static inline Py_ssize_t PyVectorcall_NARGS(size_t n)
+static inline Py_ssize_t
+PyVectorcall_NARGS(size_t n)
{
return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET;
}
#endif
-
// gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4
#if PY_VERSION_HEX < 0x030900A4
-static inline PyObject*
-PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
- size_t nargsf, PyObject *kwnames)
+static inline PyObject *
+PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf,
+ PyObject *kwnames)
{
#if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION)
// bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1
@@ -631,8 +655,7 @@ PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf);
if (kwnames) {
nkwargs = PyTuple_GET_SIZE(kwnames);
- }
- else {
+ } else {
nkwargs = 0;
}
@@ -641,7 +664,7 @@ PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
goto error;
}
if (nposargs) {
- for (i=0; i < nposargs; i++) {
+ for (i = 0; i < nposargs; i++) {
PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args));
args++;
}
@@ -661,8 +684,7 @@ PyObject_Vectorcall(PyObject *callable, PyObject *const *args,
goto error;
}
}
- }
- else {
+ } else {
kwargs = NULL;
}
@@ -679,7 +701,6 @@ error:
}
#endif
-
// gh-106521 added PyObject_GetOptionalAttr() and
// PyObject_GetOptionalAttrString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
@@ -706,7 +727,8 @@ PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result)
}
static inline int
-PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result)
+PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name,
+ PyObject **result)
{
PyObject *name_obj;
int rc;
@@ -725,7 +747,6 @@ PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **
}
#endif
-
// gh-106307 added PyObject_GetOptionalAttr() and
// PyMapping_GetOptionalItemString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
@@ -744,7 +765,8 @@ PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result)
}
static inline int
-PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result)
+PyMapping_GetOptionalItemString(PyObject *obj, const char *key,
+ PyObject **result)
{
PyObject *key_obj;
int rc;
@@ -785,7 +807,6 @@ PyMapping_HasKeyStringWithError(PyObject *obj, const char *key)
}
#endif
-
// gh-108511 added PyObject_HasAttrWithError() and
// PyObject_HasAttrStringWithError() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
@@ -808,7 +829,6 @@ PyObject_HasAttrStringWithError(PyObject *obj, const char *attr)
}
#endif
-
// gh-106004 added PyDict_GetItemRef() and PyDict_GetItemStringRef()
// to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
@@ -851,7 +871,6 @@ PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result)
}
#endif
-
// gh-106307 added PyModule_Add() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
@@ -863,13 +882,13 @@ PyModule_Add(PyObject *mod, const char *name, PyObject *value)
}
#endif
-
// gh-108014 added Py_IsFinalizing() to Python 3.13.0a1
// bpo-1856 added _Py_Finalizing to Python 3.2.1b1.
// _Py_IsFinalizing() was added to PyPy 7.3.0.
-#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \
- && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000)
-static inline int Py_IsFinalizing(void)
+#if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) && \
+ (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000)
+static inline int
+Py_IsFinalizing(void)
{
#if PY_VERSION_HEX >= 0x030700A1
// _Py_IsFinalizing() was added to Python 3.7.0a1.
@@ -880,10 +899,10 @@ static inline int Py_IsFinalizing(void)
}
#endif
-
// gh-108323 added PyDict_ContainsString() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
-static inline int PyDict_ContainsString(PyObject *op, const char *key)
+static inline int
+PyDict_ContainsString(PyObject *op, const char *key)
{
PyObject *key_obj = PyUnicode_FromString(key);
if (key_obj == NULL) {
@@ -895,10 +914,10 @@ static inline int PyDict_ContainsString(PyObject *op, const char *key)
}
#endif
-
// gh-108445 added PyLong_AsInt() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
-static inline int PyLong_AsInt(PyObject *obj)
+static inline int
+PyLong_AsInt(PyObject *obj)
{
#ifdef PYPY_VERSION
long value = PyLong_AsLong(obj);
@@ -917,7 +936,6 @@ static inline int PyLong_AsInt(PyObject *obj)
}
#endif
-
// gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
@@ -945,7 +963,7 @@ PyObject_ClearManagedDict(PyObject *obj)
// gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1
// Python 3.5.2 added _PyThreadState_UncheckedGet().
#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1
-static inline PyThreadState*
+static inline PyThreadState *
PyThreadState_GetUnchecked(void)
{
return _PyThreadState_UncheckedGet();
@@ -956,7 +974,8 @@ PyThreadState_GetUnchecked(void)
// to Python 3.13.0a1
#if PY_VERSION_HEX < 0x030D00A1
static inline int
-PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_len)
+PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str,
+ Py_ssize_t str_len)
{
Py_ssize_t len;
const void *utf8;
@@ -971,8 +990,7 @@ PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_
if (PyUnicode_IS_ASCII(unicode)) {
utf8 = PyUnicode_DATA(unicode);
len = PyUnicode_GET_LENGTH(unicode);
- }
- else {
+ } else {
utf8 = PyUnicode_AsUTF8AndSize(unicode, &len);
if (utf8 == NULL) {
// Memory allocation failure. The API cannot report error,
@@ -1025,7 +1043,6 @@ PyUnicode_EqualToUTF8(PyObject *unicode, const char *str)
}
#endif
-
// gh-111138 added PyList_Extend() and PyList_Clear() to Python 3.13.0a2
#if PY_VERSION_HEX < 0x030D00A2
static inline int
@@ -1059,10 +1076,11 @@ PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result)
// bpo-16991 added _PyDict_Pop() to Python 3.5.0b2.
// Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*.
// Python 3.13.0a1 removed _PyDict_Pop().
-#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000
+#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || \
+ PY_VERSION_HEX >= 0x030D0000
value = PyObject_CallMethod(dict, "pop", "O", key);
#elif PY_VERSION_HEX < 0x030600b3
- value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL);
+ value = _PyDict_Pop(_Py_CAST(PyDictObject *, dict), key, NULL);
#else
value = _PyDict_Pop(dict, key, NULL);
#endif
@@ -1078,8 +1096,7 @@ PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result)
}
if (result) {
*result = value;
- }
- else {
+ } else {
Py_DECREF(value);
}
return 1;
@@ -1102,43 +1119,51 @@ PyDict_PopString(PyObject *dict, const char *key, PyObject **result)
}
#endif
-
#if PY_VERSION_HEX < 0x030200A4
// Python 3.2.0a4 added Py_hash_t type
typedef Py_ssize_t Py_hash_t;
#endif
-
// gh-111545 added Py_HashPointer() to Python 3.13.0a3
#if PY_VERSION_HEX < 0x030D00A3
-static inline Py_hash_t Py_HashPointer(const void *ptr)
+static inline Py_hash_t
+Py_HashPointer(const void *ptr)
{
#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION)
return _Py_HashPointer(ptr);
#else
- return _Py_HashPointer(_Py_CAST(void*, ptr));
+ return _Py_HashPointer(_Py_CAST(void *, ptr));
#endif
}
#endif
-
// Python 3.13a4 added a PyTime API.
// Use the private API added to Python 3.5.
-#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000
+#if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000
typedef _PyTime_t PyTime_t;
#define PyTime_MIN _PyTime_MIN
#define PyTime_MAX _PyTime_MAX
-static inline double PyTime_AsSecondsDouble(PyTime_t t)
-{ return _PyTime_AsSecondsDouble(t); }
+static inline double
+PyTime_AsSecondsDouble(PyTime_t t)
+{
+ return _PyTime_AsSecondsDouble(t);
+}
-static inline int PyTime_Monotonic(PyTime_t *result)
-{ return _PyTime_GetMonotonicClockWithInfo(result, NULL); }
+static inline int
+PyTime_Monotonic(PyTime_t *result)
+{
+ return _PyTime_GetMonotonicClockWithInfo(result, NULL);
+}
-static inline int PyTime_Time(PyTime_t *result)
-{ return _PyTime_GetSystemClockWithInfo(result, NULL); }
+static inline int
+PyTime_Time(PyTime_t *result)
+{
+ return _PyTime_GetSystemClockWithInfo(result, NULL);
+}
-static inline int PyTime_PerfCounter(PyTime_t *result)
+static inline int
+PyTime_PerfCounter(PyTime_t *result)
{
#if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION)
return _PyTime_GetPerfCounterWithInfo(result, NULL);
@@ -1211,17 +1236,16 @@ static inline int PyTime_PerfCounter(PyTime_t *result)
// gh-111389 added hash constants to Python 3.13.0a5. These constants were
// added first as private macros to Python 3.4.0b1 and PyPy 7.3.8.
-#if (!defined(PyHASH_BITS) \
- && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \
- || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \
- && PYPY_VERSION_NUM >= 0x07030800)))
-# define PyHASH_BITS _PyHASH_BITS
-# define PyHASH_MODULUS _PyHASH_MODULUS
-# define PyHASH_INF _PyHASH_INF
-# define PyHASH_IMAG _PyHASH_IMAG
+#if (!defined(PyHASH_BITS) && \
+ ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) || \
+ (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 && \
+ PYPY_VERSION_NUM >= 0x07030800)))
+#define PyHASH_BITS _PyHASH_BITS
+#define PyHASH_MODULUS _PyHASH_MODULUS
+#define PyHASH_INF _PyHASH_INF
+#define PyHASH_IMAG _PyHASH_IMAG
#endif
-
// gh-111545 added Py_GetConstant() and Py_GetConstantBorrowed()
// to Python 3.13.0a6
#if PY_VERSION_HEX < 0x030D00A6 && !defined(Py_CONSTANT_NONE)
@@ -1237,9 +1261,10 @@ static inline int PyTime_PerfCounter(PyTime_t *result)
#define Py_CONSTANT_EMPTY_BYTES 8
#define Py_CONSTANT_EMPTY_TUPLE 9
-static inline PyObject* Py_GetConstant(unsigned int constant_id)
+static inline PyObject *
+Py_GetConstant(unsigned int constant_id)
{
- static PyObject* constants[Py_CONSTANT_EMPTY_TUPLE + 1] = {NULL};
+ static PyObject *constants[Py_CONSTANT_EMPTY_TUPLE + 1] = {NULL};
if (constants[Py_CONSTANT_NONE] == NULL) {
constants[Py_CONSTANT_NONE] = Py_None;
@@ -1275,7 +1300,7 @@ static inline PyObject* Py_GetConstant(unsigned int constant_id)
// goto dance to avoid compiler warnings about Py_FatalError()
goto init_done;
-fatal_error:
+ fatal_error:
// This case should never happen
Py_FatalError("Py_GetConstant() failed to get constants");
}
@@ -1283,14 +1308,14 @@ fatal_error:
init_done:
if (constant_id <= Py_CONSTANT_EMPTY_TUPLE) {
return Py_NewRef(constants[constant_id]);
- }
- else {
+ } else {
PyErr_BadInternalCall();
return NULL;
}
}
-static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
+static inline PyObject *
+Py_GetConstantBorrowed(unsigned int constant_id)
{
PyObject *obj = Py_GetConstant(constant_id);
Py_XDECREF(obj);
@@ -1298,7 +1323,6 @@ static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id)
}
#endif
-
// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
#if PY_VERSION_HEX < 0x030D00A4
static inline PyObject *
@@ -1310,7 +1334,6 @@ PyList_GetItemRef(PyObject *op, Py_ssize_t index)
}
#endif
-
// gh-114329 added PyList_GetItemRef() to Python 3.13.0a4
#if PY_VERSION_HEX < 0x030D00A4
static inline int
@@ -1329,8 +1352,7 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
// present
if (result) {
*result = value;
- }
- else {
+ } else {
Py_DECREF(value);
}
return 1;
@@ -1352,26 +1374,28 @@ PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value,
#endif
#if PY_VERSION_HEX < 0x030D00B3
-# define Py_BEGIN_CRITICAL_SECTION(op) {
-# define Py_END_CRITICAL_SECTION() }
-# define Py_BEGIN_CRITICAL_SECTION2(a, b) {
-# define Py_END_CRITICAL_SECTION2() }
+#define Py_BEGIN_CRITICAL_SECTION(op) {
+#define Py_END_CRITICAL_SECTION() }
+#define Py_BEGIN_CRITICAL_SECTION2(a, b) {
+#define Py_END_CRITICAL_SECTION2() }
#endif
-#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
+#if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && \
+ !defined(PYPY_VERSION)
typedef struct PyUnicodeWriter PyUnicodeWriter;
-static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
+static inline void
+PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
{
- _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer);
+ _PyUnicodeWriter_Dealloc((_PyUnicodeWriter *)writer);
PyMem_Free(writer);
}
-static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
+static inline PyUnicodeWriter *
+PyUnicodeWriter_Create(Py_ssize_t length)
{
if (length < 0) {
- PyErr_SetString(PyExc_ValueError,
- "length must be positive");
+ PyErr_SetString(PyExc_ValueError, "length must be positive");
return NULL;
}
@@ -1392,10 +1416,11 @@ static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length)
return pub_writer;
}
-static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
+static inline PyObject *
+PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
{
- PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer);
- assert(((_PyUnicodeWriter*)writer)->buffer == NULL);
+ PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter *)writer);
+ assert(((_PyUnicodeWriter *)writer)->buffer == NULL);
PyMem_Free(writer);
return str;
}
@@ -1409,7 +1434,7 @@ PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
return -1;
}
- return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch);
+ return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter *)writer, ch);
}
static inline int
@@ -1420,7 +1445,7 @@ PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
return -1;
}
- int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter *)writer, str);
Py_DECREF(str);
return res;
}
@@ -1433,14 +1458,14 @@ PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
return -1;
}
- int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter *)writer, str);
Py_DECREF(str);
return res;
}
static inline int
-PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
- const char *str, Py_ssize_t size)
+PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, const char *str,
+ Py_ssize_t size)
{
if (size < 0) {
size = (Py_ssize_t)strlen(str);
@@ -1451,14 +1476,14 @@ PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer,
return -1;
}
- int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter *)writer, str_obj);
Py_DECREF(str_obj);
return res;
}
static inline int
-PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer,
- const wchar_t *str, Py_ssize_t size)
+PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer, const wchar_t *str,
+ Py_ssize_t size)
{
if (size < 0) {
size = (Py_ssize_t)wcslen(str);
@@ -1469,7 +1494,7 @@ PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer,
return -1;
}
- int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj);
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter *)writer, str_obj);
Py_DECREF(str_obj);
return res;
}
@@ -1491,8 +1516,8 @@ PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str,
return -1;
}
- return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str,
- start, end);
+ return _PyUnicodeWriter_WriteSubstring(
+ (_PyUnicodeWriter *)writer, str, start, end);
}
static inline int
@@ -1506,7 +1531,7 @@ PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
return -1;
}
- int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str);
+ int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter *)writer, str);
Py_DECREF(str);
return res;
}
@@ -1514,10 +1539,12 @@ PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
// gh-116560 added PyLong_GetSign() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
-static inline int PyLong_GetSign(PyObject *obj, int *sign)
+static inline int
+PyLong_GetSign(PyObject *obj, int *sign)
{
if (!PyLong_Check(obj)) {
- PyErr_Format(PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name);
+ PyErr_Format(
+ PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name);
return -1;
}
@@ -1528,52 +1555,60 @@ static inline int PyLong_GetSign(PyObject *obj, int *sign)
// gh-126061 added PyLong_IsPositive/Negative/Zero() to Python in 3.14.0a2
#if PY_VERSION_HEX < 0x030E00A2
-static inline int PyLong_IsPositive(PyObject *obj)
+static inline int
+PyLong_IsPositive(PyObject *obj)
{
if (!PyLong_Check(obj)) {
- PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
+ PyErr_Format(
+ PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
return -1;
}
return _PyLong_Sign(obj) == 1;
}
-static inline int PyLong_IsNegative(PyObject *obj)
+static inline int
+PyLong_IsNegative(PyObject *obj)
{
if (!PyLong_Check(obj)) {
- PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
+ PyErr_Format(
+ PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
return -1;
}
return _PyLong_Sign(obj) == -1;
}
-static inline int PyLong_IsZero(PyObject *obj)
+static inline int
+PyLong_IsZero(PyObject *obj)
{
if (!PyLong_Check(obj)) {
- PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
+ PyErr_Format(
+ PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
return -1;
}
return _PyLong_Sign(obj) == 0;
}
#endif
-
// gh-124502 added PyUnicode_Equal() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
-static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
+static inline int
+PyUnicode_Equal(PyObject *str1, PyObject *str2)
{
if (!PyUnicode_Check(str1)) {
- PyErr_Format(PyExc_TypeError, "first argument must be str, not %s",
+ PyErr_Format(PyExc_TypeError,
+ "first argument must be str, not %s",
Py_TYPE(str1)->tp_name);
return -1;
}
if (!PyUnicode_Check(str2)) {
- PyErr_Format(PyExc_TypeError, "second argument must be str, not %s",
+ PyErr_Format(PyExc_TypeError,
+ "second argument must be str, not %s",
Py_TYPE(str2)->tp_name);
return -1;
}
#if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION)
- PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2);
+ PyAPI_FUNC(int) _PyUnicode_Equal(PyObject * str1, PyObject * str2);
return _PyUnicode_Equal(str1, str2);
#elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION)
@@ -1586,18 +1621,18 @@ static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2)
}
#endif
-
// gh-121645 added PyBytes_Join() to Python 3.14.0a0
#if PY_VERSION_HEX < 0x030E00A0
-static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable)
+static inline PyObject *
+PyBytes_Join(PyObject *sep, PyObject *iterable)
{
return _PyBytes_Join(sep, iterable);
}
#endif
-
#if PY_VERSION_HEX < 0x030E00A0
-static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
+static inline Py_hash_t
+Py_HashBuffer(const void *ptr, Py_ssize_t len)
{
#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len);
@@ -1605,7 +1640,7 @@ static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
return _Py_HashBytes(ptr, len);
#else
Py_hash_t hash;
- PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len);
+ PyObject *bytes = PyBytes_FromStringAndSize((const char *)ptr, len);
if (bytes == NULL) {
return -1;
}
@@ -1616,9 +1651,9 @@ static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len)
}
#endif
-
#if PY_VERSION_HEX < 0x030E00A0
-static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
+static inline int
+PyIter_NextItem(PyObject *iter, PyObject **item)
{
iternextfunc tp_iternext;
@@ -1628,7 +1663,8 @@ static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
tp_iternext = Py_TYPE(iter)->tp_iternext;
if (tp_iternext == NULL) {
*item = NULL;
- PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'",
+ PyErr_Format(PyExc_TypeError,
+ "expected an iterator, got '%s'",
Py_TYPE(iter)->tp_name);
return -1;
}
@@ -1647,33 +1683,37 @@ static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
}
#endif
-
#if PY_VERSION_HEX < 0x030E00A0
-static inline PyObject* PyLong_FromInt32(int32_t value)
+static inline PyObject *
+PyLong_FromInt32(int32_t value)
{
Py_BUILD_ASSERT(sizeof(long) >= 4);
return PyLong_FromLong(value);
}
-static inline PyObject* PyLong_FromInt64(int64_t value)
+static inline PyObject *
+PyLong_FromInt64(int64_t value)
{
Py_BUILD_ASSERT(sizeof(long long) >= 8);
return PyLong_FromLongLong(value);
}
-static inline PyObject* PyLong_FromUInt32(uint32_t value)
+static inline PyObject *
+PyLong_FromUInt32(uint32_t value)
{
Py_BUILD_ASSERT(sizeof(unsigned long) >= 4);
return PyLong_FromUnsignedLong(value);
}
-static inline PyObject* PyLong_FromUInt64(uint64_t value)
+static inline PyObject *
+PyLong_FromUInt64(uint64_t value)
{
Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8);
return PyLong_FromUnsignedLongLong(value);
}
-static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
+static inline int
+PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
{
Py_BUILD_ASSERT(sizeof(int) == 4);
int value = PyLong_AsInt(obj);
@@ -1684,7 +1724,8 @@ static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
return 0;
}
-static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
+static inline int
+PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
{
Py_BUILD_ASSERT(sizeof(long long) == 8);
long long value = PyLong_AsLongLong(obj);
@@ -1695,7 +1736,8 @@ static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
return 0;
}
-static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
+static inline int
+PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
{
Py_BUILD_ASSERT(sizeof(long) >= 4);
unsigned long value = PyLong_AsUnsignedLong(obj);
@@ -1713,7 +1755,8 @@ static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
return 0;
}
-static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
+static inline int
+PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
{
Py_BUILD_ASSERT(sizeof(long long) == 8);
unsigned long long value = PyLong_AsUnsignedLongLong(obj);
@@ -1725,9 +1768,9 @@ static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
}
#endif
-
// gh-102471 added import and export API for integers to 3.14.0a2.
-#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
+#if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && \
+ !defined(PYPY_VERSION)
// Helpers to access PyLongObject internals.
static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
@@ -1747,17 +1790,17 @@ _PyLong_DigitCount(const PyLongObject *op)
#if PY_VERSION_HEX >= 0x030C0000
return (Py_ssize_t)(op->long_value.lv_tag >> 3);
#else
- return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op);
+ return _PyLong_Sign((PyObject *)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op);
#endif
}
-static inline digit*
+static inline digit *
_PyLong_GetDigits(const PyLongObject *op)
{
#if PY_VERSION_HEX >= 0x030C0000
- return (digit*)(op->long_value.ob_digit);
+ return (digit *)(op->long_value.ob_digit);
#else
- return (digit*)(op->ob_digit);
+ return (digit *)(op->ob_digit);
#endif
}
@@ -1778,7 +1821,7 @@ typedef struct PyLongExport {
typedef struct PyLongWriter PyLongWriter;
-static inline const PyLongLayout*
+static inline const PyLongLayout *
PyLong_GetNativeLayout(void)
{
static const PyLongLayout PyLong_LAYOUT = {
@@ -1796,13 +1839,13 @@ PyLong_Export(PyObject *obj, PyLongExport *export_long)
{
if (!PyLong_Check(obj)) {
memset(export_long, 0, sizeof(*export_long));
- PyErr_Format(PyExc_TypeError, "expected int, got %s",
- Py_TYPE(obj)->tp_name);
+ PyErr_Format(
+ PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name);
return -1;
}
// Fast-path: try to convert to a int64_t
- PyLongObject *self = (PyLongObject*)obj;
+ PyLongObject *self = (PyLongObject *)obj;
int overflow;
#if SIZEOF_LONG == 8
long value = PyLong_AsLongAndOverflow(obj, &overflow);
@@ -1820,8 +1863,7 @@ PyLong_Export(PyObject *obj, PyLongExport *export_long)
export_long->ndigits = 0;
export_long->digits = 0;
export_long->_reserved = 0;
- }
- else {
+ } else {
export_long->value = 0;
export_long->negative = _PyLong_Sign(obj) < 0;
export_long->ndigits = _PyLong_DigitCount(self);
@@ -1837,7 +1879,7 @@ PyLong_Export(PyObject *obj, PyLongExport *export_long)
static inline void
PyLong_FreeExport(PyLongExport *export_long)
{
- PyObject *obj = (PyObject*)export_long->_reserved;
+ PyObject *obj = (PyObject *)export_long->_reserved;
if (obj) {
export_long->_reserved = 0;
@@ -1845,7 +1887,7 @@ PyLong_FreeExport(PyLongExport *export_long)
}
}
-static inline PyLongWriter*
+static inline PyLongWriter *
PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
{
if (ndigits <= 0) {
@@ -1858,10 +1900,10 @@ PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
if (obj == NULL) {
return NULL;
}
- _PyLong_SetSignAndDigitCount(obj, negative?-1:1, ndigits);
+ _PyLong_SetSignAndDigitCount(obj, negative ? -1 : 1, ndigits);
*digits = _PyLong_GetDigits(obj);
- return (PyLongWriter*)obj;
+ return (PyLongWriter *)obj;
}
static inline void
@@ -1873,11 +1915,11 @@ PyLongWriter_Discard(PyLongWriter *writer)
Py_DECREF(obj);
}
-static inline PyObject*
+static inline PyObject *
PyLongWriter_Finish(PyLongWriter *writer)
{
PyObject *obj = (PyObject *)writer;
- PyLongObject *self = (PyLongObject*)obj;
+ PyLongObject *self = (PyLongObject *)obj;
Py_ssize_t j = _PyLong_DigitCount(self);
Py_ssize_t i = j;
int sign = _PyLong_Sign(obj);
@@ -1885,7 +1927,7 @@ PyLongWriter_Finish(PyLongWriter *writer)
assert(Py_REFCNT(obj) == 1);
// Normalize and get singleton if possible
- while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) {
+ while (i > 0 && _PyLong_GetDigits(self)[i - 1] == 0) {
--i;
}
if (i != j) {
@@ -1904,44 +1946,43 @@ PyLongWriter_Finish(PyLongWriter *writer)
}
#endif
-
#if PY_VERSION_HEX < 0x030C00A3
-# define Py_T_SHORT T_SHORT
-# define Py_T_INT T_INT
-# define Py_T_LONG T_LONG
-# define Py_T_FLOAT T_FLOAT
-# define Py_T_DOUBLE T_DOUBLE
-# define Py_T_STRING T_STRING
-# define _Py_T_OBJECT T_OBJECT
-# define Py_T_CHAR T_CHAR
-# define Py_T_BYTE T_BYTE
-# define Py_T_UBYTE T_UBYTE
-# define Py_T_USHORT T_USHORT
-# define Py_T_UINT T_UINT
-# define Py_T_ULONG T_ULONG
-# define Py_T_STRING_INPLACE T_STRING_INPLACE
-# define Py_T_BOOL T_BOOL
-# define Py_T_OBJECT_EX T_OBJECT_EX
-# define Py_T_LONGLONG T_LONGLONG
-# define Py_T_ULONGLONG T_ULONGLONG
-# define Py_T_PYSSIZET T_PYSSIZET
-
-# if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
-# define _Py_T_NONE T_NONE
-# endif
-
-# define Py_READONLY READONLY
-# define Py_AUDIT_READ READ_RESTRICTED
-# define _Py_WRITE_RESTRICTED PY_WRITE_RESTRICTED
+#define Py_T_SHORT T_SHORT
+#define Py_T_INT T_INT
+#define Py_T_LONG T_LONG
+#define Py_T_FLOAT T_FLOAT
+#define Py_T_DOUBLE T_DOUBLE
+#define Py_T_STRING T_STRING
+#define _Py_T_OBJECT T_OBJECT
+#define Py_T_CHAR T_CHAR
+#define Py_T_BYTE T_BYTE
+#define Py_T_UBYTE T_UBYTE
+#define Py_T_USHORT T_USHORT
+#define Py_T_UINT T_UINT
+#define Py_T_ULONG T_ULONG
+#define Py_T_STRING_INPLACE T_STRING_INPLACE
+#define Py_T_BOOL T_BOOL
+#define Py_T_OBJECT_EX T_OBJECT_EX
+#define Py_T_LONGLONG T_LONGLONG
+#define Py_T_ULONGLONG T_ULONGLONG
+#define Py_T_PYSSIZET T_PYSSIZET
+
+#if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION)
+#define _Py_T_NONE T_NONE
#endif
+#define Py_READONLY READONLY
+#define Py_AUDIT_READ READ_RESTRICTED
+#define _Py_WRITE_RESTRICTED PY_WRITE_RESTRICTED
+#endif
// gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4
#if PY_VERSION_HEX < 0x030E00A4
-static inline FILE* Py_fopen(PyObject *path, const char *mode)
+static inline FILE *
+Py_fopen(PyObject *path, const char *mode)
{
#if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION)
- PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode);
+ PyAPI_FUNC(FILE *) _Py_fopen_obj(PyObject * path, const char *mode);
return _Py_fopen_obj(path, mode);
#else
@@ -1971,15 +2012,16 @@ static inline FILE* Py_fopen(PyObject *path, const char *mode)
#endif
}
-static inline int Py_fclose(FILE *file)
+static inline int
+Py_fclose(FILE *file)
{
return fclose(file);
}
#endif
-
-#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION)
-static inline PyObject*
+#if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && \
+ !defined(PYPY_VERSION)
+static inline PyObject *
PyConfig_Get(const char *name)
{
typedef enum {
@@ -1999,9 +2041,11 @@ PyConfig_Get(const char *name)
const char *sys_attr;
} PyConfigSpec;
-#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \
- {#MEMBER, offsetof(PyConfig, MEMBER), \
- _PyConfig_MEMBER_##TYPE, sys_attr}
+#define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \
+ { \
+ #MEMBER, offsetof(PyConfig, MEMBER), _PyConfig_MEMBER_##TYPE, \
+ sys_attr \
+ }
static const PyConfigSpec config_spec[] = {
PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"),
@@ -2095,7 +2139,7 @@ PyConfig_Get(const char *name)
const PyConfigSpec *spec;
int found = 0;
- for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) {
+ for (size_t i = 0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) {
spec = &config_spec[i];
if (strcmp(spec->name, name) == 0) {
found = 1;
@@ -2106,64 +2150,61 @@ PyConfig_Get(const char *name)
if (spec->sys_attr != NULL) {
PyObject *value = PySys_GetObject(spec->sys_attr);
if (value == NULL) {
- PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr);
+ PyErr_Format(
+ PyExc_RuntimeError, "lost sys.%s", spec->sys_attr);
return NULL;
}
return Py_NewRef(value);
}
- PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void);
+ PyAPI_FUNC(const PyConfig *) _Py_GetConfig(void);
const PyConfig *config = _Py_GetConfig();
void *member = (char *)config + spec->offset;
switch (spec->type) {
- case _PyConfig_MEMBER_INT:
- case _PyConfig_MEMBER_UINT:
- {
- int value = *(int *)member;
- return PyLong_FromLong(value);
- }
- case _PyConfig_MEMBER_BOOL:
- {
- int value = *(int *)member;
- return PyBool_FromLong(value != 0);
- }
- case _PyConfig_MEMBER_ULONG:
- {
- unsigned long value = *(unsigned long *)member;
- return PyLong_FromUnsignedLong(value);
- }
- case _PyConfig_MEMBER_WSTR:
- case _PyConfig_MEMBER_WSTR_OPT:
- {
- wchar_t *wstr = *(wchar_t **)member;
- if (wstr != NULL) {
- return PyUnicode_FromWideChar(wstr, -1);
+ case _PyConfig_MEMBER_INT:
+ case _PyConfig_MEMBER_UINT: {
+ int value = *(int *)member;
+ return PyLong_FromLong(value);
}
- else {
- return Py_NewRef(Py_None);
+ case _PyConfig_MEMBER_BOOL: {
+ int value = *(int *)member;
+ return PyBool_FromLong(value != 0);
}
- }
- case _PyConfig_MEMBER_WSTR_LIST:
- {
- const PyWideStringList *list = (const PyWideStringList *)member;
- PyObject *tuple = PyTuple_New(list->length);
- if (tuple == NULL) {
- return NULL;
+ case _PyConfig_MEMBER_ULONG: {
+ unsigned long value = *(unsigned long *)member;
+ return PyLong_FromUnsignedLong(value);
}
-
- for (Py_ssize_t i = 0; i < list->length; i++) {
- PyObject *item = PyUnicode_FromWideChar(list->items[i], -1);
- if (item == NULL) {
- Py_DECREF(tuple);
+ case _PyConfig_MEMBER_WSTR:
+ case _PyConfig_MEMBER_WSTR_OPT: {
+ wchar_t *wstr = *(wchar_t **)member;
+ if (wstr != NULL) {
+ return PyUnicode_FromWideChar(wstr, -1);
+ } else {
+ return Py_NewRef(Py_None);
+ }
+ }
+ case _PyConfig_MEMBER_WSTR_LIST: {
+ const PyWideStringList *list =
+ (const PyWideStringList *)member;
+ PyObject *tuple = PyTuple_New(list->length);
+ if (tuple == NULL) {
return NULL;
}
- PyTuple_SET_ITEM(tuple, i, item);
+
+ for (Py_ssize_t i = 0; i < list->length; i++) {
+ PyObject *item =
+ PyUnicode_FromWideChar(list->items[i], -1);
+ if (item == NULL) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple, i, item);
+ }
+ return tuple;
}
- return tuple;
- }
- default:
- Py_UNREACHABLE();
+ default:
+ Py_UNREACHABLE();
}
}
@@ -2189,7 +2230,8 @@ PyConfig_GetInt(const char *name, int *value)
Py_DECREF(obj);
if (as_int == -1 && PyErr_Occurred()) {
PyErr_Format(PyExc_OverflowError,
- "config option %s value does not fit into a C int", name);
+ "config option %s value does not fit into a C int",
+ name);
return -1;
}
@@ -2198,7 +2240,6 @@ PyConfig_GetInt(const char *name, int *value)
}
#endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)
-
#ifdef __cplusplus
}
#endif
diff --git a/contrib/python/multidict/multidict/_multilib/state.h b/contrib/python/multidict/multidict/_multilib/state.h
index 58110d973a7..4e2610b6c1d 100644
--- a/contrib/python/multidict/multidict/_multilib/state.h
+++ b/contrib/python/multidict/multidict/_multilib/state.h
@@ -22,8 +22,11 @@ typedef struct {
PyTypeObject *ItemsIterType;
PyTypeObject *ValuesIterType;
- PyObject *str_lower;
PyObject *str_canonical;
+ PyObject *str_lower;
+ PyObject *str_name;
+
+ uint64_t global_version;
} mod_state;
static inline mod_state *
@@ -42,12 +45,11 @@ get_mod_state_by_cls(PyTypeObject *cls)
return state;
}
-
#if PY_VERSION_HEX < 0x030b0000
PyObject *
PyType_GetModuleByDef(PyTypeObject *tp, PyModuleDef *def)
{
- PyModuleDef * mod_def;
+ PyModuleDef *mod_def;
if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
goto err;
}
@@ -75,7 +77,7 @@ PyType_GetModuleByDef(PyTypeObject *tp, PyModuleDef *def)
if (!PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
continue;
}
- mod = PyType_GetModule((PyTypeObject*)super);
+ mod = PyType_GetModule((PyTypeObject *)super);
if (mod == NULL) {
PyErr_Clear();
} else {
@@ -92,7 +94,6 @@ err:
"PyType_GetModuleByDef: No superclass of '%s' has the given module",
tp->tp_name);
return NULL;
-
}
#endif
@@ -115,7 +116,6 @@ get_mod_state_by_def_checked(PyObject *self, mod_state **ret)
return 1;
}
-
static inline mod_state *
get_mod_state_by_def(PyObject *self)
{
@@ -125,6 +125,11 @@ get_mod_state_by_def(PyObject *self)
return get_mod_state(mod);
}
+static inline uint64_t
+NEXT_VERSION(mod_state *state)
+{
+ return ++state->global_version;
+}
#ifdef __cplusplus
}
diff --git a/contrib/python/multidict/multidict/_multilib/views.h b/contrib/python/multidict/multidict/_multilib/views.h
index e734ce57849..a15641d5b0b 100644
--- a/contrib/python/multidict/multidict/_multilib/views.h
+++ b/contrib/python/multidict/multidict/_multilib/views.h
@@ -6,7 +6,7 @@ extern "C" {
#endif
#include "dict.h"
-#include "pair_list.h"
+#include "hashtable.h"
#include "state.h"
typedef struct {
@@ -14,12 +14,10 @@ typedef struct {
MultiDictObject *md;
} _Multidict_ViewObject;
-
#define Items_CheckExact(state, obj) Py_IS_TYPE(obj, state->ItemsViewType)
#define Keys_CheckExact(state, obj) Py_IS_TYPE(obj, state->KeysViewType)
#define Values_CheckExact(state, obj) Py_IS_TYPE(obj, state->ValuesViewType)
-
/********** Base **********/
static inline void
@@ -38,7 +36,8 @@ multidict_view_dealloc(_Multidict_ViewObject *self)
}
static inline int
-multidict_view_traverse(_Multidict_ViewObject *self, visitproc visit, void *arg)
+multidict_view_traverse(_Multidict_ViewObject *self, visitproc visit,
+ void *arg)
{
Py_VISIT(self->md);
return 0;
@@ -54,17 +53,15 @@ multidict_view_clear(_Multidict_ViewObject *self)
static inline Py_ssize_t
multidict_view_len(_Multidict_ViewObject *self)
{
- return pair_list_len(&self->md->pairs);
+ return md_len(self->md);
}
static inline PyObject *
-multidict_view_richcompare(PyObject *self, PyObject *other, int op)
+multidict_view_richcompare(_Multidict_ViewObject *self, PyObject *other,
+ int op)
{
int tmp;
- Py_ssize_t self_size = PyObject_Length(self);
- if (self_size < 0) {
- return NULL;
- }
+ Py_ssize_t self_size = md_len(self->md);
Py_ssize_t size = PyObject_Length(other);
if (size < 0) {
PyErr_Clear();
@@ -72,16 +69,15 @@ multidict_view_richcompare(PyObject *self, PyObject *other, int op)
}
PyObject *iter = NULL;
PyObject *item = NULL;
- switch(op) {
+ switch (op) {
case Py_LT:
- if (self_size >= size)
- Py_RETURN_FALSE;
- return PyObject_RichCompare(self, other, Py_LE);
+ if (self_size >= size) Py_RETURN_FALSE;
+ return multidict_view_richcompare(self, other, Py_LE);
case Py_LE:
if (self_size > size) {
Py_RETURN_FALSE;
}
- iter = PyObject_GetIter(self);
+ iter = PyObject_GetIter((PyObject *)self);
if (iter == NULL) {
goto fail;
}
@@ -102,18 +98,23 @@ multidict_view_richcompare(PyObject *self, PyObject *other, int op)
}
Py_RETURN_TRUE;
case Py_EQ:
- if (self_size != size)
- Py_RETURN_FALSE;
- return PyObject_RichCompare(self, other, Py_LE);
+ if (self_size != size) Py_RETURN_FALSE;
+ return multidict_view_richcompare(self, other, Py_LE);
case Py_NE:
- tmp = PyObject_RichCompareBool(self, other, Py_EQ);
- if (tmp < 0)
+ item = multidict_view_richcompare(self, other, Py_EQ);
+ if (item == NULL) {
goto fail;
- return PyBool_FromLong(!tmp);
- case Py_GT:
- if (self_size <= size)
+ }
+ if (item == Py_True) {
+ Py_DECREF(item);
Py_RETURN_FALSE;
- return PyObject_RichCompare(self, other, Py_GE);
+ } else {
+ Py_DECREF(item);
+ Py_RETURN_TRUE;
+ }
+ case Py_GT:
+ if (self_size <= size) Py_RETURN_FALSE;
+ return multidict_view_richcompare(self, other, Py_GE);
case Py_GE:
if (self_size < size) {
Py_RETURN_FALSE;
@@ -123,7 +124,7 @@ multidict_view_richcompare(PyObject *self, PyObject *other, int op)
goto fail;
}
while ((item = PyIter_Next(iter))) {
- tmp = PySequence_Contains(self, item);
+ tmp = PySequence_Contains((PyObject *)self, item);
if (tmp < 0) {
goto fail;
}
@@ -145,14 +146,13 @@ fail:
return NULL;
}
-
/********** Items **********/
static inline PyObject *
multidict_itemsview_new(MultiDictObject *md)
{
- _Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, md->pairs.state->ItemsViewType);
+ _Multidict_ViewObject *mv =
+ PyObject_GC_New(_Multidict_ViewObject, md->state->ItemsViewType);
if (mv == NULL) {
return NULL;
}
@@ -179,12 +179,13 @@ multidict_itemsview_repr(_Multidict_ViewObject *self)
if (tmp > 0) {
return PyUnicode_FromString("...");
}
- PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
+ PyObject *name =
+ PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
if (name == NULL) {
Py_ReprLeave((PyObject *)self);
return NULL;
}
- PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true);
+ PyObject *ret = md_repr(self->md, name, true, true);
Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
@@ -214,7 +215,7 @@ _multidict_itemsview_parse_item(_Multidict_ViewObject *self, PyObject *arg,
*pvalue = Py_NewRef(PyTuple_GET_ITEM(arg, 1));
}
- *pidentity = pair_list_calc_identity(&self->md->pairs, key);
+ *pidentity = md_calc_identity(self->md, key);
Py_DECREF(key);
if (*pidentity == NULL) {
if (pkey != NULL) {
@@ -233,8 +234,8 @@ _multidict_itemsview_parse_item(_Multidict_ViewObject *self, PyObject *arg,
return 1;
}
-static int
-_set_add(PyObject *set, PyObject *key, PyObject * value)
+static inline int
+_set_add(PyObject *set, PyObject *key, PyObject *value)
{
PyObject *tpl = PyTuple_Pack(2, key, value);
if (tpl == NULL) {
@@ -255,8 +256,7 @@ multidict_itemsview_and1(_Multidict_ViewObject *self, PyObject *other)
PyObject *value2 = NULL;
PyObject *arg = NULL;
PyObject *ret = NULL;
-
- pair_list_pos_t pos;
+ md_finder_t finder = {0};
PyObject *iter = PyObject_GetIter(other);
if (iter == NULL) {
@@ -271,8 +271,8 @@ multidict_itemsview_and1(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, &key, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, &key, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -280,29 +280,28 @@ multidict_itemsview_and1(_Multidict_ViewObject *self, PyObject *other)
continue;
}
- pair_list_init_pos(&self->md->pairs, &pos);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
- while (true) {
- tmp = pair_list_next_by_identity(&self->md->pairs, &pos,
- identity, &key2, &value2);
+ while ((tmp = md_find_next(&finder, &key2, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
if (tmp < 0) {
goto fail;
- } else if (tmp == 0) {
- break;
- } else {
- tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
- if (tmp < 0) {
+ }
+ if (tmp > 0) {
+ if (_set_add(ret, key2, value2) < 0) {
goto fail;
}
- if (tmp > 0) {
- if (_set_add(ret, key2, value2) < 0) {
- goto fail;
- }
- }
}
Py_CLEAR(key2);
Py_CLEAR(value2);
}
+ if (tmp < 0) {
+ goto fail;
+ }
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -314,6 +313,7 @@ multidict_itemsview_and1(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(iter);
return ret;
fail:
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -334,8 +334,7 @@ multidict_itemsview_and2(_Multidict_ViewObject *self, PyObject *other)
PyObject *value2 = NULL;
PyObject *arg = NULL;
PyObject *ret = NULL;
-
- pair_list_pos_t pos;
+ md_finder_t finder = {0};
PyObject *iter = PyObject_GetIter(other);
if (iter == NULL) {
@@ -350,8 +349,8 @@ multidict_itemsview_and2(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, &key, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, &key, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -359,28 +358,27 @@ multidict_itemsview_and2(_Multidict_ViewObject *self, PyObject *other)
continue;
}
- pair_list_init_pos(&self->md->pairs, &pos);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
- while (true) {
- tmp = pair_list_next_by_identity(&self->md->pairs, &pos,
- identity, NULL, &value2);
+ while ((tmp = md_find_next(&finder, NULL, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
if (tmp < 0) {
goto fail;
- } else if (tmp == 0) {
- break;
- } else {
- tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
- if (tmp < 0) {
+ }
+ if (tmp > 0) {
+ if (_set_add(ret, key, value2) < 0) {
goto fail;
}
- if (tmp > 0) {
- if (_set_add(ret, key, value2) < 0) {
- goto fail;
- }
- }
}
Py_CLEAR(value2);
}
+ if (tmp < 0) {
+ goto fail;
+ }
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -392,6 +390,7 @@ multidict_itemsview_and2(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(iter);
return ret;
fail:
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -405,7 +404,7 @@ fail:
static inline PyObject *
multidict_itemsview_and(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -435,8 +434,7 @@ multidict_itemsview_or1(_Multidict_ViewObject *self, PyObject *other)
PyObject *value2 = NULL;
PyObject *arg = NULL;
PyObject *ret = NULL;
-
- pair_list_pos_t pos;
+ md_finder_t finder = {0};
PyObject *iter = PyObject_GetIter(other);
if (iter == NULL) {
@@ -451,8 +449,8 @@ multidict_itemsview_or1(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, &key, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, &key, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -463,30 +461,30 @@ multidict_itemsview_or1(_Multidict_ViewObject *self, PyObject *other)
continue;
}
- pair_list_init_pos(&self->md->pairs, &pos);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
- while (true) {
- tmp = pair_list_next_by_identity(&self->md->pairs, &pos,
- identity, NULL, &value2);
+ while ((tmp = md_find_next(&finder, NULL, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
if (tmp < 0) {
goto fail;
- } else if (tmp == 0) {
- if (PySet_Add(ret, arg) < 0) {
- goto fail;
- }
+ }
+ if (tmp > 0) {
+ Py_CLEAR(value2);
break;
- } else {
- tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
- if (tmp < 0) {
- goto fail;
- }
- if (tmp > 0) {
- Py_CLEAR(value2);
- break;
- }
}
Py_CLEAR(value2);
}
+ if (tmp < 0) {
+ goto fail;
+ } else if (tmp == 0) {
+ if (PySet_Add(ret, arg) < 0) {
+ goto fail;
+ }
+ }
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -498,6 +496,7 @@ multidict_itemsview_or1(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(iter);
return ret;
fail:
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -518,7 +517,7 @@ multidict_itemsview_or2(_Multidict_ViewObject *self, PyObject *other)
PyObject *arg = NULL;
PyObject *tmp_set = NULL;
- pair_list_pos_t pos;
+ md_pos_t pos;
PyObject *ret = PySet_New(other);
if (ret == NULL) {
@@ -537,8 +536,8 @@ multidict_itemsview_or2(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, NULL, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, NULL, &value);
if (tmp < 0) {
goto fail;
} else if (tmp > 0) {
@@ -553,11 +552,10 @@ multidict_itemsview_or2(_Multidict_ViewObject *self, PyObject *other)
}
Py_CLEAR(iter);
- pair_list_init_pos(&self->md->pairs, &pos);
+ md_init_pos(self->md, &pos);
while (true) {
- int tmp = pair_list_next(&self->md->pairs, &pos,
- &identity, &key, &value);
+ int tmp = md_next(self->md, &pos, &identity, &key, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -597,7 +595,7 @@ fail:
static inline PyObject *
multidict_itemsview_or(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -618,7 +616,6 @@ multidict_itemsview_or(PyObject *lft, PyObject *rht)
Py_RETURN_NOTIMPLEMENTED;
}
-
static inline PyObject *
multidict_itemsview_sub1(_Multidict_ViewObject *self, PyObject *other)
{
@@ -629,7 +626,7 @@ multidict_itemsview_sub1(_Multidict_ViewObject *self, PyObject *other)
PyObject *ret = NULL;
PyObject *tmp_set = NULL;
- pair_list_pos_t pos;
+ md_pos_t pos;
PyObject *iter = PyObject_GetIter(other);
if (iter == NULL) {
@@ -648,8 +645,8 @@ multidict_itemsview_sub1(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, NULL, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, NULL, &value);
if (tmp < 0) {
goto fail;
} else if (tmp > 0) {
@@ -664,11 +661,10 @@ multidict_itemsview_sub1(_Multidict_ViewObject *self, PyObject *other)
}
Py_CLEAR(iter);
- pair_list_init_pos(&self->md->pairs, &pos);
+ md_init_pos(self->md, &pos);
while (true) {
- int tmp = pair_list_next(&self->md->pairs, &pos,
- &identity, &key, &value);
+ int tmp = md_next(self->md, &pos, &identity, &key, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -715,8 +711,7 @@ multidict_itemsview_sub2(_Multidict_ViewObject *self, PyObject *other)
PyObject *value2 = NULL;
PyObject *ret = NULL;
PyObject *iter = PyObject_GetIter(other);
-
- pair_list_pos_t pos;
+ md_finder_t finder = {0};
if (iter == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
@@ -730,8 +725,8 @@ multidict_itemsview_sub2(_Multidict_ViewObject *self, PyObject *other)
goto fail;
}
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, NULL, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, NULL, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -742,31 +737,30 @@ multidict_itemsview_sub2(_Multidict_ViewObject *self, PyObject *other)
continue;
}
- pair_list_init_pos(&self->md->pairs, &pos);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
- while (true) {
- tmp = pair_list_next_by_identity(&self->md->pairs, &pos,
- identity, NULL, &value2);
+ while ((tmp = md_find_next(&finder, NULL, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
if (tmp < 0) {
goto fail;
- } else if (tmp == 0) {
- if (PySet_Add(ret, arg) < 0) {
- goto fail;
- }
+ }
+ if (tmp > 0) {
+ Py_CLEAR(value2);
break;
- } else {
- tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
- if (tmp < 0) {
- goto fail;
- }
- if (tmp > 0) {
- Py_CLEAR(value2);
- break;
- }
}
Py_CLEAR(value2);
}
-
+ if (tmp < 0) {
+ goto fail;
+ } else if (tmp == 0) {
+ if (PySet_Add(ret, arg) < 0) {
+ goto fail;
+ }
+ }
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -778,6 +772,7 @@ multidict_itemsview_sub2(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(iter);
return ret;
fail:
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(key);
@@ -790,7 +785,7 @@ fail:
static inline PyObject *
multidict_itemsview_sub(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -814,7 +809,7 @@ multidict_itemsview_sub(PyObject *lft, PyObject *rht)
static inline PyObject *
multidict_itemsview_xor(_Multidict_ViewObject *self, PyObject *other)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked((PyObject *)self, &state);
if (tmp < 0) {
return NULL;
@@ -874,64 +869,88 @@ fail:
static inline int
multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
{
- PyObject *akey = NULL,
- *aval = NULL,
- *bkey = NULL,
- *bval = NULL,
- *iter = NULL,
- *item = NULL;
- int ret1, ret2;
-
- if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2) {
- return 0;
- }
-
- bkey = PyTuple_GET_ITEM(obj, 0);
- bval = PyTuple_GET_ITEM(obj, 1);
-
- iter = multidict_itemsview_iter(self);
- if (iter == NULL) {
- return 0;
- }
-
- while ((item = PyIter_Next(iter)) != NULL) {
- akey = PyTuple_GET_ITEM(item, 0);
- aval = PyTuple_GET_ITEM(item, 1);
+ PyObject *identity = NULL;
+ PyObject *key = NULL;
+ PyObject *value = NULL;
+ PyObject *value2 = NULL;
+ int tmp;
+ int ret = 0;
+ md_finder_t finder = {0};
- ret1 = PyObject_RichCompareBool(akey, bkey, Py_EQ);
- if (ret1 < 0) {
- Py_DECREF(iter);
- Py_DECREF(item);
- return -1;
+ if (PyTuple_CheckExact(obj)) {
+ if (PyTuple_GET_SIZE(obj) != 2) {
+ return 0;
+ }
+ key = Py_NewRef(PyTuple_GET_ITEM(obj, 0));
+ value = Py_NewRef(PyTuple_GET_ITEM(obj, 1));
+ } else if (PyList_CheckExact(obj)) {
+ if (PyList_GET_SIZE(obj) != 2) {
+ return 0;
+ }
+ key = Py_NewRef(PyList_GET_ITEM(obj, 0));
+ value = Py_NewRef(PyList_GET_ITEM(obj, 1));
+ } else {
+ tmp = PyObject_Length(obj);
+ if (tmp < 0) {
+ PyErr_Clear();
+ return 0;
}
- ret2 = PyObject_RichCompareBool(aval, bval, Py_EQ);
- if (ret2 < 0) {
- Py_DECREF(iter);
- Py_DECREF(item);
+ if (tmp != 2) {
+ return 0;
+ }
+ key = PySequence_GetItem(obj, 0);
+ if (key == NULL) {
return -1;
}
- if (ret1 > 0 && ret2 > 0)
- {
- Py_DECREF(iter);
- Py_DECREF(item);
- return 1;
+ value = PySequence_GetItem(obj, 1);
+ if (value == NULL) {
+ return -1;
}
+ }
- Py_DECREF(item);
+ identity = md_calc_identity(self->md, key);
+ if (identity == NULL) {
+ PyErr_Clear();
+ ret = 0;
+ goto done;
}
- Py_DECREF(iter);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ ret = -1;
+ goto done;
+ }
- if (PyErr_Occurred()) {
- return -1;
+ while ((tmp = md_find_next(&finder, NULL, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
+ Py_CLEAR(value2);
+ if (tmp < 0) {
+ ret = -1;
+ goto done;
+ }
+ if (tmp > 0) {
+ ret = 1;
+ goto done;
+ }
+ }
+ if (tmp < 0) {
+ ret = -1;
+ goto done;
}
- return 0;
+done:
+ md_finder_cleanup(&finder);
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ ASSERT_CONSISTENT(self->md, false);
+ return ret;
}
static inline PyObject *
multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
{
+ md_finder_t finder = {0};
PyObject *iter = PyObject_GetIter(other);
if (iter == NULL) {
return NULL;
@@ -941,11 +960,9 @@ multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
PyObject *value = NULL;
PyObject *value2 = NULL;
- pair_list_pos_t pos;
-
while ((arg = PyIter_Next(iter))) {
- int tmp = _multidict_itemsview_parse_item(self, arg,
- &identity, NULL, &value);
+ int tmp = _multidict_itemsview_parse_item(
+ self, arg, &identity, NULL, &value);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -953,31 +970,31 @@ multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
continue;
}
- pair_list_init_pos(&self->md->pairs, &pos);
+ if (md_init_finder(self->md, identity, &finder) < 0) {
+ assert(PyErr_Occurred());
+ goto fail;
+ }
- while (true) {
- tmp = pair_list_next_by_identity(&self->md->pairs, &pos,
- identity, NULL, &value2);
+ while ((tmp = md_find_next(&finder, NULL, &value2)) > 0) {
+ tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
+ Py_CLEAR(value2);
if (tmp < 0) {
goto fail;
- } else if (tmp == 0) {
- Py_CLEAR(value2);
- break;
- } else {
- tmp = PyObject_RichCompareBool(value, value2, Py_EQ);
- Py_CLEAR(value2);
- if (tmp < 0) {
- goto fail;
- }
- if (tmp > 0) {
- Py_CLEAR(iter);
- Py_CLEAR(arg);
- Py_CLEAR(identity);
- Py_CLEAR(value);
- Py_RETURN_FALSE;
- }
}
+ if (tmp > 0) {
+ md_finder_cleanup(&finder);
+ Py_CLEAR(iter);
+ Py_CLEAR(arg);
+ Py_CLEAR(identity);
+ Py_CLEAR(value);
+ ASSERT_CONSISTENT(self->md, false);
+ Py_RETURN_FALSE;
+ }
+ }
+ if (tmp < 0) {
+ goto fail;
}
+ md_finder_cleanup(&finder);
Py_CLEAR(arg);
Py_CLEAR(identity);
Py_CLEAR(value);
@@ -986,8 +1003,10 @@ multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
if (PyErr_Occurred()) {
return NULL;
}
+ ASSERT_CONSISTENT(self->md, false);
Py_RETURN_TRUE;
fail:
+ md_finder_cleanup(&finder);
Py_CLEAR(iter);
Py_CLEAR(arg);
Py_CLEAR(identity);
@@ -999,18 +1018,21 @@ fail:
PyDoc_STRVAR(itemsview_isdisjoint_doc,
"Return True if two sets have a null intersection.");
-
static PyMethodDef multidict_itemsview_methods[] = {
- {"isdisjoint", (PyCFunction)multidict_itemsview_isdisjoint,
- METH_O, itemsview_isdisjoint_doc},
- {NULL, NULL} /* sentinel */
+ {"isdisjoint",
+ (PyCFunction)multidict_itemsview_isdisjoint,
+ METH_O,
+ itemsview_isdisjoint_doc},
+ {NULL, NULL} /* sentinel */
};
static inline PyObject *
-multidict_view_forbidden_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+multidict_view_forbidden_new(PyTypeObject *type, PyObject *args,
+ PyObject *kwargs)
{
PyErr_Format(PyExc_TypeError,
- "cannot create '%s' instances directly", type->tp_name);
+ "cannot create '%s' instances directly",
+ type->tp_name);
return NULL;
}
@@ -1045,14 +1067,13 @@ static PyType_Spec multidict_itemsview_spec = {
.slots = multidict_itemsview_slots,
};
-
/********** Keys **********/
static inline PyObject *
multidict_keysview_new(MultiDictObject *md)
{
- _Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, md->pairs.state->KeysViewType);
+ _Multidict_ViewObject *mv =
+ PyObject_GC_New(_Multidict_ViewObject, md->state->KeysViewType);
if (mv == NULL) {
return NULL;
}
@@ -1072,11 +1093,12 @@ multidict_keysview_iter(_Multidict_ViewObject *self)
static inline PyObject *
multidict_keysview_repr(_Multidict_ViewObject *self)
{
- PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
+ PyObject *name =
+ PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
if (name == NULL) {
return NULL;
}
- PyObject *ret = pair_list_repr(&self->md->pairs, name, true, false);
+ PyObject *ret = md_repr(self->md, name, true, false);
Py_CLEAR(name);
return ret;
}
@@ -1104,7 +1126,7 @@ multidict_keysview_and1(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- int tmp = pair_list_contains(&self->md->pairs, key, &key2);
+ int tmp = md_contains(self->md, key, &key2);
if (tmp < 0) {
goto fail;
}
@@ -1151,7 +1173,7 @@ multidict_keysview_and2(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- int tmp = pair_list_contains(&self->md->pairs, key, NULL);
+ int tmp = md_contains(self->md, key, NULL);
if (tmp < 0) {
goto fail;
}
@@ -1177,7 +1199,7 @@ fail:
static inline PyObject *
multidict_keysview_and(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -1223,7 +1245,7 @@ multidict_keysview_or1(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- int tmp = pair_list_contains(&self->md->pairs, key, NULL);
+ int tmp = md_contains(self->md, key, NULL);
if (tmp < 0) {
goto fail;
}
@@ -1274,7 +1296,7 @@ multidict_keysview_or2(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- identity = pair_list_calc_identity(&self->md->pairs, key);
+ identity = md_calc_identity(self->md, key);
if (identity == NULL) {
goto fail;
}
@@ -1289,11 +1311,11 @@ multidict_keysview_or2(_Multidict_ViewObject *self, PyObject *other)
}
Py_CLEAR(iter);
- pair_list_pos_t pos;
- pair_list_init_pos(&self->md->pairs, &pos);
+ md_pos_t pos;
+ md_init_pos(self->md, &pos);
while (true) {
- int tmp = pair_list_next(&self->md->pairs, &pos, &identity, &key, NULL);
+ int tmp = md_next(self->md, &pos, &identity, &key, NULL);
if (tmp < 0) {
goto fail;
} else if (tmp == 0) {
@@ -1326,7 +1348,7 @@ fail:
static inline PyObject *
multidict_keysview_or(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -1371,7 +1393,7 @@ multidict_keysview_sub1(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- tmp = pair_list_contains(&self->md->pairs, key, &key2);
+ tmp = md_contains(self->md, key, &key2);
if (tmp < 0) {
goto fail;
}
@@ -1419,7 +1441,7 @@ multidict_keysview_sub2(_Multidict_ViewObject *self, PyObject *other)
Py_CLEAR(key);
continue;
}
- tmp = pair_list_contains(&self->md->pairs, key, NULL);
+ tmp = md_contains(self->md, key, NULL);
if (tmp < 0) {
goto fail;
}
@@ -1445,7 +1467,7 @@ fail:
static inline PyObject *
multidict_keysview_sub(PyObject *lft, PyObject *rht)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
@@ -1469,7 +1491,7 @@ multidict_keysview_sub(PyObject *lft, PyObject *rht)
static inline PyObject *
multidict_keysview_xor(_Multidict_ViewObject *self, PyObject *other)
{
- mod_state * state;
+ mod_state *state;
int tmp = get_mod_state_by_def_checked((PyObject *)self, &state);
if (tmp < 0) {
return NULL;
@@ -1529,7 +1551,7 @@ fail:
static inline int
multidict_keysview_contains(_Multidict_ViewObject *self, PyObject *key)
{
- return pair_list_contains(&self->md->pairs, key, NULL);
+ return md_contains(self->md, key, NULL);
}
static inline PyObject *
@@ -1541,7 +1563,7 @@ multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
}
PyObject *key = NULL;
while ((key = PyIter_Next(iter))) {
- int tmp = pair_list_contains(&self->md->pairs, key, NULL);
+ int tmp = md_contains(self->md, key, NULL);
Py_CLEAR(key);
if (tmp < 0) {
Py_CLEAR(iter);
@@ -1562,11 +1584,12 @@ multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
PyDoc_STRVAR(keysview_isdisjoint_doc,
"Return True if two sets have a null intersection.");
-
static PyMethodDef multidict_keysview_methods[] = {
- {"isdisjoint", (PyCFunction)multidict_keysview_isdisjoint,
- METH_O, keysview_isdisjoint_doc},
- {NULL, NULL} /* sentinel */
+ {"isdisjoint",
+ (PyCFunction)multidict_keysview_isdisjoint,
+ METH_O,
+ keysview_isdisjoint_doc},
+ {NULL, NULL} /* sentinel */
};
static PyType_Slot multidict_keysview_slots[] = {
@@ -1605,8 +1628,8 @@ static PyType_Spec multidict_keysview_spec = {
static inline PyObject *
multidict_valuesview_new(MultiDictObject *md)
{
- _Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, md->pairs.state->ValuesViewType);
+ _Multidict_ViewObject *mv =
+ PyObject_GC_New(_Multidict_ViewObject, md->state->ValuesViewType);
if (mv == NULL) {
return NULL;
}
@@ -1633,12 +1656,13 @@ multidict_valuesview_repr(_Multidict_ViewObject *self)
if (tmp > 0) {
return PyUnicode_FromString("...");
}
- PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
+ PyObject *name =
+ PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
if (name == NULL) {
Py_ReprLeave((PyObject *)self);
return NULL;
}
- PyObject *ret = pair_list_repr(&self->md->pairs, name, false, true);
+ PyObject *ret = md_repr(self->md, name, false, true);
Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
@@ -1668,11 +1692,10 @@ static PyType_Spec multidict_valuesview_spec = {
.slots = multidict_valuesview_slots,
};
-
static inline int
multidict_views_init(PyObject *module, mod_state *state)
{
- PyObject * tmp;
+ PyObject *tmp;
tmp = PyType_FromModuleAndSpec(module, &multidict_itemsview_spec, NULL);
if (tmp == NULL) {
return -1;
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.0 b/contrib/python/multidict/tests/cimultidict-c.pickle.0
index 7b2ed008451..7b2ed008451 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.0
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.0
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.1 b/contrib/python/multidict/tests/cimultidict-c.pickle.1
index 225458ba299..225458ba299 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.1
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.2 b/contrib/python/multidict/tests/cimultidict-c.pickle.2
index d33600e615a..d33600e615a 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.2
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.3 b/contrib/python/multidict/tests/cimultidict-c.pickle.3
index cbb8624db07..cbb8624db07 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.3
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.4 b/contrib/python/multidict/tests/cimultidict-c.pickle.4
index 1f5164ca37b..1f5164ca37b 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.4
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.5 b/contrib/python/multidict/tests/cimultidict-c.pickle.5
index 11bf552c436..11bf552c436 100644
--- a/contrib/python/multidict/tests/cimultidict-c-extension.pickle.5
+++ b/contrib/python/multidict/tests/cimultidict-c.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.0 b/contrib/python/multidict/tests/cimultidict-py.pickle.0
index bd39b6db202..bd39b6db202 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.0
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.0
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.1 b/contrib/python/multidict/tests/cimultidict-py.pickle.1
index 866003d26ca..866003d26ca 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.1
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.2 b/contrib/python/multidict/tests/cimultidict-py.pickle.2
index c9e43fef9c9..c9e43fef9c9 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.2
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.3 b/contrib/python/multidict/tests/cimultidict-py.pickle.3
index 821659fe0c5..821659fe0c5 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.3
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.4 b/contrib/python/multidict/tests/cimultidict-py.pickle.4
index a17c6e9b731..a17c6e9b731 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.4
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.5 b/contrib/python/multidict/tests/cimultidict-py.pickle.5
index 479bfe3a5d3..479bfe3a5d3 100644
--- a/contrib/python/multidict/tests/cimultidict-pure-python.pickle.5
+++ b/contrib/python/multidict/tests/cimultidict-py.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/conftest.py b/contrib/python/multidict/tests/conftest.py
index a37f58f2d1f..dfc1a6703cd 100644
--- a/contrib/python/multidict/tests/conftest.py
+++ b/contrib/python/multidict/tests/conftest.py
@@ -39,7 +39,7 @@ class MultidictImplementation:
@cached_property
def tag(self) -> str:
"""Return a text representation of the pure-python attribute."""
- return "pure-python" if self.is_pure_python else "c-extension"
+ return "py" if self.is_pure_python else "c"
@cached_property
def imported_module(self) -> ModuleType:
@@ -49,7 +49,7 @@ class MultidictImplementation:
def __str__(self) -> str:
"""Render the implementation facade instance as a string."""
- return f"{self.tag}-module"
+ return self.tag
@pytest.fixture(
@@ -79,7 +79,7 @@ def multidict_module(
@pytest.fixture(
scope="session",
params=("MultiDict", "CIMultiDict"),
- ids=("case-sensitive", "case-insensitive"),
+ ids=("cs", "ci"),
)
def any_multidict_class_name(request: pytest.FixtureRequest) -> str:
"""Return a class name of a mutable multidict implementation."""
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.0 b/contrib/python/multidict/tests/istr-c.pickle.0
index 2be573802a5..2be573802a5 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.0
+++ b/contrib/python/multidict/tests/istr-c.pickle.0
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.1 b/contrib/python/multidict/tests/istr-c.pickle.1
index 206775444b5..206775444b5 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.1
+++ b/contrib/python/multidict/tests/istr-c.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.2 b/contrib/python/multidict/tests/istr-c.pickle.2
index 5c038d23faf..5c038d23faf 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.2
+++ b/contrib/python/multidict/tests/istr-c.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.3 b/contrib/python/multidict/tests/istr-c.pickle.3
index a9184bb4c32..a9184bb4c32 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.3
+++ b/contrib/python/multidict/tests/istr-c.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.4 b/contrib/python/multidict/tests/istr-c.pickle.4
index d6c52d24491..d6c52d24491 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.4
+++ b/contrib/python/multidict/tests/istr-c.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-c-extension.pickle.5 b/contrib/python/multidict/tests/istr-c.pickle.5
index fce4bc01efc..fce4bc01efc 100644
--- a/contrib/python/multidict/tests/istr-c-extension.pickle.5
+++ b/contrib/python/multidict/tests/istr-c.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.0 b/contrib/python/multidict/tests/istr-py.pickle.0
index 9e3f0a2a6b7..9e3f0a2a6b7 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.0
+++ b/contrib/python/multidict/tests/istr-py.pickle.0
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.1 b/contrib/python/multidict/tests/istr-py.pickle.1
index 88b7a9d434a..88b7a9d434a 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.1
+++ b/contrib/python/multidict/tests/istr-py.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.2 b/contrib/python/multidict/tests/istr-py.pickle.2
index 9f17e5997e7..9f17e5997e7 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.2
+++ b/contrib/python/multidict/tests/istr-py.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.3 b/contrib/python/multidict/tests/istr-py.pickle.3
index 09f70c0ae81..09f70c0ae81 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.3
+++ b/contrib/python/multidict/tests/istr-py.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.4 b/contrib/python/multidict/tests/istr-py.pickle.4
index d092a4eb550..d092a4eb550 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.4
+++ b/contrib/python/multidict/tests/istr-py.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/istr-pure-python.pickle.5 b/contrib/python/multidict/tests/istr-py.pickle.5
index b8f03af6562..b8f03af6562 100644
--- a/contrib/python/multidict/tests/istr-pure-python.pickle.5
+++ b/contrib/python/multidict/tests/istr-py.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.0 b/contrib/python/multidict/tests/multidict-c.pickle.0
index eb979fcf725..eb979fcf725 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.0
+++ b/contrib/python/multidict/tests/multidict-c.pickle.0
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.1 b/contrib/python/multidict/tests/multidict-c.pickle.1
index a4f211d7b1b..a4f211d7b1b 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.1
+++ b/contrib/python/multidict/tests/multidict-c.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.2 b/contrib/python/multidict/tests/multidict-c.pickle.2
index b4563f879d0..b4563f879d0 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.2
+++ b/contrib/python/multidict/tests/multidict-c.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.3 b/contrib/python/multidict/tests/multidict-c.pickle.3
index 415960a3eed..415960a3eed 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.3
+++ b/contrib/python/multidict/tests/multidict-c.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.4 b/contrib/python/multidict/tests/multidict-c.pickle.4
index 00ef17c3f7f..00ef17c3f7f 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.4
+++ b/contrib/python/multidict/tests/multidict-c.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-c-extension.pickle.5 b/contrib/python/multidict/tests/multidict-c.pickle.5
index 2c4ae0a0d38..2c4ae0a0d38 100644
--- a/contrib/python/multidict/tests/multidict-c-extension.pickle.5
+++ b/contrib/python/multidict/tests/multidict-c.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.0 b/contrib/python/multidict/tests/multidict-py.pickle.0
index e91023ecf97..e91023ecf97 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.0
+++ b/contrib/python/multidict/tests/multidict-py.pickle.0
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.1 b/contrib/python/multidict/tests/multidict-py.pickle.1
index acce9bf7939..acce9bf7939 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.1
+++ b/contrib/python/multidict/tests/multidict-py.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.2 b/contrib/python/multidict/tests/multidict-py.pickle.2
index 900446ad8da..900446ad8da 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.2
+++ b/contrib/python/multidict/tests/multidict-py.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.3 b/contrib/python/multidict/tests/multidict-py.pickle.3
index 9b9073515a7..9b9073515a7 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.3
+++ b/contrib/python/multidict/tests/multidict-py.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.4 b/contrib/python/multidict/tests/multidict-py.pickle.4
index db363f8d3c3..db363f8d3c3 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.4
+++ b/contrib/python/multidict/tests/multidict-py.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict-pure-python.pickle.5 b/contrib/python/multidict/tests/multidict-py.pickle.5
index 7dc772d58fb..7dc772d58fb 100644
--- a/contrib/python/multidict/tests/multidict-pure-python.pickle.5
+++ b/contrib/python/multidict/tests/multidict-py.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/test_circular_imports.py b/contrib/python/multidict/tests/test_circular_imports.py
index f6ea323ee22..75741388b0b 100644
--- a/contrib/python/multidict/tests/test_circular_imports.py
+++ b/contrib/python/multidict/tests/test_circular_imports.py
@@ -82,8 +82,10 @@ def test_no_warnings(import_path: str) -> None:
# fmt: off
sys.executable,
"-I",
- "-W", "error",
- "-c", f"import {import_path!s}",
+ "-W",
+ "error",
+ "-c",
+ f"import {import_path!s}",
# fmt: on
)
@@ -99,8 +101,10 @@ def test_c_extension_preferred_by_default(monkeypatch: pytest.MonkeyPatch) -> No
# fmt: off
sys.executable,
"-I",
- "-W", "error",
- "-c", "import multidict; raise SystemExit(int("
+ "-W",
+ "error",
+ "-c",
+ "import multidict; raise SystemExit(int("
"multidict.istr.__module__ != 'multidict._multidict' "
"or multidict.USE_EXTENSIONS is not True))",
# fmt: on
diff --git a/contrib/python/multidict/tests/test_multidict.py b/contrib/python/multidict/tests/test_multidict.py
index d1539fb45d2..eec0b862cd6 100644
--- a/contrib/python/multidict/tests/test_multidict.py
+++ b/contrib/python/multidict/tests/test_multidict.py
@@ -58,7 +58,7 @@ def chained_callable(
@pytest.fixture
-def cls( # type: ignore[misc]
+def cls(
request: pytest.FixtureRequest,
multidict_module: ModuleType,
) -> Callable[..., MultiMapping[int | str] | MutableMultiMapping[int | str]]:
@@ -708,7 +708,7 @@ class TestMultiDict(BaseMultiDictTest):
("MultiDict", "MultiDictProxy"),
],
)
- def cls( # type: ignore[misc]
+ def cls(
self,
request: pytest.FixtureRequest,
multidict_module: ModuleType,
@@ -800,7 +800,7 @@ class TestCIMultiDict(BaseMultiDictTest):
("CIMultiDict", "CIMultiDictProxy"),
],
)
- def cls( # type: ignore[misc]
+ def cls(
self,
request: pytest.FixtureRequest,
multidict_module: ModuleType,
@@ -1093,17 +1093,19 @@ class TestCIMultiDict(BaseMultiDictTest):
assert arg & d.items() == expected
def test_items_case_insensitive_or(self, cls: type[CIMultiDict[str]]) -> None:
- d = cls([("KEY", "one")])
+ d = cls([("K", "v"), ("KEY", "one")])
assert d.items() | {("key", "one"), ("other", "two")} == {
+ ("K", "v"),
("KEY", "one"),
("other", "two"),
}
def test_items_case_insensitive_ror(self, cls: type[CIMultiDict[str]]) -> None:
- d = cls([("KEY", "one"), ("KEY2", "three")])
+ d = cls([("K", "v"), ("KEY", "one"), ("KEY2", "three")])
assert [("key", "one"), ("other", "two")] | d.items() == {
+ ("K", "v"),
("key", "one"),
("other", "two"),
("KEY2", "three"),
@@ -1333,13 +1335,19 @@ def test_view_direct_instantiation_segfault() -> None:
This test only applies to the C extension implementation.
"""
# Test that _ItemsView cannot be instantiated directly
- with pytest.raises(TypeError, match="cannot create '.*_ItemsView' instances directly"):
+ with pytest.raises(
+ TypeError, match="cannot create '.*_ItemsView' instances directly"
+ ):
multidict._ItemsView() # type: ignore[attr-defined]
# Test that _KeysView cannot be instantiated directly
- with pytest.raises(TypeError, match="cannot create '.*_KeysView' instances directly"):
+ with pytest.raises(
+ TypeError, match="cannot create '.*_KeysView' instances directly"
+ ):
multidict._KeysView() # type: ignore[attr-defined]
# Test that _ValuesView cannot be instantiated directly
- with pytest.raises(TypeError, match="cannot create '.*_ValuesView' instances directly"):
+ with pytest.raises(
+ TypeError, match="cannot create '.*_ValuesView' instances directly"
+ ):
multidict._ValuesView() # type: ignore[attr-defined]
diff --git a/contrib/python/multidict/tests/test_multidict_benchmarks.py b/contrib/python/multidict/tests/test_multidict_benchmarks.py
index b5cc193c6af..b27041493ba 100644
--- a/contrib/python/multidict/tests/test_multidict_benchmarks.py
+++ b/contrib/python/multidict/tests/test_multidict_benchmarks.py
@@ -261,7 +261,8 @@ def test_multidict_getall_str_hit(
@benchmark
def _run() -> None:
- md.getall("key3")
+ for i in range(30):
+ md.getall("key3")
def test_multidict_getall_str_miss(
@@ -273,7 +274,8 @@ def test_multidict_getall_str_miss(
@benchmark
def _run() -> None:
- md.getall("miss", ())
+ for i in range(30):
+ md.getall("miss", ())
def test_cimultidict_getall_istr_hit(
@@ -287,7 +289,8 @@ def test_cimultidict_getall_istr_hit(
@benchmark
def _run() -> None:
- md.getall(all_istr)
+ for i in range(30):
+ md.getall(all_istr)
def test_cimultidict_getall_istr_miss(
@@ -301,7 +304,8 @@ def test_cimultidict_getall_istr_miss(
@benchmark
def _run() -> None:
- md.getall(miss_istr, ())
+ for i in range(30):
+ md.getall(miss_istr, ())
def test_multidict_fetch(
diff --git a/contrib/python/multidict/tests/test_mutable_multidict.py b/contrib/python/multidict/tests/test_mutable_multidict.py
index 74bbd697fee..d6fe42fc255 100644
--- a/contrib/python/multidict/tests/test_mutable_multidict.py
+++ b/contrib/python/multidict/tests/test_mutable_multidict.py
@@ -34,8 +34,7 @@ class TestMutableMultiDict:
d = case_sensitive_multidict_class([("key", "one"), ("key", "two")])
expected = (
- f"<{case_sensitive_multidict_class.__name__}"
- "('key': 'one', 'key': 'two')>"
+ f"<{case_sensitive_multidict_class.__name__}('key': 'one', 'key': 'two')>"
)
assert str(d) == expected
@@ -174,6 +173,21 @@ class TestMutableMultiDict:
d.add("key", "val2")
assert ("key", "val2") == d.popitem()
+ assert len(d) == 1
+ assert [("key", "val1")] == list(d.items())
+
+ def test_popitem2(
+ self,
+ case_sensitive_multidict_class: type[CIMultiDict[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
+ d.add("key", "val1")
+ d.add("key", "val2")
+ d.add("key2", "val3")
+
+ del d["key2"] # make dummy at the end
+
+ assert ("key", "val2") == d.popitem()
assert [("key", "val1")] == list(d.items())
def test_popitem_empty_multidict(
@@ -365,6 +379,56 @@ class TestMutableMultiDict:
with pytest.raises(TypeError):
d.update("foo", "bar") # type: ignore[arg-type, call-arg]
+ def test_repr_with_dummy(
+ self, case_sensitive_multidict_class: type[MultiDict[int]]
+ ) -> None:
+ d = case_sensitive_multidict_class({"a": 1, "b": 2, "c": 3})
+ cls = d.__class__.__name__
+ del d["b"] # make a dummy entry
+ assert repr(d) == f"<{cls}('a': 1, 'c': 3)>"
+
+ def test_items_repr_with_dummy(
+ self, case_sensitive_multidict_class: type[MultiDict[int]]
+ ) -> None:
+ d = case_sensitive_multidict_class({"a": 1, "b": 2, "c": 3})
+ del d["b"] # make a dummy entry
+ cls = d.items().__class__.__name__
+ assert repr(d.items()) == f"<{cls}('a': 1, 'c': 3)>"
+
+ def test_keys_repr_with_dummy(
+ self, case_sensitive_multidict_class: type[MultiDict[int]]
+ ) -> None:
+ d = case_sensitive_multidict_class({"a": 1, "b": 2, "c": 3})
+ del d["b"] # make a dummy entry
+ cls = d.keys().__class__.__name__
+ assert repr(d.keys()) == f"<{cls}('a', 'c')>"
+
+ def test_values_repr_with_dummy(
+ self, case_sensitive_multidict_class: type[MultiDict[int]]
+ ) -> None:
+ d = case_sensitive_multidict_class({"a": 1, "b": 2, "c": 3})
+ del d["b"] # make a dummy entry
+ cls = d.values().__class__.__name__
+ assert repr(d.values()) == f"<{cls}(1, 3)>"
+
+ def test_huge_md(
+ self,
+ case_sensitive_multidict_class: type[MultiDict[int]],
+ ) -> None:
+ size = 1 << 16
+ d = case_sensitive_multidict_class((str(i), i) for i in range(size))
+ assert d[str(size // 2)] == size // 2
+
+ def test_create_from_proxy(
+ self,
+ case_sensitive_multidict_class: type[MultiDict[int]],
+ case_sensitive_multidict_proxy_class: type[MultiDictProxy[int]],
+ ) -> None:
+ d = case_sensitive_multidict_class({"a": 1, "b": 2, "c": 3})
+ p = case_sensitive_multidict_proxy_class(d)
+ d2 = case_sensitive_multidict_class(p)
+ assert d2 == d
+
class TestCIMutableMultiDict:
def test_getall(
@@ -429,8 +493,7 @@ class TestCIMutableMultiDict:
d = case_insensitive_multidict_class([("KEY", "one"), ("KEY", "two")])
expected = (
- f"<{case_insensitive_multidict_class.__name__}"
- "('KEY': 'one', 'KEY': 'two')>"
+ f"<{case_insensitive_multidict_class.__name__}('KEY': 'one', 'KEY': 'two')>"
)
assert str(d) == expected
@@ -730,3 +793,23 @@ class TestCIMutableMultiDict:
k, v = d.popitem()
assert type(k) is case_insensitive_str_class
+
+ def test_issue_1195(
+ self, case_insensitive_multidict_class: type[CIMultiDict[bytes]]
+ ) -> None:
+ md = case_insensitive_multidict_class(
+ {
+ "User-Agent": b"Bacon/1.0",
+ "Cookie": b"valued-visitor=yes;foo=bar",
+ "X-Bar": b"Foo",
+ "X-Foo": b"Bar",
+ "Referer": b"https://httpie.org/",
+ }
+ )
+
+ md2 = md.copy()
+
+ md.popone("User-Agent")
+ assert md.keys() == md2.keys() - {"User-Agent"}
+ md.update([("User-Agent", b"Bacon/1.0")])
+ assert md.keys() == md2.keys()
diff --git a/contrib/python/multidict/tests/test_types.py b/contrib/python/multidict/tests/test_types.py
index 6339006b68f..65f83f66a2a 100644
--- a/contrib/python/multidict/tests/test_types.py
+++ b/contrib/python/multidict/tests/test_types.py
@@ -75,8 +75,7 @@ def test_create_cimultidict_proxy_from_nonmultidict(
with pytest.raises(
TypeError,
match=(
- "ctor requires CIMultiDict or CIMultiDictProxy instance, "
- "not <class 'dict'>"
+ "ctor requires CIMultiDict or CIMultiDictProxy instance, not <class 'dict'>"
),
):
multidict_module.CIMultiDictProxy({})
diff --git a/contrib/python/multidict/tests/test_update.py b/contrib/python/multidict/tests/test_update.py
index 46ab30a08bd..a1d8814a3b2 100644
--- a/contrib/python/multidict/tests/test_update.py
+++ b/contrib/python/multidict/tests/test_update.py
@@ -119,3 +119,32 @@ def test_update_deque_arg_and_kwds(any_multidict_class: _MD_Classes) -> None:
obj.update(arg, b=2)
assert list(obj.items()) == [("a", 1), ("b", 2)]
assert arg == deque([("a", 1)])
+
+
+def test_update_with_second_md(any_multidict_class: _MD_Classes) -> None:
+ obj1 = any_multidict_class()
+ obj2 = any_multidict_class([("a", 2)])
+ obj1.update(obj2)
+ assert obj1 == obj2
+
+
+def test_compact_after_deletion(any_multidict_class: _MD_Classes) -> None:
+ # multidict is resized when it is filled up to 2/3 of the index table size
+ NUM = 16 * 2 // 3
+ obj = any_multidict_class((str(i), i) for i in range(NUM - 1))
+ # keys.usable == 0
+ # delete items, it adds empty entries but not reduce keys.usable
+ for i in range(5):
+ del obj[str(i)]
+ # adding an entry requres keys resizing to remove empty entries
+ dct = {str(i): i for i in range(100, 105)}
+ obj.extend(dct)
+ assert obj == {str(i): i for i in range(5, NUM - 1)} | dct
+
+
+def test_update_with_empty_slots(any_multidict_class: _MD_Classes) -> None:
+ # multidict is resized when it is filled up to 2/3 of the index table size
+ obj = any_multidict_class([("0", 0), ("1", 1), ("1", 2)])
+ del obj["0"]
+ obj.update({"1": 100})
+ assert obj == {"1": 100}
diff --git a/contrib/python/multidict/ya.make b/contrib/python/multidict/ya.make
index 81c5990eb8a..c24361e5d33 100644
--- a/contrib/python/multidict/ya.make
+++ b/contrib/python/multidict/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.4.4)
+VERSION(6.5.1)
LICENSE(Apache-2.0)