bpo-33712: OrderedDict only creates od_fast_nodes cache if needed (GH… · python/cpython@861d34e
@@ -101,10 +101,6 @@ For removing nodes:
101101* _odict_find_node(od, key)
102102* _odict_keys_equal(od1, od2)
103103104-Used, but specific to the linked-list implementation:
105-106-* _odict_free_fast_nodes(od)
107-108104And here's a look at how the linked-list relates to the OrderedDict API:
109105110106============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
@@ -378,7 +374,6 @@ tp_iter odict_iter
378374tp_dictoffset (offset)
379375tp_init odict_init
380376tp_alloc (repeated)
381-tp_new odict_new
382377================= ================
383378384379================= ================
@@ -530,15 +525,6 @@ struct _odictnode {
530525#define _odict_FOREACH(od, node) \
531526 for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
532527533-#define _odict_FAST_SIZE(od) ((PyDictObject *)od)->ma_keys->dk_size
534-535-static void
536-_odict_free_fast_nodes(PyODictObject *od) {
537-if (od->od_fast_nodes) {
538-PyMem_FREE(od->od_fast_nodes);
539- }
540-}
541-542528/* Return the index into the hash table, regardless of a valid node. */
543529static Py_ssize_t
544530_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
@@ -559,7 +545,8 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
559545560546/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
561547static int
562-_odict_resize(PyODictObject *od) {
548+_odict_resize(PyODictObject *od)
549+{
563550Py_ssize_t size, i;
564551_ODictNode **fast_nodes, *node;
565552@@ -585,7 +572,7 @@ _odict_resize(PyODictObject *od) {
585572 }
586573587574/* Replace the old fast nodes table. */
588-_odict_free_fast_nodes(od);
575+PyMem_FREE(od->od_fast_nodes);
589576od->od_fast_nodes = fast_nodes;
590577od->od_fast_nodes_size = size;
591578od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
@@ -623,6 +610,7 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
623610index = _odict_get_index(od, key, hash);
624611if (index < 0)
625612return NULL;
613+assert(od->od_fast_nodes != NULL);
626614return od->od_fast_nodes[index];
627615}
628616@@ -640,6 +628,7 @@ _odict_find_node(PyODictObject *od, PyObject *key)
640628index = _odict_get_index(od, key, hash);
641629if (index < 0)
642630return NULL;
631+assert(od->od_fast_nodes != NULL);
643632return od->od_fast_nodes[index];
644633}
645634@@ -684,7 +673,8 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
684673Py_DECREF(key);
685674return -1;
686675 }
687-else if (od->od_fast_nodes[i] != NULL) {
676+assert(od->od_fast_nodes != NULL);
677+if (od->od_fast_nodes[i] != NULL) {
688678/* We already have a node for the key so there's no need to add one. */
689679Py_DECREF(key);
690680return 0;
@@ -763,6 +753,7 @@ _odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
763753if (i < 0)
764754return PyErr_Occurred() ? -1 : 0;
765755756+assert(od->od_fast_nodes != NULL);
766757if (node == NULL)
767758node = od->od_fast_nodes[i];
768759assert(node == od->od_fast_nodes[i]);
@@ -783,8 +774,10 @@ _odict_clear_nodes(PyODictObject *od)
783774{
784775_ODictNode *node, *next;
785776786-_odict_free_fast_nodes(od);
777+PyMem_FREE(od->od_fast_nodes);
787778od->od_fast_nodes = NULL;
779+od->od_fast_nodes_size = 0;
780+od->od_resize_sentinel = NULL;
788781789782node = _odict_FIRST(od);
790783_odict_FIRST(od) = NULL;
@@ -887,7 +880,7 @@ static PyObject *
887880odict_sizeof(PyODictObject *od)
888881{
889882Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
890-res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */
883+res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
891884if (!_odict_EMPTY(od)) {
892885res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
893886 }
@@ -1175,12 +1168,10 @@ PyDoc_STRVAR(odict_clear__doc__,
11751168"od.clear() -> None. Remove all items from od.");
1176116911771170static PyObject *
1178-odict_clear(register PyODictObject *od)
1171+odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
11791172{
11801173PyDict_Clear((PyObject *)od);
11811174_odict_clear_nodes(od);
1182-if (_odict_resize(od) < 0)
1183-return NULL;
11841175Py_RETURN_NONE;
11851176}
11861177@@ -1484,13 +1475,10 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
14841475static int
14851476odict_tp_clear(PyODictObject *od)
14861477{
1487-PyObject *res;
14881478Py_CLEAR(od->od_inst_dict);
14891479Py_CLEAR(od->od_weakreflist);
1490-res = odict_clear(od);
1491-if (res == NULL)
1492-return -1;
1493-Py_DECREF(res);
1480+PyDict_Clear((PyObject *)od);
1481+_odict_clear_nodes(od);
14941482return 0;
14951483}
14961484@@ -1565,27 +1553,6 @@ odict_init(PyObject *self, PyObject *args, PyObject *kwds)
15651553 }
15661554}
156715551568-/* tp_new */
1569-1570-static PyObject *
1571-odict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1572-{
1573-PyODictObject *od;
1574-1575-od = (PyODictObject *)PyDict_Type.tp_new(type, args, kwds);
1576-if (od == NULL)
1577-return NULL;
1578-1579-/* type constructor fills the memory with zeros (see
1580- PyType_GenericAlloc()), there is no need to set them to zero again */
1581-if (_odict_resize(od) < 0) {
1582-Py_DECREF(od);
1583-return NULL;
1584- }
1585-1586-return (PyObject*)od;
1587-}
1588-15891556/* PyODict_Type */
1590155715911558PyTypeObject PyODict_Type = {
@@ -1626,7 +1593,7 @@ PyTypeObject PyODict_Type = {
16261593 offsetof(PyODictObject, od_inst_dict), /* tp_dictoffset */
16271594 (initproc)odict_init, /* tp_init */
16281595PyType_GenericAlloc, /* tp_alloc */
1629-(newfunc)odict_new, /* tp_new */
1596+0, /* tp_new */
163015970, /* tp_free */
16311598};
16321599@@ -1636,8 +1603,9 @@ PyTypeObject PyODict_Type = {
16361603 */
1637160416381605PyObject *
1639-PyODict_New(void) {
1640-return odict_new(&PyODict_Type, NULL, NULL);
1606+PyODict_New(void)
1607+{
1608+return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
16411609}
1642161016431611static int