{-# LANGUAGE RecordWildCards #-} -- | Internal representation of dynamic automata nodes. module Data.DAWG.Dynamic.Node ( Node(..) , onSym , edges , children , insert ) where import Control.Applicative ((<$>), (<*>)) import Data.Binary (Binary, Get, put, get) import Data.DAWG.Types import Data.DAWG.Util (combine) import Data.DAWG.HashMap (Hash, hash) import Data.DAWG.Trans.Map (Trans) import qualified Data.DAWG.Trans as T import qualified Data.DAWG.Trans.Hashed as H -- | Two nodes (states) belong to the same equivalence class (and, -- consequently, they must be represented as one node in the graph) -- iff they are equal with respect to their values and outgoing -- edges. -- -- Since 'Leaf' nodes are distinguished from 'Branch' nodes, two values -- equal with respect to '==' function are always kept in one 'Leaf' -- node in the graph. It doesn't change the fact that to all 'Branch' -- nodes one value is assigned through the epsilon transition. -- -- Invariant: the 'eps' identifier always points to the 'Leaf' node. -- Edges in the 'edgeMap', on the other hand, point to 'Branch' nodes. data Node a = Branch { -- | Epsilon transition. eps :: {-# UNPACK #-} !ID -- | Transition map (outgoing edges). , transMap :: !(H.Hashed Trans) } | Leaf { value :: !(Maybe a) } deriving (Show, Eq, Ord) instance Ord a => Hash (Node a) where hash Branch{..} = combine eps (H.hash transMap) hash Leaf{..} = case value of Just _ -> (-1) Nothing -> (-2) instance Binary a => Binary (Node a) where put Branch{..} = put (1 :: Int) >> put eps >> put transMap put Leaf{..} = put (2 :: Int) >> put value get = do x <- get :: Get Int case x of 1 -> Branch <$> get <*> get _ -> Leaf <$> get -- | Transition function. onSym :: Sym -> Node a -> Maybe ID onSym x (Branch _ t) = T.lookup x t onSym _ (Leaf _) = Nothing {-# INLINE onSym #-} -- | List of symbol/edge pairs outgoing from the node. edges :: Node a -> [(Sym, ID)] edges (Branch _ t) = T.toList t edges (Leaf _) = [] {-# INLINE edges #-} -- | List of children identifiers. children :: Node a -> [ID] children = map snd . edges {-# INLINE children #-} -- | Substitue edge determined by a given symbol. insert :: Sym -> ID -> Node a -> Node a insert x i (Branch w t) = Branch w (T.insert x i t) insert _ _ l = l {-# INLINE insert #-}