@@ -2453,6 +2453,8 @@ map_alloc(void)
24532453 return NULL ;
24542454 }
24552455 o -> h_weakreflist = NULL ;
2456+ o -> h_hash = -1 ;
2457+ o -> h_count = 0 ;
24562458 PyObject_GC_Track (o );
24572459 return o ;
24582460}
@@ -2478,8 +2480,6 @@ map_new(void)
24782480 return NULL ;
24792481 }
24802482
2481- o -> h_count = 0 ;
2482-
24832483 if (_empty_map == NULL ) {
24842484 Py_INCREF (o );
24852485 _empty_map = o ;
@@ -2942,6 +2942,65 @@ map_py_repr(MapObject *self)
29422942}
29432943
29442944
2945+ static Py_uhash_t
2946+ _shuffle_bits (Py_uhash_t h )
2947+ {
2948+ return ((h ^ 89869747UL ) ^ (h << 16 )) * 3644798167UL ;
2949+ }
2950+
2951+
2952+ static Py_hash_t
2953+ map_py_hash (MapObject * self )
2954+ {
2955+ /* Adapted version of frozenset.__hash__: it's important
2956+ that Map.__hash__ is independant of key/values order.
2957+
2958+ Optimization idea: compute and memoize intermediate
2959+ hash values for HAMT nodes.
2960+ */
2961+
2962+ if (self -> h_hash != -1 ) {
2963+ return self -> h_hash ;
2964+ }
2965+
2966+ Py_uhash_t hash = 0 ;
2967+
2968+ MapIteratorState iter ;
2969+ map_iter_t iter_res ;
2970+ map_iterator_init (& iter , self -> h_root );
2971+ do {
2972+ PyObject * v_key ;
2973+ PyObject * v_val ;
2974+
2975+ iter_res = map_iterator_next (& iter , & v_key , & v_val );
2976+ if (iter_res == I_ITEM ) {
2977+ Py_hash_t vh = PyObject_Hash (v_key );
2978+ if (vh == -1 ) {
2979+ return -1 ;
2980+ }
2981+ hash ^= _shuffle_bits ((Py_uhash_t )vh );
2982+
2983+ vh = PyObject_Hash (v_val );
2984+ if (vh == -1 ) {
2985+ return -1 ;
2986+ }
2987+ hash ^= _shuffle_bits ((Py_uhash_t )vh );
2988+ }
2989+ } while (iter_res != I_END );
2990+
2991+ hash ^= ((Py_uhash_t )self -> h_count * 2 + 1 ) * 1927868237UL ;
2992+
2993+ hash ^= (hash >> 11 ) ^ (hash >> 25 );
2994+ hash = hash * 69069U + 907133923UL ;
2995+
2996+ self -> h_hash = (Py_hash_t )hash ;
2997+ if (self -> h_hash == -1 ) {
2998+ self -> h_hash = 1 ;
2999+ }
3000+ return self -> h_hash ;
3001+ }
3002+
3003+
29453004static PyMethodDef Map_methods [] = {
29463005 {"set" , (PyCFunction )map_py_set , METH_VARARGS , NULL },
29473006 {"get" , (PyCFunction )map_py_get , METH_VARARGS , NULL },
@@ -2987,7 +3046,7 @@ PyTypeObject _Map_Type = {
29873046 .tp_clear = (inquiry )map_tp_clear ,
29883047 .tp_new = map_tp_new ,
29893048 .tp_weaklistoffset = offsetof(MapObject , h_weakreflist ),
2990- .tp_hash = PyObject_HashNotImplemented ,
3049+ .tp_hash = ( hashfunc ) map_py_hash ,
29913050 .tp_repr = (reprfunc )map_py_repr ,
29923051};
29933052
0 commit comments