@@ -19,9 +19,7 @@ import Control.Monad (replicateM, (>=>))
1919import Control.Monad.Trans.Class (lift )
2020import Control.Monad.Trans.State.Strict (StateT , evalStateT )
2121import qualified Control.Monad.Trans.State.Strict as St
22- import Data.Bits (shiftL , shiftR , testBit )
23- import Data.Bitstream (Bitstream , Right )
24- import qualified Data.Bitstream as BiS
22+ import Data.Bits (clearBit , setBit , shiftL , shiftR , testBit )
2523import Data.Bool (bool )
2624import Data.ByteArray.Hash (
2725 SipHash (.. ),
@@ -30,6 +28,7 @@ import Data.ByteArray.Hash (
3028 )
3129import Data.ByteString (ByteString )
3230import qualified Data.ByteString as BS
31+ import qualified Data.ByteString.Lazy as BSL
3332import Data.Foldable (foldl' )
3433import Data.List (sort )
3534import Data.Serialize (
@@ -72,8 +71,8 @@ paramM = 784931
7271
7372-- | Hashes of scripts in the block
7473newtype BlockFilter = BlockFilter
75- { -- | Get the list of hashes in increasing order
76- blockFilter :: [ Word64 ]
74+ { blockFilter :: [ Word64 ]
75+ -- ^ Get the list of hashes in increasing order
7776 }
7877 deriving (Eq , Show )
7978
@@ -221,15 +220,45 @@ toSet = dedup . sort
221220 | otherwise -> x0 : dedup xs
222221 xs -> xs
223222
223+ {- | Golomb coded sets are not naturally expressed in bytes, but rather as a bit
224+ stream
225+ -}
226+ data Bitstream
227+ = Bitstream
228+ BSL. ByteString
229+ -- ^ Complete bytes written so far, in reverse order
230+ {- # UNPACK #-} !Word8
231+ -- ^ The current work byte
232+ {- # UNPACK #-} !Int
233+ -- ^ Pointer to the first open bit
234+
235+ emptyB :: Bitstream
236+ emptyB = Bitstream mempty 0 7
237+
238+ appendBit :: Bool -> Bitstream -> Bitstream
239+ appendBit b (Bitstream bytes inFlight cursor)
240+ | cursor == 0 = Bitstream (BSL. cons nextInFlight bytes) 0 7
241+ | otherwise = Bitstream bytes nextInFlight (cursor - 1 )
242+ where
243+ nextInFlight = bool clearBit setBit b inFlight cursor
244+
245+ asByteString :: Bitstream -> ByteString
246+ asByteString (Bitstream bytes inFlight cursor) =
247+ BSL. toStrict $ BSL. reverse paddedBytes
248+ where
249+ paddedBytes
250+ | cursor == 7 = bytes
251+ | otherwise = BSL. cons inFlight bytes
252+
224253constructGCS ::
225254 -- | modulus
226255 Int ->
227256 -- | sorted list of input values
228257 [Word64 ] ->
229258 ByteString
230259constructGCS p =
231- BiS. toByteString
232- . foldMap (golombRiceEncode p)
260+ asByteString
261+ . foldl' (golombRiceEncode p) emptyB
233262 . diffs
234263
235264diffs :: Num a => [a ] -> [a ]
@@ -239,12 +268,12 @@ unDiffs :: Num a => [a] -> [a]
239268unDiffs (x : xs) = scanl (+) x xs
240269unDiffs [] = []
241270
242- golombRiceEncode :: Int -> Word64 -> Bitstream Right
243- golombRiceEncode p v = x <> BiS. singleton False <> y
271+ golombRiceEncode :: Int -> Bitstream -> Word64 -> Bitstream
272+ golombRiceEncode p b v = foldl' ( flip nextBit) prefix [p - i | i <- [ 1 .. p]]
244273 where
245274 q = fromIntegral $ v `shiftR` p
246- x = BiS. replicate q True
247- y = BiS. fromNBits p v
275+ prefix = appendBit False $ iterate (appendBit True ) b !! q
276+ nextBit = appendBit . testBit v
248277
249278fromBits :: Num a => [Bool ] -> a
250279fromBits = foldl' onBit 0
0 commit comments