ArrRef: Have SliceMem copy container contents instead of trying to store a reference.
This commit is contained in:
parent
aaf89d2589
commit
adc21f8e29
2 changed files with 92 additions and 53 deletions
|
@ -1,12 +1,5 @@
|
|||
import std/strformat
|
||||
import std/hashes
|
||||
import ./slice_mem
|
||||
export slice_mem
|
||||
|
||||
const header_size = when not defined(release):
|
||||
sizeof(pointer)*2 + sizeof(Natural)
|
||||
else:
|
||||
sizeof(pointer)
|
||||
|
||||
type ArrRef*[T] = ref object
|
||||
byte_len: int
|
||||
|
@ -15,6 +8,8 @@ type ArrRef*[T] = ref object
|
|||
arr_ptr: ptr T
|
||||
arr: UncheckedArray[T]
|
||||
|
||||
const header_size = offsetof(ArrRef[byte], arr)
|
||||
|
||||
proc newArrRef*[T](size: Natural): ArrRef[T] =
|
||||
when defined(TCC):
|
||||
var r: ref pointer # workaround for tcc bug
|
||||
|
@ -130,9 +125,6 @@ proc hash*[T](arr: ArrRef[T]): Hash =
|
|||
hash(cast[ptr UncheckedArray[byte]](arr.arr.addr).toOpenArray(0, arr.len * sizeof(T) - 1))
|
||||
# TODO: for bigger elements, would a different algorithm be faster?
|
||||
|
||||
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:
|
||||
|
@ -152,3 +144,9 @@ proc concat*[T](arrs: seq[ArrRef[T]]): ArrRef[T] =
|
|||
template `&`*[T,U](a: ArrRef[T], b: ArrRef[U]): ArrRef[T] =
|
||||
concat(a, b.to(T))
|
||||
|
||||
import ./slice_mem
|
||||
export slice_mem
|
||||
|
||||
template `[]`*[T](a: ArrRef[T], s: Slice[int]): var SliceMem[T] =
|
||||
toSliceMem(a, s)
|
||||
|
||||
|
|
|
@ -7,23 +7,32 @@
|
|||
##
|
||||
## It's called "SliceMem" because "MemSlice" is taken by std/memfiles.
|
||||
|
||||
const arrRefCopyContainers {.booldefine.} = true
|
||||
|
||||
import std/strformat
|
||||
import std/hashes
|
||||
import std/macros # for noMove()
|
||||
import ./arr_ref
|
||||
|
||||
type
|
||||
SliceMem*[T] = object
|
||||
when arrRefCopyContainers:
|
||||
type SliceMem*[T] = object
|
||||
data*: ptr UncheckedArray[T]
|
||||
byte_len*: int
|
||||
destroy_ref: ref CustomDestructor
|
||||
|
||||
CustomDestructor = object
|
||||
destroy: proc() {.closure, raises: [].}
|
||||
data_ref: ArrRef[T]
|
||||
else:
|
||||
type
|
||||
SliceMem*[T] = object
|
||||
data*: ptr UncheckedArray[T]
|
||||
byte_len*: int
|
||||
destroy_ref: ref CustomDestructor
|
||||
|
||||
CustomDestructor = object
|
||||
destroy: proc() {.closure, raises: [].}
|
||||
|
||||
proc `=destroy`(s: var CustomDestructor) =
|
||||
if s.destroy != nil:
|
||||
s.destroy()
|
||||
s.destroy = nil
|
||||
proc `=destroy`(s: var CustomDestructor) =
|
||||
if s.destroy != nil:
|
||||
s.destroy()
|
||||
s.destroy = nil
|
||||
|
||||
template toInt(p: pointer): int = cast[int](p)
|
||||
# template toPointer(i: int): pointer = cast[pointer](p)
|
||||
|
@ -31,23 +40,31 @@ template toInt(p: pointer): int = cast[int](p)
|
|||
template toPointer*(s: SliceMem): pointer =
|
||||
s.data.pointer
|
||||
|
||||
proc newSliceMem*[T, U](container: sink U; p: pointer, byte_len: int): SliceMem[T] =
|
||||
proc newSliceMem*[T, U](container: sink U; p: pointer, byte_len: Natural): SliceMem[T] =
|
||||
## Create a SliceMem from a container, a pointer, and a length in bytes.
|
||||
runnableExamples:
|
||||
let x = @[1,2,3,4,5]
|
||||
# You can omit the [int] here because the container is iterable
|
||||
let s = newSliceMem[int](x, x[0].addr, x.len * sizeof(x[0]))
|
||||
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](p),
|
||||
byte_len: byte_len,
|
||||
destroy_ref: (ref CustomDestructor)(destroy: proc()=
|
||||
# we don't actually need to destroy the container here, destroying
|
||||
# the closure will do it for us. Calling it allows us to use custom
|
||||
# destructors though.
|
||||
discard container
|
||||
),
|
||||
)
|
||||
|
||||
when arrRefCopyContainers:
|
||||
result = SliceMem[T](
|
||||
byte_len: byte_len,
|
||||
data_ref: newArrRef[T](byte_len div sizeof(T)),
|
||||
)
|
||||
copyMem(result.data_ref.toPointer, p, byte_len)
|
||||
result.data = cast[ptr UncheckedArray[T]](result.data_ref.toPointer)
|
||||
else:
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](p),
|
||||
byte_len: byte_len,
|
||||
destroy_ref: (ref CustomDestructor)(destroy: proc()=
|
||||
# we don't actually need to destroy the container here, destroying
|
||||
# the closure will do it for us. Calling it allows us to use custom
|
||||
# destructors though.
|
||||
discard container
|
||||
),
|
||||
)
|
||||
|
||||
proc newSliceMem*[T](p: ptr T, len: int, destructor: proc() {.closure, raises: [].}): SliceMem[T] =
|
||||
# Create a SliceMem from a pointer to a type, a length, and a destructor
|
||||
|
@ -57,11 +74,20 @@ proc newSliceMem*[T](p: ptr T, len: int, destructor: proc() {.closure, raises: [
|
|||
proc destroy() = deallocShared(x)
|
||||
let s = newSliceMem(x, 5, destroy)
|
||||
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](p),
|
||||
byte_len: len * sizeof(T),
|
||||
destroy_ref: (ref CustomDestructor)(destroy: destructor),
|
||||
)
|
||||
when arrRefCopyContainers:
|
||||
result = SliceMem[T](
|
||||
byte_len: len * sizeof(T),
|
||||
data_ref: newArrRef[T](len),
|
||||
)
|
||||
copyMem(result.data_ref.toPointer, p, len * sizeof(T))
|
||||
result.data = cast[ptr UncheckedArray[T]](result.data_ref.toPointer)
|
||||
destructor()
|
||||
else:
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](p),
|
||||
byte_len: len * sizeof(T),
|
||||
destroy_ref: (ref CustomDestructor)(destroy: destructor),
|
||||
)
|
||||
|
||||
proc newSliceMem*(p: pointer, byte_len: int, destructor: proc() {.closure, raises: [].}): SliceMem[byte] {.inline.} =
|
||||
## Create a SliceMem from a pointer without type, a length in bytes, and a
|
||||
|
@ -76,13 +102,22 @@ proc newSliceMem*[T, U](container: sink U; first, last: pointer): SliceMem[T] =
|
|||
## Create a SliceMem from a container and the two pointers of the first and
|
||||
## last elements in the container. Usually you will want to use `toSliceMem`
|
||||
## instead.
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](first),
|
||||
byte_len: (last.toInt -% first.toInt) + sizeof(T),
|
||||
destroy_ref: (ref CustomDestructor)(destroy: proc()=
|
||||
discard container
|
||||
),
|
||||
)
|
||||
let byte_len = (last.toInt -% first.toInt) + sizeof(T)
|
||||
when arrRefCopyContainers:
|
||||
result = SliceMem[T](
|
||||
byte_len: byte_len,
|
||||
data_ref: newArrRef[T](byte_len div sizeof(T)),
|
||||
)
|
||||
copyMem(result.data_ref.toPointer, first, byte_len)
|
||||
result.data = cast[ptr UncheckedArray[T]](result.data_ref.toPointer)
|
||||
else:
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](first),
|
||||
byte_len: byte_len,
|
||||
destroy_ref: (ref CustomDestructor)(destroy: proc()=
|
||||
discard container
|
||||
),
|
||||
)
|
||||
|
||||
proc newSliceMem*[T](size: int): SliceMem[T] =
|
||||
## Create a SliceMem from new memory, similar to ArrRef[T].
|
||||
|
@ -91,15 +126,21 @@ proc newSliceMem*[T](size: int): SliceMem[T] =
|
|||
for i,n in s.mpairs:
|
||||
n = (i+1)*11
|
||||
doAssert $s == "SliceMem([11, 22, 33, 44, 55, 66, 77, 88, 99, 110])"
|
||||
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
|
||||
),
|
||||
)
|
||||
when arrRefCopyContainers:
|
||||
result = SliceMem[T](
|
||||
byte_len: size * sizeof(T),
|
||||
data_ref: newArrRef[T](size),
|
||||
)
|
||||
result.data = cast[ptr UncheckedArray[T]](result.data_ref.toPointer)
|
||||
else:
|
||||
var r = allocShared0 size * sizeof(T)
|
||||
result = SliceMem[T](
|
||||
data: cast[ptr UncheckedArray[T]](r),
|
||||
byte_len: size * sizeof(T),
|
||||
destroy_ref: (ref CustomDestructor)(destroy: proc()=
|
||||
deallocShared r
|
||||
),
|
||||
)
|
||||
|
||||
macro noMove(e: untyped): untyped =
|
||||
# remove the "move" from an expression
|
||||
|
|
Loading…
Reference in a new issue