{-# LANGUAGE DeriveGeneric #-}
-- | Ring buffers.
module Game.LambdaHack.Common.RingBuffer
  ( RingBuffer
  , empty, cons, toList, length
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude hiding (length, uncons)

import           Data.Binary
import qualified Data.Foldable as Foldable
import qualified Data.Sequence as Seq
import           GHC.Generics (Generic)

-- | Ring buffers of a size determined at initialization.
data RingBuffer a = RingBuffer
  { RingBuffer a -> Seq a
rbCarrier :: Seq.Seq a
  , RingBuffer a -> Int
rbMaxSize :: Int
  , RingBuffer a -> Int
rbNext    :: Int
  , RingBuffer a -> Int
rbLength  :: Int
  }
  deriving (Int -> RingBuffer a -> ShowS
[RingBuffer a] -> ShowS
RingBuffer a -> String
(Int -> RingBuffer a -> ShowS)
-> (RingBuffer a -> String)
-> ([RingBuffer a] -> ShowS)
-> Show (RingBuffer a)
forall a. Show a => Int -> RingBuffer a -> ShowS
forall a. Show a => [RingBuffer a] -> ShowS
forall a. Show a => RingBuffer a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RingBuffer a] -> ShowS
$cshowList :: forall a. Show a => [RingBuffer a] -> ShowS
show :: RingBuffer a -> String
$cshow :: forall a. Show a => RingBuffer a -> String
showsPrec :: Int -> RingBuffer a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> RingBuffer a -> ShowS
Show, (forall x. RingBuffer a -> Rep (RingBuffer a) x)
-> (forall x. Rep (RingBuffer a) x -> RingBuffer a)
-> Generic (RingBuffer a)
forall x. Rep (RingBuffer a) x -> RingBuffer a
forall x. RingBuffer a -> Rep (RingBuffer a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (RingBuffer a) x -> RingBuffer a
forall a x. RingBuffer a -> Rep (RingBuffer a) x
$cto :: forall a x. Rep (RingBuffer a) x -> RingBuffer a
$cfrom :: forall a x. RingBuffer a -> Rep (RingBuffer a) x
Generic)

instance Binary a => Binary (RingBuffer a)

-- Only takes O(log n)).
empty :: Int -> a -> RingBuffer a
empty :: Int -> a -> RingBuffer a
empty Int
size a
dummy =
  let rbMaxSize :: Int
rbMaxSize = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 Int
size
  in Seq a -> Int -> Int -> Int -> RingBuffer a
forall a. Seq a -> Int -> Int -> Int -> RingBuffer a
RingBuffer (Int -> a -> Seq a
forall a. Int -> a -> Seq a
Seq.replicate Int
rbMaxSize a
dummy) Int
rbMaxSize Int
0 Int
0

cons :: a -> RingBuffer a -> RingBuffer a
cons :: a -> RingBuffer a -> RingBuffer a
cons a
a RingBuffer{Int
Seq a
rbLength :: Int
rbNext :: Int
rbMaxSize :: Int
rbCarrier :: Seq a
rbLength :: forall a. RingBuffer a -> Int
rbNext :: forall a. RingBuffer a -> Int
rbMaxSize :: forall a. RingBuffer a -> Int
rbCarrier :: forall a. RingBuffer a -> Seq a
..} =
  let incNext :: Int
incNext = (Int
rbNext Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
rbMaxSize
      incLength :: Int
incLength = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
rbMaxSize (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int
rbLength Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
  in Seq a -> Int -> Int -> Int -> RingBuffer a
forall a. Seq a -> Int -> Int -> Int -> RingBuffer a
RingBuffer (Int -> a -> Seq a -> Seq a
forall a. Int -> a -> Seq a -> Seq a
Seq.update Int
rbNext a
a Seq a
rbCarrier) Int
rbMaxSize Int
incNext Int
incLength

toList :: RingBuffer a -> [a]
toList :: RingBuffer a -> [a]
toList RingBuffer{Int
Seq a
rbLength :: Int
rbNext :: Int
rbMaxSize :: Int
rbCarrier :: Seq a
rbLength :: forall a. RingBuffer a -> Int
rbNext :: forall a. RingBuffer a -> Int
rbMaxSize :: forall a. RingBuffer a -> Int
rbCarrier :: forall a. RingBuffer a -> Seq a
..} =
  let l :: [a]
l = Seq a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
Foldable.toList Seq a
rbCarrier
      start :: Int
start = (Int
rbNext Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
rbMaxSize Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
rbLength) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
rbMaxSize
  in Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
rbLength ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
start ([a] -> [a]) -> [a] -> [a]
forall a b. (a -> b) -> a -> b
$ [a]
l [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
l

length :: RingBuffer a -> Int
length :: RingBuffer a -> Int
length RingBuffer{Int
rbLength :: Int
rbLength :: forall a. RingBuffer a -> Int
rbLength} = Int
rbLength