{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Development.IDE.Graph.Internal.Intern(
    Intern, Id,
    empty, insert, add, lookup, toList, fromList
    ) where

import qualified Data.HashMap.Strict       as Map
import           Data.List                 (foldl')
import           Development.IDE.Graph.Classes
import           Prelude                   hiding (lookup)


-- Invariant: The first field is the highest value in the Map
data Intern a = Intern {-# UNPACK #-} !Int !(Map.HashMap a Id)

type Id = Int

empty :: Intern a
empty :: Intern a
empty = Int -> HashMap a Int -> Intern a
forall a. Int -> HashMap a Int -> Intern a
Intern Int
0 HashMap a Int
forall k v. HashMap k v
Map.empty


insert :: (Eq a, Hashable a) => a -> Id -> Intern a -> Intern a
insert :: a -> Int -> Intern a -> Intern a
insert a
k Int
v (Intern Int
n HashMap a Int
mp) = Int -> HashMap a Int -> Intern a
forall a. Int -> HashMap a Int -> Intern a
Intern (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
n Int
v) (HashMap a Int -> Intern a) -> HashMap a Int -> Intern a
forall a b. (a -> b) -> a -> b
$ a -> Int -> HashMap a Int -> HashMap a Int
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insert a
k Int
v HashMap a Int
mp


add :: (Eq a, Hashable a) => a -> Intern a -> (Intern a, Id)
add :: a -> Intern a -> (Intern a, Int)
add a
k (Intern Int
v HashMap a Int
mp) = (Int -> HashMap a Int -> Intern a
forall a. Int -> HashMap a Int -> Intern a
Intern Int
v2 (HashMap a Int -> Intern a) -> HashMap a Int -> Intern a
forall a b. (a -> b) -> a -> b
$ a -> Int -> HashMap a Int -> HashMap a Int
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
Map.insert a
k Int
v2 HashMap a Int
mp, Int
v2)
    where v2 :: Int
v2 = Int
v Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1


lookup :: (Eq a, Hashable a) => a -> Intern a -> Maybe Id
lookup :: a -> Intern a -> Maybe Int
lookup a
k (Intern Int
_ HashMap a Int
mp) = a -> HashMap a Int -> Maybe Int
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
Map.lookup a
k HashMap a Int
mp


toList :: Intern a -> [(a, Id)]
toList :: Intern a -> [(a, Int)]
toList (Intern Int
_ HashMap a Int
mp) = HashMap a Int -> [(a, Int)]
forall k v. HashMap k v -> [(k, v)]
Map.toList HashMap a Int
mp


fromList :: (Eq a, Hashable a) => [(a, Id)] -> Intern a
fromList :: [(a, Int)] -> Intern a
fromList [(a, Int)]
xs = Int -> HashMap a Int -> Intern a
forall a. Int -> HashMap a Int -> Intern a
Intern ((Int -> Int -> Int) -> Int -> [Int] -> Int
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 [Int
i | (a
_, Int
i) <- [(a, Int)]
xs]) ([(a, Int)] -> HashMap a Int
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
Map.fromList [(a, Int)]
xs)