{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE BangPatterns #-}
module Data.Queue
( Queue
, newQueue
, peek
, tryPeek
, enqueue
, dequeue
, tryDequeue
) where
import Control.Concurrent
import Control.Concurrent.STM
data Queue a = Queue
!(TVar [a])
!(TVar [a])
!(TVar [a])
newQueue :: STM (Queue a)
newQueue = Queue
<$> newTVar []
<*> newTVar []
<*> newTVar []
rotate :: [a] -> [a] -> [a] -> [a]
rotate [] (y : _) zs = y : zs
rotate (x : xs) (y : ys) zs = x : rotate xs ys (y : zs)
queue :: Queue a -> STM ()
queue (Queue top schedule bottom) =
readTVar schedule >>= \case
x : xs -> writeTVar schedule xs
[] -> do
xs <- readTVar top
ys <- readTVar bottom
let rs = rotate xs ys []
writeTVar top rs
writeTVar bottom []
writeTVar schedule rs
enqueue :: Queue a -> a -> STM ()
enqueue q@(Queue _top _schedule bottom) a = do
modifyTVar bottom (a :)
queue q
dequeue :: Queue a -> STM a
dequeue q@(Queue top _schedule _bottom) =
readTVar top >>= \case
x : xs -> do
writeTVar top xs
queue q
pure x
[] -> retry
tryDequeue :: Queue a -> STM (Maybe a)
tryDequeue q@(Queue top _schedule _bottom) =
readTVar top >>= \case
x : xs -> do
writeTVar top xs
queue q
pure (Just x)
[] -> pure Nothing
peek :: Queue a -> STM a
peek (Queue top _schedule _bottom) =
readTVar top >>= \case
x : xs -> pure x
[] -> retry
tryPeek :: Queue a -> STM (Maybe a)
tryPeek (Queue top _schedule _bottom) =
readTVar top >>= \case
x : xs -> pure (Just x)
[] -> pure Nothing
flush :: Queue a -> STM [a]
flush (Queue top schedule bottom) = do
xs <- swapTVar top []
ys <- swapTVar bottom []
writeTVar schedule []
pure (xs ++ reverse ys)