{- | Module : Codec.Goat.Fluid Description : Transition between compressed and raw data Copyright : (c) Daniel Lovasko, 2016-2017 License : BSD3 Maintainer : Daniel Lovasko Stability : stable Portability : portable By using the Frame abstraction, the Fluid type achieves transition between the raw and compressed states for both TimeFrame and ValueFrame. It is intended for internal use only. -} module Codec.Goat.Fluid ( Fluid(..) , fluidAppend , fluidDump , fluidFirst , fluidHeads , fluidNew , fluidSelect , fluidShift ) where import Safe import Codec.Goat.Frame import Codec.Goat.Util -- | Management of fluid transitions between compressed and uncompresed -- state. The constructor arguments are as follows: -- * section lengths -- * raw section -- * compressed section data Fluid r c = Fluid (Int, Int) [[r]] [c] -- | Pretty-printing of the Fluid type. instance Show (Fluid r c) where show (Fluid (l1, l2) rs cs) = unwords [ "Fluid" , "l1max=" ++ show l1 , "l2max=" ++ show l2 , "l1cur=" ++ show (length rs) , "l2cur=" ++ show (length cs) ] -- | Create a new fluid. fluidNew :: (Int, Int) -- ^ section lengths -> Fluid r c -- ^ new fluid fluidNew ls = Fluid ls [[]] [] -- | Obtain the first element stored in the frame. fluidFirst :: Fluid r c -> Maybe r fluidFirst (Fluid _ [] _) = Nothing fluidFirst (Fluid _ (x:_) _) = headMay x -- | Obtain the first elements of each section blocks. Empty frames and -- lists are represented as Nothing. fluidHeads :: Frame r c => Fluid r c -- ^ fluid -> [Maybe r] -- ^ block heads fluidHeads (Fluid _ rs cs) = map headMay rs ++ map frameHead cs -- | Return raw values stored within specified block indices. fluidSelect :: Frame r c => Fluid r c -- ^ fluid -> [Bool] -- ^ block presence -> [r] -- ^ raw values fluidSelect (Fluid _ rs cs) presence = rvalues ++ cvalues where (rpres, cpres) = splitAt (length rs) presence rvalues = concat $ select rs rpres cvalues = concatMap frameDecode (select cs cpres) -- | Shift one uncompressed component into the compressed ones and create -- a new empty uncompressed component. fluidShift :: Frame r c => Fluid r c -- ^ old fluid -> Fluid r c -- ^ new fluid fluidShift (Fluid ls@(l1, l2) rs cs) | (null . last) rs || (length rs < l1) = Fluid ls newRs cs | otherwise = Fluid ls newRs newCs where newRs = [] : bool rs (init rs) (length rs < l1) newCs = frameEncode (last rs) : bool cs (init cs) (length cs < l2) -- | Add new value to the fluid. Internally this function is _prepending_ -- in front of all existing values. fluidAppend :: Fluid r c -- ^ old fluid -> r -- ^ new value -> Fluid r c -- ^ new fluid fluidAppend (Fluid ls [] cs) val = Fluid ls [[val]] cs fluidAppend (Fluid ls (r:rs) cs) val = Fluid ls ((val:r):rs) cs -- | Dump all stored values in the uncompressed form. fluidDump :: Frame r c => Fluid r c -- ^ fluid -> [r] -- ^ uncompressed values fluidDump (Fluid _ rs cs) = concat rs ++ concatMap frameDecode cs