{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-} {-# OPTIONS -fno-warn-missing-methods #-} {- | An efficient implementation of a priority queue. The implementation of 'PQueue' is based on a /pairing heap/, a simple and efficient implementation of a general-purpose priority queue. 'PQueue' supports 'insert', 'merge', and 'peek' in constant time, and 'extract' and 'delete' in logarithmic time. -} module Data.Queue.PQueue (PQueue) where import Data.Monoid import Data.Maybe import Control.Monad import Data.Tree import Data.Queue.Class import GHC.Exts data PHeap e = PH {elts :: {-# UNPACK #-} !Int, heap :: {-# UNPACK #-} !(Tree e)} deriving (Read, Show) newtype PQueue e = PQ {getQ :: Maybe (PHeap e)} deriving (Monoid, Read, Show) instance Ord e => Monoid (PHeap e) where -- elegant hack to automatically derive the Monoid instance for PQueue (via Maybe) PH n1 h1 `mappend` PH n2 h2 = PH (n1 + n2) (h1 `meld` h2) instance Ord e => Queuelike (PQueue e) e where singleton x = mkQ 1 (single x) peek (PQ h) = fmap (rootLabel . heap) h delete (PQ h) = fmap (\ (PH (n+1) (Node _ ts)) -> mkQ n (fuser ts)) h isEmpty = isNothing . getQ size = maybe 0 elts . getQ fromList xs = case foldr (\ x (n, ys) -> (n+1, single x : ys)) (0, []) xs of (0, _) -> PQ Nothing (n, ys) -> mkQ n (fuser ys) {-# INLINE toList_ #-} toList_ (PQ h) = maybe [] (flatten . heap) h merge = mappend empty = PQ Nothing xs `insertAll` q = q `merge` fromList xs {-# INLINE mkQ #-} mkQ :: Int -> Tree e -> PQueue e mkQ n t = PQ (Just (PH n t)) meld :: Ord e => Tree e -> Tree e -> Tree e t1@(Node x1 ts1) `meld` t2@(Node x2 ts2) = if x1 > x2 then Node x2 (t1:ts2) else Node x1 (t2:ts1) fuser :: Ord e => Forest e -> Tree e fuser [t] = t fuser l = fuser (fuser' l) where fuser' (t1:t2:ts) = t1 `meld` t2 : fuser' ts fuser' [t1] = [t1] fuser' [] = [] {-# INLINE single #-} single :: e -> Tree e single x = Node x [] mergeAllPH :: Ord e => [PQueue e] -> PQueue e mergeAllPH qs = let (n, ts) = foldr (\ (PH n t) (m, ts) -> (n+m, t:ts)) (0, []) [ph | PQ (Just ph) <- qs] in if n == 0 then PQ Nothing else mkQ n (fuser ts) {-# NOINLINE [0] flattenFB #-} flattenFB :: Tree a -> (a -> b -> b) -> b -> b flattenFB (Node x ts) c n = x `c` foldr (flip flattenFB c) n ts {-# RULES "flatten" [~1] forall t . flatten t = build (flattenFB t); "flattenList" [1] forall t . build (flattenFB t) = flatten t; #-}