From 366f4ee4da4420842eac26b3fa00c2b01d4515a6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 1 Dec 2016 14:43:22 +0100 Subject: Replace PyObject_CallFunctionObjArgs() with fastcall * PyObject_CallFunctionObjArgs(func, NULL) => _PyObject_CallNoArg(func) * PyObject_CallFunctionObjArgs(func, arg, NULL) => _PyObject_CallArg1(func, arg) PyObject_CallFunctionObjArgs() allocates 40 bytes on the C stack and requires extra work to "parse" C arguments to build a C array of PyObject*. _PyObject_CallNoArg() and _PyObject_CallArg1() are simpler and don't allocate memory on the C stack. This change is part of the fastcall project. The change on listsort() is related to the issue #23507. --- Objects/odictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 22b1f1dfed..77fb3a181d 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); + od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); if (od_copy == NULL) return NULL; -- cgit v1.2.1 From 39ae5bedd90f9caf9a78efa82f4d11e838933b3a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 4 Dec 2016 22:59:09 +0100 Subject: Backed out changeset b9c9691c72c5 Issue #28858: The change b9c9691c72c5 introduced a regression. It seems like _PyObject_CallArg1() uses more stack memory than PyObject_CallFunctionObjArgs(). --- Objects/odictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 77fb3a181d..22b1f1dfed 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); + od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); if (od_copy == NULL) return NULL; -- cgit v1.2.1 From a95a307d2cbb7fc1c778691f142e0c21c05fd5bc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Dec 2016 18:46:19 +0100 Subject: Use _PyObject_CallNoArg() Replace: PyObject_CallFunctionObjArgs(callable, NULL) with: _PyObject_CallNoArg(callable) --- Objects/odictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 22b1f1dfed..77fb3a181d 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); + od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); if (od_copy == NULL) return NULL; -- cgit v1.2.1 From e5f0c097b310b8aea17164d8851aba4b7571ce49 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 7 Dec 2016 20:41:42 +0900 Subject: Issue #28818: Simplify lookdict functions --- Objects/odictobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 77fb3a181d..6b33386e17 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -535,11 +535,11 @@ _odict_free_fast_nodes(PyODictObject *od) { static Py_ssize_t _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) { - PyObject **value_addr = NULL; + PyObject *value = NULL; PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys; Py_ssize_t ix; - ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr, NULL); + ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value, NULL); if (ix == DKIX_EMPTY) { return keys->dk_nentries; /* index of new entry */ } -- cgit v1.2.1 From f22b56b777f7134b5c4e6c9caa9249e92c4f4fd9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 16 Dec 2016 16:18:57 +0200 Subject: Issue #28959: Added private macro PyDict_GET_SIZE for retrieving the size of dict. --- Objects/odictobject.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 6b33386e17..8e6d643e90 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -2423,8 +2423,7 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) /* now handle kwargs */ assert(kwargs == NULL || PyDict_Check(kwargs)); - len = (kwargs != NULL) ? PyDict_Size(kwargs) : 0; - if (len > 0) { + if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) { PyObject *items = PyDict_Items(kwargs); if (items == NULL) return NULL; -- cgit v1.2.1 From 6f60ffbcc042a8ee070e9f254d5f016a0467eda6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 03:46:13 +0100 Subject: Convert some OrderedDict methods to Argument Clinic Issue #29289. Convert methods: * fromkeys() class method * setdefault() * popitem() * move_to_end() --- Objects/odictobject.c | 171 +++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 87 deletions(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 5833df5f72..aac454c817 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -474,6 +474,13 @@ later: #include "dict-common.h" #include +#include "clinic/odictobject.c.h" + +/*[clinic input] +class OrderedDict "PyODictObject *" "&PyODict_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ca0641cf6143d4af]*/ + typedef struct _odictnode _ODictNode; @@ -912,25 +919,23 @@ PyDoc_STRVAR(odict_setitem__doc__, "od.__setitem__(i, y) <==> od[i]=y"); /* fromkeys() */ -PyDoc_STRVAR(odict_fromkeys__doc__, -"OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.\n\ - If not specified, the value defaults to None.\n\ -\n\ - "); +/*[clinic input] +@classmethod +OrderedDict.fromkeys + + iterable as seq: object + value: object = None + +New ordered dictionary with keys from S. + +If not specified, the value defaults to None. +[clinic start generated code]*/ static PyObject * -odict_fromkeys(PyObject *cls, PyObject *args, PyObject *kwargs) +OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value) +/*[clinic end generated code: output=c10390d452d78d6d input=33eefc496d5eee7b]*/ { - static char *kwlist[] = {"iterable", "value", 0}; - PyObject *seq; - PyObject *value = Py_None; - - /* both borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:fromkeys", kwlist, - &seq, &value)) { - return NULL; - } - return _PyDict_FromKeys(cls, seq, value); + return _PyDict_FromKeys((PyObject *)type, seq, value); } /* __sizeof__() */ @@ -1000,32 +1005,32 @@ Done: return result; } -/* setdefault() */ +/* setdefault(): Skips __missing__() calls. */ -PyDoc_STRVAR(odict_setdefault__doc__, - "od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od"); -/* Skips __missing__() calls. */ +/*[clinic input] +OrderedDict.setdefault + + key: object + default as failobj: object = None + +od.get(k,d), also set od[k]=d if k not in od. +[clinic start generated code]*/ + static PyObject * -odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, + PyObject *failobj) +/*[clinic end generated code: output=605d0f6f61ccb0a6 input=4ee5006f32f5691b]*/ { - static char *kwlist[] = {"key", "default", 0}; - PyObject *key, *result = NULL; - PyObject *failobj = Py_None; + PyObject *result = NULL; - /* both borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:setdefault", kwlist, - &key, &failobj)) { - return NULL; - } - - if (PyODict_CheckExact(od)) { - result = PyODict_GetItemWithError(od, key); /* borrowed */ + if (PyODict_CheckExact(self)) { + result = PyODict_GetItemWithError(self, key); /* borrowed */ if (result == NULL) { if (PyErr_Occurred()) return NULL; - assert(_odict_find_node(od, key) == NULL); - if (PyODict_SetItem((PyObject *)od, key, failobj) >= 0) { + assert(_odict_find_node(self, key) == NULL); + if (PyODict_SetItem((PyObject *)self, key, failobj) >= 0) { result = failobj; Py_INCREF(failobj); } @@ -1035,14 +1040,14 @@ odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs) } } else { - int exists = PySequence_Contains((PyObject *)od, key); + int exists = PySequence_Contains((PyObject *)self, key); if (exists < 0) { return NULL; } else if (exists) { - result = PyObject_GetItem((PyObject *)od, key); + result = PyObject_GetItem((PyObject *)self, key); } - else if (PyObject_SetItem((PyObject *)od, key, failobj) >= 0) { + else if (PyObject_SetItem((PyObject *)self, key, failobj) >= 0) { result = failobj; Py_INCREF(failobj); } @@ -1152,39 +1157,37 @@ _odict_popkey(PyObject *od, PyObject *key, PyObject *failobj) return _odict_popkey_hash(od, key, failobj, hash); } + /* popitem() */ -PyDoc_STRVAR(odict_popitem__doc__, -"od.popitem() -> (k, v), return and remove a (key, value) pair.\n\ - Pairs are returned in LIFO order if last is true or FIFO order if false.\n\ -\n\ - "); +/*[clinic input] +OrderedDict.popitem + + last: bool = True + +Return (k, v) and remove a (key, value) pair. + +Pairs are returned in LIFO order if last is true or FIFO order if false. +[clinic start generated code]*/ static PyObject * -odict_popitem(PyObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_popitem_impl(PyODictObject *self, int last) +/*[clinic end generated code: output=98e7d986690d49eb input=4937da2015939126]*/ { - static char *kwlist[] = {"last", 0}; PyObject *key, *value, *item = NULL; _ODictNode *node; - int last = 1; /* pull the item */ - /* borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p:popitem", kwlist, - &last)) { - return NULL; - } - - if (_odict_EMPTY(od)) { + if (_odict_EMPTY(self)) { PyErr_SetString(PyExc_KeyError, "dictionary is empty"); return NULL; } - node = last ? _odict_LAST(od) : _odict_FIRST(od); + node = last ? _odict_LAST(self) : _odict_FIRST(self); key = _odictnode_KEY(node); Py_INCREF(key); - value = _odict_popkey_hash(od, key, NULL, _odictnode_HASH(node)); + value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node)); if (value == NULL) return NULL; item = PyTuple_Pack(2, key, value); @@ -1312,36 +1315,34 @@ odict_reversed(PyODictObject *od) return odictiter_new(od, _odict_ITER_KEYS|_odict_ITER_REVERSED); } + /* move_to_end() */ -PyDoc_STRVAR(odict_move_to_end__doc__, -"Move an existing element to the end (or beginning if last==False).\n\ -\n\ - Raises KeyError if the element does not exist.\n\ - When last=True, acts like a fast version of self[key]=self.pop(key).\n\ -\n\ - "); +/*[clinic input] +OrderedDict.move_to_end + + key: object + last: bool = True + +"Move an existing element to the end (or beginning if last==False). + + Raises KeyError if the element does not exist. + When last=True, acts like a fast version of self[key]=self.pop(key). +[clinic start generated code]*/ static PyObject * -odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last) +/*[clinic end generated code: output=fafa4c5cc9b92f20 input=3b8283f7d0e15e43]*/ { - static char *kwlist[] = {"key", "last", 0}; - PyObject *key; - int last = 1; _ODictNode *node; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|p:move_to_end", kwlist, - &key, &last)) { - return NULL; - } - - if (_odict_EMPTY(od)) { + if (_odict_EMPTY(self)) { PyErr_SetObject(PyExc_KeyError, key); return NULL; } - node = last ? _odict_LAST(od) : _odict_FIRST(od); + node = last ? _odict_LAST(self) : _odict_FIRST(self); if (key != _odictnode_KEY(node)) { - node = _odict_find_node(od, key); + node = _odict_find_node(self, key); if (node == NULL) { if (!PyErr_Occurred()) PyErr_SetObject(PyExc_KeyError, key); @@ -1349,16 +1350,16 @@ odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs) } if (last) { /* Only move if not already the last one. */ - if (node != _odict_LAST(od)) { - _odict_remove_node(od, node); - _odict_add_tail(od, node); + if (node != _odict_LAST(self)) { + _odict_remove_node(self, node); + _odict_add_tail(self, node); } } else { /* Only move if not already the first one. */ - if (node != _odict_FIRST(od)) { - _odict_remove_node(od, node); - _odict_add_head(od, node); + if (node != _odict_FIRST(self)) { + _odict_remove_node(self, node); + _odict_add_head(self, node); } } } @@ -1386,20 +1387,17 @@ static PyMethodDef odict_methods[] = { odict_repr__doc__}, {"__setitem__", (PyCFunction)odict_mp_ass_sub, METH_NOARGS, odict_setitem__doc__}, - {"fromkeys", (PyCFunction)odict_fromkeys, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, odict_fromkeys__doc__}, + ORDEREDDICT_FROMKEYS_METHODDEF /* overridden dict methods */ {"__sizeof__", (PyCFunction)odict_sizeof, METH_NOARGS, odict_sizeof__doc__}, {"__reduce__", (PyCFunction)odict_reduce, METH_NOARGS, odict_reduce__doc__}, - {"setdefault", (PyCFunction)odict_setdefault, - METH_VARARGS | METH_KEYWORDS, odict_setdefault__doc__}, + ORDEREDDICT_SETDEFAULT_METHODDEF {"pop", (PyCFunction)odict_pop, METH_VARARGS | METH_KEYWORDS, odict_pop__doc__}, - {"popitem", (PyCFunction)odict_popitem, - METH_VARARGS | METH_KEYWORDS, odict_popitem__doc__}, + ORDEREDDICT_POPITEM_METHODDEF {"keys", (PyCFunction)odictkeys_new, METH_NOARGS, odict_keys__doc__}, {"values", (PyCFunction)odictvalues_new, METH_NOARGS, @@ -1416,8 +1414,7 @@ static PyMethodDef odict_methods[] = { /* new methods */ {"__reversed__", (PyCFunction)odict_reversed, METH_NOARGS, odict_reversed__doc__}, - {"move_to_end", (PyCFunction)odict_move_to_end, - METH_VARARGS | METH_KEYWORDS, odict_move_to_end__doc__}, + ORDEREDDICT_MOVE_TO_END_METHODDEF {NULL, NULL} /* sentinel */ }; -- cgit v1.2.1 From cece81f7dee3141bee23cc291834f4c04ebaf6c2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 Jan 2017 19:38:13 +0200 Subject: Issue #29289: Argument Clinic generates reasonable name for the parameter "default". --- Objects/odictobject.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index aac454c817..8b1e114181 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1012,15 +1012,15 @@ Done: OrderedDict.setdefault key: object - default as failobj: object = None + default: object = None od.get(k,d), also set od[k]=d if k not in od. [clinic start generated code]*/ static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, - PyObject *failobj) -/*[clinic end generated code: output=605d0f6f61ccb0a6 input=4ee5006f32f5691b]*/ + PyObject *default_value) +/*[clinic end generated code: output=97537cb7c28464b6 input=d5e940fcea7a5a67]*/ { PyObject *result = NULL; @@ -1030,9 +1030,9 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, if (PyErr_Occurred()) return NULL; assert(_odict_find_node(self, key) == NULL); - if (PyODict_SetItem((PyObject *)self, key, failobj) >= 0) { - result = failobj; - Py_INCREF(failobj); + if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) { + result = default_value; + Py_INCREF(result); } } else { @@ -1047,9 +1047,9 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, else if (exists) { result = PyObject_GetItem((PyObject *)self, key); } - else if (PyObject_SetItem((PyObject *)self, key, failobj) >= 0) { - result = failobj; - Py_INCREF(failobj); + else if (PyObject_SetItem((PyObject *)self, key, default_value) >= 0) { + result = default_value; + Py_INCREF(result); } } -- cgit v1.2.1 From 35d2352df15a03d98bb7296a49fd16032b949bb3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 Jan 2017 00:30:04 +0200 Subject: Issues #29311, #29289: Fixed and improved docstrings for dict and OrderedDict methods. --- Objects/odictobject.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'Objects/odictobject.c') diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 8b1e114181..c2cef21b49 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -926,14 +926,12 @@ OrderedDict.fromkeys iterable as seq: object value: object = None -New ordered dictionary with keys from S. - -If not specified, the value defaults to None. +Create a new ordered dictionary with keys from iterable and values set to value. [clinic start generated code]*/ static PyObject * OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value) -/*[clinic end generated code: output=c10390d452d78d6d input=33eefc496d5eee7b]*/ +/*[clinic end generated code: output=c10390d452d78d6d input=1a0476c229c597b3]*/ { return _PyDict_FromKeys((PyObject *)type, seq, value); } @@ -1014,13 +1012,15 @@ OrderedDict.setdefault key: object default: object = None -od.get(k,d), also set od[k]=d if k not in od. +Insert key with a value of default if key is not in the dictionary. + +Return the value for key if key is in the dictionary, else default. [clinic start generated code]*/ static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=97537cb7c28464b6 input=d5e940fcea7a5a67]*/ +/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/ { PyObject *result = NULL; @@ -1165,14 +1165,14 @@ OrderedDict.popitem last: bool = True -Return (k, v) and remove a (key, value) pair. +Remove and return a (key, value) pair from the dictionary. Pairs are returned in LIFO order if last is true or FIFO order if false. [clinic start generated code]*/ static PyObject * OrderedDict_popitem_impl(PyODictObject *self, int last) -/*[clinic end generated code: output=98e7d986690d49eb input=4937da2015939126]*/ +/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/ { PyObject *key, *value, *item = NULL; _ODictNode *node; @@ -1324,15 +1324,14 @@ OrderedDict.move_to_end key: object last: bool = True -"Move an existing element to the end (or beginning if last==False). +Move an existing element to the end (or beginning if last is false). - Raises KeyError if the element does not exist. - When last=True, acts like a fast version of self[key]=self.pop(key). +Raise KeyError if the element does not exist. [clinic start generated code]*/ static PyObject * OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last) -/*[clinic end generated code: output=fafa4c5cc9b92f20 input=3b8283f7d0e15e43]*/ +/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/ { _ODictNode *node; -- cgit v1.2.1