module Data.RingBuffer.ComboBuffer (
ComboBuffer (..)
)
where
import Prelude hiding (length)
import Data.RingBuffer.Class
import Data.RingBuffer.Chord
import qualified Data.Vector.Unboxed as V
data ComboBuffer a =
CB !Int
!Int
!(V.Vector a)
!(V.Vector a)
(Chord a)
| CBOdd !Int
!Int
!(V.Vector a)
!(V.Vector a)
(Chord a)
deriving (Eq, Ord, Show)
type instance El (ComboBuffer a) = a
instance V.Unbox a => Initializable (ComboBuffer a) where
newInit = newInit'
newInit' :: V.Unbox a => a -> Int -> ComboBuffer a
newInit' el sz
| sz <= 0 = error "Can't initialize ComboBuffer with size <= 0"
| sz `rem` 2 == 0 = let half = sz `div` 2
iv = V.replicate half el
in CB half 0 iv iv (emptyChord el)
| otherwise = let half = (1+sz) `div` 2
iv = V.replicate half el
in CBOdd half 0 iv iv (emptyChord el)
instance V.Unbox a => RingBuffer (ComboBuffer a) where
length (CB sz _ _ _ _) = 2*sz
length (CBOdd sz _ _ _ _) = 2*sz1
(!) = at
push = pushB
slice = sliceB
at :: V.Unbox a => ComboBuffer a -> Int -> a
at (CB sz pos v1 v2 upds) ix
| ix < 0 = error $ "ComboBuffer: index out of range: " ++ show ix
| ix < pos = upds ! ix
| ix < 2*sz = let ix' = ix pos in if ix' < sz
then v1 `V.unsafeIndex` ix'
else v2 `V.unsafeIndex` (ix' sz)
| otherwise = error $ "ComboBuffer: index out of range: " ++ show (ix,2*sz)
at (CBOdd sz pos v1 v2 upds) ix
| ix < 0 = error $ "ComboBuffer: index out of range: " ++ show ix
| ix < pos = upds ! ix
| ix < 2*sz1 = let ix' = ix pos in if ix' < sz
then v1 `V.unsafeIndex` ix'
else v2 `V.unsafeIndex` (ix' sz)
| otherwise = error $ "ComboBuffer: index out of range: " ++ show (ix,2*sz1)
sliceB :: V.Unbox a => ComboBuffer a -> Int -> Int -> [a]
sliceB (CB sz pos v1 v2 upds) start num
= let ix' = start pos
fstTake = sz (ix'+num)
in if ix' < sz
then slice upds start num
++ V.toList (V.slice ix' (min 0 fstTake) v1)
++ V.toList (V.slice 0 (min 0 (negate fstTake)) v2)
else V.toList (V.slice (ix'sz) num v2)
sliceB (CBOdd sz pos v1 v2 upds) start num
= let ix' = start pos
fstTake = sz (ix'+num)
in if ix' < sz
then slice upds start num
++ V.toList (V.slice ix' (min 0 fstTake) v1)
++ V.toList (V.slice 0 (min 0 (negate fstTake)) v2)
else V.toList (V.slice (ix'sz) num v2)
pushB :: V.Unbox a => ComboBuffer a -> a -> ComboBuffer a
pushB (CB sz pos v1 v2 upds) el
| pos == sz1 = CB sz 0 (cToVec $ push upds el) v1
(emptyChord el)
| otherwise = CB sz (pos+1) v1 v2 (push upds el)
pushB (CBOdd sz pos v1 v2 upds) el
| pos == sz1 = CBOdd sz 0 (cToVec $ push upds el) v1
(emptyChord el)
| otherwise = CBOdd sz (pos+1) v1 v2 (push upds el)