diff --git a/changelog.md b/changelog.md index e905dd941b321..1f0c0c6eb9d5b 100644 --- a/changelog.md +++ b/changelog.md @@ -212,6 +212,7 @@ - Added `progressInterval` argument to `asyncftpclient.newAsyncFtpClient` to control the interval at which progress callbacks are called. +- Added `std/pointers` to handle `ptr[T]` variables without needing `cast`. ## Language changes diff --git a/lib/std/pointers.nim b/lib/std/pointers.nim new file mode 100644 index 0000000000000..6a8a83fa56e49 --- /dev/null +++ b/lib/std/pointers.nim @@ -0,0 +1,33 @@ +##[ +Convenience procs to process `ptr[T]` variables without requiring `cast`. +]## + +runnableExamples: + var a = @[10, 11, 12] + let pa = a[0].addr + doAssert (pa + 1)[] == 11 + doAssert pa[2] == 12 + pa[1] = 2 + doAssert a[1] == 2 + + +template `+`*[T](p: ptr T, off: int): ptr T = + type T = typeof(p[]) # pending https://github.com/nim-lang/Nim/issues/13527 + cast[ptr T](cast[ByteAddress](p) +% off * sizeof(T)) + +template `-`*[T](p: ptr T, off: int): ptr T = + type T = typeof(p[]) + cast[ptr T](cast[ByteAddress](p) -% off * sizeof(T)) + +template `[]`*[T](p: ptr T, off: int): T = + (p + off)[] + +template `[]=`*[T](p: ptr T, off: int, val: T) = + (p + off)[] = val + +proc `+=`*[T](p: var ptr T, off: int) {.inline.} = + # not a template to avoid double evaluation issues + p = p + off + +proc `-=`*[T](p: var ptr T, off: int) {.inline.} = + p = p - off diff --git a/tests/stdlib/tpointers.nim b/tests/stdlib/tpointers.nim new file mode 100644 index 0000000000000..ab7c36fdef8df --- /dev/null +++ b/tests/stdlib/tpointers.nim @@ -0,0 +1,19 @@ +import std/pointers + +block: + var a = @[10, 11, 12] + let pa = a[0].addr + let pb = pa + 1 + doAssert pb[] == 11 + doAssert (pb - 1)[] == 10 + pa[] = 100 + doAssert a[0] == 100 + doAssert pa[1] == 11 + + var pc = pa + pc += 1 + doAssert pc[] == 11 + doAssert pc[0] == 11 + doAssert pc == pb + pc -= 1 + doAssert pc == pa