{-# LANGUAGE CPP #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE NoBangPatterns #-} ----------------------------------------------------------------------------- -- | -- Module : PDFTree.hs -- Copyright : (c) Daan Leijen 2002 -- License : BSD-style -- Maintainer : misc@NOSPAMalpheccar.org -- Stability : provisional -- Portability : portable -- -- An efficient implementation of maps from integer keys to values. -- -- Customized by alpheccar for the need of the PDF library. The original is IntMap from -- the ghc standard libraries ----------------------------------------------------------------------------- -- #hide 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 -- | A map of integers to values @a@. -- The total size of subtrees is tracked by each node. It is needed for the PDF Tree data PDFTree a = Nil | Tip {-# UNPACK #-} !(Key a) a | Bin {-# UNPACK #-} !(Prefix a) {-# UNPACK #-} !(Mask a) !(PDFTree a) !(PDFTree a) deriving(Eq,Show) -- | The key function needed to export a Tree of PDF objects into the format defined -- by the PDF spec fold2 :: Monad m => Maybe b -- ^ Parent ref -> (Maybe b -> PDFTree a -> PDFTree a -> m (Int,b)) -- ^ Node action -> (Maybe b -> Key a -> a -> m (Int,b)) -- ^ Leaf action -> PDFTree a -- ^ PDFTree -> m (Int,b) -- ^ Final action and reference of the root node 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" {-------------------------------------------------------------------- Query --------------------------------------------------------------------} -- | /O(n)/. Number of elements in the map. size :: PDFTree a -> Int size t = case t of Bin _ _ l r -> (size l) + (size r) Tip _ _ -> 1 Nil -> 0 -- | /O(min(n,W))/. Lookup the value at a key in the map. 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) {-------------------------------------------------------------------- Big endian operations --------------------------------------------------------------------} 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 -- for 64 bit platforms x6 -> (x6 `xor` (shiftRL x6 1)) shiftRL :: Nat -> Int -> Nat #if __GLASGOW_HASKELL__ {-------------------------------------------------------------------- GHC: use unboxing to get @shiftRL@ inlined. --------------------------------------------------------------------} shiftRL (W# x) (I# i) = W# (shiftRL# x i) #else shiftRL x i = shiftR x i #endif empty :: PDFTree a empty = Nil {-------------------------------------------------------------------- Utilities --------------------------------------------------------------------} 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) -- | /O(n*min(n,W))/. Create a map from a list of key\/value pairs. fromList :: [(Key a,a)] -> PDFTree a fromList xs = foldlStrict ins empty xs where ins t (k,x) = insert k x t