mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Add withValue for immutable tables (#24825)
This change adds `withValue` templates for the `Table` type that are able to operate on immutable table values -- the existing implementation requires a `var`. This is needed for situations where performance is sensitive. There are two goals with my implementation: 1. Don't create a copy of the value in the table. That's why I need the `cursor` pragma. Otherwise, it would copy the value 2. Don't double calculate the hash. That's kind of intrinsic with this implementation. But the only way to achieve this without this PR is to first check `if key in table` then to read `table[key]` I brought this up in the discord and a few folks tried to come up with options that were as fast as this, but nothing quite matched the performance here. Thread starts here: https://discord.com/channels/371759389889003530/371759389889003532/1355206546966974584
This commit is contained in:
@@ -676,6 +676,68 @@ template withValue*[A, B](t: var Table[A, B], key: A,
|
||||
else:
|
||||
body2
|
||||
|
||||
template withValue*[A, B](t: Table[A, B], key: A,
|
||||
value, body1, body2: untyped) =
|
||||
## Retrieves the value at `t[key]` if it exists, assigns
|
||||
## it to the variable `value` and executes `body`
|
||||
runnableExamples:
|
||||
type
|
||||
User = object
|
||||
name: string
|
||||
|
||||
proc `=copy`(dest: var User, source: User) {.error.}
|
||||
|
||||
proc exec(t: Table[int, User]) =
|
||||
t.withValue(1, value):
|
||||
assert value.name == "Hello"
|
||||
do:
|
||||
doAssert false
|
||||
|
||||
var executedElseBranch = false
|
||||
t.withValue(521, value):
|
||||
doAssert false
|
||||
do:
|
||||
executedElseBranch = true
|
||||
assert executedElseBranch
|
||||
|
||||
var t = initTable[int, User]()
|
||||
t[1] = User(name: "Hello")
|
||||
t.exec()
|
||||
|
||||
mixin rawGet
|
||||
var hc: Hash
|
||||
var index = rawGet(t, key, hc)
|
||||
if index > 0:
|
||||
let value {.cursor, inject.} = t.data[index].val
|
||||
body1
|
||||
else:
|
||||
body2
|
||||
|
||||
template withValue*[A, B](t: Table[A, B], key: A,
|
||||
value, body: untyped) =
|
||||
## Retrieves the value at `t[key]` if it exists, assigns
|
||||
## it to the variable `value` and executes `body`
|
||||
runnableExamples:
|
||||
type
|
||||
User = object
|
||||
name: string
|
||||
|
||||
proc `=copy`(dest: var User, source: User) {.error.}
|
||||
|
||||
proc exec(t: Table[int, User]) =
|
||||
t.withValue(1, value):
|
||||
assert value.name == "Hello"
|
||||
|
||||
t.withValue(521, value):
|
||||
doAssert false
|
||||
|
||||
var t = initTable[int, User]()
|
||||
t[1] = User(name: "Hello")
|
||||
t.exec()
|
||||
|
||||
withValue(t, key, value, body):
|
||||
discard
|
||||
|
||||
|
||||
iterator pairs*[A, B](t: Table[A, B]): (A, B) =
|
||||
## Iterates over any `(key, value)` pair in the table `t`.
|
||||
|
||||
Reference in New Issue
Block a user