Add compute proc for SharedTable (#5385)
This commit is contained in:
parent
e2567e2e03
commit
a81247dcbe
3 changed files with 77 additions and 4 deletions
|
|
@ -130,6 +130,52 @@ proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool =
|
||||||
withLock t:
|
withLock t:
|
||||||
hasKeyOrPutImpl(enlarge)
|
hasKeyOrPutImpl(enlarge)
|
||||||
|
|
||||||
|
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:
|
||||||
|
##
|
||||||
|
## .. code-block:: nim
|
||||||
|
##
|
||||||
|
## # 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
|
||||||
|
withLock t:
|
||||||
|
var hc: Hash
|
||||||
|
var index = rawGet(t, key, hc)
|
||||||
|
|
||||||
|
var pairExists = index >= 0
|
||||||
|
if pairExists:
|
||||||
|
mapper(t.data[index].key, t.data[index].val, pairExists)
|
||||||
|
if not pairExists:
|
||||||
|
delImplIdx(t, index)
|
||||||
|
else:
|
||||||
|
var val: B
|
||||||
|
mapper(key, val, pairExists)
|
||||||
|
if pairExists:
|
||||||
|
maybeRehashPutImpl(enlarge)
|
||||||
|
|
||||||
proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) =
|
proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) =
|
||||||
## puts a (key, value)-pair into `t`.
|
## puts a (key, value)-pair into `t`.
|
||||||
withLock t:
|
withLock t:
|
||||||
|
|
|
||||||
|
|
@ -120,9 +120,7 @@ template default[T](t: typedesc[T]): T =
|
||||||
var v: T
|
var v: T
|
||||||
v
|
v
|
||||||
|
|
||||||
template delImpl() {.dirty.} =
|
template delImplIdx(t, i) =
|
||||||
var hc: Hash
|
|
||||||
var i = rawGet(t, key, hc)
|
|
||||||
let msk = maxHash(t)
|
let msk = maxHash(t)
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
dec(t.counter)
|
dec(t.counter)
|
||||||
|
|
@ -145,6 +143,11 @@ template delImpl() {.dirty.} =
|
||||||
else:
|
else:
|
||||||
shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
|
shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
|
||||||
|
|
||||||
|
template delImpl() {.dirty.} =
|
||||||
|
var hc: Hash
|
||||||
|
var i = rawGet(t, key, hc)
|
||||||
|
delImplIdx(t, i)
|
||||||
|
|
||||||
template clearImpl() {.dirty.} =
|
template clearImpl() {.dirty.} =
|
||||||
for i in 0 .. <t.data.len:
|
for i in 0 .. <t.data.len:
|
||||||
when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
|
when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
discard """
|
discard """
|
||||||
|
cmd: "nim c --threads:on $file"
|
||||||
output: '''true'''
|
output: '''true'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hashes, tables
|
import hashes, tables, sharedtables
|
||||||
|
|
||||||
const
|
const
|
||||||
data = {
|
data = {
|
||||||
|
|
@ -211,6 +212,29 @@ block clearCountTableTest:
|
||||||
t.clear()
|
t.clear()
|
||||||
assert t.len() == 0
|
assert t.len() == 0
|
||||||
|
|
||||||
|
block withKeyTest:
|
||||||
|
var t = initSharedTable[int, int]()
|
||||||
|
t.withKey(1) do (k: int, v: var int, pairExists: var bool):
|
||||||
|
assert(v == 0)
|
||||||
|
pairExists = true
|
||||||
|
v = 42
|
||||||
|
assert(t.mget(1) == 42)
|
||||||
|
t.withKey(1) do (k: int, v: var int, pairExists: var bool):
|
||||||
|
assert(v == 42)
|
||||||
|
pairExists = false
|
||||||
|
try:
|
||||||
|
discard t.mget(1)
|
||||||
|
assert(false, "KeyError expected")
|
||||||
|
except KeyError:
|
||||||
|
discard
|
||||||
|
t.withKey(2) do (k: int, v: var int, pairExists: var bool):
|
||||||
|
pairExists = false
|
||||||
|
try:
|
||||||
|
discard t.mget(2)
|
||||||
|
assert(false, "KeyError expected")
|
||||||
|
except KeyError:
|
||||||
|
discard
|
||||||
|
|
||||||
proc orderedTableSortTest() =
|
proc orderedTableSortTest() =
|
||||||
var t = initOrderedTable[string, int](2)
|
var t = initOrderedTable[string, int](2)
|
||||||
for key, val in items(data): t[key] = val
|
for key, val in items(data): t[key] = val
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue