-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Thread-safe hash tables for multi-cores! -- -- Please see the README on GitHub at -- https://github.com/pwrobinson/concurrent-hashtable#readme @package concurrent-hashtable @version 0.1.4 -- | You can find benchmarks and more information about the internals of -- this package here: -- https://lowerbound.io/blog/2019-10-24_concurrent_hash_table_performance.html -- -- List of atomic operations: insert, insertIfNotExists, -- lookup, delete, readAssocs, resize module Data.HashTable.Internal data MigrationStatus NotStarted :: MigrationStatus Ongoing :: MigrationStatus Finished :: MigrationStatus -- | Used for chain-hashing. data Chain k v Chain :: TVar [(k, v)] -> TVar MigrationStatus -> Chain k v -- | stores the items for this index [_itemsTV] :: Chain k v -> TVar [(k, v)] -- | used internally for resizing [_migrationStatusTV] :: Chain k v -> TVar MigrationStatus newChainIO :: IO (Chain k v) -- | A thread-safe hash table that supports dynamic resizing. data HashTable k v HashTable :: TVar (Vector (Chain k v)) -> IORef Int -> Config k -> HashTable k v -- | vector of linked lists [_chainsVecTV] :: HashTable k v -> TVar (Vector (Chain k v)) [_totalLoad] :: HashTable k v -> IORef Int [_config] :: HashTable k v -> Config k -- | Configuration options that may affect the performance of the hash -- table data Config k Config :: Float -> Float -> Int -> (k -> Int) -> Config k -- | scale factor for resizing [_scaleFactor] :: Config k -> Float -- | load threshold for initiating resizing. [_threshold] :: Config k -> Float -- | maximum number of worker threads used during resizing [_numResizeWorkers] :: Config k -> Int [_hashFunc] :: Config k -> k -> Int -- | Default configuration: scale factor = 2.0; resizing threshold = 0.75; -- number of worker threads for resizing = getNumCapabilities; -- hash function = use hashWithSalt with a random salt mkDefaultConfig :: Hashable k => IO (Config k) -- | Creates a new hash table with an initial size. See -- newWithDefaults for more details. You probably either want to -- use newWithDefaults instead or something like this: > -- mkDefaultConfig { _field = myValue } >>= new 10 new :: Eq k => Int -> Config k -> IO (HashTable k v) -- | Creates a new hash table with the given initial vector size, scale -- factor 2.0, a resizing load threshold of 0.75, and we use as many -- threads for resizing as we have cores available. This will use a hash -- function with a (single) random salt, so if you need security, you -- MUST supply your own hash function. To be replaced by universal -- hashing in future versions. newWithDefaults :: (Eq k, Hashable k) => Int -> IO (HashTable k v) -- | Returns the size of the vector representing the hash table. readSizeIO :: HashTable k v -> IO Int readSize :: HashTable k v -> STM Int -- | Resizes the hash table by scaling it according to the _scaleFactor in -- the configuration. resize :: Eq k => HashTable k v -> IO () -- | Lookup the value for the key in the hash table if it exists. lookup :: Eq k => HashTable k v -> k -> IO (Maybe v) -- | Used internally. An action to be executed atomically for the given -- chain. type STMAction k v a = TVar [(k, v)] -> STM (Maybe a) -- | Used internally by insert, insertIfNotExists, -- delete, update genericModify :: Eq k => HashTable k v -> k -> STMAction k v a -> IO a -- | Inserts the key-value pair k v into the hash table. -- Uses chain hashing to resolve collisions. insert :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Inserts a key and value pair into the hash table only if the key does -- not exist yet. Returns True if the insertion was successful, -- i.e., the hash table did not contain this key before. To get the same -- behaviour as insert, use insert. If you want to update -- an entry only if it exists, use update. insertIfNotExists :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Deletes the entry for the given key from the hash table. Returns -- True if and only if an entry was deleted from the table. delete :: Eq k => HashTable k v -> k -> IO Bool -- | Atomically increment/decrement the table load value by adding the -- provided integer value to the current value. atomicallyChangeLoad :: Eq k => HashTable k v -> Int -> IO () -- | The load (i.e. number of stored items) in the table. Note that this is -- not synchronized for performance reasons and hence might be somewhat -- out of date if a lot of contention is happening. readLoad :: HashTable k v -> IO Int readAssocs :: Eq k => HashTable k v -> STM [(k, v)] deleteFirstKey :: Eq a => a -> [(a, b)] -> [(a, b)] -- | Atomically read the chain for the given key. readChainForKeyIO :: HashTable k v -> k -> IO (Chain k v) -- | Atomically read the chain for the given index. (Warning: bounds are -- not checked.) readChainForIndexIO :: HashTable k v -> Int -> IO (Chain k v) -- | Atomically read the chain for the given index. (Warning: bounds are -- not checked.) readChainForIndex :: HashTable k v -> Int -> STM (Chain k v) debug :: Show a => a -> IO () instance GHC.Classes.Eq (Data.HashTable.Internal.Chain k v) instance GHC.Classes.Eq Data.HashTable.Internal.MigrationStatus instance GHC.Show.Show Data.HashTable.Internal.MigrationStatus instance GHC.Show.Show (Data.HashTable.Internal.Config k) -- | You can find benchmarks and more information about the internals of -- this package here: -- https://lowerbound.io/blog/2019-10-24_concurrent_hash_table_performance.html -- -- Usage Example: -- --
-- > ht <- newWithDefaults 4 -- creates hash table of initial size 4 -- > insert ht 1 "hello" -- adds key-value pair (1,"hello") -- > insert ht 2 "world" -- adds key-value pair (2,"world") -- > atomically $ readAssocs ht -- convert to a key-value list -- [(1,"hello"),(2,"world")] -- > readSizeIO ht -- returns 4 -- > insert ht 3 "!" -- adds key-value pair (3,"!") and triggers a resize as the load fraction is ≥ 0.75 -- > readSizeIO ht -- returns 8 -- > atomically $ readAssocs ht -- convert to a key-value list -- [(1,"hello"),(3,"!"),(2,"world")] ---- -- List of atomic operations: insert, insertIfNotExists, -- lookup, delete, getAssocs, resize module Data.HashTable -- | A thread-safe hash table that supports dynamic resizing. data HashTable k v -- | Used for chain-hashing. data Chain k v -- | Creates a new hash table with an initial size. See -- newWithDefaults for more details. You probably either want to -- use newWithDefaults instead or something like this: > -- mkDefaultConfig { _field = myValue } >>= new 10 new :: Eq k => Int -> Config k -> IO (HashTable k v) -- | Creates a new hash table with the given initial vector size, scale -- factor 2.0, a resizing load threshold of 0.75, and we use as many -- threads for resizing as we have cores available. This will use a hash -- function with a (single) random salt, so if you need security, you -- MUST supply your own hash function. To be replaced by universal -- hashing in future versions. newWithDefaults :: (Eq k, Hashable k) => Int -> IO (HashTable k v) -- | Default configuration: scale factor = 2.0; resizing threshold = 0.75; -- number of worker threads for resizing = getNumCapabilities; -- hash function = use hashWithSalt with a random salt mkDefaultConfig :: Hashable k => IO (Config k) -- | Configuration options that may affect the performance of the hash -- table data Config k Config :: Float -> Float -> Int -> (k -> Int) -> Config k -- | scale factor for resizing [_scaleFactor] :: Config k -> Float -- | load threshold for initiating resizing. [_threshold] :: Config k -> Float -- | maximum number of worker threads used during resizing [_numResizeWorkers] :: Config k -> Int [_hashFunc] :: Config k -> k -> Int -- | Lookup the value for the key in the hash table if it exists. lookup :: Eq k => HashTable k v -> k -> IO (Maybe v) -- | Inserts the key-value pair k v into the hash table. -- Uses chain hashing to resolve collisions. insert :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Inserts a key and value pair into the hash table only if the key does -- not exist yet. Returns True if the insertion was successful, -- i.e., the hash table did not contain this key before. To get the same -- behaviour as insert, use insert. If you want to update -- an entry only if it exists, use update. insertIfNotExists :: Eq k => HashTable k v -> k -> v -> IO Bool -- | Deletes the entry for the given key from the hash table. Returns -- True if and only if an entry was deleted from the table. delete :: Eq k => HashTable k v -> k -> IO Bool readAssocs :: Eq k => HashTable k v -> STM [(k, v)] -- | Returns the size of the vector representing the hash table. readSizeIO :: HashTable k v -> IO Int readSize :: HashTable k v -> STM Int