btree-concurrent-0.1.0: Data/BTree/HashTable/STM.hs
{-# LANGUAGE TupleSections
, BangPatterns
#-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.BTree.HashTable.STM
-- A hashtable in STM.
--
-----------------------------------------------------------------------------
module Data.BTree.HashTable.STM
( HashTableSTM
, newSized
, insert
, lookup
, delete
, size
, keys
, toList
) where
import Prelude hiding (lookup)
import Control.Concurrent.STM
import Control.Monad
import Data.Array
import Data.Hashable (Hashable(..))
import Data.Maybe
import qualified Data.List as L
import qualified Data.Map as M
type Bucket k v = M.Map k v
data HashTableSTM k v = HashTableSTM { buckets :: !Int -- number of buckets
, count :: TVar Int -- current element count
, getArray :: Array Int (TVar (Bucket k v)) }
bucket (HashTableSTM n _ arr) k = arr ! (hash k `mod` n)
{-# INLINE bucket #-}
-- | Create a new HashTable with fixed size
newSized :: Int -> IO (HashTableSTM k v)
newSized n =
do co <- newTVarIO 0
vs <- mapM (\i -> (i,) `fmap` newTVarIO M.empty) [0..n-1]
return $! HashTableSTM n co $! array (0, n-1) vs
modifyCount h f = do
n <- readTVar $ count h
writeTVar (count h) $! f n
{-# INLINE modifyCount #-}
-- | /O(log n)/. Insert a key/value pair into HashTable.
insert :: (Hashable k, Ord k) => HashTableSTM k v -> k -> v -> STM ()
insert h !k !v = do
m <- readTVar b
let m' = M.insert k v m
writeTVar b $! m'
modifyCount h (+1)
where
b = bucket h k
-- | /O(log n)/. Lookup a key in HashTable.
lookup :: (Hashable k, Ord k) => HashTableSTM k v -> k -> STM (Maybe v)
lookup h !k =
do lst <- readTVar $ bucket h k
return $! M.lookup k lst
-- | /O(log n)/. Delete a key from HashTable.
delete :: (Hashable k, Ord k) => HashTableSTM k v -> k -> STM ()
delete h !k =
do m <- readTVar b
let (a, m') = M.updateLookupWithKey (\_ _ -> Nothing) k m
when (isJust a) $
modifyCount h (subtract 1)
M.lookup k m' `seq` writeTVar b m'
where
b = bucket h k
-- | /O(1)/. Grab the size of the hash table.
size :: HashTableSTM k v -> STM Int
size h = readTVar c
where
c = count h
-- | /O(n)/. Get a list of key/value pairs.
toList :: HashTableSTM k v -> STM [(k, v)]
toList h =
do bs <- buckets h
return $ concat $ map M.toList bs
where
buckets (HashTableSTM n _ arr) =
mapM readTVar $ elems arr
-- | /O(n)/. Get a list of keys.
keys :: HashTableSTM k v -> STM [k]
keys h =
do l <- toList h
return $ map fst l