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 ()
import Data.PropertyList.Binary.Types
import Data.Sequence as S
import Prelude as P
linearize :: PropertyList -> BPListRecords Abs
linearize = intern . absolutize . fromPlist
absolutize :: BPListRecords Rel -> BPListRecords Abs
absolutize (BPListRecords root recs) =
BPListRecords root (S.mapWithIndex shiftRec recs)
where
shiftRec i = mapObjRefs (fromIntegral i +)
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)
delinearize :: BPListRecords Abs -> PartialPropertyList UnparsedBPListRecord
delinearize = toPlist