8000 bpo-33712: OrderedDict only creates od_fast_nodes cache if needed (GH… · python/cpython@f1b90e3 · GitHub
[go: up one dir, main page]

Skip to content

Commit f1b90e3

Browse files
bpo-33712: OrderedDict only creates od_fast_nodes cache if needed (GH-7349). (GH-10001)
(cherry picked from commit 6f17e51)
1 parent 0d3dd9f commit f1b90e3

File tree

2 files changed

+21
-53
lines changed

2 files changed

+21
-53
lines changed

Lib/test/test_ordered_dict.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,9 +697,9 @@ def test_sizeof_exact(self):
697697
nodesize = calcsize('Pn2P')
698698

699699
od = OrderedDict()
700-
check(od, basicsize + 8*p + 8 + 5*entrysize) # 8byte indicies + 8*2//3 * entry table
700+
check(od, basicsize + 8 + 5*entrysize) # 8byte indices + 8*2//3 * entry table
701701
od.x = 1
702-
check(od, basicsize + 8*p + 8 + 5*entrysize)
702+
check(od, basicsize + 8 + 5*entrysize)
703703
od.update([(i, i) for i in range(3)])
704704
check(od, basicsize + 8*p + 8 + 5*entrysize + 3*nodesize)
705705
od.update([(i, i) for i in range(3, 10)])

Objects/odictobject.c

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,6 @@ For removing nodes:
101101
* _odict_find_node(od, key)
102102
* _odict_keys_equal(od1, od2)
103103
104-
Used, but specific to the linked-list implementation:
105-
106-
* _odict_free_fast_nodes(od)
107-
108104
And here's a look at how the linked-list relates to the OrderedDict API:
109105
110106
============ === === ==== ==== ==== === ==== ===== ==== ==== === ==== === ===
@@ -378,7 +374,6 @@ tp_iter odict_iter
378374
tp_dictoffset (offset)
379375
tp_init odict_init
380376
tp_alloc (repeated)
381-
tp_new odict_new
382377
================= ================
383378
384379
================= ================
@@ -522,15 +517,6 @@ struct _odictnode {
522517
#define _odict_FOREACH(od, node) \
523518
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
524519

525-
#define _odict_FAST_SIZE(od) ((PyDictObject *)od)->ma_keys->dk_size
526-
527-
static void
528-
_odict_free_fast_nodes(PyODictObject *od) {
529-
if (od->od_fast_nodes) {
530-
PyMem_FREE(od->od_fast_nodes);
531-
}
532-
}
533-
534520
/* Return the index into the hash table, regardless of a valid node. */
535521
static Py_ssize_t
536522
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
@@ -551,7 +537,8 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
551537

552538
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
553539
static int
554-
_odict_resize(PyODictObject *od) {
540+
_odict_resize(PyODictObject *od)
541+
{
555542
Py_ssize_t size, i;
556543
_ODictNode **fast_nodes, *node;
557544

@@ -577,7 +564,7 @@ _odict_resize(PyODictObject *od) {
577564
}
578565

579566
/* Replace the old fast nodes table. */
580-
_odict_free_fast_nodes(od);
567+
PyMem_FREE(od->od_fast_nodes);
581568
od->od_fast_nodes = fast_nodes;
582569
od->od_fast_nodes_size = size;
583570
od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys;
@@ -615,6 +602,7 @@ _odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
615602
index = _odict_get_index(od, key, hash);
616603
if (index < 0)
617604
return NULL;
605+
assert(od->od_fast_nodes != NULL);
618606
return od->od_fast_nodes[index];
619607
}
620608

@@ -632,6 +620,7 @@ _odict_find_node(PyODictObject *od, PyObject *key)
632620
index = _odict_get_index(od, key, hash);
633621
if (index < 0)
634622
return NULL;
623+
assert(od->od_fast_nodes != NULL);
635624
return od->od_fast_nodes[index];
636625
}
637626

@@ -676,7 +665,8 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
676665
Py_DECREF(key);
677666
return -1;
678667
}
679-
else if (od->od_fast_nodes[i] != NULL) {
668+
assert(od->od_fast_nodes != NULL);
669+
if (od->od_fast_nodes[i] != NULL) {
680670
/* We already have a node for the key so there's no need to add one. */
681671
Py_DECREF(key);
682672
return 0;
@@ -755,6 +745,7 @@ _odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
755745
if (i < 0)
756746
return PyErr_Occurred() ? -1 : 0;
757747

748+
assert(od->od_fast_nodes != NULL);
758749
if (node == NULL)
759750
node = od->od_fast_nodes[i];
760751
assert(node == od->od_fast_nodes[i]);
@@ -775,8 +766,10 @@ _odict_clear_nodes(PyODictObject *od)
775766
{
776767
_ODictNode *node, *next;
777768

778-
_odict_free_fast_nodes(od);
769+
PyMem_FREE(od->od_fast_nodes);
779770
od->od_fast_nodes = NULL;
771+
od->od_fast_nodes_size = 0;
772+
od->od_resize_sentinel = NULL;
780773

781774
node = _odict_FIRST(od);
782775
_odict_FIRST(od) = NULL;
@@ -941,7 +934,7 @@ static PyObject *
941934
odict_sizeof(PyODictObject *od)
942935
{
943936
Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
944-
res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */
937+
res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
945938
if (!_odict_EMPTY(od)) {
946939
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
947940
}
@@ -1231,12 +1224,10 @@ PyDoc_STRVAR(odict_clear__doc__,
12311224
"od.clear() -> None. Remove all items from od.");
12321225

12331226
static PyObject *
1234-
odict_clear(register PyODictObject *od)
1227+
odict_clear(register PyODictObject *od, PyObject *Py_UNUSED(ignored))
12351228
{
12361229
PyDict_Clear((PyObject *)od);
12371230
_odict_clear_nodes(od);
1238-
if (_odict_resize(od) < 0)
1239-
return NULL;
12401231
Py_RETURN_NONE;
12411232
}
12421233

@@ -1570,13 +1561,10 @@ odict_traverse(PyODictObject *od, visitproc visit, void *arg)
15701561
static int
15711562
odict_tp_clear(PyODictObject *od)
15721563
{
1573-
PyObject *res;
15741564
Py_CLEAR(od->od_inst_dict);
15751565
Py_CLEAR(od->od_weakreflist);
1576-
res = odict_clear(od);
1577-
if (res == NULL)
1578-
return -1;
1579-
Py_DECREF(res);
1566+
PyDict_Clear((PyObject *)od);
1567+
_odict_clear_nodes(od);
15801568
return 0;
15811569
}
15821570

@@ -1651,27 +1639,6 @@ odict_init(PyObject *self, PyObject *args, PyObject *kwds)
16511639
}
16521640
}
16531641

1654-
/* tp_new */
1655-
1656-
static PyObject *
1657-
odict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1658-
{
1659-
PyODictObject *od;
1660-
1661-
od = (PyODictObject *)PyDict_Type.tp_new(type, args, kwds);
1662-
if (od == NULL)
1663-
return NULL;
1664-
1665-
/* type constructor fills the memory with zeros (see
1666-
PyType_GenericAlloc()), there is no need to set them to zero again */
1667-
if (_odict_resize(od) < 0) {
1668-
Py_DECREF(od);
1669-
return NULL;
1670-
}
1671-
1672-
return (PyObject*)od;
1673-
}
1674-
16751642
/* PyODict_Type */
16761643

16771644
PyTypeObject PyODict_Type = {
@@ -1712,7 +1679,7 @@ PyTypeObject PyODict_Type = {
17121679
offsetof(PyODictObject, od_inst_dict), /* tp_dictoffset */
17131680
(initproc)odict_init, /* tp_init */
17141681
PyType_GenericAlloc, /* tp_alloc */
1715-
(newfunc)odict_new, /* tp_new */
1682+
0, /* tp_new */
17161683
0, /* tp_free */
17171684
};
17181685

@@ -1722,8 +1689,9 @@ PyTypeObject PyODict_Type = {
17221689
*/
17231690

17241691
PyObject *
1725-
PyODict_New(void) {
1726-
return odict_new(&PyODict_Type, NULL, NULL);
1692+
PyODict_New(void)
1693+
{
1694+
return PyDict_Type.tp_new(&PyODict_Type, NULL, NULL);
17271695
}
17281696

17291697
static int

0 commit comments

Comments
 (0)
0