5 -- | Lazy bitstrings based on 'L.ByteString' which treats a byte
6 -- stream as a bit sequence in the same way as WavPack's manner.
7 module Codec.Audio.WavPack.BitString
8 ( -- * The BitString Type
24 -- * Conversion from/to 'L.ByteString'
29 import qualified Data.ByteString.Lazy as L
32 import qualified Data.Strict as S
34 import Prelude hiding (head, length, null, tail)
35 import Prelude.Unicode
37 -- | The BitString Type.
41 , leftBytes ∷ !L.ByteString
43 , rightBytes ∷ !L.ByteString
50 -- | bit length from 0 to 8
58 remEmpty = Remnant 0 0
60 remNull ∷ Remnant → Bool
61 remNull = (0 ≡) ∘ remLen
63 remSingleton ∷ Bool -> Remnant
64 remSingleton b = Remnant {
66 , remByte = if b then 1 else 0
69 byteToRem ∷ Word8 → Remnant
70 byteToRem w = Remnant {
75 remToStr ∷ Remnant → L.ByteString
78 | otherwise = L.singleton $ remByte r
80 consRem ∷ Bool → Remnant → (# Remnant, S.Maybe Word8 #)
82 | remLen r ≡ 8 = (# remSingleton b, S.Just $ remByte r #)
83 | remLen r ≡ 7 = (# remEmpty, S.Just w' #)
84 | otherwise = let !r' = r {
91 w' = (remByte r `shiftR` 1)
95 snocRem ∷ Remnant → Bool → (# S.Maybe Word8, Remnant #)
97 | remLen r ≡ 8 = (# S.Just $ remByte r, remSingleton b #)
98 | remLen r ≡ 7 = (# S.Just w', remEmpty #)
99 | otherwise = let !r' = r {
100 remLen = remLen r + 1
106 w' | b = bit (remLen r) .|. remByte r
107 | otherwise = remByte r
109 unconsRem ∷ Remnant → (# S.Maybe Bool, Remnant #)
111 | remNull r = (# S.Nothing, remEmpty #)
112 | otherwise = let !b = remByte r `testBit` 1
114 remLen = remLen r - 1
115 , remByte = remByte r `shiftR` 1
120 unconsBytes ∷ L.ByteString → (# S.Maybe Remnant, L.ByteString #)
122 = case L.uncons bs of
124 → (# S.Just (byteToRem w), bs' #)
126 → (# S.Nothing, L.empty #)
128 -- | /O(1)/ The empty 'BitString'.
132 , leftBytes = L.empty
133 , rightBytes = L.empty
134 , rightRem = remEmpty
137 -- | /O(1)/ Convert a 'Bool' into a 'BitString'.
138 singleton ∷ Bool → BitString
139 singleton b = BitString {
140 leftRem = remSingleton b
141 , leftBytes = L.empty
142 , rightBytes = L.empty
143 , rightRem = remEmpty
146 -- | /O(1)/ Prepend a bit to the beginning of a 'BitString'.
147 cons ∷ Bool → BitString → BitString
149 = case consRem b $ leftRem bs of
153 , leftBytes = L.cons' w $ leftBytes bs
157 → bs { leftRem = lr' }
159 -- | /O(1)/ Append a bit to the end of a 'BitString'.
160 snoc ∷ BitString → Bool → BitString
162 = case snocRem (rightRem bs) b of
165 rightBytes = L.cons' w $ rightBytes bs
170 → bs { rightRem = rr' }
172 -- | /amortized O(1)/ Extract the first bit of a 'BitString', which
173 -- must be non-empty.
174 head ∷ BitString → Bool
175 head bs = case uncons bs of
179 → error "head: empty BitString"
181 -- | /amortized O(1)/ Extract the bits after the head of a
182 -- 'BitString', which must be non-empty.
183 tail ∷ BitString → BitString
184 tail bs = case uncons bs of
188 → error "tail: empty BitString"
190 -- | /amortized O(1)/ Extract the the head and tail of a 'BitString',
191 -- returning 'Nothing' if it's empty.
192 uncons ∷ BitString → Maybe (Bool, BitString)
194 = case unconsRem $ leftRem bs of
196 → Just (b, bs { leftRem = lr' })
199 → case unconsBytes $ leftBytes bs of
201 → let !bs' = bs { leftRem = lr
208 → if L.null $ rightBytes bs then
209 case unconsRem $ rightRem bs of
211 → Just (b, bs { rightRem = rr' })
216 let !bs' = bs { leftBytes = L.reverse
222 -- | /O(1)/ Test whether a 'BitString' is empty.
223 null ∷ BitString → Bool
225 = remLen (leftRem bs) ≡ 0
227 L.null (leftBytes bs)
229 L.null (rightBytes bs)
231 remLen (rightRem bs) ≡ 0
233 -- | /O(n)/ Return the number of bits in a 'BitString'.
234 length ∷ Integral n ⇒ BitString → n
236 = fromIntegral $ ( fromIntegral (remLen $ leftRem bs)
238 L.length (leftBytes bs) ⋅ 8
240 L.length (rightBytes bs) ⋅ 8
242 fromIntegral (remLen $ rightRem bs)
244 {-# SPECIALISE length ∷ BitString → Int64 #-}
246 -- | /O(1)/ Convert a 'L.ByteString' into a 'BitString'.
247 fromByteString ∷ L.ByteString → BitString
248 fromByteString bs = BitString {
251 , rightBytes = L.empty
252 , rightRem = remEmpty
255 -- | /O(n)/ Convert a 'BitString' into 'L.ByteString', padding
256 -- incomplete bytes to single bytes with necessary 0's at their
257 -- MSB. Thus the following equation does not hold when the length of
258 -- 'BitString' isn't multiple of 8.
260 -- > fromByteString . toByteString = id
262 -- But the following always holds true.
264 -- > toByteString . fromByteString = id
265 toByteString ∷ BitString → L.ByteString
267 = L.concat [ remToStr $ leftRem bs
269 , L.reverse $ rightBytes bs
270 , remToStr $ rightRem bs