summaryrefslogtreecommitdiff
path: root/RingBuffer.hs
diff options
context:
space:
mode:
Diffstat (limited to 'RingBuffer.hs')
-rw-r--r--RingBuffer.hs70
1 files changed, 70 insertions, 0 deletions
diff --git a/RingBuffer.hs b/RingBuffer.hs
new file mode 100644
index 0000000..b2779d7
--- /dev/null
+++ b/RingBuffer.hs
@@ -0,0 +1,70 @@
1module RingBuffer where
2
3import Control.Monad
4import Data.Int
5import Data.IORef
6
7data TargetBuffer u = TargetBuffer
8 { -- | Called whenever the rBack or rSize changes. The purpose is so that
9 -- some other state, such as an OpenGL vertex buffer object, can remain in
10 -- sync.
11 syncBuffer :: (Int32 -> [(Int32,Int32)]) -> IO ()
12 -- | This updates the data associated with a particular index (usually
13 -- rBack). The update specification /u/ may be a value or a set of
14 -- key-value pairs or whatever is most convenient way to instruct the
15 -- target representation to update itself.
16 , updateBuffer :: Int -> u -> IO ()
17 }
18
19data RingBuffer u = RingBuffer
20 { rBack :: IORef Int
21 , rSize :: IORef Int
22 , ringCapacity :: Int
23 , rBuffer :: TargetBuffer u
24 }
25
26newRing :: Int -> IO (TargetBuffer u) -> IO (RingBuffer u)
27newRing sz newBuffer = do
28 backRef <- newIORef 0
29 sizeRef <- newIORef 0
30 b <- newBuffer
31 let r = RingBuffer
32 { rBack = backRef
33 , rSize = sizeRef
34 , ringCapacity = sz
35 , rBuffer = b
36 }
37 syncRing r
38 return r
39
40syncRing :: RingBuffer u -> IO ()
41syncRing r = do
42 size <- fromIntegral <$> readIORef (rSize r)
43 back <- fromIntegral <$> readIORef (rBack r)
44 let mask 0 = []
45 mask cnt
46 | cnt==size = [(0,cnt)]
47 | otherwise = case cnt + back - size of
48 front | front > cnt -> [(front - cnt,size)]
49 | otherwise -> [(0,back), (front,cnt - front)]
50 syncBuffer (rBuffer r) mask
51
52clearRing :: RingBuffer u -> IO ()
53clearRing r = do
54 writeIORef (rBack r) 0
55 writeIORef (rSize r) 0
56 syncRing r
57
58pushBack :: RingBuffer u -> u -> IO ()
59pushBack r upd = do
60 back <- readIORef $ rBack r
61 writeIORef (rBack r) (mod (back + 1) (ringCapacity r))
62 updateBuffer (rBuffer r) back upd
63 sz <- readIORef (rSize r)
64 when (sz < ringCapacity r) $ writeIORef (rSize r) (sz + 1)
65 syncRing r
66
67updateBack :: RingBuffer u -> u -> IO ()
68updateBack r upd = do
69 back <- readIORef $ rBack r
70 updateBuffer (rBuffer r) back upd