Skip to content

Instantly share code, notes, and snippets.

@mratsim
Created April 17, 2017 21:14
Show Gist options
  • Save mratsim/0bf8a8ea45b36f7bf79c43c9a98411a2 to your computer and use it in GitHub Desktop.
Save mratsim/0bf8a8ea45b36f7bf79c43c9a98411a2 to your computer and use it in GitHub Desktop.
Nim pointer arithmetic examples
# Deleted pointer arithmetic routines
# Original data structure with pointer:
type Tensor*[B: static[Backend]; T] = object
# Size of the datastructure is 32 bytes - perfect !
dimensions: seq[int]
strides: seq[int]
offset: ptr T
data: seq[T] # Perf note: seq are always deep copied on assignement.
##### Pointer arithmetic
# Adapted from Jehan: https://forum.nim-lang.org/t/1188#7366
# Added `-` to get integer offset of pointers
template ptrMath(body: untyped) =
{.push hint[XDeclaredButNotUsed]: off.}
# FIXME: XDeclaredButNotUsed pending: https://github.com/nim-lang/Nim/issues/4044
template `+`[T](p: ptr T, off: int): ptr T =
cast[ptr type(p[])](cast[ByteAddress](p) +% off * sizeof(p[]))
template `+=`[T](p: ptr T, off: int) =
p = p + off
# template `-`[T](p: ptr T, off: int): ptr T =
# cast[ptr type(p[])](cast[ByteAddress](p) -% off * sizeof(p[]))
#
# template `-=`[T](p: ptr T, off: int) =
# p = p - off
#
# template `[]`[T](p: ptr T, off: int): T =
# (p + off)[]
#
# template `[]=`[T](p: ptr T, off: int, val: T) =
# (p + off)[] = val
## TODO: Thorougly test this, especially with negative offset
template `-`[T](off_p: ptr T, p: ptr T): int =
(cast[ByteAddress](off_p) -% cast[ByteAddress](p)) div sizeof(p[])
{.pop.}
body
#############
# Apache Licence v2, Mamy André-Ratsimbazafy
template offset_to_index[B,T](t: Tensor[B,T]): int =
## Convert the pointer offset to the corresponding integer index
ptrMath:
# TODO: Thoroughly test this, especially with negative offsets
let d0: ptr T = unsafeAddr(t.data[0])
let offset_idx: int = t.offset - d0
offset_idx
############
# Apache Licence v2, Mamy André-Ratsimbazafy
## Strided indexing with pointers
template getIndex[B: static[Backend], T](t: Tensor[B,T], idx: varargs[int]): ptr T =
## Convert [i, j, k, l ...] to the proper index.
when compileOption("boundChecks"):
if idx.len != t.rank:
raise newException(IndexError, "Number of arguments: " &
$(idx.len) &
", is different from tensor rank: " &
$(t.rank))
var real_idx = t.offset
ptrMath:
for i,j in zip(t.strides,idx):
real_idx += i*j
when compileOption("boundChecks"):
let d0 = unsafeAddr(t.data[0])
if real_idx < d0 or real_idx >= d0 + t.data.len:
raise newException(IndexError, "Index out of bounds")
real_idx
proc `[]`*[B: static[Backend], T](t: Tensor[B,T], idx: varargs[int]): T {.noSideEffect.} =
## Get the value at input coordinates
return t.getIndex(idx)[]
proc `[]=`*[B: static[Backend], T](t: var Tensor[B,T], idx: varargs[int], val: T) {.noSideEffect.} =
## Set the value at input coordinates
t.getIndex(idx)[] = val
@mratsim
Copy link
Author

mratsim commented May 27, 2017

type CArray*{.unchecked.}[T] = array[0..0, T]
type CPtr*[T] = ptr CArray[T]

type SafeCPtr*[T] =
  object
    when not defined(release):
      size: int
    mem: CPtr[T]

proc safe*[T](p: CPtr[T], k: int): SafeCPtr[T] =
  when defined(release):
    SafeCPtr[T](mem: p)
  else:
    SafeCPtr[T](mem: p, size: k)

proc safe*[T](a: var openarray[T], k: int): SafeCPtr[T] =
  safe(cast[CPtr[T]](addr(a)), k)

proc `[]`*[T](p: SafeCPtr[T], k: int): T =
  when not defined(release):
    assert k < p.size
  result = p.mem[k]

proc `[]=`*[T](p: SafeCPtr[T], k: int, val: T) =
  when not defined(release):
    assert k < p.size
  p.mem[k] = val

var t: array[100, cint]
var a = safe(t, 50)
t[17] = 314
echo(a[17])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment