bloomfilter-blocked 0.1.0.0 → 0.1.0.1
raw patch · 11 files changed
+250/−228 lines, 11 filesdep ~randomPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: random
API changes (from Hackage documentation)
Files
- CHANGELOG.md +6/−0
- NOTICE +1/−0
- README.md +4/−0
- bloomfilter-blocked.cabal +46/−35
- src/Data/BloomFilter/Hash.hs +1/−1
- tests/fpr-calc.hs +6/−6
- xxhash/src/Data/Digest/XXH3.hs +110/−0
- xxhash/src/Data/Digest/XXH3/FFI.hs +75/−0
- xxhash/src/FFI.hs +0/−75
- xxhash/src/XXH3.hs +0/−110
- xxhash/tests/xxhash-tests.hs +1/−1
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for bloomfilter-blocked +## 0.1.0.1 -- 2025-11-25++* PATCH: Change source code repository to a new location.+* PATCH: Update copyright information.+* PATCH: Update the package synopsis and package description.+ ## 0.1.0.0 -- 2025-08-06 * First version. Released on an unsuspecting world.
NOTICE view
@@ -1,4 +1,5 @@ Copyright (c) 2023-2025 Cardano Development Foundation+Copyright (c) 2025 Well-Typed LLP Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
README.md view
@@ -1,5 +1,9 @@ # bloomfilter-blocked +[](https://hackage.haskell.org/package/bloomfilter-blocked)+[](https://github.com/well-typed/bloomfilter-blocked/actions/workflows/ci.yml)+[](https://well-typed.github.io/bloomfilter-blocked/)+ `bloomfilter-blocked` is a Haskell library providing multiple fast and efficient implementations of [bloom filters](https://en.wikipedia.org/wiki/Bloom_filter). It is a full rewrite of the
bloomfilter-blocked.cabal view
@@ -1,35 +1,55 @@ cabal-version: 3.4 name: bloomfilter-blocked-version: 0.1.0.0-synopsis: Classic and block-style bloom filters+version: 0.1.0.1+synopsis: Fast, compact Bloom filters description:- @bloomfilter-blocked@ is a Haskell library providing multiple fast and efficient- implementations of [bloom filters](https://en.wikipedia.org/wiki/Bloom_filter).- It is a full rewrite of the- [bloomfilter](https://hackage.haskell.org/package/bloomfilter) package,- originally authored by Bryan O'Sullivan <bos@serpentine.com>.+ This library provides [Bloom filters](https://en.wikipedia.org/wiki/Bloom_filter).+ A Bloom filter is a compact but probabilistic set-like data structure,+ supporting fast insert and membership operations. - The library includes two implementations of bloom filters: classic, and blocked.+ Bloom filters are probabilistic in the sense that when querying for set+ membership, they can (with some probability) falsely report that an element+ is present when it is not present. On the other hand it will /never/ falsely+ report that an element is not present when in fact it is present. That is, it+ can have false positives but not false negatives. The false positive rate+ (FPR) can be adjusted. - * /Classic/ bloom filters, found in the "Data.BloomFilter.Classic" module: a- default implementation that is faithful to the canonical description of a- bloom filter data structure.+ Bloom filters are compact, needing only a few /bits/ per element. For example+ 10 bits per element is enough for a false positive rate (FPR) of 1%, and 15+ bits for 0.1%. - * /Blocked/ floom filters, found in the "Data.BloomFilter.Blocked" module: an- implementation that optimises the memory layout of a classic bloom filter for- speed (cheaper CPU cache reads), at the cost of a slightly higher FPR for the- same amount of assigned memory.+ The library includes two implementations of Bloom filters: + [classic]: in "Data.BloomFilter.Classic":+ a default implementation that is faithful to the classical description of a+ Bloom filter data structure.++ [block-structured]: in "Data.BloomFilter.Blocked":+ a cache optimised representation that is faster, at the cost of needing a+ few more bits per element to achieve a target FPR.++ Features of the library:++ * Fast. See the benchmark results.+ * Compact. It uses optimal sized bit arrays: no bigger than necessary.+ * Faster still: the block-structured Bloom filters are even faster, at the+ expense of needing more bits per entry.+ * Supports very large Bloom filters, bigger than 2^32 bits.+ * Simple API for specifying the size of Bloom filters.+ * Support for hash salting, for using Bloom filters with untrusted inputs.+ * Serialisation support with format version tracking.+ license: Apache-2.0 license-files: LICENSE NOTICE -author:- Duncan Coutts, Joris Dral, Matthias Heinzel, Wolfgang Jeltsch, Wen Kokke, and Alex Washburn-+author: Duncan Coutts, Joris Dral, Matthias Heinzel, Wen Kokke maintainer: duncan@well-typed.com, joris@well-typed.com-copyright: (c) 2023-2025 Cardano Development Foundation+copyright:+ (c) 2023-2025 Cardano Development Foundation+ (c) 2025 Well-Typed LLP+ category: Data build-type: Simple tested-with:@@ -47,14 +67,12 @@ source-repository head type: git- location: https://github.com/IntersectMBO/lsm-tree- subdir: bloomfilter-blocked+ location: https://github.com/well-typed/bloomfilter-blocked source-repository this type: git- location: https://github.com/IntersectMBO/lsm-tree- subdir: bloomfilter-blocked- tag: bloomfilter-blocked-0.1.0.0+ location: https://github.com/well-typed/bloomfilter-blocked+ tag: bloomfilter-blocked-0.1.0.1 common warnings ghc-options:@@ -68,15 +86,9 @@ common language default-language: GHC2021 default-extensions:- DeriveAnyClass DerivingStrategies- DerivingVia- ExplicitNamespaces- GADTs- LambdaCase RecordWildCards RoleAnnotations- ViewPatterns library import: language, warnings@@ -142,10 +154,10 @@ , bloomfilter-blocked , containers , parallel- , random+ , random >=1.3 , regression-simple - ghc-options: -threaded+ ghc-options: -threaded -rtsopts -- It's not really a test suite, but if we make it an executable then its -- dependencies will be included for dependency resolution when building the@@ -161,7 +173,6 @@ , bloomfilter-blocked , directory --- this exists due to windows library xxhash import: language, warnings visibility: private@@ -170,14 +181,14 @@ HsXXHash.h xxhash.h - exposed-modules: XXH3+ exposed-modules: Data.Digest.XXH3 if (arch(x86_64) && !os(osx)) -- Cabal doesn't pass cc-options to "ordinary" Haskell source compilation -- https://github.com/haskell/cabal/issues/9801 ghc-options: -optc=-mavx2 -optc=-O3 - other-modules: FFI+ other-modules: Data.Digest.XXH3.FFI hs-source-dirs: xxhash/src build-depends: , base <5
src/Data/BloomFilter/Hash.hs view
@@ -23,9 +23,9 @@ import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS import Data.Char (ord)+import qualified Data.Digest.XXH3 as XXH3 import qualified Data.Primitive.ByteArray as P import Data.Word (Word32, Word64)-import qualified XXH3 -- | A hash value is 64 bits wide. type Hash = Word64
tests/fpr-calc.hs view
@@ -27,12 +27,12 @@ ["Generate"] -> main_generateData ["Regression"] -> main_regression _ -> do- putStrLn "Usage: bloomfilter-fpr-calc [Generate|Regression]"+ putStrLn "Usage: fpr-calc [Generate|Regression]" exitSuccess main_regression :: IO () main_regression = do- s <- readFile "bloomfilter/fpr.blocked.gnuplot.data"+ s <- readFile "plots/fpr.blocked.gnuplot.data" let parseLine l = case words l of [w_xs_blocked, _, w_ys_blocked_actual] -> ( read w_xs_blocked, read w_ys_blocked_actual )@@ -55,7 +55,7 @@ main_generateData :: IO () main_generateData = do- withFile "bloomfilter/fpr.classic.gnuplot.data" WriteMode $ \h -> do+ withFile "plots/fpr.classic.gnuplot.data" WriteMode $ \h -> do hSetBuffering h LineBuffering --for incremental output mapM_ (\l -> hPutStrLn h l >> putChar '.') $ [ unwords [show bitsperkey, show y1, show y2]@@ -63,9 +63,9 @@ | y1 <- ys_classic_calc | y2 <- ys_classic_actual ]- putStrLn "Wrote bloomfilter/fpr.classic.gnuplot.data"+ putStrLn "Wrote plots/fpr.classic.gnuplot.data" - withFile "bloomfilter/fpr.blocked.gnuplot.data" WriteMode $ \h -> do+ withFile "plots/fpr.blocked.gnuplot.data" WriteMode $ \h -> do hSetBuffering h LineBuffering --for incremental output mapM_ (\l -> hPutStrLn h l >> putChar '.') $ [ unwords [show bitsperkey, show y1, show y2]@@ -73,7 +73,7 @@ | y1 <- ys_blocked_calc | y2 <- ys_blocked_actual ]- putStrLn "Wrote bloomfilter/fpr.blocked.gnuplot.data"+ putStrLn "Wrote plots/fpr.blocked.gnuplot.data" where -- x axis values xs_classic =
+ xxhash/src/Data/Digest/XXH3.hs view
@@ -0,0 +1,110 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}++module Data.Digest.XXH3 (+ -- * One shot+ xxh3_64bit_withSeed_bs,+ xxh3_64bit_withSeed_ba,+ xxh3_64bit_withSeed_w64,+ xxh3_64bit_withSeed_w32,+ -- * Incremental+ XXH3_State,+ xxh3_64bit_createState,+ xxh3_64bit_reset_withSeed,+ xxh3_64bit_digest,+ xxh3_64bit_update_bs,+ xxh3_64bit_update_ba,+ xxh3_64bit_update_w64,+ xxh3_64bit_update_w32,+) where++import Control.Monad.ST (ST)+import Control.Monad.ST.Unsafe (unsafeIOToST)+import Data.ByteString.Internal (ByteString (..),+ accursedUnutterablePerformIO)+import qualified Data.Primitive as P+import Data.Primitive.ByteArray (ByteArray (..))+import Data.Word (Word32, Word64)+import Foreign.ForeignPtr+import GHC.Exts (MutableByteArray#)+import GHC.ForeignPtr++import Data.Digest.XXH3.FFI++{-# INLINE withFP #-}+withFP :: ForeignPtr a -> (P.Ptr a -> IO b) -> IO b+withFP = unsafeWithForeignPtr++-------------------------------------------------------------------------------+-- OneShot+-------------------------------------------------------------------------------++-- | Hash 'ByteString'.+xxh3_64bit_withSeed_bs :: ByteString -> Word64 -> Word64+xxh3_64bit_withSeed_bs (BS fptr len) !salt = accursedUnutterablePerformIO $+ withFP fptr $ \ptr ->+ unsafe_xxh3_64bit_withSeed_ptr ptr (fromIntegral len) salt++-- | Hash (part of) 'ByteArray'.+xxh3_64bit_withSeed_ba :: ByteArray -> Int -> Int -> Word64 -> Word64+xxh3_64bit_withSeed_ba (ByteArray ba) !off !len !salt =+ unsafe_xxh3_64bit_withSeed_ba ba (fromIntegral off) (fromIntegral len) salt++-- | Hash 'Word64'.+xxh3_64bit_withSeed_w64 :: Word64 -> Word64 -> Word64+xxh3_64bit_withSeed_w64 !x !salt =+ unsafe_xxh3_64bit_withSeed_u64 x salt++-- | Hash 'Word32'.+xxh3_64bit_withSeed_w32 :: Word32 -> Word64 -> Word64+xxh3_64bit_withSeed_w32 !x !salt =+ unsafe_xxh3_64bit_withSeed_u32 x salt++-------------------------------------------------------------------------------+-- Incremental+-------------------------------------------------------------------------------++-- | Mutable XXH3 state.+data XXH3_State s = XXH3 (MutableByteArray# s)++-- | Create 'XXH3_State'.+xxh3_64bit_createState :: forall s. ST s (XXH3_State s)+xxh3_64bit_createState = do+ -- aligned alloc, otherwise we get segfaults.+ -- see XXH3_createState implementation+ P.MutableByteArray ba <- P.newAlignedPinnedByteArray unsafe_xxh3_sizeof_state 64+ unsafeIOToST (unsafe_xxh3_initState ba)+ pure (XXH3 ba)++-- | Reset 'XXH3_State' with a seed.+xxh3_64bit_reset_withSeed :: XXH3_State s -> Word64 -> ST s ()+xxh3_64bit_reset_withSeed (XXH3 s) seed = do+ unsafeIOToST (unsafe_xxh3_64bit_reset_withSeed s seed)++-- | Return a hash value from a 'XXH3_State'.+--+-- Doesn't mutate given state, so you can update, digest and update again.+xxh3_64bit_digest :: XXH3_State s -> ST s Word64+xxh3_64bit_digest (XXH3 s) =+ unsafeIOToST (unsafe_xxh3_64bit_digest s)++-- | Update 'XXH3_State' with 'ByteString'.+xxh3_64bit_update_bs :: XXH3_State s -> ByteString -> ST s ()+xxh3_64bit_update_bs (XXH3 s) (BS fptr len) = unsafeIOToST $+ withFP fptr $ \ptr ->+ unsafe_xxh3_64bit_update_ptr s ptr (fromIntegral len)++-- | Update 'XXH3_State' with (part of) 'ByteArray'+xxh3_64bit_update_ba :: XXH3_State s -> ByteArray -> Int -> Int -> ST s ()+xxh3_64bit_update_ba (XXH3 s) (ByteArray ba) !off !len = unsafeIOToST $+ unsafe_xxh3_64bit_update_ba s ba (fromIntegral off) (fromIntegral len)++-- | Update 'XXH3_State' with 'Word64'.+xxh3_64bit_update_w64 :: XXH3_State s -> Word64 -> ST s ()+xxh3_64bit_update_w64 (XXH3 s) w64 = unsafeIOToST $+ unsafe_xxh3_64bit_update_u64 s w64++-- | Update 'XXH3_State' with 'Word32'.+xxh3_64bit_update_w32 :: XXH3_State s -> Word32 -> ST s ()+xxh3_64bit_update_w32 (XXH3 s) w32 = unsafeIOToST $+ unsafe_xxh3_64bit_update_u32 s w32
+ xxhash/src/Data/Digest/XXH3/FFI.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnliftedFFITypes #-}+module Data.Digest.XXH3.FFI (+ -- * One shot+ unsafe_xxh3_64bit_withSeed_ptr,+ unsafe_xxh3_64bit_withSeed_ba,+ unsafe_xxh3_64bit_withSeed_u64,+ unsafe_xxh3_64bit_withSeed_u32,+ -- * Incremental+ unsafe_xxh3_sizeof_state,+ unsafe_xxh3_initState,+ unsafe_xxh3_64bit_reset_withSeed,+ unsafe_xxh3_64bit_digest,+ unsafe_xxh3_64bit_update_ptr,+ unsafe_xxh3_64bit_update_ba,+ unsafe_xxh3_64bit_update_u64,+ unsafe_xxh3_64bit_update_u32,+) where++import Data.Word (Word32, Word64, Word8)+import Foreign.C.Types (CSize (..))+import Foreign.Ptr (Ptr)+import GHC.Exts (ByteArray#, MutableByteArray#)++-- Note: we use unsafe FFI calls, as we expect our use case to be hashing only small data (<1kb, at most 4k).++-------------------------------------------------------------------------------+-- OneShot+-------------------------------------------------------------------------------++foreign import capi unsafe "HsXXHash.h XXH3_64bits_withSeed"+ unsafe_xxh3_64bit_withSeed_ptr :: Ptr Word8 -> CSize -> Word64 -> IO Word64++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_offset"+ unsafe_xxh3_64bit_withSeed_ba :: ByteArray# -> CSize -> CSize -> Word64 -> Word64++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_u64"+ unsafe_xxh3_64bit_withSeed_u64 :: Word64 -> Word64 -> Word64++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_u32"+ unsafe_xxh3_64bit_withSeed_u32 :: Word32 -> Word64 -> Word64++-------------------------------------------------------------------------------+-- Incremental+-------------------------------------------------------------------------------++-- reset and update functions return OK/Error+-- we ignore that:+-- * reset errors only on NULL state+-- * update cannot even error++foreign import capi unsafe "HsXXHash.h value hs_XXH3_sizeof_state_s"+ unsafe_xxh3_sizeof_state :: Int++foreign import capi unsafe "HsXXHash.h XXH3_INITSTATE"+ unsafe_xxh3_initState :: MutableByteArray# s -> IO ()++foreign import capi unsafe "HsXXHash.h XXH3_64bits_reset_withSeed"+ unsafe_xxh3_64bit_reset_withSeed :: MutableByteArray# s -> Word64 -> IO ()++foreign import capi unsafe "HsXXHash.h XXH3_64bits_digest"+ unsafe_xxh3_64bit_digest :: MutableByteArray# s -> IO Word64++foreign import capi unsafe "HsXXHash.h XXH3_64bits_update"+ unsafe_xxh3_64bit_update_ptr :: MutableByteArray# s -> Ptr Word8 -> CSize -> IO ()++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_offset"+ unsafe_xxh3_64bit_update_ba :: MutableByteArray# s -> ByteArray# -> CSize -> CSize -> IO ()++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_u64"+ unsafe_xxh3_64bit_update_u64 :: MutableByteArray# s -> Word64 -> IO ()++foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_u32"+ unsafe_xxh3_64bit_update_u32 :: MutableByteArray# s -> Word32 -> IO ()
− xxhash/src/FFI.hs
@@ -1,75 +0,0 @@-{-# LANGUAGE CApiFFI #-}-{-# LANGUAGE MagicHash #-}-{-# LANGUAGE UnliftedFFITypes #-}-module FFI (- -- * One shot- unsafe_xxh3_64bit_withSeed_ptr,- unsafe_xxh3_64bit_withSeed_ba,- unsafe_xxh3_64bit_withSeed_u64,- unsafe_xxh3_64bit_withSeed_u32,- -- * Incremental- unsafe_xxh3_sizeof_state,- unsafe_xxh3_initState,- unsafe_xxh3_64bit_reset_withSeed,- unsafe_xxh3_64bit_digest,- unsafe_xxh3_64bit_update_ptr,- unsafe_xxh3_64bit_update_ba,- unsafe_xxh3_64bit_update_u64,- unsafe_xxh3_64bit_update_u32,-) where--import Data.Word (Word32, Word64, Word8)-import Foreign.C.Types (CSize (..))-import Foreign.Ptr (Ptr)-import GHC.Exts (ByteArray#, MutableByteArray#)---- Note: we use unsafe FFI calls, as we expect our use case to be hashing only small data (<1kb, at most 4k).------------------------------------------------------------------------------------ OneShot----------------------------------------------------------------------------------foreign import capi unsafe "HsXXHash.h XXH3_64bits_withSeed"- unsafe_xxh3_64bit_withSeed_ptr :: Ptr Word8 -> CSize -> Word64 -> IO Word64--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_offset"- unsafe_xxh3_64bit_withSeed_ba :: ByteArray# -> CSize -> CSize -> Word64 -> Word64--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_u64"- unsafe_xxh3_64bit_withSeed_u64 :: Word64 -> Word64 -> Word64--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_withSeed_u32"- unsafe_xxh3_64bit_withSeed_u32 :: Word32 -> Word64 -> Word64------------------------------------------------------------------------------------ Incremental------------------------------------------------------------------------------------ reset and update functions return OK/Error--- we ignore that:--- * reset errors only on NULL state--- * update cannot even error--foreign import capi unsafe "HsXXHash.h value hs_XXH3_sizeof_state_s"- unsafe_xxh3_sizeof_state :: Int--foreign import capi unsafe "HsXXHash.h XXH3_INITSTATE"- unsafe_xxh3_initState :: MutableByteArray# s -> IO ()--foreign import capi unsafe "HsXXHash.h XXH3_64bits_reset_withSeed"- unsafe_xxh3_64bit_reset_withSeed :: MutableByteArray# s -> Word64 -> IO ()--foreign import capi unsafe "HsXXHash.h XXH3_64bits_digest"- unsafe_xxh3_64bit_digest :: MutableByteArray# s -> IO Word64--foreign import capi unsafe "HsXXHash.h XXH3_64bits_update"- unsafe_xxh3_64bit_update_ptr :: MutableByteArray# s -> Ptr Word8 -> CSize -> IO ()--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_offset"- unsafe_xxh3_64bit_update_ba :: MutableByteArray# s -> ByteArray# -> CSize -> CSize -> IO ()--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_u64"- unsafe_xxh3_64bit_update_u64 :: MutableByteArray# s -> Word64 -> IO ()--foreign import capi unsafe "HsXXHash.h hs_XXH3_64bits_update_u32"- unsafe_xxh3_64bit_update_u32 :: MutableByteArray# s -> Word32 -> IO ()
− xxhash/src/XXH3.hs
@@ -1,110 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE MagicHash #-}--module XXH3 (- -- * One shot- xxh3_64bit_withSeed_bs,- xxh3_64bit_withSeed_ba,- xxh3_64bit_withSeed_w64,- xxh3_64bit_withSeed_w32,- -- * Incremental- XXH3_State,- xxh3_64bit_createState,- xxh3_64bit_reset_withSeed,- xxh3_64bit_digest,- xxh3_64bit_update_bs,- xxh3_64bit_update_ba,- xxh3_64bit_update_w64,- xxh3_64bit_update_w32,-) where--import Control.Monad.ST (ST)-import Control.Monad.ST.Unsafe (unsafeIOToST)-import Data.ByteString.Internal (ByteString (..),- accursedUnutterablePerformIO)-import qualified Data.Primitive as P-import Data.Primitive.ByteArray (ByteArray (..))-import Data.Word (Word32, Word64)-import Foreign.ForeignPtr-import GHC.Exts (MutableByteArray#)-import GHC.ForeignPtr--import FFI--{-# INLINE withFP #-}-withFP :: ForeignPtr a -> (P.Ptr a -> IO b) -> IO b-withFP = unsafeWithForeignPtr------------------------------------------------------------------------------------ OneShot------------------------------------------------------------------------------------ | Hash 'ByteString'.-xxh3_64bit_withSeed_bs :: ByteString -> Word64 -> Word64-xxh3_64bit_withSeed_bs (BS fptr len) !salt = accursedUnutterablePerformIO $- withFP fptr $ \ptr ->- unsafe_xxh3_64bit_withSeed_ptr ptr (fromIntegral len) salt---- | Hash (part of) 'ByteArray'.-xxh3_64bit_withSeed_ba :: ByteArray -> Int -> Int -> Word64 -> Word64-xxh3_64bit_withSeed_ba (ByteArray ba) !off !len !salt =- unsafe_xxh3_64bit_withSeed_ba ba (fromIntegral off) (fromIntegral len) salt---- | Hash 'Word64'.-xxh3_64bit_withSeed_w64 :: Word64 -> Word64 -> Word64-xxh3_64bit_withSeed_w64 !x !salt =- unsafe_xxh3_64bit_withSeed_u64 x salt---- | Hash 'Word32'.-xxh3_64bit_withSeed_w32 :: Word32 -> Word64 -> Word64-xxh3_64bit_withSeed_w32 !x !salt =- unsafe_xxh3_64bit_withSeed_u32 x salt------------------------------------------------------------------------------------ Incremental------------------------------------------------------------------------------------ | Mutable XXH3 state.-data XXH3_State s = XXH3 (MutableByteArray# s)---- | Create 'XXH3_State'.-xxh3_64bit_createState :: forall s. ST s (XXH3_State s)-xxh3_64bit_createState = do- -- aligned alloc, otherwise we get segfaults.- -- see XXH3_createState implementation- P.MutableByteArray ba <- P.newAlignedPinnedByteArray unsafe_xxh3_sizeof_state 64- unsafeIOToST (unsafe_xxh3_initState ba)- pure (XXH3 ba)---- | Reset 'XXH3_State' with a seed.-xxh3_64bit_reset_withSeed :: XXH3_State s -> Word64 -> ST s ()-xxh3_64bit_reset_withSeed (XXH3 s) seed = do- unsafeIOToST (unsafe_xxh3_64bit_reset_withSeed s seed)---- | Return a hash value from a 'XXH3_State'.------ Doesn't mutate given state, so you can update, digest and update again.-xxh3_64bit_digest :: XXH3_State s -> ST s Word64-xxh3_64bit_digest (XXH3 s) =- unsafeIOToST (unsafe_xxh3_64bit_digest s)---- | Update 'XXH3_State' with 'ByteString'.-xxh3_64bit_update_bs :: XXH3_State s -> ByteString -> ST s ()-xxh3_64bit_update_bs (XXH3 s) (BS fptr len) = unsafeIOToST $- withFP fptr $ \ptr ->- unsafe_xxh3_64bit_update_ptr s ptr (fromIntegral len)---- | Update 'XXH3_State' with (part of) 'ByteArray'-xxh3_64bit_update_ba :: XXH3_State s -> ByteArray -> Int -> Int -> ST s ()-xxh3_64bit_update_ba (XXH3 s) (ByteArray ba) !off !len = unsafeIOToST $- unsafe_xxh3_64bit_update_ba s ba (fromIntegral off) (fromIntegral len)---- | Update 'XXH3_State' with 'Word64'.-xxh3_64bit_update_w64 :: XXH3_State s -> Word64 -> ST s ()-xxh3_64bit_update_w64 (XXH3 s) w64 = unsafeIOToST $- unsafe_xxh3_64bit_update_u64 s w64---- | Update 'XXH3_State' with 'Word32'.-xxh3_64bit_update_w32 :: XXH3_State s -> Word32 -> ST s ()-xxh3_64bit_update_w32 (XXH3 s) w32 = unsafeIOToST $- unsafe_xxh3_64bit_update_u32 s w32
xxhash/tests/xxhash-tests.hs view
@@ -9,7 +9,7 @@ import Test.Tasty.HUnit (testCase, (@=?)) import Test.Tasty.QuickCheck (testProperty, (===)) -import XXH3+import Data.Digest.XXH3 main :: IO () main = defaultMain $ testGroup "xxhash"