packages feed

bitstream-0.3.0.0: Data/Bitstream/Internal.hs

{-# LANGUAGE
    BangPatterns
  , CPP
  , FlexibleContexts
  , UnicodeSyntax
  #-}
module Data.Bitstream.Internal
    ( packPackets
    , packPacketsSize

    , lePacketsFromNBits
    , bePacketsFromNBits
    , packetsFromNBitsSize

    , lePacketsToBits
    , bePacketsToBits
    )
    where
import Data.Bits
import Data.Bitstream.Generic
import Data.Bitstream.Packet
import Data.Vector.Fusion.Stream.Monadic (Stream(..), Step(..))
#if MIN_VERSION_vector(0,11,0)
import qualified Data.Vector.Fusion.Bundle.Monadic as B
import Data.Vector.Fusion.Bundle.Monadic (Bundle)
import Data.Vector.Fusion.Bundle.Size
#else
import Data.Vector.Fusion.Stream.Size
#endif
import Prelude hiding (length, null)
import Prelude.Unicode

packPacketsSize ∷ Size -> Size
{-# INLINE packPacketsSize #-}
packPacketsSize sz = case sz of
    Exact n → Exact ((n+7) `div` 8)
    Max   n → Max   ((n+7) `div` 8)
    Unknown → Unknown

#if MIN_VERSION_vector(0,11,0)
inplace :: Monad m => (Stream m a -> Stream m b)
        -> (Size -> Size) -> Bundle m v a -> Bundle m v b
inplace f g b = b `seq` B.fromStream (f (B.elements b)) (g (B.size b))
#endif

{-# INLINEABLE packPackets #-}
#if MIN_VERSION_vector(0,11,0)
packPackets ∷ (Bitstream (Packet d), Monad m) ⇒ Bundle m v Bool → Bundle m v (Packet d)
packPackets = inplace (\(Stream s s0) -> Stream (step' s) ((∅), Just s0)) packPacketsSize
#else
packPackets ∷ (Bitstream (Packet d), Monad m) ⇒ Stream m Bool → Stream m (Packet d)
packPackets (Stream s s0 sz) = Stream (step' s) ((∅), Just s0) (packPacketsSize sz)
#endif
    where
      {-# INLINE step' #-}
      step' step (p, Just s)
          = do r ← step s
               case r of
                 Yield b s'
                     | full p    → return $ Yield p (singleton b, Just s')
                     | otherwise → return $ Skip    (p `snoc` b , Just s')
                 Skip    s'      → return $ Skip    (p          , Just s')
                 Done
                     | null p    → return Done
                     | otherwise → return $ Yield p ((⊥)       , Nothing)
      step' _ (_, Nothing)
          = return Done

nOctets ∷ Integral n ⇒ n → Int
{-# INLINE nOctets #-}
nOctets nBits
    = (fromIntegral nBits + 7) `div` 8

packetsFromNBitsSize ∷ Integral n ⇒ n → Size
packetsFromNBitsSize = Exact . nOctets

{-# INLINEABLE lePacketsFromNBits #-}
#if MIN_VERSION_vector(0,11,0)
lePacketsFromNBits ∷ ( Integral n
                     , Integral β
                     , Bits β
                     , Monad m
                     )
                   ⇒ n
                   → β
                   → Bundle m v (Packet Left)
lePacketsFromNBits n0 β0 = B.fromStream (Stream step (n0, β0)) (packetsFromNBitsSize n0)
#else
lePacketsFromNBits ∷ ( Integral n
                     , Integral β
                     , Bits β
                     , Monad m
                     )
                   ⇒ n
                   → β
                   → Stream m (Packet Left)
lePacketsFromNBits n0 β0 = Stream step (n0, β0) (packetsFromNBitsSize n0)
#endif
    where
      {-# INLINE step #-}
      step (n, β)
          | n > 0
              = let !n'  = min 8 n
                    !n'' = n - n'
                    !p   = fromNBits n' β
                    !β'  = β `shiftR` 8
                in
                  return $ Yield p (n'', β')
          | otherwise
              = return Done

{-# INLINEABLE bePacketsFromNBits #-}
#if MIN_VERSION_vector(0,11,0)
bePacketsFromNBits ∷ ( Integral n
                   , Integral β
                   , Bits β
                   , Monad m
                   )
                 ⇒ n
                 → β
                 → Bundle m v (Packet Right)
bePacketsFromNBits n0 β = B.fromStream (Stream step (n0, nOctets n0 ⋅ 8)) (packetsFromNBitsSize n0)
#else
bePacketsFromNBits ∷ ( Integral n
                     , Integral β
                     , Bits β
                     , Monad m
                     )
                   ⇒ n
                   → β
                   → Stream m (Packet Right)
bePacketsFromNBits n0 β = Stream step (n0, nOctets n0 ⋅ 8) (bePacketsFromNBitsSize n0)
#endif
    where
      {-# INLINE step #-}
      step (n, r)
          | n > 0
              = let !r'  = r - 8
                    !n'  = n - fromIntegral r'
                    !n'' = n - n'
                    !p   = fromNBits n' (β `shiftR` r')
                in
                  return $ Yield p (n'', r')
          | otherwise
              = return Done

{-# INLINEABLE lePacketsToBits #-}
#if MIN_VERSION_vector(0,11,0)
lePacketsToBits ∷ (Monad m, Integral β, Bits β) ⇒ Bundle m v (Packet Left) → m β
lePacketsToBits (B.Bundle (Stream step s0) _ _ _) = go (s0, 0, 0)
#else
lePacketsToBits ∷ (Monad m, Integral β, Bits β) ⇒ Stream m (Packet Left) → m β
lePacketsToBits (Stream step s0 _) = go (s0, 0, 0)
#endif
    where
      {-# INLINE go #-}
      go (s, o, n)
          = do r ← step s
               case r of
                 Yield p s' → let !n' = (toBits p `shiftL` o) .|. n
                                  !o' = o + length p
                              in
                                go (s', o', n')
                 Skip    s' → go (s', o, n)
                 Done       → return n

{-# INLINEABLE bePacketsToBits #-}
#if MIN_VERSION_vector(0,11,0)
bePacketsToBits ∷ (Monad m, Integral β, Bits β) ⇒ Bundle m v (Packet Right) → m β
bePacketsToBits (B.Bundle (Stream step s0) _ _ _) = go (s0, 0)
#else
bePacketsToBits ∷ (Monad m, Integral β, Bits β) ⇒ Stream m (Packet Right) → m β
bePacketsToBits (Stream step s0 _) = go (s0, 0)
#endif
    where
      {-# INLINE go #-}
      go (s, n)
          = do r ← step s
               case r of
                 Yield p s' → let !o  = length p
                                  !n' = (n `shiftL` o) .|. toBits p
                              in
                                go (s', n')
                 Skip    s' → go (s', n)
                 Done       → return n