101 lines
3.3 KiB
Nim
101 lines
3.3 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
# http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed except
|
|
# according to those terms.
|
|
|
|
## Keyed Queue, Debuugig support
|
|
## =============================
|
|
##
|
|
|
|
import
|
|
std/tables,
|
|
../keyed_queue,
|
|
../results
|
|
|
|
type
|
|
KeyedQueueInfo* = enum ##\
|
|
## Error messages as returned by `verify()`
|
|
kQOk = 0
|
|
kQVfyFirstInconsistent
|
|
kQVfyLastInconsistent
|
|
kQVfyNoSuchTabItem
|
|
kQVfyNoPrvTabItem
|
|
kQVfyNxtPrvExpected
|
|
kQVfyLastExpected
|
|
kQVfyNoNxtTabItem
|
|
kQVfyPrvNxtExpected
|
|
kQVfyFirstExpected
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions, debugging
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc `$`*[K,V](item: KeyedQueueItem[K,V]): string =
|
|
## Pretty print data container item.
|
|
##
|
|
## :CAVEAT:
|
|
## This function needs working definitions for the `key` and `value` items:
|
|
## ::
|
|
## proc `$`*[K](key: K): string {.gcsafe,raises:[Defect,CatchableError].}
|
|
## proc `$`*[V](value: V): string {.gcsafe,raises:[Defect,CatchableError].}
|
|
##
|
|
if item.isNil:
|
|
"nil"
|
|
else:
|
|
"(" & $item.value & ", link[" & $item.prv & "," & $item.kNxt & "])"
|
|
|
|
proc verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
|
|
{.gcsafe,raises: [Defect,KeyError].} =
|
|
## Check for consistency. Returns an error unless the argument
|
|
## queue `rq` is consistent.
|
|
let tabLen = rq.tab.len
|
|
if tabLen == 0:
|
|
return ok()
|
|
|
|
# Ckeck first and last items
|
|
if rq.tab[rq.kFirst].kPrv != rq.tab[rq.kFirst].kNxt:
|
|
return err((rq.kFirst, rq.tab[rq.kFirst].data, kQVfyFirstInconsistent))
|
|
|
|
if rq.tab[rq.kLast].kPrv != rq.tab[rq.kLast].kNxt:
|
|
return err((rq.kLast, rq.tab[rq.kLast].data, kQVfyLastInconsistent))
|
|
|
|
# Just a return value
|
|
var any: V
|
|
|
|
# Forward walk item list
|
|
var key = rq.kFirst
|
|
for _ in 1 .. tabLen:
|
|
if not rq.tab.hasKey(key):
|
|
return err((key, any, kQVfyNoSuchTabItem))
|
|
if not rq.tab.hasKey(rq.tab[key].kNxt):
|
|
return err((rq.tab[key].kNxt, rq.tab[key].data, kQVfyNoNxtTabItem))
|
|
if key != rq.kLast and key != rq.tab[rq.tab[key].kNxt].kPrv:
|
|
return err((key, rq.tab[rq.tab[key].kNxt].data, kQVfyNxtPrvExpected))
|
|
key = rq.tab[key].kNxt
|
|
if rq.tab[key].kNxt != rq.kLast:
|
|
return err((key, rq.tab[key].data, kQVfyLastExpected))
|
|
|
|
# Backwards walk item list
|
|
key = rq.kLast
|
|
for _ in 1 .. tabLen:
|
|
if not rq.tab.hasKey(key):
|
|
return err((key, any, kQVfyNoSuchTabItem))
|
|
if not rq.tab.hasKey(rq.tab[key].kPrv):
|
|
return err((rq.tab[key].kPrv, rq.tab[key].data, kQVfyNoPrvTabItem))
|
|
if key != rq.kFirst and key != rq.tab[rq.tab[key].kPrv].kNxt:
|
|
return err((key, rq.tab[rq.tab[key].kPrv].data, kQVfyPrvNxtExpected))
|
|
key = rq.tab[key].kPrv
|
|
if rq.tab[key].kPrv != rq.kFirst:
|
|
return err((key, rq.tab[key].data, kQVfyFirstExpected))
|
|
|
|
ok()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|