packages feed

queuelike-1.0.7: Data/Queue/Fuse/PHeap2.hs

{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}

module Data.Queue.Fuse.PHeap2 (FusePHeap, extractSingle, replace) where

import Data.Queue.Class
import Data.Semigroup
import Data.Maybe

data PHeap k v = PH k v [PHeap k v] deriving (Show)
newtype FusePHeap k v = FPH (Point (PHeap k v)) deriving (Show, Monoid)

data Merge k v = Mrg v [v] [PHeap k v]

extractSingle :: FusePHeap k v -> Maybe (k, v)
extractSingle (FPH (Pt (Just (PH k v [])))) = Just (k,v)
extractSingle _ = Nothing

replace :: v -> FusePHeap k v -> FusePHeap k v
replace v (FPH (Pt (Just (PH k _ ts)))) = fph (Just (PH k v ts))
replace _ h = h

instance Functor (PHeap k) where
	fmap f (PH k v hs) = PH k (f v) (map (fmap f) hs)

instance Semigroup (Merge k v) where
	Mrg v1 vs1 qs1 `sappend` Mrg v2 vs2 qs2 = Mrg v1 (v2:vs1 ++ vs2) (qs1 ++ qs2)

merger :: (v -> v -> v) -> v -> [v] -> v
merger (><) h hs = case merger' h hs of (h', hs') -> foldl (><) h' hs ; where
	merger' h [] = (h, [])
	merger' h1 (h2:hs) = (h1 >< h2, case hs of
		[]	-> []
		(h3:hs)	-> case merger' h3 hs of (h, hs) -> h:hs)

instance (Ord k, Semigroup v) => Semigroup (PHeap k v) where
	sappend = mergePH
	sconcat_ = merger mergePH
	sconcat [] = Nothing
	sconcat (h:hs) = Just (merger mergePH h hs)

mergePH :: (Ord k, Semigroup v) => Endo (PHeap k v)
h1@(PH k1 v1 hs1) `mergePH` h2@(PH k2 v2 hs2) = case compare k1 k2 of
	LT	-> PH k1 v1 (h2:hs1)
	EQ	-> PH k1 (v1 `sappend` v2) (hs1 ++ hs2)
	GT	-> PH k2 v2 (h1:hs2)
	--sconcat = fusePHs sconcat_

{-# NOINLINE fusePHs #-}
fusePHs :: (Ord k) => (v -> [v] -> v) -> Fusion (PHeap k v)
fusePHs scat hs = {-cmp hs `seq`-} fmap fromMrg (fusing [single (k, Mrg v [] qs) | PH k v qs <- hs]) where
	fromMrg (PH k (Mrg v vs qs) qs0) = PH k (scat v vs) (map fromMrg qs0 ++ qs)
	cmp :: Ord k => [PHeap k v] -> k -> k -> Ordering
	cmp _ = compare

instance (Ord k, Semigroup v) => IQueue (FusePHeap k v) where
	type QueueKey (FusePHeap k v) = (k, v)
	empty = FPH pNothing --mempty
	merge = mappend
	mergeAll = mconcat

	insertAll = merge . fph . fusing . map single
	singleton = fph . Just . single
	fromList = fph . fusing . map single
	
	{-# INLINE extract #-}
	extract (FPH (Pt h)) = fmap extract' h where extract' (PH k v hs) = ((k, v), fph $ fusing hs)
--	top (FPH (Pt h)) = fmap top' h where top' (PH k v _) = (k, v)
--	delete (FPH (Pt h)) = fmap delete' h where delete' (PH _ _ hs) = fph $ fusing hs

	null (FPH (Pt Nothing)) = True
	null _ = False

single :: (k, v) -> PHeap k v
single (k, v) = PH k v []

fph = FPH . Pt