{-# LANGUAGE FlexibleContexts #-}

-- |
-- Module     : Simulation.Aivika.Trans.Queue.Base
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- This module defines an optimised finite queue, which has no counters nor signals.
--
module Simulation.Aivika.Trans.Queue.Base
       (-- * Queue Types
        FCFSQueue,
        LCFSQueue,
        SIROQueue,
        PriorityQueue,
        Queue,
        -- * Creating Queue
        newFCFSQueue,
        newLCFSQueue,
        newSIROQueue,
        newPriorityQueue,
        newQueue,
        -- * Queue Properties and Activities
        enqueueStrategy,
        enqueueStoringStrategy,
        dequeueStrategy,
        queueNull,
        queueFull,
        queueMaxCount,
        queueCount,
        -- * Dequeuing and Enqueuing
        dequeue,
        dequeueWithOutputPriority,
        tryDequeue,
        enqueue,
        enqueueWithInputPriority,
        enqueueWithStoringPriority,
        enqueueWithInputStoringPriorities,
        tryEnqueue,
        tryEnqueueWithStoringPriority,
        queueDelete,
        queueDelete_,
        queueDeleteBy,
        queueDeleteBy_,
        queueContains,
        queueContainsBy,
        clearQueue) where

import Data.Monoid
import Data.Maybe

import Control.Monad
import Control.Monad.Trans

import Simulation.Aivika.Trans.Ref.Base
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Parameter
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Dynamics
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Internal.Process
import Simulation.Aivika.Trans.Resource.Base
import Simulation.Aivika.Trans.QueueStrategy

-- | A type synonym for the ordinary FIFO queue also known as the FCFS
-- (First Come - First Serviced) queue.
type FCFSQueue m a = Queue m FCFS FCFS FCFS a

-- | A type synonym for the ordinary LIFO queue also known as the LCFS
-- (Last Come - First Serviced) queue.
type LCFSQueue m a = Queue m FCFS LCFS FCFS a

-- | A type synonym for the SIRO (Serviced in Random Order) queue.
type SIROQueue m a = Queue m FCFS SIRO FCFS a

-- | A type synonym for the queue with static priorities applied when
-- storing the elements in the queue.
type PriorityQueue m a = Queue m FCFS StaticPriorities FCFS a

-- | Represents a queue using the specified strategies for enqueueing (input), @si@,
-- internal storing (in memory), @sm@, and dequeueing (output), @so@, where @a@ denotes
-- the type of items stored in the queue. Type @m@ denotes the underlying monad within
-- which the simulation executes.
data Queue m si sm so a =
  Queue { forall (m :: * -> *) si sm so a. Queue m si sm so a -> Int
queueMaxCount :: Int,
          -- ^ The queue capacity.
          forall (m :: * -> *) si sm so a. Queue m si sm so a -> si
enqueueStrategy :: si,
          -- ^ The strategy applied to the enqueueing (input) processes when the queue is full.
          forall (m :: * -> *) si sm so a. Queue m si sm so a -> sm
enqueueStoringStrategy :: sm,
          -- ^ The strategy applied when storing (in memory) items in the queue.
          forall (m :: * -> *) si sm so a. Queue m si sm so a -> so
dequeueStrategy :: so,
          -- ^ The strategy applied to the dequeueing (output) processes when the queue is empty.
          forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes :: Resource m si,
          forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore :: StrategyQueue m sm a,
          forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes :: Resource m so,
          forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef :: Ref m Int
        }

-- | Create a new FCFS queue with the specified capacity.  
newFCFSQueue :: MonadDES m => Int -> Simulation m (FCFSQueue m a)
{-# INLINABLE newFCFSQueue #-}
newFCFSQueue :: forall (m :: * -> *) a.
MonadDES m =>
Int -> Simulation m (FCFSQueue m a)
newFCFSQueue = forall (m :: * -> *) si sm so a.
(MonadDES m, QueueStrategy m si, QueueStrategy m sm,
 QueueStrategy m so) =>
si -> sm -> so -> Int -> Simulation m (Queue m si sm so a)
newQueue FCFS
FCFS FCFS
FCFS FCFS
FCFS
  
-- | Create a new LCFS queue with the specified capacity.  
newLCFSQueue :: MonadDES m => Int -> Simulation m (LCFSQueue m a)
{-# INLINABLE newLCFSQueue #-}
newLCFSQueue :: forall (m :: * -> *) a.
MonadDES m =>
Int -> Simulation m (LCFSQueue m a)
newLCFSQueue = forall (m :: * -> *) si sm so a.
(MonadDES m, QueueStrategy m si, QueueStrategy m sm,
 QueueStrategy m so) =>
si -> sm -> so -> Int -> Simulation m (Queue m si sm so a)
newQueue FCFS
FCFS LCFS
LCFS FCFS
FCFS
  
-- | Create a new SIRO queue with the specified capacity.  
newSIROQueue :: (MonadDES m, QueueStrategy m SIRO) => Int -> Simulation m (SIROQueue m a)
{-# INLINABLE newSIROQueue #-}
newSIROQueue :: forall (m :: * -> *) a.
(MonadDES m, QueueStrategy m SIRO) =>
Int -> Simulation m (SIROQueue m a)
newSIROQueue = forall (m :: * -> *) si sm so a.
(MonadDES m, QueueStrategy m si, QueueStrategy m sm,
 QueueStrategy m so) =>
si -> sm -> so -> Int -> Simulation m (Queue m si sm so a)
newQueue FCFS
FCFS SIRO
SIRO FCFS
FCFS
  
-- | Create a new priority queue with the specified capacity.  
newPriorityQueue :: (MonadDES m, QueueStrategy m StaticPriorities) => Int -> Simulation m (PriorityQueue m a)
{-# INLINABLE newPriorityQueue #-}
newPriorityQueue :: forall (m :: * -> *) a.
(MonadDES m, QueueStrategy m StaticPriorities) =>
Int -> Simulation m (PriorityQueue m a)
newPriorityQueue = forall (m :: * -> *) si sm so a.
(MonadDES m, QueueStrategy m si, QueueStrategy m sm,
 QueueStrategy m so) =>
si -> sm -> so -> Int -> Simulation m (Queue m si sm so a)
newQueue FCFS
FCFS StaticPriorities
StaticPriorities FCFS
FCFS
  
-- | Create a new queue with the specified strategies and capacity.  
newQueue :: (MonadDES m,
             QueueStrategy m si,
             QueueStrategy m sm,
             QueueStrategy m so) =>
            si
            -- ^ the strategy applied to the enqueueing (input) processes when the queue is full
            -> sm
            -- ^ the strategy applied when storing items in the queue
            -> so
            -- ^ the strategy applied to the dequeueing (output) processes when the queue is empty
            -> Int
            -- ^ the queue capacity
            -> Simulation m (Queue m si sm so a)
{-# INLINABLE newQueue #-}
newQueue :: forall (m :: * -> *) si sm so a.
(MonadDES m, QueueStrategy m si, QueueStrategy m sm,
 QueueStrategy m so) =>
si -> sm -> so -> Int -> Simulation m (Queue m si sm so a)
newQueue si
si sm
sm so
so Int
count =
  do Ref m Int
i  <- forall (m :: * -> *) a. MonadRef m => a -> Simulation m (Ref m a)
newRef Int
0
     Resource m si
ri <- forall (m :: * -> *) s.
(MonadDES m, QueueStrategy m s) =>
s -> Int -> Maybe Int -> Simulation m (Resource m s)
newResourceWithMaxCount si
si Int
count (forall a. a -> Maybe a
Just Int
count)
     StrategyQueue m sm a
qm <- forall (m :: * -> *) s a.
QueueStrategy m s =>
s -> Simulation m (StrategyQueue m s a)
newStrategyQueue sm
sm
     Resource m so
ro <- forall (m :: * -> *) s.
(MonadDES m, QueueStrategy m s) =>
s -> Int -> Maybe Int -> Simulation m (Resource m s)
newResourceWithMaxCount so
so Int
0 (forall a. a -> Maybe a
Just Int
count)
     forall (m :: * -> *) a. Monad m => a -> m a
return Queue { queueMaxCount :: Int
queueMaxCount = Int
count,
                    enqueueStrategy :: si
enqueueStrategy = si
si,
                    enqueueStoringStrategy :: sm
enqueueStoringStrategy = sm
sm,
                    dequeueStrategy :: so
dequeueStrategy = so
so,
                    enqueueRes :: Resource m si
enqueueRes = Resource m si
ri,
                    queueStore :: StrategyQueue m sm a
queueStore = StrategyQueue m sm a
qm,
                    dequeueRes :: Resource m so
dequeueRes = Resource m so
ro,
                    queueCountRef :: Ref m Int
queueCountRef = Ref m Int
i }
  
-- | Test whether the queue is empty.
--
-- See also 'queueNullChanged' and 'queueNullChanged_'.
queueNull :: MonadDES m => Queue m si sm so a -> Event m Bool
{-# INLINABLE queueNull #-}
queueNull :: forall (m :: * -> *) si sm so a.
MonadDES m =>
Queue m si sm so a -> Event m Bool
queueNull Queue m si sm so a
q =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
n <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     forall (m :: * -> *) a. Monad m => a -> m a
return (Int
n forall a. Eq a => a -> a -> Bool
== Int
0)
  
-- | Test whether the queue is full.
--
-- See also 'queueFullChanged' and 'queueFullChanged_'.
queueFull :: MonadDES m => Queue m si sm so a -> Event m Bool
{-# INLINABLE queueFull #-}
queueFull :: forall (m :: * -> *) si sm so a.
MonadDES m =>
Queue m si sm so a -> Event m Bool
queueFull Queue m si sm so a
q =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
n <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     forall (m :: * -> *) a. Monad m => a -> m a
return (Int
n forall a. Eq a => a -> a -> Bool
== forall (m :: * -> *) si sm so a. Queue m si sm so a -> Int
queueMaxCount Queue m si sm so a
q)
  
-- | Return the current queue size.
--
-- See also 'queueCountStats', 'queueCountChanged' and 'queueCountChanged_'.
queueCount :: MonadDES m => Queue m si sm so a -> Event m Int
{-# INLINABLE queueCount #-}
queueCount :: forall (m :: * -> *) si sm so a.
MonadDES m =>
Queue m si sm so a -> Event m Int
queueCount Queue m si sm so a
q =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p -> forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)

-- | Dequeue suspending the process if the queue is empty.
dequeue :: (MonadDES m,
            DequeueStrategy m si,
            DequeueStrategy m sm,
            EnqueueStrategy m so)
           => Queue m si sm so a
           -- ^ the queue
           -> Process m a
           -- ^ the dequeued value
{-# INLINABLE dequeue #-}
dequeue :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm,
 EnqueueStrategy m so) =>
Queue m si sm so a -> Process m a
dequeue Queue m si sm so a
q =
  do forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m a
dequeueExtract Queue m si sm so a
q
  
-- | Dequeue with the output priority suspending the process if the queue is empty.
dequeueWithOutputPriority :: (MonadDES m,
                              DequeueStrategy m si,
                              DequeueStrategy m sm,
                              PriorityQueueStrategy m so po)
                             => Queue m si sm so a
                             -- ^ the queue
                             -> po
                             -- ^ the priority for output
                             -> Process m a
                             -- ^ the dequeued value
{-# INLINABLE dequeueWithOutputPriority #-}
dequeueWithOutputPriority :: forall (m :: * -> *) si sm so po a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm,
 PriorityQueueStrategy m so po) =>
Queue m si sm so a -> po -> Process m a
dequeueWithOutputPriority Queue m si sm so a
q po
po =
  do forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q) po
po
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m a
dequeueExtract Queue m si sm so a
q
  
-- | Try to dequeue immediately.
tryDequeue :: (MonadDES m,
               DequeueStrategy m si,
               DequeueStrategy m sm)
              => Queue m si sm so a
              -- ^ the queue
              -> Event m (Maybe a)
              -- ^ the dequeued value of 'Nothing'
{-# INLINABLE tryDequeue #-}
tryDequeue :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m (Maybe a)
tryDequeue Queue m si sm so a
q =
  do Bool
x <- forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
     if Bool
x 
       then forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m a
dequeueExtract Queue m si sm so a
q
       else forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing

-- | Remove the item from the queue and return a flag indicating
-- whether the item was found and actually removed.
queueDelete :: (MonadDES m,
                Eq a,
                DequeueStrategy m si,
                DeletingQueueStrategy m sm,
                DequeueStrategy m so)
               => Queue m si sm so a
               -- ^ the queue
               -> a
               -- ^ the item to remove from the queue
               -> Event m Bool
               -- ^ whether the item was found and removed
{-# INLINABLE queueDelete #-}
queueDelete :: forall (m :: * -> *) a si sm so.
(MonadDES m, Eq a, DequeueStrategy m si,
 DeletingQueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m Bool
queueDelete Queue m si sm so a
q a
a = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DeletingQueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueDeleteBy Queue m si sm so a
q (forall a. Eq a => a -> a -> Bool
== a
a)

-- | Remove the specified item from the queue.
queueDelete_ :: (MonadDES m,
                 Eq a,
                 DequeueStrategy m si,
                 DeletingQueueStrategy m sm,
                 DequeueStrategy m so)
                => Queue m si sm so a
                -- ^ the queue
                -> a
                -- ^ the item to remove from the queue
                -> Event m ()
{-# INLINABLE queueDelete_ #-}
queueDelete_ :: forall (m :: * -> *) a si sm so.
(MonadDES m, Eq a, DequeueStrategy m si,
 DeletingQueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m ()
queueDelete_ Queue m si sm so a
q a
a = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. a -> b -> a
const ()) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DeletingQueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueDeleteBy Queue m si sm so a
q (forall a. Eq a => a -> a -> Bool
== a
a)

-- | Remove an item satisfying the specified predicate and return the item if found.
queueDeleteBy :: (MonadDES m,
                  DequeueStrategy m si,
                  DeletingQueueStrategy m sm,
                  DequeueStrategy m so)
                 => Queue m si sm so a
                 -- ^ the queue
                 -> (a -> Bool)
                 -- ^ the predicate
                 -> Event m (Maybe a)
{-# INLINABLE queueDeleteBy #-}
queueDeleteBy :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DeletingQueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueDeleteBy Queue m si sm so a
q a -> Bool
pred =
  do Bool
x <- forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
     if Bool
x
       then do Maybe a
i <- forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueDeleteBy (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q) a -> Bool
pred
               case Maybe a
i of
                 Maybe a
Nothing ->
                   do forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
                      forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
                 Just a
i ->
                   forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> a -> Event m a
dequeuePostExtract Queue m si sm so a
q a
i
       else forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
               
-- | Remove an item satisfying the specified predicate.
queueDeleteBy_ :: (MonadDES m,
                   DequeueStrategy m si,
                   DeletingQueueStrategy m sm,
                   DequeueStrategy m so)
                  => Queue m si sm so a
                  -- ^ the queue
                  -> (a -> Bool)
                  -- ^ the predicate
                  -> Event m ()
{-# INLINABLE queueDeleteBy_ #-}
queueDeleteBy_ :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DeletingQueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> (a -> Bool) -> Event m ()
queueDeleteBy_ Queue m si sm so a
q a -> Bool
pred = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. a -> b -> a
const ()) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DeletingQueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueDeleteBy Queue m si sm so a
q a -> Bool
pred

-- | Detect whether the item is contained in the queue.
queueContains :: (MonadDES m,
                  Eq a,
                  DeletingQueueStrategy m sm)
                 => Queue m si sm so a
                 -- ^ the queue
                 -> a
                 -- ^ the item to search the queue for
                 -> Event m Bool
                 -- ^ whether the item was found
{-# INLINABLE queueContains #-}
queueContains :: forall (m :: * -> *) a sm si so.
(MonadDES m, Eq a, DeletingQueueStrategy m sm) =>
Queue m si sm so a -> a -> Event m Bool
queueContains Queue m si sm so a
q a
a = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) sm si so a.
(MonadDES m, DeletingQueueStrategy m sm) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueContainsBy Queue m si sm so a
q (forall a. Eq a => a -> a -> Bool
== a
a)

-- | Detect whether an item satisfying the specified predicate is contained in the queue.
queueContainsBy :: (MonadDES m,
                    DeletingQueueStrategy m sm)
                   => Queue m si sm so a
                   -- ^ the queue
                   -> (a -> Bool)
                   -- ^ the predicate
                   -> Event m (Maybe a)
                   -- ^ the item if it was found
{-# INLINABLE queueContainsBy #-}
queueContainsBy :: forall (m :: * -> *) sm si so a.
(MonadDES m, DeletingQueueStrategy m sm) =>
Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueContainsBy Queue m si sm so a
q a -> Bool
pred =
  forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueContainsBy (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q) a -> Bool
pred

-- | Clear the queue immediately.
clearQueue :: (MonadDES m,
               DequeueStrategy m si,
               DequeueStrategy m sm)
              => Queue m si sm so a
              -- ^ the queue
              -> Event m ()
{-# INLINABLE clearQueue #-}
clearQueue :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m ()
clearQueue Queue m si sm so a
q =
  do Maybe a
x <- forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m (Maybe a)
tryDequeue Queue m si sm so a
q
     case Maybe a
x of
       Maybe a
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
       Just a
a  -> forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m ()
clearQueue Queue m si sm so a
q
              
-- | Enqueue the item suspending the process if the queue is full.  
enqueue :: (MonadDES m,
            EnqueueStrategy m si,
            EnqueueStrategy m sm,
            DequeueStrategy m so)
           => Queue m si sm so a
           -- ^ the queue
           -> a
           -- ^ the item to enqueue
           -> Process m ()
{-# INLINABLE enqueue #-}
enqueue :: forall (m :: * -> *) si sm so a.
(MonadDES m, EnqueueStrategy m si, EnqueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> a -> Process m ()
enqueue Queue m si sm so a
q a
a =
  do forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) sm so si a.
(MonadDES m, EnqueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m ()
enqueueStore Queue m si sm so a
q a
a
     
-- | Enqueue with the input priority the item suspending the process if the queue is full.  
enqueueWithInputPriority :: (MonadDES m,
                             PriorityQueueStrategy m si pi,
                             EnqueueStrategy m sm,
                             DequeueStrategy m so)
                            => Queue m si sm so a
                            -- ^ the queue
                            -> pi
                            -- ^ the priority for input
                            -> a
                            -- ^ the item to enqueue
                            -> Process m ()
{-# INLINABLE enqueueWithInputPriority #-}
enqueueWithInputPriority :: forall (m :: * -> *) si pi sm so a.
(MonadDES m, PriorityQueueStrategy m si pi, EnqueueStrategy m sm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pi -> a -> Process m ()
enqueueWithInputPriority Queue m si sm so a
q pi
pi a
a =
  do forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q) pi
pi
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) sm so si a.
(MonadDES m, EnqueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m ()
enqueueStore Queue m si sm so a
q a
a
     
-- | Enqueue with the storing priority the item suspending the process if the queue is full.  
enqueueWithStoringPriority :: (MonadDES m,
                               EnqueueStrategy m si,
                               PriorityQueueStrategy m sm pm,
                               DequeueStrategy m so)
                              => Queue m si sm so a
                              -- ^ the queue
                              -> pm
                              -- ^ the priority for storing
                              -> a
                              -- ^ the item to enqueue
                              -> Process m ()
{-# INLINABLE enqueueWithStoringPriority #-}
enqueueWithStoringPriority :: forall (m :: * -> *) si sm pm so a.
(MonadDES m, EnqueueStrategy m si, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Process m ()
enqueueWithStoringPriority Queue m si sm so a
q pm
pm a
a =
  do forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) sm pm so si a.
(MonadDES m, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Event m ()
enqueueStoreWithPriority Queue m si sm so a
q pm
pm a
a
     
-- | Enqueue with the input and storing priorities the item suspending the process if the queue is full.  
enqueueWithInputStoringPriorities :: (MonadDES m,
                                      PriorityQueueStrategy m si pi,
                                      PriorityQueueStrategy m sm pm,
                                      DequeueStrategy m so)
                                     => Queue m si sm so a
                                     -- ^ the queue
                                     -> pi
                                     -- ^ the priority for input
                                     -> pm
                                     -- ^ the priority for storing
                                     -> a
                                     -- ^ the item to enqueue
                                     -> Process m ()
{-# INLINABLE enqueueWithInputStoringPriorities #-}
enqueueWithInputStoringPriorities :: forall (m :: * -> *) si pi sm pm so a.
(MonadDES m, PriorityQueueStrategy m si pi,
 PriorityQueueStrategy m sm pm, DequeueStrategy m so) =>
Queue m si sm so a -> pi -> pm -> a -> Process m ()
enqueueWithInputStoringPriorities Queue m si sm so a
q pi
pi pm
pm a
a =
  do forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q) pi
pi
     forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) sm pm so si a.
(MonadDES m, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Event m ()
enqueueStoreWithPriority Queue m si sm so a
q pm
pm a
a
     
-- | Try to enqueue the item. Return 'False' in the monad if the queue is full.
tryEnqueue :: (MonadDES m,
               EnqueueStrategy m sm,
               DequeueStrategy m so)
              => Queue m si sm so a
              -- ^ the queue
              -> a
              -- ^ the item which we try to enqueue
              -> Event m Bool
{-# INLINABLE tryEnqueue #-}
tryEnqueue :: forall (m :: * -> *) sm so si a.
(MonadDES m, EnqueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m Bool
tryEnqueue Queue m si sm so a
q a
a =
  do Bool
x <- forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     if Bool
x 
       then do forall (m :: * -> *) sm so si a.
(MonadDES m, EnqueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m ()
enqueueStore Queue m si sm so a
q a
a
               forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
       else forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

-- | Try to enqueue with the storing priority the item. Return 'False' in
-- the monad if the queue is full.
tryEnqueueWithStoringPriority :: (MonadDES m,
                                  PriorityQueueStrategy m sm pm,
                                  DequeueStrategy m so)
                                 => Queue m si sm so a
                                 -- ^ the queue
                                 -> pm
                                 -- ^ the priority for storing
                                 -> a
                                 -- ^ the item which we try to enqueue
                                 -> Event m Bool
{-# INLINABLE tryEnqueueWithStoringPriority #-}
tryEnqueueWithStoringPriority :: forall (m :: * -> *) sm pm so si a.
(MonadDES m, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Event m Bool
tryEnqueueWithStoringPriority Queue m si sm so a
q pm
pm a
a =
  do Bool
x <- forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     if Bool
x 
       then do forall (m :: * -> *) sm pm so si a.
(MonadDES m, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Event m ()
enqueueStoreWithPriority Queue m si sm so a
q pm
pm a
a
               forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
       else forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

-- | Store the item.
enqueueStore :: (MonadDES m,
                 EnqueueStrategy m sm,
                 DequeueStrategy m so)
                => Queue m si sm so a
                -- ^ the queue
                -> a
                -- ^ the item to be stored
                -> Event m ()
{-# INLINE enqueueStore #-}
enqueueStore :: forall (m :: * -> *) sm so si a.
(MonadDES m, EnqueueStrategy m sm, DequeueStrategy m so) =>
Queue m si sm so a -> a -> Event m ()
enqueueStore Queue m si sm so a
q a
a =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) s a.
EnqueueStrategy m s =>
StrategyQueue m s a -> a -> Event m ()
strategyEnqueue (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q) a
a
     Int
c <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
          forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     let c' :: Int
c' = Int
c forall a. Num a => a -> a -> a
+ Int
1
     Int
c' seq :: forall a b. a -> b -> b
`seq` forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q) Int
c'
     forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)

-- | Store with the priority the item.
enqueueStoreWithPriority :: (MonadDES m,
                             PriorityQueueStrategy m sm pm,
                             DequeueStrategy m so)
                            => Queue m si sm so a
                            -- ^ the queue
                            -> pm
                            -- ^ the priority for storing
                            -> a
                            -- ^ the item to be enqueued
                            -> Event m ()
{-# INLINE enqueueStoreWithPriority #-}
enqueueStoreWithPriority :: forall (m :: * -> *) sm pm so si a.
(MonadDES m, PriorityQueueStrategy m sm pm,
 DequeueStrategy m so) =>
Queue m si sm so a -> pm -> a -> Event m ()
enqueueStoreWithPriority Queue m si sm so a
q pm
pm a
a =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) s p a.
PriorityQueueStrategy m s p =>
StrategyQueue m s a -> p -> a -> Event m ()
strategyEnqueueWithPriority (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q) pm
pm a
a
     Int
c <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
          forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     let c' :: Int
c' = Int
c forall a. Num a => a -> a -> a
+ Int
1
     Int
c' seq :: forall a b. a -> b -> b
`seq` forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q) Int
c'
     forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)

-- | Extract an item for the dequeuing request.  
dequeueExtract :: (MonadDES m,
                   DequeueStrategy m si,
                   DequeueStrategy m sm)
                  => Queue m si sm so a
                  -- ^ the queue
                  -> Event m a
                  -- ^ the dequeued value
{-# INLINE dequeueExtract #-}
dequeueExtract :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> Event m a
dequeueExtract Queue m si sm so a
q =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do a
a <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
          forall (m :: * -> *) s a.
DequeueStrategy m s =>
StrategyQueue m s a -> Event m a
strategyDequeue (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q)
     forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> a -> Event m a
dequeuePostExtract Queue m si sm so a
q a
a

-- | A post action after extracting the item by the dequeuing request.  
dequeuePostExtract :: (MonadDES m,
                       DequeueStrategy m si,
                       DequeueStrategy m sm)
                      => Queue m si sm so a
                      -- ^ the queue
                      -> a
                      -- ^ the item to dequeue
                      -> Event m a
                      -- ^ the dequeued value
{-# INLINE dequeuePostExtract #-}
dequeuePostExtract :: forall (m :: * -> *) si sm so a.
(MonadDES m, DequeueStrategy m si, DequeueStrategy m sm) =>
Queue m si sm so a -> a -> Event m a
dequeuePostExtract Queue m si sm so a
q a
a =
  forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
c <- forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
          forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     let c' :: Int
c' = Int
c forall a. Num a => a -> a -> a
- Int
1
     Int
c' seq :: forall a b. a -> b -> b
`seq` forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q) Int
c'
     forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     forall (m :: * -> *) a. Monad m => a -> m a
return a
a