module Data.HSet.Mutable
  ( HKey
  , HSet
  , new
  , insert
  , lookup
  , delete
  ) where

import Data.HSet.Types

import Prelude hiding (lookup, length)
import Data.Maybe (fromMaybe)

import Data.Typeable.Internal (Fingerprint, TypeRep (TypeRep))
import Data.Dynamic

import           Data.HashTable.ST.Basic (HashTable)
import qualified Data.HashTable.ST.Basic as HT
import Control.Monad.ST



data HSet s = HSet
  { hSetValues :: {-# UNPACK #-} !(HashTable s HKey' Dynamic)
  , hSetCount  :: {-# UNPACK #-} !(HashTable s Fingerprint Int)
  }


new :: ST s (HSet s)
new = HSet <$> HT.new <*> HT.new


insert :: ( Typeable a
          ) => a -> HSet s -> ST s (HKey a)
insert x (HSet xs count) = do
  let (TypeRep f _ _ _) = typeOf x
  c <- fromMaybe 0 <$> HT.lookup count f
  HT.insert count f (c+1)
  let k = HKey' f c
  HT.insert xs k (toDyn x)
  pure (HKey k)


lookup :: ( Typeable a
          ) => HKey a -> HSet s -> ST s (Maybe a)
lookup (HKey k) (HSet xs _) = (>>= fromDynamic) <$> HT.lookup xs k


delete :: HKey a -> HSet s -> ST s ()
delete (HKey k@(HKey' f _)) (HSet xs count) = do
  HT.delete count f
  HT.delete xs k