Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4c72918

Browse files
Issue #24362: Simplify the C OrderedDict fast nodes resize logic.
1 parent 24ac877 commit 4c72918

2 files changed

Lines changed: 42 additions & 34 deletions

File tree

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Library
2323

2424
- Issue #24368: Support keyword arguments in OrderedDict methods.
2525

26+
- Issue #24362: Simplify the C OrderedDict fast nodes resize logic.
27+
2628

2729
What's New in Python 3.5.0 beta 2?
2830
==================================

Objects/odictobject.c

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -503,12 +503,15 @@ struct _odictobject {
503503

504504
struct _odictnode {
505505
PyObject *key;
506+
Py_hash_t hash;
506507
_ODictNode *next;
507508
_ODictNode *prev;
508509
};
509510

510511
#define _odictnode_KEY(node) \
511512
(node->key)
513+
#define _odictnode_HASH(node) \
514+
(node->hash)
512515
/* borrowed reference */
513516
#define _odictnode_VALUE(node, od) \
514517
PyODict_GetItemWithError((PyObject *)od, _odictnode_KEY(node))
@@ -523,18 +526,32 @@ struct _odictnode {
523526
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
524527

525528

526-
static Py_ssize_t _odict_get_index(PyODictObject *, PyObject *); /* forward */
527-
528529
static void
529530
_odict_free_fast_nodes(PyODictObject *od) {
530531
if (od->od_fast_nodes) {
531532
PyMem_FREE(od->od_fast_nodes);
532533
}
533534
}
534535

536+
/* Return the index into the hash table, regardless of a valid node. */
537+
static Py_ssize_t
538+
_odict_get_index_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
539+
{
540+
PyObject **value_addr = NULL;
541+
PyDictKeyEntry *ep;
542+
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
543+
544+
ep = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr);
545+
if (ep == NULL)
546+
return -1;
547+
/* We use pointer arithmetic to get the entry's index into the table. */
548+
return ep - keys->dk_entries;
549+
}
550+
551+
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
535552
static int
536553
_odict_resize(PyODictObject *od) {
537-
Py_ssize_t size, prev_size, i;
554+
Py_ssize_t size, i;
538555
_ODictNode **fast_nodes, *node;
539556

540557
/* Initialize a new "fast nodes" table. */
@@ -548,27 +565,20 @@ _odict_resize(PyODictObject *od) {
548565
fast_nodes[i] = NULL;
549566

550567
/* Copy the current nodes into the table. */
551-
prev_size = od->od_size;
552-
od->od_size = size;
553568
_odict_FOREACH(od, node) {
554-
assert(node != NULL);
555-
i = _odict_get_index(od, _odictnode_KEY(node));
569+
i = _odict_get_index_hash(od, _odictnode_KEY(node),
570+
_odictnode_HASH(node));
556571
if (i < 0) {
557-
od->od_size = prev_size;
558572
PyMem_FREE(fast_nodes);
559573
return -1;
560574
}
561575
fast_nodes[i] = node;
562576
}
563-
if (size != ((PyDictObject *)od)->ma_keys->dk_size) {
564-
/* If _odict_get_index triggered a resize then we are already done. */
565-
PyMem_FREE(fast_nodes);
566-
return 0;
567-
}
568577

569578
/* Replace the old fast nodes table. */
570579
_odict_free_fast_nodes(od);
571580
od->od_fast_nodes = fast_nodes;
581+
od->od_size = size;
572582
return 0;
573583
}
574584

@@ -577,32 +587,22 @@ static Py_ssize_t
577587
_odict_get_index(PyODictObject *od, PyObject *key)
578588
{
579589
Py_hash_t hash;
580-
PyObject **value_addr = NULL;
581-
PyDictKeyEntry *ep;
582-
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
590+
PyDictKeysObject *keys;
583591

584592
assert(key != NULL);
585-
do {
586-
/* Ensure od_fast_nodes and dk_entries are in sync. */
587-
if (keys->dk_size != od->od_size) {
588-
int resize_res = _odict_resize(od);
589-
if (resize_res < 0)
590-
return -1;
591-
}
593+
hash = PyObject_Hash(key);
594+
if (hash == -1)
595+
return -1;
596+
keys = ((PyDictObject *)od)->ma_keys;
592597

593-
/* now get the index */
594-
hash = PyObject_Hash(key);
595-
if (hash == -1)
598+
/* Ensure od_fast_nodes and dk_entries are in sync. */
599+
if (keys->dk_size != od->od_size) {
600+
int resize_res = _odict_resize(od);
601+
if (resize_res < 0)
596602
return -1;
597-
/* May have resized during the PyObject_Hash() call. */
598-
keys = ((PyDictObject *)od)->ma_keys;
599-
} while (keys->dk_size != od->od_size);
603+
}
600604

601-
ep = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr);
602-
if (ep == NULL)
603-
return -1;
604-
/* We use pointer arithmetic to get the entry's index into the table. */
605-
return ep - keys->dk_entries;
605+
return _odict_get_index_hash(od, key, hash);
606606
}
607607

608608
static int
@@ -665,10 +665,15 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
665665
static int
666666
_odict_add_new_node(PyODictObject *od, PyObject *key)
667667
{
668+
Py_hash_t hash;
668669
Py_ssize_t i;
669670
_ODictNode *node;
670671

671672
Py_INCREF(key);
673+
hash = PyObject_Hash(key);
674+
if (hash == -1)
675+
return -1;
676+
672677
i = _odict_get_index(od, key);
673678
if (i < 0) {
674679
if (!PyErr_Occurred())
@@ -691,6 +696,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key)
691696
}
692697

693698
_odictnode_KEY(node) = key;
699+
_odictnode_HASH(node) = hash;
694700
_odict_add_tail(od, node);
695701
od->od_fast_nodes[i] = node;
696702
return 0;

0 commit comments

Comments
 (0)