module Simulation.Aivika.PriorityQueue.Pure
(PriorityQueue,
queueNull,
queueCount,
emptyQueue,
enqueue,
dequeue,
queueFront) where
import Control.Monad
data PriorityQueue a = EmptyQueue
| Queue !Int !Double a !Int (PriorityQueue a) (PriorityQueue a)
deriving Show
queueNull :: PriorityQueue a -> Bool
queueNull EmptyQueue = True
queueNull _ = False
queueCount :: PriorityQueue a -> Int
queueCount EmptyQueue = 0
queueCount (Queue n k v r a b) = n
emptyQueue :: PriorityQueue a
emptyQueue = EmptyQueue
enqueue :: PriorityQueue a -> Double -> a -> PriorityQueue a
enqueue pq k v = mergeQueues pq (Queue 1 k v 1 EmptyQueue EmptyQueue)
dequeue :: PriorityQueue a -> PriorityQueue a
dequeue EmptyQueue = error "The queue is empty: dequeue"
dequeue (Queue n k v r a b) = mergeQueues a b
queueFront :: PriorityQueue a -> (Double, a)
queueFront EmptyQueue = error "The queue is empty: queueFront"
queueFront (Queue n k v r a b) = (k, v)
queueRank :: PriorityQueue a -> Int
queueRank EmptyQueue = 0
queueRank (Queue n k v r a b) = r
makeQueue :: Double -> a -> PriorityQueue a -> PriorityQueue a -> PriorityQueue a
makeQueue k v a b
| queueRank a >= queueRank b = n `seq` Queue n k v (queueRank b + 1) a b
| otherwise = n `seq` Queue n k v (queueRank a + 1) b a
where n = queueCount a + queueCount b + 1
mergeQueues :: PriorityQueue a -> PriorityQueue a -> PriorityQueue a
mergeQueues h EmptyQueue = h
mergeQueues EmptyQueue h = h
mergeQueues h1@(Queue _ k1 v1 _ a1 b1) h2@(Queue _ k2 v2 _ a2 b2)
| k1 <= k2 = makeQueue k1 v1 a1 (mergeQueues b1 h2)
| otherwise = makeQueue k2 v2 a2 (mergeQueues h1 b2)