hw-rankselect-0.13.3.1: src/HaskellWorks/Data/RankSelect/Internal/BitSeq.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module HaskellWorks.Data.RankSelect.Internal.BitSeq
( Elem(..)
, Measure(..)
, BitSeq(..)
, BitSeqFt
, (|>#)
, (#<|)
, ftSplit
, atBitCountBelow
, atPopCountBelow
, splitAt
) where
import Control.DeepSeq
import Data.Monoid (Monoid)
import Data.Semigroup (Semigroup (..))
import Data.Word
import GHC.Generics
import HaskellWorks.Data.Bits.BitWise
import HaskellWorks.Data.Bits.PopCount.PopCount1
import HaskellWorks.Data.FingerTree (ViewL (..), ViewR (..), (<|), (><), (|>))
import HaskellWorks.Data.Positioning
import HaskellWorks.Data.RankSelect.Base.Rank1
import HaskellWorks.Data.RankSelect.Base.Select1
import Prelude hiding (max, min, splitAt)
import qualified HaskellWorks.Data.Cons as HW
import qualified HaskellWorks.Data.Container as HW
import qualified HaskellWorks.Data.FingerTree as FT
import qualified HaskellWorks.Data.Snoc as HW
data Elem = Elem
{ elemBits :: {-# UNPACK #-} !Word64
, elemSize :: {-# UNPACK #-} !Count
} deriving (Eq, Show, Generic)
instance NFData Elem
data Measure = Measure
{ measureBitCount :: {-# UNPACK #-} !Count
, measurePopCount :: {-# UNPACK #-} !Count
} deriving (Eq, Ord, Show, Generic)
instance NFData Measure
type BitSeqFt = FT.FingerTree Measure Elem
newtype BitSeq = BitSeq
{ parens :: BitSeqFt
} deriving (Show, NFData, Generic)
instance Semigroup Measure where
a <> b = Measure
{ measureBitCount = measureBitCount a + measureBitCount b
, measurePopCount = measurePopCount a + measurePopCount b
}
instance Monoid Measure where
mempty = Measure 0 0
mappend = (<>)
instance FT.Measured Measure Elem where
measure (Elem w size) = Measure
{ measureBitCount = size
, measurePopCount = popCount1 w
}
instance HW.Container BitSeq where
type Elem BitSeq = Bool
instance HW.Cons BitSeq where
cons b (BitSeq ft) = BitSeq $ case FT.viewl ft of
Elem w nw :< rt -> if nw >= 0 && nw < 64
then Elem ((w .<. 1) .|. bw) (nw + 1) <| rt
else Elem bw 1 <| ft
FT.EmptyL -> FT.singleton (Elem bw 1)
where bw = if b then 1 else 0
instance HW.Snoc BitSeq where
snoc (BitSeq ft) b = BitSeq $ case FT.viewr ft of
lt :> Elem w nw -> if nw >= 0 && nw < 64
then Elem (w .|. (bw .<. nw)) (nw + 1) <| lt
else Elem bw 1 <| lt
FT.EmptyR -> FT.singleton (Elem bw 1)
where bw = if b then 1 else 0
instance Semigroup BitSeq where
BitSeq tl <> BitSeq tr = BitSeq $ case FT.viewr tl of
tll :> Elem wl nwl -> case FT.viewl tr of
Elem wr nwr :< trr -> let nw = nwl + nwr in if nw <= 64
then (tll |> Elem (wl .|. (wr .<. nwl)) nw) >< trr
else tl >< tr
FT.EmptyL -> tr
FT.EmptyR -> FT.empty
instance Select1 BitSeq where
select1 (BitSeq ft) n = case FT.split (atPopCountBelow n) ft of
(lt, _) -> case FT.viewr lt of
FT.EmptyR -> 0
llt :> Elem w _ ->
let llpc = measurePopCount (FT.measure llt :: Measure) in
let llbc = measureBitCount (FT.measure llt :: Measure) in
llbc + select1 w (n - llpc)
instance Rank1 BitSeq where
rank1 bs n = let (lt, _) = splitAt n bs in popCount1 lt
instance PopCount1 BitSeq where
popCount1 (BitSeq ft) = measureBitCount (FT.measure ft :: Measure)
(|>#) :: BitSeqFt -> Elem -> BitSeqFt
(|>#) ft e@(Elem _ wn) = if wn > 0 then ft |> e else ft
(#<|) :: Elem ->BitSeqFt -> BitSeqFt
(#<|) e@(Elem _ wn) ft = if wn > 0 then e <| ft else ft
ftSplit :: (Measure -> Bool) -> BitSeqFt -> (BitSeqFt, BitSeqFt)
ftSplit p ft = case FT.viewl rt of
Elem w nw :< rrt -> let c = go w nw nw in (lt |># Elem w c, Elem (w .>. c) (nw - c) #<| rrt)
FT.EmptyL -> (ft, FT.empty)
where (lt, rt) = FT.split p ft
ltm = FT.measure lt
go :: Word64 -> Count -> Count -> Count
go w c nw = if c > 0
then if p (ltm <> FT.measure (Elem (w .<. (64 - c) .>. (64 - c)) c))
then go w (c - 1) nw
else c
else 0
atBitCountBelow :: Count -> Measure -> Bool
atBitCountBelow n m = n < measureBitCount (m :: Measure)
atPopCountBelow :: Count -> Measure -> Bool
atPopCountBelow n m = n < measurePopCount (m :: Measure)
splitAt :: Count -> BitSeq -> (BitSeq, BitSeq)
splitAt n (BitSeq ft) = case FT.split (atBitCountBelow n) ft of
(lt, rt) -> let
n' = n - measureBitCount (FT.measure lt)
u = 64 - n'
in case FT.viewl rt of
Elem w nw :< rrt -> if n' >= nw
then (BitSeq lt , BitSeq rrt )
else (BitSeq (lt |> Elem ((w .<. u) .>. u) n'), BitSeq (Elem (w .>. n') (nw - n') <| rrt))
FT.EmptyL -> (BitSeq lt, BitSeq FT.empty)