request. This can be conceived as an alternate, more capable resolution of https://github.com/nim-lang/Nim/issues/12200 than https://github.com/nim-lang/Nim/pull/12208 The code re-org idea here is to upgrade tablimpl.nim:`delImpl`/`delImplIdx` to abstract client code conventions for cell emptiness & cell hashing via three new template arguments - `makeEmpty`, `cellEmpty`, `cellHash` which all take a single integer argument and clear a cell, test if clear or produce the hash of the key stored at that index in `.data[]`. Then we update the 3 call sites (`Table`, `CountTable`, `SharedTable`) of `delImpl`/`delImplIdx` by defining define those arguments just before the first invocation as non-exported templates. Because `CountTable` does not save hash() outputs as `.hcode`, it needs a new tableimpl.nim:`delImplNoHCode` which simply in-lines the hash search when no `.hcode` field is available for "prefix compare" acceleration. It is conceivable this new template could be used by future variants, such as one optimized for integer keys where `hash()` and `==` are fast and `.hcode` is both wasted space & time (though a small change to interfaces there for a sentinel key meaning "empty" is needed for maximum efficiency). We also eliminate the old O(n) `proc remove(CountTable...)` in favor of simply invoking the new `delImpl*` templates and take care to correctly handle the case where `val` is either zero for non-existent keys in `inc` or evolves to zero over time in `[]=` or `inc`. The only user-visible changes from the +-42 delta here are speed, iteration order post deletes, and relaxing the `Positive` constraint on `val` in `proc inc` again, as indicated in the `changelog.md` entry.
This commit is contained in:
parent
86c9b78339
commit
b2a1944587
4 changed files with 42 additions and 42 deletions
|
|
@ -138,6 +138,10 @@ proc hasKeyOrPut*[A, B](t: var SharedTable[A, B], key: A, val: B): bool =
|
|||
withLock t:
|
||||
hasKeyOrPutImpl(enlarge)
|
||||
|
||||
template tabMakeEmpty(i) = t.data[i].hcode = 0
|
||||
template tabCellEmpty(i) = isEmpty(t.data[i].hcode)
|
||||
template tabCellHash(i) = t.data[i].hcode
|
||||
|
||||
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``
|
||||
|
|
@ -179,7 +183,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A,
|
|||
if pairExists:
|
||||
mapper(t.data[index].key, t.data[index].val, pairExists)
|
||||
if not pairExists:
|
||||
delImplIdx(t, index)
|
||||
delImplIdx(t, index, tabMakeEmpty, tabCellEmpty, tabCellHash)
|
||||
else:
|
||||
var val: B
|
||||
mapper(key, val, pairExists)
|
||||
|
|
@ -200,7 +204,7 @@ proc add*[A, B](t: var SharedTable[A, B], key: A, val: B) =
|
|||
proc del*[A, B](t: var SharedTable[A, B], key: A) =
|
||||
## deletes `key` from hash table `t`.
|
||||
withLock t:
|
||||
delImpl()
|
||||
delImpl(tabMakeEmpty, tabCellEmpty, tabCellHash)
|
||||
|
||||
proc len*[A, B](t: var SharedTable[A, B]): int =
|
||||
## number of elements in `t`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue