module Data.TrieMap.RadixTrie.Edge ( searchEdgeC,
afterEdge,
assignEdge,
beforeEdge,
clearEdge,
diffEdge,
extractEdgeLoc,
indexEdge,
insertEdge,
isectEdge,
lookupEdge,
mapEitherEdge,
mapMaybeEdge,
unionEdge,
fromAscListEdge) where
import Control.Monad.Lookup
import Control.Monad.Ends
import Control.Monad.Unpack
import Data.TrieMap.TrieKey
import Data.TrieMap.WordMap ()
import Data.TrieMap.RadixTrie.Label
import Data.TrieMap.RadixTrie.Slice
import Data.Word
import Data.Vector.Generic (length)
import qualified Data.Vector (Vector)
import qualified Data.Vector.Primitive (Vector)
import Prelude hiding (length, foldr, foldl, zip, take, map)
import GHC.Exts
#define V(f) f (Data.Vector.Vector) (k)
#define U(f) f (Data.Vector.Primitive.Vector) (Word)
#define EDGE(args) (!(eView -> Edge args))
#define LOC(args) !(locView -> Loc args)
#define DEEP(args) !(pView -> Deep args)
instance Label v k => Functor (Edge v k) where
fmap f = map where
map EDGE(sz ks v ts) = edge' sz ks (f <$> v) (map <$> ts)
instance Label v k => Foldable (Edge v k) where
foldMap f = fold where
foldBranch = foldMap fold
fold e = case eView e of
Edge _ _ Nothing ts -> foldBranch ts
Edge _ _ (Just a) ts -> f a `mappend` foldBranch ts
foldr f = flip fold where
foldBranch = foldr fold
fold e z = case eView e of
Edge _ _ Nothing ts -> foldBranch z ts
Edge _ _ (Just a) ts -> a `f` foldBranch z ts
foldl f = fold where
foldBranch = foldl fold
fold z e = case eView e of
Edge _ _ Nothing ts -> foldBranch z ts
Edge _ _ (Just a) ts -> foldBranch (z `f` a) ts
instance Label v k => Traversable (Edge v k) where
traverse f = trav where
travBranch = traverse trav
trav e = case eView e of
Edge sz ks Nothing ts -> edge' sz ks Nothing <$> travBranch ts
Edge sz ks (Just a) ts -> edge' sz ks . Just <$> f a <*> travBranch ts
lookupEdge :: (Eq k, Label v k) => v k -> Edge v k a -> Lookup r a
lookupEdge ks e = Lookup $ \ no yes -> let
lookupE !ks !EDGE(_ ls !v ts) = if kLen < lLen then no else matchSlice matcher matches ks ls where
!kLen = length ks
!lLen = length ls
matcher k l z
| k == l = z
| otherwise = no
matches _ _
| kLen == lLen = maybe no yes v
| (_, k, ks') <- splitSlice lLen ks
= runLookup (lookupMC k ts) no (lookupE ks')
in lookupE ks e
searchEdgeC :: (Eq k, Label v k, Unpackable (EdgeLoc v k a)) =>
v k -> Edge v k a -> (EdgeLoc v k a :~> r) -> (a -> EdgeLoc v k a :~> r) -> r
searchEdgeC ks0 e nomatch match = searchE ks0 e root where
searchE !ks e@EDGE(_ !ls !v ts) path = iMatchSlice matcher matches ks ls where
matcher i k l z =
runLookup (unifierM k l (dropEdge (i+1) e)) z
(\ tHole -> nomatch $~ loc (dropSlice (i+1) ks) emptyM (deep path (takeSlice i ls) Nothing tHole))
matches kLen lLen = case compare kLen lLen of
LT -> let lPre = takeSlice kLen ls; l = ls !$ kLen; e' = dropEdge (kLen + 1) e in
nomatch $~ loc lPre (singletonM l e') path
EQ -> maybe nomatch match v $~ loc ls ts path
GT -> let
kk = ks !$ lLen
ks' = dropSlice (lLen + 1) ks
nomatch' tHole = nomatch $~ loc ks' emptyM (deep path ls v tHole)
match' e' tHole = searchE ks' e' (deep path ls v tHole)
in searchMC kk ts nomatch' match'
mapMaybeEdge :: (Label v k, Sized b) => (a -> Maybe b) -> Edge v k a -> MEdge v k b
mapMaybeEdge f = mapMaybeE where
mapMaybeE !EDGE(_ ks !v ts) = let !v' = v >>= f in cEdge ks v' (mapMaybe mapMaybeE ts)
mapEitherEdge :: (Label v k, Sized b, Sized c) =>
(a -> (# Maybe b, Maybe c #)) -> Edge v k a -> (# MEdge v k b, MEdge v k c #)
mapEitherEdge f = mapEitherE where
mapEitherE EDGE(_ ks v ts) = (# cEdge ks vL tsL, cEdge ks vR tsR #)
where !(# vL, vR #) = mapEither f v
!(# tsL, tsR #) = mapEither mapEitherE ts
assignEdge :: (Label v k, Sized a) => a -> EdgeLoc v k a -> Edge v k a
assignEdge v LOC(ks ts path) = assign (edge ks (Just v) ts) path
assign :: (Label v k, Sized a) => Edge v k a -> Path v k a -> Edge v k a
assign e DEEP(path ks v tHole) = assign (edge ks v (assignM e tHole)) path
assign e _ = e
clearEdge :: (Label v k, Sized a) => EdgeLoc v k a -> MEdge v k a
clearEdge LOC(ks ts path) = rebuild (cEdge ks Nothing ts) path where
rebuild Nothing DEEP(path ks v tHole) = rebuild (cEdge ks v (clearM tHole)) path
rebuild Nothing _ = Nothing
rebuild (Just e) path = Just $ assign e path
unionEdge :: (Label v k, Sized a) =>
(a -> a -> Maybe a) -> Edge v k a -> Edge v k a -> MEdge v k a
unionEdge f = unionE where
unionE !eK@EDGE(_ ks0 !vK tsK) !eL@EDGE(_ ls0 !vL tsL) = iMatchSlice matcher matches ks0 ls0 where
matcher !i k l z = runLookup (unifyM k eK' l eL') z $ Just . edge (takeSlice i ks0) Nothing
where eK' = dropEdge (i+1) eK
eL' = dropEdge (i+1) eL
matches kLen lLen = case compare kLen lLen of
EQ -> cEdge ks0 (union f vK vL) $ union unionE tsK tsL
LT -> searchMC l tsK nomatch match where
eL' = dropEdge (kLen + 1) eL; l = ls0 !$ kLen
nomatch holeKT = cEdge ks0 vK $ assignM eL' holeKT
match eK' holeKT = cEdge ks0 vK $ fillHoleM (eK' `unionE` eL') holeKT
GT -> searchMC k tsL nomatch match where
eK' = dropEdge (lLen + 1) eK; k = ks0 !$ lLen
nomatch holeLT = cEdge ls0 vL $ assignM eK' holeLT
match eL' holeLT = cEdge ls0 vL $ fillHoleM (eK' `unionE` eL') holeLT
isectEdge :: (Eq k, Label v k, Sized c) =>
(a -> b -> Maybe c) -> Edge v k a -> Edge v k b -> MEdge v k c
isectEdge f = isectE where
isectE !eK@EDGE(_ ks0 vK tsK) !eL@EDGE(_ ls0 vL tsL) = matchSlice matcher matches ks0 ls0 where
matcher k l z = guard (k == l) >> z
matches kLen lLen = case compare kLen lLen of
EQ -> cEdge ks0 (isect f vK vL) $ isect isectE tsK tsL
LT -> let l = ls0 !$ kLen in runLookup (lookupMC l tsK) Nothing $ \ eK' ->
let eL' = dropEdge (kLen + 1) eL in unDropEdge (kLen + 1) <$> eK' `isectE` eL'
GT -> let k = ks0 !$ lLen in runLookup (lookupMC k tsL) Nothing $ \ eL' ->
let eK' = dropEdge (lLen + 1) eK in unDropEdge (lLen + 1) <$> eK' `isectE` eL'
diffEdge :: (Eq k, Label v k, Sized a) =>
(a -> b -> Maybe a) -> Edge v k a -> Edge v k b -> MEdge v k a
diffEdge f = diffE where
diffE !eK@EDGE(_ ks0 !vK tsK) !eL@EDGE(_ ls0 !vL tsL) = matchSlice matcher matches ks0 ls0 where
matcher k l z
| k == l = z
| otherwise = Just eK
matches kLen lLen = case compare kLen lLen of
EQ -> cEdge ks0 (diff f vK vL) $ diff diffE tsK tsL
LT -> searchMC l tsK nomatch match where
l = ls0 !$ kLen; eL' = dropEdge (kLen + 1) eL
nomatch _ = Just eK
match eK' holeKT = cEdge ks0 vK $ fillHoleM (eK' `diffE` eL') holeKT
GT -> let k = ks0 !$ lLen; eK' = dropEdge (lLen + 1) eK in
runLookup (lookupMC k tsL) (Just eK) (\ eL' -> fmap (unDropEdge (lLen + 1)) (eK' `diffE` eL'))
instance (Eq k, Label v k) => Subset (Edge v k) where
eK@EDGE(_ ks0 vK tsK) <=? EDGE(_ ls0 vL tsL) = matchSlice matcher matches ks0 ls0 where
matcher k l z = k == l && z
matches kLen lLen = case compare kLen lLen of
LT -> False
EQ -> vK <=? vL && tsK <<=? tsL
GT -> let k = ks0 !$ lLen in runLookup (lookupMC k tsL) False (dropEdge (lLen + 1) eK <=?)
beforeEdge, afterEdge :: (Label v k, Sized a) => Maybe a -> EdgeLoc v k a -> MEdge v k a
beforeEdge v LOC(ks ts path) = case cEdge ks v ts of
Nothing -> before path
Just e -> Just $ beforeWith e path
where before DEEP(path ks v tHole) = case cEdge ks v (beforeM tHole) of
Nothing -> before path
Just e -> Just $ beforeWith e path
before _ = Nothing
beforeWith e DEEP(path ks v tHole)
= beforeWith (edge ks v (beforeWithM e tHole)) path
beforeWith e _ = e
afterEdge v LOC(ks ts path) = case cEdge ks v ts of
Nothing -> after path
Just e -> Just $ afterWith e path
where after DEEP(path ks _ tHole) = case cEdge ks Nothing (afterM tHole) of
Nothing -> after path
Just e -> Just $ afterWith e path
after _ = Nothing
afterWith e DEEP(path ks _ tHole)
= afterWith (edge ks Nothing (afterWithM e tHole)) path
afterWith e _ = e
extractEdgeLoc :: (Label v k, Functor m, MonadPlus m) => Edge v k a -> Path v k a -> m (a, EdgeLoc v k a)
extractEdgeLoc EDGE(_ ks v ts) path = case v of
Nothing -> extractTS
Just a -> return (a, loc ks ts path) `mplus` extractTS
where extractTS = do (e', tHole) <- extractHoleM ts
extractEdgeLoc e' (deep path ks v tHole)
indexEdge :: (Label v k, Sized a) => Edge v k a -> Int# -> (# Int#, a, EdgeLoc v k a #)
indexEdge e i = let
indexE i !e path = case eView e of
Edge sE ks v@(Just a) ts
| i <# sv -> (# i, a, loc ks ts path #)
| otherwise -> case indexM ts (i -# sv) of
(# i', e', tHole #) -> indexE i' e' (deep path ks v tHole)
where !sv = unbox $ sE sizeM ts
Edge _ ks Nothing ts -> case indexM ts i of
(# i', e', tHole #) -> indexE i' e' (deep path ks Nothing tHole)
in indexE i e root
insertEdge :: (Label v k, Sized a) => (a -> a) -> v k -> a -> Edge v k a -> Edge v k a
insertEdge f ks0 a e = insertE ks0 e where
!sza = getSize a
insertE !ks eL@EDGE(szL ls !v ts) = iMatchSlice matcher matches ks ls where
!szV = szL sizeM ts
matcher !i k l z = runLookup (unifyM k eK' l eL') z (edge (takeSlice i ls) Nothing)
where eK' = edge' sza (dropSlice (i+1) ks) (Just a) emptyM
eL' = dropEdge (i+1) eL
matches kLen lLen = case compare kLen lLen of
LT -> (edge' (sza + szL) ks (Just a) (singletonM l eL'))
where l = ls !$ kLen; eL' = dropEdge (kLen+1) eL
EQ -> (edge ls (Just (maybe a f v)) ts)
GT -> edge' sz' ls v ts' where
ks' = dropSlice (lLen + 1) ks
k = ks !$ lLen
ts' = insertWithM (insertE ks') k (edge' sza ks' (Just a) emptyM) ts
sz' = sizeM ts' + szV
fromAscListEdge :: forall v k a .(Label v k, Sized a) => (a -> a -> a) ->
Foldl (Stack v k) (v k) a (MEdge v k a)
fromAscListEdge f = case inline daFold of
Foldl{snoc = snocB, begin = beginB, done = doneB}
-> Foldl{..} where
begin ks a = stack ks (Just a) Nothing Nothing
zero = Nothing
snoc stk ks vK = snoc' ks stk where
snoc' !ks !stk = case sView stk of
Stack ls !vL !brL !lStack -> iMatchSlice matcher matches ks ls where
matcher i k l z
| k == l = z
| otherwise = let
ksPre = takeSlice i ks
ksSuf = dropSlice (i+1) ks
ls' = dropSlice (i+1) ls
eL = roll (stack ls' vL brL lStack)
in stack ksPre Nothing (Just (beginB l eL)) (Just (k, begin ksSuf vK))
matches kLen lLen
| kLen > lLen = let
ksPre = takeSlice lLen ks
k = ks !$ lLen
ksSuf = dropSlice (lLen + 1) ks
in case lStack of
Just (lChar, lStack)
| k == lChar -> stack ksPre vL brL (Just (lChar, snoc' ksSuf lStack))
| otherwise -> stack ksPre vL (Just $ snocBranch brL lChar lStack)
(Just (k, begin ksSuf vK))
Nothing -> stack ksPre vL brL (Just (k, begin ksSuf vK))
| otherwise = stack ks (Just (maybe vK (f vK) vL)) brL lStack
snocBranch Nothing k stack = beginB k (roll stack)
snocBranch (Just s) k stack = snocB s k (roll stack)
roll stack = case sView stack of
Stack ks (Just vK) _ Nothing -> singletonEdge ks vK
Stack ks vK brK (Just (kChar, stack')) ->
edge ks vK $ inline doneB $ snocBranch brK kChar stack'
_ -> error "Error: bad stack"
done = Just . roll