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 ## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) ## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT)) ## * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -10,7 +10,7 @@
## ##
## Encoding procedures are adopted versions of C functions described here: ## Encoding procedures are adopted versions of C functions described here:
## # https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 ## # https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
import results import pkg/results
export results export results
{.push raises: [].} {.push raises: [].}
@ -39,7 +39,7 @@ type
data*: array[maxLen(Base10, T), byte] data*: array[maxLen(Base10, T), byte]
len*: int8 # >= 1 when holding valid unsigned integer 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], B: typedesc[Base10], t: typedesc[T],
src: openArray[A]): Result[T, cstring] = src: openArray[A]): Result[T, cstring] =
## Convert base10 encoded string or array of bytes to unsigned integer. ## 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) v = (v shl 3) + (v shl 1) + T(d)
ok(v) 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``. ## Procedure returns number of characters needed to encode integer ``value``.
when type(value) is uint8: when type(value) is uint8:
if value < 10'u8: 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 11'i8 + (if value >= P11: 1'i8 else: 0)
return 12'i8 + B.encodedLength(value div P12) 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], output: var openArray[A],
length: int8): Result[int8, cstring] = length: int8): Result[int8, cstring] =
const Digits = cstring( const Digits = cstring(
@ -175,25 +175,25 @@ proc encode[A: byte|char](B: typedesc[Base10], value: SomeUnsignedInt,
output[next - 1] = byte(Digits[index]) output[next - 1] = byte(Digits[index])
ok(length) 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] = output: var openArray[A]): Result[int8, cstring] =
## Encode integer value to array of characters or bytes. ## Encode integer value to array of characters or bytes.
B.encode(value, output, B.encodedLength(value)) 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. ## Encode integer value ``value`` to string.
var buf = newString(B.encodedLength(value)) var buf = newString(B.encodedLength(value))
# Buffer of proper size is allocated, so error is not possible # Buffer of proper size is allocated, so error is not possible
discard B.encode(value, buf, int8(len(buf))) discard B.encode(value, buf, int8(len(buf)))
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.} = noinit.} =
## Encode integer value ``value`` to array of bytes. ## Encode integer value ``value`` to array of bytes.
let res = B.encode(v, result.data, B.encodedLength(v)) let res = B.encode(v, result.data, B.encodedLength(v))
result.len = int8(res.get()) 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.} = noinit.} =
## Encode integer value ``value`` to array of bytes. ## Encode integer value ``value`` to array of bytes.
let res = B.encode(v, result.data, B.encodedLength(v)) 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 # 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 # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -108,11 +108,12 @@
## isomorpic to a subclass of `S`. ## isomorpic to a subclass of `S`.
## ##
import
"."/[results, sorted_set]
{.push raises: [].} {.push raises: [].}
import
pkg/results,
"."/sorted_set
export export
`isRed=`, `isRed=`,
`linkLeft=`, `linkLeft=`,
@ -282,25 +283,25 @@ template scalarOne(): untyped =
## the value `1` from the scalar data type ## the value `1` from the scalar data type
(S.default + 1) (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 kvp.data
proc left[P,S](kvp: DataRef[P,S]): P = func left[P,S](kvp: DataRef[P,S]): P =
kvp.key 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 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 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 ## Constructor using `[left,right)` points representation
T(start: left, size: right - left) 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.) ## Constructor providing `[left, max(left,right)-left)` (if any.)
if high(P) <= left: if high(P) <= left:
return err() return err()
@ -313,39 +314,39 @@ proc brew[P,S](T: type Segm[P,S]; left, right: P): Result[T,void] =
(high(P) - left) (high(P) - left)
ok(T(start: left, size: length)) 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 iv.start
proc right[P,S](iv: Segm[P,S]): P = func right[P,S](iv: Segm[P,S]): P =
iv.start + iv.size iv.start + iv.size
proc len[P,S](iv: Segm[P,S]): S = func len[P,S](iv: Segm[P,S]): S =
iv.size 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` ## Might not be generally available for point `P` and scalar `S`
a = a + n 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 ## Instead of max() which might not be generally available
if a < b: b else: a 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 ## Instead of min() which might not be generally available
if a < b: a else: b 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) T(least: kvp.left, last: kvp.right - scalarOne)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private helpers # 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 ## Find and return
## * either the rightmost interval `[a,b)` which overlaps `r` ## * either the rightmost interval `[a,b)` which overlaps `r`
## * or `[a,b)` with `b==l` ## * 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) return ok(rc.value)
err() 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) 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)`. ## Find and return the rightmost `[l,r)` overlapping interval `[a,b)`.
doAssert l < r doAssert l < r
let rc = ds.leftPos.lt(r) # search for `max(a) < 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) return ok(rc.value)
err() 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) ds.overlap(iv.left, iv.right)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private transfer function helpers # 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 ## Find largest sub-segment of `iv` fully contained in another segment
## of the argument database. ## 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)) 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 ## Merges argument interval into into database and returns
## the segment really added (if any) ## 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: [--------------) # 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 ## Delete fully contained interval
if not ds.isNil and 0 < iv.len: 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 # 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 ## From the `src` argument database, delete the data segment/interval
## `[start,start+length)` and merge it into the `trg` argument database. ## `[start,start+length)` and merge it into the `trg` argument database.
## Not both arguments `src` and `trg` must be `nil`. ## 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 # 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)` ## Calulate the accumulated size of the interval `[start,start+length)`
## covered by intervals in the set `ds`. The result cannot exceed the ## covered by intervals in the set `ds`. The result cannot exceed the
## argument `length` (of course.) ## 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. # 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. ## Interval set constructor.
new result new result
result.leftPos.init() 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 ## Return a copy of the interval list. Beware, this might be slow as it
## needs to copy every interval record. ## needs to copy every interval record.
result = Desc[P,S].init() 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 # optional clean up, see comments on the destroy() directive
walk.destroy 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 ## Compare interval sets for equality. Beware, this can be slow. Every
## interval record has to be checked. ## interval record has to be checked.
if a.ptsCount == b.ptsCount and 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 # optional clean up, see comments on the destroy() directive
aWalk.destroy() aWalk.destroy()
proc clear*[P,S](ds: IntervalSetRef[P,S]) = func clear*[P,S](ds: IntervalSetRef[P,S]) =
## Clear the interval set. ## Clear the interval set.
ds.ptsCount = scalarZero ds.ptsCount = scalarZero
ds.lastHigh = false ds.lastHigh = false
ds.leftPos.clear() 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)]` ## Create interval `[minPt,max(minPt,maxPt)]`
Interval[P,S](least: minPt, last: 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. # 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)]`, ## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## merge `I` with the intervals of the argument set `ds`. The function ## merge `I` with the intervals of the argument set `ds`. The function
## returns the accumulated number of points that were added to some ## 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: else:
result = scalarZero 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()` ## Variant of `merge()`
ds.merge(iv.least, iv.last) 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)]`, ## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## remove the points from `I` from intervals of the argument set `ds`. ## remove the points from `I` from intervals of the argument set `ds`.
## The function returns the accumulated number of elements removed (i.e. ## 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: else:
result = scalarZero 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()` ## Variant of `reduce()`
ds.reduce(iv.least, iv.last) 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)]`, ## For the argument interval `I` implied as `[minPt,max(minPt,maxPt)]`,
## calulate the accumulated points `I` contained in some interval in the ## calulate the accumulated points `I` contained in some interval in the
## set `ds`. The return value is the same as that for `reduce()` (only ## 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: else:
result = scalarZero 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()` ## Variant of `covered()`
ds.covered(iv.least, iv.last) 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 ## 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`. ## value in the interval as a set) greater or equal the argument `minPt`.
let rc = ds.leftPos.ge(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))) return ok(Interval[P,S].new(high(P),high(P)))
err() 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.) ## Find the interval with the least elements of type `P` (if any.)
ds.ge(low(P)) 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 ## 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`. ## value in the interval as a set) smaller or equal to the argument `maxPt`.
let rc = ds.leftPos.le(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))) return ok(Interval[P,S].new(high(P),high(P)))
err() 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.) ## Find the interval with the largest elements of type `P` (if any.)
ds.le(high(P)) 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) ## Find the interval that contains the argument point `pt` (if any)
let rc = ds.leftPos.le(pt) let rc = ds.leftPos.le(pt)
if rc.isOk: if rc.isOk:
@ -838,7 +839,7 @@ proc envelope*[P,S](ds: IntervalSetRef[P,S]; pt: P): IntervalRc[P,S] =
err() 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 ## Find the interval `[minPt,maxPt]` for some point `maxPt` in the interval
## set `ds` and remove it from `ds`. The function returns the deleted ## set `ds` and remove it from `ds`. The function returns the deleted
## interval (if any.) ## interval (if any.)
@ -915,21 +916,21 @@ iterator decreasing*[P,S](
# Public interval operators # 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 ## Compare intervals for equality
iv.least == jv.least and iv.last == jv.last 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 `==` ## Variant of `==`
if iv.isOk: if iv.isOk:
return iv.value == jv 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 `==` ## Variant of `==`
if jv.isOk: if jv.isOk:
return iv == jv.value return iv == jv.value
proc `==`*[P,S](iv, jv: IntervalRc[P,S]): bool = func `==`*[P,S](iv, jv: IntervalRc[P,S]): bool =
## Variant of `==` ## Variant of `==`
if iv.isOk: if iv.isOk:
if jv.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 ## Intersect itervals `iv` and `jv` if this operation results in a
## non-emty interval. Note that the `*` operation is associative, i.e. ## 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))) maxPt(jv.least,iv.least), minPt(jv.last,iv.last)))
err() 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 `*` ## Variant of `*`
if iv.isOk: if iv.isOk:
return iv.value * jv return iv.value * jv
err() 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 `*` ## Variant of `*`
if jv.isOk: if jv.isOk:
return iv * jv.value return iv * jv.value
err() 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 `*` ## Variant of `*`
if iv.isOk and jv.isOk: if iv.isOk and jv.isOk:
return iv.value * jv.value 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. ## Merge intervals `iv` and `jv` if this operation results in an interval.
## Note that the `+` operation is *not* associative, i.e. ## 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() 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 `+` ## Variant of `+`
if iv.isOk: if iv.isOk:
return iv.value + jv return iv.value + jv
err() 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 `+` ## Variant of `+`
if jv.isOk: if jv.isOk:
return iv + jv.value return iv + jv.value
err() 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 `+` ## Variant of `+`
if iv.isOk and jv.isOk: if iv.isOk and jv.isOk:
return iv.value + jv.value 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 ## Return the interval `iv` reduced by elements of `jv` if this operation
## results in a non-empty interval. ## results in a non-empty interval.
## Note that the `-` operation is *not* associative, i.e. ## 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() 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 `-` ## Variant of `-`
if iv.isOk: if iv.isOk:
return iv.value - jv return iv.value - jv
err() 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 `-` ## Variant of `-`
if jv.isOk: if jv.isOk:
return iv - jv.value return iv - jv.value
err() 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 `-` ## Variant of `-`
if iv.isOk and jv.isOk: if iv.isOk and jv.isOk:
return iv.value - jv.valu return iv.value - jv.valu
@ -1096,7 +1097,7 @@ proc `-`*[P,S](iv, jv: IntervalRc[P,S]): IntervalRc[P,S] =
# Public getters # 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 ## Cardinality (ie. length) of argument interval `iv`. If the argument
## interval `iv` is `[low(P),high(P)]`, the return value will be the scalar ## interval `iv` is `[low(P),high(P)]`, the return value will be the scalar
## *zero* (there are no empty intervals in this implementation.) ## *zero* (there are no empty intervals in this implementation.)
@ -1105,15 +1106,15 @@ proc len*[P,S](iv: Interval[P,S]): S =
else: else:
(iv.last - iv.least) + scalarOne (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 ## Left end, smallest point of `P` contained in the interval
iv.least 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 ## Right end, largest point of `P` contained in the interval
iv.last 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`. ## Accumulated size covered by intervals in the interval set `ds`.
## ##
## In the special case when there is only the single interval ## 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: else:
ds.ptsCount + scalarOne 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`. ## Number of disjunkt intervals (aka chunks) in the interval set `ds`.
result = ds.leftPos.len result = ds.leftPos.len
if ds.lastHigh: if ds.lastHigh:
@ -1138,7 +1139,7 @@ proc chunks*[P,S](ds: IntervalSetRef[P,S]): int =
# Public debugging functions # 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 ## Needed by `ds.verify()` for printing error messages
"[" & $p.left & "," & $p.right & ")" "[" & $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)])): when not compiles(writeFile("filename", @[byte(1)])):
proc writeFile*(filename: string, content: openArray[byte]) = proc writeFile*(filename: string, content: openArray[byte]) =
## Opens a file named `filename` for writing. Then writes the ## Opens a file named `filename` for writing. Then writes the
@ -11,4 +13,3 @@ when not compiles(writeFile("filename", @[byte(1)])):
close(f) close(f)
else: else:
raise newException(IOError, "cannot open: " & filename) 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 ## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) ## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT)) ## * MIT license ([LICENSE-MIT](LICENSE-MIT))
@ -12,8 +12,8 @@
{.push raises: [].} {.push raises: [].}
import algorithm import std/algorithm
import results import pkg/results
export results export results
when defined(windows): when defined(windows):

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -22,12 +22,12 @@
## semantics, this means that `=` performs a deep copy of the allocated queue ## 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. ## 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 export results
{.push raises: [].}
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.

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -12,10 +12,12 @@
## ============================= ## =============================
## ##
{.push raises: [].}
import import
std/tables, std/tables,
../keyed_queue, results,
../results ../keyed_queue
type type
KeyedQueueInfo* = enum ##\ KeyedQueueInfo* = enum ##\
@ -31,13 +33,11 @@ type
kQVfyPrvNxtExpected kQVfyPrvNxtExpected
kQVfyFirstExpected kQVfyFirstExpected
{.push raises: [].}
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions, debugging # Public functions, debugging
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc `$`*[K,V](item: KeyedQueueItem[K,V]): string = func `$`*[K,V](item: KeyedQueueItem[K,V]): string =
## Pretty print data container item. ## Pretty print data container item.
## ##
## :CAVEAT: ## :CAVEAT:
@ -51,8 +51,8 @@ proc `$`*[K,V](item: KeyedQueueItem[K,V]): string =
else: else:
"(" & $item.value & ", link[" & $item.prv & "," & $item.kNxt & "])" "(" & $item.value & ", link[" & $item.prv & "," & $item.kNxt & "])"
proc verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)] func verify*[K,V](rq: var KeyedQueue[K,V]): Result[void,(K,V,KeyedQueueInfo)]
{.gcsafe,raises: [KeyError].} = {.raises: [KeyError].} =
## Check for consistency. Returns an error unless the argument ## Check for consistency. Returns an error unless the argument
## queue `rq` is consistent. ## queue `rq` is consistent.
let tabLen = rq.tab.len let tabLen = rq.tab.len
@ -97,7 +97,7 @@ 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 = func dumpLinkedKeys*[K,V](rq: var KeyedQueue[K,V]): string =
## Dump the linked key list. This function depends on the `$` operator ## Dump the linked key list. This function depends on the `$` operator
## for converting a `K` type into a string ## for converting a `K` type into a string
if 0 < rq.tab.len: 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 # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # http://www.apache.org/licenses/LICENSE-2.0)
@ -47,9 +47,12 @@
## rc = w.next ## rc = w.next
## # optional clean up, see comments on the destroy() directive ## # optional clean up, see comments on the destroy() directive
## walk.destroy ## walk.destroy
##
{.push raises: [].}
import import
std/[tables], std/[tables],
pkg/results,
./sorted_set/[rbtree_delete, ./sorted_set/[rbtree_delete,
rbtree_desc, rbtree_desc,
rbtree_find, rbtree_find,
@ -57,8 +60,7 @@ import
rbtree_insert, rbtree_insert,
rbtree_reset, rbtree_reset,
rbtree_verify, rbtree_verify,
rbtree_walk], rbtree_walk]
./results
export export
RbInfo, RbInfo,
@ -93,18 +95,18 @@ type
# Private helpers # 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) 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) 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? # ... some smart stuff here?
c = nil # GC hint (if any, todo?) 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 ## Debugging only
a.slstCmp(b.key) < 0 a.slstCmp(b.key) < 0
@ -116,22 +118,22 @@ proc slstPr(code: RbInfo; ctxInfo: string) =
# Public functions, constructor # 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` ## Constructor for sorted list with key type `K` and data type `V`
sl.tree = newRbTreeRef[SortedSetItemRef[K,V],K]( sl.tree = newRbTreeRef[SortedSetItemRef[K,V],K](
cmp = proc(c: SortedSetItemRef[K,V]; k: K): int = c.slstCmp(k), cmp = proc(c: SortedSetItemRef[K,V]; k: K): int = c.slstCmp(k),
mkc = proc(k: K): SortedSetItemRef[K,V] = slstMkc[K,V](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()` ## Variant of `init()`
result.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`. ## Return a shallow copy of the argument list `sl`, then reset `sl`.
result.tree = sl.tree result.tree = sl.tree
sl.init 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 ## Reset list descriptor to its inital value. This function also de-registers
## and flushes all traversal descriptors of type `SortedSetWalkRef`. ## and flushes all traversal descriptors of type `SortedSetWalkRef`.
sl.tree.rbTreeReset(clup = proc(c: var SortedSetItemRef[K,V]) = c.slstClup) 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 # 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. ## Getter, extracts the key from the data container item.
data.key 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 ## Number of list elements
sl.tree.size 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 ## Helper, chreate `ok()` result
ok(SortedSetItemRef[K,V](key: key, data: data)) 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 # 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 ## Insert `key`, returns data container item with the `key`. Function fails
## if `key` exists in the list. ## if `key` exists in the list.
sl.tree.rbTreeInsert(key) 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 ## Insert or find `key`, returns data container item with the `key`. This
## function always succeeds (unless there is s problem with the list.) ## function always succeeds (unless there is s problem with the list.)
result = sl.tree.rbTreeInsert(key) result = sl.tree.rbTreeInsert(key)
if result.isErr: if result.isErr:
return sl.tree.rbTreeFindEq(key) 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 ## Delete `key` from list and return the data container item that was
## holding the `key` if it was deleted. ## holding the `key` if it was deleted.
sl.tree.rbTreeDelete(key) 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 ## Flush the sorted list, i.e. delete all entries. This function is
## more efficient than running a `delete()` loop. ## more efficient than running a `delete()` loop.
sl.tree.rbTreeFlush(clup = proc(c: var SortedSetItemRef[K,V]) = c.slstClup) 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 # 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 ## Find `key` in list, returns data container item with the `key` if it
## exists. ## exists.
sl.tree.rbTreeFindEq(key) 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 ## Find data container iten with *largest* key *less or equal* the argument
## `key` in list and return it if found. ## `key` in list and return it if found.
sl.tree.rbTreeFindLe(key) 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 ## Find data container item with *largest* key *less than* the argument
## `key` in list and return it if found. ## `key` in list and return it if found.
sl.tree.rbTreeFindLt(key) 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 ## Find data container item with *smallest* key *greater or equal* the
## argument `key` in list and return it if found. ## argument `key` in list and return it if found.
sl.tree.rbTreeFindGe(key) 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 ## Find data container item with *smallest* key *greater than* the argument
## `key` in list and return it if found. ## `key` in list and return it if found.
sl.tree.rbTreeFindGt(key) 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 # 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` ## Open traversal descriptor on list and register it on the 'SortedSet`
## descriptor. ## descriptor.
sl.tree.newRbWalk 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 ## De-register and close the traversal descriptor. This function renders
## the descriptor unusable, so it must be disposed of. ## the descriptor unusable, so it must be disposed of.
## ##
@ -227,7 +229,7 @@ proc destroy*[K,V](w: SortedSetWalkRef[K,V]) =
## rewound or destroyed. ## rewound or destroyed.
w.rbWalkDestroy 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 ## Rewind the traversal descriptor to the *least* list key and return
## the corresponding data container item. ## the corresponding data container item.
## ##
@ -235,7 +237,7 @@ proc first*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## list operations are reset. ## list operations are reset.
w.rbWalkFirst 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 ## Rewind the traversal descriptor to the *greatest* list key and return
## the corresponding data container item. ## the corresponding data container item.
## ##
@ -243,14 +245,14 @@ proc last*[K,V](w: SortedSetWalkRef[K,V]): SortedSetResult[K,V] =
## list operations are reset. ## list operations are reset.
w.rbWalkLast 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 ## Retrieve the *current* data container item. This is the same one retrieved
## last with any of the traversal functions returning the data container item. ## last with any of the traversal functions returning the data container item.
## ##
## Note that the current node becomes unavailable if it was recently deleted. ## Note that the current node becomes unavailable if it was recently deleted.
w.rbWalkCurrent 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 ## Move the traversal descriptor to the next *greater* key and return the
## corresponding data container item. If this is the first call after ## corresponding data container item. If this is the first call after
## `newWalk()`, then `w.first` is called implicitly. ## `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. ## causing this function to fail so that a rewind is needed.
w.rbWalkNext 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 ## Move the traversal descriptor to the next *smaller* key and return the
## corresponding data container item . If this is the first call after ## corresponding data container item . If this is the first call after
## `newWalk()`, then `w.last` is called implicitly. ## `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 # Public helpers, debugging
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc `$`*[K,V](casket: SortedSetItemRef[K,V]): string = func `$`*[K,V](casket: SortedSetItemRef[K,V]): string =
## Pretty printer ## Pretty printer
## ##
## :CAVEAT: ## :CAVEAT:
@ -284,7 +286,7 @@ proc `$`*[K,V](casket: SortedSetItemRef[K,V]): string =
return "nil" return "nil"
"(" & $casket.key & "," & $casket.data & ")" "(" & $casket.key & "," & $casket.data & ")"
proc `$`*[K,V](rc: SortedSetResult[K,V]): string = func `$`*[K,V](rc: SortedSetResult[K,V]): string =
## Pretty printer ## Pretty printer
## ##
## :CAVEAT: ## :CAVEAT:

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # 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 # at your option. This file may not be copied, modified, or distributed except
# according to those terms. # according to those terms.
import
./rbtree_desc,
./rbtree_rotate,
../results
{.push raises: [].} {.push raises: [].}
import
results,
./rbtree_desc,
./rbtree_rotate
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public # 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. ## 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 ## The node to be removed wraps a data container `casket` matching the
## argument `key`, i.e. `rbt.cmp(casket,key) == 0`. ## argument `key`, i.e. `rbt.cmp(casket,key) == 0`.

View File

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

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # 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 # at your option. This file may not be copied, modified, or distributed except
# according to those terms. # according to those terms.
import
./rbtree_desc,
../results
{.push raises: [].} {.push raises: [].}
import
results,
./rbtree_desc
# ----------------------------------------------------------------------- ------ # ----------------------------------------------------------------------- ------
# Public # 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 ## Generic red-black tree function. Search for a data container `casket` of
## type `C` in the red black tree which matches the argument `key`, ## 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 ## 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) 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 ## Generic red-black tree function. Search for the *smallest* data container
## `casket` of type `C` which is *greater or equal* to the specified argument ## `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 ## `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) 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 ## Generic red-black tree function. Search for the *smallest* data container
## of type `C` which is *strictly greater* than the specified argument `key` ## of type `C` which is *strictly greater* than the specified argument `key`
## in the red-black tree. ## in the red-black tree.
@ -148,7 +148,7 @@ proc rbTreeFindGt*[C,K](rbt: RbTreeRef[C,K]; key: K): RbResult[C] =
return err(rbNotFound) 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 ## Generic red-black tree function. Search for the *greatest* data container
## of type `C` which is *less than or equal* to the specified argument ## of type `C` which is *less than or equal* to the specified argument
## `key` in the red-black tree. ## `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) 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 ## Generic red-black tree function. Search for the *greatest* data container
## of type `C` which is *strictly less* than the specified argument `key` in ## of type `C` which is *strictly less* than the specified argument `key` in
## the red-black tree. ## the red-black tree.

View File

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

View File

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

View File

@ -1,5 +1,5 @@
# Nimbus # Nimbus
# Copyright (c) 2018-2023 Status Research & Development GmbH # Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of # Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0) # 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 # at your option. This file may not be copied, modified, or distributed except
# according to those terms. # according to those terms.
import
std/[tables],
./rbtree_desc,
../results
{.push raises: [].} {.push raises: [].}
import
results,
std/[tables],
./rbtree_desc
# ----------------------------------------------------------------------- ------ # ----------------------------------------------------------------------- ------
# Priv # 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. ## Traverse a red black tree in the user-specified direction.
## ##
## :Returns: ## :Returns:
@ -62,7 +62,7 @@ proc walkMove[C,K](w: RbWalkRef[C,K]; dir: RbDir): RbResult[C] =
return err(rbEndOfWalk) 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 ## Rewind the traversal position to the left-most or-right-most position
## as defined by the function argument `dir`. After successfully rewinding, ## as defined by the function argument `dir`. After successfully rewinding,
## the desriptor is in `start` position (see `walkClearDirty()`). ## 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) 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. ## Clear dirty flag if all traversal descriptors are in `start` postion.
if w.tree.dirty != 0: if w.tree.dirty != 0:
for u in w.tree.walks.values: for u in w.tree.walks.values:
@ -110,7 +110,7 @@ proc walkClearDirtyFlags[C,K](w: RbWalkRef[C,K]): bool =
# Public constructor/desctructor # 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 ## Generic red-black tree function, creates a new traversal descriptor on the
## argument red-black tree `rbt`. ## 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 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 ## Explicit destructor for current walk descriptor `w`. Clears the descriptor
## argument `w`. ## argument `w`.
## ##
@ -142,7 +142,7 @@ proc rbWalkDestroy*[C,K](w: RbWalkRef[C,K]) =
w.path = @[] w.path = @[]
w[].reset 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. ## Apply `rbWalkDestroy()` to all registered walk descriptors.
for w in rbt.walks.values: for w in rbt.walks.values:
w.tree = nil # notify GC (if any, todo?) w.tree = nil # notify GC (if any, todo?)
@ -151,7 +151,7 @@ proc rbWalkDestroyAll*[C,K](rbt: RbTreeRef[C,K]) =
w[].reset # clear w[].reset # clear
rbt.walks = initTable[uint,RbWalkRef[C,K]](1) 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()` ## Variant of `rbWalkDestroyAll()`
if not w.tree.isNil: if not w.tree.isNil:
w.tree.rbWalkDestroyAll w.tree.rbWalkDestroyAll
@ -160,7 +160,7 @@ proc rbWalkDestroyAll*[C,K](w: RbWalkRef[C,K]) =
# Public functions: rewind # 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 ## Move to the beginning of the tree (*smallest* item) and return the
## corresponding data container of type `C`. ## corresponding data container of type `C`.
## ##
@ -181,7 +181,7 @@ proc rbWalkFirst*[C,K](w: RbWalkRef[C,K]): RbResult[C] =
return w.walkStart(rbLeft) 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 ## Move to the end of the tree (*greatest* item) and return the corresponding
## data container of type `C`. ## 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 # 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 ## Retrieves the data container of type `C` for the current node. Note that
## the current node becomes unavailable if it was recently deleted. ## 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 ## 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()`, ## data container of type `C`. If this is the first call after `newRbWalk()`,
## then `rbWalkFirst()` is called implicitly. ## 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 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 ## Traverse to the next value in descending order and return the
## corresponding data container of type `C`. If this is the first call ## corresponding data container of type `C`. If this is the first call
## after `newRbWalk()`, then `rbWalkLast()` is called implicitly. ## 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 # Licensed and distributed under either of
# * MIT license: http://opensource.org/licenses/MIT # * MIT license: http://opensource.org/licenses/MIT
# * Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 # * 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. # at your option. This file may not be copied, modified, or distributed except according to those terms.
import std/[os, strutils] import std/[os, strutils]
import ../stew/io2, ../stew/results import pkg/results
import ../stew/io2
proc lockFileFlags(path: string, flags: set[OpenFlags], proc lockFileFlags(path: string, flags: set[OpenFlags],
lockType: LockType): IoResult[void] = lockType: LockType): IoResult[void] =