packages feed

cuckoo 0.2.2 → 0.3.0

raw patch · 9 files changed

+257/−154 lines, 9 filesdep +blake2dep +hashesdep −cryptonitedep −memorydep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: blake2, hashes

Dependencies removed: cryptonite, memory

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.Cuckoo: fnv1a :: Storable a => Int -> a -> Word64
- Data.Cuckoo: fnv1a_bytes :: ByteArrayAccess a => Int -> a -> Word64
- Data.Cuckoo: sip :: Storable a => Int -> a -> Word64
- Data.Cuckoo: sip_bytes :: ByteArrayAccess a => Int -> a -> Word64
- Data.Cuckoo.Internal: fnv1a :: Storable a => Int -> a -> Word64
- Data.Cuckoo.Internal: fnv1a_bytes :: ByteArrayAccess a => Int -> a -> Word64
- Data.Cuckoo.Internal: sip :: Storable a => Int -> a -> Word64
- Data.Cuckoo.Internal: sip2 :: Storable a => Int -> a -> Word64
- Data.Cuckoo.Internal: sip_bytes :: ByteArrayAccess a => Int -> a -> Word64
+ Data.Cuckoo: saltedFnv1aByteString :: Int -> ByteString -> Word64
+ Data.Cuckoo: saltedFnv1aPtr :: Int -> Ptr Word8 -> Int -> Word64
+ Data.Cuckoo: saltedFnv1aStorable :: Storable a => Int -> a -> Word64
+ Data.Cuckoo: saltedSipHashByteString :: Int -> ByteString -> Word64
+ Data.Cuckoo: saltedSipHashPtr :: Int -> Ptr Word8 -> Int -> Word64
+ Data.Cuckoo: saltedSipHashStorable :: Storable a => Int -> a -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedFnv1aByteString :: Int -> ByteString -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedFnv1aPtr :: Int -> Ptr Word8 -> Int -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedFnv1aStorable :: Storable a => Int -> a -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedSipHashByteString :: Int -> ByteString -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedSipHashPtr :: Int -> Ptr Word8 -> Int -> Word64
+ Data.Cuckoo.Internal.HashFunctions: saltedSipHashStorable :: Storable a => Int -> a -> Word64
+ Data.Cuckoo.Internal.HashFunctions: sipHashInternal :: Storable a => Int -> a -> Word64

Files

CHANGELOG.md view
@@ -1,5 +1,26 @@ # Revision history for cuckoo +## 0.3.0 -- 2021-09-30++*   Rename hash functions provided hash functions to++    *   `saltedSipHashStorable`+    *   `saltedSipHashByteString`+    *   `saltedSipHashPtr`+    *   `saltedFnv1aStorable`+    *   `saltedFnv1aByteString`+    *   `saltedFnv1aPtr`++*   Use [hashes](https://hackage.haskell.org/package/hashes) package for hash+    functions and drop dependency on+    [memory](https://hackage.haskell.org/package/memory).++    The [bytestring](https://hackage.haskell.org/package/bytestring) package is+    is added as a new dependency.++*   Move implementation of hash functions from+    `Data.Cuckoo.Internal` to `Data.Cuckoo.Internal.HashFunctions`.+ ## 0.2.2 -- 2021-06-24  * Support GHC-9
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2019, Lars Kuhtz <lakuhtz@gmail.com>+Copyright (c) 2019-2021, Lars Kuhtz <lakuhtz@gmail.com>  All rights reserved. 
bench/Internal.hs view
@@ -7,7 +7,7 @@  -- | -- Module: Main--- Copyright: Copyright © 2019 Lars Kuhtz <lakuhtz@gmail.com>+-- Copyright: Copyright © 2019-2021 Lars Kuhtz <lakuhtz@gmail.com> -- License: BSD3 -- Maintainer: Lars Kuhtz <lakuhtz@gmail.com> -- Stability: experimental@@ -36,7 +36,9 @@  main :: IO () main = do+    putStrLn "prop_fit"     quickCheck prop_fit+    putStrLn "prop_p2"     quickCheck prop_p2     defaultMain         [ bgroup "fit"@@ -117,8 +119,8 @@  -- Ignore negative values ---prop_p2 :: NonNegative Int -> Property-prop_p2 (NonNegative x)+prop_p2 :: Positive Int -> Property+prop_p2 (Positive x)     = floatingP2 x === integralP2_0 x     .&&. floatingP2 x === integralP2_1 x     .&&. floatingP2 x === integralP2_2 x
bench/SpellChecker.hs view
@@ -21,7 +21,6 @@ import Control.Monad (filterM, unless) import Control.StopWatch -import Data.ByteArray () import qualified Data.ByteString.Char8 as B import qualified Data.Cuckoo as C import Data.List ((\\))@@ -38,8 +37,8 @@ --     {-# INLINE cuckooFingerprint #-}  instance C.CuckooFilterHash B.ByteString where-    cuckooHash (C.Salt s) = C.fnv1a_bytes s-    cuckooFingerprint (C.Salt s) = C.sip_bytes s+    cuckooHash (C.Salt s) = C.saltedFnv1aByteString s+    cuckooFingerprint (C.Salt s) = C.saltedSipHashByteString s     {-# INLINE cuckooHash #-}     {-# INLINE cuckooFingerprint #-} 
cuckoo.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: cuckoo-version: 0.2.2+version: 0.3.0 synopsis: Haskell Implementation of Cuckoo Filters Description:     Haskell implementation of Cuckoo filters as described in@@ -29,7 +29,7 @@ category: Data tested-with:     GHC==9.0.1-    GHC==8.10.5+    GHC==8.10.7     GHC==8.8.4 extra-source-files:     README.md@@ -57,7 +57,7 @@     ghc-options:         -Wall     build-depends:-        , base >=4.11 && <4.16+        , base >=4.11 && <5         , primitive >=0.6.4.0      if flag(pcg-random)@@ -81,14 +81,15 @@     exposed-modules:         Data.Cuckoo         Data.Cuckoo.Internal+        Data.Cuckoo.Internal.HashFunctions     build-depends:         , random-internal          -- external-        , base >=4.11 && <4.16-        , memory >=0.14+        , base >=4.11 && <5+        , bytestring >=0.10+        , hashes >=0.1         , primitive >=0.6.4.0-        , vector >=0.12  test-suite tests     type: exitcode-stdio-1.0@@ -106,11 +107,10 @@         , random-internal          -- external-        , base >=4.11 && <4.16+        , base >=4.11 && <5+        , blake2 >=0.3         , bytestring >=0.10-        , cryptonite >=0.26         , hashable >=1.3-        , memory >=0.14         , stopwatch >=0.1  test-suite doctests@@ -123,11 +123,8 @@         -with-rtsopts=-N     main-is: doctest.hs     build-depends:-        , cuckoo-        , base >=4.11 && <4.16+        , base >=4.11 && <5         , doctest >= 0.18-        , memory >=0.14-        , primitive >=0.6.4.0  benchmark spellchecker     type: exitcode-stdio-1.0@@ -144,9 +141,8 @@         , cuckoo          -- external-        , base >=4.11 && <4.16+        , base >=4.11 && <5         , bytestring >=0.10-        , memory >=0.14         , stopwatch >=0.1  benchmark internal-benchmarks@@ -167,6 +163,6 @@          -- external         , QuickCheck >= 2.13-        , base >=4.10 && <4.16+        , base >=4.10 && <5         , criterion >= 1.5 
src/Data/Cuckoo.hs view
@@ -10,7 +10,7 @@  -- | -- Module: Data.Cuckoo--- Copyright: Copyright © 2019 Lars Kuhtz <lakuhtz@gmail.com>+-- Copyright: Copyright © 2019-2021 Lars Kuhtz <lakuhtz@gmail.com> -- License: BSD3 -- Maintainer: Lars Kuhtz <lakuhtz@gmail.com> -- Stability: experimental@@ -83,10 +83,12 @@ , CuckooFilterHash(..)  -- ** Hash functions-, sip-, sip_bytes-, fnv1a-, fnv1a_bytes+, saltedSipHashStorable+, saltedSipHashByteString+, saltedSipHashPtr+, saltedFnv1aStorable+, saltedFnv1aByteString+, saltedFnv1aPtr  -- * Cuckoo Filter , CuckooFilter@@ -134,10 +136,18 @@ -- internal modules  import Data.Cuckoo.Internal+import Data.Cuckoo.Internal.HashFunctions  -- $setup -- >>> :set -XTypeApplications -XDataKinds -XTypeFamilies--- >>> instance CuckooFilterHash Int+-- >>> :{+-- instance CuckooFilterHash Int where+--     -- can't use default implementation with doctest because of a bug in GHC-9+--     cuckooHash (Salt s) a = saltedFnv1aStorable s a+--     cuckooFingerprint (Salt s) a = saltedSipHashStorable s a+--     {-# INLINE cuckooHash #-}+--     {-# INLINE cuckooFingerprint #-}+-- :}  -- -------------------------------------------------------------------------- -- -- Hash Functions@@ -156,7 +166,7 @@ -- implementation of fnv. -- -- Because of the variying quality and properties of the functions, absence of--- any control over which function is use, and no guarantees with respect to+-- any control over which function is used, and no guarantees with respect to -- stability accross versions, we don't use that package altogether. -- @@ -174,7 +184,14 @@ -- The default implementations use sip hash for 'cuckooHash' and 'fnv1a' (64 -- bit) for 'cuckooFingerprint' and require an instance of 'Storable'. ----- >>> instance CuckooFilterHash Int+-- >>> :{+-- instance CuckooFilterHash Int where+--     -- can't use default implementation with doctest because of a bug in GHC-9+--     cuckooHash (Salt s) a = saltedFnv1aStorable s a+--     cuckooFingerprint (Salt s) a = saltedSipHashStorable s a+--     {-# INLINE cuckooHash #-}+--     {-# INLINE cuckooFingerprint #-}+-- :} -- -- The following example uses the hash functions that are provided in this -- module to define an instance for 'B.ByteString':@@ -182,8 +199,8 @@ -- >>> import qualified Data.ByteString as B -- >>> :{ -- instance CuckooFilterHash B.ByteString where---     cuckooHash (Salt s) a = fnv1a_bytes s a---     cuckooFingerprint (Salt s) a = sip_bytes s a+--     cuckooHash (Salt s) a = saltedFnv1aByteString s a+--     cuckooFingerprint (Salt s) a = saltedSipHashByteString s a --     {-# INLINE cuckooHash #-} --     {-# INLINE cuckooFingerprint #-} -- :}@@ -204,14 +221,14 @@     -- of 'Storable'.     --     default cuckooHash :: Storable a => Salt -> a -> Word64-    cuckooHash (Salt s) a = sip s a+    cuckooHash (Salt s) = saltedSipHashStorable s     {-# INLINE cuckooHash #-}      -- | Default implementation of 'cuckooFingerprint' for types that are an     -- instance of 'Storable'.     --     default cuckooFingerprint :: Storable a => Salt -> a -> Word64-    cuckooFingerprint (Salt s) a = fnv1a s a+    cuckooFingerprint (Salt s) = saltedFnv1aStorable s     {-# INLINE cuckooFingerprint #-}  -- -------------------------------------------------------------------------- --@@ -494,7 +511,7 @@ -- isn't independent from this one. -- hashFingerprint :: Salt -> Fingerprint f -> Int-hashFingerprint (Salt s) (Fingerprint a) = int $! sip2 s a+hashFingerprint (Salt s) (Fingerprint a) = int $! sipHashInternal s a {-# INLINE hashFingerprint #-}  mkFingerprint@@ -509,12 +526,12 @@ {-# INLINE mkFingerprint #-}  bucket1 :: CuckooFilterHash a => CuckooFilter s b f a -> a -> Bucket-bucket1 f a = Bucket $! int $! cuckooHash (_cfSalt f) a .&. (int $ _cfBucketCount f - 1)+bucket1 f a = Bucket $! int $! cuckooHash (_cfSalt f) a .&. int (_cfBucketCount f - 1) {-# INLINE bucket1 #-}  otherBucket :: CuckooFilter s b f a -> Bucket -> Fingerprint f -> Bucket otherBucket f (Bucket b) fp = Bucket $!-    (b `xor` hashFingerprint (_cfSalt f) fp) .&. (int $ _cfBucketCount f - 1)+    (b `xor` hashFingerprint (_cfSalt f) fp) .&. int (_cfBucketCount f - 1) {-# INLINE otherBucket #-}  ix :: Bucket -> Int
src/Data/Cuckoo/Internal.hs view
@@ -9,7 +9,7 @@  -- | -- Module: Data.Cuckoo.Internal--- Copyright: Copyright © 2019 Lars Kuhtz <lakuhtz@gmail.com>+-- Copyright: Copyright © 2019-2021 Lars Kuhtz <lakuhtz@gmail.com> -- License: BSD3 -- Maintainer: Lars Kuhtz <lakuhtz@gmail.com> -- Stability: experimental@@ -27,21 +27,11 @@ , intNextPowerOfTwo , set , get---- * Hash functions-, sip-, fnv1a-, fnv1a_bytes-, sip_bytes-, sip2 ) where  import Control.Monad.Primitive  import Data.Bits-import qualified Data.ByteArray as BA-import qualified Data.ByteArray.Hash as BA-import qualified Data.ByteArray.Pack as BA import Data.Primitive.ByteArray  import Foreign@@ -105,89 +95,6 @@ intNextPowerOfTwo 0 = 1 intNextPowerOfTwo x = 1 `unsafeShiftL` (finiteBitSize x - countLeadingZeros (x - 1)) {-# INLINE intNextPowerOfTwo #-}---- | Computes a 64 bit Fnv1a hash for a value that has an 'Storable' instance.------ The first argument is use as a salt.----fnv1a-    :: Storable a-    => Int-        -- ^ Salt-    -> a-        -- ^ Value that is hashes-    -> Word64-fnv1a s x = r-  where-    Right (BA.FnvHash64 r) = BA.fnv1a_64Hash-        <$> BA.fill @BA.Bytes (8 + sizeOf x) (BA.putStorable s >> BA.putStorable x)-{-# INLINE fnv1a #-}---- | Computes a 64 bit Fnv1a hash for a value that is an instance of--- 'BA.ByteArrayAccess'.------ The first argument is use as a salt.----fnv1a_bytes-    :: BA.ByteArrayAccess a-    => Int-        -- ^ Salt-    -> a-        -- ^ Value that is hashes-    -> Word64-fnv1a_bytes s x = r-  where-    Right (BA.FnvHash64 r) = BA.fnv1a_64Hash-        <$> BA.fill @BA.Bytes (8 + BA.length x) (BA.putStorable s >> BA.putBytes x)-{-# INLINE fnv1a_bytes #-}---- | Computes a Sip hash for a value that has an 'Storable' instance.------ The first argument is a salt value that is used to derive the key for the--- hash computation.----sip-    :: Storable a-    => Int-        -- ^ Salt-    -> a-        -- ^ Value that is hashes-    -> Word64-sip s x = r-  where-    Right (BA.SipHash r) = BA.sipHash (BA.SipKey (int s) 914279)-        <$> BA.fill @BA.Bytes (sizeOf x) (BA.putStorable x)-{-# INLINE sip #-}---- | Computes a Sip hash for a value that is an instance of--- 'BA.ByteArrayAccess'.------ The first argument is a salt value that is used to derive the key for the--- hash computation.----sip_bytes-    :: BA.ByteArrayAccess a-    => Int-        -- ^ Salt-    -> a-        -- ^ Value that is hashes-    -> Word64-sip_bytes s x = r-  where-    Right (BA.SipHash r) = BA.sipHash (BA.SipKey (int s) 1043639)-        <$> BA.fill @BA.Bytes (BA.length x) (BA.putBytes x)-{-# INLINE sip_bytes #-}---- | An version of a Sip hash that is used internally. In order to avoid--- dependencies between different hash computations, it shouldn't be used in the--- implementation of instances of 'Data.Cuckoo.CuckooFilterHash'.----sip2 :: Storable a => Int -> a -> Word64-sip2 s x = r-  where-    Right (BA.SipHash r) = BA.sipHash (BA.SipKey 994559 (int s * 713243))-        <$> BA.fill @BA.Bytes (sizeOf x) (BA.putStorable x)-{-# INLINE sip2 #-}  -- | Write a 'Word64' value into a 'Word32' aligned 'MutableByteArray' --
+ src/Data/Cuckoo/Internal/HashFunctions.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- |+-- Module: Data.Cuckoo.Internal.HashFunctions+-- Copyright: Copyright © 2021 Lars Kuhtz <lakuhtz@gmail.com>+-- License: BSD3+-- Maintainer: Lars Kuhtz <lakuhtz@gmail.com>+-- Stability: experimental+--+module Data.Cuckoo.Internal.HashFunctions+(+-- * Salted Hash Functions+  saltedFnv1aPtr+, saltedFnv1aStorable+, saltedFnv1aByteString++-- ** Salted Sip Hash+, saltedSipHashPtr+, saltedSipHashStorable+, saltedSipHashByteString++-- * Internal Use Only+, sipHashInternal+) where++import qualified Data.ByteString as B+import Data.Hash.FNV1+import Data.Hash.SipHash++import Foreign++import Data.Cuckoo.Internal++-- -------------------------------------------------------------------------- --+-- FNV1a++-- | Computes a 64 bit Fnv1a hash for a value that is an instance of+-- 'BA.ByteArrayAccess'.+--+-- The first argument is use as a salt.+--+saltedFnv1aPtr+    :: Int+        -- ^ Salt+    -> Ptr Word8+        -- ^ Bytes that are hashed+    -> Int+        -- ^ Number of bytes+    -> Word64+saltedFnv1aPtr s p ps = hashPtr_ fnv1a_64_ p ps+    $! hashStorable fnv1a_64 s+{-# INLINE saltedFnv1aPtr #-}++-- | Computes a 64 bit Fnv1a hash for a value that has an 'Storable' instance.+--+-- The first argument is use as a salt.+--+saltedFnv1aStorable+    :: Storable a+    => Int+        -- ^ Salt+    -> a+        -- ^ Value that is hashed+    -> Word64+saltedFnv1aStorable s x = hashStorable_ fnv1a_64_ x+    $! hashStorable fnv1a_64 s+{-# INLINE saltedFnv1aStorable #-}++saltedFnv1aByteString+    :: Int+        -- ^ Salt+    -> B.ByteString+        -- ^ Bytes that are hashed+    -> Word64+saltedFnv1aByteString s b = hashByteString_ fnv1a_64_ b+    $! hashStorable fnv1a_64 s+{-# INLINE saltedFnv1aByteString #-}++-- -------------------------------------------------------------------------- --+-- Sip Hash++-- | Computes a Sip hash for a value that is represented as byte pointer.+--+-- The first argument is a salt value that is used to derive the key for the+-- hash computation.+--+saltedSipHashPtr+    :: Int+        -- ^ Salt+    -> Ptr Word8+        -- ^ Bytes that is hashed+    -> Int+        -- ^ Number of bytes+    -> Word64+saltedSipHashPtr s ptr l = hashPtr (sipHash24 (int s) 1043639) ptr l+{-# INLINE saltedSipHashPtr #-}++-- | Computes a Sip hash for a value that has an 'Storable' instance.+--+-- The first argument is a salt value that is used to derive the key for the+-- hash computation.+--+saltedSipHashStorable+    :: Storable a+    => Int+        -- ^ Salt+    -> a+        -- ^ Value that is hashed+    -> Word64+saltedSipHashStorable s = hashStorable (sipHash24 (int s) 914279)+{-# INLINE saltedSipHashStorable #-}++-- | Computes a Sip hash for a value that has an 'Storable' instance.+--+-- The first argument is a salt value that is used to derive the key for the+-- hash computation.+--+saltedSipHashByteString+    :: Int+        -- ^ Salt+    -> B.ByteString+        -- ^ Value that is hashed+    -> Word64+saltedSipHashByteString s = hashByteString (sipHash24 (int s) 914279)+{-# INLINE saltedSipHashByteString #-}++-- -------------------------------------------------------------------------- --+-- Interal Use Only (Do Not Use)++-- | An version of a Sip hash that is used only internally. In order to avoid+-- dependencies between different hash computations, it shouldn't be used in the+-- implementation of instances of 'Data.Cuckoo.CuckooFilterHash'.+--+sipHashInternal :: Storable a => Int -> a -> Word64+sipHashInternal s = hashStorable (sipHash24 994559 (int s * 713243))+{-# INLINE sipHashInternal #-}+
test/Main.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PackageImports #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} @@ -11,7 +12,7 @@  -- | -- Module: Main--- Copyright: Copyright © 2019 Lars Kuhtz <lakuhtz@gmail.com>+-- Copyright: Copyright © 2019-2021 Lars Kuhtz <lakuhtz@gmail.com> -- License: BSD3 -- Maintainer: Lars Kuhtz <lakuhtz@gmail.com> -- Stability: experimental@@ -29,13 +30,13 @@  import Control.StopWatch -import qualified Crypto.Hash as C+import qualified Crypto.Hash.BLAKE2.BLAKE2b as C  import Data.Bool-import qualified Data.ByteArray as BA-import qualified Data.ByteArray.Pack as BA hiding (pack) import qualified Data.ByteString as B-import Data.Either+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy as LB+import qualified Data.ByteString.Unsafe as B import Data.Hashable  import Foreign@@ -43,8 +44,9 @@ import Numeric.Natural  import System.IO.Unsafe-import System.Random.Internal +import "cuckoo" System.Random.Internal+ -- internal modules  import Data.Cuckoo@@ -67,13 +69,13 @@     putStrLn "[ByteString] fill up to first insert failure"     stopWatch (test2 @HashablePkg n) >>= p "Hashable Package"     stopWatch (test2 @Fnv1aSip n) >>= p "Fnv1a+Sip"-    stopWatch (test2 @Crypto n) >>= p "Blake2b_256"+    stopWatch (test2 @Crypto n) >>= p "Blake2b_8"      putStrLn ""     putStrLn "[ByteString] fill to 95%"     stopWatch (test3 @HashablePkg n) >>= p "Hashable Package"     stopWatch (test3 @Fnv1aSip n) >>= p "Fnv1a+Sip"-    stopWatch (test3 @Crypto n) >>= p "Blake2b_256"+    stopWatch (test3 @Crypto n) >>= p "Blake2b_8"   where     p l (r, t) = putStrLn $ show t <> " - " <> l <> " - " <> show r     n = 500000@@ -85,11 +87,28 @@ instance CuckooFilterHash Double  -- -------------------------------------------------------------------------- --+-- Hash Utils++integralBytes :: Integral a => a -> B.ByteString+integralBytes = LB.toStrict . BB.toLazyByteString . BB.int64LE . fromIntegral+{-# INLINE integralBytes #-}++class Pack a where+    pack :: [Word8] -> a+    unpack :: a -> [Word8]++instance Pack B.ByteString where+    pack = B.pack+    unpack = B.unpack+    {-# INLINE pack #-}+    {-# INLINE unpack #-}++-- -------------------------------------------------------------------------- -- -- Hashable (I think, this uses SIP hash)  newtype HashablePkg = HashablePkg B.ByteString     deriving (Show, Eq, Ord)-    deriving newtype (BA.ByteArrayAccess, BA.ByteArray, Semigroup, Monoid, Hashable)+    deriving newtype (Semigroup, Monoid, Hashable, Pack)  instance CuckooFilterHash HashablePkg where     cuckooHash (Salt s) a = fromIntegral $! hashWithSalt s a@@ -102,11 +121,11 @@  newtype Fnv1aSip = Fnv1aSip B.ByteString     deriving (Show, Eq, Ord)-    deriving newtype (BA.ByteArrayAccess, BA.ByteArray, Semigroup, Monoid)+    deriving newtype (Semigroup, Monoid, Pack)  instance CuckooFilterHash Fnv1aSip where-    cuckooHash (Salt s) a = fnv1a_bytes s a-    cuckooFingerprint (Salt s) a = sip_bytes s a+    cuckooHash (Salt s) (Fnv1aSip b) = saltedFnv1aByteString s b+    cuckooFingerprint (Salt s) (Fnv1aSip b) = saltedSipHashByteString s b     {-# INLINE cuckooHash #-}     {-# INLINE cuckooFingerprint #-} @@ -115,14 +134,17 @@  newtype Crypto = Crypto B.ByteString     deriving (Show, Eq, Ord)-    deriving newtype (BA.ByteArrayAccess, BA.ByteArray, Semigroup, Monoid)+    deriving newtype (Semigroup, Monoid, Pack)  instance CuckooFilterHash Crypto where-    -- cuckooHash _ a = unsafePerformIO $ BA.withByteArray (C.hash @_ @C.Blake2b_256 a) $ peek-    cuckooHash (Salt s) a = unsafePerformIO $ flip BA.withByteArray peek-        $ C.hash @BA.Bytes @C.Blake2b_256-        $ fromRight (error "must not happen")-        $ BA.fill (BA.length a + 8) (BA.putStorable s >> BA.putBytes a)+    cuckooHash (Salt s) (Crypto a) = unsafeDupablePerformIO $!+        B.unsafeUseAsCStringLen h $ \(ptr, _) -> peek (castPtr ptr)+      where+        h = C.finalize 8+            $! C.update a+            $! C.update (integralBytes s)+            $! C.initialize 8+     cuckooFingerprint s a = int $ cuckooHash (s + 23) a     {-# INLINE cuckooHash #-}     {-# INLINE cuckooFingerprint #-}@@ -170,13 +192,13 @@  -- | Fill up to first insert failure ---test2 :: forall a . CuckooFilterHash a => BA.ByteArray a => Natural -> IO TestResult+test2 :: forall a . Pack a => CuckooFilterHash a => Natural -> IO TestResult test2 n = do     rng <- initialize 0     s <- Salt <$> uniform rng     f <- newCuckooFilter @4 @10 @a s n     let go i fp = do-            let x = BA.pack (castEnum <$> show i)+            let x = pack (castEnum <$> show i)             fp' <- bool fp (succ fp) <$> member f x             insert f x >>= \case                 True -> go (succ i) fp'@@ -189,7 +211,7 @@  -- | Fill 90% of the filter ---test3 :: forall a . CuckooFilterHash a => BA.ByteArray a => Natural -> IO TestResult+test3 :: forall a . Pack a => CuckooFilterHash a => Natural -> IO TestResult test3 n = do     rng <- initialize 0     s <- Salt <$> uniform rng@@ -197,7 +219,7 @@     let go i x fp             | int i >= int @_ @Double n * 95 / 100 = return (i, x, fp)         go i x fp = do-            let bytes = BA.pack (castEnum <$> show i)+            let bytes = pack (castEnum <$> show i)             fp' <- bool fp (succ fp) <$> member f bytes              -- unless (fp == fp') $ do