ArrRef and SliceMem: Add concat, suport for backward indexes, and fix $.

This commit is contained in:
Alberto Torres 2024-09-03 14:42:57 +02:00
parent d784dd3a52
commit e759f25519
2 changed files with 87 additions and 19 deletions

View file

@ -48,6 +48,12 @@ proc `[]=`*[T](a: ArrRef[T], i: Natural, v: T) =
raise newException(RangeDefect, &"index out of range: {i} >= {a.len}")
a.arr[i] = v
template `[]`*[T](a: ArrRef[T], i: BackwardsIndex): T =
a[a.len - i.int]
template `[]=`*[T](a: ArrRef[T], i: BackwardsIndex, v: T) =
a[a.len - i.int] = v
template toPointer*[T](a: ArrRef[T]): pointer = a.arr[0].addr
iterator items*[T](a: ArrRef[T]): T =
@ -68,7 +74,7 @@ iterator mpairs*[T](a: ArrRef[T]): tuple[key: int, val: var T] =
proc `$`*[T](a: ArrRef[T]): string =
result = "ArrRef(["
if a.endp != a.arr:
if a.byte_len >= sizeof(T):
let hi = a.high
for i in 0 ..< hi:
result &= $a[i] & ", "
@ -78,21 +84,6 @@ proc `$`*[T](a: ArrRef[T]): string =
template to*[T](a: ArrRef[T], U: untyped): untyped =
cast[ArrRef[U]](a)
# proc setCap*[T](a: var ArrRef[T], size: Natural) =
# let n = newArrRef[T](size)
# copyMem(n[0].addr, a[0].addr, min(size, a.len) * sizeof(T))
# a = n
# proc setGrow*[T](a: var ArrRef[T], i: Natural, v: T) =
# let p = cast[int](a) +% header_size +% sizeof(T) * i
# if p +% sizeof(T) > cast[int](a.endp):
# var cap = max(1, a.len)
# while i >= cap:
# if cap < 65535: cap *= 2
# else: cap = (cap * 3) div 2
# a.setCap cap
# cast[ptr T](p)[] = v
proc fill*[T](a: ArrRef[T], v: T) =
for i in a.low .. a.high: a[i] = v
@ -108,11 +99,14 @@ proc newArrRefWith*[T](size: Natural, v: T): ArrRef[T] =
result.arr_ptr = result.arr[0].addr
for i in result.low .. result.high: result[i] = v
proc newArrRef*[T](s: seq[T] | ArrRef[T]): ArrRef[T] =
proc newArrRef*[T](s: seq[T] | ArrRef[T] | openArray[T]): ArrRef[T] =
result = newArrRef[T](s.len)
if s.len != 0:
copyMem(result.arr.addr, s[0].addr, s.len * sizeof(T))
template newArrRef*[T](s: string): ArrRef[T] =
newArrRef[byte](s.toOpenArrayByte(0, s.high)).to(T)
proc newArrRef*[T; U: not T](s: seq[U]): ArrRef[T] =
result = newArrRef[T](s.len)
for i,v in s: result[i] = v.T
@ -139,3 +133,22 @@ proc hash*[T](arr: ArrRef[T]): Hash =
template `[]`*[T](a: ArrRef[T], s: Slice[int]): var SliceMem[T] =
toSliceMem(a, s)
template concatImpl(arrs: untyped) =
var total = 0
for a in arrs:
total += a.len
result = newArrRef[T](total)
var offset = 0
for a in arrs:
copyMem(result[offset].addr, a.toPointer, a.len * sizeof(T))
offset += a.len
proc concat*[T](arrs: varargs[ArrRef[T]]): ArrRef[T] =
concatImpl(arrs)
proc concat*[T](arrs: seq[ArrRef[T]]): ArrRef[T] =
concatImpl(arrs)
template `&`*[T,U](a: ArrRef[T], b: ArrRef[U]): ArrRef[T] =
concat(a, b.to(T))

View file

@ -26,6 +26,9 @@ proc `=destroy`(s: var CustomDestructor) =
template toInt(p: pointer): int = cast[int](p)
# template toPointer(i: int): pointer = cast[pointer](p)
template toPointer*(s: SliceMem): pointer =
s.data.pointer
proc newSliceMem*[T, U](container: sink U; p: pointer, byte_len: int): SliceMem[T] =
## Create a SliceMem from a container, a pointer, and a length in bytes.
result = SliceMem[T](
@ -67,6 +70,18 @@ proc newSliceMem*[T, U](container: sink U; first, last: pointer): SliceMem[T] =
),
)
proc newSliceMem*[T](size: int): SliceMem[T] =
## Create a SliceMem from new memory, similar to ArrRef[T].
var r: ref byte
unsafeNew(r, size * sizeof(T))
result = SliceMem[T](
data: cast[ptr UncheckedArray[T]](r),
byte_len: size * sizeof(T),
destroy_ref: (ref CustomDestructor)(destroy: proc()=
discard r
),
)
macro noMove(e: untyped): untyped =
if e.kind == nnkCommand and e[0].repr == "move": e[1]
else: e
@ -97,18 +112,33 @@ template low*[T](s: SliceMem[T]): Natural = 0
template high*[T](s: SliceMem[T]): int = s.len - 1
template `[]`*[T](s: SliceMem[T], i: Natural): var T =
proc `[]`*[T](s: SliceMem[T], i: Natural): var T {.inline.} =
when compileOption("rangechecks"):
if i >= s.len:
raise newException(RangeDefect, &"index out of range: {i} >= {s.len}")
s.data[i]
proc `[]=`*[T](s: SliceMem[T], i: Natural, v: T) =
proc `[]=`*[T](s: SliceMem[T], i: Natural, v: T) {.inline.} =
when compileOption("rangechecks"):
if i >= s.len:
raise newException(RangeDefect, &"index out of range: {i} >= {s.len}")
s.data[i] = v
template `[]`*[T](s: SliceMem[T], i: BackwardsIndex): T =
s[s.len - i.int]
template `[]=`*[T](s: SliceMem[T], i: BackwardsIndex, v: T) =
s[s.len - i.int] = v
template `[]`*[T](s: SliceMem[T], i: BackwardsIndex): T =
s[s.len - i.int]
template `[]=`*[T](s: SliceMem[T], i: BackwardsIndex, v: T) =
s[s.len - i.int] = v
template `[]`*[T](a: SliceMem[T], s: Slice[int]): var SliceMem[T] =
toSliceMem(a, s)
iterator items*[T](s: SliceMem[T]): T =
for i in 0 ..< s.len:
yield s.data[i]
@ -146,3 +176,28 @@ template toOpenArrayByte*(s: SliceMem): untyped =
template to*[T](s: SliceMem, typ: typedesc[T]): SliceMem[T] =
cast[SliceMem[T]](s)
template to*[T](s: seq[SliceMem], typ: typedesc[T]): seq[SliceMem[T]] =
var s2 = newSeqOfCap[SliceMem[T]](s.len)
for slice in s:
s2.add cast[SliceMem[T]](slice)
s2
template concatImpl(slices: untyped) =
var total = 0
for s in slices:
total += s.len
result = newSliceMem[T](total)
var offset = 0
for s in slices:
copyMem(result[offset].addr, s.data, s.len * sizeof(T))
offset += s.len
proc concat*[T](slices: varargs[SliceMem[T]]): SliceMem[T] =
concatImpl(slices)
proc concat*[T](slices: seq[SliceMem[T]]): SliceMem[T] =
concatImpl(slices)
template `&`*[T,U](a: SliceMem[T], b: SliceMem[U]): SliceMem[T] =
concat(a, b.to(T))