#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706
#define USE_TYPE_LITS 1
#endif
module Data.HyperLogLog.Config
(
Config
, HasConfig(..)
, hll
, numBits, numBuckets, smallRange, interRange, rawFact, alpha, bucketMask
, ReifiesConfig(..)
, reifyConfig
, Rank
, calcBucket
, calcRank
, lim32
) where
import Control.Lens
import Data.Bits
import Data.Bits.Extras
import Data.Proxy
import Data.Reflection
import Data.Serialize
import Data.Vector.Serialize ()
import GHC.Int
import GHC.Word
import Generics.Deriving hiding (to, D)
#ifdef USE_TYPE_LITS
import GHC.TypeLits
#endif
type Rank = Int8
data Config = Config
{ _numBits :: !Int
, _numBuckets :: !Int
, _smallRange :: !Double
, _interRange :: !Double
, _rawFact :: !Double
, _alpha :: !Double
, _bucketMask :: !Word32
} deriving (Eq, Show, Generic)
class HasConfig t where
config :: Getter t Config
makeLensesWith ?? ''Config $ classyRules
& generateSignatures .~ False
& createClass .~ False
& createInstance .~ False
instance HasConfig Config where
config = id
instance Serialize Config
hll :: Int -> Config
hll b = Config
{ _numBits = b
, _numBuckets = m
, _smallRange = 5/2 * m'
, _interRange = lim32 / 30
, _rawFact = a * m' * m'
, _alpha = a
, _bucketMask = bit b 1
} where
m = bit b
m' = fromIntegral m
a = 0.7213 / (1 + 1.079 / m')
class ReifiesConfig o where
reflectConfig :: p o -> Config
#ifdef USE_TYPE_LITS
instance SingRep n Integer => ReifiesConfig (n :: Nat) where
reflectConfig _ = hll $ fromInteger $ withSing $ \(x :: Sing n) -> fromSing x
#endif
data ReifiedConfig (s :: *)
retagReifiedConfig :: (Proxy s -> a) -> proxy (ReifiedConfig s) -> a
retagReifiedConfig f _ = f Proxy
instance Reifies s Config => ReifiesConfig (ReifiedConfig s) where
reflectConfig = retagReifiedConfig reflect
reifyConfig :: Int -> (forall (o :: *). ReifiesConfig o => Proxy o -> r) -> r
reifyConfig i f = reify (hll i) (go f) where
go :: Reifies o Config => (Proxy (ReifiedConfig o) -> a) -> proxy o -> a
go g _ = g Proxy
instance Reifies n Int => ReifiesConfig (D n) where
reflectConfig = hll . reflect
instance Reifies n Int => ReifiesConfig (SD n) where
reflectConfig = hll . reflect
calcBucket :: HasConfig t => t -> Word32 -> Int
calcBucket t w = fromIntegral (w .&. t^.bucketMask)
calcRank :: HasConfig t => t -> Word32 -> Int8
calcRank t w = fromIntegral $ rank $ shiftR w $ t^.numBits
lim32 :: Double
lim32 = fromInteger (bit 32)