Merge branch 'master' into test-with-nightly-nimble

This commit is contained in:
Roman Zajic 2024-07-01 09:05:16 +02:00 committed by GitHub
commit 2e765379be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 201 additions and 195 deletions

View File

@ -1,4 +1,4 @@
## Copyright (c) 2021-2023 Status Research & Development GmbH
## Copyright (c) 2021-2024 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -10,7 +10,7 @@
##
## Encoding procedures are adopted versions of C functions described here:
## # https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
import results
import pkg/results
export results
{.push raises: [].}
@ -39,7 +39,7 @@ type
data*: array[maxLen(Base10, T), byte]
len*: int8 # >= 1 when holding valid unsigned integer
proc decode*[A: byte|char, T: SomeUnsignedInt](
func decode*[A: byte|char, T: SomeUnsignedInt](
B: typedesc[Base10], t: typedesc[T],
src: openArray[A]): Result[T, cstring] =
## Convert base10 encoded string or array of bytes to unsigned integer.
@ -62,7 +62,7 @@ proc decode*[A: byte|char, T: SomeUnsignedInt](
v = (v shl 3) + (v shl 1) + T(d)
ok(v)
proc encodedLength*(B: typedesc[Base10], value: SomeUnsignedInt): int8 =
func encodedLength*(B: typedesc[Base10], value: SomeUnsignedInt): int8 =
## Procedure returns number of characters needed to encode integer ``value``.
when type(value) is uint8:
if value < 10'u8:
@ -132,7 +132,7 @@ proc encodedLength*(B: typedesc[Base10], value: SomeUnsignedInt): int8 =
return 11'i8 + (if value >= P11: 1'i8 else: 0)
return 12'i8 + B.encodedLength(value div P12)
proc encode[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
func encode[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
output: var openArray[A],
length: int8): Result[int8, cstring] =
const Digits = cstring(
@ -175,25 +175,25 @@ proc encode[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
output[next - 1] = byte(Digits[index])
ok(length)
proc encode*[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
func encode*[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
output: var openArray[A]): Result[int8, cstring] =
## Encode integer value to array of characters or bytes.
B.encode(value, output, B.encodedLength(value))
proc toString*(B: typedesc[Base10], value: SomeUnsignedInt): string =
func toString*(B: typedesc[Base10], value: SomeUnsignedInt): string =
## Encode integer value ``value`` to string.
var buf = newString(B.encodedLength(value))
# Buffer of proper size is allocated, so error is not possible
discard B.encode(value, buf, int8(len(buf)))
buf
proc toBytes*[I: SomeUnsignedInt](B: typedesc[Base10], v: I): Base10Buf[I] {.
func toBytes*[I: SomeUnsignedInt](B: typedesc[Base10], v: I): Base10Buf[I] {.
noinit.} =
## Encode integer value ``value`` to array of bytes.
let res = B.encode(v, result.data, B.encodedLength(v))
result.len = int8(res.get())
proc toBytes*[I: SomeUnsignedInt](v: I, B: typedesc[Base10]): Base10Buf[I] {.
func toBytes*[I: SomeUnsignedInt](v: I, B: typedesc[Base10]): Base10Buf[I] {.
noinit.} =
## Encode integer value ``value`` to array of bytes.
let res = B.encode(v, result.data, B.encodedLength(v))

View File

@ -1,6 +1,6 @@
# Nimbus - Types, data structures and shared utilities used in network sync
#
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -108,11 +108,12 @@
## isomorpic to a subclass of `S`.
##
import
"."/[results, sorted_set]
{.push raises: [].}
import
pkg/results,
"."/sorted_set
export
`isRed=`,
`linkLeft=`,
@ -282,25 +283,25 @@ template scalarOne(): untyped =
## the value `1` from the scalar data type
(S.default + 1)
proc blk[P,S](kvp: DataRef[P,S]): BlockRef[S] =
func blk[P,S](kvp: DataRef[P,S]): BlockRef[S] =
kvp.data
proc left[P,S](kvp: DataRef[P,S]): P =
func left[P,S](kvp: DataRef[P,S]): P =
kvp.key
proc right[P,S](kvp: DataRef[P,S]): P =
func right[P,S](kvp: DataRef[P,S]): P =
kvp.key + kvp.blk.size
proc len[P,S](kvp: DataRef[P,S]): S =
func len[P,S](kvp: DataRef[P,S]): S =
kvp.data.size
# -----
proc new[P,S](T: type Segm[P,S]; left, right: P): T =
func new[P,S](T: type Segm[P,S]; left, right: P): T =
## Constructor using `[left,right)` points representation
T(start: left, size: right - left)
proc brew[P,S](T: type Segm[P,S]; left, right: P): Result[T,void] =
func brew[P,S](T: type Segm[P,S]; left, right: P): Result[T,void] =
## Constructor providing `[left, max(left,right)-left)` (if any.)
if high(P) <= left:
return err()
@ -313,39 +314,39 @@ proc brew[P,S](T: type Segm[P,S]; left, right: P): Result[T,void] =
(high(P) - left)
ok(T(start: left, size: length))
proc left[P,S](iv: Segm[P,S]): P =
func left[P,S](iv: Segm[P,S]): P =
iv.start
proc right[P,S](iv: Segm[P,S]): P =
func right[P,S](iv: Segm[P,S]): P =
iv.start + iv.size
proc len[P,S](iv: Segm[P,S]): S =
func len[P,S](iv: Segm[P,S]): S =
iv.size
# ------
proc incPt[P,S](a: var P; n: S) =
func incPt[P,S](a: var P; n: S) =
## Might not be generally available for point `P` and scalar `S`
a = a + n
proc maxPt[P](a, b: P): P =
func maxPt[P](a, b: P): P =
## Instead of max() which might not be generally available
if a < b: b else: a
proc minPt[P](a, b: P): P =
func minPt[P](a, b: P): P =
## Instead of min() which might not be generally available
if a < b: a else: b
# ------
proc new[P,S](T: type Interval[P,S]; kvp: DataRef[P,S]): T =
func new[P,S](T: type Interval[P,S]; kvp: DataRef[P,S]): T =
T(least: kvp.left, last: kvp.right - scalarOne)
# ------------------------------------------------------------------------------
# Private helpers
# ------------------------------------------------------------------------------
proc overlapOrLeftJoin[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
func overlapOrLeftJoin[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
## Find and return
## * either the rightmost interval `[a,b)` which overlaps `r`
## * or `[a,b)` with `b==l`
@ -358,11 +359,11 @@ proc overlapOrLeftJoin[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
return ok(rc.value)
err()
proc overlapOrLeftJoin[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Rc[P,S] =
func overlapOrLeftJoin[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Rc[P,S] =
ds.overlapOrLeftJoin(iv.left, iv.right)
proc overlap[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
func overlap[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
## Find and return the rightmost `[l,r)` overlapping interval `[a,b)`.
doAssert l < r
let rc = ds.leftPos.lt(r) # search for `max(a) < r`
@ -373,14 +374,14 @@ proc overlap[P,S](ds: Desc[P,S]; l, r: P): Rc[P,S] =
return ok(rc.value)
err()
proc overlap[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Rc[P,S] =
func overlap[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Rc[P,S] =
ds.overlap(iv.left, iv.right)
# ------------------------------------------------------------------------------
# Private transfer function helpers
# ------------------------------------------------------------------------------
proc findInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
func findInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
## Find largest sub-segment of `iv` fully contained in another segment
## of the argument database.
##
@ -400,7 +401,7 @@ proc findInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
Segm[P,S].new(maxPt(p.left,iv.left), minPt(p.right,iv.right))
proc merge[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
func merge[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
## Merges argument interval into into database and returns
## the segment really added (if any)
@ -513,7 +514,7 @@ proc merge[P,S](ds: Desc[P,S]; iv: Segm[P,S]): Segm[P,S] =
# s: [--------------)
proc deleteInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]) =
func deleteInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]) =
## Delete fully contained interval
if not ds.isNil and 0 < iv.len:
@ -560,7 +561,7 @@ proc deleteInlet[P,S](ds: Desc[P,S]; iv: Segm[P,S]) =
# Private transfer() function implementation for merge/reduce
# ------------------------------------------------------------------------------
proc transferImpl[P,S](src, trg: Desc[P,S]; iv: Segm[P,S]): S =
func transferImpl[P,S](src, trg: Desc[P,S]; iv: Segm[P,S]): S =
## From the `src` argument database, delete the data segment/interval
## `[start,start+length)` and merge it into the `trg` argument database.
## Not both arguments `src` and `trg` must be `nil`.
@ -592,7 +593,7 @@ proc transferImpl[P,S](src, trg: Desc[P,S]; iv: Segm[P,S]): S =
# Private covered() function implementation
# ------------------------------------------------------------------------------
proc coveredImpl[P,S](ds: IntervalSetRef[P,S]; start: P; length: S): S =
func coveredImpl[P,S](ds: IntervalSetRef[P,S]; start: P; length: S): S =
## Calulate the accumulated size of the interval `[start,start+length)`
## covered by intervals in the set `ds`. The result cannot exceed the
## argument `length` (of course.)
@ -644,12 +645,12 @@ proc coveredImpl[P,S](ds: IntervalSetRef[P,S]; start: P; length: S): S =
# Public constructor, clone, etc.
# ------------------------------------------------------------------------------
proc init*[P,S](T: type IntervalSetRef[P,S]): T =
func init*[P,S](T: type IntervalSetRef[P,S]): T =
## Interval set constructor.
new result
result.leftPos.init()
proc clone*[P,S](ds: IntervalSetRef[P,S]): IntervalSetRef[P,S] =
func clone*[P,S](ds: IntervalSetRef[P,S]): IntervalSetRef[P,S] =
## Return a copy of the interval list. Beware, this might be slow as it
## needs to copy every interval record.
result = Desc[P,S].init()
@ -666,7 +667,7 @@ proc clone*[P,S](ds: IntervalSetRef[P,S]): IntervalSetRef[P,S] =
# optional clean up, see comments on the destroy() directive
walk.destroy
proc `==`*[P,S](a, b: IntervalSetRef[P,S]): bool =
func `==`*[P,S](a, b: IntervalSetRef[P,S]): bool =
## Compare interval sets for equality. Beware, this can be slow. Every
## interval record has to be checked.
if a.ptsCount == b.ptsCount and
@ -686,13 +687,13 @@ proc `==`*[P,S](a, b: IntervalSetRef[P,S]): bool =
# optional clean up, see comments on the destroy() directive
aWalk.destroy()
proc clear*[P,S](ds: IntervalSetRef[P,S]) =
func clear*[P,S](ds: IntervalSetRef[P,S]) =
## Clear the interval set.
ds.ptsCount = scalarZero
ds.lastHigh = false
ds.leftPos.clear()
proc new*[P,S](T: type Interval[P,S]; minPt, maxPt: P): T =
func new*[P,S](T: type Interval[P,S]; minPt, maxPt: P): T =
## Create interval `[minPt,max(minPt,maxPt)]`
Interval[P,S](least: minPt, last: max(minPt, maxPt))
@ -700,7 +701,7 @@ proc new*[P,S](T: type Interval[P,S]; minPt, maxPt: P): T =
# Public interval operations add, remove, erc.
# ------------------------------------------------------------------------------
proc merge*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
func merge*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## merge `I` with the intervals of the argument set `ds`. The function
## returns the accumulated number of points that were added to some
@ -720,12 +721,12 @@ proc merge*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
else:
result = scalarZero
proc merge*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
func merge*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
## Variant of `merge()`
ds.merge(iv.least, iv.last)
proc reduce*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
func reduce*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## remove the points from `I` from intervals of the argument set `ds`.
## The function returns the accumulated number of elements removed (i.e.
@ -745,12 +746,12 @@ proc reduce*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
else:
result = scalarZero
proc reduce*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
func reduce*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
## Variant of `reduce()`
ds.reduce(iv.least, iv.last)
proc covered*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
func covered*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## calulate the accumulated points `I` contained in some interval in the
## set `ds`. The return value is the same as that for `reduce()` (only
@ -765,12 +766,12 @@ proc covered*[P,S](ds: IntervalSetRef[P,S]; minPt, maxPt: P): S =
else:
result = scalarZero
proc covered*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
func covered*[P,S](ds: IntervalSetRef[P,S]; iv: Interval[P,S]): S =
## Variant of `covered()`
ds.covered(iv.least, iv.last)
proc ge*[P,S](ds: IntervalSetRef[P,S]; minPt: P): IntervalRc[P,S] =
func ge*[P,S](ds: IntervalSetRef[P,S]; minPt: P): IntervalRc[P,S] =
## Find smallest interval in the set `ds` with start point (i.e. minimal
## value in the interval as a set) greater or equal the argument `minPt`.
let rc = ds.leftPos.ge(minPt)
@ -785,11 +786,11 @@ proc ge*[P,S](ds: IntervalSetRef[P,S]; minPt: P): IntervalRc[P,S] =
return ok(Interval[P,S].new(high(P),high(P)))
err()
proc ge*[P,S](ds: IntervalSetRef[P,S]): IntervalRc[P,S] =
func ge*[P,S](ds: IntervalSetRef[P,S]): IntervalRc[P,S] =
## Find the interval with the least elements of type `P` (if any.)
ds.ge(low(P))
proc le*[P,S](ds: IntervalSetRef[P,S]; maxPt: P): IntervalRc[P,S] =
func le*[P,S](ds: IntervalSetRef[P,S]; maxPt: P): IntervalRc[P,S] =
## Find largest interval in the set `ds` with end point (i.e. maximal
## value in the interval as a set) smaller or equal to the argument `maxPt`.
let rc = ds.leftPos.le(maxPt)
@ -818,12 +819,12 @@ proc le*[P,S](ds: IntervalSetRef[P,S]; maxPt: P): IntervalRc[P,S] =
return ok(Interval[P,S].new(high(P),high(P)))
err()
proc le*[P,S](ds: IntervalSetRef[P,S]): IntervalRc[P,S] =
func le*[P,S](ds: IntervalSetRef[P,S]): IntervalRc[P,S] =
## Find the interval with the largest elements of type `P` (if any.)
ds.le(high(P))
proc envelope*[P,S](ds: IntervalSetRef[P,S]; pt: P): IntervalRc[P,S] =
func envelope*[P,S](ds: IntervalSetRef[P,S]; pt: P): IntervalRc[P,S] =
## Find the interval that contains the argument point `pt` (if any)
let rc = ds.leftPos.le(pt)
if rc.isOk:
@ -838,7 +839,7 @@ proc envelope*[P,S](ds: IntervalSetRef[P,S]; pt: P): IntervalRc[P,S] =
err()
proc delete*[P,S](ds: IntervalSetRef[P,S]; minPt: P): IntervalRc[P,S] =
func delete*[P,S](ds: IntervalSetRef[P,S]; minPt: P): IntervalRc[P,S] =
## Find the interval `[minPt,maxPt]` for some point `maxPt` in the interval
## set `ds` and remove it from `ds`. The function returns the deleted
## interval (if any.)
@ -915,21 +916,21 @@ iterator decreasing*[P,S](
# Public interval operators
# ------------------------------------------------------------------------------
proc `==`*[P,S](iv, jv: Interval[P,S]): bool =
func `==`*[P,S](iv, jv: Interval[P,S]): bool =
## Compare intervals for equality
iv.least == jv.least and iv.last == jv.last
proc `==`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): bool =
func `==`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): bool =
## Variant of `==`
if iv.isOk:
return iv.value == jv
proc `==`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): bool =
func `==`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): bool =
## Variant of `==`
if jv.isOk:
return iv == jv.value
proc `==`*[P,S](iv, jv: IntervalRc[P,S]): bool =
func `==`*[P,S](iv, jv: IntervalRc[P,S]): bool =
## Variant of `==`
if iv.isOk:
if jv.isOk:
@ -941,7 +942,7 @@ proc `==`*[P,S](iv, jv: IntervalRc[P,S]): bool =
# ------
proc `*`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
func `*`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
## Intersect itervals `iv` and `jv` if this operation results in a
## non-emty interval. Note that the `*` operation is associative, i.e.
## ::
@ -953,19 +954,19 @@ proc `*`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
maxPt(jv.least,iv.least), minPt(jv.last,iv.last)))
err()
proc `*`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
func `*`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
## Variant of `*`
if iv.isOk:
return iv.value * jv
err()
proc `*`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `*`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `*`
if jv.isOk:
return iv * jv.value
err()
proc `*`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `*`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `*`
if iv.isOk and jv.isOk:
return iv.value * jv.value
@ -973,7 +974,7 @@ proc `*`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
# ------
proc `+`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
func `+`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
## Merge intervals `iv` and `jv` if this operation results in an interval.
## Note that the `+` operation is *not* associative, i.e.
## ::
@ -997,19 +998,19 @@ proc `+`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
err()
proc `+`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
func `+`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
## Variant of `+`
if iv.isOk:
return iv.value + jv
err()
proc `+`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `+`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `+`
if jv.isOk:
return iv + jv.value
err()
proc `+`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `+`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `+`
if iv.isOk and jv.isOk:
return iv.value + jv.value
@ -1017,7 +1018,7 @@ proc `+`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
# ------
proc `-`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
func `-`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
## Return the interval `iv` reduced by elements of `jv` if this operation
## results in a non-empty interval.
## Note that the `-` operation is *not* associative, i.e.
@ -1074,19 +1075,19 @@ proc `-`*[P,S](iv, jv: Interval[P,S]): IntervalRc[P,S] =
err()
proc `-`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
func `-`*[P,S](iv: IntervalRc[P,S]; jv: Interval[P,S]): IntervalRc[P,S] =
## Variant of `-`
if iv.isOk:
return iv.value - jv
err()
proc `-`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `-`*[P,S](iv: Interval[P,S]; jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `-`
if jv.isOk:
return iv - jv.value
err()
proc `-`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
func `-`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
## Variant of `-`
if iv.isOk and jv.isOk:
return iv.value - jv.valu
@ -1096,7 +1097,7 @@ proc `-`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
# Public getters
# ------------------------------------------------------------------------------
proc len*[P,S](iv: Interval[P,S]): S =
func len*[P,S](iv: Interval[P,S]): S =
## Cardinality (ie. length) of argument interval `iv`. If the argument
## interval `iv` is `[low(P),high(P)]`, the return value will be the scalar
## *zero* (there are no empty intervals in this implementation.)
@ -1105,15 +1106,15 @@ proc len*[P,S](iv: Interval[P,S]): S =
else:
(iv.last - iv.least) + scalarOne
proc minPt*[P,S](iv: Interval[P,S]): P =
func minPt*[P,S](iv: Interval[P,S]): P =
## Left end, smallest point of `P` contained in the interval
iv.least
proc maxPt*[P,S](iv: Interval[P,S]): P =
func maxPt*[P,S](iv: Interval[P,S]): P =
## Right end, largest point of `P` contained in the interval
iv.last
proc total*[P,S](ds: IntervalSetRef[P,S]): S =
func total*[P,S](ds: IntervalSetRef[P,S]): S =
## Accumulated size covered by intervals in the interval set `ds`.
##
## In the special case when there is only the single interval
@ -1126,7 +1127,7 @@ proc total*[P,S](ds: IntervalSetRef[P,S]): S =
else:
ds.ptsCount + scalarOne
proc chunks*[P,S](ds: IntervalSetRef[P,S]): int =
func chunks*[P,S](ds: IntervalSetRef[P,S]): int =
## Number of disjunkt intervals (aka chunks) in the interval set `ds`.
result = ds.leftPos.len
if ds.lastHigh:
@ -1138,7 +1139,7 @@ proc chunks*[P,S](ds: IntervalSetRef[P,S]): int =
# Public debugging functions
# ------------------------------------------------------------------------------
proc `$`*[P,S](p: DataRef[P,S]): string =
func `$`*[P,S](p: DataRef[P,S]): string =
## Needed by `ds.verify()` for printing error messages
"[" & $p.left & "," & $p.right & ")"

View File

@ -1,3 +1,5 @@
{.deprecated: "use https://nim-lang.org/docs/syncio.html#writeFile%2Cstring%2CopenArray%5Bbyte%5D directly".}
when not compiles(writeFile("filename", @[byte(1)])):
proc writeFile*(filename: string, content: openArray[byte]) =
## Opens a file named `filename` for writing. Then writes the
@ -11,4 +13,3 @@ when not compiles(writeFile("filename", @[byte(1)])):
close(f)
else:
raise newException(IOError, "cannot open: " & filename)

View File

@ -1,4 +1,4 @@
## Copyright (c) 2020-2023 Status Research & Development GmbH
## Copyright (c) 2020-2024 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -12,8 +12,8 @@
{.push raises: [].}
import algorithm
import results
import std/algorithm
import pkg/results
export results
when defined(windows):

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -22,12 +22,12 @@
## semantics, this means that `=` performs a deep copy of the allocated queue
## which is refered to the deep copy semantics of the underlying table driver.
import std/tables, results
{.push raises: [].}
import std/tables, pkg/results
export results
{.push raises: [].}
type
KeyedQueueItem*[K, V] = object
## Data value container as stored in the queue.

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -12,10 +12,12 @@
## =============================
##
{.push raises: [].}
import
std/tables,
../keyed_queue,
../results
results,
../keyed_queue
type
KeyedQueueInfo* = enum ##\
@ -31,13 +33,11 @@ type
kQVfyPrvNxtExpected
kQVfyFirstExpected
{.push raises: [].}
# ------------------------------------------------------------------------------
# Public functions, debugging
# ------------------------------------------------------------------------------
proc `$`*[K,V](item: KeyedQueueItem[K,V]): string =
func `$`*[K,V](item: KeyedQueueItem[K,V]): string =
## Pretty print data container item.
##
## :CAVEAT:
@ -51,8 +51,8 @@ proc `$`*[K,V](item: KeyedQueueItem[K,V]): string =
else:
"(" & $item.value & ", link[" & $item.prv & "," & $item.kNxt & "])"
proc verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
{.gcsafe,raises: [KeyError].} =
func verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
{.raises: [KeyError].} =
## Check for consistency. Returns an error unless the argument
## queue `rq` is consistent.
let tabLen = rq.tab.len
@ -97,7 +97,7 @@ proc verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
ok()
proc dumpLinkedKeys*[K,V](rq: var KeyedQueue[K,V]): string =
func 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:

View File

@ -1,3 +0,0 @@
{.deprecated: "use std/os".}
import std/os
export os

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -47,9 +47,12 @@
## rc = w.next
## # optional clean up, see comments on the destroy() directive
## walk.destroy
##
{.push raises: [].}
import
std/[tables],
pkg/results,
./sorted_set/[rbtree_delete,
rbtree_desc,
rbtree_find,
@ -57,8 +60,7 @@ import
rbtree_insert,
rbtree_reset,
rbtree_verify,
rbtree_walk],
./results
rbtree_walk]
export
RbInfo,
@ -93,18 +95,18 @@ type
# Private helpers
# ------------------------------------------------------------------------------
proc slstCmp[K,V](casket: SortedSetItemRef[K,V]; key: K): int =
func slstCmp[K,V](casket: SortedSetItemRef[K,V]; key: K): int =
casket.key.cmp(key)
proc slstMkc[K,V](key: K): SortedSetItemRef[K,V] =
func slstMkc[K,V](key: K): SortedSetItemRef[K,V] =
SortedSetItemRef[K,V](key: key)
proc slstClup[K,V](c: var SortedSetItemRef[K,V]) =
func slstClup[K,V](c: var SortedSetItemRef[K,V]) =
# ... some smart stuff here?
c = nil # GC hint (if any, todo?)
proc slstLt[K,V](a, b: SortedSetItemRef[K,V]): bool =
func slstLt[K,V](a, b: SortedSetItemRef[K,V]): bool =
## Debugging only
a.slstCmp(b.key) < 0
@ -116,22 +118,22 @@ proc slstPr(code: RbInfo; ctxInfo: string) =
# Public functions, constructor
# ------------------------------------------------------------------------------
proc init*[K,V](sl: var SortedSet[K,V]) =
func init*[K,V](sl: var SortedSet[K,V]) =
## Constructor for sorted list with key type `K` and data type `V`
sl.tree = newRbTreeRef[SortedSetItemRef[K,V],K](
cmp = proc(c: SortedSetItemRef[K,V]; k: K): int = c.slstCmp(k),
mkc = proc(k: K): SortedSetItemRef[K,V] = slstMkc[K,V](k))
proc init*[K,V](T: type SortedSet[K,V]): T =
func init*[K,V](T: type SortedSet[K,V]): T =
## Variant of `init()`
result.init
proc move*[K,V](sl: var SortedSet[K,V]): SortedSet[K,V] =
func move*[K,V](sl: var SortedSet[K,V]): SortedSet[K,V] =
## Return a shallow copy of the argument list `sl`, then reset `sl`.
result.tree = sl.tree
sl.init
proc clear*[K,V](sl: var SortedSet[K,V]) =
func clear*[K,V](sl: var SortedSet[K,V]) =
## Reset list descriptor to its inital value. This function also de-registers
## and flushes all traversal descriptors of type `SortedSetWalkRef`.
sl.tree.rbTreeReset(clup = proc(c: var SortedSetItemRef[K,V]) = c.slstClup)
@ -140,15 +142,15 @@ proc clear*[K,V](sl: var SortedSet[K,V]) =
# Public functions, getter, converter
# ------------------------------------------------------------------------------
proc key*[K,V](data: SortedSetItemRef[K,V]): K =
func key*[K,V](data: SortedSetItemRef[K,V]): K =
## Getter, extracts the key from the data container item.
data.key
proc len*[K,V](sl: var SortedSet[K,V]): int =
func len*[K,V](sl: var SortedSet[K,V]): int =
## Number of list elements
sl.tree.size
proc toSortedSetResult*[K,V](key: K; data: V): SortedSetResult[K,V] =
func toSortedSetResult*[K,V](key: K; data: V): SortedSetResult[K,V] =
## Helper, chreate `ok()` result
ok(SortedSetItemRef[K,V](key: key, data: data))
@ -156,24 +158,24 @@ proc toSortedSetResult*[K,V](key: K; data: V): SortedSetResult[K,V] =
# Public functions, list operations
# ------------------------------------------------------------------------------
proc insert*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func insert*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Insert `key`, returns data container item with the `key`. Function fails
## if `key` exists in the list.
sl.tree.rbTreeInsert(key)
proc findOrInsert*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func findOrInsert*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Insert or find `key`, returns data container item with the `key`. This
## function always succeeds (unless there is s problem with the list.)
result = sl.tree.rbTreeInsert(key)
if result.isErr:
return sl.tree.rbTreeFindEq(key)
proc delete*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func delete*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Delete `key` from list and return the data container item that was
## holding the `key` if it was deleted.
sl.tree.rbTreeDelete(key)
proc flush*[K,V](sl: var SortedSet[K,V]) =
func flush*[K,V](sl: var SortedSet[K,V]) =
## Flush the sorted list, i.e. delete all entries. This function is
## more efficient than running a `delete()` loop.
sl.tree.rbTreeFlush(clup = proc(c: var SortedSetItemRef[K,V]) = c.slstClup)
@ -182,27 +184,27 @@ proc flush*[K,V](sl: var SortedSet[K,V]) =
# Public functions, query functions
# ------------------------------------------------------------------------------
proc eq*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func eq*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Find `key` in list, returns data container item with the `key` if it
## exists.
sl.tree.rbTreeFindEq(key)
proc le*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func le*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Find data container iten with *largest* key *less or equal* the argument
## `key` in list and return it if found.
sl.tree.rbTreeFindLe(key)
proc lt*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func lt*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Find data container item with *largest* key *less than* the argument
## `key` in list and return it if found.
sl.tree.rbTreeFindLt(key)
proc ge*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func ge*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Find data container item with *smallest* key *greater or equal* the
## argument `key` in list and return it if found.
sl.tree.rbTreeFindGe(key)
proc gt*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
func gt*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
## Find data container item with *smallest* key *greater than* the argument
## `key` in list and return it if found.
sl.tree.rbTreeFindGt(key)
@ -211,12 +213,12 @@ proc gt*[K,V](sl: var SortedSet[K,V]; key: K): SortedSetResult[K,V] =
# Public functions, walk/traversal functions
# ------------------------------------------------------------------------------
proc init*[K,V](T: type SortedSetWalkRef[K,V]; sl: var SortedSet[K,V]): T =
func init*[K,V](T: type SortedSetWalkRef[K,V]; sl: var SortedSet[K,V]): T =
## Open traversal descriptor on list and register it on the 'SortedSet`
## descriptor.
sl.tree.newRbWalk
proc destroy*[K,V](w: SortedSetWalkRef[K,V]) =
func destroy*[K,V](w: SortedSetWalkRef[K,V]) =
## De-register and close the traversal descriptor. This function renders
## the descriptor unusable, so it must be disposed of.
##
@ -227,7 +229,7 @@ proc destroy*[K,V](w: SortedSetWalkRef[K,V]) =
## rewound or destroyed.
w.rbWalkDestroy
proc first*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
func first*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## Rewind the traversal descriptor to the *least* list key and return
## the corresponding data container item.
##
@ -235,7 +237,7 @@ proc first*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## list operations are reset.
w.rbWalkFirst
proc last*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
func last*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## Rewind the traversal descriptor to the *greatest* list key and return
## the corresponding data container item.
##
@ -243,14 +245,14 @@ proc last*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## list operations are reset.
w.rbWalkLast
proc this*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
func this*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## Retrieve the *current* data container item. This is the same one retrieved
## last with any of the traversal functions returning the data container item.
##
## Note that the current node becomes unavailable if it was recently deleted.
w.rbWalkCurrent
proc next*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
func next*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## Move the traversal descriptor to the next *greater* key and return the
## corresponding data container item. If this is the first call after
## `newWalk()`, then `w.first` is called implicitly.
@ -259,7 +261,7 @@ proc next*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## causing this function to fail so that a rewind is needed.
w.rbWalkNext
proc prev*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
func prev*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## Move the traversal descriptor to the next *smaller* key and return the
## corresponding data container item . If this is the first call after
## `newWalk()`, then `w.last` is called implicitly.
@ -272,7 +274,7 @@ proc prev*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
# Public helpers, debugging
# ------------------------------------------------------------------------------
proc `$`*[K,V](casket: SortedSetItemRef[K,V]): string =
func `$`*[K,V](casket: SortedSetItemRef[K,V]): string =
## Pretty printer
##
## :CAVEAT:
@ -284,7 +286,7 @@ proc `$`*[K,V](casket: SortedSetItemRef[K,V]): string =
return "nil"
"(" & $casket.key & "," & $casket.data & ")"
proc `$`*[K,V](rc: SortedSetResult[K,V]): string =
func `$`*[K,V](rc: SortedSetResult[K,V]): string =
## Pretty printer
##
## :CAVEAT:

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -8,18 +8,18 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
./rbtree_desc,
./rbtree_rotate,
../results
{.push raises: [].}
import
results,
./rbtree_desc,
./rbtree_rotate
# ------------------------------------------------------------------------------
# Public
# ------------------------------------------------------------------------------
proc rbTreeDelete*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeDelete*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function, removes a node from the red-black tree.
## The node to be removed wraps a data container `casket` matching the
## argument `key`, i.e. `rbt.cmp(casket,key) == 0`.

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -67,9 +67,11 @@
# anyone who has modified the code through
# a header comment, such as this one.typedef
{.push raises: [].}
import
std/[tables],
../results
results,
std/[tables]
const
rbTreeReBalancedFlag* = 1
@ -176,7 +178,7 @@ type
# Public functions, constructor
# ------------------------------------------------------------------------------
proc newRbTreeRef*[C,K](cmp: RbCmpFn[C,K]; mkc: RbMkcFn[C,K]): RbTreeRef[C,K] =
func newRbTreeRef*[C,K](cmp: RbCmpFn[C,K]; mkc: RbMkcFn[C,K]): RbTreeRef[C,K] =
## Constructor. Create generic red-black tree descriptor for data container
## type `C` and key type `K`. Details about the function arguments `cmpFn`
## and `mkcFn` are documented with the type definitions of `RbCmpFn` and
@ -188,7 +190,7 @@ proc newRbTreeRef*[C,K](cmp: RbCmpFn[C,K]; mkc: RbMkcFn[C,K]): RbTreeRef[C,K] =
walks: initTable[uint,RbWalkRef[C,K]](1))
proc newWalkId*[C,K](rbt: RbTreeRef[C,K]): uint {.inline.} =
func newWalkId*[C,K](rbt: RbTreeRef[C,K]): uint {.inline.} =
## Generate new free walk ID, returns zero in (theoretical) case all other
## IDs are exhausted.
for id in rbt.walkIdGen .. high(type rbt.walkIdGen):
@ -205,12 +207,12 @@ proc newWalkId*[C,K](rbt: RbTreeRef[C,K]): uint {.inline.} =
# Public handlers
# ------------------------------------------------------------------------------
proc cmp*[C,K](rbt: RbTreeRef[C,K]; casket: C; key: K): int {.inline.} =
func cmp*[C,K](rbt: RbTreeRef[C,K]; casket: C; key: K): int {.inline.} =
## See introduction for an explanation of opaque argument types `C` and `D`,
## and the type definition for `RbCmpFn` for properties of this function.
rbt.cmpFn(casket, key)
proc mkc*[C,K](rbt: RbTreeRef[C,K]; key: K): C {.inline.} =
func mkc*[C,K](rbt: RbTreeRef[C,K]; key: K): C {.inline.} =
## See introduction for an explanation of opaque argument/return types `C`
## and `D`, and the type definition for `RbMkdFn` for properties of this
## function.
@ -220,15 +222,15 @@ proc mkc*[C,K](rbt: RbTreeRef[C,K]; key: K): C {.inline.} =
# Public getters
# ------------------------------------------------------------------------------
proc linkLeft*[C](node: RbNodeRef[C]): RbNodeRef[C] {.inline.} =
func linkLeft*[C](node: RbNodeRef[C]): RbNodeRef[C] {.inline.} =
## Getter, shortcut for `node.link[rbLeft]`
node.link[rbLeft]
proc linkRight*[C](node: RbNodeRef[C]): RbNodeRef[C] {.inline.} =
func linkRight*[C](node: RbNodeRef[C]): RbNodeRef[C] {.inline.} =
## Getter, shortcut for `node.link[rbRight]`
node.link[rbRight]
proc isRed*[C](node: RbNodeRef[C]): bool {.inline.} =
func isRed*[C](node: RbNodeRef[C]): bool {.inline.} =
## Getter, `true` if node colour is read.
not node.isNil and node.redColour
@ -236,15 +238,15 @@ proc isRed*[C](node: RbNodeRef[C]): bool {.inline.} =
# Public setters
# ------------------------------------------------------------------------------
proc `linkLeft=`*[C](node, child: RbNodeRef[C]) {.inline.} =
func `linkLeft=`*[C](node, child: RbNodeRef[C]) {.inline.} =
## Getter, shortcut for `node.link[rbLeft] = child`
node.link[rbLeft] = child
proc `linkRight=`*[C](node, child: RbNodeRef[C]) {.inline.} =
func `linkRight=`*[C](node, child: RbNodeRef[C]) {.inline.} =
## Getter, shortcut for `node.link[rbRight] = child`
node.link[rbRight] = child
proc `isRed=`*[C](node: RbNodeRef[C]; value: bool) {.inline.} =
func `isRed=`*[C](node: RbNodeRef[C]; value: bool) {.inline.} =
## Setter, `true` sets red node colour.
node.redColour = value
@ -252,11 +254,11 @@ proc `isRed=`*[C](node: RbNodeRef[C]; value: bool) {.inline.} =
# Public helpers: `rbDir` as array index
# ------------------------------------------------------------------------------
proc `not`*(d: RbDir): RbDir {.inline.} =
func `not`*(d: RbDir): RbDir {.inline.} =
## Opposite direction of argument `d`.
if d == rbLeft: rbRight else: rbLeft
proc toDir*(b: bool): RbDir {.inline.} =
func toDir*(b: bool): RbDir {.inline.} =
## Convert to link diection `rbLeft` (false) or `rbRight` (true).
if b: rbRight else: rbLeft
@ -264,7 +266,7 @@ proc toDir*(b: bool): RbDir {.inline.} =
# Public pretty printer
# ------------------------------------------------------------------------------
proc `$`*[C](node: RbNodeRef[C]): string =
func `$`*[C](node: RbNodeRef[C]): string =
## Pretty printer, requres `$()` for type `C` to be known.
if node.isNil:
return "nil"
@ -276,7 +278,7 @@ proc `$`*[C](node: RbNodeRef[C]): string =
"left=" & $node.linkLeft & "," &
"right=" & $node.linkRight & ")"
proc `$`*[C,K](rbt: RbTreeRef[C,K]): string =
func `$`*[C,K](rbt: RbTreeRef[C,K]): string =
## Pretty printer
if rbt.isNil:
return "nil"
@ -285,7 +287,7 @@ proc `$`*[C,K](rbt: RbTreeRef[C,K]): string =
"gen=" & $rbt.walkIdGen & "," &
"root=" & $rbt.root & "]"
proc `$`*[C,K](w: RbWalkRef[C,K]): string =
func `$`*[C,K](w: RbWalkRef[C,K]): string =
## Pretty printer
if w.isNil:
return "nil"

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -8,17 +8,17 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
./rbtree_desc,
../results
{.push raises: [].}
import
results,
./rbtree_desc
# ----------------------------------------------------------------------- ------
# Public
# ------------------------------------------------------------------------------
proc rbTreeFindEq*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeFindEq*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function. Search for a data container `casket` of
## type `C` in the red black tree which matches the argument `key`,
## i.e. `rbt.cmp(casket,key) == 0`. If found, this data container `casket` is
@ -51,7 +51,7 @@ proc rbTreeFindEq*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
return err(rbNotFound)
proc rbTreeFindGe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeFindGe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function. Search for the *smallest* data container
## `casket` of type `C` which is *greater or equal* to the specified argument
## `key` in the red black-tree. If such a data container is found in the
@ -109,7 +109,7 @@ proc rbTreeFindGe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
return err(rbNotFound)
proc rbTreeFindGt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeFindGt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function. Search for the *smallest* data container
## of type `C` which is *strictly greater* than the specified argument `key`
## in the red-black tree.
@ -148,7 +148,7 @@ proc rbTreeFindGt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
return err(rbNotFound)
proc rbTreeFindLe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeFindLe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function. Search for the *greatest* data container
## of type `C` which is *less than or equal* to the specified argument
## `key` in the red-black tree.
@ -190,7 +190,7 @@ proc rbTreeFindLe*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
return err(rbNotFound)
proc rbTreeFindLt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeFindLt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function. Search for the *greatest* data container
## of type `C` which is *strictly less* than the specified argument `key` in
## the red-black tree.

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -8,25 +8,25 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
./rbtree_desc,
./rbtree_rotate,
../results
{.push raises: [].}
import
results,
./rbtree_desc,
./rbtree_rotate
# ----------------------------------------------------------------------- ------
# Private functions
# ------------------------------------------------------------------------------
proc insertRoot[C,K](rbt: RbTreeRef[C,K]; key: K): C {.inline.} =
func insertRoot[C,K](rbt: RbTreeRef[C,K]; key: K): C {.inline.} =
## Insert item `x` into an empty tree.
rbt.root = RbNodeRef[C](
casket: rbt.mkc(key))
rbt.size = 1
rbt.root.casket
proc insertNode[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] {.inline.} =
func insertNode[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] {.inline.} =
## Insert item `key` into a non-empty tree.
doAssert not rbt.root.isNil
@ -108,7 +108,7 @@ proc insertNode[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] {.inline.} =
# Public
# ------------------------------------------------------------------------------
proc rbTreeInsert*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
func rbTreeInsert*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
## Generic red-black tree function, inserts a data container `casket` derived
## from argument `key` into the red-black tree.
##

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -8,9 +8,11 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
{.push raises: [].}
import
./rbtree_desc,
../results
results,
./rbtree_desc
type
RbLtFn*[C] = ##\
@ -40,7 +42,7 @@ type
# Private
# ------------------------------------------------------------------------------
proc pp[C](n: RbNodeRef[C]): string =
func pp[C](n: RbNodeRef[C]): string =
if n.isNil:
return "nil"
result = $n.casket

View File

@ -1,5 +1,5 @@
# Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH
# Copyright (c) 2018-2024 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)
@ -8,18 +8,18 @@
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
std/[tables],
./rbtree_desc,
../results
{.push raises: [].}
import
results,
std/[tables],
./rbtree_desc
# ----------------------------------------------------------------------- ------
# Priv
# ------------------------------------------------------------------------------
proc walkMove[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
func walkMove[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
## Traverse a red black tree in the user-specified direction.
##
## :Returns:
@ -62,7 +62,7 @@ proc walkMove[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
return err(rbEndOfWalk)
proc walkStart[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
func walkStart[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
## Rewind the traversal position to the left-most or-right-most position
## as defined by the function argument `dir`. After successfully rewinding,
## the desriptor is in `start` position (see `walkClearDirty()`).
@ -94,7 +94,7 @@ proc walkStart[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
return ok(w.node.casket)
proc walkClearDirtyFlags[C,K](w: RbWalkRef[C,K]): bool =
func walkClearDirtyFlags[C,K](w: RbWalkRef[C,K]): bool =
## Clear dirty flag if all traversal descriptors are in `start` postion.
if w.tree.dirty != 0:
for u in w.tree.walks.values:
@ -110,7 +110,7 @@ proc walkClearDirtyFlags[C,K](w: RbWalkRef[C,K]): bool =
# Public constructor/desctructor
# ------------------------------------------------------------------------------
proc newRbWalk*[C,K](rbt: RbTreeRef[C,K]): RbWalkRef[C,K] =
func newRbWalk*[C,K](rbt: RbTreeRef[C,K]): RbWalkRef[C,K] =
## Generic red-black tree function, creates a new traversal descriptor on the
## argument red-black tree `rbt`.
##
@ -127,7 +127,7 @@ proc newRbWalk*[C,K](rbt: RbTreeRef[C,K]): RbWalkRef[C,K] =
rbt.walks[result.id] = result # register in parent descriptor
proc rbWalkDestroy*[C,K](w: RbWalkRef[C,K]) =
func rbWalkDestroy*[C,K](w: RbWalkRef[C,K]) =
## Explicit destructor for current walk descriptor `w`. Clears the descriptor
## argument `w`.
##
@ -142,7 +142,7 @@ proc rbWalkDestroy*[C,K](w: RbWalkRef[C,K]) =
w.path = @[]
w[].reset
proc rbWalkDestroyAll*[C,K](rbt: RbTreeRef[C,K]) =
func rbWalkDestroyAll*[C,K](rbt: RbTreeRef[C,K]) =
## Apply `rbWalkDestroy()` to all registered walk descriptors.
for w in rbt.walks.values:
w.tree = nil # notify GC (if any, todo?)
@ -151,7 +151,7 @@ proc rbWalkDestroyAll*[C,K](rbt: RbTreeRef[C,K]) =
w[].reset # clear
rbt.walks = initTable[uint,RbWalkRef[C,K]](1)
proc rbWalkDestroyAll*[C,K](w: RbWalkRef[C,K]) =
func rbWalkDestroyAll*[C,K](w: RbWalkRef[C,K]) =
## Variant of `rbWalkDestroyAll()`
if not w.tree.isNil:
w.tree.rbWalkDestroyAll
@ -160,7 +160,7 @@ proc rbWalkDestroyAll*[C,K](w: RbWalkRef[C,K]) =
# Public functions: rewind
# ------------------------------------------------------------------------------
proc rbWalkFirst*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
func rbWalkFirst*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
## Move to the beginning of the tree (*smallest* item) and return the
## corresponding data container of type `C`.
##
@ -181,7 +181,7 @@ proc rbWalkFirst*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
return w.walkStart(rbLeft)
proc rbWalkLast*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
func rbWalkLast*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
## Move to the end of the tree (*greatest* item) and return the corresponding
## data container of type `C`.
##
@ -205,7 +205,7 @@ proc rbWalkLast*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
# Public functions: traversal, get data entry
# ------------------------------------------------------------------------------
proc rbWalkCurrent*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
func rbWalkCurrent*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
## Retrieves the data container of type `C` for the current node. Note that
## the current node becomes unavailable if it was recently deleted.
##
@ -222,7 +222,7 @@ proc rbWalkCurrent*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
proc rbWalkNext*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
func rbWalkNext*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
## Traverse to the next value in ascending order and return the corresponding
## data container of type `C`. If this is the first call after `newRbWalk()`,
## then `rbWalkFirst()` is called implicitly.
@ -253,7 +253,7 @@ proc rbWalkNext*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
return w.walkStart(rbLeft) # minimum index item
proc rbWalkPrev*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
func rbWalkPrev*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
## Traverse to the next value in descending order and return the
## corresponding data container of type `C`. If this is the first call
## after `newRbWalk()`, then `rbWalkLast()` is called implicitly.

View File

@ -1,11 +1,12 @@
# Copyright (c) 2020-2022 Status Research & Development GmbH
# Copyright (c) 2020-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license: http://opensource.org/licenses/MIT
# * Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import std/[os, strutils]
import ../stew/io2, ../stew/results
import pkg/results
import ../stew/io2
proc lockFileFlags(path: string, flags: set[OpenFlags],
lockType: LockType): IoResult[void] =