{-# 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 { Queue m si sm so a -> Int
queueMaxCount :: Int,
          -- ^ The queue capacity.
          Queue m si sm so a -> si
enqueueStrategy :: si,
          -- ^ The strategy applied to the enqueueing (input) processes when the queue is full.
          Queue m si sm so a -> sm
enqueueStoringStrategy :: sm,
          -- ^ The strategy applied when storing (in memory) items in the queue.
          Queue m si sm so a -> so
dequeueStrategy :: so,
          -- ^ The strategy applied to the dequeueing (output) processes when the queue is empty.
          Queue m si sm so a -> Resource m si
enqueueRes :: Resource m si,
          Queue m si sm so a -> StrategyQueue m sm a
queueStore :: StrategyQueue m sm a,
          Queue m si sm so a -> Resource m so
dequeueRes :: Resource m so,
          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 :: Int -> Simulation m (FCFSQueue m a)
newFCFSQueue = FCFS -> FCFS -> FCFS -> Int -> Simulation m (FCFSQueue m a)
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 :: Int -> Simulation m (LCFSQueue m a)
newLCFSQueue = FCFS -> LCFS -> FCFS -> Int -> Simulation m (LCFSQueue m a)
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 :: Int -> Simulation m (SIROQueue m a)
newSIROQueue = FCFS -> SIRO -> FCFS -> Int -> Simulation m (SIROQueue m a)
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 :: Int -> Simulation m (PriorityQueue m a)
newPriorityQueue = FCFS
-> StaticPriorities
-> FCFS
-> Int
-> Simulation m (PriorityQueue m a)
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 :: 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  <- Int -> Simulation m (Ref m Int)
forall (m :: * -> *) a. MonadRef m => a -> Simulation m (Ref m a)
newRef Int
0
     Resource m si
ri <- si -> Int -> Maybe Int -> Simulation m (Resource m si)
forall (m :: * -> *) s.
(MonadDES m, QueueStrategy m s) =>
s -> Int -> Maybe Int -> Simulation m (Resource m s)
newResourceWithMaxCount si
si Int
count (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
count)
     StrategyQueue m sm a
qm <- sm -> Simulation m (StrategyQueue m sm a)
forall (m :: * -> *) s a.
QueueStrategy m s =>
s -> Simulation m (StrategyQueue m s a)
newStrategyQueue sm
sm
     Resource m so
ro <- so -> Int -> Maybe Int -> Simulation m (Resource m so)
forall (m :: * -> *) s.
(MonadDES m, QueueStrategy m s) =>
s -> Int -> Maybe Int -> Simulation m (Resource m s)
newResourceWithMaxCount so
so Int
0 (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
count)
     Queue m si sm so a -> Simulation m (Queue m si sm so a)
forall (m :: * -> *) a. Monad m => a -> m a
return Queue :: forall (m :: * -> *) si sm so a.
Int
-> si
-> sm
-> so
-> Resource m si
-> StrategyQueue m sm a
-> Resource m so
-> Ref m Int
-> Queue m si sm so a
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 :: Queue m si sm so a -> Event m Bool
queueNull Queue m si sm so a
q =
  (Point m -> m Bool) -> Event m Bool
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m Bool) -> Event m Bool)
-> (Point m -> m Bool) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
n <- Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$ Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
n Int -> Int -> Bool
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 :: Queue m si sm so a -> Event m Bool
queueFull Queue m si sm so a
q =
  (Point m -> m Bool) -> Event m Bool
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m Bool) -> Event m Bool)
-> (Point m -> m Bool) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
n <- Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$ Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
forall (m :: * -> *) si sm so a. Queue m si sm so a -> Ref m Int
queueCountRef Queue m si sm so a
q)
     Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Queue m si sm so a -> Int
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 :: Queue m si sm so a -> Event m Int
queueCount Queue m si sm so a
q =
  (Point m -> m Int) -> Event m Int
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m Int) -> Event m Int)
-> (Point m -> m Int) -> Event m Int
forall a b. (a -> b) -> a -> b
$ \Point m
p -> Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$ Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
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 :: Queue m si sm so a -> Process m a
dequeue Queue m si sm so a
q =
  do Resource m so -> Process m ()
forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (Queue m si sm so a -> Resource m so
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
     Event m a -> Process m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m a -> Process m a) -> Event m a -> Process m a
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> Event m a
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 :: Queue m si sm so a -> po -> Process m a
dequeueWithOutputPriority Queue m si sm so a
q po
po =
  do Resource m so -> po -> Process m ()
forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (Queue m si sm so a -> Resource m so
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
     Event m a -> Process m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m a -> Process m a) -> Event m a -> Process m a
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> Event m a
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 :: Queue m si sm so a -> Event m (Maybe a)
tryDequeue Queue m si sm so a
q =
  do Bool
x <- Resource m so -> Event m Bool
forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (Queue m si sm so a -> Resource m so
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 (a -> Maybe a) -> Event m a -> Event m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Maybe a
forall a. a -> Maybe a
Just (Event m a -> Event m (Maybe a)) -> Event m a -> Event m (Maybe a)
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> Event m a
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 Maybe a -> Event m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
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 :: Queue m si sm so a -> a -> Event m Bool
queueDelete Queue m si sm so a
q a
a = (Maybe a -> Bool) -> Event m (Maybe a) -> Event m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Event m (Maybe a) -> Event m Bool)
-> Event m (Maybe a) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
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 -> a -> Bool
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_ :: Queue m si sm so a -> a -> Event m ()
queueDelete_ Queue m si sm so a
q a
a = (Maybe a -> ()) -> Event m (Maybe a) -> Event m ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> Maybe a -> ()
forall a b. a -> b -> a
const ()) (Event m (Maybe a) -> Event m ())
-> Event m (Maybe a) -> Event m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
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 -> a -> Bool
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 :: 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 <- Resource m so -> Event m Bool
forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (Queue m si sm so a -> Resource m so
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 <- StrategyQueue m sm a -> (a -> Bool) -> Event m (Maybe a)
forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueDeleteBy (Queue m si sm so a -> StrategyQueue m sm a
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 Resource m so -> Event m ()
forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (Queue m si sm so a -> Resource m so
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m so
dequeueRes Queue m si sm so a
q)
                      Maybe a -> Event m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing
                 Just a
i ->
                   (a -> Maybe a) -> Event m a -> Event m (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Maybe a
forall a. a -> Maybe a
Just (Event m a -> Event m (Maybe a)) -> Event m a -> Event m (Maybe a)
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> a -> Event m a
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 Maybe a -> Event m (Maybe a)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
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_ :: Queue m si sm so a -> (a -> Bool) -> Event m ()
queueDeleteBy_ Queue m si sm so a
q a -> Bool
pred = (Maybe a -> ()) -> Event m (Maybe a) -> Event m ()
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> Maybe a -> ()
forall a b. a -> b -> a
const ()) (Event m (Maybe a) -> Event m ())
-> Event m (Maybe a) -> Event m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
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 :: Queue m si sm so a -> a -> Event m Bool
queueContains Queue m si sm so a
q a
a = (Maybe a -> Bool) -> Event m (Maybe a) -> Event m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Event m (Maybe a) -> Event m Bool)
-> Event m (Maybe a) -> Event m Bool
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
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 -> a -> Bool
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 :: Queue m si sm so a -> (a -> Bool) -> Event m (Maybe a)
queueContainsBy Queue m si sm so a
q a -> Bool
pred =
  StrategyQueue m sm a -> (a -> Bool) -> Event m (Maybe a)
forall (m :: * -> *) s a.
DeletingQueueStrategy m s =>
StrategyQueue m s a -> (a -> Bool) -> Event m (Maybe a)
strategyQueueContainsBy (Queue m si sm so a -> StrategyQueue m sm a
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 :: Queue m si sm so a -> Event m ()
clearQueue Queue m si sm so a
q =
  do Maybe a
x <- Queue m si sm so a -> Event m (Maybe a)
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 -> () -> Event m ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
       Just a
a  -> Queue m si sm so a -> Event m ()
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 :: Queue m si sm so a -> a -> Process m ()
enqueue Queue m si sm so a
q a
a =
  do Resource m si -> Process m ()
forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (Queue m si sm so a -> Resource m si
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     Event m () -> Process m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m () -> Process m ()) -> Event m () -> Process m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> a -> Event m ()
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 :: Queue m si sm so a -> pi -> a -> Process m ()
enqueueWithInputPriority Queue m si sm so a
q pi
pi a
a =
  do Resource m si -> pi -> Process m ()
forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (Queue m si sm so a -> Resource m si
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
     Event m () -> Process m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m () -> Process m ()) -> Event m () -> Process m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> a -> Event m ()
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 :: Queue m si sm so a -> pm -> a -> Process m ()
enqueueWithStoringPriority Queue m si sm so a
q pm
pm a
a =
  do Resource m si -> Process m ()
forall (m :: * -> *) s.
(MonadDES m, EnqueueStrategy m s) =>
Resource m s -> Process m ()
requestResource (Queue m si sm so a -> Resource m si
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     Event m () -> Process m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m () -> Process m ()) -> Event m () -> Process m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> pm -> a -> Event m ()
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 :: 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 Resource m si -> pi -> Process m ()
forall (m :: * -> *) s p.
(MonadDES m, PriorityQueueStrategy m s p) =>
Resource m s -> p -> Process m ()
requestResourceWithPriority (Queue m si sm so a -> Resource m si
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
     Event m () -> Process m ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent (Event m () -> Process m ()) -> Event m () -> Process m ()
forall a b. (a -> b) -> a -> b
$ Queue m si sm so a -> pm -> a -> Event m ()
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 :: Queue m si sm so a -> a -> Event m Bool
tryEnqueue Queue m si sm so a
q a
a =
  do Bool
x <- Resource m si -> Event m Bool
forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (Queue m si sm so a -> Resource m si
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 Queue m si sm so a -> a -> Event m ()
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
               Bool -> Event m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
       else Bool -> Event m Bool
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 :: 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 <- Resource m si -> Event m Bool
forall (m :: * -> *) s. MonadDES m => Resource m s -> Event m Bool
tryRequestResourceWithinEvent (Queue m si sm so a -> Resource m si
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 Queue m si sm so a -> pm -> a -> Event m ()
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
               Bool -> Event m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
       else Bool -> Event m Bool
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 :: Queue m si sm so a -> a -> Event m ()
enqueueStore Queue m si sm so a
q a
a =
  (Point m -> m ()) -> Event m ()
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m ()) -> Event m ())
-> (Point m -> m ()) -> Event m ()
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       StrategyQueue m sm a -> a -> Event m ()
forall (m :: * -> *) s a.
EnqueueStrategy m s =>
StrategyQueue m s a -> a -> Event m ()
strategyEnqueue (Queue m si sm so a -> StrategyQueue m sm a
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 <- Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$
          Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
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 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
     Int
c' Int -> m () -> m ()
`seq` Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Ref m Int -> Int -> Event m ()
forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (Queue m si sm so a -> Ref m Int
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'
     Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Resource m so -> Event m ()
forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (Queue m si sm so a -> Resource m so
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 :: Queue m si sm so a -> pm -> a -> Event m ()
enqueueStoreWithPriority Queue m si sm so a
q pm
pm a
a =
  (Point m -> m ()) -> Event m ()
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m ()) -> Event m ())
-> (Point m -> m ()) -> Event m ()
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       StrategyQueue m sm a -> pm -> a -> Event m ()
forall (m :: * -> *) s p a.
PriorityQueueStrategy m s p =>
StrategyQueue m s a -> p -> a -> Event m ()
strategyEnqueueWithPriority (Queue m si sm so a -> StrategyQueue m sm a
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 <- Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$
          Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
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 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
     Int
c' Int -> m () -> m ()
`seq` Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Ref m Int -> Int -> Event m ()
forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (Queue m si sm so a -> Ref m Int
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'
     Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Resource m so -> Event m ()
forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (Queue m si sm so a -> Resource m so
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 :: Queue m si sm so a -> Event m a
dequeueExtract Queue m si sm so a
q =
  (Point m -> m a) -> Event m a
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m a) -> Event m a) -> (Point m -> m a) -> Event m a
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do a
a <- Point m -> Event m a -> m a
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m a -> m a) -> Event m a -> m a
forall a b. (a -> b) -> a -> b
$
          StrategyQueue m sm a -> Event m a
forall (m :: * -> *) s a.
DequeueStrategy m s =>
StrategyQueue m s a -> Event m a
strategyDequeue (Queue m si sm so a -> StrategyQueue m sm a
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> StrategyQueue m sm a
queueStore Queue m si sm so a
q)
     Point m -> Event m a -> m a
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m a -> m a) -> Event m a -> m a
forall a b. (a -> b) -> a -> b
$
       Queue m si sm so a -> a -> Event m a
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 :: Queue m si sm so a -> a -> Event m a
dequeuePostExtract Queue m si sm so a
q a
a =
  (Point m -> m a) -> Event m a
forall (m :: * -> *) a. (Point m -> m a) -> Event m a
Event ((Point m -> m a) -> Event m a) -> (Point m -> m a) -> Event m a
forall a b. (a -> b) -> a -> b
$ \Point m
p ->
  do Int
c <- Point m -> Event m Int -> m Int
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m Int -> m Int) -> Event m Int -> m Int
forall a b. (a -> b) -> a -> b
$
          Ref m Int -> Event m Int
forall (m :: * -> *) a. MonadRef m => Ref m a -> Event m a
readRef (Queue m si sm so a -> Ref m Int
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 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
     Int
c' Int -> m () -> m ()
`seq` Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Ref m Int -> Int -> Event m ()
forall (m :: * -> *) a. MonadRef m => Ref m a -> a -> Event m ()
writeRef (Queue m si sm so a -> Ref m Int
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'
     Point m -> Event m () -> m ()
forall (m :: * -> *) a. Point m -> Event m a -> m a
invokeEvent Point m
p (Event m () -> m ()) -> Event m () -> m ()
forall a b. (a -> b) -> a -> b
$
       Resource m si -> Event m ()
forall (m :: * -> *) s.
(MonadDES m, DequeueStrategy m s) =>
Resource m s -> Event m ()
releaseResourceWithinEvent (Queue m si sm so a -> Resource m si
forall (m :: * -> *) si sm so a.
Queue m si sm so a -> Resource m si
enqueueRes Queue m si sm so a
q)
     a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a