module HashtablesPlus
(
Table,
Set,
HashRefSet,
MultiTable,
Sized,
Basic,
Cuckoo,
Linear,
Key,
Row,
UniqueKey,
MultiKey,
Value,
Collection(..),
Lookup(..),
LookupMulti(..),
Elem(..),
Insert(..),
Delete(..),
Size(..),
Null(..),
forM_,
toList,
)
where
import HashtablesPlus.Prelude hiding (elem, toList, null, insert, delete, lookup, foldM, forM_)
import qualified HashtablesPlus.HashRef as HR
import qualified Data.HashTable.IO as T
import qualified Data.HashTable.ST.Basic
import qualified Data.HashTable.ST.Cuckoo
import qualified Data.HashTable.ST.Linear
type family Row c
type family UniqueKey c
type family MultiKey c
type family Value c
class Collection c where
new :: IO c
foldM :: c -> r -> (r -> Row c -> IO r) -> IO r
class Collection c => Lookup c where
lookup :: c -> UniqueKey c -> IO (Maybe (Value c))
class Collection c => LookupMulti c where
lookupMulti :: c -> MultiKey c -> IO [Value c]
class Collection c => Elem c where
elem :: c -> UniqueKey c -> IO Bool
default elem :: Lookup c => c -> UniqueKey c -> IO Bool
elem = ((fmap isJust) .) . lookup
class Collection c => Insert c where
insert :: c -> Row c -> IO Bool
insertFast :: c -> Row c -> IO ()
insertFast = (void .) . insert
class Collection c => Delete c where
delete :: c -> UniqueKey c -> IO Bool
deleteFast :: c -> UniqueKey c -> IO ()
deleteFast = (void .) . delete
class Collection c => Size c where
size :: c -> IO Int
class Collection c => Null c where
null :: c -> IO Bool
default null :: (Size c) => c -> IO Bool
null = fmap (<= 0) . size
forM_ :: (Collection c) => c -> (Row c -> IO ()) -> IO ()
forM_ c f = foldM c () (\() r -> f r)
toList :: (Collection c) => c -> IO [Row c]
toList c = foldM c [] (\li ro -> return $ ro : li)
type Key k = (Hashable k, Eq k)
type Basic = Data.HashTable.ST.Basic.HashTable
type Cuckoo = Data.HashTable.ST.Cuckoo.HashTable
type Linear = Data.HashTable.ST.Linear.HashTable
newtype Table t k v = Table (T.IOHashTable t k v)
type instance Row (Table t k v) = (k, v)
type instance UniqueKey (Table t k v) = k
type instance Value (Table t k v) = v
instance (HashTable t, Key k) => Collection (Table t k v) where
new = Table <$> T.new
foldM (Table t) z f = T.foldM f z t
instance (HashTable t, Key k) => Lookup (Table t k v) where
lookup (Table t) = T.lookup t
instance (HashTable t, Key k) => Elem (Table t k v)
instance (HashTable t, Key k) => Insert (Table t k v) where
insert (Table t) (k, v) = do
T.lookup t k >>= \case
Just v' -> return False
Nothing -> T.insert t k v >> return True
insertFast (Table t) (k, v) = T.insert t k v
instance (HashTable t, Key k) => Delete (Table t k v) where
delete (Table t) k = do
T.lookup t k >>= \case
Just v' -> return False
Nothing -> T.delete t k >> return True
deleteFast (Table t) k = T.delete t k
newtype Set t a = Set (T.IOHashTable t a ())
type instance Row (Set t a) = a
type instance UniqueKey (Set t a) = a
type instance Value (Set t a) = a
instance (HashTable t, Key a) => Collection (Set t a) where
new = Set <$> T.new
foldM (Set table) z f = T.foldM f' z table where
f' z (a, _) = f z a
instance (HashTable t, Key a) => Elem (Set t a) where
elem (Set table) a = T.lookup table a >>= return . isJust
instance (HashTable t, Key a) => Insert (Set t a) where
insert (Set table) a = do
T.lookup table a >>= \case
Just _ -> return False
Nothing -> do
T.insert table a ()
return True
insertFast (Set table) a = T.insert table a ()
instance (HashTable t, Key a) => Delete (Set t a) where
delete (Set table) a = do
T.lookup table a >>= \case
Just _ -> do
T.delete table a
return True
Nothing -> return False
deleteFast (Set table) a = T.delete table a
newtype HashRefSet t a = HashRefSet (T.IOHashTable t (StableName a) a)
type instance Row (HashRefSet t a) = HR.HashRef a
type instance UniqueKey (HashRefSet t a) = HR.HashRef a
type instance Value (HashRefSet t a) = HR.HashRef a
instance (HashTable t) => Collection (HashRefSet t a) where
new = HashRefSet <$> T.new
foldM (HashRefSet table) z f = T.foldM f' z table where
f' z (sn, a) = f z (HR.HashRef sn a)
instance (HashTable t) => Elem (HashRefSet t a) where
elem (HashRefSet table) (HR.HashRef sn a) = T.lookup table sn >>= return . isJust
instance (HashTable t) => Insert (HashRefSet t a) where
insert (HashRefSet table) (HR.HashRef sn a) = do
T.lookup table sn >>= \case
Just _ -> return False
Nothing -> do
T.insert table sn a
return True
insertFast (HashRefSet table) (HR.HashRef sn a) = T.insert table sn a
instance (HashTable t) => Delete (HashRefSet t a) where
delete (HashRefSet table) (HR.HashRef sn a) = do
T.lookup table sn >>= \case
Just _ -> do
T.delete table sn
return True
Nothing -> return False
deleteFast (HashRefSet table) (HR.HashRef sn a) = T.delete table sn
data Sized c = Sized !c !(IORef Int)
type instance Row (Sized c) = Row c
type instance UniqueKey (Sized c) = UniqueKey c
type instance MultiKey (Sized c) = MultiKey c
type instance Value (Sized c) = Value c
instance (Collection c) => Collection (Sized c) where
new = Sized <$> new <*> newIORef 0
foldM (Sized c _) = foldM c
instance (Lookup c) => Lookup (Sized c) where
lookup (Sized c _) a = lookup c a
instance (LookupMulti c) => LookupMulti (Sized c) where
lookupMulti (Sized c _) k = lookupMulti c k
instance (Elem c) => Elem (Sized c) where
elem (Sized c _) a = elem c a
instance (Insert c) => Insert (Sized c) where
insert (Sized c size) a = do
ok <- insert c a
when ok $ modifyIORef size succ
return ok
instance (Delete c) => Delete (Sized c) where
delete (Sized c size) a = do
ok <- delete c a
when ok $ modifyIORef size pred
return ok
instance (Collection c) => Size (Sized c) where
size (Sized _ s) = readIORef s
instance (Collection c) => Null (Sized c)
newtype MultiTable t k s = MultiTable (T.IOHashTable t k s)
type instance Row (MultiTable t k s) = (k, Row s)
type instance UniqueKey (MultiTable t k s) = (k, UniqueKey s)
type instance MultiKey (MultiTable t k s) = k
type instance Value (MultiTable t k s) = Value s
instance (HashTable t, Key k, Collection s) =>
Collection (MultiTable t k s) where
new = MultiTable <$> T.new
foldM (MultiTable t) z f = T.foldM f' z t where
f' z (k, s) = foldM s z f'' where
f'' z v = f z (k, v)
instance (HashTable t, Key k, Collection s, Value s ~ Row s) =>
LookupMulti (MultiTable t k s) where
lookupMulti (MultiTable t) k = do
T.lookup t k >>= \case
Nothing -> return []
Just s -> toList s
instance (HashTable t, Key k, Elem s) =>
Elem (MultiTable t k s) where
elem (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> return False
Just s -> elem s v
instance (HashTable t, Key k, Insert s) =>
Insert (MultiTable t k s) where
insert (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> do
s <- new
insertFast s v
T.insert t k s
return True
Just s -> do
insert s v
insertFast (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> do
s <- new
insertFast s v
T.insert t k s
Just s -> do
insertFast s v
instance (HashTable t, Key k, Delete c) => Delete (MultiTable t k c) where
delete (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> return False
Just s -> delete s v
deleteFast (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> return ()
Just s -> deleteFast s v
instance (HashTable t, Key k, Delete c) => Delete (MultiTable t k (Sized c)) where
delete (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> return False
Just s -> do
delete s v >>= \case
False -> return False
True -> do
null s >>= \case
False -> return ()
True -> T.delete t k
return True
deleteFast (MultiTable t) (k, v) = do
T.lookup t k >>= \case
Nothing -> return ()
Just s -> do
deleteFast s v
null s >>= \case
False -> return ()
True -> T.delete t k