Update LRU directives (#217)
why: Clarify pre-conditions needed for `lruAppend()` to work properly. In a nutshell, it needs to be used in concert with `lruFetch()` or `lruUpdate()`.
This commit is contained in:
parent
a0c085a51f
commit
104132fd02
|
@ -79,20 +79,21 @@ template noKeyError(info: static[string]; code: untyped) =
|
||||||
|
|
||||||
proc shiftImpl[K,V](rq: var KeyedQueue[K,V]) =
|
proc shiftImpl[K,V](rq: var KeyedQueue[K,V]) =
|
||||||
## Expects: rq.tab.len != 0
|
## Expects: rq.tab.len != 0
|
||||||
|
assert rq.tab.len != 0 # debugging only
|
||||||
|
|
||||||
noKeyError("shiftImpl"):
|
noKeyError("shiftImpl"):
|
||||||
# Unqueue first item
|
# Unqueue first item
|
||||||
let item = rq.tab[rq.kFirst] # yes, crashes if `rq.tab.len == 0`
|
let item = rq.tab[rq.kFirst] # yes, crashes if `rq.tab.len == 0`
|
||||||
rq.tab.del(rq.kFirst)
|
rq.tab.del(rq.kFirst)
|
||||||
|
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
rq.kFirst.reset
|
rq.kFirst.reset
|
||||||
rq.kLast.reset
|
rq.kLast.reset
|
||||||
else:
|
else:
|
||||||
rq.kFirst = item.kNxt
|
rq.kFirst = item.kNxt
|
||||||
if rq.tab.len == 1:
|
if rq.tab.len == 1:
|
||||||
rq.tab[rq.kFirst].kNxt = rq.kFirst # node points to itself
|
rq.tab[rq.kFirst].kNxt = rq.kFirst # node points to itself
|
||||||
rq.tab[rq.kFirst].kPrv = rq.tab[rq.kFirst].kNxt # term node has: nxt == prv
|
rq.tab[rq.kFirst].kPrv = rq.tab[rq.kFirst].kNxt # term nd has: nxt == prv
|
||||||
|
|
||||||
|
|
||||||
proc popImpl[K,V](rq: var KeyedQueue[K,V]) =
|
proc popImpl[K,V](rq: var KeyedQueue[K,V]) =
|
||||||
|
@ -494,14 +495,28 @@ proc lruFetch*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[V,void] =
|
||||||
rq.tab[key].kPrv = rq.kLast
|
rq.tab[key].kPrv = rq.kLast
|
||||||
rq.kLast = key
|
rq.kLast = key
|
||||||
rq.tab[key].kNxt = rq.tab[key].kPrv # term node: nxt == prv
|
rq.tab[key].kNxt = rq.tab[key].kPrv # term node: nxt == prv
|
||||||
|
|
||||||
return ok(item.data)
|
return ok(item.data)
|
||||||
|
|
||||||
|
proc lruUpdate*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
|
## Similar to `lruFetch()` with the difference that the item value is
|
||||||
|
## updated (i.e. set to `val`) if it is found on the queue. In that case,
|
||||||
|
## `true` is returned.
|
||||||
|
##
|
||||||
|
## Otherwise `false` is returned.
|
||||||
|
##
|
||||||
|
rq.tab.withValue(key, w):
|
||||||
|
w.data = val
|
||||||
|
discard rq.lruFetch key
|
||||||
|
return true
|
||||||
|
|
||||||
proc lruAppend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V; maxItems: int): V =
|
proc lruAppend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V; maxItems: int): V =
|
||||||
## Append in *last-recently-used* mode: If the queue has at least `maxItems`
|
## Append in *last-recently-used* mode: If the queue has at least `maxItems`
|
||||||
## item entries, do `shift()` out the *left-most* one. Then `append()` the
|
## item entries, do `shift()` out the *left-most* one. Then `append()` the
|
||||||
## key-value argument pair `(key,val)` to the *right end*. Together with
|
## key-value argument pair `(key,val)` to the *right end*. Together with
|
||||||
## `lruFetch()` this function can be used to build a *LRU cache*:
|
## `lruFetch()` (or `lruUpdate()`) this function can be used to implement
|
||||||
|
## an *LRU cache*.
|
||||||
|
##
|
||||||
|
## Example:
|
||||||
## ::
|
## ::
|
||||||
## const queueMax = 10
|
## const queueMax = 10
|
||||||
##
|
##
|
||||||
|
@ -519,6 +534,15 @@ proc lruAppend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V; maxItems: int): V
|
||||||
## return ok(q.lruAppend(key, rc.value, queueMax))
|
## return ok(q.lruAppend(key, rc.value, queueMax))
|
||||||
## err()
|
## err()
|
||||||
##
|
##
|
||||||
|
## Caveat:
|
||||||
|
## This fuction must always be used in combination with `lruFetch()` or
|
||||||
|
## `lruUpdate()` while making sure that there exists no key `key` on the
|
||||||
|
## queue. This function might throw an exception if this is violated.
|
||||||
|
##
|
||||||
|
# Make sure that there is no such key. Otherwise the optimised `appendImpl()`
|
||||||
|
# function might garble the list of links.
|
||||||
|
doAssert not rq.tab.hasKey key
|
||||||
|
|
||||||
# Limit number of cached items
|
# Limit number of cached items
|
||||||
try:
|
try:
|
||||||
if maxItems <= rq.tab.len:
|
if maxItems <= rq.tab.len:
|
||||||
|
|
Loading…
Reference in New Issue