module Data.Concurrent.Deque.Reference
(SimpleDeque(..),
newQ, nullQ, newBoundedQ, pushL, pushR, tryPopR, tryPopL, tryPushL, tryPushR,
_is_using_CAS
)
where
import Prelude hiding (length)
import qualified Data.Concurrent.Deque.Class as C
import Data.Sequence
import Data.IORef
#ifdef USE_CAS
#warning "abstract-deque: reference implementation using CAS..."
import Data.CAS (atomicModifyIORefCAS)
modify = atomicModifyIORefCAS
_is_using_CAS = True
#else
modify = atomicModifyIORef
_is_using_CAS = False
#endif
modify :: IORef a -> (a -> (a, b)) -> IO b
_is_using_CAS :: Bool
data SimpleDeque elt = DQ !Int !(IORef (Seq elt))
newQ :: IO (SimpleDeque elt)
newQ = do r <- newIORef empty
return $! DQ 0 r
newBoundedQ :: Int -> IO (SimpleDeque elt)
newBoundedQ lim =
do r <- newIORef empty
return $! DQ lim r
pushL :: SimpleDeque t -> t -> IO ()
pushL (DQ 0 qr) !x = do
() <- modify qr addleft
return ()
where
addleft !s = extended `seq` pair
where extended = x <| s
pair = (extended, ())
pushL (DQ n _) _ = error$ "should not call pushL on Deque with size bound "++ show n
tryPopR :: SimpleDeque a -> IO (Maybe a)
tryPopR (DQ _ qr) = modify qr $ \ s ->
case viewr s of
EmptyR -> (empty, Nothing)
s' :> x -> (s', Just x)
nullQ :: SimpleDeque elt -> IO Bool
nullQ (DQ _ qr) =
do s <- readIORef qr
case viewr s of
EmptyR -> return True
_ :> _ -> return False
tryPopL :: SimpleDeque a -> IO (Maybe a)
tryPopL (DQ _ qr) = modify qr $ \s ->
case viewl s of
EmptyL -> (empty, Nothing)
x :< s' -> (s', Just x)
pushR :: SimpleDeque t -> t -> IO ()
pushR (DQ 0 qr) x = modify qr (\s -> (s |> x, ()))
pushR (DQ n _) _ = error$ "should not call pushR on Deque with size bound "++ show n
tryPushL :: SimpleDeque a -> a -> IO Bool
tryPushL q@(DQ 0 _) v = pushL q v >> return True
tryPushL (DQ lim qr) v =
modify qr $ \s ->
if length s == lim
then (s, False)
else (v <| s, True)
tryPushR :: SimpleDeque a -> a -> IO Bool
tryPushR q@(DQ 0 _) v = pushR q v >> return True
tryPushR (DQ lim qr) v =
modify qr $ \s ->
if length s == lim
then (s, False)
else (s |> v, True)
instance C.DequeClass SimpleDeque where
newQ = newQ
nullQ = nullQ
pushL = pushL
tryPopR = tryPopR
leftThreadSafe _ = True
rightThreadSafe _ = True
instance C.PopL SimpleDeque where
tryPopL = tryPopL
instance C.PushR SimpleDeque where
pushR = pushR
instance C.BoundedL SimpleDeque where
tryPushL = tryPushL
newBoundedQ = newBoundedQ
instance C.BoundedR SimpleDeque where
tryPushR = tryPushR