packages feed

stc-lang-1.0.0: stream-bench/MutableSet.hs

{-# LANGUAGE ConstraintKinds #-}

module MutableSet
    ( Set
    , Constraint
    , new
    , delete
    , insert
    , member
    , mapM_
    , size
    , toList
    ) where

import Control.DeepSeq
import Control.Monad.IO.Class (MonadIO, liftIO)
import qualified Data.HashTable.IO as HT
import Data.Hashable (Hashable)
import Data.Maybe (isJust)
import Prelude hiding (mapM_)

type HashSetInner a = HT.BasicHashTable a ()

newtype Set a = Set
    { unwrap :: HashSetInner a
    }

type Constraint a = (Hashable a, Eq a)

new :: MonadIO m => m (Set a)
new = liftIO $ Set <$> HT.new

insert :: (MonadIO m, Constraint a) => a -> Set a -> m ()
insert item t = liftIO $ HT.insert (unwrap t) item ()

delete :: (MonadIO m, Constraint a) => a -> Set a -> m ()
delete item set = liftIO $ HT.delete (unwrap set) item

member :: (MonadIO m, Constraint a) => a -> Set a -> m Bool
member i t = liftIO $ isJust <$> HT.lookup (unwrap t) i

mapM_ :: MonadIO m => (a -> IO b) -> Set a -> m ()
mapM_ f = liftIO . HT.mapM_ (f . fst) . unwrap

size :: MonadIO m => Set a -> m Word
size = liftIO . HT.foldM (\a _ -> pure $ a + 1) 0 . unwrap

toList :: (MonadIO m, Constraint a) => Set a -> m [a]
toList = liftIO . fmap (map fst) . HT.toList . unwrap

-- This is a weird NFData instance, but the assumption is that HashMaps are
-- strict in the keys, because computing the hash forces the key. And since a
-- set does not have non-unit values, the values need not be forced.
instance NFData (Set i) where
    rnf _ = ()