ipc-0.0.3: Data/Queue.hs
module Data.Queue
( Queue
, Data.Queue.empty
, Input
, Output
, isEmpty
, snoc
, pop
, cons
, append
, Data.Queue.foldr
, Data.Queue.map
, send
, recv
, sendAtomic
, recvAtomic) where
import qualified Data.DList as D
import Control.Concurrent.STM
-- |A buffer data type with the direction ('Input' or 'Output') and element type.
data Queue dir a = Q (D.DList a) Int
data Input
data Output
empty :: Queue d a
empty = Q D.empty 0
-- |Tests if the element count of a queue is zero.
isEmpty :: Queue d a -> Bool
isEmpty (Q _ 0) = True
isEmpty _ = False
-- |Places an element at the end of the queue. O(1)
snoc :: Queue d a -> a -> Queue d a
snoc (Q d n) e = Q (D.snoc d e) (n + 1)
-- |Extracts an element from the front of the queue. O(1)
pop :: Queue d a -> (Maybe a, Queue d a)
pop (Q d 0) = (Nothing, Q d 0)
pop (Q d n) = (Just (D.head d), Q (D.tail d) (n - 1))
-- |Places an element at the front of the queue. O(1)
cons :: a -> Queue d a -> Queue d a
cons e (Q d n) = Q (D.cons e d) (n + 1)
-- |Combine two queues.
append :: Queue d a -> Queue d a -> Queue d a
append (Q q i) (Q p j) = Q (D.append q p) (i + j)
map :: (a -> b) -> Queue d a -> Queue d b
map f (Q xs len) = Q (D.map f xs) len
foldr :: (a -> b -> b) -> b -> Queue d a -> b
foldr f z (Q xs len) = D.foldr f z xs
-- |IO action for snoc on a TVar queue
send :: TVar (Queue Output a) -> a -> IO ()
send tv a = atomically ( sendAtomic tv a )
-- |STM action to snoc on a TVar queue
sendAtomic :: TVar (Queue Output a) -> a -> STM ()
sendAtomic tv a = do
q <- readTVar tv
writeTVar tv (snoc q a)
-- |IO action for popping an element from a TVar queue
recv :: TVar (Queue Input a) -> IO a
recv tv = atomically (recvAtomic tv)
-- |STM action for popping an element from a TVar queue
recvAtomic :: TVar (Queue Input a) -> STM a
recvAtomic tv = do
q <- readTVar tv
case pop q of
(Nothing, _) -> retry
(Just e, qs) -> writeTVar tv qs >> return e