Refactor lruFetch() item rotation (#112)
* Re-route KeyError exceptions as Defect for all except the `[]` function why: Access via key is verified, error is returned via Result[] * Refactor lruFetch() item rotation why: Previously, the item was deleted and re-inserted in the table although for rotation, only the queue links need to be updated. * Delete some KeyError annotations why: Was overlooked earlier * More KeyError fixes
This commit is contained in:
parent
cdb1f213d0
commit
779ba052c8
|
@ -29,6 +29,8 @@ import
|
||||||
export
|
export
|
||||||
results
|
results
|
||||||
|
|
||||||
|
{.push raises: [Defect].}
|
||||||
|
|
||||||
type
|
type
|
||||||
KeyedQueueItem*[K,V] = object ##\
|
KeyedQueueItem*[K,V] = object ##\
|
||||||
## Data value container as stored in the queue.
|
## Data value container as stored in the queue.
|
||||||
|
@ -61,16 +63,24 @@ type
|
||||||
## Key-only queue, no values
|
## Key-only queue, no values
|
||||||
KeyedQueue[K,BlindValue]
|
KeyedQueue[K,BlindValue]
|
||||||
|
|
||||||
{.push raises: [Defect].}
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private helpers
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template noKeyError(info: static[string]; code: untyped) =
|
||||||
|
try:
|
||||||
|
code
|
||||||
|
except KeyError as e:
|
||||||
|
raiseAssert "Not possible (" & info & "): " & e.msg
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Private functions
|
# Private functions
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc shiftImpl[K,V](rq: var KeyedQueue[K,V])
|
proc shiftImpl[K,V](rq: var KeyedQueue[K,V]) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Expects: rq.tab.len != 0
|
## Expects: rq.tab.len != 0
|
||||||
|
|
||||||
|
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)
|
||||||
|
@ -85,11 +95,11 @@ proc shiftImpl[K,V](rq: var KeyedQueue[K,V])
|
||||||
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 node has: nxt == prv
|
||||||
|
|
||||||
|
|
||||||
proc popImpl[K,V](rq: var KeyedQueue[K,V])
|
proc popImpl[K,V](rq: var KeyedQueue[K,V]) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Expects: rq.tab.len != 0
|
## Expects: rq.tab.len != 0
|
||||||
|
|
||||||
# Pop last item
|
# Pop last item
|
||||||
|
noKeyError("popImpl"):
|
||||||
let item = rq.tab[rq.kLast] # yes, crashes if `rq.tab.len == 0`
|
let item = rq.tab[rq.kLast] # yes, crashes if `rq.tab.len == 0`
|
||||||
rq.tab.del(rq.kLast)
|
rq.tab.del(rq.kLast)
|
||||||
|
|
||||||
|
@ -103,8 +113,7 @@ proc popImpl[K,V](rq: var KeyedQueue[K,V])
|
||||||
rq.tab[rq.kLast].kNxt = rq.tab[rq.kLast].kPrv # term node has: nxt == prv
|
rq.tab[rq.kLast].kNxt = rq.tab[rq.kLast].kPrv # term node has: nxt == prv
|
||||||
|
|
||||||
|
|
||||||
proc deleteImpl[K,V](rq: var KeyedQueue[K,V]; key: K)
|
proc deleteImpl[K,V](rq: var KeyedQueue[K,V]; key: K) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Expects: rq.tab.hesKey(key)
|
## Expects: rq.tab.hesKey(key)
|
||||||
|
|
||||||
if rq.kFirst == key:
|
if rq.kFirst == key:
|
||||||
|
@ -114,6 +123,7 @@ proc deleteImpl[K,V](rq: var KeyedQueue[K,V]; key: K)
|
||||||
rq.popImpl
|
rq.popImpl
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
noKeyError("deleteImpl"):
|
||||||
let item = rq.tab[key] # yes, crashes if `not rq.tab.hasKey(key)`
|
let item = rq.tab[key] # yes, crashes if `not rq.tab.hasKey(key)`
|
||||||
rq.tab.del(key)
|
rq.tab.del(key)
|
||||||
|
|
||||||
|
@ -129,13 +139,13 @@ proc deleteImpl[K,V](rq: var KeyedQueue[K,V]; key: K)
|
||||||
rq.tab[item.kNxt].kPrv = item.kPrv
|
rq.tab[item.kNxt].kPrv = item.kPrv
|
||||||
|
|
||||||
|
|
||||||
proc appendImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
proc appendImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Expects: not rq.tab.hasKey(key)
|
## Expects: not rq.tab.hasKey(key)
|
||||||
|
|
||||||
# Append queue item
|
# Append queue item
|
||||||
var item = KeyedQueueItem[K,V](data: val)
|
var item = KeyedQueueItem[K,V](data: val)
|
||||||
|
|
||||||
|
noKeyError("appendImpl"):
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
rq.kFirst = key
|
rq.kFirst = key
|
||||||
item.kPrv = key
|
item.kPrv = key
|
||||||
|
@ -151,13 +161,13 @@ proc appendImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
||||||
rq.tab[key] = item # yes, makes `verify()` fail if `rq.tab.hasKey(key)`
|
rq.tab[key] = item # yes, makes `verify()` fail if `rq.tab.hasKey(key)`
|
||||||
|
|
||||||
|
|
||||||
proc prependImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
proc prependImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Expects: not rq.tab.hasKey(key)
|
## Expects: not rq.tab.hasKey(key)
|
||||||
|
|
||||||
# Prepend queue item
|
# Prepend queue item
|
||||||
var item = KeyedQueueItem[K,V](data: val)
|
var item = KeyedQueueItem[K,V](data: val)
|
||||||
|
|
||||||
|
noKeyError("prependImpl"):
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
rq.kLast = key
|
rq.kLast = key
|
||||||
item.kNxt = key
|
item.kNxt = key
|
||||||
|
@ -174,16 +184,16 @@ proc prependImpl[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
||||||
|
|
||||||
# -----------
|
# -----------
|
||||||
|
|
||||||
proc shiftKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc shiftKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
noKeyError("shiftKeyImpl"):
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
let key = rq.kFirst
|
let key = rq.kFirst
|
||||||
rq.shiftImpl
|
rq.shiftImpl
|
||||||
return ok(key)
|
return ok(key)
|
||||||
err()
|
err()
|
||||||
|
|
||||||
proc popKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc popKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
noKeyError("popKeyImpl"):
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
let key = rq.kLast
|
let key = rq.kLast
|
||||||
rq.popImpl
|
rq.popImpl
|
||||||
|
@ -197,34 +207,34 @@ proc firstKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
return err()
|
return err()
|
||||||
ok(rq.kFirst)
|
ok(rq.kFirst)
|
||||||
|
|
||||||
proc secondKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc secondKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.kFirst].kNxt)
|
noKeyError("secondKeyImpl"):
|
||||||
|
return ok(rq.tab[rq.kFirst].kNxt)
|
||||||
|
|
||||||
proc beforeLastKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc beforeLastKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.kLast].kPrv)
|
noKeyError("lastKeyImpl"):
|
||||||
|
return ok(rq.tab[rq.kLast].kPrv)
|
||||||
|
|
||||||
proc lastKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
proc lastKeyImpl[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.kLast)
|
ok(rq.kLast)
|
||||||
|
|
||||||
proc nextKeyImpl[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
proc nextKeyImpl[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
if not rq.tab.hasKey(key) or rq.kLast == key:
|
if not rq.tab.hasKey(key) or rq.kLast == key:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[key].kNxt)
|
noKeyError("nextKeyImpl"):
|
||||||
|
return ok(rq.tab[key].kNxt)
|
||||||
|
|
||||||
proc prevKeyImpl[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
proc prevKeyImpl[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
if not rq.tab.hasKey(key) or rq.kFirst == key:
|
if not rq.tab.hasKey(key) or rq.kFirst == key:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[key].kPrv)
|
noKeyError("prevKeyImpl"):
|
||||||
|
return ok(rq.tab[key].kPrv)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions, constructor
|
# Public functions, constructor
|
||||||
|
@ -251,8 +261,7 @@ proc init*[K](T: type KeyedQueueNV[K]; initSize = 10): T =
|
||||||
# Public functions, list operations
|
# Public functions, list operations
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc append*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool
|
proc append*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Append new `key`. The function will succeed returning `true` unless the
|
## Append new `key`. The function will succeed returning `true` unless the
|
||||||
## `key` argument exists in the queue, already.
|
## `key` argument exists in the queue, already.
|
||||||
##
|
##
|
||||||
|
@ -268,16 +277,15 @@ template push*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
rq.append(key, val)
|
rq.append(key, val)
|
||||||
|
|
||||||
|
|
||||||
proc replace*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool
|
proc replace*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Replace value for entry associated with the key argument `key`. Returns
|
## Replace value for entry associated with the key argument `key`. Returns
|
||||||
## `true` on success, and `false` otherwise.
|
## `true` on success, and `false` otherwise.
|
||||||
if rq.tab.hasKey(key):
|
if rq.tab.hasKey(key):
|
||||||
|
noKeyError("replace"):
|
||||||
rq.tab[key].data = val
|
rq.tab[key].data = val
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc `[]=`*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
proc `[]=`*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V) =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## This function provides a combined append/replace action with table
|
## This function provides a combined append/replace action with table
|
||||||
## semantics:
|
## semantics:
|
||||||
## * If the argument `key` is not in the queue yet, append the `(key,val)`
|
## * If the argument `key` is not in the queue yet, append the `(key,val)`
|
||||||
|
@ -285,13 +293,13 @@ proc `[]=`*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V)
|
||||||
## * Otherwise replace the value entry of the queue item by the argument
|
## * Otherwise replace the value entry of the queue item by the argument
|
||||||
## `val` as in `rq.replace(key,val)`
|
## `val` as in `rq.replace(key,val)`
|
||||||
if rq.tab.hasKey(key):
|
if rq.tab.hasKey(key):
|
||||||
|
noKeyError("[]="):
|
||||||
rq.tab[key].data = val
|
rq.tab[key].data = val
|
||||||
else:
|
else:
|
||||||
rq.appendImpl(key, val)
|
rq.appendImpl(key, val)
|
||||||
|
|
||||||
|
|
||||||
proc prepend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool
|
proc prepend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Prepend new `key`. The function will succeed returning `true` unless the
|
## Prepend new `key`. The function will succeed returning `true` unless the
|
||||||
## `key` argument exists in the queue, already.
|
## `key` argument exists in the queue, already.
|
||||||
##
|
##
|
||||||
|
@ -307,8 +315,7 @@ template unshift*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V): bool =
|
||||||
rq.prepend(key,val)
|
rq.prepend(key,val)
|
||||||
|
|
||||||
|
|
||||||
proc shift*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
proc shift*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Deletes the *first* queue item and returns the key-value item pair just
|
## Deletes the *first* queue item and returns the key-value item pair just
|
||||||
## deleted. For a non-empty queue this function is the same as
|
## deleted. For a non-empty queue this function is the same as
|
||||||
## `rq.firstKey.value.delele`.
|
## `rq.firstKey.value.delele`.
|
||||||
|
@ -316,6 +323,7 @@ proc shift*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## item returned and deleted is the *left-most* item.
|
## item returned and deleted is the *left-most* item.
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
|
noKeyError("shift"):
|
||||||
let kvp = KeyedQueuePair[K,V](
|
let kvp = KeyedQueuePair[K,V](
|
||||||
key: rq.kFirst,
|
key: rq.kFirst,
|
||||||
data: rq.tab[rq.kFirst].data)
|
data: rq.tab[rq.kFirst].data)
|
||||||
|
@ -323,23 +331,21 @@ proc shift*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
||||||
return ok(KeyedQueuePair[K,V](kvp))
|
return ok(KeyedQueuePair[K,V](kvp))
|
||||||
err()
|
err()
|
||||||
|
|
||||||
proc shiftKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc shiftKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `shift()` but with different return value.
|
## Similar to `shift()` but with different return value.
|
||||||
rq.shiftKeyImpl
|
rq.shiftKeyImpl
|
||||||
|
|
||||||
proc shiftValue*[K,V](rq: var KeyedQueue[K,V]):
|
proc shiftValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
Result[V,void] {.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `shift()` but with different return value.
|
## Similar to `shift()` but with different return value.
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
|
noKeyError("shiftValue"):
|
||||||
let val = rq.tab[rq.kFirst].data
|
let val = rq.tab[rq.kFirst].data
|
||||||
rq.shiftImpl
|
rq.shiftImpl
|
||||||
return ok(val)
|
return ok(val)
|
||||||
err()
|
err()
|
||||||
|
|
||||||
|
|
||||||
proc pop*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
proc pop*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Deletes the *last* queue item and returns the key-value item pair just
|
## Deletes the *last* queue item and returns the key-value item pair just
|
||||||
## deleted. For a non-empty queue this function is the same as
|
## deleted. For a non-empty queue this function is the same as
|
||||||
## `rq.lastKey.value.delele`.
|
## `rq.lastKey.value.delele`.
|
||||||
|
@ -347,6 +353,7 @@ proc pop*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## item returned and deleted is the *right-most* item.
|
## item returned and deleted is the *right-most* item.
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
|
noKeyError("pop"):
|
||||||
let kvp = KeyedQueuePair[K,V](
|
let kvp = KeyedQueuePair[K,V](
|
||||||
key: rq.kLast,
|
key: rq.kLast,
|
||||||
data: rq.tab[rq.kLast].data)
|
data: rq.tab[rq.kLast].data)
|
||||||
|
@ -354,15 +361,14 @@ proc pop*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void]
|
||||||
return ok(KeyedQueuePair[K,V](kvp))
|
return ok(KeyedQueuePair[K,V](kvp))
|
||||||
err()
|
err()
|
||||||
|
|
||||||
proc popKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc popKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `pop()` but with different return value.
|
## Similar to `pop()` but with different return value.
|
||||||
rq.popKeyImpl
|
rq.popKeyImpl
|
||||||
|
|
||||||
proc popValue*[K,V](rq: var KeyedQueue[K,V]):
|
proc popValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
Result[V,void] {.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `pop()` but with different return value.
|
## Similar to `pop()` but with different return value.
|
||||||
if 0 < rq.tab.len:
|
if 0 < rq.tab.len:
|
||||||
|
noKeyError("popValue"):
|
||||||
let val = rq.tab[rq.kLast].data
|
let val = rq.tab[rq.kLast].data
|
||||||
rq.popImpl
|
rq.popImpl
|
||||||
return ok(val)
|
return ok(val)
|
||||||
|
@ -384,16 +390,14 @@ proc delete*[K,V](rq: var KeyedQueue[K,V]; key: K):
|
||||||
raiseAssert "We've checked that the key is present above"
|
raiseAssert "We've checked that the key is present above"
|
||||||
err()
|
err()
|
||||||
|
|
||||||
proc del*[K,V](rq: var KeyedQueue[K,V]; key: K)
|
proc del*[K,V](rq: var KeyedQueue[K,V]; key: K) =
|
||||||
{.gcsafe,raises: [Defect, KeyError].} =
|
|
||||||
## Similar to `delete()` but without return code.
|
## Similar to `delete()` but without return code.
|
||||||
if rq.tab.hasKey(key):
|
if rq.tab.hasKey(key):
|
||||||
rq.deleteImpl(key)
|
rq.deleteImpl(key)
|
||||||
|
|
||||||
# --------
|
# --------
|
||||||
|
|
||||||
proc append*[K](rq: var KeyedQueueNV[K]; key: K): bool
|
proc append*[K](rq: var KeyedQueueNV[K]; key: K): bool =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.append(key,BlindValue(0))
|
rq.append(key,BlindValue(0))
|
||||||
|
|
||||||
|
@ -402,8 +406,7 @@ template push*[K](rq: var KeyedQueueNV[K]; key: K): bool =
|
||||||
rq.append(key)
|
rq.append(key)
|
||||||
|
|
||||||
|
|
||||||
proc prepend*[K](rq: var KeyedQueueNV[K]; key: K): bool
|
proc prepend*[K](rq: var KeyedQueueNV[K]; key: K): bool =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.prepend(key,BlindValue(0))
|
rq.prepend(key,BlindValue(0))
|
||||||
|
|
||||||
|
@ -412,27 +415,21 @@ template unshift*[K](rq: var KeyedQueueNV[K]; key: K): bool =
|
||||||
rq.prepend(key)
|
rq.prepend(key)
|
||||||
|
|
||||||
|
|
||||||
proc shift*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc shift*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.shiftKeyImpl
|
rq.shiftKeyImpl
|
||||||
|
|
||||||
proc shiftKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc shiftKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use shift() for key-only queue".} =
|
||||||
deprecated: "use shift() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.shiftKeyImpl
|
rq.shiftKeyImpl
|
||||||
|
|
||||||
|
|
||||||
proc pop*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc pop*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only variant of `pop()` (same as `popKey()`)
|
## Key-only variant of `pop()` (same as `popKey()`)
|
||||||
rq.popKeyImpl
|
rq.popKeyImpl
|
||||||
|
|
||||||
proc popKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc popKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use pop() for key-only queue".} =
|
||||||
deprecated: "use pop() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.popKeyImpl
|
rq.popKeyImpl
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -443,14 +440,13 @@ proc hasKey*[K,V](rq: var KeyedQueue[K,V]; key: K): bool =
|
||||||
## Check whether the argument `key` has been queued, already
|
## Check whether the argument `key` has been queued, already
|
||||||
rq.tab.hasKey(key)
|
rq.tab.hasKey(key)
|
||||||
|
|
||||||
|
proc eq*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[V,void] =
|
||||||
proc eq*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[V,void]
|
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the value data stored with the argument `key` from
|
## Retrieve the value data stored with the argument `key` from
|
||||||
## the queue if there is any.
|
## the queue if there is any.
|
||||||
if not rq.tab.hasKey(key):
|
if not rq.tab.hasKey(key):
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[key].data)
|
noKeyError("eq"):
|
||||||
|
return ok(rq.tab[key].data)
|
||||||
|
|
||||||
proc `[]`*[K,V](rq: var KeyedQueue[K,V]; key: K): V
|
proc `[]`*[K,V](rq: var KeyedQueue[K,V]; key: K): V
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
{.gcsafe,raises: [Defect,KeyError].} =
|
||||||
|
@ -467,17 +463,33 @@ proc lruFetch*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[V,void] =
|
||||||
## Fetch in *last-recently-used* mode: If the argument `key` exists in the
|
## Fetch in *last-recently-used* mode: If the argument `key` exists in the
|
||||||
## queue, move the key-value item pair to the *right end* (see `append()`)
|
## queue, move the key-value item pair to the *right end* (see `append()`)
|
||||||
## of the queue and return the value associated with the key.
|
## of the queue and return the value associated with the key.
|
||||||
let rc = rq.delete(key)
|
if not rq.tab.hasKey(key):
|
||||||
if rc.isErr:
|
|
||||||
return err()
|
return err()
|
||||||
|
|
||||||
# Unlink and re-append item
|
noKeyError("lruFetch"):
|
||||||
try:
|
let item = rq.tab[key]
|
||||||
rq.appendImpl(key, rc.value.data)
|
if rq.kLast != key:
|
||||||
except KeyError:
|
# Now, `key` is in the table and does not refer to the last `item`,
|
||||||
raiseAssert "Not possible"
|
# so the table has at least two entries.
|
||||||
|
|
||||||
ok(rc.value.data)
|
# unlink item
|
||||||
|
if rq.kFirst == key:
|
||||||
|
rq.kFirst = item.kNxt
|
||||||
|
rq.tab[rq.kFirst].kPrv = rq.tab[rq.kFirst].kNxt # term node: nxt == prv
|
||||||
|
|
||||||
|
else: # Now, there are at least three entries
|
||||||
|
if rq.tab[rq.kFirst].kNxt == key:
|
||||||
|
rq.tab[rq.kFirst].kPrv = item.kNxt # item was the 2nd one
|
||||||
|
rq.tab[item.kPrv].kNxt = item.kNxt
|
||||||
|
rq.tab[item.kNxt].kPrv = item.kPrv
|
||||||
|
|
||||||
|
# Re-append item, i.e. appendImpl() without adding item.
|
||||||
|
rq.tab[rq.kLast].kNxt = key
|
||||||
|
rq.tab[key].kPrv = rq.kLast
|
||||||
|
rq.kLast = key
|
||||||
|
rq.tab[key].kNxt = rq.tab[key].kPrv # term node: nxt == prv
|
||||||
|
|
||||||
|
return ok(item.data)
|
||||||
|
|
||||||
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`
|
||||||
|
@ -515,40 +527,35 @@ proc lruAppend*[K,V](rq: var KeyedQueue[K,V]; key: K; val: V; maxItems: int): V
|
||||||
# Public traversal functions, fetch keys
|
# Public traversal functions, fetch keys
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc firstKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc firstKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe.} =
|
|
||||||
## Retrieve first key from the queue unless it is empty.
|
## Retrieve first key from the queue unless it is empty.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## key returned is the *left-most* one.
|
## key returned is the *left-most* one.
|
||||||
rq.firstKeyImpl
|
rq.firstKeyImpl
|
||||||
|
|
||||||
proc secondKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc secondKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the key next after the first key from queue unless it is empty.
|
## Retrieve the key next after the first key from queue unless it is empty.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## key returned is the one ti the right of the *left-most* one.
|
## key returned is the one ti the right of the *left-most* one.
|
||||||
rq.secondKeyImpl
|
rq.secondKeyImpl
|
||||||
|
|
||||||
proc beforeLastKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc beforeLastKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the key just before the last one from queue unless it is empty.
|
## Retrieve the key just before the last one from queue unless it is empty.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## key returned is the one to the left of the *right-most* one.
|
## key returned is the one to the left of the *right-most* one.
|
||||||
rq.beforeLastKeyImpl
|
rq.beforeLastKeyImpl
|
||||||
|
|
||||||
proc lastKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void]
|
proc lastKey*[K,V](rq: var KeyedQueue[K,V]): Result[K,void] =
|
||||||
{.inline,gcsafe.} =
|
|
||||||
## Retrieve last key from queue unless it is empty.
|
## Retrieve last key from queue unless it is empty.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## key returned is the *right-most* one.
|
## key returned is the *right-most* one.
|
||||||
rq.lastKeyImpl
|
rq.lastKeyImpl
|
||||||
|
|
||||||
proc nextKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
proc nextKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the key following the argument `key` from queue if
|
## Retrieve the key following the argument `key` from queue if
|
||||||
## there is any.
|
## there is any.
|
||||||
##
|
##
|
||||||
|
@ -556,8 +563,7 @@ proc nextKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
||||||
## key returned is the next one to the *right*.
|
## key returned is the next one to the *right*.
|
||||||
rq.nextKeyImpl(key)
|
rq.nextKeyImpl(key)
|
||||||
|
|
||||||
proc prevKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
proc prevKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the key preceeding the argument `key` from queue if
|
## Retrieve the key preceeding the argument `key` from queue if
|
||||||
## there is any.
|
## there is any.
|
||||||
##
|
##
|
||||||
|
@ -568,124 +574,107 @@ proc prevKey*[K,V](rq: var KeyedQueue[K,V]; key: K): Result[K,void]
|
||||||
# ----------
|
# ----------
|
||||||
|
|
||||||
proc firstKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc firstKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use first() for key-only queue".} =
|
||||||
deprecated: "use first() for key-only queue".} =
|
|
||||||
rq.firstKeyImpl
|
rq.firstKeyImpl
|
||||||
|
|
||||||
proc secondKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc secondKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use second() for key-only queue".} =
|
||||||
deprecated: "use second() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.secondKeyImpl
|
rq.secondKeyImpl
|
||||||
|
|
||||||
proc beforeLastKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc beforeLastKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use beforeLast() for key-only queue".} =
|
||||||
deprecated: "use beforeLast() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.beforeLastKeyImpl
|
rq.beforeLastKeyImpl
|
||||||
|
|
||||||
proc lastKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc lastKey*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use last() for key-only queue".} =
|
||||||
deprecated: "use last() for key-only queue".} =
|
|
||||||
rq.lastKeyImpl
|
rq.lastKeyImpl
|
||||||
|
|
||||||
proc nextKey*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
proc nextKey*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use next() for key-only queue".} =
|
||||||
deprecated: "use next() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.nextKeyImpl(key)
|
rq.nextKeyImpl(key)
|
||||||
|
|
||||||
proc prevKey*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
proc prevKey*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
||||||
{.inline,gcsafe,
|
{.gcsafe, deprecated: "use prev() for key-only queue".} =
|
||||||
deprecated: "use prev() for key-only queue",
|
|
||||||
raises: [Defect,KeyError].} =
|
|
||||||
rq.nextKeyImpl(key)
|
rq.nextKeyImpl(key)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public traversal functions, fetch key/value pairs
|
# Public traversal functions, fetch key/value pairs
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc first*[K,V](rq: var KeyedQueue[K,V]):
|
proc first*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void] =
|
||||||
Result[KeyedQueuePair[K,V],void]
|
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `firstKey()` but with key-value item pair return value.
|
## Similar to `firstKey()` but with key-value item pair return value.
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("first"):
|
||||||
let key = rq.kFirst
|
let key = rq.kFirst
|
||||||
ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
return ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
||||||
|
|
||||||
proc second*[K,V](rq: var KeyedQueue[K,V]):
|
proc second*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void] =
|
||||||
Result[KeyedQueuePair[K,V],void]
|
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `secondKey()` but with key-value item pair return value.
|
## Similar to `secondKey()` but with key-value item pair return value.
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("second"):
|
||||||
let key = rq.tab[rq.kFirst].kNxt
|
let key = rq.tab[rq.kFirst].kNxt
|
||||||
ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
return ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
||||||
|
|
||||||
proc beforeLast*[K,V](rq: var KeyedQueue[K,V]):
|
proc beforeLast*[K,V](rq: var KeyedQueue[K,V]):
|
||||||
Result[KeyedQueuePair[K,V],void]
|
Result[KeyedQueuePair[K,V],void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `beforeLastKey()` but with key-value item pair return value.
|
## Similar to `beforeLastKey()` but with key-value item pair return value.
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("beforeLast"):
|
||||||
let key = rq.tab[rq.kLast].kPrv
|
let key = rq.tab[rq.kLast].kPrv
|
||||||
ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
return ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
||||||
|
|
||||||
proc last*[K,V](rq: var KeyedQueue[K,V]):
|
proc last*[K,V](rq: var KeyedQueue[K,V]): Result[KeyedQueuePair[K,V],void] =
|
||||||
Result[KeyedQueuePair[K,V],void]
|
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `lastKey()` but with key-value item pair return value.
|
## Similar to `lastKey()` but with key-value item pair return value.
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("last"):
|
||||||
let key = rq.kLast
|
let key = rq.kLast
|
||||||
ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
return ok(KeyedQueuePair[K,V](key: key, data: rq.tab[key].data))
|
||||||
|
|
||||||
proc next*[K,V](rq: var KeyedQueue[K,V]; key: K):
|
proc next*[K,V](rq: var KeyedQueue[K,V]; key: K):
|
||||||
Result[KeyedQueuePair[K,V],void]
|
Result[KeyedQueuePair[K,V],void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `nextKey()` but with key-value item pair return value.
|
## Similar to `nextKey()` but with key-value item pair return value.
|
||||||
if not rq.tab.hasKey(key) or rq.kLast == key:
|
if not rq.tab.hasKey(key) or rq.kLast == key:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("next"):
|
||||||
let nKey = rq.tab[key].kNxt
|
let nKey = rq.tab[key].kNxt
|
||||||
ok(KeyedQueuePair[K,V](key: nKey, data: rq.tab[nKey].data))
|
return ok(KeyedQueuePair[K,V](key: nKey, data: rq.tab[nKey].data))
|
||||||
|
|
||||||
proc prev*[K,V](rq: var KeyedQueue[K,V]; key: K):
|
proc prev*[K,V](rq: var KeyedQueue[K,V]; key: K):
|
||||||
Result[KeyedQueuePair[K,V],void]
|
Result[KeyedQueuePair[K,V],void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Similar to `prevKey()` but with key-value item pair return value.
|
## Similar to `prevKey()` but with key-value item pair return value.
|
||||||
if not rq.tab.hasKey(key) or rq.kFirst == key:
|
if not rq.tab.hasKey(key) or rq.kFirst == key:
|
||||||
return err()
|
return err()
|
||||||
|
noKeyError("prev"):
|
||||||
let pKey = rq.tab[key].kPrv
|
let pKey = rq.tab[key].kPrv
|
||||||
ok(KeyedQueuePair[K,V](key: pKey, data: rq.tab[pKey].data))
|
return ok(KeyedQueuePair[K,V](key: pKey, data: rq.tab[pKey].data))
|
||||||
|
|
||||||
# ------------
|
# ------------
|
||||||
|
|
||||||
proc first*[K](rq: var KeyedQueueNV[K]): Result[K,void] {.inline,gcsafe.} =
|
proc first*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.firstKeyImpl
|
rq.firstKeyImpl
|
||||||
|
|
||||||
proc second*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc second*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.secondKeyImpl
|
rq.secondKeyImpl
|
||||||
|
|
||||||
proc beforeLast*[K](rq: var KeyedQueueNV[K]): Result[K,void]
|
proc beforeLast*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.beforeLastKeyImpl
|
rq.beforeLastKeyImpl
|
||||||
|
|
||||||
proc last*[K](rq: var KeyedQueueNV[K]): Result[K,void] {.inline,gcsafe.} =
|
proc last*[K](rq: var KeyedQueueNV[K]): Result[K,void] =
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.lastKeyImpl
|
rq.lastKeyImpl
|
||||||
|
|
||||||
proc next*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
proc next*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.nextKeyImpl(key)
|
rq.nextKeyImpl(key)
|
||||||
|
|
||||||
proc prev*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
proc prev*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void] =
|
||||||
{.inline,gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Key-only queue variant
|
## Key-only queue variant
|
||||||
rq.nextKeyImpl(key)
|
rq.nextKeyImpl(key)
|
||||||
|
|
||||||
|
@ -693,18 +682,17 @@ proc prev*[K](rq: var KeyedQueueNV[K]; key: K): Result[K,void]
|
||||||
# Public traversal functions, data container items
|
# Public traversal functions, data container items
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc firstValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
proc firstValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve first value item from the queue unless it is empty.
|
## Retrieve first value item from the queue unless it is empty.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## value item returned is the *left-most* one.
|
## value item returned is the *left-most* one.
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.kFirst].data)
|
noKeyError("firstValue"):
|
||||||
|
return ok(rq.tab[rq.kFirst].data)
|
||||||
|
|
||||||
proc secondValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
proc secondValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the value item next to the first one from the queue unless it
|
## Retrieve the value item next to the first one from the queue unless it
|
||||||
## is empty.
|
## is empty.
|
||||||
##
|
##
|
||||||
|
@ -712,10 +700,10 @@ proc secondValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
||||||
## value item returned is the one to the *right* of the *left-most* one.
|
## value item returned is the one to the *right* of the *left-most* one.
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.tab[rq.kFirst].kNxt].data)
|
noKeyError("secondValue"):
|
||||||
|
return ok(rq.tab[rq.tab[rq.kFirst].kNxt].data)
|
||||||
|
|
||||||
proc beforeLastValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
proc beforeLastValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the value item just before the last item from the queue
|
## Retrieve the value item just before the last item from the queue
|
||||||
## unless it is empty.
|
## unless it is empty.
|
||||||
##
|
##
|
||||||
|
@ -723,45 +711,46 @@ proc beforeLastValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
||||||
## value item returned is the one to the *left* of the *right-most* one.
|
## value item returned is the one to the *left* of the *right-most* one.
|
||||||
if rq.tab.len < 2:
|
if rq.tab.len < 2:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.tab[rq.kLast].kPrv].data)
|
noKeyError("beforeLastValue"):
|
||||||
|
return ok(rq.tab[rq.tab[rq.kLast].kPrv].data)
|
||||||
|
|
||||||
proc lastValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void]
|
proc lastValue*[K,V](rq: var KeyedQueue[K,V]): Result[V,void] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Retrieve the last value item from the queue if there is any.
|
## Retrieve the last value item from the queue if there is any.
|
||||||
##
|
##
|
||||||
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
## Using the notation introduced with `rq.append` and `rq.prepend`, the
|
||||||
## value item returned is the *right-most* one.
|
## value item returned is the *right-most* one.
|
||||||
if rq.tab.len == 0:
|
if rq.tab.len == 0:
|
||||||
return err()
|
return err()
|
||||||
ok(rq.tab[rq.kLast].data)
|
noKeyError("lastValue"):
|
||||||
|
return ok(rq.tab[rq.kLast].data)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Public functions, miscellaneous
|
# Public functions, miscellaneous
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
proc `==`*[K,V](a, b: var KeyedQueue[K,V]): bool
|
proc `==`*[K,V](a, b: var KeyedQueue[K,V]): bool =
|
||||||
{.gcsafe, raises: [Defect,KeyError].} =
|
|
||||||
## Returns `true` if both argument queues contain the same data. Note that
|
## Returns `true` if both argument queues contain the same data. Note that
|
||||||
## this is a slow operation as all `(key,data)` pairs will to be compared.
|
## this is a slow operation as all `(key,data)` pairs will to be compared.
|
||||||
if a.tab.len == b.tab.len and a.kFirst == b.kFirst and a.kLast == b.kLast:
|
if a.tab.len == b.tab.len and a.kFirst == b.kFirst and a.kLast == b.kLast:
|
||||||
for (k,av) in a.tab.pairs:
|
for (k,av) in a.tab.pairs:
|
||||||
if not b.tab.hasKey(k):
|
if not b.tab.hasKey(k):
|
||||||
return false
|
return false
|
||||||
|
noKeyError("=="):
|
||||||
let bv = b.tab[k]
|
let bv = b.tab[k]
|
||||||
# bv.data might be a reference, so dive into it explicitely.
|
# bv.data might be a reference, so dive into it explicitely.
|
||||||
if av.kPrv != bv.kPrv or av.kNxt != bv.kNxt or bv.data != av.data:
|
if av.kPrv != bv.kPrv or av.kNxt != bv.kNxt or bv.data != av.data:
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc key*[K,V](kqp: KeyedQueuePair[K,V]): K {.inline.} =
|
proc key*[K,V](kqp: KeyedQueuePair[K,V]): K =
|
||||||
## Getter
|
## Getter
|
||||||
kqp.key
|
kqp.key
|
||||||
|
|
||||||
proc len*[K,V](rq: var KeyedQueue[K,V]): int {.inline.} =
|
proc len*[K,V](rq: var KeyedQueue[K,V]): int =
|
||||||
## Returns the number of items in the queue
|
## Returns the number of items in the queue
|
||||||
rq.tab.len
|
rq.tab.len
|
||||||
|
|
||||||
proc clear*[K,V](rq: var KeyedQueue[K,V]) {.inline.} =
|
proc clear*[K,V](rq: var KeyedQueue[K,V]) =
|
||||||
## Clear the queue
|
## Clear the queue
|
||||||
rq.tab.clear
|
rq.tab.clear
|
||||||
rq.kFirst.reset
|
rq.kFirst.reset
|
||||||
|
@ -776,8 +765,7 @@ proc toKeyedQueueResult*[K,V](key: K; data: V):
|
||||||
# Public iterators
|
# Public iterators
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
iterator nextKeys*[K,V](rq: var KeyedQueue[K,V]): K
|
iterator nextKeys*[K,V](rq: var KeyedQueue[K,V]): K =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Iterate over all keys in the queue starting with the `rq.firstKey.value`
|
## Iterate over all keys in the queue starting with the `rq.firstKey.value`
|
||||||
## key (if any). Using the notation introduced with `rq.append` and
|
## key (if any). Using the notation introduced with `rq.append` and
|
||||||
## `rq.prepend`, the iterator processes *left* to *right*.
|
## `rq.prepend`, the iterator processes *left* to *right*.
|
||||||
|
@ -793,11 +781,11 @@ iterator nextKeys*[K,V](rq: var KeyedQueue[K,V]): K
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let yKey = key
|
let yKey = key
|
||||||
loopOK = key != rq.kLast
|
loopOK = key != rq.kLast
|
||||||
|
noKeyError("nextKeys"):
|
||||||
key = rq.tab[key].kNxt
|
key = rq.tab[key].kNxt
|
||||||
yield yKey
|
yield yKey
|
||||||
|
|
||||||
iterator nextValues*[K,V](rq: var KeyedQueue[K,V]): V
|
iterator nextValues*[K,V](rq: var KeyedQueue[K,V]): V =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Iterate over all values in the queue starting with the
|
## Iterate over all values in the queue starting with the
|
||||||
## `rq.kFirst.value.value` item value (if any). Using the notation introduced
|
## `rq.kFirst.value.value` item value (if any). Using the notation introduced
|
||||||
## with `rq.append` and `rq.prepend`, the iterator processes *left* to
|
## with `rq.append` and `rq.prepend`, the iterator processes *left* to
|
||||||
|
@ -809,13 +797,14 @@ iterator nextValues*[K,V](rq: var KeyedQueue[K,V]): V
|
||||||
key = rq.kFirst
|
key = rq.kFirst
|
||||||
loopOK = true
|
loopOK = true
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let item = rq.tab[key]
|
var item: KeyedQueueItem[K,V]
|
||||||
|
noKeyError("nextValues"):
|
||||||
|
item = rq.tab[key]
|
||||||
loopOK = key != rq.kLast
|
loopOK = key != rq.kLast
|
||||||
key = item.kNxt
|
key = item.kNxt
|
||||||
yield item.data
|
yield item.data
|
||||||
|
|
||||||
iterator nextPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V]
|
iterator nextPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Iterate over all (key,value) pairs in the queue starting with the
|
## Iterate over all (key,value) pairs in the queue starting with the
|
||||||
## `(rq.firstKey.value,rq.first.value.value)` key/item pair (if any). Using
|
## `(rq.firstKey.value,rq.first.value.value)` key/item pair (if any). Using
|
||||||
## the notation introduced with `rq.append` and `rq.prepend`, the iterator
|
## the notation introduced with `rq.append` and `rq.prepend`, the iterator
|
||||||
|
@ -827,15 +816,15 @@ iterator nextPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V]
|
||||||
key = rq.kFirst
|
key = rq.kFirst
|
||||||
loopOK = true
|
loopOK = true
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let
|
let yKey = key
|
||||||
yKey = key
|
var item: KeyedQueueItem[K,V]
|
||||||
|
noKeyError("nextPairs"):
|
||||||
item = rq.tab[key]
|
item = rq.tab[key]
|
||||||
loopOK = key != rq.kLast
|
loopOK = key != rq.kLast
|
||||||
key = item.kNxt
|
key = item.kNxt
|
||||||
yield KeyedQueuePair[K,V](key: yKey, data: item.data)
|
yield KeyedQueuePair[K,V](key: yKey, data: item.data)
|
||||||
|
|
||||||
iterator prevKeys*[K,V](rq: var KeyedQueue[K,V]): K
|
iterator prevKeys*[K,V](rq: var KeyedQueue[K,V]): K =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Reverse iterate over all keys in the queue starting with the
|
## Reverse iterate over all keys in the queue starting with the
|
||||||
## `rq.lastKey.value` key (if any). Using the notation introduced with
|
## `rq.lastKey.value` key (if any). Using the notation introduced with
|
||||||
## `rq.append` and `rq.prepend`, the iterator processes *right* to *left*.
|
## `rq.append` and `rq.prepend`, the iterator processes *right* to *left*.
|
||||||
|
@ -848,11 +837,11 @@ iterator prevKeys*[K,V](rq: var KeyedQueue[K,V]): K
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let yKey = key
|
let yKey = key
|
||||||
loopOK = key != rq.kFirst
|
loopOK = key != rq.kFirst
|
||||||
|
noKeyError("prevKeys"):
|
||||||
key = rq.tab[key].kPrv
|
key = rq.tab[key].kPrv
|
||||||
yield yKey
|
yield yKey
|
||||||
|
|
||||||
iterator prevValues*[K,V](rq: var KeyedQueue[K,V]): V
|
iterator prevValues*[K,V](rq: var KeyedQueue[K,V]): V =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Reverse iterate over all values in the queue starting with the
|
## Reverse iterate over all values in the queue starting with the
|
||||||
## `rq.kLast.value.value` item value (if any). Using the notation introduced
|
## `rq.kLast.value.value` item value (if any). Using the notation introduced
|
||||||
## with `rq.append` and `rq.prepend`, the iterator processes *right* to
|
## with `rq.append` and `rq.prepend`, the iterator processes *right* to
|
||||||
|
@ -864,13 +853,14 @@ iterator prevValues*[K,V](rq: var KeyedQueue[K,V]): V
|
||||||
key = rq.kLast
|
key = rq.kLast
|
||||||
loopOK = true
|
loopOK = true
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let item = rq.tab[key]
|
var item: KeyedQueueItem[K,V]
|
||||||
|
noKeyError("prevValues"):
|
||||||
|
item = rq.tab[key]
|
||||||
loopOK = key != rq.kFirst
|
loopOK = key != rq.kFirst
|
||||||
key = item.kPrv
|
key = item.kPrv
|
||||||
yield item.data
|
yield item.data
|
||||||
|
|
||||||
iterator prevPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V]
|
iterator prevPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V] =
|
||||||
{.gcsafe,raises: [Defect,KeyError].} =
|
|
||||||
## Reverse iterate over all (key,value) pairs in the queue starting with the
|
## Reverse iterate over all (key,value) pairs in the queue starting with the
|
||||||
## `(rq.lastKey.value,rq.last.value.value)` key/item pair (if any). Using
|
## `(rq.lastKey.value,rq.last.value.value)` key/item pair (if any). Using
|
||||||
## the notation introduced with `rq.append` and `rq.prepend`, the iterator
|
## the notation introduced with `rq.append` and `rq.prepend`, the iterator
|
||||||
|
@ -882,8 +872,9 @@ iterator prevPairs*[K,V](rq: var KeyedQueue[K,V]): KeyedQueuePair[K,V]
|
||||||
key = rq.kLast
|
key = rq.kLast
|
||||||
loopOK = true
|
loopOK = true
|
||||||
while loopOK:
|
while loopOK:
|
||||||
let
|
let yKey = key
|
||||||
yKey = key
|
var item: KeyedQueueItem[K,V]
|
||||||
|
noKeyError("prevPairs"):
|
||||||
item = rq.tab[key]
|
item = rq.tab[key]
|
||||||
loopOK = key != rq.kFirst
|
loopOK = key != rq.kFirst
|
||||||
key = item.kPrv
|
key = item.kPrv
|
||||||
|
|
|
@ -95,6 +95,23 @@ proc verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
proc dumpLinkedKeys*[K,V](rq: var KeyedQueue[K,V]): string =
|
||||||
|
## Dump the linked key list. This function depends on the `$` operator
|
||||||
|
## for converting a `K` type into a string
|
||||||
|
if 0 < rq.tab.len:
|
||||||
|
var
|
||||||
|
key = rq.kFirst
|
||||||
|
loopOK = true
|
||||||
|
while loopOK:
|
||||||
|
let
|
||||||
|
yKey = key
|
||||||
|
item = rq.tab[key]
|
||||||
|
loopOK = key != rq.kLast
|
||||||
|
key = item.kNxt
|
||||||
|
if yKey != rq.kFirst:
|
||||||
|
result &= ","
|
||||||
|
result &= $yKey & "(" & $item.kPrv & "," & $item.kNxt & ")"
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# End
|
# End
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -94,8 +94,11 @@ proc lruValue(lru: var LruCache; n: int): uint =
|
||||||
key = n.toKey
|
key = n.toKey
|
||||||
rc = lru.q.lruFetch(key)
|
rc = lru.q.lruFetch(key)
|
||||||
if rc.isOk:
|
if rc.isOk:
|
||||||
|
doAssert key == lru.q.lastKey.value
|
||||||
|
doAssert lru.q.verify.isOk
|
||||||
return rc.value
|
return rc.value
|
||||||
lru.q.lruAppend(key, key.fromKey.toValue, lru.size)
|
result = lru.q.lruAppend(key, key.fromKey.toValue, lru.size)
|
||||||
|
doAssert lru.q.verify.isOk
|
||||||
|
|
||||||
proc toLruCache(a: openArray[int]): LruCache =
|
proc toLruCache(a: openArray[int]): LruCache =
|
||||||
result.size = lruCacheLimit
|
result.size = lruCacheLimit
|
||||||
|
|
Loading…
Reference in New Issue