{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Trustworthy #-}
module Data.Parameterized.HashTable
  ( HashTable
  , new
  , newSized
  , clone
  , lookup
  , insert
  , member
  , delete
  , clear
  , Data.Parameterized.Classes.HashableF(..)
  , Control.Monad.ST.RealWorld
  ) where
import Control.Applicative
import Control.Monad.ST
import qualified Data.HashTable.ST.Cuckoo as H
import GHC.Exts (Any)
import Unsafe.Coerce
import Prelude hiding (lookup)
import Data.Parameterized.Classes
import Data.Parameterized.Some
newtype HashTable s (key :: k -> *) (val :: k -> *)
      = HashTable (H.HashTable s (Some key) Any)
new :: ST s (HashTable s key val)
new = HashTable <$> H.new
newSized :: Int -> ST s (HashTable s k v)
newSized n = HashTable <$> H.newSized n
clone :: (HashableF key, TestEquality key)
      => HashTable s key val
      -> ST s (HashTable s key val)
clone (HashTable tbl) = do
  
  r <- H.new
  
  H.mapM_ (uncurry (H.insert r)) tbl
  
  return $! HashTable r
lookup :: (HashableF key, TestEquality key)
       => HashTable s key val
       -> key tp
       -> ST s (Maybe (val tp))
lookup (HashTable h) k = fmap unsafeCoerce <$> H.lookup h (Some k)
{-# INLINE lookup #-}
insert :: (HashableF key, TestEquality key)
       => HashTable s (key :: k -> *) (val :: k -> *)
       -> key tp
       -> val tp
       -> ST s ()
insert (HashTable h) k v = H.insert h (Some k) (unsafeCoerce v)
member :: (HashableF key, TestEquality key)
       => HashTable s (key :: k -> *) (val :: k -> *)
       -> key (tp :: k)
       -> ST s Bool
member (HashTable h) k = isJust <$> H.lookup h (Some k)
delete :: (HashableF key, TestEquality key)
       => HashTable s (key :: k -> *) (val :: k -> *)
       -> key (tp :: k)
       -> ST s ()
delete (HashTable h) k = H.delete h (Some k)
clear :: (HashableF key, TestEquality key)
      => HashTable s (key :: k -> *) (val :: k -> *) -> ST s ()
clear (HashTable h) = H.mapM_ (\(k,_) -> H.delete h k) h