{-# LANGUAGE DeriveGeneric #-}
module Game.LambdaHack.Common.RingBuffer
( RingBuffer
, empty, cons, uncons, toList, length
) where
import Prelude ()
import Game.LambdaHack.Common.Prelude hiding (length, uncons)
import Data.Binary
import qualified Data.Foldable as Foldable
import qualified Data.Sequence as Seq
import GHC.Generics (Generic)
data RingBuffer a = RingBuffer
{ rbCarrier :: Seq.Seq a
, rbMaxSize :: Int
, rbNext :: Int
, rbLength :: Int
}
deriving (Show, Generic)
instance Binary a => Binary (RingBuffer a)
empty :: Int -> a -> RingBuffer a
empty size dummy =
let rbMaxSize = max 1 size
in RingBuffer (Seq.replicate rbMaxSize dummy) rbMaxSize 0 0
cons :: a -> RingBuffer a -> RingBuffer a
cons a RingBuffer{..} =
let incNext = (rbNext + 1) `mod` rbMaxSize
incLength = min rbMaxSize $ rbLength + 1
in RingBuffer (Seq.update rbNext a rbCarrier) rbMaxSize incNext incLength
uncons :: RingBuffer a -> Maybe (a, RingBuffer a)
uncons RingBuffer{..} =
let decNext = (rbNext - 1) `mod` rbMaxSize
in if rbLength == 0
then Nothing
else Just ( Seq.index rbCarrier decNext
, RingBuffer rbCarrier rbMaxSize decNext (rbLength - 1) )
toList :: RingBuffer a -> [a]
toList RingBuffer{..} =
let l = Foldable.toList rbCarrier
start = (rbNext + rbMaxSize - rbLength) `mod` rbMaxSize
in take rbLength $ drop start $ l ++ l
length :: RingBuffer a -> Int
length RingBuffer{rbLength} = rbLength