queuelike-1.0.7: Data/Queue/Fuse/Vanilla.hs
{-# LANGUAGE TypeFamilies, GeneralizedNewtypeDeriving #-}
module Data.Queue.Fuse.Vanilla (FuseVHeap, extractSingle, replace) where
import Data.Queue.Class
import Data.Queue.PQueue
import Data.Semigroup
import Prelude hiding (null)
data Assoc k v = A k v deriving (Show)
data VHeap k v = VH k v {-# UNPACK #-} !(PQueue (Assoc k v)) deriving (Show)
newtype FuseVHeap k v = FVH (Point (VHeap k v)) deriving (Monoid, Show)
instance Eq k => Eq (Assoc k v) where
A x _ == A y _ = x == y
instance Ord k => Ord (Assoc k v) where
A x _ `compare` A y _ = x `compare` y
A x _ <= A y _ = x <= y
instance (Ord k, Semigroup v) => Semigroup (VHeap k v) where
sappend = mergeVH
sconcat [] = Nothing
sconcat (q:qs) = Just (mergeVHs q qs)
sconcat_ = mergeVHs
mergeVH :: (Ord k, Semigroup v) => Endo (VHeap k v)
VH k1 v1 q1 `mergeVH` VH k2 v2 q2 = case compare k1 k2 of
LT -> VH k1 v1 (A k2 v2 `insert` q)
EQ -> VH k1 (v1 `sappend` v2) q
GT -> VH k2 v2 (A k1 v1 `insert` q)
where q = q1 `merge` q2
data Acc k v = Ac k v [v] [Assoc k v] [PQueue (Assoc k v)]
mergeVHs :: (Ord k, Semigroup v) => VHeap k v -> [VHeap k v] -> VHeap k v
mergeVHs (VH k0 v0 q0) hs = case foldl merger (Ac k0 v0 [] [] []) hs of
Ac k v vs as qs -> VH k (v <<| vs) (as `insertAll` mergeAll qs)
where Ac k v vs as qs `merger` VH k' v' q' = let qs' = q':qs in case compare k' k of
LT -> Ac k' v' [] (A k (v <<| vs):as) qs'
EQ -> Ac k v (v':vs) as qs'
GT -> Ac k v vs (A k' v':as) qs'
{-# NOINLINE (<<|) #-}
(<<|) = sconcat_
toVH :: (Ord k, Semigroup v) => PQueue (Assoc k v) -> Maybe (VHeap k v)
toVH = fmap toVH1 . extract where
toVH1 (A k v, q) = let toVH' vs q = case extract q of Just (A k' v', q') | k == k'
-> toVH' (v':vs) q'
_ -> VH k (sconcat_ v vs) q
in toVH' [] q
instance (Ord k, Semigroup v) => IQueue (FuseVHeap k v) where
type QueueKey (FuseVHeap k v) = (k, v)
empty = fvh Nothing
merge = mappend
mergeAll = mconcat
singleton = fvh . Just . single
fromList = fvh . fusing . map single
null (FVH (Pt Nothing)) = True
null _ = False
extract (FVH (Pt h)) = fmap extract' h where
extract' (VH k v q) = ((k, v), fvh $ toVH q)
single :: (Ord k, Semigroup v) => (k, v) -> VHeap k v
single (k, v) = VH k v empty
fvh :: (Ord k, Semigroup v) => Maybe (VHeap k v) -> FuseVHeap k v
fvh = FVH . Pt
extractSingle :: Ord k => FuseVHeap k v -> Maybe (k, v)
extractSingle (FVH (Pt (Just (VH k v q))))
| null q = Just (k, v)
extractSingle _ = Nothing
replace :: (Ord k, Semigroup v) => v -> FuseVHeap k v -> FuseVHeap k v
replace v (FVH (Pt (Just (VH k _ q)))) = fvh (Just (VH k v q))
replace _ q = q