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 +5/−9
- Data/Hashable/Class.hs +21/−80
- benchmarks/cbits/fnv.c +0/−53
- benchmarks/cbits/siphash-sse2.c +129/−0
- benchmarks/cbits/siphash-sse41.c +86/−0
- benchmarks/cbits/siphash.c +262/−0
- benchmarks/cbits/wang.c +29/−0
- cbits/fnv.c +53/−0
- cbits/inthash.c +0/−29
- cbits/siphash-sse2.c +0/−129
- cbits/siphash-sse41.c +0/−86
- cbits/siphash.c +0/−262
- cbits/siphash.h +0/−67
- hashable.cabal +8/−17
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)