xxhash-ffi (empty) → 0.1.0.0
raw patch · 8 files changed
+1284/−0 lines, 8 filesdep +QuickCheckdep +basedep +bytestringsetup-changed
Dependencies added: QuickCheck, base, bytestring, criterion, deepseq, digest, hashable, hspec, murmur-hash, xxhash, xxhash-ffi
Files
- LICENSE +30/−0
- README.md +9/−0
- Setup.hs +2/−0
- bench/Bench.hs +54/−0
- src-c/xxhash.c +888/−0
- src/Data/Digest/XXHash/FFI.hs +180/−0
- test/Spec.hs +64/−0
- xxhash-ffi.cabal +57/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Henri Verroken (c) 2017++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 Henri Verroken 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.
+ README.md view
@@ -0,0 +1,9 @@+xxhash-ffi+==========++[](https://travis-ci.org/haskell-haskey/xxhash-ffi)+[](https://hackage.haskell.org/package/xxhash-ffi)+[](http://stackage.org/nightly/package/xxhash-ffi)+[](http://stackage.org/lts/package/xxhash-ffi)++Fastest Haskell FFI bindings to the xxHash library. The C implementation is directly taken from [xxHash](https://github.com/Cyan4973/xxHash).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bench/Bench.hs view
@@ -0,0 +1,54 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Main where++import Prelude hiding (words)++import qualified Data.ByteString as B+import qualified Data.Digest.Adler32 as Adler32+import qualified Data.Digest.CRC32 as CRC32+import qualified Data.Digest.XXHash as XXHash+import qualified Data.Digest.XXHash.FFI as FFI+import qualified Data.Hashable as Hashable++import Criterion.Main++main :: IO ()+main = do+ -- apt-get install wamerican+ med <- B.readFile "/usr/share/dict/words"++ defaultMain+ [ bgroup "1MB"+ [ bench "Data.Digest.XXHash.FFI (32) (c)" $ nf (FFI.xxh32 med) 0+ , bench "Data.Digest.XXHash.FFI (64) (c)" $ nf (FFI.xxh64 med) 0+ , bench "xxhash (c)" $ nf XXHash.c_xxHash' med+ , bench "Data.Digest.XXHash (haskell)" $ nf XXHash.xxHash' med+ , bench "Data.Digest.adler32 (c, zlib)" $ nf Adler32.adler32 med+ , bench "Data.Digest.crc32 (c, zlib)" $ nf CRC32.crc32 med+ , bench "Data.Hashable (c, FNV?)" $ nf Hashable.hash med+ ]+ , bgroup "1kB"+ [ bench "Data.Digest.XXHash.FFI (32) (c)" $ nf (FFI.xxh32 bs1k) 0+ , bench "Data.Digest.XXHash.FFI (64) (c)" $ nf (FFI.xxh64 bs1k) 0+ , bench "xxhash (c)" $ nf XXHash.c_xxHash' bs1k+ , bench "Data.Digest.XXHash (haskell)" $ nf XXHash.xxHash' bs1k+ , bench "Data.Digest.adler32 (c, zlib)" $ nf Adler32.adler32 bs1k+ , bench "Data.Digest.crc32 (c, zlib)" $ nf CRC32.crc32 bs1k+ , bench "Data.Hashable (c, FNV?)" $ nf Hashable.hash bs1k+ ]+ , bgroup "4kB"+ [ bench "Data.Digest.XXHash.FFI (32) (c)" $ nf (FFI.xxh32 bs4k) 0+ , bench "Data.Digest.XXHash.FFI (64) (c)" $ nf (FFI.xxh64 bs4k) 0+ , bench "xxhash (c)" $ nf XXHash.c_xxHash' bs4k+ , bench "Data.Digest.XXHash (haskell)" $ nf XXHash.xxHash' bs4k+ , bench "Data.Digest.adler32 (c, zlib)" $ nf Adler32.adler32 bs4k+ , bench "Data.Digest.crc32 (c, zlib)" $ nf CRC32.crc32 bs4k+ , bench "Data.Hashable (c, FNV?)" $ nf Hashable.hash bs4k+ ]+ ]++bs1k :: B.ByteString+bs1k = fst $ B.unfoldrN 1024 (\x -> Just (x, x)) 0++bs4k :: B.ByteString+bs4k = fst $ B.unfoldrN 4096 (\x -> Just (x, x)) 0
+ src-c/xxhash.c view
@@ -0,0 +1,888 @@+/*+* xxHash - Fast Hash algorithm+* Copyright (C) 2012-2016, Yann Collet+*+* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)+*+* 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.+*+* 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.+*+* You can contact the author at :+* - xxHash homepage: http://www.xxhash.com+* - xxHash source repository : https://github.com/Cyan4973/xxHash+*/+++/* *************************************+* Tuning parameters+***************************************/+/*!XXH_FORCE_MEMORY_ACCESS :+ * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.+ * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.+ * The below switch allow to select different access method for improved performance.+ * Method 0 (default) : use `memcpy()`. Safe and portable.+ * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).+ * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.+ * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.+ * It can generate buggy code on targets which do not support unaligned memory accesses.+ * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)+ * See http://stackoverflow.com/a/32095106/646947 for details.+ * Prefer these methods in priority order (0 > 1 > 2)+ */+#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */+# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )+# define XXH_FORCE_MEMORY_ACCESS 2+# elif defined(__INTEL_COMPILER) || \+ (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))+# define XXH_FORCE_MEMORY_ACCESS 1+# endif+#endif++/*!XXH_ACCEPT_NULL_INPUT_POINTER :+ * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.+ * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.+ * By default, this option is disabled. To enable it, uncomment below define :+ */+/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */++/*!XXH_FORCE_NATIVE_FORMAT :+ * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.+ * Results are therefore identical for little-endian and big-endian CPU.+ * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.+ * Should endian-independence be of no importance for your application, you may set the #define below to 1,+ * to improve speed for Big-endian CPU.+ * This option has no impact on Little_Endian CPU.+ */+#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */+# define XXH_FORCE_NATIVE_FORMAT 0+#endif++/*!XXH_FORCE_ALIGN_CHECK :+ * This is a minor performance trick, only useful with lots of very small keys.+ * It means : check for aligned/unaligned input.+ * The check costs one initial branch per hash;+ * set it to 0 when the input is guaranteed to be aligned,+ * or when alignment doesn't matter for performance.+ */+#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */+# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)+# define XXH_FORCE_ALIGN_CHECK 0+# else+# define XXH_FORCE_ALIGN_CHECK 1+# endif+#endif+++/* *************************************+* Includes & Memory related functions+***************************************/+/*! Modify the local functions below should you wish to use some other memory routines+* for malloc(), free() */+#include <stdlib.h>+static void* XXH_malloc(size_t s) { return malloc(s); }+static void XXH_free (void* p) { free(p); }+/*! and for memcpy() */+#include <string.h>+static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }++#define XXH_STATIC_LINKING_ONLY+#include "xxhash.h"+++/* *************************************+* Compiler Specific Options+***************************************/+#ifdef _MSC_VER /* Visual Studio */+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */+# define FORCE_INLINE static __forceinline+#else+# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */+# ifdef __GNUC__+# define FORCE_INLINE static inline __attribute__((always_inline))+# else+# define FORCE_INLINE static inline+# endif+# else+# define FORCE_INLINE static+# endif /* __STDC_VERSION__ */+#endif+++/* *************************************+* Basic Types+***************************************/+#ifndef MEM_MODULE+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+# include <stdint.h>+ typedef uint8_t BYTE;+ typedef uint16_t U16;+ typedef uint32_t U32;+# else+ typedef unsigned char BYTE;+ typedef unsigned short U16;+ typedef unsigned int U32;+# endif+#endif++#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))++/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */+static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }++#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+typedef union { U32 u32; } __attribute__((packed)) unalign;+static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }++#else++/* portable and safe solution. Generally efficient.+ * see : http://stackoverflow.com/a/32095106/646947+ */+static U32 XXH_read32(const void* memPtr)+{+ U32 val;+ memcpy(&val, memPtr, sizeof(val));+ return val;+}++#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */+++/* ****************************************+* Compiler-specific Functions and Macros+******************************************/+#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)++/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */+#if defined(_MSC_VER)+# define XXH_rotl32(x,r) _rotl(x,r)+# define XXH_rotl64(x,r) _rotl64(x,r)+#else+# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))+# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))+#endif++#if defined(_MSC_VER) /* Visual Studio */+# define XXH_swap32 _byteswap_ulong+#elif XXH_GCC_VERSION >= 403+# define XXH_swap32 __builtin_bswap32+#else+static U32 XXH_swap32 (U32 x)+{+ return ((x << 24) & 0xff000000 ) |+ ((x << 8) & 0x00ff0000 ) |+ ((x >> 8) & 0x0000ff00 ) |+ ((x >> 24) & 0x000000ff );+}+#endif+++/* *************************************+* Architecture Macros+***************************************/+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;++/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */+#ifndef XXH_CPU_LITTLE_ENDIAN+ static const int g_one = 1;+# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))+#endif+++/* ***************************+* Memory reads+*****************************/+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;++FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+ if (align==XXH_unaligned)+ return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));+ else+ return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);+}++FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)+{+ return XXH_readLE32_align(ptr, endian, XXH_unaligned);+}++static U32 XXH_readBE32(const void* ptr)+{+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);+}+++/* *************************************+* Macros+***************************************/+#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */+XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }+++/* *******************************************************************+* 32-bits hash functions+*********************************************************************/+static const U32 PRIME32_1 = 2654435761U;+static const U32 PRIME32_2 = 2246822519U;+static const U32 PRIME32_3 = 3266489917U;+static const U32 PRIME32_4 = 668265263U;+static const U32 PRIME32_5 = 374761393U;++static U32 XXH32_round(U32 seed, U32 input)+{+ seed += input * PRIME32_2;+ seed = XXH_rotl32(seed, 13);+ seed *= PRIME32_1;+ return seed;+}++FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)+{+ const BYTE* p = (const BYTE*)input;+ const BYTE* bEnd = p + len;+ U32 h32;+#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+ if (p==NULL) {+ len=0;+ bEnd=p=(const BYTE*)(size_t)16;+ }+#endif++ if (len>=16) {+ const BYTE* const limit = bEnd - 16;+ U32 v1 = seed + PRIME32_1 + PRIME32_2;+ U32 v2 = seed + PRIME32_2;+ U32 v3 = seed + 0;+ U32 v4 = seed - PRIME32_1;++ do {+ v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;+ v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;+ v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;+ v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;+ } while (p<=limit);++ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);+ } else {+ h32 = seed + PRIME32_5;+ }++ h32 += (U32) len;++ while (p+4<=bEnd) {+ h32 += XXH_get32bits(p) * PRIME32_3;+ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;+ p+=4;+ }++ while (p<bEnd) {+ h32 += (*p) * PRIME32_5;+ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;+ p++;+ }++ h32 ^= h32 >> 15;+ h32 *= PRIME32_2;+ h32 ^= h32 >> 13;+ h32 *= PRIME32_3;+ h32 ^= h32 >> 16;++ return h32;+}+++XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)+{+#if 0+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+ XXH32_state_t state;+ XXH32_reset(&state, seed);+ XXH32_update(&state, input, len);+ return XXH32_digest(&state);+#else+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if (XXH_FORCE_ALIGN_CHECK) {+ if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+ else+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+ } }++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+ else+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}++++/*====== Hash streaming ======*/++XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)+{+ return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)+{+ XXH_free(statePtr);+ return XXH_OK;+}++XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)+{+ memcpy(dstState, srcState, sizeof(*dstState));+}++XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)+{+ XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+ memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */+ state.v1 = seed + PRIME32_1 + PRIME32_2;+ state.v2 = seed + PRIME32_2;+ state.v3 = seed + 0;+ state.v4 = seed - PRIME32_1;+ memcpy(statePtr, &state, sizeof(state));+ return XXH_OK;+}+++FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+ const BYTE* p = (const BYTE*)input;+ const BYTE* const bEnd = p + len;++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+ if (input==NULL) return XXH_ERROR;+#endif++ state->total_len_32 += (unsigned)len;+ state->large_len |= (len>=16) | (state->total_len_32>=16);++ if (state->memsize + len < 16) { /* fill in tmp buffer */+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);+ state->memsize += (unsigned)len;+ return XXH_OK;+ }++ if (state->memsize) { /* some data left from previous update */+ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);+ { const U32* p32 = state->mem32;+ state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;+ state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;+ state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;+ state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));+ }+ p += 16-state->memsize;+ state->memsize = 0;+ }++ if (p <= bEnd-16) {+ const BYTE* const limit = bEnd - 16;+ U32 v1 = state->v1;+ U32 v2 = state->v2;+ U32 v3 = state->v3;+ U32 v4 = state->v4;++ do {+ v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;+ v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;+ v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;+ v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;+ } while (p<=limit);++ state->v1 = v1;+ state->v2 = v2;+ state->v3 = v3;+ state->v4 = v4;+ }++ if (p < bEnd) {+ XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));+ state->memsize = (unsigned)(bEnd-p);+ }++ return XXH_OK;+}++XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)+{+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH32_update_endian(state_in, input, len, XXH_littleEndian);+ else+ return XXH32_update_endian(state_in, input, len, XXH_bigEndian);+}++++FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)+{+ const BYTE * p = (const BYTE*)state->mem32;+ const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;+ U32 h32;++ if (state->large_len) {+ h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);+ } else {+ h32 = state->v3 /* == seed */ + PRIME32_5;+ }++ h32 += state->total_len_32;++ while (p+4<=bEnd) {+ h32 += XXH_readLE32(p, endian) * PRIME32_3;+ h32 = XXH_rotl32(h32, 17) * PRIME32_4;+ p+=4;+ }++ while (p<bEnd) {+ h32 += (*p) * PRIME32_5;+ h32 = XXH_rotl32(h32, 11) * PRIME32_1;+ p++;+ }++ h32 ^= h32 >> 15;+ h32 *= PRIME32_2;+ h32 ^= h32 >> 13;+ h32 *= PRIME32_3;+ h32 ^= h32 >> 16;++ return h32;+}+++XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)+{+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH32_digest_endian(state_in, XXH_littleEndian);+ else+ return XXH32_digest_endian(state_in, XXH_bigEndian);+}+++/*====== Canonical representation ======*/++/*! Default XXH result types are basic unsigned 32 and 64 bits.+* The canonical representation follows human-readable write convention, aka big-endian (large digits first).+* These functions allow transformation of hash result into and from its canonical format.+* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.+*/++XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)+{+ XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);+ memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)+{+ return XXH_readBE32(src);+}+++#ifndef XXH_NO_LONG_LONG++/* *******************************************************************+* 64-bits hash functions+*********************************************************************/++/*====== Memory access ======*/++#ifndef MEM_MODULE+# define MEM_MODULE+# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )+# include <stdint.h>+ typedef uint64_t U64;+# else+ typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */+# endif+#endif+++#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))++/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */+static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }++#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))++/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */+/* currently only defined for gcc and icc */+typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;+static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }++#else++/* portable and safe solution. Generally efficient.+ * see : http://stackoverflow.com/a/32095106/646947+ */++static U64 XXH_read64(const void* memPtr)+{+ U64 val;+ memcpy(&val, memPtr, sizeof(val));+ return val;+}++#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */++#if defined(_MSC_VER) /* Visual Studio */+# define XXH_swap64 _byteswap_uint64+#elif XXH_GCC_VERSION >= 403+# define XXH_swap64 __builtin_bswap64+#else+static U64 XXH_swap64 (U64 x)+{+ return ((x << 56) & 0xff00000000000000ULL) |+ ((x << 40) & 0x00ff000000000000ULL) |+ ((x << 24) & 0x0000ff0000000000ULL) |+ ((x << 8) & 0x000000ff00000000ULL) |+ ((x >> 8) & 0x00000000ff000000ULL) |+ ((x >> 24) & 0x0000000000ff0000ULL) |+ ((x >> 40) & 0x000000000000ff00ULL) |+ ((x >> 56) & 0x00000000000000ffULL);+}+#endif++FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)+{+ if (align==XXH_unaligned)+ return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));+ else+ return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);+}++FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)+{+ return XXH_readLE64_align(ptr, endian, XXH_unaligned);+}++static U64 XXH_readBE64(const void* ptr)+{+ return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);+}+++/*====== xxh64 ======*/++static const U64 PRIME64_1 = 11400714785074694791ULL;+static const U64 PRIME64_2 = 14029467366897019727ULL;+static const U64 PRIME64_3 = 1609587929392839161ULL;+static const U64 PRIME64_4 = 9650029242287828579ULL;+static const U64 PRIME64_5 = 2870177450012600261ULL;++static U64 XXH64_round(U64 acc, U64 input)+{+ acc += input * PRIME64_2;+ acc = XXH_rotl64(acc, 31);+ acc *= PRIME64_1;+ return acc;+}++static U64 XXH64_mergeRound(U64 acc, U64 val)+{+ val = XXH64_round(0, val);+ acc ^= val;+ acc = acc * PRIME64_1 + PRIME64_4;+ return acc;+}++FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)+{+ const BYTE* p = (const BYTE*)input;+ const BYTE* bEnd = p + len;+ U64 h64;+#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+ if (p==NULL) {+ len=0;+ bEnd=p=(const BYTE*)(size_t)32;+ }+#endif++ if (len>=32) {+ const BYTE* const limit = bEnd - 32;+ U64 v1 = seed + PRIME64_1 + PRIME64_2;+ U64 v2 = seed + PRIME64_2;+ U64 v3 = seed + 0;+ U64 v4 = seed - PRIME64_1;++ do {+ v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;+ v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;+ v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;+ v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;+ } while (p<=limit);++ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+ h64 = XXH64_mergeRound(h64, v1);+ h64 = XXH64_mergeRound(h64, v2);+ h64 = XXH64_mergeRound(h64, v3);+ h64 = XXH64_mergeRound(h64, v4);++ } else {+ h64 = seed + PRIME64_5;+ }++ h64 += (U64) len;++ while (p+8<=bEnd) {+ U64 const k1 = XXH64_round(0, XXH_get64bits(p));+ h64 ^= k1;+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;+ p+=8;+ }++ if (p+4<=bEnd) {+ h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;+ p+=4;+ }++ while (p<bEnd) {+ h64 ^= (*p) * PRIME64_5;+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;+ p++;+ }++ h64 ^= h64 >> 33;+ h64 *= PRIME64_2;+ h64 ^= h64 >> 29;+ h64 *= PRIME64_3;+ h64 ^= h64 >> 32;++ return h64;+}+++XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)+{+#if 0+ /* Simple version, good for code maintenance, but unfortunately slow for small inputs */+ XXH64_state_t state;+ XXH64_reset(&state, seed);+ XXH64_update(&state, input, len);+ return XXH64_digest(&state);+#else+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if (XXH_FORCE_ALIGN_CHECK) {+ if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);+ else+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);+ } }++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);+ else+ return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);+#endif+}++/*====== Hash Streaming ======*/++XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)+{+ return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));+}+XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)+{+ XXH_free(statePtr);+ return XXH_OK;+}++XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)+{+ memcpy(dstState, srcState, sizeof(*dstState));+}++XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)+{+ XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */+ memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */+ state.v1 = seed + PRIME64_1 + PRIME64_2;+ state.v2 = seed + PRIME64_2;+ state.v3 = seed + 0;+ state.v4 = seed - PRIME64_1;+ memcpy(statePtr, &state, sizeof(state));+ return XXH_OK;+}++FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)+{+ const BYTE* p = (const BYTE*)input;+ const BYTE* const bEnd = p + len;++#ifdef XXH_ACCEPT_NULL_INPUT_POINTER+ if (input==NULL) return XXH_ERROR;+#endif++ state->total_len += len;++ if (state->memsize + len < 32) { /* fill in tmp buffer */+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);+ state->memsize += (U32)len;+ return XXH_OK;+ }++ if (state->memsize) { /* tmp buffer is full */+ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);+ state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));+ state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));+ state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));+ state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));+ p += 32-state->memsize;+ state->memsize = 0;+ }++ if (p+32 <= bEnd) {+ const BYTE* const limit = bEnd - 32;+ U64 v1 = state->v1;+ U64 v2 = state->v2;+ U64 v3 = state->v3;+ U64 v4 = state->v4;++ do {+ v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;+ v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;+ v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;+ v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;+ } while (p<=limit);++ state->v1 = v1;+ state->v2 = v2;+ state->v3 = v3;+ state->v4 = v4;+ }++ if (p < bEnd) {+ XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));+ state->memsize = (unsigned)(bEnd-p);+ }++ return XXH_OK;+}++XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)+{+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH64_update_endian(state_in, input, len, XXH_littleEndian);+ else+ return XXH64_update_endian(state_in, input, len, XXH_bigEndian);+}++FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)+{+ const BYTE * p = (const BYTE*)state->mem64;+ const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;+ U64 h64;++ if (state->total_len >= 32) {+ U64 const v1 = state->v1;+ U64 const v2 = state->v2;+ U64 const v3 = state->v3;+ U64 const v4 = state->v4;++ h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);+ h64 = XXH64_mergeRound(h64, v1);+ h64 = XXH64_mergeRound(h64, v2);+ h64 = XXH64_mergeRound(h64, v3);+ h64 = XXH64_mergeRound(h64, v4);+ } else {+ h64 = state->v3 + PRIME64_5;+ }++ h64 += (U64) state->total_len;++ while (p+8<=bEnd) {+ U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));+ h64 ^= k1;+ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;+ p+=8;+ }++ if (p+4<=bEnd) {+ h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;+ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;+ p+=4;+ }++ while (p<bEnd) {+ h64 ^= (*p) * PRIME64_5;+ h64 = XXH_rotl64(h64, 11) * PRIME64_1;+ p++;+ }++ h64 ^= h64 >> 33;+ h64 *= PRIME64_2;+ h64 ^= h64 >> 29;+ h64 *= PRIME64_3;+ h64 ^= h64 >> 32;++ return h64;+}++XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)+{+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;++ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)+ return XXH64_digest_endian(state_in, XXH_littleEndian);+ else+ return XXH64_digest_endian(state_in, XXH_bigEndian);+}+++/*====== Canonical representation ======*/++XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)+{+ XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));+ if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);+ memcpy(dst, &hash, sizeof(*dst));+}++XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)+{+ return XXH_readBE64(src);+}++#endif /* XXH_NO_LONG_LONG */
+ src/Data/Digest/XXHash/FFI.hs view
@@ -0,0 +1,180 @@+{-# LANGUAGE ForeignFunctionInterface #-}+-- |+-- Module: Data.Digest.XXHash.FFI+-- Copyright: (c) 2017 Henri Verroken+-- Licence: BSD3+-- Maintainer: Henri Verroken <henriverroken@gmail.com+-- Stability: stable+--+-- This module provides bindings to the xxHash64 and the xxHash32 algorithm.+--+-- The C implementation used is directly taken from <https://github.com/Cyan4973/xxHash>.+module Data.Digest.XXHash.FFI (+ -- * Interface+ XXHash(..)++ -- * C Interface+ -- ** Direct Calculation+, c_xxh64+, c_xxh32++ -- ** 32-bit state functions+, XXH32State+, c_xxh32_createState+, c_xxh32_freeState+, c_xxh32_copyState+, c_xxh32_reset+, c_xxh32_update+, c_xxh32_digest++ -- ** 64-bit state functions+, XXH64State+, c_xxh64_createState+, c_xxh64_freeState+, c_xxh64_copyState+, c_xxh64_reset+, c_xxh64_update+, c_xxh64_digest+) where++import Control.Exception (bracket)++import Data.ByteString.Unsafe (unsafeUseAsCString)+import Data.Word (Word32, Word64)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as BL++import Foreign.C+import Foreign.Ptr++import System.IO.Unsafe (unsafePerformIO)++foreign import ccall unsafe "XXH64" c_xxh64 ::+ Ptr a -- ^ 'Ptr' to the input buffer+ -> CSize -- ^ Buffer length+ -> CULLong -- ^ Seed+ -> CULLong -- ^ Resulting hash++foreign import ccall unsafe "XXH32" c_xxh32 ::+ Ptr a -- ^ 'Ptr' to the input buffer+ -> CSize -- ^ Buffer length+ -> CUInt -- ^ Seed+ -> CUInt -- ^ Resulting hash++data XXH32State++foreign import ccall unsafe "XXH32_createState" c_xxh32_createState ::+ IO (Ptr XXH32State) -- ^ Pointer to a newly allocated state++foreign import ccall unsafe "XXH32_freeState" c_xxh32_freeState ::+ Ptr XXH32State+ -> IO () -- ^ Free pointer allocated by 'c_xxh32_createState'++foreign import ccall unsafe "XXH32_copyState" c_xxh32_copyState ::+ Ptr XXH32State -- ^ Destination+ -> Ptr XXH32State -- ^ Source+ -> IO ()++foreign import ccall unsafe "XXH32_reset" c_xxh32_reset ::+ Ptr XXH32State -- ^ The state to reset+ -> CUInt -- ^ The initial seed+ -> IO ()++foreign import ccall unsafe "XXH32_update" c_xxh32_update ::+ Ptr XXH32State -- ^ The state to update+ -> Ptr a -- ^ 'Ptr' to the input buffer+ -> CSize -- ^ Buffer length+ -> IO ()++foreign import ccall unsafe "XXH32_digest" c_xxh32_digest ::+ Ptr XXH32State -- ^ The state to digest+ -> IO CUInt -- ^ Resulting hash++data XXH64State++foreign import ccall unsafe "XXH64_createState" c_xxh64_createState ::+ IO (Ptr XXH64State) -- ^ Pointer to a newly allocated state++foreign import ccall unsafe "XXH64_freeState" c_xxh64_freeState ::+ Ptr XXH64State+ -> IO () -- ^ Free pointer allocated by 'c_xxh64_createState'++foreign import ccall unsafe "XXH64_copyState" c_xxh64_copyState ::+ Ptr XXH64State -- ^ Destination+ -> Ptr XXH64State -- ^ Source+ -> IO ()++foreign import ccall unsafe "XXH64_reset" c_xxh64_reset ::+ Ptr XXH64State -- ^ The state to reset+ -> CULLong -- ^ The initial seed+ -> IO ()++foreign import ccall unsafe "XXH64_update" c_xxh64_update ::+ Ptr XXH64State -- ^ The state to update+ -> Ptr a -- ^ 'Ptr' to the input buffer+ -> CSize -- ^ Buffer length+ -> IO ()++foreign import ccall unsafe "XXH64_digest" c_xxh64_digest ::+ Ptr XXH64State -- ^ The state to digest+ -> IO CULLong -- ^ Resulting hash++-- | Class for hashable data types.+--+-- Not that all standard instances are specialized using the @SPECIALIZE@+-- pragma.+class XXHash t where+ -- | Calculate the 32-bit xxHash using a given seed.+ xxh32 :: t -- ^ Data to hash+ -> Word32 -- ^ Seed+ -> Word32 -- ^ Resulting hash++ -- | Calculate the 64-bit xxHash using a given seed.+ xxh64 :: t -- ^ Data to hash+ -> Word64 -- ^ Seed+ -> Word64 -- ^ Resulting hash+++instance XXHash BS.ByteString where+ xxh32 bs seed = unsafePerformIO $+ unsafeUseAsCString bs $ \ptr ->+ return . fromIntegral $ c_xxh32 (castPtr ptr) len (fromIntegral seed)+ where+ len = fromIntegral $ BS.length bs++ xxh64 bs seed = unsafePerformIO $+ unsafeUseAsCString bs $ \ptr ->+ return . fromIntegral $ c_xxh64 (castPtr ptr) len (fromIntegral seed)+ where+ len = fromIntegral $ BS.length bs++{-# SPECIALIZE xxh32 :: BS.ByteString -> Word32 -> Word32 #-}+{-# SPECIALIZE xxh64 :: BS.ByteString -> Word64 -> Word64 #-}++instance XXHash BL.ByteString where+ xxh32 bs seed = fromIntegral . unsafePerformIO $+ bracket c_xxh32_createState+ c_xxh32_freeState $ \state -> do+ c_xxh32_reset state (fromIntegral seed)+ mapM_ (update state) (BL.toChunks bs)+ c_xxh32_digest state+ where+ update state bs' =+ let len = fromIntegral (BS.length bs') in+ unsafeUseAsCString bs' $ \ ptr ->+ c_xxh32_update state ptr len++ xxh64 bs seed = fromIntegral . unsafePerformIO $+ bracket c_xxh64_createState+ c_xxh64_freeState $ \state -> do+ c_xxh64_reset state (fromIntegral seed)+ mapM_ (update state) (BL.toChunks bs)+ c_xxh64_digest state+ where+ update state bs' =+ let len = fromIntegral (BS.length bs') in+ unsafeUseAsCString bs' $ \ ptr ->+ c_xxh64_update state ptr len++{-# SPECIALIZE xxh32 :: BL.ByteString -> Word32 -> Word32 #-}+{-# SPECIALIZE xxh64 :: BL.ByteString -> Word64 -> Word64 #-}
+ test/Spec.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Main where++import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck++import Control.Applicative ((<$>))++import Data.ByteString (ByteString)+import Data.Word (Word32, Word64)+import qualified Data.ByteString.Lazy as BL++import Data.Digest.XXHash.FFI (xxh32, xxh64)++instance Arbitrary BL.ByteString where+ arbitrary = BL.pack <$> arbitrary+ shrink bs = BL.pack <$> shrink (BL.unpack bs)++main :: IO ()+main = hspec suite++suite :: Spec+suite = do+ describe "xxh32 strict" $+ it "hashes known pairs" $ do+ xxh32bs' "" `shouldBe` 0x02cc5d05+ xxh32bs' "Hello World" `shouldBe` 0xb1fd16ee+ xxh32bs' "xxhash is a hashing library" `shouldBe` 0x5e213914++ describe "xxh64 strict" $+ it "hashes known pairs" $ do+ xxh64bs' "" `shouldBe` 0xef46db3751d8e999+ xxh64bs' "Hello World" `shouldBe` 0x6334d20719245bc2+ xxh64bs' "xxhash is a hashing library" `shouldBe` 0xea6cd1701a857e7c++ describe "xxh32 lazy" $+ it "hashes known pairs" $ do+ xxh32bs (BL.fromChunks [""]) `shouldBe` 0x02cc5d05+ xxh32bs (BL.fromChunks ["Hello ", "World"]) `shouldBe` 0xb1fd16ee+ xxh32bs (BL.fromChunks ["xxhash is ", "a hashing ", "library"]) `shouldBe` 0x5e213914++ describe "xxh64 lazy" $+ it "hashes known pairs" $ do+ xxh64bs (BL.fromChunks [""]) `shouldBe` 0xef46db3751d8e999+ xxh64bs (BL.fromChunks ["Hello ", "World"]) `shouldBe` 0x6334d20719245bc2+ xxh64bs (BL.fromChunks ["xxhash is ", "a hashing ", "library"]) `shouldBe` 0xea6cd1701a857e7c+ describe "lazy and strict" $+ prop "hashes lazy and strict" $ \(bs :: BL.ByteString) ->+ xxh64 bs 0 == xxh64 (BL.toStrict bs) 0+++xxh32bs' :: ByteString -> Word32+xxh32bs' = flip xxh32 0++xxh64bs' :: ByteString -> Word64+xxh64bs' = flip xxh64 0++xxh32bs :: BL.ByteString -> Word32+xxh32bs = flip xxh32 0++xxh64bs :: BL.ByteString -> Word64+xxh64bs = flip xxh64 0
+ xxhash-ffi.cabal view
@@ -0,0 +1,57 @@+name: xxhash-ffi+version: 0.1.0.0+synopsis: Bindings to the C implementation the xxHash algorithm+description: Bindings to the C implementation the xxHash algorithm. xxHash provides 32-bit and 64-bit extremely fast non-cryptographic hash functions.+homepage: https://github.com/haskell-haskey/xxhash-ffi#readme+license: BSD3+license-file: LICENSE+author: Henri Verroken+maintainer: henriverroken@gmail.com+copyright: 2017 Henri Verroken+category: Cryptography+build-type: Simple+extra-source-files: README.md+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules: Data.Digest.XXHash.FFI+ build-depends: base >= 4.7 && < 5+ , bytestring+ ghc-options: -Wall+ default-language: Haskell2010+ c-sources: src-c/xxhash.c+ include-dirs: src-c+ includes: xxhash.h++test-suite xxhash-ffi-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ build-depends: base+ , xxhash-ffi+ , QuickCheck+ , bytestring+ , hspec+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ default-language: Haskell2010++benchmark xxhash-ffi-bench+ type: exitcode-stdio-1.0+ hs-source-dirs: bench+ main-is: Bench.hs+ build-depends: base+ , xxhash-ffi+ , bytestring+ , criterion+ , deepseq+ , digest+ , hashable+ , murmur-hash+ , xxhash+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/hverr/xxhash-ffi