property-list-0.1: src/Data/PropertyList/Binary/Linearize.hs
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