module Data.PropertyList.Binary.Linearize ( linearize , absolutize , intern , delinearize ) where import qualified Data.Foldable as F import qualified Data.Map as M import Data.Maybe import Data.PropertyList.Types import Data.PropertyList.Algebra import Data.PropertyList.Binary.Algebra ({- instances-}) import Data.PropertyList.Binary.Types import Data.Sequence as S import Prelude as P -- |Flatten a 'PropertyList' to a sequence of 'BPListRecords'. The resulting records will -- use absolute addressing and will not have any duplicates. linearize :: PropertyList -> BPListRecords Abs linearize = intern . absolutize . fromPlist -- |Take some 'BPListRecords' using relative addressing and change them to use absolute addressing absolutize :: BPListRecords Rel -> BPListRecords Abs absolutize (BPListRecords root recs) = BPListRecords root (S.mapWithIndex shiftRec recs) where shiftRec i = mapObjRefs (fromIntegral i +) -- |Take some 'BPListRecords' using absolute addressing and eliminate -- all duplicate records, compact the table and update all internal -- references. -- -- Does not necessarily yield a totally deduplicated table; The process -- of interning can introduce duplicate records (because it alters arrays, -- dicts and sets). All other node types will be deduplicated in one pass, -- though, which is usually sufficient. intern :: BPListRecords Abs -> BPListRecords Abs intern (BPListRecords root recs) = BPListRecords (reloc root) recs' where reloc i' | i < 0 || i >= n = error ("intern: reference out of bounds: " ++ show i) | otherwise = S.index relocs i where i = fromIntegral i'; n = S.length recs (_, relocs, recs') = F.foldl updateRec (M.empty, S.empty, S.empty) recs updateRec (index, relocs, recs) x = case M.lookup x index of Nothing -> let nRecs = fromIntegral (S.length recs) in ( M.insert x nRecs index , relocs |> nRecs , recs |> mapObjRefs reloc x ) Just loc -> ( index, relocs |> loc, recs) -- TODO: check for cycles? -- |Reconstruct a property list from a collection of 'BPListRecords' delinearize :: BPListRecords Abs -> PartialPropertyList UnparsedBPListRecord delinearize = toPlist