module System.Wlog.MemoryQueue
( Sized(..)
, MemoryQueue(..)
, newMemoryQueue
, popLast
, pushFront
, toList
) where
import Control.Lens (to)
import Data.Sequence (Seq, ViewR (..), viewr, (<|))
import Universum hiding (toList)
import qualified Universum as U
import Control.Lens (makeLenses, (%=), (+=))
import Control.Monad.Loops (whileM_)
class Sized e where
getSize :: e -> Word64
instance Sized Text where
getSize = fromIntegral . length
data MemoryQueue a = MemoryQueue
{ _mqLimit :: !Word64
, _mqMemSize :: !Word64
, _mqQueue :: !(Seq a)
} deriving (Show)
makeLenses ''MemoryQueue
newMemoryQueue :: (Sized a) => Word64 -> MemoryQueue a
newMemoryQueue _mqLimit = MemoryQueue { _mqMemSize = 0, _mqQueue = mempty, .. }
popLast :: (Sized a) => MemoryQueue a -> (Maybe a, MemoryQueue a)
popLast mq@MemoryQueue{..} = case viewr _mqQueue of
EmptyR -> (Nothing, mq)
rest :> popped ->
let newMemSize = _mqMemSize getSize popped
in (Just popped, MemoryQueue{ _mqMemSize = newMemSize, _mqQueue = rest, .. })
pushFront :: (Sized a) => a -> MemoryQueue a -> MemoryQueue a
pushFront msg mq = executingState mq $ do
mqMemSize += getSize msg
mqQueue %= (msg <|)
whileM_ isLimitExceeded $
modify (snd . popLast)
where
isLimitExceeded = liftA2 (<) (use mqLimit) (use mqMemSize)
toList :: (Sized a) => MemoryQueue a -> [a]
toList = view $ mqQueue . to U.toList