Shared table support for Nim. Use plain old non GC'ed keys and values or you'll be in trouble. Uses a single lock to protect the table, lockfree implementations welcome but if lock contention is so high that you need a lockfree hash table, you're doing it wrong.
SharedTable[A; B] = object data: KeyValuePairSeq[A, B] counter, dataLen: int lock: Lock
proc mget[A, B](t: var SharedTable[A, B]; key: A): var B
t[key]
. The value can be modified. If key is not in t, the KeyError
exception is raised. proc mgetOrPut[A, B](t: var SharedTable[A, B]; key: A; val: B): var B
t[key]
or puts val
if not present, either way returning a value which can be modified. Note: This is inherently unsafe in the context of multi-threading since it returns a pointer to B
. proc hasKeyOrPut[A, B](t: var SharedTable[A, B]; key: A; val: B): bool
proc withKey[A, B](t: var SharedTable[A, B]; key: A; mapper: proc (key: A; val: var B; pairExists: var bool))
Computes a new mapping for the key
with the specified mapper
procedure.
The mapper
takes 3 arguments:
key
- the current key, if it exists, or the key passed to withKey
otherwise;val
- the current value, if the key exists, or default value of the type otherwise;pairExists
- true
if the key exists, false
otherwise.The mapper
can can modify val
and pairExists
values to change the mapping of the key or delete it from the table. When adding a value, make sure to set pairExists
to true
along with modifying the val
.
The operation is performed atomically and other operations on the table will be blocked while the mapper
is invoked, so it should be short and simple.
Example usage:
# If value exists, decrement it. # If it becomes zero or less, delete the key t.withKey(1'i64) do (k: int64, v: var int, pairExists: var bool): if pairExists: dec v if v <= 0: pairExists = false
proc `[]=`[A, B](t: var SharedTable[A, B]; key: A; val: B)
proc add[A, B](t: var SharedTable[A, B]; key: A; val: B)
t[key]
already exists. This can introduce duplicate keys into the table! proc del[A, B](t: var SharedTable[A, B]; key: A)
proc init[A, B](t: var SharedTable[A, B]; initialSize = 64)
creates a new hash table that is empty.
initialSize needs to be a power of two. If you need to accept runtime values for this you could use the nextPowerOfTwo
proc from the math module or the rightSize
proc from this module.
proc deinitSharedTable[A, B](t: var SharedTable[A, B])
proc initSharedTable[A, B](initialSize = 64): SharedTable[A, B] {...}{.deprecated.}
template withValue[A; B](t: var SharedTable[A, B]; key: A; value, body: untyped)
t[key]
. value can be modified in the scope of the withValue
call.sharedTable.withValue(key, value) do: # block is executed only if ``key`` in ``t`` # value is threadsafe in block value.name = "username" value.uid = 1000
template withValue[A; B](t: var SharedTable[A, B]; key: A; value, body1, body2: untyped)
t[key]
. value can be modified in the scope of the withValue
call.sharedTable.withValue(key, value) do: # block is executed only if ``key`` in ``t`` # value is threadsafe in block value.name = "username" value.uid = 1000 do: # block is executed when ``key`` not in ``t`` raise newException(KeyError, "Key not found")
© 2006–2018 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/sharedtables.html