module Data.Queue.QueueHelpers (MonoidQ (..), HeapQ, endoMaybe, order, fusing, fuseMerge) where
import Data.Monoid
import Data.Maybe
data MonoidQ m = HQ {elts :: !Int, heap :: m}
type HeapQ m = MonoidQ (Maybe m)
instance Monoid m => Monoid (MonoidQ m) where
mempty = HQ 0 mempty
HQ n1 h1 `mappend` HQ n2 h2 = HQ (n1 + n2) (h1 `mappend` h2)
mconcat = fuseMerge
endoMaybe :: (a -> a -> a) -> Maybe a -> Maybe a -> Maybe a
endoMaybe f (Just a) (Just b) = Just (f a b)
endoMaybe _ ma Nothing = ma
endoMaybe _ _ mb = mb
fusing :: Monoid m => [m] -> Maybe m
fusing = let meld = mappend
fuser [] = Nothing
fuser (t:ts) = Just (t `fuse1` ts)
t `fuse1` [] = t
t1 `fuse1` (t2:ts) = (t1 `meld` t2) `fuse1` fuse ts
fuse (t1:t2:ts) = t1 `meld` t2 : fuse ts
fuse ts = ts
in meld `seq` fuser
order :: (e -> e -> Ordering) -> e -> e -> (e, e)
order cmp x y | cmp x y == GT = (y, x)
| otherwise = (x, y)
data IntAcc e = IA !Int e
fuseMerge :: Monoid m => [MonoidQ m] -> MonoidQ m
fuseMerge qs = let merger (HQ size t) (IA n ts) = IA (n + size) (t:ts)
in case foldr merger (IA 0 []) qs of
IA n ts -> HQ n (fromMaybe mempty (fusing ts))
fuseMergeM :: Monoid m => [HeapQ m] -> HeapQ m
fuseMergeM qs = let merger (HQ size (Just t)) (IA n ts) = IA (n + size) (t:ts)
merger _ (IA n ts) = IA n ts
in case foldr merger (IA 0 []) qs of
IA n ts -> HQ n (fusing ts)