return mul32hi(statistical_prng(), range ? range - 1 : 0);
}
+/* The functions below are used to hash one or two pointers together and reduce
+ * the result to fit into a given number of bits. The first part is made of a
+ * multiplication (and possibly an addition) by one or two prime numbers giving
+ * a 64-bit number whose center bits are the most distributed, and the second
+ * part will reuse this value and return a mix of the most variable bits that
+ * fits in the requested size. The most convenient approach is to directly
+ * call ptr_hash() / ptr2_hash(), though for some specific use cases where a
+ * second value could be useful, one may prefer to call the lower level
+ * operations instead.
+ */
+
+/* reduce a 64-bit pointer hash to <bits> bits */
+static forceinline uint _ptr_hash_reduce(unsigned long long x, const int bits)
+{
+ if (!bits)
+ return 0;
+
+ if (sizeof(long) == 4)
+ x ^= x >> 32;
+ else
+ x >>= 31 - (bits + 1) / 2;
+ return x & (~0U >> (-bits & 31));
+}
+
+/* single-pointer version, low-level, use ptr_hash() instead */
+static forceinline ullong _ptr_hash(const void *p)
+{
+ unsigned long long x = (unsigned long)p;
+
+ x *= 0xacd1be85U;
+ return x;
+}
+
+/* two-pointer version, low-level, use ptr2_hash() instead */
+static forceinline ullong _ptr2_hash(const void *p1, const void *p2)
+{
+ unsigned long long x = (unsigned long)p1;
+ unsigned long long y = (unsigned long)p2;
+
+ x *= 0xacd1be85U;
+ y *= 0x9d28e4e9U;
+ return x ^ y;
+}
+
/* returns a hash on <bits> bits of pointer <p> that is suitable for being used
* to compute statistic buckets, in that it's fast and reasonably distributed
* thanks to mixing the bits via a multiplication by a prime number and using
*/
static forceinline uint ptr_hash(const void *p, const int bits)
{
- unsigned long long x = (unsigned long)p;
-
- if (!bits)
- return 0;
-
- x *= 0xacd1be85U;
- if (sizeof(long) == 4)
- x ^= x >> 32;
- else
- x >>= 31 - (bits + 1) / 2;
- return x & (~0U >> (-bits & 31));
+ return _ptr_hash_reduce(_ptr_hash(p), bits);
}
/* Same as above but works on two pointers. It will return the same values
*/
static forceinline uint ptr2_hash(const void *p1, const void *p2, const int bits)
{
- unsigned long long x = (unsigned long)p1;
- unsigned long long y = (unsigned long)p2;
-
- if (!bits)
- return 0;
-
- x *= 0xacd1be85U;
- y *= 0x9d28e4e9U;
- x ^= y;
- if (sizeof(long) == 4)
- x ^= x >> 32;
- else
- x >>= 33 - bits / 2;
- return x & (~0U >> (-bits & 31));
+ return _ptr_hash_reduce(_ptr2_hash(p1, p2), bits);
}