{-# 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