Skip to content

Commit 389758e

Browse files
asvetlovbdraco
andauthored
Use istr as keys in CIMultiDict (#1097)
Currently, keys of CIMultiDict are stored as-is, e.g. `CIMultiDict({'k': 'v'})` has `str` key. But it is slightly incorrect, CIMultiDict should store `istr` keys. The PR fixes it. The change is backward compatible because `istr` is derived from `str`. --------- Co-authored-by: J. Nick Koston <[email protected]>
1 parent 10a97e1 commit 389758e

File tree

10 files changed

+383
-165
lines changed

10 files changed

+383
-165
lines changed

CHANGES/1097.bugfix

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Rewrote :class:`multidict.CIMultiDict` and it proxy to always return
2+
:class:`multidict.istr` keys. ``istr`` is derived from :class:`str`,
3+
thus the change is backward compatible.
4+
5+
The performance boost is about 15% for some operations for C Extension,
6+
pure Python implementation have got a visible (15% - 230%) speedup as well.

multidict/_multidict.c

+12-76
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ _multidict_extend(MultiDictObject *self, PyObject *arg,
126126
}
127127

128128

129-
static inline int
129+
static inline Py_ssize_t
130130
_multidict_extend_parse_args(PyObject *args, PyObject *kwds,
131131
const char *name, PyObject **parg)
132132
{
@@ -344,85 +344,13 @@ multidict_reduce(MultiDictObject *self)
344344
return result;
345345
}
346346

347-
static inline PyObject *
348-
_do_multidict_repr(MultiDictObject *md, PyObject *name,
349-
bool show_keys, bool show_values)
350-
{
351-
PyObject *key = NULL,
352-
*value = NULL;
353-
bool comma = false;
354-
355-
PyUnicodeWriter *writer = PyUnicodeWriter_Create(1024);
356-
if (writer == NULL)
357-
return NULL;
358-
359-
if (PyUnicodeWriter_WriteChar(writer, '<') <0)
360-
goto fail;
361-
if (PyUnicodeWriter_WriteStr(writer, name) <0)
362-
goto fail;
363-
if (PyUnicodeWriter_WriteChar(writer, '(') <0)
364-
goto fail;
365-
366-
pair_list_pos_t pos;
367-
pair_list_init_pos(&md->pairs, &pos);
368-
369-
for (;;) {
370-
int res = pair_list_next(&md->pairs, &pos, &key, &value);
371-
if (res < 0) {
372-
goto fail;
373-
}
374-
if (res == 0) {
375-
break;
376-
}
377-
378-
if (comma) {
379-
if (PyUnicodeWriter_WriteChar(writer, ',') <0)
380-
goto fail;
381-
if (PyUnicodeWriter_WriteChar(writer, ' ') <0)
382-
goto fail;
383-
}
384-
if (show_keys) {
385-
if (PyUnicodeWriter_WriteChar(writer, '\'') <0)
386-
goto fail;
387-
if (PyUnicodeWriter_WriteStr(writer, key) <0)
388-
goto fail;
389-
if (PyUnicodeWriter_WriteChar(writer, '\'') <0)
390-
goto fail;
391-
}
392-
if (show_keys && show_values) {
393-
if (PyUnicodeWriter_WriteChar(writer, ':') <0)
394-
goto fail;
395-
if (PyUnicodeWriter_WriteChar(writer, ' ') <0)
396-
goto fail;
397-
}
398-
if (show_values) {
399-
if (PyUnicodeWriter_WriteRepr(writer, value) <0)
400-
goto fail;
401-
}
402-
403-
Py_CLEAR(key);
404-
Py_CLEAR(value);
405-
comma = true;
406-
}
407-
408-
if (PyUnicodeWriter_WriteChar(writer, ')') <0)
409-
goto fail;
410-
if (PyUnicodeWriter_WriteChar(writer, '>') <0)
411-
goto fail;
412-
return PyUnicodeWriter_Finish(writer);
413-
fail:
414-
Py_CLEAR(key);
415-
Py_CLEAR(value);
416-
PyUnicodeWriter_Discard(writer);
417-
}
418-
419347
static inline PyObject *
420348
multidict_repr(MultiDictObject *self)
421349
{
422350
PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
423351
if (name == NULL)
424352
return NULL;
425-
PyObject *ret = _do_multidict_repr(self, name, true, true);
353+
PyObject *ret = pair_list_repr(&self->pairs, name, true, true);
426354
Py_CLEAR(name);
427355
return ret;
428356
}
@@ -604,9 +532,11 @@ static inline PyObject *
604532
multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds)
605533
{
606534
PyObject *arg = NULL;
607-
if (_multidict_extend_parse_args(args, kwds, "extend", &arg) < 0) {
535+
Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "extend", &arg);
536+
if (size < 0) {
608537
return NULL;
609538
}
539+
pair_list_grow(&self->pairs, size);
610540
if (_multidict_extend(self, arg, kwds, "extend", 1) < 0) {
611541
return NULL;
612542
}
@@ -1200,7 +1130,7 @@ multidict_proxy_repr(MultiDictProxyObject *self)
12001130
PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
12011131
if (name == NULL)
12021132
return NULL;
1203-
PyObject *ret = _do_multidict_repr(self->md, name, true, true);
1133+
PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true);
12041134
Py_CLEAR(name);
12051135
return ret;
12061136
}
@@ -1412,6 +1342,7 @@ static inline void
14121342
module_free(void *m)
14131343
{
14141344
Py_CLEAR(multidict_str_lower);
1345+
Py_CLEAR(multidict_str_canonical);
14151346
Py_CLEAR(viewbaseset_and_func);
14161347
Py_CLEAR(viewbaseset_or_func);
14171348
Py_CLEAR(viewbaseset_sub_func);
@@ -1438,6 +1369,10 @@ PyInit__multidict(void)
14381369
if (multidict_str_lower == NULL) {
14391370
goto fail;
14401371
}
1372+
multidict_str_canonical = PyUnicode_InternFromString("_canonical");
1373+
if (multidict_str_canonical == NULL) {
1374+
goto fail;
1375+
}
14411376

14421377
PyObject *module = NULL;
14431378

@@ -1531,6 +1466,7 @@ PyInit__multidict(void)
15311466

15321467
fail:
15331468
Py_XDECREF(multidict_str_lower);
1469+
Py_XDECREF(multidict_str_canonical);
15341470

15351471
return NULL;
15361472
}

0 commit comments

Comments
 (0)