data-sketches-core-0.2.0.0: src/DataSketches/Distinct/HyperLogLog/Internal.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module DataSketches.Distinct.HyperLogLog.Internal
( HllSketch
, mkHllSketch
, hllInsert
, hllInsertBatch
, hllEstimate
, hllMerge
, hllPrecision
) where
import Control.DeepSeq (NFData(..))
import Control.Monad (when)
import Control.Monad.Primitive
import Data.Word
import qualified Data.Vector.Storable as VS
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr
newtype HllSketch s = HllSketch (ForeignPtr (HllSketch s))
instance NFData (HllSketch s) where rnf !_ = ()
foreign import ccall unsafe "hll_new" c_hll_new :: CInt -> IO (Ptr (HllSketch s))
foreign import ccall unsafe "&hll_free" c_hll_free :: FunPtr (Ptr (HllSketch s) -> IO ())
foreign import ccall unsafe "hll_c_insert" c_hll_insert :: Ptr (HllSketch s) -> Word64 -> IO ()
foreign import ccall unsafe "hll_c_insert_batch" c_hll_insert_batch :: Ptr (HllSketch s) -> Ptr Word64 -> CInt -> IO ()
foreign import ccall unsafe "hll_c_estimate" c_hll_estimate :: Ptr (HllSketch s) -> IO CDouble
foreign import ccall unsafe "hll_c_merge" c_hll_merge :: Ptr (HllSketch s) -> Ptr (HllSketch s) -> IO ()
foreign import ccall unsafe "hll_c_precision" c_hll_precision :: Ptr (HllSketch s) -> IO CInt
mkHllSketch :: PrimMonad m => Int -> m (HllSketch (PrimState m))
mkHllSketch p = unsafePrimToPrim $ do
when (p < 4 || p > 26) $ error "HLL: precision must be in [4, 26]"
ptr <- c_hll_new (fromIntegral p)
fp <- newForeignPtr c_hll_free ptr
pure (HllSketch fp)
hllPrecision :: PrimMonad m => HllSketch (PrimState m) -> m Int
hllPrecision (HllSketch sk) = unsafePrimToPrim $ withForeignPtr sk $ fmap fromIntegral . c_hll_precision
hllInsert :: PrimMonad m => HllSketch (PrimState m) -> Word64 -> m ()
hllInsert (HllSketch sk) !item = unsafePrimToPrim $ withForeignPtr sk $ \p -> c_hll_insert p item
{-# INLINE hllInsert #-}
hllInsertBatch :: PrimMonad m => HllSketch (PrimState m) -> VS.Vector Word64 -> m ()
hllInsertBatch (HllSketch sk) vals = unsafePrimToPrim $ withForeignPtr sk $ \p ->
VS.unsafeWith vals $ \arr ->
c_hll_insert_batch p arr (fromIntegral $ VS.length vals)
hllEstimate :: PrimMonad m => HllSketch (PrimState m) -> m Double
hllEstimate (HllSketch sk) = unsafePrimToPrim $ withForeignPtr sk $ fmap realToFrac . c_hll_estimate
hllMerge :: PrimMonad m => HllSketch (PrimState m) -> HllSketch (PrimState m) -> m ()
hllMerge (HllSketch this) (HllSketch other) = unsafePrimToPrim $
withForeignPtr this $ \pd -> withForeignPtr other $ \ps -> c_hll_merge pd ps