TernaryTrees-0.1.2.0: Data/Map/TernaryMap.hs
module Data.Map.TernaryMap (
TernaryMap,
insert,
singleton,
member,
size,
) where
import Data.Bits
import Data.Binary
import Control.Monad
import Prelude hiding (lookup)
-- | TernaryMap a b is ternary tree. It is commonly used for storing word lists
-- like dictionaries.
data TernaryMap a b = Node !a !(TernaryMap a b) !(TernaryMap a b) !(TernaryMap a b)
| Null b !(TernaryMap a b)
| End
deriving (Show, Eq)
-- | Quickly build a tree without an initial tree. This should be used
-- to create an initial tree, using insert there after.
singleton :: Ord a => [a] -> b -> TernaryMap a b
singleton (x:xs) b = Node x End (singleton xs b) End
singleton [] b = Null b End
-- | Inserts an entrie into a tree. Values with the same key will be replaced
-- with the newer value.
insert :: Ord a => [a] -> b -> TernaryMap a b -> TernaryMap a b
insert xss@(_:_) b End = singleton xss b
insert xss@(_:_) b (Null b' rest) = Null b' $ insert xss b rest
insert [] b End = Null b End
insert [] b (Node ele l e h) = Node ele (insert [] b l) e h
insert [] b (Null _ rest) = Null b rest
insert xss@(x:xs) b (Node ele l e h) =
case compare x ele of
LT -> Node ele (insert xss b l) e h
EQ -> Node ele l (insert xs b e) h
GT -> Node ele l e (insert xss b h)
-- | Returns true if the `[a]` is a key in the TernaryMap.
member :: Ord a => [a] -> TernaryMap a b -> Bool
member _ End = False
member [] (Null _ _) = True
member [] (Node _ l _ _) = member [] l
member xss@(_:_) (Null _ rest) = member xss rest
member xss@(x:xs) (Node ele l e h) =
case compare x ele of
LT -> member xss l
EQ -> member xs e
GT -> member xss h
lookup :: Ord a => [a] -> TernaryMap a b -> Maybe b
lookup _ End = Nothing
lookup [] (Null b _) = Just b
lookup [] (Node _ l _ _) = lookup [] l
lookup xs (Null _ rest) = lookup xs rest
lookup xss@(x:xs) (Node ele l e h) =
case compare x ele of
LT -> lookup xss l
EQ -> lookup xs e
GT -> lookup xss h
(!) :: Ord a => TernaryMap a b -> [a] -> Maybe b
(!) = flip lookup
-- | Returns the number of non-Val Elems. not exported
treeSize :: TernaryMap a b -> Int
treeSize End = 0
treeSize (Node _ l e h) = 1 + treeSize l + treeSize e + treeSize h
treeSize (Null _ rest) = treeSize rest
-- | Counts how many entries there are in the tree.
size :: TernaryMap a b -> Int
size End = 0
size (Node _ l e h) = size l + size e + size h
size (Null _ rest) = 1 + size rest
-- | Creates a new tree from a list of 'strings'
fromList :: Ord a => [([a],b)] -> TernaryMap a b
fromList = foldl (\tree (as,b) -> insert as b tree) empty
-- | An empty map.
empty :: TernaryMap a b
empty = End
-- | Makes a list of all the values in the map.
elems :: TernaryMap a b -> [b]
elems End = []
elems (Node _ l e h) = elems l ++ (elems e ++ elems h)
elems (Null b rest) = b : elems rest
-- | Returns true if the map is empty.
null :: TernaryMap a b -> Bool
null End = True
null _ = False
-- keySet :: TernaryMap a b -> S.TernarySet a
-- keySet End = S.End
-- keySet (Node (C x) l e h) = S.Node (S.C x) (keySet l) (keySet e) (keySet h)
-- keySet (Node (Val _) l e h) = S.Node (S.Null) (keySet l) (keySet e) (keySet h)
instance Functor (TernaryMap a) where
fmap _ End = End
fmap f (Null b rest) = Null (f b) (fmap f rest)
fmap f (Node ele l e h) = Node ele (fmap f l) (fmap f e) (fmap f h)
-- | A rather long Binary instance, that uses binary numbers to indicate
-- where Ends are efficiently.
instance (Binary a, Binary b) => Binary (TernaryMap a b) where
put (Node ch End End End) = do
putWord8 0
put ch
put (Node ch End End h) = do
putWord8 1
put ch
put h
put (Node ch End e End) = do
putWord8 2
put ch
put e
put (Node ch End e h) = do
putWord8 3
put ch
put e
put h
put (Node ch l End End) = do
putWord8 4
put ch
put l
put (Node ch l End h) = do
putWord8 5
put ch
put l
put h
put (Node ch l e End) = do
putWord8 6
put ch
put l
put e
-- General case
put (Node ch l e h) = do
putWord8 7
put ch
put l
put e
put h
put (Null b End) = putWord8 8 >> put b
put (Null b rest) = do
putWord8 9
put b
put rest
put End = putWord8 10
get = do
tag <- getWord8
case tag of
_ | tag < 8 ->
do
ch <- get
l <- if (tag `testBit` 2) then get else return End
e <- if (tag `testBit` 1) then get else return End
h <- if (tag `testBit` 0) then get else return End
return (Node ch l e h)
8 -> liftM (flip Null End) get
9 -> liftM2 Null get get
_ -> return End