mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-09 04:59:31 -06:00
62 lines
1.6 KiB
Haskell
62 lines
1.6 KiB
Haskell
-- | In order to build an IntMap in one pass, we need a map data structure with
|
|
-- fast lookup in both keys and values.
|
|
-- This is achieved by keeping a separate reversed map of values to keys during building.
|
|
module GF.Data.IntMapBuilder where
|
|
|
|
import Data.IntMap (IntMap)
|
|
import qualified Data.IntMap as IntMap
|
|
import Data.Hashable (Hashable)
|
|
import Data.HashMap.Strict (HashMap)
|
|
import qualified Data.HashMap.Strict as HashMap
|
|
import Data.Tuple (swap)
|
|
import Prelude hiding (lookup)
|
|
|
|
data IMB a = IMB {
|
|
intMap :: IntMap a,
|
|
valMap :: HashMap a Int
|
|
}
|
|
|
|
-- | An empty IMB
|
|
empty :: (Eq a, Hashable a) => IMB a
|
|
empty = IMB {
|
|
intMap = IntMap.empty,
|
|
valMap = HashMap.empty
|
|
}
|
|
|
|
-- | An empty IntMap
|
|
emptyIntMap :: IntMap a
|
|
emptyIntMap = IntMap.empty
|
|
|
|
-- | Lookup a value
|
|
lookup :: (Eq a, Hashable a) => a -> IMB a -> Maybe Int
|
|
lookup a IMB { valMap = vm } = HashMap.lookup a vm
|
|
|
|
-- | Insert without any lookup
|
|
insert :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
|
|
insert a IMB { intMap = im, valMap = vm } =
|
|
let
|
|
ix = IntMap.size im
|
|
im' = IntMap.insert ix a im
|
|
vm' = HashMap.insert a ix vm
|
|
imb' = IMB { intMap = im', valMap = vm' }
|
|
in
|
|
(ix, imb')
|
|
|
|
-- | Insert only when lookup fails
|
|
insert' :: (Eq a, Hashable a) => a -> IMB a -> (Int, IMB a)
|
|
insert' a imb =
|
|
case lookup a imb of
|
|
Just ix -> (ix, imb)
|
|
Nothing -> insert a imb
|
|
|
|
-- | Build IMB from existing IntMap
|
|
fromIntMap :: (Eq a, Hashable a) => IntMap a -> IMB a
|
|
fromIntMap im = IMB {
|
|
intMap = im,
|
|
valMap = HashMap.fromList (map swap (IntMap.toList im))
|
|
}
|
|
|
|
-- | Get IntMap from IMB
|
|
toIntMap :: (Eq a, Hashable a) => IMB a -> IntMap a
|
|
toIntMap = intMap
|