{-# OPTIONS_HADDOCK not-home #-}
-- | This module exports 'Bloom'' definition.
module Data.BloomFilter.Internal (
    Bloom'(..),
    bloomInvariant,
) where

import           Control.DeepSeq (NFData (..))
import           Data.Bits
import qualified Data.BloomFilter.BitVec64 as V
import           Data.Kind (Type)
import           Data.Primitive.ByteArray (sizeofByteArray)
import qualified Data.Vector.Primitive as P
import           Data.Word (Word64)

type Bloom' :: (Type -> Type) -> Type -> Type
data Bloom' h a = Bloom {
      forall (h :: * -> *) a. Bloom' h a -> Int
hashesN  :: {-# UNPACK #-} !Int
    , forall (h :: * -> *) a. Bloom' h a -> Word64
size     :: {-# UNPACK #-} !Word64 -- ^ size is non-zero
    , forall (h :: * -> *) a. Bloom' h a -> BitVec64
bitArray :: {-# UNPACK #-} !V.BitVec64
    }
type role Bloom' nominal nominal

bloomInvariant :: Bloom' h a -> Bool
bloomInvariant :: forall (h :: * -> *) a. Bloom' h a -> Bool
bloomInvariant (Bloom Int
_ Word64
s (V.BV64 (P.Vector Int
off Int
len ByteArray
ba))) =
       Word64
s Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
> Word64
0
    Bool -> Bool -> Bool
&& Word64
s Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word64
2Word64 -> Int -> Word64
forall a b. (Num a, Integral b) => a -> b -> a
^(Int
48 :: Int)
    Bool -> Bool -> Bool
&& Int
off Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
    Bool -> Bool -> Bool
&& Word64 -> Word64
forall {a}. (Bits a, Num a) => a -> a
ceilDiv64 Word64
s Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len
    Bool -> Bool -> Bool
&& (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
len) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
8 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= ByteArray -> Int
sizeofByteArray ByteArray
ba
  where
    ceilDiv64 :: a -> a
ceilDiv64 a
x = a -> Int -> a
forall a. Bits a => a -> Int -> a
unsafeShiftR (a
x a -> a -> a
forall a. Num a => a -> a -> a
+ a
63) Int
6

instance Eq (Bloom' h a) where
    -- We support arbitrary sized bitvectors,
    -- therefore an equality is a bit involved:
    -- we need to be careful when comparing the last bits of bitArray.
    Bloom Int
k Word64
n (V.BV64 Vector Word64
v) == :: Bloom' h a -> Bloom' h a -> Bool
== Bloom Int
k' Word64
n' (V.BV64 Vector Word64
v') =
        Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
k' Bool -> Bool -> Bool
&&
        Word64
n Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
n' Bool -> Bool -> Bool
&&
        Int -> Vector Word64 -> Vector Word64
forall a. Prim a => Int -> Vector a -> Vector a
P.take Int
w Vector Word64
v Vector Word64 -> Vector Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Vector Word64 -> Vector Word64
forall a. Prim a => Int -> Vector a -> Vector a
P.take Int
w Vector Word64
v' Bool -> Bool -> Bool
&& -- compare full words
        if Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then Bool
True else Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL Word64
x Int
s Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftL Word64
x' Int
s -- compare last words
      where
        !w :: Int
w = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
unsafeShiftR Word64
n Int
6) :: Int  -- n `div` 64
        !l :: Int
l = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
n Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
63) :: Int          -- n `mod` 64
        !s :: Int
s = Int
64 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
l

        -- last words
        x :: Word64
x = Vector Word64 -> Int -> Word64
forall a. Prim a => Vector a -> Int -> a
P.unsafeIndex Vector Word64
v Int
w
        x' :: Word64
x' = Vector Word64 -> Int -> Word64
forall a. Prim a => Vector a -> Int -> a
P.unsafeIndex Vector Word64
v' Int
w

instance Show (Bloom' h a) where
    show :: Bloom' h a -> String
show Bloom' h a
mb = String
"Bloom { " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word64 -> String
forall a. Show a => a -> String
show (Bloom' h a -> Word64
forall (h :: * -> *) a. Bloom' h a -> Word64
size Bloom' h a
mb) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" bits } "

instance NFData (Bloom' h a) where
    rnf :: Bloom' h a -> ()
rnf !Bloom' h a
_ = ()