{-|
Module      : Data.CuckooFilter.Mutable
Copyright   : (c) Chris Coffey, 2018
License     : MIT
Maintainer  : chris@foldl.io
Stability   : experimental

An unboxed, mutable array implementation of the cuckoo filter. This is quite space efficient,
using only x% of the memory the pure IntMap implementation uses. Prefer this if you need memory
or cpu performance.
-}

module Data.CuckooFilter.Mutable (
    MFilter
    ) where

import Data.CuckooFilter.Internal (CuckooFilter(..), Bucket(..), Size(..), emptyBucket)

import Control.Monad.ST (stToIO)
import Data.Aeson (ToJSON, FromJSON)
import qualified Data.Array.IO as IOA
import qualified Data.Array.MArray as A
import Data.Serialize (Serialize)
import Data.Word (Word32, Word8)
import GHC.Generics (Generic)
import Numeric.Natural (Natural)

-- Write it in IO first
-- Given a mutable array, can I actually fix a C array & use that?

data MFilter a = MF {
    buckets :: IOA.IOUArray Int Word32,
    size :: !Size,
    numBuckets :: !Natural
    }
    deriving (Eq)

instance CuckooFilter MFilter IO where
    initialize (Size s) = do
        rawArray <- A.newArray (0::Int, fromIntegral nb) 0
        pure MF {
            buckets = rawArray,
            size = Size s,
            numBuckets = nb
            }
        where
            nb = s `div` 4

    {-# INLINE bucketCount #-}
    bucketCount MF { numBuckets } = pure numBuckets

    {-# INLINE writeBucket #-}
    writeBucket index (B val) filt = do
        A.writeArray (buckets filt) index val
        pure filt

    {-# INLINE readBucket #-}
    readBucket index filt =
        B <$> A.readArray (buckets filt)index