Created
April 17, 2017 21:14
-
-
Save mratsim/0bf8a8ea45b36f7bf79c43c9a98411a2 to your computer and use it in GitHub Desktop.
Nim pointer arithmetic examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Author
mratsim
commented
May 27, 2017
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment