module UHC.Light.Compiler.Base.TreeTrie
( TreeTrie1Key (..), TreeTrieMp1Key (..), TreeTrieMpKey, TreeTrieKey
, ppTreeTrieKey
, ttkSingleton, ttkAdd', ttkAdd, ttkChildren, ttkFixate
, ttkParentChildren
, TreeTrieKeyable (..)
, TreeTrieLookup (..)
, TreeTrie, emptyTreeTrie, empty
, toListByKey, toList
, fromListByKeyWith, fromList
, lookupPartialByKey, lookupPartialByKey', lookupByKey, lookup
, lookupResultToList
, isEmpty, null
, elems
, singleton, singletonKeyable
, unionWith, union, unionsWith, unions
, insertByKeyWith, insertByKey
, deleteByKey, delete
, deleteListByKey )
where
import qualified Data.Set as Set
import qualified Data.Map as Map
import Data.Maybe
import Prelude hiding (lookup,null)
import qualified UHC.Util.FastSeq as Seq
import qualified Data.List as List
import UHC.Util.Utils
import UHC.Util.Pretty hiding (empty)
import qualified UHC.Util.Pretty as PP
import UHC.Light.Compiler.Base.Debug
import Data.Typeable
import Data.Generics (Data)
import Control.Monad
import UHC.Util.Serialize
data TreeTrie1Key k
= TT1K_One !k
| TT1K_Any
deriving (Eq, Ord)
data TreeTrieMp1Key k
= TTM1K [TreeTrie1Key k]
| TTM1K_Any
deriving (Eq, Ord)
type TreeTrieMpKey k
= [TreeTrieMp1Key k]
type TreeTrieKey k
= [TreeTrieMpKey k]
#if __GLASGOW_HASKELL__ >= 708
deriving instance Typeable TreeTrie1Key
deriving instance Typeable TreeTrieMp1Key
#else
deriving instance Typeable1 TreeTrie1Key
deriving instance Typeable1 TreeTrieMp1Key
#endif
deriving instance Data x => Data (TreeTrie1Key x)
deriving instance Data x => Data (TreeTrieMp1Key x)
instance Show k => Show (TreeTrie1Key k) where
show TT1K_Any = "*"
show (TT1K_One k) = "1:" ++ show k
instance Show k => Show (TreeTrieMp1Key k) where
show (TTM1K_Any ) = "**"
show (TTM1K k) = show k
instance PP k => PP (TreeTrie1Key k) where
pp TT1K_Any = pp "*"
pp (TT1K_One k) = "1:" >|< k
instance PP k => PP (TreeTrieMp1Key k) where
pp = ppTreeTrieMp1Key
ppTreeTrieMp1Key :: PP k => TreeTrieMp1Key k -> PP_Doc
ppTreeTrieMp1Key (TTM1K l) = ppBracketsCommas l
ppTreeTrieMp1Key (TTM1K_Any ) = pp "**"
ppTreeTrieMpKey :: PP k => TreeTrieMpKey k -> PP_Doc
ppTreeTrieMpKey = ppListSep "<" ">" "," . map ppTreeTrieMp1Key
ppTreeTrieKey :: PP k => TreeTrieKey k -> PP_Doc
ppTreeTrieKey = ppBracketsCommas . map ppTreeTrieMpKey
ttkSingleton :: TreeTrie1Key k -> TreeTrieKey k
ttkSingleton k = [TTM1K [k]] : ttkEmpty
ttkEmpty :: TreeTrieKey k
ttkEmpty = [[TTM1K []]]
ttkChildren :: [TreeTrieKey k] -> [TreeTrieMpKey k]
ttkChildren ks
= [TTM1K $ concat [k | TTM1K k <- concat hs]]
: merge (split tls)
where (hs,tls) = split ks
split = unzip . map hdAndTl
merge (hs,[]) = [concat hs]
merge (hs,tls) = concat hs : merge (split $ filter (not . List.null) tls)
ttkAdd' :: TreeTrie1Key k -> [TreeTrieMpKey k] -> TreeTrieKey k
ttkAdd' k ks = [TTM1K [k]] : ks
ttkAdd :: TreeTrie1Key k -> [TreeTrieKey k] -> TreeTrieKey k
ttkAdd k ks = ttkAdd' k (ttkChildren ks)
ttkFixate :: TreeTrieKey k -> TreeTrieKey k
ttkFixate (kk:kks) | all (\(TTM1K k) -> List.null k) kk = []
| otherwise = kk : ttkFixate kks
ttkFixate _ = []
ttkParentChildren :: TreeTrieKey k -> ( TreeTrie1Key k, [TreeTrieMpKey k] )
ttkParentChildren k
= case k of
([TTM1K [h]] : t) -> (h,t)
matchTreeTrieMpKeyTo :: Eq k => TreeTrieMpKey k -> TreeTrieMpKey k -> Maybe (TreeTrieMpKey k -> TreeTrieMpKey k)
matchTreeTrieMpKeyTo l r
| all isJust llrr = Just (\k -> concat $ zipWith ($) (concatMap (fromJust) llrr) k)
| otherwise = Nothing
where llrr = zipWith m l r
m (TTM1K l) (TTM1K r) | length l == length r && all isJust lr
= Just (concatMap fromJust lr)
| otherwise = Nothing
where lr = zipWith m1 l r
m (TTM1K_Any ) (TTM1K []) = Just []
m (TTM1K_Any ) (TTM1K r ) = Just [const $ replicate (length r) TTM1K_Any]
m1 TT1K_Any _ = Just [const [TTM1K_Any]]
m1 (TT1K_One l) (TT1K_One r) | l == r = Just [\x -> [x]]
m1 _ _ = Nothing
class TreeTrieKeyable x k where
toTreeTrieKey :: x -> TreeTrieKey k
data TreeTrieLookup
= TTL_Exact
| TTL_WildInTrie
| TTL_WildInKey
deriving (Eq)
type TreeTrieChildren k v
= Map.Map (TreeTrieMpKey k) (TreeTrie k v)
data TreeTrie k v
= TreeTrie
{ ttrieMbVal :: Maybe v
, ttrieSubs :: TreeTrieChildren k v
}
deriving (Typeable, Data)
emptyTreeTrie, empty :: TreeTrie k v
emptyTreeTrie = TreeTrie Nothing Map.empty
empty = emptyTreeTrie
instance (Show k, Show v) => Show (TreeTrie k v) where
showsPrec _ t = showList $ toListByKey t
instance (PP k, PP v) => PP (TreeTrie k v) where
pp t = ppBracketsCommasBlock $ map (\(a,b) -> ppTreeTrieKey a >#< ":" >#< b) $ toListByKey t
toFastSeqSubs :: TreeTrieChildren k v -> Seq.FastSeq (TreeTrieKey k,v)
toFastSeqSubs ttries
= Seq.unions
[ Seq.map (\(ks,v) -> (k:ks,v)) $ toFastSeq True t
| (k,t) <- Map.toList ttries
]
toFastSeq :: Bool -> TreeTrie k v -> Seq.FastSeq (TreeTrieKey k,v)
toFastSeq inclEmpty ttrie
= (case ttrieMbVal ttrie of
Just v | inclEmpty -> Seq.singleton ([],v)
_ -> Seq.empty
)
Seq.:++: toFastSeqSubs (ttrieSubs ttrie)
toListByKey, toList :: TreeTrie k v -> [(TreeTrieKey k,v)]
toListByKey = Seq.toList . toFastSeq True
toList = toListByKey
fromListByKeyWith :: Ord k => (v -> v -> v) -> [(TreeTrieKey k,v)] -> TreeTrie k v
fromListByKeyWith cmb = unionsWith cmb . map (uncurry singleton)
fromListByKey :: Ord k => [(TreeTrieKey k,v)] -> TreeTrie k v
fromListByKey = unions . map (uncurry singleton)
fromListWith :: Ord k => (v -> v -> v) -> [(TreeTrieKey k,v)] -> TreeTrie k v
fromListWith cmb = fromListByKeyWith cmb
fromList :: Ord k => [(TreeTrieKey k,v)] -> TreeTrie k v
fromList = fromListByKey
lookupPartialByKey' :: forall k v v' . (PP k,Ord k) => (TreeTrieKey k -> v -> v') -> TreeTrieLookup -> TreeTrieKey k -> TreeTrie k v -> ([v'],Maybe v')
lookupPartialByKey' mkRes ttrieLookup keys ttrie
= l id mkRes keys ttrie
where l :: (TreeTrieMpKey k -> TreeTrieMpKey k) -> (TreeTrieKey k -> v -> v') -> TreeTrieKey k -> TreeTrie k v -> ([v'],Maybe v')
l = case ttrieLookup of
TTL_Exact -> \updTKey mkRes keys ttrie ->
case keys of
[] -> dflt mkRes ttrie
(k : ks)
-> case Map.lookup k $ ttrieSubs ttrie of
Just ttrie'
-> ([], m)
where (_,m) = l id (res mkRes k) ks ttrie'
_ -> ([], Nothing)
TTL_WildInTrie -> \updTKey mkRes keys ttrie ->
case keys of
[] -> dflt mkRes ttrie
(k : ks)
-> (catMaybes mbs ++ concat subs, Nothing)
where (subs,mbs)
= unzip
[ case ks of
[] -> l id (res mkRes k) [] t
(ksk:ksks) | Map.null (ttrieSubs t) -> match (res mkRes k) (fromJust mbm) ks
| otherwise -> l (fromJust mbm) (res mkRes k) ks t
where match mkRes m (km:kms)
= case matchTreeTrieMpKeyTo kt' km of
Just m -> match (res mkRes k) m kms
_ -> ([], Nothing)
where kt' = m $ repeat (TTM1K [])
match mkRes _ []
= l id (res mkRes k) [] t
| (kt,t) <- Map.toList $ ttrieSubs ttrie
, let kt' = updTKey kt
mbm =
matchTreeTrieMpKeyTo kt' k
, isJust mbm
]
TTL_WildInKey -> \updTKey mkRes keys ttrie ->
case keys of
[] -> dflt mkRes ttrie
(k : ks)
-> (catMaybes mbs ++ concat subs, Nothing)
where (subs,mbs)
= unzip
[ case ks of
(ksk:ksks) -> l id (res mkRes kt) (fromJust m ksk : ksks) t
[] | Map.null (ttrieSubs t) -> l id (res mkRes kt) [] t
| otherwise -> l id (res mkRes kt) [fromJust m $ repeat (TTM1K [])] t
| (kt,t) <- Map.toList $ ttrieSubs ttrie
, let m =
matchTreeTrieMpKeyTo k kt
, isJust m
]
where dflt mkRes ttrie = ([],fmap (mkRes []) $ ttrieMbVal ttrie)
res mkRes k = \ks v -> mkRes (k : ks) v
lookupPartialByKey :: (PP k,Ord k) => TreeTrieLookup -> TreeTrieKey k -> TreeTrie k v -> ([v],Maybe v)
lookupPartialByKey = lookupPartialByKey' (\_ v -> v)
lookupByKey, lookup :: (PP k,Ord k) => TreeTrieKey k -> TreeTrie k v -> Maybe v
lookupByKey keys ttrie = snd $ lookupPartialByKey TTL_WildInTrie keys ttrie
lookup = lookupByKey
lookupResultToList :: ([v],Maybe v) -> [v]
lookupResultToList (vs,mv) = maybeToList mv ++ vs
isEmpty :: TreeTrie k v -> Bool
isEmpty ttrie
= isNothing (ttrieMbVal ttrie)
&& Map.null (ttrieSubs ttrie)
null :: TreeTrie k v -> Bool
null = isEmpty
elems :: TreeTrie k v -> [v]
elems = map snd . toListByKey
singleton :: Ord k => TreeTrieKey k -> v -> TreeTrie k v
singleton keys val
= s keys
where s [] = TreeTrie (Just val) Map.empty
s (k : ks) = TreeTrie Nothing (Map.singleton k $ singleton ks val)
singletonKeyable :: (Ord k,TreeTrieKeyable v k) => v -> TreeTrie k v
singletonKeyable val = singleton (toTreeTrieKey val) val
unionWith :: Ord k => (v -> v -> v) -> TreeTrie k v -> TreeTrie k v -> TreeTrie k v
unionWith cmb t1 t2
= TreeTrie
{ ttrieMbVal = mkMb cmb (ttrieMbVal t1) (ttrieMbVal t2)
, ttrieSubs = Map.unionWith (unionWith cmb) (ttrieSubs t1) (ttrieSubs t2)
}
where mkMb _ j Nothing = j
mkMb _ Nothing j = j
mkMb cmb (Just x1) (Just x2) = Just $ cmb x1 x2
union :: Ord k => TreeTrie k v -> TreeTrie k v -> TreeTrie k v
union = unionWith const
unionsWith :: Ord k => (v -> v -> v) -> [TreeTrie k v] -> TreeTrie k v
unionsWith cmb [] = emptyTreeTrie
unionsWith cmb ts = foldr1 (unionWith cmb) ts
unions :: Ord k => [TreeTrie k v] -> TreeTrie k v
unions = unionsWith const
insertByKeyWith :: Ord k => (v -> v -> v) -> TreeTrieKey k -> v -> TreeTrie k v -> TreeTrie k v
insertByKeyWith cmb keys val ttrie = unionsWith cmb [singleton keys val,ttrie]
insertByKey :: Ord k => TreeTrieKey k -> v -> TreeTrie k v -> TreeTrie k v
insertByKey = insertByKeyWith const
insert :: Ord k => TreeTrieKey k -> v -> TreeTrie k v -> TreeTrie k v
insert = insertByKey
insertKeyable :: (Ord k,TreeTrieKeyable v k) => v -> TreeTrie k v -> TreeTrie k v
insertKeyable val = insertByKey (toTreeTrieKey val) val
deleteByKey, delete :: Ord k => TreeTrieKey k -> TreeTrie k v -> TreeTrie k v
deleteByKey keys ttrie
= d keys ttrie
where d [] t
= t {ttrieMbVal = Nothing}
d (k : ks) t
= case fmap (d ks) $ Map.lookup k $ ttrieSubs t of
Just c | isEmpty c -> t { ttrieSubs = k `Map.delete` ttrieSubs t }
| otherwise -> t { ttrieSubs = Map.insert k c $ ttrieSubs t }
_ -> t
delete = deleteByKey
deleteListByKey :: Ord k => [TreeTrieKey k] -> TreeTrie k v -> TreeTrie k v
deleteListByKey keys ttrie = foldl (\t k -> deleteByKey k t) ttrie keys
instance Serialize k => Serialize (TreeTrie1Key k) where
sput (TT1K_Any ) = sputWord8 0
sput (TT1K_One a ) = sputWord8 1 >> sput a
sget
= do t <- sgetWord8
case t of
0 -> return TT1K_Any
1 -> liftM TT1K_One sget
instance Serialize k => Serialize (TreeTrieMp1Key k) where
sput (TTM1K_Any ) = sputWord8 0
sput (TTM1K a ) = sputWord8 1 >> sput a
sget
= do t <- sgetWord8
case t of
0 -> return TTM1K_Any
1 -> liftM TTM1K sget
instance (Ord k, Serialize k, Serialize v) => Serialize (TreeTrie k v) where
sput (TreeTrie a b) = sput a >> sput b
sget = liftM2 TreeTrie sget sget