packages feed

hashable 1.2.0.8 → 1.2.0.9

raw patch · 14 files changed

+593/−732 lines, 14 filesdep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: bytestring

API changes (from Hackage documentation)

Files

Data/Hashable.hs view
@@ -232,11 +232,7 @@ -- inputs to force an application into unexpectedly behaving with -- quadratic time complexity. ----- This library uses the SipHash algorithm to hash strings. SipHash--- was designed to be more robust against collision attacks than--- traditional hash algorithms, while retaining good performance.------ To further mitigate the risk from collision attacks, this library+-- To mitigate the risk from collision attacks, this library -- provides an environment variable named @HASHABLE_SALT@ that allows -- the default salt used by the 'hash' function to be chosen at -- application startup time.@@ -260,7 +256,7 @@ -- call to 'hash' is made, the application will halt with an -- informative error message. ----- (Implementation note: while SipHash is used for strings, a--- faster—and almost certainly less secure—algorithm is--- used for numeric types, on the assumption that strings are much--- more likely as a hash DoS attack vector.)+-- (Implementation note: FNV-1, the hash function used for strings,+-- can still be susceptible to collision attacks, even if a salt+-- unknown to the attacker is used. Future versions of the library+-- might improve on this situation.)
Data/Hashable/Class.hs view
@@ -50,27 +50,25 @@ import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B import qualified Data.ByteString.Lazy as BL-import qualified Data.ByteString.Lazy.Internal as BL #if defined(__GLASGOW_HASKELL__) import qualified Data.Text as T import qualified Data.Text.Array as TA import qualified Data.Text.Internal as T import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Internal as TL # ifdef GENERICS import GHC.Generics # endif #endif+import Foreign.C (CString) #if __GLASGOW_HASKELL__ >= 703-import Foreign.C (CSize(..))+import Foreign.C (CLong(..)) #else-import Foreign.C (CSize)+import Foreign.C (CLong) #endif import Foreign.Marshal.Utils (with)-import Foreign.Ptr (Ptr, castPtr, nullPtr)+import Foreign.Ptr (Ptr, castPtr) import Foreign.Storable (alignment, peek, sizeOf) import System.IO.Unsafe (unsafePerformIO)-import Foreign.Marshal.Array (advancePtr, allocaArray)  -- Byte arrays and Integers. #if defined(__GLASGOW_HASKELL__)@@ -264,14 +262,18 @@ hashNative salt = fromIntegral . go . xor (fromIntegral salt) . fromIntegral   where #if WORD_SIZE_IN_BITS == 32-    go = c_wang32+    go :: Word32 -> Word32 #else-    go = c_wang64+    go :: Word64 -> Word64 #endif+    go = id  -- | Hash a 64-bit integer. hash64 :: (Integral a) => Int -> a -> Int-hash64 salt = fromIntegral . c_wang64 . xor (fromIntegral salt) . fromIntegral+hash64 salt = fromIntegral . go . xor (fromIntegral salt) . fromIntegral+  where+    go :: Word64 -> Word64+    go = id  instance Hashable Integer where #if defined(__GLASGOW_HASKELL__) && defined(VERSION_integer_gmp)@@ -375,7 +377,7 @@                            hashPtrWithSalt p (fromIntegral len) salt  instance Hashable BL.ByteString where-    hashWithSalt = hashLazyByteStringWithSalt+    hashWithSalt = BL.foldlChunks hashWithSalt  #if defined(__GLASGOW_HASKELL__) instance Hashable T.Text where@@ -384,7 +386,7 @@         salt  instance Hashable TL.Text where-    hashWithSalt = hashLazyTextWithSalt+    hashWithSalt = TL.foldlChunks hashWithSalt #endif  @@ -437,54 +439,11 @@                 -> Int     -- ^ salt                 -> IO Int  -- ^ hash value hashPtrWithSalt p len salt =-    fromIntegral `fmap` c_siphash24 k0 (fromSalt salt) (castPtr p)-                        (fromIntegral len)--k0 :: Word64-k0 = 0x56e2b8a0aee1721a-{-# INLINE k0 #-}--hashLazyByteStringWithSalt :: Int -> BL.ByteString -> Int-hashLazyByteStringWithSalt salt cs0 = unsafePerformIO . allocaArray 5 $ \v -> do-  c_siphash_init k0 (fromSalt salt) v-  let go !buffered !totallen (BL.Chunk c cs) =-        B.unsafeUseAsCStringLen c $ \(ptr, len) -> do-          let len' = fromIntegral len-          buffered' <- c_siphash24_chunk buffered v (castPtr ptr) len' (-1)-          go buffered' (totallen + len') cs-      go buffered totallen _ = do-        _ <- c_siphash24_chunk buffered v nullPtr 0 totallen-        fromIntegral `fmap` peek (v `advancePtr` 4)-  go 0 0 cs0--#if defined(__GLASGOW_HASKELL__)-hashLazyTextWithSalt :: Int -> TL.Text -> Int-hashLazyTextWithSalt salt cs0 = unsafePerformIO . allocaArray 5 $ \v -> do-  c_siphash_init k0 (fromSalt salt) v-  let go !buffered !totallen (TL.Chunk (T.Text arr off len) cs) = do-        let len' = fromIntegral (len `shiftL` 1)-        buffered' <- c_siphash24_chunk_offset buffered v (TA.aBA arr)-                     (fromIntegral (off `shiftL` 1)) len' (-1)-        go buffered' (totallen + len') cs-      go buffered totallen _ = do-        _ <- c_siphash24_chunk buffered v nullPtr 0 totallen-        fromIntegral `fmap` peek (v `advancePtr` 4)-  go 0 0 cs0-#endif--fromSalt :: Int -> Word64-#if WORD_SIZE_IN_BITS == 64-fromSalt = fromIntegral-#else-fromSalt v = fromIntegral v `xor` k1--k1 :: Word64-k1 = 0x7654954208bdfef9-{-# INLINE k1 #-}-#endif+    fromIntegral `fmap` c_hashCString (castPtr p) (fromIntegral len)+    (fromIntegral salt) -foreign import ccall unsafe "hashable_siphash24" c_siphash24-    :: Word64 -> Word64 -> Ptr Word8 -> CSize -> IO Word64+foreign import ccall unsafe "hashable_fnv_hash" c_hashCString+    :: CString -> CLong -> CLong -> IO CLong  #if defined(__GLASGOW_HASKELL__) -- | Compute a hash value for the content of this 'ByteArray#',@@ -512,27 +471,9 @@     -> Int         -- ^ salt     -> Int         -- ^ hash value hashByteArrayWithSalt ba !off !len !h =-    fromIntegral $-    c_siphash24_offset k0 (fromSalt h) ba (fromIntegral off) (fromIntegral len)--foreign import ccall unsafe "hashable_siphash24_offset" c_siphash24_offset-    :: Word64 -> Word64 -> ByteArray# -> CSize -> CSize -> Word64--foreign import ccall unsafe "hashable_siphash24_chunk_offset"-        c_siphash24_chunk_offset-    :: CInt -> Ptr Word64 -> ByteArray# -> CSize -> CSize -> CSize -> IO CInt-#endif+    fromIntegral $ c_hashByteArray ba (fromIntegral off) (fromIntegral len)+    (fromIntegral h) -#if WORD_SIZE_IN_BITS == 32-foreign import ccall unsafe "hashable_wang_32" c_wang32-    :: Word32 -> Word32+foreign import ccall unsafe "hashable_fnv_hash_offset" c_hashByteArray+    :: ByteArray# -> CLong -> CLong -> CLong -> CLong #endif--foreign import ccall unsafe "hashable_wang_64" c_wang64-    :: Word64 -> Word64--foreign import ccall unsafe "hashable_siphash_init" c_siphash_init-    :: Word64 -> Word64 -> Ptr Word64 -> IO ()--foreign import ccall unsafe "hashable_siphash24_chunk" c_siphash24_chunk-    :: CInt -> Ptr Word64 -> Ptr Word8 -> CSize -> CSize -> IO CInt
− benchmarks/cbits/fnv.c
@@ -1,53 +0,0 @@-/*-Copyright Johan Tibell 2011--All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:--    * Redistributions of source code must retain the above copyright-      notice, this list of conditions and the following disclaimer.--    * Redistributions in binary form must reproduce the above-      copyright notice, this list of conditions and the following-      disclaimer in the documentation and/or other materials provided-      with the distribution.--    * Neither the name of Johan Tibell nor the names of other-      contributors may be used to endorse or promote products derived-      from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-*/--/* FNV-1 hash- *- * The FNV-1 hash description: http://isthe.com/chongo/tech/comp/fnv/- * The FNV-1 hash is public domain: http://isthe.com/chongo/tech/comp/fnv/#public_domain- */-long hashable_fnv_hash(const unsigned char* str, long len, long hash) {--  while (len--) {-    hash = (hash * 16777619) ^ *str++;-  }--  return hash;-}--/* Used for ByteArray#s. We can't treat them like pointers in-   native Haskell, but we can in unsafe FFI calls.- */-long hashable_fnv_hash_offset(const unsigned char* str, long offset, long len, long hash) {-  return hashable_fnv_hash(str + offset, len, hash);-}
+ benchmarks/cbits/siphash-sse2.c view
@@ -0,0 +1,129 @@+/*+ * The original code was developed by Samuel Neves, and has been+ * only lightly modified.+ *+ * Used with permission.+ */+#pragma GCC target("sse2")++#include <emmintrin.h>+#include "siphash.h"++#define _mm_roti_epi64(x, c) ((16 == (c)) ? _mm_shufflelo_epi16((x), _MM_SHUFFLE(2,1,0,3)) : _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c))))++u64 hashable_siphash24_sse2(u64 ik0, u64 ik1, const u8 *m, size_t n)+{+	__m128i v0, v1, v2, v3;+	__m128i k0, k1;+	__m128i mi, mask, len;+	size_t i, k;+	union { u64 gpr; __m128i xmm; } hash;+	const u8 *p;++	/* We used to use the _mm_seti_epi32 intrinsic to initialize+	   SSE2 registers. This compiles to a movdqa instruction,+	   which requires 16-byte alignment. On 32-bit Windows, it+	   looks like ghc's runtime linker doesn't align ".rdata"+	   sections as requested, so we got segfaults for our trouble.++	   Now we use an intrinsic that cares less about alignment+	   (_mm_loadu_si128, aka movdqu) instead, and all seems+	   happy. */++	static const u32 const iv[6][4] = {+		{ 0x70736575, 0x736f6d65, 0, 0 },+		{ 0x6e646f6d, 0x646f7261, 0, 0 },+		{ 0x6e657261, 0x6c796765, 0, 0 },+		{ 0x79746573, 0x74656462, 0, 0 },+		{ -1, -1, 0, 0 },+		{ 255, 0, 0, 0 },+	};++	k0 = _mm_loadl_epi64((__m128i*)(&ik0));+	k1 = _mm_loadl_epi64((__m128i*)(&ik1));++	v0 = _mm_xor_si128(k0, _mm_loadu_si128((__m128i*) &iv[0]));+	v1 = _mm_xor_si128(k1, _mm_loadu_si128((__m128i*) &iv[1]));+	v2 = _mm_xor_si128(k0, _mm_loadu_si128((__m128i*) &iv[2]));+	v3 = _mm_xor_si128(k1, _mm_loadu_si128((__m128i*) &iv[3]));++#define HALF_ROUND(a,b,c,d,s,t) \+	do \+	{ \+		a = _mm_add_epi64(a, b);  c = _mm_add_epi64(c, d); \+		b = _mm_roti_epi64(b, s); d = _mm_roti_epi64(d, t); \+		b = _mm_xor_si128(b, a);  d = _mm_xor_si128(d, c); \+	} while(0)++#define COMPRESS(v0,v1,v2,v3) \+	do \+	{ \+		HALF_ROUND(v0,v1,v2,v3,13,16); \+		v0 = _mm_shufflelo_epi16(v0, _MM_SHUFFLE(1,0,3,2)); \+		HALF_ROUND(v2,v1,v0,v3,17,21); \+		v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(1,0,3,2)); \+	} while(0)++	for(i = 0; i < (n-n%8); i += 8)+	{+		mi = _mm_loadl_epi64((__m128i*)(m + i));+		v3 = _mm_xor_si128(v3, mi);+		if (SIPHASH_ROUNDS == 2) {+			COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);+		} else {+			for (k = 0; k < SIPHASH_ROUNDS; ++k)+				COMPRESS(v0,v1,v2,v3);+		}+		v0 = _mm_xor_si128(v0, mi);+	}++	p = m + n;++	/* We must be careful to not trigger a segfault by reading an+	   unmapped page. So where is the end of our input? */++	if (((uintptr_t) p & 4095) == 0)+		/* Exactly at a page boundary: do not read past the end. */+		mi = _mm_setzero_si128();+	else if (((uintptr_t) p & 4095) <= 4088)+		/* Inside a page: safe to read past the end, as we'll+		   mask out any bits we shouldn't have looked at below. */+		mi = _mm_loadl_epi64((__m128i*)(m + i));+	else+		/* Within 8 bytes of the end of a page: ensure that+		   our final read re-reads some bytes so that we do+		   not cross the page boundary, then shift our result+		   right so that the re-read bytes vanish. */+		mi = _mm_srli_epi64(_mm_loadl_epi64((__m128i*)(((uintptr_t) m + i) & ~7)),+				    8 * (((uintptr_t) m + i) % 8));++	len = _mm_set_epi32(0, 0, (n&0xff) << 24, 0);+	mask = _mm_srli_epi64(_mm_loadu_si128((__m128i*) &iv[4]), 8*(8-n%8));+	mi = _mm_xor_si128(_mm_and_si128(mi, mask), len);++	v3 = _mm_xor_si128(v3, mi);+	if (SIPHASH_ROUNDS == 2) {+		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);+	} else {+		for (k = 0; k < SIPHASH_ROUNDS; ++k)+			COMPRESS(v0,v1,v2,v3);+	}+	v0 = _mm_xor_si128(v0, mi);++	v2 = _mm_xor_si128(v2, _mm_loadu_si128((__m128i*) &iv[5]));+	if (SIPHASH_FINALROUNDS == 4) {+		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);+		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);+	} else {+		for (k = 0; k < SIPHASH_FINALROUNDS; ++k)+			COMPRESS(v0,v1,v2,v3);+	}++	v0 = _mm_xor_si128(_mm_xor_si128(v0, v1), _mm_xor_si128(v2, v3));+	hash.xmm = v0;++#undef COMPRESS+#undef HALF_ROUND+	//return _mm_extract_epi32(v0, 0) | (((u64)_mm_extract_epi32(v0, 1)) << 32);+	return hash.gpr;+}
+ benchmarks/cbits/siphash-sse41.c view
@@ -0,0 +1,86 @@+/*+ * The original code was developed by Samuel Neves, and has been+ * only lightly modified.+ *+ * Used with permission.+ */+#pragma GCC target("sse4.1")++#include <smmintrin.h>+#include "siphash.h"++// Specialized for siphash, do not reuse+#define rotate16(x) _mm_shufflehi_epi16((x), _MM_SHUFFLE(2,1,0,3))++#define _mm_roti_epi64(x, c) (((c) == 16) ? rotate16((x)) : _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c))))+//#define _mm_roti_epi64(x, c)  _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c)))+++u64 hashable_siphash24_sse41(u64 _k0, u64 _k1, const unsigned char *m, size_t n)+{+	__m128i v0, v1, v02, v13;+	__m128i k0;+	__m128i mi, mask, len, h;+	const __m128i zero = _mm_setzero_si128();+	size_t i, k;+	union { u64 gpr; __m128i xmm; } hash;+	unsigned char key[16];++	((u64 *)key)[0] = _k0;+	((u64 *)key)[1] = _k1;++	k0 = _mm_loadu_si128((__m128i*)(key + 0));++	v0 = _mm_xor_si128(k0, _mm_set_epi32(0x646f7261, 0x6e646f6d, 0x736f6d65, 0x70736575));+	v1 = _mm_xor_si128(k0, _mm_set_epi32(0x74656462, 0x79746573, 0x6c796765, 0x6e657261));++	v02 = _mm_unpacklo_epi64(v0, v1);+	v13 = _mm_unpackhi_epi64(v0, v1);++#define HALF_ROUND(a,b,s,t) \+do \+{ \+	__m128i b1,b2; \+	a = _mm_add_epi64(a, b);  \+	b1 = _mm_roti_epi64(b, s); b2 = _mm_roti_epi64(b, t); b = _mm_blend_epi16(b1, b2, 0xF0); \+	b = _mm_xor_si128(b, a);  \+} while(0)++#define COMPRESS(v02,v13) \+	do \+	{ \+		HALF_ROUND(v02,v13,13,16); \+		v02 = _mm_shuffle_epi32(v02, _MM_SHUFFLE(0,1,3,2)); \+		HALF_ROUND(v02,v13,17,21); \+		v02 = _mm_shuffle_epi32(v02, _MM_SHUFFLE(0,1,3,2)); \+	} while(0)++	for(i = 0; i < (n-n%8); i += 8)+	{+		mi = _mm_loadl_epi64((__m128i*)(m + i));+		v13 = _mm_xor_si128(v13, _mm_unpacklo_epi64(zero, mi));+		for(k = 0; k < SIPHASH_ROUNDS; ++k) COMPRESS(v02,v13);+		v02 = _mm_xor_si128(v02, mi);+	}++	mi = _mm_loadl_epi64((__m128i*)(m + i));+	len = _mm_set_epi32(0, 0, (n&0xff) << 24, 0);+	mask = _mm_srli_epi64(_mm_set_epi32(0, 0, 0xffffffff, 0xffffffff), 8*(8-n%8));+	mi = _mm_xor_si128(_mm_and_si128(mi, mask), len);++	v13 = _mm_xor_si128(v13, _mm_unpacklo_epi64(zero, mi));+	for(k = 0; k < SIPHASH_ROUNDS; ++k) COMPRESS(v02,v13);+	v02 = _mm_xor_si128(v02, mi);++	v02 = _mm_xor_si128(v02, _mm_set_epi32(0, 0xff, 0, 0));+	for(k = 0; k < SIPHASH_FINALROUNDS; ++k) COMPRESS(v02,v13);++	v0 = _mm_xor_si128(v02, v13);+	v0 = _mm_xor_si128(v0, _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(zero), _mm_castsi128_ps(v0))));+	hash.xmm = v0;++#undef COMPRESS+#undef HALF_ROUND+	//return _mm_extract_epi32(v0, 0) | (((u64)_mm_extract_epi32(v0, 1)) << 32);+	return hash.gpr;+}
+ benchmarks/cbits/siphash.c view
@@ -0,0 +1,262 @@+/* Almost a verbatim copy of the reference implementation. */++#include <stddef.h>+#include "siphash.h"++#define ROTL(x,b) (u64)(((x) << (b)) | ((x) >> (64 - (b))))++#define SIPROUND \+    do { \+	v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \+	v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \+	v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \+	v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \+    } while(0)++#if defined(__i386)+# define _siphash24 plain_siphash24+#endif++static inline u64 odd_read(const u8 *p, int count, u64 val, int shift)+{+    switch (count) {+    case 7: val |= ((u64)p[6]) << (shift + 48);+    case 6: val |= ((u64)p[5]) << (shift + 40);+    case 5: val |= ((u64)p[4]) << (shift + 32);+    case 4: val |= ((u64)p[3]) << (shift + 24);+    case 3: val |= ((u64)p[2]) << (shift + 16);+    case 2: val |= ((u64)p[1]) << (shift + 8);+    case 1: val |= ((u64)p[0]) << shift;+    }+    return val;+}++static inline u64 _siphash(int c, int d, u64 k0, u64 k1,+			   const u8 *str, size_t len)+{+    u64 v0 = 0x736f6d6570736575ull ^ k0;+    u64 v1 = 0x646f72616e646f6dull ^ k1;+    u64 v2 = 0x6c7967656e657261ull ^ k0;+    u64 v3 = 0x7465646279746573ull ^ k1;+    const u8 *end, *p;+    u64 b;+    int i;++    for (p = str, end = str + (len & ~7); p < end; p += 8) {+	u64 m = peek_u64le((u64 *) p);+	v3 ^= m;+	if (c == 2) {+	    SIPROUND;+	    SIPROUND;+	} else {+	    for (i = 0; i < c; i++)+		SIPROUND;+	}+	v0 ^= m;+    }++    b = odd_read(p, len & 7, ((u64) len) << 56, 0);++    v3 ^= b;+    if (c == 2) {+	SIPROUND;+	SIPROUND;+    } else {+	for (i = 0; i < c; i++)+	    SIPROUND;+    }+    v0 ^= b;++    v2 ^= 0xff;+    if (d == 4) {+	SIPROUND;+	SIPROUND;+	SIPROUND;+	SIPROUND;+    } else {+	for (i = 0; i < d; i++)+	    SIPROUND;+    }+    b = v0 ^ v1 ^ v2  ^ v3;+    return b;+}+++static inline u64 _siphash24(u64 k0, u64 k1, const u8 *str, size_t len)+{+    return _siphash(2, 4, k0, k1, str, len);+}++#if defined(__i386)+# undef _siphash24++static u64 (*_siphash24)(u64 k0, u64 k1, const u8 *, size_t);++static void maybe_use_sse()+    __attribute__((constructor));++static void maybe_use_sse()+{+    uint32_t eax = 1, ebx, ecx, edx;++    __asm volatile+	("mov %%ebx, %%edi;" /* 32bit PIC: don't clobber ebx */+	 "cpuid;"+	 "mov %%ebx, %%esi;"+	 "mov %%edi, %%ebx;"+	 :"+a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx)+	 : :"edi");++#if defined(HAVE_SSE2)+    if (edx & (1 << 26))+	_siphash24 = hashable_siphash24_sse2;+#if defined(HAVE_SSE41)+    else if (ecx & (1 << 19))+	_siphash24 = hashable_siphash24_sse41;+#endif+    else+#endif+	_siphash24 = plain_siphash24;+}++#endif++/* ghci's linker fails to call static initializers. */+static inline void ensure_sse_init()+{+#if defined(__i386)+    if (_siphash24 == NULL)+	maybe_use_sse();+#endif+}++u64 hashable_siphash(int c, int d, u64 k0, u64 k1, const u8 *str, size_t len)+{+    return _siphash(c, d, k0, k1, str, len);+}++u64 hashable_siphash24(u64 k0, u64 k1, const u8 *str, size_t len)+{+    ensure_sse_init();+    return _siphash24(k0, k1, str, len);+}++/* Used for ByteArray#s. We can't treat them like pointers in+   native Haskell, but we can in unsafe FFI calls.+ */+u64 hashable_siphash24_offset(u64 k0, u64 k1,+			      const u8 *str, size_t off, size_t len)+{+    ensure_sse_init();+    return _siphash24(k0, k1, str + off, len);+}++static int _siphash_chunk(int c, int d, int buffered, u64 v[5],+			  const u8 *str, size_t len, size_t totallen)+{+    u64 v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3], m, b;+    const u8 *p, *end;+    u64 carry = 0;+    int i;++    if (buffered > 0) {+	int unbuffered = 8 - buffered;+	int tobuffer = unbuffered > len ? len : unbuffered;+	int shift = buffered << 3;++	m = odd_read(str, tobuffer, v[4], shift);+	str += tobuffer;+	buffered += tobuffer;+	len -= tobuffer;++	if (buffered < 8)+	    carry = m;+	else {+	    v3 ^= m;+	    if (c == 2) {+		SIPROUND;+		SIPROUND;+	    } else {+		for (i = 0; i < c; i++)+		    SIPROUND;+	    }+	    v0 ^= m;+	    buffered = 0;+	    m = 0;+	}+    }++    for (p = str, end = str + (len & ~7); p < end; p += 8) {+	m = peek_u64le((u64 *) p);+	v3 ^= m;+	if (c == 2) {+	    SIPROUND;+	    SIPROUND;+	} else {+	    for (i = 0; i < c; i++)+		SIPROUND;+	}+	v0 ^= m;+    }++    b = odd_read(p, len & 7, 0, 0);++    if (totallen == -1) {+	v[0] = v0;+	v[1] = v1;+	v[2] = v2;+	v[3] = v3;+	v[4] = b | carry;++	return buffered + (len & 7);+    }++    b |= ((u64) totallen) << 56;++    v3 ^= b;+    if (c == 2) {+	SIPROUND;+	SIPROUND;+    } else {+	for (i = 0; i < c; i++)+	    SIPROUND;+    }+    v0 ^= b;++    v2 ^= 0xff;+    if (d == 4) {+	SIPROUND;+	SIPROUND;+	SIPROUND;+	SIPROUND;+    } else {+	for (i = 0; i < d; i++)+	    SIPROUND;+    }+    v[4] = v0 ^ v1 ^ v2  ^ v3;+    return 0;+}++void hashable_siphash_init(u64 k0, u64 k1, u64 *v)+{+    v[0] = 0x736f6d6570736575ull ^ k0;+    v[1] = 0x646f72616e646f6dull ^ k1;+    v[2] = 0x6c7967656e657261ull ^ k0;+    v[3] = 0x7465646279746573ull ^ k1;+    v[4] = 0;+}++int hashable_siphash24_chunk(int buffered, u64 v[5], const u8 *str,+			     size_t len, size_t totallen)+{+    return _siphash_chunk(2, 4, buffered, v, str, len, totallen);+}++/*+ * Used for ByteArray#.+ */+int hashable_siphash24_chunk_offset(int buffered, u64 v[5], const u8 *str,+				    size_t off, size_t len, size_t totallen)+{+    return _siphash_chunk(2, 4, buffered, v, str + off, len, totallen);+}
+ benchmarks/cbits/wang.c view
@@ -0,0 +1,29 @@+/*+ * These hash functions were developed by Thomas Wang.+ *+ * http://www.concentric.net/~ttwang/tech/inthash.htm+ */++#include <stdint.h>++uint32_t hashable_wang_32(uint32_t a)+{+    a = (a ^ 61) ^ (a >> 16);+    a = a + (a << 3);+    a = a ^ (a >> 4);+    a = a * 0x27d4eb2d;+    a = a ^ (a >> 15);+    return a;+}++uint64_t hashable_wang_64(uint64_t key)+{+    key = (~key) + (key << 21); // key = (key << 21) - key - 1;+    key = key ^ ((key >> 24) | (key << 40));+    key = (key + (key << 3)) + (key << 8); // key * 265+    key = key ^ ((key >> 14) | (key << 50));+    key = (key + (key << 2)) + (key << 4); // key * 21+    key = key ^ ((key >> 28) | (key << 36));+    key = key + (key << 31);+    return key;+}
+ cbits/fnv.c view
@@ -0,0 +1,53 @@+/*+Copyright Johan Tibell 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Johan Tibell nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+*/++/* FNV-1 hash+ *+ * The FNV-1 hash description: http://isthe.com/chongo/tech/comp/fnv/+ * The FNV-1 hash is public domain: http://isthe.com/chongo/tech/comp/fnv/#public_domain+ */+long hashable_fnv_hash(const unsigned char* str, long len, long hash) {++  while (len--) {+    hash = (hash * 16777619) ^ *str++;+  }++  return hash;+}++/* Used for ByteArray#s. We can't treat them like pointers in+   native Haskell, but we can in unsafe FFI calls.+ */+long hashable_fnv_hash_offset(const unsigned char* str, long offset, long len, long hash) {+  return hashable_fnv_hash(str + offset, len, hash);+}
− cbits/inthash.c
@@ -1,29 +0,0 @@-/*- * These hash functions were developed by Thomas Wang.- *- * http://www.concentric.net/~ttwang/tech/inthash.htm- */--#include <stdint.h>--uint32_t hashable_wang_32(uint32_t a)-{-    a = (a ^ 61) ^ (a >> 16);-    a = a + (a << 3);-    a = a ^ (a >> 4);-    a = a * 0x27d4eb2d;-    a = a ^ (a >> 15);-    return a;-}--uint64_t hashable_wang_64(uint64_t key)-{-    key = (~key) + (key << 21); // key = (key << 21) - key - 1;-    key = key ^ ((key >> 24) | (key << 40));-    key = (key + (key << 3)) + (key << 8); // key * 265-    key = key ^ ((key >> 14) | (key << 50));-    key = (key + (key << 2)) + (key << 4); // key * 21-    key = key ^ ((key >> 28) | (key << 36));-    key = key + (key << 31);-    return key;-}
− cbits/siphash-sse2.c
@@ -1,129 +0,0 @@-/*- * The original code was developed by Samuel Neves, and has been- * only lightly modified.- *- * Used with permission.- */-#pragma GCC target("sse2")--#include <emmintrin.h>-#include "siphash.h"--#define _mm_roti_epi64(x, c) ((16 == (c)) ? _mm_shufflelo_epi16((x), _MM_SHUFFLE(2,1,0,3)) : _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c))))--u64 hashable_siphash24_sse2(u64 ik0, u64 ik1, const u8 *m, size_t n)-{-	__m128i v0, v1, v2, v3;-	__m128i k0, k1;-	__m128i mi, mask, len;-	size_t i, k;-	union { u64 gpr; __m128i xmm; } hash;-	const u8 *p;--	/* We used to use the _mm_seti_epi32 intrinsic to initialize-	   SSE2 registers. This compiles to a movdqa instruction,-	   which requires 16-byte alignment. On 32-bit Windows, it-	   looks like ghc's runtime linker doesn't align ".rdata"-	   sections as requested, so we got segfaults for our trouble.--	   Now we use an intrinsic that cares less about alignment-	   (_mm_loadu_si128, aka movdqu) instead, and all seems-	   happy. */--	static const u32 const iv[6][4] = {-		{ 0x70736575, 0x736f6d65, 0, 0 },-		{ 0x6e646f6d, 0x646f7261, 0, 0 },-		{ 0x6e657261, 0x6c796765, 0, 0 },-		{ 0x79746573, 0x74656462, 0, 0 },-		{ -1, -1, 0, 0 },-		{ 255, 0, 0, 0 },-	};--	k0 = _mm_loadl_epi64((__m128i*)(&ik0));-	k1 = _mm_loadl_epi64((__m128i*)(&ik1));--	v0 = _mm_xor_si128(k0, _mm_loadu_si128((__m128i*) &iv[0]));-	v1 = _mm_xor_si128(k1, _mm_loadu_si128((__m128i*) &iv[1]));-	v2 = _mm_xor_si128(k0, _mm_loadu_si128((__m128i*) &iv[2]));-	v3 = _mm_xor_si128(k1, _mm_loadu_si128((__m128i*) &iv[3]));--#define HALF_ROUND(a,b,c,d,s,t) \-	do \-	{ \-		a = _mm_add_epi64(a, b);  c = _mm_add_epi64(c, d); \-		b = _mm_roti_epi64(b, s); d = _mm_roti_epi64(d, t); \-		b = _mm_xor_si128(b, a);  d = _mm_xor_si128(d, c); \-	} while(0)--#define COMPRESS(v0,v1,v2,v3) \-	do \-	{ \-		HALF_ROUND(v0,v1,v2,v3,13,16); \-		v0 = _mm_shufflelo_epi16(v0, _MM_SHUFFLE(1,0,3,2)); \-		HALF_ROUND(v2,v1,v0,v3,17,21); \-		v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(1,0,3,2)); \-	} while(0)--	for(i = 0; i < (n-n%8); i += 8)-	{-		mi = _mm_loadl_epi64((__m128i*)(m + i));-		v3 = _mm_xor_si128(v3, mi);-		if (SIPHASH_ROUNDS == 2) {-			COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);-		} else {-			for (k = 0; k < SIPHASH_ROUNDS; ++k)-				COMPRESS(v0,v1,v2,v3);-		}-		v0 = _mm_xor_si128(v0, mi);-	}--	p = m + n;--	/* We must be careful to not trigger a segfault by reading an-	   unmapped page. So where is the end of our input? */--	if (((uintptr_t) p & 4095) == 0)-		/* Exactly at a page boundary: do not read past the end. */-		mi = _mm_setzero_si128();-	else if (((uintptr_t) p & 4095) <= 4088)-		/* Inside a page: safe to read past the end, as we'll-		   mask out any bits we shouldn't have looked at below. */-		mi = _mm_loadl_epi64((__m128i*)(m + i));-	else-		/* Within 8 bytes of the end of a page: ensure that-		   our final read re-reads some bytes so that we do-		   not cross the page boundary, then shift our result-		   right so that the re-read bytes vanish. */-		mi = _mm_srli_epi64(_mm_loadl_epi64((__m128i*)(((uintptr_t) m + i) & ~7)),-				    8 * (((uintptr_t) m + i) % 8));--	len = _mm_set_epi32(0, 0, (n&0xff) << 24, 0);-	mask = _mm_srli_epi64(_mm_loadu_si128((__m128i*) &iv[4]), 8*(8-n%8));-	mi = _mm_xor_si128(_mm_and_si128(mi, mask), len);--	v3 = _mm_xor_si128(v3, mi);-	if (SIPHASH_ROUNDS == 2) {-		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);-	} else {-		for (k = 0; k < SIPHASH_ROUNDS; ++k)-			COMPRESS(v0,v1,v2,v3);-	}-	v0 = _mm_xor_si128(v0, mi);--	v2 = _mm_xor_si128(v2, _mm_loadu_si128((__m128i*) &iv[5]));-	if (SIPHASH_FINALROUNDS == 4) {-		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);-		COMPRESS(v0,v1,v2,v3); COMPRESS(v0,v1,v2,v3);-	} else {-		for (k = 0; k < SIPHASH_FINALROUNDS; ++k)-			COMPRESS(v0,v1,v2,v3);-	}--	v0 = _mm_xor_si128(_mm_xor_si128(v0, v1), _mm_xor_si128(v2, v3));-	hash.xmm = v0;--#undef COMPRESS-#undef HALF_ROUND-	//return _mm_extract_epi32(v0, 0) | (((u64)_mm_extract_epi32(v0, 1)) << 32);-	return hash.gpr;-}
− cbits/siphash-sse41.c
@@ -1,86 +0,0 @@-/*- * The original code was developed by Samuel Neves, and has been- * only lightly modified.- *- * Used with permission.- */-#pragma GCC target("sse4.1")--#include <smmintrin.h>-#include "siphash.h"--// Specialized for siphash, do not reuse-#define rotate16(x) _mm_shufflehi_epi16((x), _MM_SHUFFLE(2,1,0,3))--#define _mm_roti_epi64(x, c) (((c) == 16) ? rotate16((x)) : _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c))))-//#define _mm_roti_epi64(x, c)  _mm_xor_si128(_mm_slli_epi64((x), (c)), _mm_srli_epi64((x), 64-(c)))---u64 hashable_siphash24_sse41(u64 _k0, u64 _k1, const unsigned char *m, size_t n)-{-	__m128i v0, v1, v02, v13;-	__m128i k0;-	__m128i mi, mask, len, h;-	const __m128i zero = _mm_setzero_si128();-	size_t i, k;-	union { u64 gpr; __m128i xmm; } hash;-	unsigned char key[16];--	((u64 *)key)[0] = _k0;-	((u64 *)key)[1] = _k1;--	k0 = _mm_loadu_si128((__m128i*)(key + 0));--	v0 = _mm_xor_si128(k0, _mm_set_epi32(0x646f7261, 0x6e646f6d, 0x736f6d65, 0x70736575));-	v1 = _mm_xor_si128(k0, _mm_set_epi32(0x74656462, 0x79746573, 0x6c796765, 0x6e657261));--	v02 = _mm_unpacklo_epi64(v0, v1);-	v13 = _mm_unpackhi_epi64(v0, v1);--#define HALF_ROUND(a,b,s,t) \-do \-{ \-	__m128i b1,b2; \-	a = _mm_add_epi64(a, b);  \-	b1 = _mm_roti_epi64(b, s); b2 = _mm_roti_epi64(b, t); b = _mm_blend_epi16(b1, b2, 0xF0); \-	b = _mm_xor_si128(b, a);  \-} while(0)--#define COMPRESS(v02,v13) \-	do \-	{ \-		HALF_ROUND(v02,v13,13,16); \-		v02 = _mm_shuffle_epi32(v02, _MM_SHUFFLE(0,1,3,2)); \-		HALF_ROUND(v02,v13,17,21); \-		v02 = _mm_shuffle_epi32(v02, _MM_SHUFFLE(0,1,3,2)); \-	} while(0)--	for(i = 0; i < (n-n%8); i += 8)-	{-		mi = _mm_loadl_epi64((__m128i*)(m + i));-		v13 = _mm_xor_si128(v13, _mm_unpacklo_epi64(zero, mi));-		for(k = 0; k < SIPHASH_ROUNDS; ++k) COMPRESS(v02,v13);-		v02 = _mm_xor_si128(v02, mi);-	}--	mi = _mm_loadl_epi64((__m128i*)(m + i));-	len = _mm_set_epi32(0, 0, (n&0xff) << 24, 0);-	mask = _mm_srli_epi64(_mm_set_epi32(0, 0, 0xffffffff, 0xffffffff), 8*(8-n%8));-	mi = _mm_xor_si128(_mm_and_si128(mi, mask), len);--	v13 = _mm_xor_si128(v13, _mm_unpacklo_epi64(zero, mi));-	for(k = 0; k < SIPHASH_ROUNDS; ++k) COMPRESS(v02,v13);-	v02 = _mm_xor_si128(v02, mi);--	v02 = _mm_xor_si128(v02, _mm_set_epi32(0, 0xff, 0, 0));-	for(k = 0; k < SIPHASH_FINALROUNDS; ++k) COMPRESS(v02,v13);--	v0 = _mm_xor_si128(v02, v13);-	v0 = _mm_xor_si128(v0, _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(zero), _mm_castsi128_ps(v0))));-	hash.xmm = v0;--#undef COMPRESS-#undef HALF_ROUND-	//return _mm_extract_epi32(v0, 0) | (((u64)_mm_extract_epi32(v0, 1)) << 32);-	return hash.gpr;-}
− cbits/siphash.c
@@ -1,262 +0,0 @@-/* Almost a verbatim copy of the reference implementation. */--#include <stddef.h>-#include "siphash.h"--#define ROTL(x,b) (u64)(((x) << (b)) | ((x) >> (64 - (b))))--#define SIPROUND \-    do { \-	v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \-	v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \-	v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \-	v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \-    } while(0)--#if defined(__i386)-# define _siphash24 plain_siphash24-#endif--static inline u64 odd_read(const u8 *p, int count, u64 val, int shift)-{-    switch (count) {-    case 7: val |= ((u64)p[6]) << (shift + 48);-    case 6: val |= ((u64)p[5]) << (shift + 40);-    case 5: val |= ((u64)p[4]) << (shift + 32);-    case 4: val |= ((u64)p[3]) << (shift + 24);-    case 3: val |= ((u64)p[2]) << (shift + 16);-    case 2: val |= ((u64)p[1]) << (shift + 8);-    case 1: val |= ((u64)p[0]) << shift;-    }-    return val;-}--static inline u64 _siphash(int c, int d, u64 k0, u64 k1,-			   const u8 *str, size_t len)-{-    u64 v0 = 0x736f6d6570736575ull ^ k0;-    u64 v1 = 0x646f72616e646f6dull ^ k1;-    u64 v2 = 0x6c7967656e657261ull ^ k0;-    u64 v3 = 0x7465646279746573ull ^ k1;-    const u8 *end, *p;-    u64 b;-    int i;--    for (p = str, end = str + (len & ~7); p < end; p += 8) {-	u64 m = peek_u64le((u64 *) p);-	v3 ^= m;-	if (c == 2) {-	    SIPROUND;-	    SIPROUND;-	} else {-	    for (i = 0; i < c; i++)-		SIPROUND;-	}-	v0 ^= m;-    }--    b = odd_read(p, len & 7, ((u64) len) << 56, 0);--    v3 ^= b;-    if (c == 2) {-	SIPROUND;-	SIPROUND;-    } else {-	for (i = 0; i < c; i++)-	    SIPROUND;-    }-    v0 ^= b;--    v2 ^= 0xff;-    if (d == 4) {-	SIPROUND;-	SIPROUND;-	SIPROUND;-	SIPROUND;-    } else {-	for (i = 0; i < d; i++)-	    SIPROUND;-    }-    b = v0 ^ v1 ^ v2  ^ v3;-    return b;-}---static inline u64 _siphash24(u64 k0, u64 k1, const u8 *str, size_t len)-{-    return _siphash(2, 4, k0, k1, str, len);-}--#if defined(__i386)-# undef _siphash24--static u64 (*_siphash24)(u64 k0, u64 k1, const u8 *, size_t);--static void maybe_use_sse()-    __attribute__((constructor));--static void maybe_use_sse()-{-    uint32_t eax = 1, ebx, ecx, edx;--    __asm volatile-	("mov %%ebx, %%edi;" /* 32bit PIC: don't clobber ebx */-	 "cpuid;"-	 "mov %%ebx, %%esi;"-	 "mov %%edi, %%ebx;"-	 :"+a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx)-	 : :"edi");--#if defined(HAVE_SSE2)-    if (edx & (1 << 26))-	_siphash24 = hashable_siphash24_sse2;-#if defined(HAVE_SSE41)-    else if (ecx & (1 << 19))-	_siphash24 = hashable_siphash24_sse41;-#endif-    else-#endif-	_siphash24 = plain_siphash24;-}--#endif--/* ghci's linker fails to call static initializers. */-static inline void ensure_sse_init()-{-#if defined(__i386)-    if (_siphash24 == NULL)-	maybe_use_sse();-#endif-}--u64 hashable_siphash(int c, int d, u64 k0, u64 k1, const u8 *str, size_t len)-{-    return _siphash(c, d, k0, k1, str, len);-}--u64 hashable_siphash24(u64 k0, u64 k1, const u8 *str, size_t len)-{-    ensure_sse_init();-    return _siphash24(k0, k1, str, len);-}--/* Used for ByteArray#s. We can't treat them like pointers in-   native Haskell, but we can in unsafe FFI calls.- */-u64 hashable_siphash24_offset(u64 k0, u64 k1,-			      const u8 *str, size_t off, size_t len)-{-    ensure_sse_init();-    return _siphash24(k0, k1, str + off, len);-}--static int _siphash_chunk(int c, int d, int buffered, u64 v[5],-			  const u8 *str, size_t len, size_t totallen)-{-    u64 v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3], m, b;-    const u8 *p, *end;-    u64 carry = 0;-    int i;--    if (buffered > 0) {-	int unbuffered = 8 - buffered;-	int tobuffer = unbuffered > len ? len : unbuffered;-	int shift = buffered << 3;--	m = odd_read(str, tobuffer, v[4], shift);-	str += tobuffer;-	buffered += tobuffer;-	len -= tobuffer;--	if (buffered < 8)-	    carry = m;-	else {-	    v3 ^= m;-	    if (c == 2) {-		SIPROUND;-		SIPROUND;-	    } else {-		for (i = 0; i < c; i++)-		    SIPROUND;-	    }-	    v0 ^= m;-	    buffered = 0;-	    m = 0;-	}-    }--    for (p = str, end = str + (len & ~7); p < end; p += 8) {-	m = peek_u64le((u64 *) p);-	v3 ^= m;-	if (c == 2) {-	    SIPROUND;-	    SIPROUND;-	} else {-	    for (i = 0; i < c; i++)-		SIPROUND;-	}-	v0 ^= m;-    }--    b = odd_read(p, len & 7, 0, 0);--    if (totallen == -1) {-	v[0] = v0;-	v[1] = v1;-	v[2] = v2;-	v[3] = v3;-	v[4] = b | carry;--	return buffered + (len & 7);-    }--    b |= ((u64) totallen) << 56;--    v3 ^= b;-    if (c == 2) {-	SIPROUND;-	SIPROUND;-    } else {-	for (i = 0; i < c; i++)-	    SIPROUND;-    }-    v0 ^= b;--    v2 ^= 0xff;-    if (d == 4) {-	SIPROUND;-	SIPROUND;-	SIPROUND;-	SIPROUND;-    } else {-	for (i = 0; i < d; i++)-	    SIPROUND;-    }-    v[4] = v0 ^ v1 ^ v2  ^ v3;-    return 0;-}--void hashable_siphash_init(u64 k0, u64 k1, u64 *v)-{-    v[0] = 0x736f6d6570736575ull ^ k0;-    v[1] = 0x646f72616e646f6dull ^ k1;-    v[2] = 0x6c7967656e657261ull ^ k0;-    v[3] = 0x7465646279746573ull ^ k1;-    v[4] = 0;-}--int hashable_siphash24_chunk(int buffered, u64 v[5], const u8 *str,-			     size_t len, size_t totallen)-{-    return _siphash_chunk(2, 4, buffered, v, str, len, totallen);-}--/*- * Used for ByteArray#.- */-int hashable_siphash24_chunk_offset(int buffered, u64 v[5], const u8 *str,-				    size_t off, size_t len, size_t totallen)-{-    return _siphash_chunk(2, 4, buffered, v, str + off, len, totallen);-}
− cbits/siphash.h
@@ -1,67 +0,0 @@-#ifndef _hashable_siphash_h-#define _hashable_siphash_h--#include <stdint.h>--typedef uint64_t u64;-typedef uint32_t u32;-typedef uint16_t u16;-typedef uint8_t u8;--#define SIPHASH_ROUNDS 2-#define SIPHASH_FINALROUNDS 4--u64 hashable_siphash(int, int, u64, u64, const u8 *, size_t);-u64 hashable_siphash24(u64, u64, const u8 *, size_t);--#if defined(__i386)--/* To use SSE instructions, we have to adjust the stack from its-   default of 4-byte alignment to use 16-byte alignment. */--# define ALIGNED_STACK __attribute__((force_align_arg_pointer))--u64 hashable_siphash24_sse2(u64, u64, const u8 *, size_t) ALIGNED_STACK;-u64 hashable_siphash24_sse41(u64, u64, const u8 *, size_t) ALIGNED_STACK;-#endif--#if defined(_WIN32)-# define __LITTLE_ENDIAN 1234-# define __BIG_ENDIAN 4321-# define __BYTE_ORDER __LITTLE_ENDIAN--#elif (defined(__FreeBSD__) && __FreeBSD_version >= 470000) || defined(__OpenBSD__) || defined(__NetBSD__)-# include <sys/endian.h>-# define __BIG_ENDIAN BIG_ENDIAN-# define __LITTLE_ENDIAN LITTLE_ENDIAN-# define __BYTE_ORDER BYTE_ORDER--#elif (defined(BSD) && (BSD >= 199103)) || defined(__APPLE__)-# include <machine/endian.h>-# define __BIG_ENDIAN BIG_ENDIAN-# define __LITTLE_ENDIAN LITTLE_ENDIAN-# define __BYTE_ORDER BYTE_ORDER--#elif defined(__linux__)-# include <endian.h>-#endif--static inline u64 peek_u64le(const u64 *p)-{-    u64 x = *p;--#if __BYTE_ORDER == __BIG_ENDIAN-    x = ((x & 0xff00000000000000ull) >> 56) |-	((x & 0x00ff000000000000ull) >> 40) |-	((x & 0x0000ff0000000000ull) >> 24) |-	((x & 0x000000ff00000000ull) >> 8) |-	((x & 0x00000000ff000000ull) << 8) |-	((x & 0x0000000000ff0000ull) << 24) |-	((x & 0x000000000000ff00ull) << 40) |-	((x & 0x00000000000000ffull) << 56);-#endif--    return x;-}--#endif /* _hashable_siphash_h */
hashable.cabal view
@@ -1,5 +1,5 @@ Name:                hashable-Version:             1.2.0.8+Version:             1.2.0.9 Synopsis:            A class for types that can be converted to a hash value Description:         This package defines a class, 'Hashable', for types that                      can be converted to a hash value.  This class@@ -20,8 +20,7 @@ -- tests/Properties.hs shouldn't have to go here, but the source files -- for the test-suite stanzas don't get picked up by `cabal sdist`. Extra-source-files:-  CHANGES, README.md, tests/Properties.hs, benchmarks/Benchmarks.hs,-  cbits/siphash.h+  CHANGES, README.md, tests/Properties.hs, benchmarks/Benchmarks.hs  Flag integer-gmp   Description: Are we using integer-gmp to provide fast Integer instances?@@ -55,15 +54,7 @@     Other-modules:   Data.Hashable.Generic    C-sources:-                     cbits/inthash.c-                     cbits/siphash.c-  if arch(i386) && flag(sse2)-    CPP-Options:   -DHAVE_SSE2-    C-sources:       cbits/siphash-sse2.c--    if flag(sse41)-      CPP-Options:   -DHAVE_SSE41-      C-sources:     cbits/siphash-sse41.c+                     cbits/fnv.c    Ghc-options:       -Wall   if impl(ghc >= 6.8)@@ -129,20 +120,20 @@     Build-depends:   integer-gmp >= 0.2    c-sources:-    cbits/inthash.c-    cbits/siphash.c-    benchmarks/cbits/fnv.c     benchmarks/cbits/inthash.c+    benchmarks/cbits/siphash.c+    benchmarks/cbits/wang.c+    cbits/fnv.c    if (arch(i386) || arch(x86_64)) && flag(sse2)     cpp-options: -DHAVE_SSE2     c-sources:-      cbits/siphash-sse2.c+      benchmarks/cbits/siphash-sse2.c      if flag(sse41)       cpp-options: -DHAVE_SSE41       c-sources:-        cbits/siphash-sse41.c+        benchmarks/cbits/siphash-sse41.c    Ghc-options:       -Wall -O2   if impl(ghc >= 6.8)