src/ptr_math

Author:Kaushal Modi
License:MIT

Introduction

This module implements basic Pointer Arithmetic functions.

Source

Repo link

The code in this module is mostly from this code snippet on Nim Forum.

Example:

import src/ptr_math
var
  a: array[0 .. 3, int]
  p = addr(a[0])        # p is pointing to a[0]

for i, _ in a:
  a[i] += i

p += 1                  # p is now pointing to a[1]
p[] = 100               # p[] is accessing the contents of a[1]
doAssert a[1] == 100

p[0] = 200              # .. so does p[0]
doAssert a[1] == 200

p[1] -= 2               # p[1] is accessing the contents of a[2]
doAssert a[2] == 0

p[2] += 50              # p[2] is accessing the contents of a[3]
doAssert a[3] == 53

p += 2                  # p is now pointing to a[3]
p[-1] += 77             # p[-1] is accessing the contents of a[2]
doAssert a[2] == 77

doAssert a == [0, 200, 77, 53]

Procs

proc `+`[S: SomeInteger](p: pointer; offset: S): pointer
Increments pointer p by offset that jumps memory in increments of single bytes.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = cast[pointer](addr(a[0]))
  p2 = p + (2*sizeof(MyObject))

doAssert cast[ptr MyObject](p2)[0].i == 500
doAssert cast[ptr MyObject](p2)[-1].f == 4.5
proc `+`[T; S: SomeInteger](p: ptr T; offset: S): ptr T
Increments pointer p by offset that jumps memory in increments of the size of T.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = addr(a[0])
  p2 = p + 2

doAssert p2[0].i == 500
doAssert p2[-1].f == 4.5
proc `+=`[S: SomeInteger](p: var pointer; offset: S)
Increments pointer p in place by offset that jumps memory in increments of single bytes.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = cast[pointer](addr(a[0]))

p += (1*sizeof(MyObject))
doAssert cast[ptr MyObject](p)[].i == 300
proc `+=`[T; S: SomeInteger](p: var ptr T; offset: S)
Increments pointer p in place by offset that jumps memory in increments of the size of T.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = addr(a[0])

p += 1
doAssert p[].i == 300
proc `-`[S: SomeInteger](p: pointer; offset: S): pointer
Decrements pointer p by offset that jumps memory in increments of single bytes.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = cast[pointer](addr(a[2]))
  p1 = p - (1*sizeof(MyObject))
doAssert cast[ptr MyObject](p1)[0].i == 300
doAssert cast[ptr MyObject](p1)[-1].b == true
doAssert cast[ptr MyObject](p1)[1].f == 6.7
proc `-`[T; S: SomeInteger](p: ptr T; offset: S): ptr T
Decrements pointer p by offset that jumps memory in increments of the size of T.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = addr(a[2])
  p1 = p - 1
doAssert p1[0].i == 300
doAssert p1[-1].b == true
doAssert p1[1].f == 6.7
proc `-=`[S: SomeInteger](p: var pointer; offset: S)
Decrements pointer p in place by offset that jumps memory in increments of single bytes.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = cast[pointer](addr(a[2]))

p -= (2*sizeof(MyObject))
doAssert cast[ptr MyObject](p)[].f == 2.3
proc `-=`[T; S: SomeInteger](p: var ptr T; offset: S)
Decrements pointer p in place by offset that jumps memory in increments of the size of T.

Example:

type
  MyObject = object
    i: int
    f: float
    b: bool
var
  a = [MyObject(i: 100, f: 2.3, b: true),
       MyObject(i: 300, f: 4.5, b: false),
       MyObject(i: 500, f: 6.7, b: true)]
  p = addr(a[2])

p -= 2
doAssert p[].f == 2.3
proc `[]`[T; S: SomeInteger](p: ptr T; offset: S): var T
Retrieves the value from p[offset].

Example:

var
  a = [1, 3, 5, 7]
  p = addr(a[0])

doAssert p[] == a[0]
doAssert p[0] == a[0]
doAssert p[2] == a[2]
proc `[]=`[T; S: SomeInteger](p: ptr T; offset: S; val: T)
Assigns the value at memory location pointed by p[offset].

Example:

var
  a = [1.3, -9.5, 100.0]
  p = addr(a[1])

p[0] = 123.456
doAssert a[1] == 123.456

Iterators

iterator items[T](start: ptr T; stopBefore: ptr T): lent T
Iterates over contiguous ptr Ts, from start excluding stopBefore. Yields immutable T.

Example:

var
  a = [1, 3, 5, 7]
  p = addr(a[0])
  e = p + a.len
  sum = 0
for i in items(p, e):
  sum += i
doAssert(sum == 16)
iterator items[T](uarray: UncheckedArray[T] | ptr T; len: SomeInteger): lent T
Iterates over UncheckedArray[T] or ptr T array with length. Yields immutable T.

Example:

let
  l = 4
  a = cast[ptr UncheckedArray[int]](alloc0(sizeof(int) * l))
  b = [1, 3, 5, 7]

copyMem(a, b[0].unsafeAddr, sizeof(int) * l) 
var i = 0
for val in items(a[], l):
  doAssert(val == b[i])
  inc i

let
  p = cast[ptr int](a)
i = 0
for val in items(p, l):
  doAssert(val == b[i])
  inc i
dealloc(a)
iterator mitems[T](p: ptr T; len: SomeInteger): var T
Iterates over ptr T with length. Yields mutable T.

Example:

var a = cast[ptr int](alloc0(sizeof(int) * 4))
for i in mitems(a, 4):
  inc i
doAssert(a[0] == 1)
dealloc(a)
iterator mitems[T](start: ptr T; stopBefore: ptr T): var T
Iterates over contiguous ptr Ts, from start excluding stopBefore. Yields mutable T.

Example:

var
  a = [1, 3, 5, 7]
  p = addr(a[0])
  e = p + a.len
  sum = 0
for i in mitems(p, e):
  inc i
for i in items(p, e):
  sum += i
doAssert(sum == 20)
iterator mitems[T](uarray: var UncheckedArray[T]; len: SomeInteger): var T
Iterates over var UncheckedArray[T] with length. Yields mutable T.

Example:

var a = cast[ptr UncheckedArray[int]](alloc0(sizeof(int) * 4))
for i in mitems(a[], 4):
  inc i
doAssert(a[0] == 1)
dealloc(a)
iterator mpairs[T; S: SomeInteger](p: ptr T; len: S): (S, var T)
Iterates over ptr T array with length. Yields (index, p[index]) with mutable T.

Example:

let
  l = 4
  a = [1, 3, 5, 7]
  b = cast[ptr int](alloc0(sizeof(int) * l))

copyMem(b, a[0].unsafeAddr, sizeof(int) * l) 

for i, val in mpairs(b, l):
  inc val
  doAssert(a[i] + 1 == val)
dealloc(b)
iterator mpairs[T; S: SomeInteger](uarray: var UncheckedArray[T]; len: S): (S,
    var T)
Iterates over var UncheckedArray[T] with length. Yields (index, uarray[index]) with mutable T.

Example:

let
  l = 4
  a = [1, 3, 5, 7]
  b = cast[ptr UncheckedArray[int]](alloc0(sizeof(int) * l))

copyMem(b, a[0].unsafeAddr, sizeof(int) * l) 

for i, val in mpairs(b[], l):
  inc val
  doAssert(a[i] + 1 == val)

dealloc(b)
iterator pairs[T; S: SomeInteger](uarray: UncheckedArray[T] | ptr T; len: S): (
    S, lent T)
Iterates over UncheckedArray[T] or ptr T array with length. Yields immutable (index, uarray[index]).

Example:

let
  l = 4
  a = [1, 3, 5, 7]
  b = cast[ptr UncheckedArray[int]](alloc0(sizeof(int) * l))
  c = cast[ptr int](alloc0(sizeof(int) * l))

copyMem(b, a[0].unsafeAddr, sizeof(int) * l) 
copyMem(c, a[0].unsafeAddr, sizeof(int) * l) 

for i, val in pairs(b[], l):
  doAssert(a[i] == val)

for i, val in pairs(c, l):
  doAssert(a[i] == val)
dealloc(b)
dealloc(c)

Macros

macro mrows(x: ForLoopStmt)
This for loop macro, iterates over UncheckedArray[untyped] or ptr untyped array arguments, with a length. It "yields" (index, src1[index], src2[index], ...) where the indexed values are mutable.

Example:

import std / sugar
var 
  l = 3
  a = [100, 300, 500]
  b = ['a', 'e', 'i']
  c = [1.1, 2.2, 3.3]
  pa = a[0].addr
  pb = b[0].addr
  pc = cast[ptr UncheckedArray[float]](c[0].addr)

var tuples:seq[(int, int, char, float)]
for i, ta, tb, tc in mrows(pa, pb, pc[], l):
  inc ta
  tuples.add (i, ta, tb, tc)

doAssert(tuples[^1][0] == l-1)
doAssert(tuples[^1][3] == 3.3)
doAssert(tuples[0][1] == 101)
macro rows(x: ForLoopStmt)
This for loop macro, iterates over UncheckedArray[untyped] or ptr untyped array arguments, with a length. It "yields" (index, src1[index], src2[index], ...).

Example:

var 
  l = 3
  a = [100, 300, 500]
  b = ['a', 'e', 'i']
  c = [1.1, 2.2, 3.3]
  pa = a[0].addr
  pb = b[0].addr
  pc = cast[ptr UncheckedArray[float]](c[0].addr)

var tuples:seq[(int, int, char, float)]
for i, ta, tb, tc in rows(pa, pb, pc[], l):
  tuples.add (i, ta, tb, tc)

doAssert(tuples[^1][0] == l-1)
doAssert(tuples[^1][3] == 3.3)