combobuffer-0.1: src/Data/RingBuffer/Class.hs
{-# LANGUAGE TypeFamilies, GADTs #-}
{-# OPTIONS_GHC -Wall #-}
-- | The RingBuffer interface.
--
-- A RingBuffer is a fixed-length buffer that supports lookups anywhere in
-- the structure and pushing new elements onto the front. When a new value is
-- pushed, the oldest value will be dropped.
--
-- This module provides an implementation based on
-- 'Data.Vector.Unboxed.Vector', with O(1) lookups and O(n) pushes. Other
-- modules provide implementations with different performance profiles.
module Data.RingBuffer.Class (
El
,RingBuffer (..)
,Initializable (..)
)
where
import Prelude hiding (length)
import qualified Data.Vector.Unboxed as V
type family El c :: *
-- | Create a new 'Initializable' with the given value at every position.
-- Essentially a generalized 'Prelude.replicate'
class Initializable c where
newInit :: El c -> Int -> c
-- | The RingBuffer interface.
--
-- Instances must define 'length', 'push', and '(!)'. Instances may define
-- 'slice' for better performance.
class RingBuffer c where
length :: c -> Int
push :: c -> El c -> c
(!) :: c -> Int -> El c
slice :: c -> Int -> Int -> [El c]
{-# INLINE slice #-}
slice c start num = [ c ! ix | ix <- [start .. start+num]]
type instance El (V.Vector el) = el
instance V.Unbox el => Initializable (V.Vector el) where
{-# INLINE newInit #-}
newInit = flip V.replicate
instance V.Unbox el => RingBuffer (V.Vector el) where
{-# INLINE length #-}
length = V.length
{-# INLINE (!) #-}
(!) = (V.!)
{-# INLINE push #-}
push vec el = V.cons el $ V.unsafeInit vec
{-# INLINE slice #-}
slice vec start num = V.toList $ V.slice start num vec