@@ -874,85 +874,38 @@ lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
874874 Py_UNREACHABLE ();
875875}
876876
877- // Search non-Unicode key from Unicode table
878- static Py_ssize_t
879- unicodekeys_lookup_generic ( PyDictObject * mp , PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
877+ static inline Py_ALWAYS_INLINE Py_ssize_t
878+ do_lookup ( PyDictObject * mp , PyDictKeysObject * dk , PyObject * key , Py_hash_t hash ,
879+ Py_ssize_t ( * check_lookup )( PyDictObject * , PyDictKeysObject * , void * , Py_ssize_t ix , PyObject * key , Py_hash_t ) )
880880{
881- PyDictUnicodeEntry * ep0 = DK_UNICODE_ENTRIES (dk );
881+ void * ep0 = _DK_ENTRIES (dk );
882882 size_t mask = DK_MASK (dk );
883883 size_t perturb = hash ;
884884 size_t i = (size_t )hash & mask ;
885885 Py_ssize_t ix ;
886886 for (;;) {
887887 ix = dictkeys_get_index (dk , i );
888888 if (ix >= 0 ) {
889- PyDictUnicodeEntry * ep = & ep0 [ ix ] ;
890- assert ( ep -> me_key != NULL );
891- assert ( PyUnicode_CheckExact ( ep -> me_key )) ;
892- if ( ep -> me_key == key ) {
889+ Py_ssize_t cmp = check_lookup ( mp , dk , ep0 , ix , key , hash ) ;
890+ if ( cmp < 0 ) {
891+ return cmp ;
892+ } else if ( cmp ) {
893893 return ix ;
894894 }
895- if (unicode_get_hash (ep -> me_key ) == hash ) {
896- PyObject * startkey = ep -> me_key ;
897- Py_INCREF (startkey );
898- int cmp = PyObject_RichCompareBool (startkey , key , Py_EQ );
899- Py_DECREF (startkey );
900- if (cmp < 0 ) {
901- return DKIX_ERROR ;
902- }
903- if (dk == mp -> ma_keys && ep -> me_key == startkey ) {
904- if (cmp > 0 ) {
905- return ix ;
906- }
907- }
908- else {
909- /* The dict was mutated, restart */
910- return DKIX_KEY_CHANGED ;
911- }
912- }
913895 }
914896 else if (ix == DKIX_EMPTY ) {
915897 return DKIX_EMPTY ;
916898 }
917899 perturb >>= PERTURB_SHIFT ;
918900 i = mask & (i * 5 + perturb + 1 );
919- }
920- Py_UNREACHABLE ();
921- }
922901
923- // Search Unicode key from Unicode table.
924- static Py_ssize_t _Py_HOT_FUNCTION
925- unicodekeys_lookup_unicode (PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
926- {
927- PyDictUnicodeEntry * ep0 = DK_UNICODE_ENTRIES (dk );
928- size_t mask = DK_MASK (dk );
929- size_t perturb = hash ;
930- size_t i = (size_t )hash & mask ;
931- Py_ssize_t ix ;
932- for (;;) {
933- ix = dictkeys_get_index (dk , i );
934- if (ix >= 0 ) {
935- PyDictUnicodeEntry * ep = & ep0 [ix ];
936- assert (ep -> me_key != NULL );
937- assert (PyUnicode_CheckExact (ep -> me_key ));
938- if (ep -> me_key == key ||
939- (unicode_get_hash (ep -> me_key ) == hash && unicode_eq (ep -> me_key , key ))) {
940- return ix ;
941- }
942- }
943- else if (ix == DKIX_EMPTY ) {
944- return DKIX_EMPTY ;
945- }
946- perturb >>= PERTURB_SHIFT ;
947- i = mask & (i * 5 + perturb + 1 );
948902 // Manual loop unrolling
949903 ix = dictkeys_get_index (dk , i );
950904 if (ix >= 0 ) {
951- PyDictUnicodeEntry * ep = & ep0 [ix ];
952- assert (ep -> me_key != NULL );
953- assert (PyUnicode_CheckExact (ep -> me_key ));
954- if (ep -> me_key == key ||
955- (unicode_get_hash (ep -> me_key ) == hash && unicode_eq (ep -> me_key , key ))) {
905+ Py_ssize_t cmp = check_lookup (mp , dk , ep0 , ix , key , hash );
906+ if (cmp < 0 ) {
907+ return cmp ;
908+ } else if (cmp ) {
956909 return ix ;
957910 }
958911 }
@@ -965,49 +918,94 @@ unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
965918 Py_UNREACHABLE ();
966919}
967920
968- // Search key from Generic table.
921+ static inline Py_ALWAYS_INLINE Py_ssize_t
922+ compare_unicode_generic (PyDictObject * mp , PyDictKeysObject * dk ,
923+ void * ep0 , Py_ssize_t ix , PyObject * key , Py_hash_t hash )
924+ {
925+ PyDictUnicodeEntry * ep = & ((PyDictUnicodeEntry * )ep0 )[ix ];
926+ assert (ep -> me_key != NULL );
927+ assert (PyUnicode_CheckExact (ep -> me_key ));
928+ assert (!PyUnicode_CheckExact (key ));
929+ // TODO: Thread safety
930+
931+ if (unicode_get_hash (ep -> me_key ) == hash ) {
932+ PyObject * startkey = ep -> me_key ;
933+ Py_INCREF (startkey );
934+ int cmp = PyObject_RichCompareBool (startkey , key , Py_EQ );
935+ Py_DECREF (startkey );
936+ if (cmp < 0 ) {
937+ return DKIX_ERROR ;
938+ }
939+ if (dk == mp -> ma_keys && ep -> me_key == startkey ) {
940+ return cmp ;
941+ }
942+ else {
943+ /* The dict was mutated, restart */
944+ return DKIX_KEY_CHANGED ;
945+ }
946+ }
947+ return 0 ;
948+ }
949+
950+ // Search non-Unicode key from Unicode table
969951static Py_ssize_t
970- dictkeys_generic_lookup (PyDictObject * mp , PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
952+ unicodekeys_lookup_generic (PyDictObject * mp , PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
971953{
972- PyDictKeyEntry * ep0 = DK_ENTRIES (dk );
973- size_t mask = DK_MASK (dk );
974- size_t perturb = hash ;
975- size_t i = (size_t )hash & mask ;
976- Py_ssize_t ix ;
977- for (;;) {
978- ix = dictkeys_get_index (dk , i );
979- if (ix >= 0 ) {
980- PyDictKeyEntry * ep = & ep0 [ix ];
981- assert (ep -> me_key != NULL );
982- if (ep -> me_key == key ) {
983- return ix ;
984- }
985- if (ep -> me_hash == hash ) {
986- PyObject * startkey = ep -> me_key ;
987- Py_INCREF (startkey );
988- int cmp = PyObject_RichCompareBool (startkey , key , Py_EQ );
989- Py_DECREF (startkey );
990- if (cmp < 0 ) {
991- return DKIX_ERROR ;
992- }
993- if (dk == mp -> ma_keys && ep -> me_key == startkey ) {
994- if (cmp > 0 ) {
995- return ix ;
996- }
997- }
998- else {
999- /* The dict was mutated, restart */
1000- return DKIX_KEY_CHANGED ;
1001- }
1002- }
954+ return do_lookup (mp , dk , key , hash , compare_unicode_generic );
955+ }
956+
957+ static inline Py_ALWAYS_INLINE Py_ssize_t
958+ compare_unicode_unicode (PyDictObject * mp , PyDictKeysObject * dk ,
959+ void * ep0 , Py_ssize_t ix , PyObject * key , Py_hash_t hash )
960+ {
961+ PyDictUnicodeEntry * ep = & ((PyDictUnicodeEntry * )ep0 )[ix ];
962+ assert (ep -> me_key != NULL );
963+ assert (PyUnicode_CheckExact (ep -> me_key ));
964+ if (ep -> me_key == key ||
965+ (unicode_get_hash (ep -> me_key ) == hash && unicode_eq (ep -> me_key , key ))) {
966+ return 1 ;
967+ }
968+ return 0 ;
969+ }
970+
971+ static Py_ssize_t _Py_HOT_FUNCTION
972+ unicodekeys_lookup_unicode (PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
973+ {
974+ return do_lookup (NULL , dk , key , hash , compare_unicode_unicode );
975+ }
976+
977+ static inline Py_ALWAYS_INLINE Py_ssize_t
978+ compare_generic (PyDictObject * mp , PyDictKeysObject * dk ,
979+ void * ep0 , Py_ssize_t ix , PyObject * key , Py_hash_t hash )
980+ {
981+ PyDictKeyEntry * ep = & ((PyDictKeyEntry * )ep0 )[ix ];
982+ assert (ep -> me_key != NULL );
983+ if (ep -> me_key == key ) {
984+ return 1 ;
985+ }
986+ if (ep -> me_hash == hash ) {
987+ PyObject * startkey = ep -> me_key ;
988+ Py_INCREF (startkey );
989+ int cmp = PyObject_RichCompareBool (startkey , key , Py_EQ );
990+ Py_DECREF (startkey );
991+ if (cmp < 0 ) {
992+ return DKIX_ERROR ;
1003993 }
1004- else if (ix == DKIX_EMPTY ) {
1005- return DKIX_EMPTY ;
994+ if (dk == mp -> ma_keys && ep -> me_key == startkey ) {
995+ return cmp ;
996+ }
997+ else {
998+ /* The dict was mutated, restart */
999+ return DKIX_KEY_CHANGED ;
10061000 }
1007- perturb >>= PERTURB_SHIFT ;
1008- i = mask & (i * 5 + perturb + 1 );
10091001 }
1010- Py_UNREACHABLE ();
1002+ return 0 ;
1003+ }
1004+
1005+ static Py_ssize_t
1006+ dictkeys_generic_lookup (PyDictObject * mp , PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
1007+ {
1008+ return do_lookup (mp , dk , key , hash , compare_generic );
10111009}
10121010
10131011/* Lookup a string in a (all unicode) dict keys.
0 commit comments