module Data.Bitstream.Packet
( Left
, Right
, Packet
, full
, fromOctet
, toOctet
, packetLToR
, packetRToL
)
where
import Data.Bitstream.Generic
import Data.Bits
import qualified Data.List as L
import Data.Ord
import qualified Data.Vector.Fusion.Stream as S
import Data.Vector.Fusion.Stream.Monadic (Stream(..), Step(..))
import Data.Vector.Fusion.Stream.Size
import Data.Vector.Fusion.Util
import Data.Word
import Foreign.Storable
import Prelude ( Bool(..), Eq(..), Int, Integral, Ord(..), Maybe(..)
, Monad(..), Num(..), Show(..), ($!), error, fromIntegral
, otherwise
)
import Prelude.Unicode
data Left
data Right
data Packet d = Packet !Int
!Word8
deriving (Eq)
instance Storable (Packet d) where
sizeOf _ = 2
alignment = sizeOf
peek p
= do n ← peekByteOff p 0
o ← peekByteOff p 1
return $! Packet (fromIntegral (n ∷ Word8)) o
poke p (Packet n o)
= do pokeByteOff p 0 (fromIntegral n ∷ Word8)
pokeByteOff p 1 o
instance Show (Packet Left) where
show (Packet n0 o0)
= L.concat
[ "["
, L.unfoldr go (n0, o0)
, "←]"
]
where
go (0, _) = Nothing
go (n, o)
| o `testBit` (n1) = Just ('1', (n1, o))
| otherwise = Just ('0', (n1, o))
instance Show (Packet Right) where
show (Packet n0 o0)
= L.concat
[ "[→"
, L.unfoldr go (n0, o0)
, "]"
]
where
δ ∷ Int
δ = 7 n0
go (0, _) = Nothing
go (n, o)
| o `testBit` (n+δ) = Just ('1', (n1, o))
| otherwise = Just ('0', (n1, o))
instance Ord (Packet Left) where
px `compare` py
= comparing packetLToR px py
instance Ord (Packet Right) where
(Packet nx ox) `compare` (Packet ny oy)
= compare
(ox `shiftR` (8nx))
(oy `shiftR` (8ny))
instance Bitstream (Packet Left) where
basicStream (Packet n o)
=
Stream step 0 (Exact n)
where
step !i
| i ≥ n = return Done
| otherwise = return $! Yield (o `testBit` i) (i+1)
basicUnstream (Stream step s0 sz)
=
case upperBound sz of
Just n
| n ≤ 8 → unId (unsafeConsume s0 0 0)
| otherwise → packetOverflow
Nothing → unId (safeConsume s0 0 0)
where
unsafeConsume s !i !o
= do r ← step s
case r of
Yield True s' → unsafeConsume s' (i+1) (o `setBit` i)
Yield False s' → unsafeConsume s' (i+1) o
Skip s' → unsafeConsume s' i o
Done → return $! Packet i o
safeConsume s !i !o
= do r ← step s
case r of
Yield b s'
| i < 8 → safeConsume s' (i+1) (if b
then o `setBit` i
else o)
| otherwise → packetOverflow
Skip s' → safeConsume s' i o
Done → return $! Packet i o
basicCons b p
| full p = packetOverflow
| otherwise = b `unsafeConsL` p
basicSnoc p b
| full p = packetOverflow
| otherwise = p `unsafeSnocL` b
basicAppend (Packet nx ox) (Packet ny oy)
| nx + ny > 8 = packetOverflow
| otherwise = Packet (nx + ny) (ox .|. (oy `shiftL` nx))
basicTail (Packet 0 _) = emptyNotAllowed
basicTail (Packet n o) = Packet (n1) (o `shiftR` 1)
basicInit (Packet 0 _) = emptyNotAllowed
basicInit (Packet n o) = Packet (n1) o
basicMap f (Packet n o0) = Packet n (go 0 o0)
where
go i o
| i ≥ n = o
| f (o `testBit` i) = go (i+1) (o `setBit` i)
| otherwise = go (i+1) (o `clearBit` i)
basicReverse (Packet n o)
= Packet n (reverseBits o `shiftR` (8n))
basicScanl = scanlPacket
basicTake l (Packet n o)
| l ≤ 0 = (∅)
| otherwise
= let n' = fromIntegral (min (fromIntegral n) l)
o' = (0xFF `shiftR` (8n')) .&. o
in
Packet n' o'
basicDrop l (Packet n o)
| l ≤ 0 = Packet n o
| otherwise
= let d = fromIntegral (min (fromIntegral n) l)
n' = nd
o' = o `shiftR` d
in
Packet n' o'
basicTakeWhile = takeWhilePacket
basicDropWhile = dropWhilePacket
basicFilter = filterPacket
basicFromNBits n β
| n < 0 = (∅)
| n > 8 = packetOverflow
| n ≡ 8 = Packet (fromIntegral n) (fromIntegral β)
| otherwise = let n' ∷ Int
n' = fromIntegral n
o ∷ Word8
o = fromIntegral (β .&. ((1 `shiftL` n') 1))
in Packet n' o
basicToBits = fromIntegral ∘ toOctet
instance Bitstream (Packet Right) where
basicStream (Packet n o)
=
Stream step 0 (Exact n)
where
step !i
| i ≥ n = return Done
| otherwise = return $! Yield (o `testBit` (7i)) (i+1)
basicUnstream (Stream step s0 sz)
=
case upperBound sz of
Just n
| n ≤ 8 → unId (unsafeConsume s0 0 0)
| otherwise → packetOverflow
Nothing → unId (safeConsume s0 0 0)
where
unsafeConsume s i o
= do r ← step s
case r of
Yield True s' → unsafeConsume s' (i+1) (o `setBit` (7i))
Yield False s' → unsafeConsume s' (i+1) o
Skip s' → unsafeConsume s' i o
Done → return $! Packet i o
safeConsume s i o
= do r ← step s
case r of
Yield b s'
| i < 8 → safeConsume s' (i+1) (if b
then o `setBit` (7i)
else o)
| otherwise → packetOverflow
Skip s' → safeConsume s' i o
Done → return $! Packet i o
basicCons b p
| full p = packetOverflow
| otherwise = b `unsafeConsR` p
basicSnoc p b
| full p = packetOverflow
| otherwise = p `unsafeSnocR` b
basicAppend (Packet nx ox) (Packet ny oy)
| nx + ny > 8 = packetOverflow
| otherwise = Packet (nx + ny) (ox .|. (oy `shiftR` nx))
basicTail (Packet 0 _) = emptyNotAllowed
basicTail (Packet n o) = Packet (n1) (o `shiftL` 1)
basicInit (Packet 0 _) = emptyNotAllowed
basicInit (Packet n o) = Packet (n1) o
basicMap f (Packet n o0) = Packet n (go 0 o0)
where
go i o
| i ≥ n = o
| f (o `testBit` (7i)) = go (i+1) (o `setBit` (7i))
| otherwise = go (i+1) (o `clearBit` (7i))
basicReverse (Packet n o)
= Packet n (reverseBits o `shiftL` (8n))
basicScanl = scanlPacket
basicTake l (Packet n o)
| l ≤ 0 = (∅)
| otherwise
= let n' = fromIntegral (min (fromIntegral n) l)
o' = (0xFF `shiftL` (8n')) .&. o
in
Packet n' o'
basicDrop l (Packet n o)
| l ≤ 0 = Packet n o
| otherwise
= let d = fromIntegral (min (fromIntegral n) l)
n' = nd
o' = o `shiftL` d
in
Packet n' o'
basicTakeWhile = takeWhilePacket
basicDropWhile = dropWhilePacket
basicFilter = filterPacket
basicFromNBits n β
| n < 0 = (∅)
| n > 8 = packetOverflow
| n ≡ 8 = Packet (fromIntegral n) (fromIntegral β)
| otherwise = let n' ∷ Int
n' = fromIntegral n
o ∷ Word8
o = fromIntegral ( (β .&. ((1 `shiftL` n') 1))
`shiftL`
(8n')
)
in Packet n' o
basicToBits (Packet n o)
= fromIntegral (o `shiftR` (8n))
packetHeadL ∷ Packet Left → Bool
packetHeadL (Packet 0 _) = emptyNotAllowed
packetHeadL (Packet _ o) = o `testBit` 0
packetHeadR ∷ Packet Right → Bool
packetHeadR (Packet 0 _) = emptyNotAllowed
packetHeadR (Packet _ o) = o `testBit` 7
packetLastL ∷ Packet Left → Bool
packetLastL (Packet 0 _) = emptyNotAllowed
packetLastL (Packet n o) = o `testBit` (n1)
packetLastR ∷ Packet Right → Bool
packetLastR (Packet 0 _) = emptyNotAllowed
packetLastR (Packet n o) = o `testBit` (8n)
packetAndL ∷ Packet Left → Bool
packetAndL (Packet n o) = (0xFF `shiftR` (8n)) ≡ o
packetAndR ∷ Packet Right → Bool
packetAndR (Packet n o) = (0xFF `shiftL` (8n)) ≡ o
packetIndexL ∷ (Integral n, Show n) ⇒ Packet Left → n → Bool
packetIndexL p i
| i < 0 ∨ i ≥ length p = indexOutOfRange i
| otherwise = unsafePacketIndexL p i
packetIndexR ∷ (Integral n, Show n) ⇒ Packet Right → n → Bool
packetIndexR p i
| i < 0 ∨ i ≥ length p = indexOutOfRange i
| otherwise = unsafePacketIndexR p i
unsafePacketIndexL ∷ Integral n ⇒ Packet Left → n → Bool
unsafePacketIndexL (Packet _ o) i
= o `testBit` fromIntegral i
unsafePacketIndexR ∷ Integral n ⇒ Packet Right → n → Bool
unsafePacketIndexR (Packet _ o) i
= o `testBit` (7 fromIntegral i)
packetNull ∷ Packet d → Bool
packetNull (Packet 0 _) = True
packetNull _ = False
packetLength ∷ Num n ⇒ Packet d → n
packetLength (Packet n _) = fromIntegral n
packetOr ∷ Packet d → Bool
packetOr (Packet _ o) = o ≢ 0
emptyNotAllowed ∷ α
emptyNotAllowed = error "Data.Bitstream.Packet: packet is empty"
packetOverflow ∷ α
packetOverflow = error "Data.Bitstream.Packet: packet size overflow"
indexOutOfRange ∷ (Integral n, Show n) ⇒ n → α
indexOutOfRange n = error ("Data.Bitstream.Packet: index out of range: " L.++ show n)
full ∷ Packet d → Bool
full (Packet 8 _) = True
full _ = False
fromOctet ∷ Word8 → Packet d
fromOctet = Packet 8
toOctet ∷ Packet d → Word8
toOctet (Packet _ o) = o
unsafeConsL ∷ Bool → Packet Left → Packet Left
unsafeConsL True (Packet n o) = Packet (n+1) ((o `shiftL` 1) .|. 1)
unsafeConsL False (Packet n o) = Packet (n+1) (o `shiftL` 1)
unsafeConsR ∷ Bool → Packet Right → Packet Right
unsafeConsR True (Packet n o) = Packet (n+1) ((o `shiftR` 1) .|. 0x80)
unsafeConsR False (Packet n o) = Packet (n+1) (o `shiftR` 1)
unsafeSnocL ∷ Packet Left → Bool → Packet Left
unsafeSnocL (Packet n o) True = Packet (n+1) (o `setBit` n)
unsafeSnocL (Packet n o) False = Packet (n+1) o
unsafeSnocR ∷ Packet Right → Bool → Packet Right
unsafeSnocR (Packet n o) True = Packet (n+1) (o `setBit` (7n))
unsafeSnocR (Packet n o) False = Packet (n+1) o
packetLToR ∷ Packet Left → Packet Right
packetLToR (Packet n o) = Packet n (reverseBits o)
packetRToL ∷ Packet Right → Packet Left
packetRToL (Packet n o) = Packet n (reverseBits o)
reverseBits ∷ Word8 → Word8
reverseBits x
= ((x .&. 0x01) `shiftL` 7) .|.
((x .&. 0x02) `shiftL` 5) .|.
((x .&. 0x04) `shiftL` 3) .|.
((x .&. 0x08) `shiftL` 1) .|.
((x .&. 0x10) `shiftR` 1) .|.
((x .&. 0x20) `shiftR` 3) .|.
((x .&. 0x40) `shiftR` 5) .|.
((x .&. 0x80) `shiftR` 7)
scanlPacket ∷ Bitstream (Packet d) ⇒ (Bool → Bool → Bool) → Bool → Packet d → Packet d
scanlPacket f b
= unstream ∘ S.scanl f b ∘ stream
takeWhilePacket ∷ Bitstream (Packet d) ⇒ (Bool → Bool) → Packet d → Packet d
takeWhilePacket f α = take (go 0 ∷ Int) α
where
go i | i ≥ length α = i
| f (α !! i) = go (i+1)
| otherwise = i
dropWhilePacket ∷ Bitstream (Packet d) ⇒ (Bool → Bool) → Packet d → Packet d
dropWhilePacket f α = drop (go 0 ∷ Int) α
where
go i | i ≥ length α = i
| f (α !! i) = go (i+1)
| otherwise = i
filterPacket ∷ Bitstream (Packet d) ⇒ (Bool → Bool) → Packet d → Packet d
filterPacket f = unstream ∘ S.filter f ∘ stream