@@ -171,11 +171,50 @@ static PySequenceMethods record_as_sequence = {
171171 0 , /* sq_contains */
172172};
173173
174+ #if SIZEOF_PY_UHASH_T > 4
175+ #define _PyHASH_XXPRIME_1 ((Py_uhash_t)11400714785074694791ULL)
176+ #define _PyHASH_XXPRIME_2 ((Py_uhash_t)14029467366897019727ULL)
177+ #define _PyHASH_XXPRIME_5 ((Py_uhash_t)2870177450012600261ULL)
178+ #define _PyHASH_XXROTATE (x ) ((x << 31) | (x >> 33)) /* Rotate left 31 bits */
179+ #else
180+ #define _PyHASH_XXPRIME_1 ((Py_uhash_t)2654435761UL)
181+ #define _PyHASH_XXPRIME_2 ((Py_uhash_t)2246822519UL)
182+ #define _PyHASH_XXPRIME_5 ((Py_uhash_t)374761393UL)
183+ #define _PyHASH_XXROTATE (x ) ((x << 13) | (x >> 19)) /* Rotate left 13 bits */
184+ #endif
185+
174186static Py_hash_t
175187record_hash (PyRecordObject * v )
176188{
177- // TODO
178- return -1 ;
189+ Py_ssize_t i , len = Py_SIZE (v );
190+ PyObject * * item = v -> ob_item ;
191+ PyObject * names = v -> names ;
192+
193+ Py_uhash_t acc = _PyHASH_XXPRIME_5 ;
194+ for (i = 0 ; i < len ; i ++ ) {
195+ Py_uhash_t lane = PyObject_Hash (item [i ]);
196+ if (lane == (Py_uhash_t )- 1 ) {
197+ return -1 ;
198+ }
199+ acc += lane * _PyHASH_XXPRIME_2 ;
200+ acc = _PyHASH_XXROTATE (acc );
201+ acc *= _PyHASH_XXPRIME_1 ;
202+ }
203+ Py_uhash_t lane = PyObject_Hash (names );
204+ if (lane == (Py_uhash_t )- 1 ) {
205+ return -1 ;
206+ }
207+ acc += lane * _PyHASH_XXPRIME_2 ;
208+ acc = _PyHASH_XXROTATE (acc );
209+ acc *= _PyHASH_XXPRIME_1 ;
210+
211+ /* Add input length, mangled to keep the historical value of hash(()). */
212+ acc += len ^ (_PyHASH_XXPRIME_5 ^ 3527539UL );
213+
214+ if (acc == (Py_uhash_t )- 1 ) {
215+ return 1546275796 ;
216+ }
217+ return acc ;
179218}
180219
181220PyObject *
@@ -212,8 +251,62 @@ record_getattro(PyObject *obj, PyObject *name)
212251static PyObject *
213252record_rich_compare (PyObject * v , PyObject * w , int op )
214253{
215- // TODO
216- return NULL ;
254+ PyRecordObject * vr , * wr ;
255+ Py_ssize_t i ;
256+ Py_ssize_t vlen , wlen ;
257+
258+ if (!PyRecord_Check (v ) || !PyRecord_Check (w ))
259+ Py_RETURN_NOTIMPLEMENTED ;
260+
261+ vr = (PyRecordObject * )v ;
262+ wr = (PyRecordObject * )w ;
263+
264+ vlen = Py_SIZE (vr );
265+ wlen = Py_SIZE (wr );
266+
267+ /* Note: the corresponding code for lists has an "early out" test
268+ * here when op is EQ or NE and the lengths differ. That pays there,
269+ * but Tim was unable to find any real code where EQ/NE tuple
270+ * compares don't have the same length, so testing for it here would
271+ * have cost without benefit.
272+ */
273+
274+ /* Search for the first index where items are different.
275+ * Note that because tuples are immutable, it's safe to reuse
276+ * vlen and wlen across the comparison calls.
277+ */
278+ int k = PyObject_RichCompareBool (vr -> names , wr -> names , Py_EQ );
279+ if (k < 0 )
280+ return NULL ;
281+ if (!k ) {
282+ if (op == Py_EQ ) Py_RETURN_FALSE ;
283+ if (op == Py_NE ) Py_RETURN_TRUE ;
284+ Py_RETURN_NOTIMPLEMENTED ;
285+ }
286+ for (i = 0 ; i < vlen && i < wlen ; i ++ ) {
287+ int k = PyObject_RichCompareBool (vr -> ob_item [i ],
288+ wr -> ob_item [i ], Py_EQ );
289+ if (k < 0 )
290+ return NULL ;
291+ if (!k )
292+ break ;
293+ }
294+
295+ if (i >= vlen || i >= wlen ) {
296+ /* No more items to compare -- compare sizes */
297+ Py_RETURN_RICHCOMPARE (vlen , wlen , op );
298+ }
299+
300+ /* We have an item that differs -- shortcuts for EQ/NE */
301+ if (op == Py_EQ ) {
302+ Py_RETURN_FALSE ;
303+ }
304+ if (op == Py_NE ) {
305+ Py_RETURN_TRUE ;
306+ }
307+
308+ /* Compare the final item again using the proper operator */
309+ Py_RETURN_NOTIMPLEMENTED ;
217310}
218311
219312static PyObject *
0 commit comments