{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NoBangPatterns #-}
module Graphics.PDF.Data.PDFTree(
PDFTree
, Key
, empty
, lookup
, insert
, fromList
, fold2
, isLeaf
, size
, keyOf
) where
import Prelude hiding (lookup,map,filter,foldr,foldl,null)
import Data.Bits
#if __GLASGOW_HASKELL__ >= 503
import GHC.Exts ( Word(..), Int(..), shiftRL# )
#elif __GLASGOW_HASKELL__
import Word
import GlaExts ( Word(..), Int(..), shiftRL# )
#else
import Data.Word
#endif
import Graphics.PDF.LowLevel.Types
type Nat = Word
natFromInt :: Key a -> Nat
natFromInt (PDFReference i) = fromIntegral i
intFromNat :: Nat -> Key a
intFromNat w = PDFReference (fromIntegral w)
type Prefix a = PDFReference a
type Mask a = PDFReference a
type Key a = PDFReference a
data PDFTree a = Nil
| Tip {-# UNPACK #-} !(Key a) a
| Bin {-# UNPACK #-} !(Prefix a) {-# UNPACK #-} !(Mask a) !(PDFTree a) !(PDFTree a)
deriving(Eq,Show)
fold2 :: Monad m => Maybe b
-> (Maybe b -> PDFTree a -> PDFTree a -> m (Int,b))
-> (Maybe b -> Key a -> a -> m (Int,b))
-> PDFTree a
-> m (Int,b)
fold2 _ _ _ Nil = error "Page tree is empty"
fold2 p _ leaf (Tip k a) = leaf p k a
fold2 p node _ (Bin _ _ l r) = node p l r
isLeaf :: PDFTree a -> Bool
isLeaf (Tip _ _) = True
isLeaf _ = False
keyOf :: PDFTree a -> Key a
keyOf (Tip k _) = k
keyOf _ = error "No key for a node"
size :: PDFTree a -> Int
size t
= case t of
Bin _ _ l r -> (size l) + (size r)
Tip _ _ -> 1
Nil -> 0
lookup :: Key a -> PDFTree a -> Maybe a
lookup k t
= let nk = natFromInt k in seq nk (lookupN nk t)
lookupN :: Nat -> PDFTree a -> Maybe a
lookupN k t
= case t of
Bin _ m l r
| zeroN k (natFromInt m) -> lookupN k l
| otherwise -> lookupN k r
Tip kx x
| (k == natFromInt kx) -> Just x
| otherwise -> Nothing
Nil -> Nothing
zeroN :: Nat -> Nat -> Bool
zeroN i m = (i .&. m) == 0
insert :: Key a -> a -> PDFTree a -> PDFTree a
insert k x t
= case t of
Bin p m l r
| nomatch k p m -> join k (Tip k x) p t
| zero k m -> Bin p m (insert k x l) r
| otherwise -> Bin p m l (insert k x r)
Tip ky _
| k==ky -> Tip k x
| otherwise -> join k (Tip k x) ky t
Nil -> Tip k x
join :: Prefix a -> PDFTree a -> Prefix a -> PDFTree a -> PDFTree a
join p1 t1 p2 t2
| zero p1 m = Bin p m t1 t2
| otherwise = Bin p m t2 t1
where
m = branchMask p1 p2
p = mask p1 m
zero :: Key a -> Mask a -> Bool
zero i m
= (natFromInt i) .&. (natFromInt m) == 0
nomatch :: Key a -> Prefix a -> Mask a -> Bool
nomatch i p m
= (mask i m) /= p
mask :: Key a -> Mask a -> Prefix a
mask i m
= maskW (natFromInt i) (natFromInt m)
maskW :: Nat -> Nat -> Prefix a
maskW i m
= intFromNat (i .&. (complement (m-1) `xor` m))
branchMask :: Prefix a -> Prefix a -> Mask a
branchMask p1 p2
= intFromNat (highestBitMask (natFromInt p1 `xor` natFromInt p2))
highestBitMask :: Nat -> Nat
highestBitMask x
= case (x .|. shiftRL x 1) of
x1 -> case (x1 .|. shiftRL x1 2) of
x2 -> case (x2 .|. shiftRL x2 4) of
x3 -> case (x3 .|. shiftRL x3 8) of
x4 -> case (x4 .|. shiftRL x4 16) of
x5 -> case (x5 .|. shiftRL x5 32) of
x6 -> (x6 `xor` (shiftRL x6 1))
shiftRL :: Nat -> Int -> Nat
#if __GLASGOW_HASKELL__
shiftRL (W# x) (I# i)
= W# (shiftRL# x i)
#else
shiftRL x i = shiftR x i
#endif
empty :: PDFTree a
empty
= Nil
foldlStrict :: (a -> t -> a) -> a -> [t] -> a
foldlStrict f z xs
= case xs of
[] -> z
(x:xx) -> let z' = f z x in seq z' (foldlStrict f z' xx)
fromList :: [(Key a,a)] -> PDFTree a
fromList xs
= foldlStrict ins empty xs
where
ins t (k,x) = insert k x t