packages feed

hw-rankselect 0.13.0.0 → 0.13.1.0

raw patch · 8 files changed

+460/−19 lines, 8 filesdep +hw-fingertreedep ~hedgehogdep ~hspecdep ~hw-balancedparensPVP ok

version bump matches the API change (PVP)

Dependencies added: hw-fingertree

Dependency ranges changed: hedgehog, hspec, hw-balancedparens, hw-prim

API changes (from Hackage documentation)

+ HaskellWorks.Data.RankSelect.BitSeq: (<|) :: Cons v => Elem v -> v -> v
+ HaskellWorks.Data.RankSelect.BitSeq: (><) :: (Semigroup v, Container v) => v -> v -> v
+ HaskellWorks.Data.RankSelect.BitSeq: (|>) :: Snoc v => v -> Elem v -> v
+ HaskellWorks.Data.RankSelect.BitSeq: BitSeq :: BitSeqFt -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: [$sel:parens:BitSeq] :: BitSeq -> BitSeqFt
+ HaskellWorks.Data.RankSelect.BitSeq: drop :: Count -> BitSeq -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: fromBools :: [Bool] -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: fromPartialWord64s :: Traversable f => f (Word64, Count) -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: fromWord64s :: Traversable f => f Word64 -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: infixl 5 |>
+ HaskellWorks.Data.RankSelect.BitSeq: infixr 5 ><
+ HaskellWorks.Data.RankSelect.BitSeq: mempty :: Monoid a => a
+ HaskellWorks.Data.RankSelect.BitSeq: newtype BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: select1 :: Select1 v => v -> Count -> Count
+ HaskellWorks.Data.RankSelect.BitSeq: size :: BitSeq -> Count
+ HaskellWorks.Data.RankSelect.BitSeq: splitAt :: Count -> BitSeq -> (BitSeq, BitSeq)
+ HaskellWorks.Data.RankSelect.BitSeq: take :: Count -> BitSeq -> BitSeq
+ HaskellWorks.Data.RankSelect.BitSeq: toBools :: BitSeq -> [Bool]
+ HaskellWorks.Data.RankSelect.BitSeq: toPartialWord64s :: BitSeq -> [(Word64, Count)]
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: (#<|) :: Elem -> BitSeqFt -> BitSeqFt
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: (|>#) :: BitSeqFt -> Elem -> BitSeqFt
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: BitSeq :: BitSeqFt -> BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: Elem :: {-# UNPACK #-} !Word64 -> {-# UNPACK #-} !Count -> Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: Measure :: {-# UNPACK #-} !Count -> {-# UNPACK #-} !Count -> Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: [$sel:elemBits:Elem] :: Elem -> {-# UNPACK #-} !Word64
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: [$sel:elemSize:Elem] :: Elem -> {-# UNPACK #-} !Count
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: [$sel:measureBitCount:Measure] :: Measure -> {-# UNPACK #-} !Count
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: [$sel:measurePopCount:Measure] :: Measure -> {-# UNPACK #-} !Count
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: [$sel:parens:BitSeq] :: BitSeq -> BitSeqFt
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: atBitCountBelow :: Count -> Measure -> Bool
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: atPopCountBelow :: Count -> Measure -> Bool
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: data Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: data Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: ftSplit :: (Measure -> Bool) -> BitSeqFt -> (BitSeqFt, BitSeqFt)
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance Control.DeepSeq.NFData HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance Control.DeepSeq.NFData HaskellWorks.Data.RankSelect.Internal.BitSeq.Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance Control.DeepSeq.NFData HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Base.Monoid HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Base.Semigroup HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Base.Semigroup HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Classes.Eq HaskellWorks.Data.RankSelect.Internal.BitSeq.Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Classes.Eq HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Classes.Ord HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Generics.Generic HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Generics.Generic HaskellWorks.Data.RankSelect.Internal.BitSeq.Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Generics.Generic HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Show.Show HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Show.Show HaskellWorks.Data.RankSelect.Internal.BitSeq.Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance GHC.Show.Show HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.Bits.PopCount.PopCount1.PopCount1 HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.Cons.Cons HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.Container.Container HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.FingerTree.Measured HaskellWorks.Data.RankSelect.Internal.BitSeq.Measure HaskellWorks.Data.RankSelect.Internal.BitSeq.Elem
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.RankSelect.Base.Rank1.Rank1 HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.RankSelect.Base.Select1.Select1 HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: instance HaskellWorks.Data.Snoc.Snoc HaskellWorks.Data.RankSelect.Internal.BitSeq.BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: newtype BitSeq
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: splitAt :: Count -> BitSeq -> (BitSeq, BitSeq)
+ HaskellWorks.Data.RankSelect.Internal.BitSeq: type BitSeqFt = FingerTree Measure Elem
+ HaskellWorks.Data.RankSelect.Internal.List: chunkBy :: Int -> [a] -> [[a]]
+ HaskellWorks.Data.RankSelect.Internal.List: toBools :: [Word64] -> [Bool]
+ HaskellWorks.Data.RankSelect.Internal.Word: partialToBoolsDiff :: Count -> Word64 -> [Bool] -> [Bool]
+ HaskellWorks.Data.RankSelect.Internal.Word: toBools :: Word64 -> [Bool]
+ HaskellWorks.Data.RankSelect.Internal.Word: toBoolsDiff :: Word64 -> [Bool] -> [Bool]

Files

+ gen/HaskellWorks/Data/RankSelect/Gen.hs view
@@ -0,0 +1,16 @@+module HaskellWorks.Data.RankSelect.Gen+  ( bitSeq+  ) where++import HaskellWorks.Data.Positioning+import HaskellWorks.Data.RankSelect.BitSeq (BitSeq)+import Hedgehog++import qualified HaskellWorks.Data.RankSelect.BitSeq as BS+import qualified Hedgehog.Gen                        as G++bools :: MonadGen m => Range Count -> m [Bool]+bools r = G.list (fmap fromIntegral r) G.bool++bitSeq :: MonadGen m => Range Count -> m BitSeq+bitSeq r = BS.fromBools <$> bools r
hw-rankselect.cabal view
@@ -1,7 +1,7 @@ cabal-version:  2.2  name:           hw-rankselect-version:        0.13.0.0+version:        0.13.1.0 synopsis:       Rank-select description:    Please see README.md category:       Data, Bit, Succinct Data Structures, Data Structures@@ -12,7 +12,7 @@ copyright:      2016-2019 John Ky license:        BSD-3-Clause license-file:   LICENSE-tested-with:    GHC == 8.4.2, GHC == 8.2.2, GHC == 8.0.2, GHC == 7.10.3+tested-with:    GHC == 8.6.5, GHC == 8.4.4, GHC == 8.2.2 build-type:     Simple extra-source-files:     README.md@@ -37,13 +37,14 @@ common deepseq              { build-depends: deepseq              >= 1.4        && < 1.5    } common directory            { build-depends: directory            >= 1.2        && < 1.5    } common generic-lens         { build-depends: generic-lens         >= 1.0.0.0    && < 1.2    }-common hedgehog             { build-depends: hedgehog             >= 0.5        && < 0.7    }+common hedgehog             { build-depends: hedgehog             >= 1.0        && < 1.1    } common hspec                { build-depends: hspec                >= 2.4        && < 2.6    }-common hw-balancedparens    { build-depends: hw-balancedparens    >= 0.1.0.0    && < 0.3    }+common hw-balancedparens    { build-depends: hw-balancedparens    >= 0.2.2.0    && < 0.3    } common hw-bits              { build-depends: hw-bits              >= 0.4.0.0    && < 0.8    }+common hw-fingertree        { build-depends: hw-fingertree        >= 0.1.1.0    && < 1.2    } common hw-hedgehog          { build-depends: hw-hedgehog          >= 0.1.0.1    && < 0.2    } common hw-hspec-hedgehog    { build-depends: hw-hspec-hedgehog    >= 0.1        && < 0.2    }-common hw-prim              { build-depends: hw-prim              >= 0.6        && < 0.8    }+common hw-prim              { build-depends: hw-prim              >= 0.6.2.23   && < 0.7    } common hw-rankselect-base   { build-depends: hw-rankselect-base   >= 0.2.0.0    && < 0.4    } common lens                 { build-depends: lens                 >= 4          && < 5      } common mmap                 { build-depends: mmap                 >= 0.5        && < 0.6    }@@ -53,7 +54,7 @@ common transformers         { build-depends: transformers         >= 0.4        && < 0.6    } common vector               { build-depends: vector               >= 0.12       && < 0.13   } -common common+common config   default-language: Haskell2010   if (impl(ghc >= 8.0.1))     ghc-options: -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints@@ -63,15 +64,16 @@   ghc-options:   -O2 -Wall -msse4.2  library-  import:   base-          , common+  import:   base, config           , deepseq           , hw-balancedparens           , hw-bits+          , hw-fingertree           , hw-prim           , hw-rankselect-base           , vector   exposed-modules:+      HaskellWorks.Data.RankSelect.BitSeq       HaskellWorks.Data.RankSelect.CsPoppy       HaskellWorks.Data.RankSelect.CsPoppy0       HaskellWorks.Data.RankSelect.CsPoppy1@@ -82,14 +84,30 @@       HaskellWorks.Data.RankSelect.CsPoppy.Internal.Nice       HaskellWorks.Data.RankSelect.CsPoppy.Internal.Reference       HaskellWorks.Data.RankSelect.CsPoppy.Internal.Vector+      HaskellWorks.Data.RankSelect.Internal.BitSeq+      HaskellWorks.Data.RankSelect.Internal.List+      HaskellWorks.Data.RankSelect.Internal.Word       HaskellWorks.Data.RankSelect.Poppy512   other-modules:    Paths_hw_rankselect   autogen-modules:  Paths_hw_rankselect   hs-source-dirs:   src +library hw-rankselect-gen+  import:   base, config+          , deepseq+          , hedgehog+          , hspec+          , hw-prim+          , vector+  exposed-modules:+    HaskellWorks.Data.RankSelect.Gen+    Paths_hw_rankselect+  build-depends:      hw-rankselect+  hs-source-dirs:     gen+  autogen-modules:    Paths_hw_rankselect+ executable hw-rankselect-  import:   base-          , common+  import:   base, config           , directory           , generic-lens           , hw-bits@@ -116,8 +134,7 @@   ghc-options:        -threaded -rtsopts -with-rtsopts=-N  test-suite hw-rankselect-test-  import:   base-          , common+  import:   base, config           , QuickCheck           , directory           , hedgehog@@ -136,6 +153,7 @@   other-modules:       HaskellWorks.Data.RankSelect.BasicGen       HaskellWorks.Data.RankSelect.BinarySearchSpec+      HaskellWorks.Data.RankSelect.BitSeqSpec       HaskellWorks.Data.RankSelect.CsPoppy.InternalSpec       HaskellWorks.Data.RankSelect.CsPoppySpec       HaskellWorks.Data.RankSelect.Gen@@ -152,8 +170,7 @@   ghc-options:        -threaded -rtsopts -with-rtsopts=-N  benchmark bench-  import:   base-          , common+  import:   base, config           , bytestring                   , conduit           , criterion
+ src/HaskellWorks/Data/RankSelect/BitSeq.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module HaskellWorks.Data.RankSelect.BitSeq+  ( BitSeq(..)+  , mempty+  , size+  , fromWord64s+  , fromPartialWord64s+  , toPartialWord64s+  , fromBools+  , toBools+  , BS.splitAt+  , take+  , drop+  , (<|), (><), (|>)+  , select1+  ) where++import Data.Coerce+import Data.Foldable+import Data.Monoid+import Data.Word+import HaskellWorks.Data.Bits.BitWise+import HaskellWorks.Data.FingerTree                 (ViewL (..), ViewR (..), (<|), (><), (|>))+import HaskellWorks.Data.Positioning+import HaskellWorks.Data.RankSelect.Base.Select1    (select1)+import HaskellWorks.Data.RankSelect.Internal.BitSeq (BitSeq (BitSeq), BitSeqFt, Elem (Elem))+import Prelude                                      hiding (drop, max, min, splitAt, take)++import qualified Data.List                                    as L+import qualified HaskellWorks.Data.FingerTree                 as FT+import qualified HaskellWorks.Data.RankSelect.Internal.BitSeq as BS+import qualified HaskellWorks.Data.RankSelect.Internal.Word   as W++empty :: BitSeq+empty = BitSeq FT.empty++size :: BitSeq -> Count+size (BitSeq parens) = BS.measureBitCount (FT.measure parens)++-- TODO Needs optimisation+fromWord64s :: Traversable f => f Word64 -> BitSeq+fromWord64s = foldl go empty+  where go :: BitSeq -> Word64 -> BitSeq+        go ps w = BitSeq (BS.parens ps |> Elem w 64)++-- TODO Needs optimisation+fromPartialWord64s :: Traversable f => f (Word64, Count) -> BitSeq+fromPartialWord64s = foldl go empty+  where go :: BitSeq -> (Word64, Count) -> BitSeq+        go ps (w, n) = BitSeq (BS.parens ps |> Elem w n)++toPartialWord64s :: BitSeq -> [(Word64, Count)]+toPartialWord64s = L.unfoldr go . coerce+  where go :: BitSeqFt -> Maybe ((Word64, Count), BitSeqFt)+        go ft = case FT.viewl ft of+          BS.Elem w n :< rt -> Just ((w, coerce n), rt)+          FT.EmptyL         -> Nothing++fromBools :: [Bool] -> BitSeq+fromBools = go empty+  where go :: BitSeq -> [Bool] -> BitSeq+        go (BitSeq ps) (b:bs) = case FT.viewr ps of+          FT.EmptyR      -> go (BitSeq (FT.singleton (Elem b' 1))) bs+          lt :> Elem w n ->+            let newPs = if n >= 64+                then ps |> Elem b' 1+                else lt |> Elem (w .|. (b' .<. fromIntegral n)) (n + 1)+            in go (BitSeq newPs) bs+          where b' = if b then 1 else 0 :: Word64+        go ps [] = ps++toBools :: BitSeq -> [Bool]+toBools ps = toBoolsDiff ps []++toBoolsDiff :: BitSeq -> [Bool] -> [Bool]+toBoolsDiff ps = mconcat (fmap go (toPartialWord64s ps))+  where go :: (Word64, Count) -> [Bool] -> [Bool]+        go (w, n) = W.partialToBoolsDiff (fromIntegral n) w++drop :: Count -> BitSeq -> BitSeq+drop n ps = snd (BS.splitAt n ps)++take :: Count -> BitSeq -> BitSeq+take n ps = fst (BS.splitAt n ps)
+ src/HaskellWorks/Data/RankSelect/Internal/BitSeq.hs view
@@ -0,0 +1,152 @@+{-# 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++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)
+ src/HaskellWorks/Data/RankSelect/Internal/List.hs view
@@ -0,0 +1,18 @@+module HaskellWorks.Data.RankSelect.Internal.List+  ( chunkBy+  , toBools+  ) where++import Data.Word++import qualified HaskellWorks.Data.BalancedParens.Internal.Word as W++chunkBy :: Int -> [a] -> [[a]]+chunkBy n bs = case (take n bs, drop n bs) of+  (as, zs) -> if null zs then [as] else as:chunkBy n zs++toBoolsDiff :: [Word64] -> [Bool] -> [Bool]+toBoolsDiff = foldr ((.) . W.toBoolsDiff) id++toBools :: [Word64] -> [Bool]+toBools ws = toBoolsDiff ws []
+ src/HaskellWorks/Data/RankSelect/Internal/Word.hs view
@@ -0,0 +1,30 @@+module HaskellWorks.Data.RankSelect.Internal.Word+  ( toBools+  , toBoolsDiff+  , partialToBoolsDiff+  ) where++import Data.Word+import HaskellWorks.Data.Bits.BitWise+import HaskellWorks.Data.Positioning++toBools :: Word64 -> [Bool]+toBools w = toBoolsDiff w []++partialToBoolsDiff :: Count -> Word64 -> [Bool] -> [Bool]+partialToBoolsDiff n w | n > 0 = partialToBoolsDiff (n - 1) w . ((w .?. fromIntegral (n - 1)):)+partialToBoolsDiff 0 _ = id+partialToBoolsDiff _ _ = error "Invalid size"++toBoolsDiff :: Word64 -> [Bool] -> [Bool]+toBoolsDiff w =+  go 0x00 . go 0x01 . go 0x02 . go 0x03 . go 0x04 . go 0x05 . go 0x06 . go 0x07 .+  go 0x08 . go 0x09 . go 0x0a . go 0x0b . go 0x0c . go 0x0d . go 0x0e . go 0x0f .+  go 0x10 . go 0x11 . go 0x12 . go 0x13 . go 0x14 . go 0x15 . go 0x16 . go 0x17 .+  go 0x18 . go 0x19 . go 0x1a . go 0x1b . go 0x1c . go 0x1d . go 0x1e . go 0x1f .+  go 0x20 . go 0x21 . go 0x22 . go 0x23 . go 0x24 . go 0x25 . go 0x26 . go 0x27 .+  go 0x28 . go 0x29 . go 0x2a . go 0x2b . go 0x2c . go 0x2d . go 0x2e . go 0x2f .+  go 0x30 . go 0x31 . go 0x32 . go 0x33 . go 0x34 . go 0x35 . go 0x36 . go 0x37 .+  go 0x38 . go 0x39 . go 0x3a . go 0x3b . go 0x3c . go 0x3d . go 0x3e . go 0x3f+  where go :: Position -> [Bool] -> [Bool]+        go p = ((w .?. p):)
+ test/HaskellWorks/Data/RankSelect/BitSeqSpec.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE ScopedTypeVariables        #-}++module HaskellWorks.Data.RankSelect.BitSeqSpec where++import Data.Semigroup                            ((<>))+import HaskellWorks.Data.Bits.PopCount.PopCount1+import HaskellWorks.Data.RankSelect.Base.Rank1+import HaskellWorks.Data.RankSelect.Base.Select1+import HaskellWorks.Data.RankSelect.BitSeq       ((<|), (><), (|>))+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified HaskellWorks.Data.RankSelect.BitSeq        as BS+import qualified HaskellWorks.Data.RankSelect.Gen           as G+import qualified HaskellWorks.Data.RankSelect.Internal.List as L+import qualified Hedgehog.Gen                               as G+import qualified Hedgehog.Range                             as R++{-# ANN module ("HLint: Ignore Redundant do"        :: String) #-}+{-# ANN module ("HLint: Ignore Reduce duplication"  :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.Data.RankSelect.Internal.BitSeqSpec" $ do+  it "fromWord64s should produce Rmm of the right size" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)++    BS.size (BS.fromWord64s ws) === fromIntegral (length ws * 64)+  it "fromWord64s should produce Rmm with the right data" $ requireProperty $ do+    wns <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.word64 R.constantBounded+      <*> G.count (R.linear 1 64)++    BS.size (BS.fromPartialWord64s wns) === sum (snd <$> wns)+  it "fromWord64s should produce Rmm with the right data" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)++    BS.toPartialWord64s (BS.fromWord64s ws) === zip ws (repeat 64)+  it "fromPartialWord64s should produce Rmm with the right data" $ requireProperty $ do+    wns <- forAll $ G.list (R.linear 0 10) $ (,)+      <$> G.word64 R.constantBounded+      <*> G.count (R.linear 1 64)++    BS.toPartialWord64s (BS.fromPartialWord64s wns) === wns+  it "fromBools should produce Rmm with the right data" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)++    BS.toPartialWord64s (BS.fromBools (L.toBools ws)) === zip ws (repeat 64)+  it "drop should drop the right amount of data" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)+    let ps = BS.fromWord64s ws+    n  <- forAll $ G.count (R.linear 0 (BS.size ps))++    BS.size (BS.drop n ps) === BS.size ps - n+  it "take should take the right amount of data" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)+    let ps = BS.fromWord64s ws+    n  <- forAll $ G.count (R.linear 0 (BS.size ps))++    BS.size (BS.take n ps) === n+  it "splitAt should split at the correct point" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)+    let ps = BS.fromWord64s ws+    n  <- forAll $ G.count (R.linear 0 (BS.size ps))++    let (lt, rt) = BS.splitAt n ps+    BS.size lt === n+    BS.size rt === BS.size ps - n+    BS.toBools lt >< BS.toBools rt === BS.toBools ps+  it "firstChild should choose the first child" $ requireProperty $ do+    ws <- forAll $ G.list (R.linear 0 10) (G.word64 R.constantBounded)+    let ps = BS.fromWord64s ws+    n  <- forAll $ G.count (R.linear 0 (BS.size ps))++    BS.size (BS.drop n ps) === BS.size ps - n+  it "rose tree should be generatable" $ requireProperty $ do+    bs <- forAll $ G.list (R.linear 1 1000) G.bool++    BS.toBools (BS.fromBools bs) === bs+  it "(><) should append" $ requireTest $ do+    bs1       <- forAll $ G.list (R.linear 1 1000) G.bool+    bs2       <- forAll $ G.list (R.linear 1 1000) G.bool+    ps1       <- forAll $ pure $ BS.fromBools bs1+    ps2       <- forAll $ pure $ BS.fromBools bs2++    BS.toBools (ps1 >< ps2) === BS.toBools ps1 >< BS.toBools ps2+  it "(<|) should cons" $ requireTest $ do+    b         <- forAll $ G.bool+    bs        <- forAll $ G.list (R.linear 1 1000) G.bool+    ps        <- forAll $ pure $ BS.fromBools bs++    BS.toBools (b <| ps) === b:BS.toBools ps+  it "(|>) should snoc" $ requireTest $ do+    b         <- forAll $ G.bool+    bs        <- forAll $ G.list (R.linear 1 1000) G.bool+    ps        <- forAll $ pure $ BS.fromBools bs++    BS.toBools (ps |> b) === BS.toBools ps <> [b]+  it "select1" $ requireTest $ do+    n         <- forAll $ G.count (R.linear 0 1000)+    bools     <- forAll $ G.list (R.singleton (fromIntegral n)) G.bool+    bs        <- forAll $ pure $ BS.fromBools bools+    i         <- forAll $ G.count (R.linear 0 n)++    select1 bools i === select1 bs i+  it "rank1" $ requireTest $ do+    n         <- forAll $ G.count (R.linear 0 1000)+    bools     <- forAll $ G.list (R.singleton (fromIntegral n)) G.bool+    bs        <- forAll $ pure $ BS.fromBools bools+    i         <- forAll $ G.count (R.linear 0 (popCount1 bools))++    rank1 bools i === rank1 bs i+  it "popCount1" $ requireTest $ do+    bools     <- forAll $ G.list (R.linear 0 1000) G.bool+    bs        <- forAll $ pure $ BS.fromBools bools++    popCount1 bools === popCount1 bs
test/HaskellWorks/Data/RankSelect/InternalSpec.hs view
@@ -1,8 +1,10 @@-{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}+ module HaskellWorks.Data.RankSelect.InternalSpec (spec) where +import Data.Maybe import HaskellWorks.Data.Bits.BitRead import HaskellWorks.Data.Bits.PopCount.PopCount1 import HaskellWorks.Data.RankSelect.Base.Rank@@ -22,16 +24,16 @@ spec = describe "HaskellWorks.Data.RankSelect.InternalSpec" $ do   describe "For [Bool]" $ do     it "rank True 10010010 over [0..8] should be 011122233" $ requireProperty $ do-      let (Just bs) = bitRead "10010010" :: Maybe [Bool]+      let bs = fromJust $ bitRead "10010010" :: [Bool]       fmap (rank True bs) [0..8] === [0, 1, 1, 1, 2, 2, 2, 3, 3]     it "rank True 10010010 over [0..8] should be 001223445" $ requireProperty $ do-      let (Just bs) = bitRead "10010010" :: Maybe [Bool]+      let bs = fromJust $ bitRead "10010010" :: [Bool]       fmap (rank False bs) [0..8] === [0, 0, 1, 2, 2, 3, 4, 4, 5]     it "select True 10010010 over [0..3] should be 0147" $ requireProperty $ do-      let (Just bs) = bitRead "10010010" :: Maybe [Bool]+      let bs = fromJust $ bitRead "10010010" :: [Bool]       fmap (select True bs) [0..3] === [0, 1, 4, 7]     it "select False 10010010 over [0..5] should be 023568" $ requireProperty $ do-      let (Just bs) = bitRead "10010010" :: Maybe [Bool]+      let bs = fromJust $ bitRead "10010010" :: [Bool]       fmap (select False bs) [0..5] === [0, 2, 3, 5, 6, 8]     it "Rank and select form a galois connection" $ requireProperty $ do       bs <- forAll $ G.list (R.linear 0 70) G.bool