@@ -503,12 +503,15 @@ struct _odictobject {
503503
504504struct _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-
528529static 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. */
535552static 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
608608static int
@@ -665,10 +665,15 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
665665static 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