Merge pull request #2139 from c-blake/devel

Add mgetOrPut to support just one probe chase for the common
This commit is contained in:
Andreas Rumpf 2015-02-18 15:56:23 +01:00
commit 358d4b958c
3 changed files with 69 additions and 23 deletions

View file

@ -231,31 +231,42 @@ template addImpl() {.dirty.} =
rawInsert(t, t.data, key, val, hc, j) rawInsert(t, t.data, key, val, hc, j)
inc(t.counter) inc(t.counter)
template maybeRehashPutImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter):
enlarge(t)
index = rawGetKnownHC(t, key, hc)
index = -1 - index # important to transform for mgetOrPutImpl
rawInsert(t, t.data, key, val, hc, index)
inc(t.counter)
template putImpl() {.dirty.} = template putImpl() {.dirty.} =
var hc: THash var hc: THash
var index = rawGet(t, key, hc) var index = rawGet(t, key, hc)
if index >= 0: if index >= 0: t.data[index].val = val
t.data[index].val = val else: maybeRehashPutImpl()
else:
if mustRehash(len(t.data), t.counter):
enlarge(t)
index = rawGetKnownHC(t, key, hc)
rawInsert(t, t.data, key, val, hc, -1 - index)
inc(t.counter)
when false: template mgetOrPutImpl() {.dirty.} =
# not yet used: var hc: THash
template hasKeyOrPutImpl() {.dirty.} = var index = rawGet(t, key, hc)
var hc: THash if index < 0: maybeRehashPutImpl() # not present: insert (flipping index)
var index = rawGet(t, key, hc) result = t.data[index].val # either way return modifiable val
if index >= 0:
t.data[index].val = val template hasKeyOrPutImpl() {.dirty.} =
result = true var hc: THash
else: var index = rawGet(t, key, hc)
if mustRehash(len(t.data), t.counter): enlarge(t) if index < 0:
rawInsert(t, t.data, key, val) result = false
inc(t.counter) maybeRehashPutImpl()
result = false else: result = true
proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
## returning a value which can be modified.
mgetOrPutImpl()
proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
## returns true iff `key` is in the table, otherwise inserts `value`.
hasKeyOrPutImpl()
proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
## puts a (key, value)-pair into `t`. ## puts a (key, value)-pair into `t`.
@ -383,6 +394,15 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B =
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
t[].mget(key) t[].mget(key)
proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
## returning a value which can be modified.
t[].mgetOrPut(key, val)
proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
## returns true iff `key` is in the table, otherwise inserts `value`.
t[].hasKeyOrPut(key, val)
proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = t[].hasKey(key) result = t[].hasKey(key)
@ -539,6 +559,15 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
addImpl() addImpl()
proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
## retrieves value at ``t[key]`` or puts ``value`` if not present, either way
## returning a value which can be modified.
mgetOrPutImpl()
proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
## returns true iff `key` is in the table, otherwise inserts `value`.
hasKeyOrPutImpl()
proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] = proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
## creates a new ordered hash table that is empty. ## creates a new ordered hash table that is empty.
## ##
@ -658,6 +687,15 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B =
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
result = t[].mget(key) result = t[].mget(key)
proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
## retrieves value at ``t[key]`` or puts ``val`` if not present, either way
## returning a value which can be modified.
result = t[].mgetOrPut(key, val)
proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
## returns true iff `key` is in the table, otherwise inserts `val`.
result = t[].hasKeyOrPut(key, val)
proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
## returns true iff `key` is in the table `t`. ## returns true iff `key` is in the table `t`.
result = t[].hasKey(key) result = t[].hasKey(key)

View file

@ -66,6 +66,14 @@ block tableTest2:
for key, val in items(data): t[key] = val.toFloat for key, val in items(data): t[key] = val.toFloat
for key, val in items(data): assert t[key] == val.toFloat for key, val in items(data): assert t[key] == val.toFloat
assert(not t.hasKeyOrPut("456", 4.0)) # test absent key
assert t.hasKeyOrPut("012", 3.0) # test present key
var x = t.mgetOrPut("111", 1.5) # test absent key
x = x * 2
assert x == 3.0
x = t.mgetOrPut("test", 1.5) # test present key
x = x * 2
assert x == 2 * 1.2345
block orderedTableTest1: block orderedTableTest1:
var t = initOrderedTable[string, int](2) var t = initOrderedTable[string, int](2)

View file

@ -47,7 +47,7 @@ block tableTest1:
for y in 0..1: for y in 0..1:
assert t[(x,y)] == $x & $y assert t[(x,y)] == $x & $y
assert($t == assert($t ==
"{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}")
block tableTest2: block tableTest2:
var t = newTable[string, float]() var t = newTable[string, float]()