No matching definitions.

tur/numvec

stdlib/numvec.tur

typed numeric arrays: F64Vec, F32Vec, I64Vec, I32Vec, U8Vec.

GENERATED by tools/gen-numvec.py -- edit the template there, not this file.

A fixed-length, homogeneous, unboxed array of one numeric element type, in the manner of Racket's flvector. Each type is its own opaque handle over one C layout:

struct { int64_t len; T *data; void *raw; }   /* T = double, float, ... */

data is 32-byte aligned (raw is the malloc block it was carved from, and what free is given), so an aligned SIMD load is legal on it and gcc can skip its peeling prologue. The element is its real width: a U8Vec uses one byte a slot, not eight as a Vec does.

| Type | Element | Constructor | |--------|-----------|---------------------------| | F64Vec | float | (f64vec-new n init) | | F32Vec | float32 | (f32vec-new n init) | | I64Vec | int | (i64vec-new n init) | | I32Vec | int32 | (i32vec-new n init) | | U8Vec | uint8 | (u8vec-new n init) |

Every type has these operations, named by its prefix P (f64vec, f32vec, i64vec, i32vec, u8vec):

  • access: P-new, P-of, P-len, P-ref, P-set!, P-copy, P->vec, vec->P, P-show;
  • bulk kernels (phase N1), each one C loop that vectorizes at tur's default -O2 build as well as at --release: P-fill!, P-copy!, P-add!, P-sum, P-min, P-max, and except on U8Vec P-scale!, P-axpy!, P-dot; the float types add P-sum-ordered. A float reduction uses a fixed eight-lane order, so it is vectorized without -ffast-math and is bit-identical on every engine; integer arithmetic wraps;
  • loops (phase N2): P-for, P-for-index, P-fold, P-build, P-map!, which bind elements, never an index the program could get wrong, and go through the unchecked accessors (#fx{Unsafe}). Reads vectorize; P-build and P-map! store through a view (P-view, P-view-ref, P-view-set!), which is what lets a store loop vectorize too;
  • more kernels for common store loops, vectorized at -O2 on every compiler: P-sub!, P-add-scalar!, and except on U8Vec P-mul!.

Generic code over all five types goes through the NumArray class at the end of the module: na-len, na-ref, na-sum, ... and the loops na-for, na-fold, na-map!, with the element type as (Elem V).

Ownership: each type is ^affine with a Drop instance, so a let-bound array is freed at scope exit, exactly once, and moving it (returning it, passing it to a consumer) hands that duty on. The accessors take it ^borrow. P-free consumes an array early.

A temporary handed straight to an accessor that returns a number -- (f64vec-len (f64vec-new 4 0.0)) -- is freed after the call. One handed to anything else (P-copy, P->vec, P-show, or after an argument with side effects) has no owner and is not freed, so bind it first: (let [v (f64vec-new 4 0.0)] (f64vec-show v)) (docs/reported/borrowed-drop-temporary-leaks-outside-the-hoist.md).

A closure that captures an array the enclosing scope OWNS takes it over (the scope can no longer use it, and the closure frees it); one that captures a ^borrow parameter borrows it, and frees nothing.

Length is fixed at construction. Growth stays Vec's job; P->vec and vec->P convert. An index outside [0, len) panics, at the caller's line, on every engine.

Region stores: an element store writes a number, never a pointer, so the setters carry no TUR_REGION_NOTE (CLAUDE.md, "Region Store Hooks" covers a caller's word that can outlive a bracket -- a pointer).

Since: Phase N0 (simd-and-vectorization-plan)

defopaque affine

F64Vec

(defopaque ^affine F64Vec : int)

a fixed-length, unboxed array of 64-bit floats (float).

Opaque handle to a struct { int64_t len; double *data; void *raw; }. ^affine: freed at scope exit by its Drop instance. Use f64vec-new or f64vec-of to make one.

Since: Phase N0

defopaque

F64View

(defopaque F64View : int)

a view of a F64Vec's elements: the data pointer, for a store loop.

Made by f64vec-view, read and written by f64vec-view-ref / f64vec-view-set!. Not owned and not affine: it frees nothing, and it is valid exactly as long as the array it came from (an array never resizes, so its data never moves).

Since: Phase N2

defn

f64vec-new

(f64vec-new [n : int init : float])

allocate a F64Vec of n elements, every one init.

nelement count (>= 0; a negative or absurd n panics)
initthe value every slot starts with

A fresh F64Vec, owned by the caller and freed at scope exit.

(let [v (f64vec-new 4 7.1)]
  (f64vec-ref v 2))   ; => 7.1

Since: Phase N0

defmacro

f64vec-of

(f64vec-of [& xs])

a F64Vec holding the given elements, in order.

& xs -- zero or more elements of type float

A fresh F64Vec of length (count xs).

(let [v (f64vec-of 1.5 2.5)]
  (f64vec-len v))   ; => 2

Since: Phase N0

defn

f64vec-free

(f64vec-free [v : F64Vec])

release a F64Vec now, consuming it.

Rarely needed: a let-bound F64Vec is freed at scope exit. Call it to release a large array before the scope ends.

vthe array (consumed)
(f64vec-free v)

Since: Phase N0

definstance

Drop[F64Vec]

(definstance Drop [F64Vec])

free the array when a bound F64Vec dies unmoved.

defn

f64vec-len

(f64vec-len [^borrow v : F64Vec])

the element count of a F64Vec.

vthe array (borrowed)

The length fixed at construction.

(let [v (f64vec-new 8 7.1)]
  (f64vec-len v))   ; => 8

Since: Phase N0

defn

f64vec-ref

(f64vec-ref [^borrow v : F64Vec i : int])

the element at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics

The element, typed float.

(let [v (f64vec-of 1.5 2.5)]
  (f64vec-ref v 1))   ; => 2.5

Since: Phase N0

defn

f64vec-set!

(f64vec-set! [^borrow v : F64Vec i : int x : float])

store x at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics
xthe new element
(f64vec-set! v 0 7.1)

Since: Phase N0

defn

f64vec-copy

(f64vec-copy [^borrow v : F64Vec])

a fresh F64Vec with the same elements.

vthe array (borrowed)

An independent copy, owned by the caller.

(let [c (f64vec-copy v)] (f64vec-set! c 0 7.1))   ; v is unchanged

Since: Phase N0

defn

f64vec->vec-go__

(f64vec->vec-go__ [^borrow v : F64Vec out : (Vec float) i : int n : int] : (Vec float))

internal: push v[i..n) onto out.

defn

f64vec->vec

(f64vec->vec [^borrow v : F64Vec] : (Vec float))

copy a F64Vec into a fresh (Vec float).

vthe array (borrowed)

A growable Vec holding the same elements; the caller frees it.

(let [a (f64vec-of 1.5 2.5)
      v (f64vec->vec a)]
  (vec-len v))   ; => 2

Since: Phase N0

defn

vec->f64vec-go__

(vec->f64vec-go__ [^borrow out : F64Vec ^borrow src : (Vec float) i : int n : int] : nil)

internal: store src[i..n) into out.

defn

vec->f64vec

(vec->f64vec [^borrow src : (Vec float)] : F64Vec)

copy a (Vec float) into a fresh F64Vec.

srcthe Vec (borrowed)

A F64Vec of the same length and elements, owned by the caller.

(let [v (vec-of 1.5 2.5)
      a (vec->f64vec v)]
  (f64vec-len a))   ; => 2

Since: Phase N0

defn

f64vec-show-loop__

(f64vec-show-loop__ [^borrow v : F64Vec i : int n : int b : StringBuilder] : StringBuilder)

internal: push "e0 e1 ..." onto the builder.

defn

f64vec-show

(f64vec-show [^borrow v : F64Vec] : String)

render a F64Vec as an owned "#f64vec[a b c]" String.

vthe array (borrowed)

An owned String; release it with string/release.

(let [v (f64vec-of 1.5 2.5)]
  (f64vec-show v))   ; => String "#f64vec[1.5 2.5]"

Since: Phase N0

defn

f64vec-fill!

(f64vec-fill! [^borrow v : F64Vec x : float])

store x in every slot.

vthe array (borrowed)
xthe value
(f64vec-fill! v 1.5)

Since: Phase N1

defn

f64vec-copy!

(f64vec-copy! [^borrow dst : F64Vec ^borrow src : F64Vec])

copy src's elements into dst (same length, or a panic).

dstthe array written (borrowed)
srcthe array read (borrowed)
(f64vec-copy! dst src)

Since: Phase N1

defn

f64vec-scale!

(f64vec-scale! [^borrow v : F64Vec s : float])

multiply every element by s, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe factor
(f64vec-scale! v 2.5)

Since: Phase N1

defn

f64vec-add!

(f64vec-add! [^borrow dst : F64Vec ^borrow src : F64Vec])

dst[i] += src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array added (borrowed)
(f64vec-add! y x)

Since: Phase N1

defn

f64vec-axpy!

(f64vec-axpy! [^borrow dst : F64Vec s : float ^borrow src : F64Vec])

dst[i] += s * src[i] for every i (same length, or a panic).

Integer arithmetic wraps; the multiply and the add are not fused.

dstthe array updated (borrowed)
sthe factor
srcthe array scaled and added (borrowed)
(f64vec-axpy! y 2.5 x)

Since: Phase N1

defn

f64vec-sub!

(f64vec-sub! [^borrow dst : F64Vec ^borrow src : F64Vec])

dst[i] -= src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array subtracted (borrowed)
(f64vec-sub! y x)

Since: Phase N1

defn

f64vec-mul!

(f64vec-mul! [^borrow dst : F64Vec ^borrow src : F64Vec])

dst[i] *= src[i] for every i (same length, or a panic).

Element-wise, not a dot product. Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array multiplied in (borrowed)
(f64vec-mul! y x)

Since: Phase N1

defn

f64vec-add-scalar!

(f64vec-add-scalar! [^borrow v : F64Vec s : float])

add s to every element, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe value added
(f64vec-add-scalar! v 2.5)

Since: Phase N1

defn

f64vec-sum

(f64vec-sum [^borrow v : F64Vec])

the sum of the elements.

A float sum is computed in eight interleaved partial sums (lane k takes the elements i with i mod 8 = k), combined in one fixed tree: the same answer on every engine and machine, and vectorizable without -ffast-math. It can differ in the last bits from -sum-ordered, the left-to-right sum. An integer sum wraps modulo 2^64; a narrow element is widened to int first.

vthe array (borrowed)

A float.

(let [v (f64vec-of 1.5 2.5)] (f64vec-sum v))

Since: Phase N1

defn

f64vec-sum-ordered

(f64vec-sum-ordered [^borrow v : F64Vec])

the strict left-to-right sum of the elements.

vthe array (borrowed)

A float.

(let [v (f64vec-of 1.5 2.5)] (f64vec-sum-ordered v))

Since: Phase N1

defn

f64vec-dot

(f64vec-dot [^borrow a : F64Vec ^borrow b : F64Vec])

the dot product of two arrays (same length, or a panic).

Floats use the same eight-lane order as -sum. Integers wrap modulo 2^64; an int32 product is formed in 64 bits.

athe first array (borrowed)
bthe second array (borrowed)

A float.

(let [a (f64vec-of 1.5 2.5) b (f64vec-of 2.5 1.5)] (f64vec-dot a b))

Since: Phase N1

defn

f64vec-min

(f64vec-min [^borrow v : F64Vec])

the smallest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A float.

(let [v (f64vec-of 1.5 2.5)] (f64vec-min v))   ; => 1.5

Since: Phase N1

defn

f64vec-max

(f64vec-max [^borrow v : F64Vec])

the largest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A float.

(let [v (f64vec-of 1.5 2.5)] (f64vec-max v))   ; => 2.5

Since: Phase N1

defn

f64vec-ref-unchecked

(f64vec-ref-unchecked [^borrow v : F64Vec i : int])

the element at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The loop macros (-for, -fold, ...) use it where they have already checked the index. Its body calls nothing, so a call to it carries no panic check, and a loop of such calls can vectorize.

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len

A float.

(unsafe (f64vec-ref-unchecked v 0))

Since: Phase N2

defn

f64vec-set-unchecked!

(f64vec-set-unchecked! [^borrow v : F64Vec i : int x : float])

store x at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE (see the module header).

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (f64vec-set-unchecked! v 0 1.5))

Since: Phase N2

defn

f64vec-view

(f64vec-view [^borrow v : F64Vec])

a view of v's elements, for a loop that stores into it.

#fx{Unsafe}: nothing ties the view to the array, so a view used after the array is freed reads freed memory. Why it exists: a store through the array (-set-unchecked!) re-reads the header's data pointer, which the store might have overwritten as far as the C compiler knows, so the loop does not vectorize; a view is that pointer, read once. -build and -map! store through one; reach for it directly only for a store loop they do not cover.

vthe array (borrowed); the view is valid while v is

A F64View.

(let [v (f64vec-of 1.5 2.5) w (unsafe (f64vec-view v))] (unsafe (f64vec-view-ref w 1)))   ; => 2.5

Since: Phase N2

defn

f64vec-view-ref

(f64vec-view-ref [w : F64View i : int])

the element at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The interpreter checks the index anyway, as it does for -ref-unchecked.

wthe view
izero-based index; the caller proves 0 <= i < len

A float.

(unsafe (f64vec-view-ref w 0))

Since: Phase N2

defn

f64vec-view-set!

(f64vec-view-set! [w : F64View i : int x : float])

store x at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE. The interpreter checks the index anyway.

wthe view
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (f64vec-view-set! w 0 1.5))

Since: Phase N2

defmacro

f64vec-for

(f64vec-for [bv & body])

run body once per element of one or two F64Vecs.

(for [x v] body...) binds x to each element of v in order; (for [x v y w] body...) walks v and w together (same length, or a panic before the first pass). No index is in scope, so none can be wrong: the reads are f64vec-ref-unchecked, the body sees plain elements, and the loop carries no bounds check or panic test -- gcc can vectorize it at -O3. An array argument that is not a name is evaluated once, and freed after.

bindings[x v] or [x v y w]
bodythe forms to run per element
(let [v (f64vec-of 1.5 2.5)] (f64vec-for [x v] (println x)))

Since: Phase N2

defmacro

f64vec-for-index

(f64vec-for-index [bv & body])

run body once per element, with its index.

(for-index [i x v] body...) binds i (read-only) and x = v[i].

bindings[i x v]
bodythe forms to run per element
(let [v (f64vec-of 1.5 2.5)] (f64vec-for-index [i x v] (println i)))

Since: Phase N2

defmacro

f64vec-fold

(f64vec-fold [bv body])

fold the elements of a F64Vec into an accumulator.

(fold [acc init x v] body): acc starts at init, and for each element x in order becomes the value of body (which sees acc and x). The result is the final acc. A float sum written this way is the strict left fold, so gcc keeps it scalar; f64vec-sum is the vectorized one.

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(let [v (f64vec-of 1.5 2.5)] (f64vec-fold [n 0 x v] (+ n 1)))   ; => 2

Since: Phase N2

defmacro

f64vec-build

(f64vec-build [n bv expr])

a fresh F64Vec of n elements, element i the value of expr.

(build n [i] expr), after Racket's for/flvector: i is bound to each index in turn, and expr runs outside any unsafe. The stores go through a view (f64vec-view), so the loop vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc.

nthe length (evaluated once)
ithe index name, in a vector
exprthe element at i, of type float

A fresh F64Vec, owned by the caller.

(let [v (f64vec-build 3 [i] 1.5)] (f64vec-len v))   ; => 3

Since: Phase N2

defmacro

f64vec-map!

(f64vec-map! [dst bv expr])

store expr into dst[i] for every i, x bound to src[i].

(map! dst [x src] expr) stores into each slot of dst the value of expr with x bound to the element of src at the same index; (map! dst [x a y b] expr) walks two sources together. dst may be one of the sources: (map! v [x v] {x * 2}) maps in place. Every array has the same length, or a panic before the first element. The loop reads and stores through views (f64vec-view), so it vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc. expr runs outside any unsafe; an array argument that is not a name is evaluated once, and freed after the loop.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, of type float
(let [v (f64vec-of 1.5 2.5)] (f64vec-map! v [x v] x) (f64vec-ref v 1))   ; => 2.5

Since: Phase N2

defn

f64vec-same-len__

(f64vec-same-len__ [^borrow a : F64Vec ^borrow b : F64Vec])

internal: the common length of two arrays, or a panic.

defopaque affine

F32Vec

(defopaque ^affine F32Vec : int)

a fixed-length, unboxed array of 32-bit floats (float32).

Opaque handle to a struct { int64_t len; float *data; void *raw; }. ^affine: freed at scope exit by its Drop instance. Use f32vec-new or f32vec-of to make one.

Since: Phase N0

defopaque

F32View

(defopaque F32View : int)

a view of a F32Vec's elements: the data pointer, for a store loop.

Made by f32vec-view, read and written by f32vec-view-ref / f32vec-view-set!. Not owned and not affine: it frees nothing, and it is valid exactly as long as the array it came from (an array never resizes, so its data never moves).

Since: Phase N2

defn

f32vec-new

(f32vec-new [n : int init : float32])

allocate a F32Vec of n elements, every one init.

nelement count (>= 0; a negative or absurd n panics)
initthe value every slot starts with

A fresh F32Vec, owned by the caller and freed at scope exit.

(let [v (f32vec-new 4 (:: 3.25 float32))]
  (f32vec-ref v 2))   ; => (:: 3.25 float32)

Since: Phase N0

defmacro

f32vec-of

(f32vec-of [& xs])

a F32Vec holding the given elements, in order.

& xs -- zero or more elements of type float32

A fresh F32Vec of length (count xs).

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))]
  (f32vec-len v))   ; => 2

Since: Phase N0

defn

f32vec-free

(f32vec-free [v : F32Vec])

release a F32Vec now, consuming it.

Rarely needed: a let-bound F32Vec is freed at scope exit. Call it to release a large array before the scope ends.

vthe array (consumed)
(f32vec-free v)

Since: Phase N0

definstance

Drop[F32Vec]

(definstance Drop [F32Vec])

free the array when a bound F32Vec dies unmoved.

defn

f32vec-len

(f32vec-len [^borrow v : F32Vec])

the element count of a F32Vec.

vthe array (borrowed)

The length fixed at construction.

(let [v (f32vec-new 8 (:: 3.25 float32))]
  (f32vec-len v))   ; => 8

Since: Phase N0

defn

f32vec-ref

(f32vec-ref [^borrow v : F32Vec i : int])

the element at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics

The element, typed float32.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))]
  (f32vec-ref v 1))   ; => (:: 2.5 float32)

Since: Phase N0

defn

f32vec-set!

(f32vec-set! [^borrow v : F32Vec i : int x : float32])

store x at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics
xthe new element
(f32vec-set! v 0 (:: 3.25 float32))

Since: Phase N0

defn

f32vec-copy

(f32vec-copy [^borrow v : F32Vec])

a fresh F32Vec with the same elements.

vthe array (borrowed)

An independent copy, owned by the caller.

(let [c (f32vec-copy v)] (f32vec-set! c 0 (:: 3.25 float32)))   ; v is unchanged

Since: Phase N0

defn

f32vec->vec-go__

(f32vec->vec-go__ [^borrow v : F32Vec out : (Vec float32) i : int n : int] : (Vec float32))

internal: push v[i..n) onto out.

defn

f32vec->vec

(f32vec->vec [^borrow v : F32Vec] : (Vec float32))

copy a F32Vec into a fresh (Vec float32).

vthe array (borrowed)

A growable Vec holding the same elements; the caller frees it.

(let [a (f32vec-of (:: 1.5 float32) (:: 2.5 float32))
      v (f32vec->vec a)]
  (vec-len v))   ; => 2

Since: Phase N0

defn

vec->f32vec-go__

(vec->f32vec-go__ [^borrow out : F32Vec ^borrow src : (Vec float32) i : int n : int] : nil)

internal: store src[i..n) into out.

defn

vec->f32vec

(vec->f32vec [^borrow src : (Vec float32)] : F32Vec)

copy a (Vec float32) into a fresh F32Vec.

srcthe Vec (borrowed)

A F32Vec of the same length and elements, owned by the caller.

(let [v (vec-of (:: 1.5 float32) (:: 2.5 float32))
      a (vec->f32vec v)]
  (f32vec-len a))   ; => 2

Since: Phase N0

defn

f32vec-show-loop__

(f32vec-show-loop__ [^borrow v : F32Vec i : int n : int b : StringBuilder] : StringBuilder)

internal: push "e0 e1 ..." onto the builder.

defn

f32vec-show

(f32vec-show [^borrow v : F32Vec] : String)

render a F32Vec as an owned "#f32vec[a b c]" String.

vthe array (borrowed)

An owned String; release it with string/release.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))]
  (f32vec-show v))   ; => String "#f32vec[1.5 2.5]"

Since: Phase N0

defn

f32vec-fill!

(f32vec-fill! [^borrow v : F32Vec x : float32])

store x in every slot.

vthe array (borrowed)
xthe value
(f32vec-fill! v (:: 1.5 float32))

Since: Phase N1

defn

f32vec-copy!

(f32vec-copy! [^borrow dst : F32Vec ^borrow src : F32Vec])

copy src's elements into dst (same length, or a panic).

dstthe array written (borrowed)
srcthe array read (borrowed)
(f32vec-copy! dst src)

Since: Phase N1

defn

f32vec-scale!

(f32vec-scale! [^borrow v : F32Vec s : float32])

multiply every element by s, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe factor
(f32vec-scale! v (:: 2.5 float32))

Since: Phase N1

defn

f32vec-add!

(f32vec-add! [^borrow dst : F32Vec ^borrow src : F32Vec])

dst[i] += src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array added (borrowed)
(f32vec-add! y x)

Since: Phase N1

defn

f32vec-axpy!

(f32vec-axpy! [^borrow dst : F32Vec s : float32 ^borrow src : F32Vec])

dst[i] += s * src[i] for every i (same length, or a panic).

Integer arithmetic wraps; the multiply and the add are not fused.

dstthe array updated (borrowed)
sthe factor
srcthe array scaled and added (borrowed)
(f32vec-axpy! y (:: 2.5 float32) x)

Since: Phase N1

defn

f32vec-sub!

(f32vec-sub! [^borrow dst : F32Vec ^borrow src : F32Vec])

dst[i] -= src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array subtracted (borrowed)
(f32vec-sub! y x)

Since: Phase N1

defn

f32vec-mul!

(f32vec-mul! [^borrow dst : F32Vec ^borrow src : F32Vec])

dst[i] *= src[i] for every i (same length, or a panic).

Element-wise, not a dot product. Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array multiplied in (borrowed)
(f32vec-mul! y x)

Since: Phase N1

defn

f32vec-add-scalar!

(f32vec-add-scalar! [^borrow v : F32Vec s : float32])

add s to every element, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe value added
(f32vec-add-scalar! v (:: 2.5 float32))

Since: Phase N1

defn

f32vec-sum

(f32vec-sum [^borrow v : F32Vec])

the sum of the elements.

A float sum is computed in eight interleaved partial sums (lane k takes the elements i with i mod 8 = k), combined in one fixed tree: the same answer on every engine and machine, and vectorizable without -ffast-math. It can differ in the last bits from -sum-ordered, the left-to-right sum. An integer sum wraps modulo 2^64; a narrow element is widened to int first.

vthe array (borrowed)

A float32.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-sum v))

Since: Phase N1

defn

f32vec-sum-ordered

(f32vec-sum-ordered [^borrow v : F32Vec])

the strict left-to-right sum of the elements.

vthe array (borrowed)

A float32.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-sum-ordered v))

Since: Phase N1

defn

f32vec-dot

(f32vec-dot [^borrow a : F32Vec ^borrow b : F32Vec])

the dot product of two arrays (same length, or a panic).

Floats use the same eight-lane order as -sum. Integers wrap modulo 2^64; an int32 product is formed in 64 bits.

athe first array (borrowed)
bthe second array (borrowed)

A float32.

(let [a (f32vec-of (:: 1.5 float32) (:: 2.5 float32)) b (f32vec-of (:: 2.5 float32) (:: 1.5 float32))] (f32vec-dot a b))

Since: Phase N1

defn

f32vec-min

(f32vec-min [^borrow v : F32Vec])

the smallest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A float32.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-min v))   ; => (:: 1.5 float32)

Since: Phase N1

defn

f32vec-max

(f32vec-max [^borrow v : F32Vec])

the largest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A float32.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-max v))   ; => (:: 2.5 float32)

Since: Phase N1

defn

f32vec-ref-unchecked

(f32vec-ref-unchecked [^borrow v : F32Vec i : int])

the element at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The loop macros (-for, -fold, ...) use it where they have already checked the index. Its body calls nothing, so a call to it carries no panic check, and a loop of such calls can vectorize.

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len

A float32.

(unsafe (f32vec-ref-unchecked v 0))

Since: Phase N2

defn

f32vec-set-unchecked!

(f32vec-set-unchecked! [^borrow v : F32Vec i : int x : float32])

store x at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE (see the module header).

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (f32vec-set-unchecked! v 0 (:: 1.5 float32)))

Since: Phase N2

defn

f32vec-view

(f32vec-view [^borrow v : F32Vec])

a view of v's elements, for a loop that stores into it.

#fx{Unsafe}: nothing ties the view to the array, so a view used after the array is freed reads freed memory. Why it exists: a store through the array (-set-unchecked!) re-reads the header's data pointer, which the store might have overwritten as far as the C compiler knows, so the loop does not vectorize; a view is that pointer, read once. -build and -map! store through one; reach for it directly only for a store loop they do not cover.

vthe array (borrowed); the view is valid while v is

A F32View.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32)) w (unsafe (f32vec-view v))] (unsafe (f32vec-view-ref w 1)))   ; => (:: 2.5 float32)

Since: Phase N2

defn

f32vec-view-ref

(f32vec-view-ref [w : F32View i : int])

the element at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The interpreter checks the index anyway, as it does for -ref-unchecked.

wthe view
izero-based index; the caller proves 0 <= i < len

A float32.

(unsafe (f32vec-view-ref w 0))

Since: Phase N2

defn

f32vec-view-set!

(f32vec-view-set! [w : F32View i : int x : float32])

store x at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE. The interpreter checks the index anyway.

wthe view
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (f32vec-view-set! w 0 (:: 1.5 float32)))

Since: Phase N2

defmacro

f32vec-for

(f32vec-for [bv & body])

run body once per element of one or two F32Vecs.

(for [x v] body...) binds x to each element of v in order; (for [x v y w] body...) walks v and w together (same length, or a panic before the first pass). No index is in scope, so none can be wrong: the reads are f32vec-ref-unchecked, the body sees plain elements, and the loop carries no bounds check or panic test -- gcc can vectorize it at -O3. An array argument that is not a name is evaluated once, and freed after.

bindings[x v] or [x v y w]
bodythe forms to run per element
(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-for [x v] (println x)))

Since: Phase N2

defmacro

f32vec-for-index

(f32vec-for-index [bv & body])

run body once per element, with its index.

(for-index [i x v] body...) binds i (read-only) and x = v[i].

bindings[i x v]
bodythe forms to run per element
(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-for-index [i x v] (println i)))

Since: Phase N2

defmacro

f32vec-fold

(f32vec-fold [bv body])

fold the elements of a F32Vec into an accumulator.

(fold [acc init x v] body): acc starts at init, and for each element x in order becomes the value of body (which sees acc and x). The result is the final acc. A float sum written this way is the strict left fold, so gcc keeps it scalar; f32vec-sum is the vectorized one.

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-fold [n 0 x v] (+ n 1)))   ; => 2

Since: Phase N2

defmacro

f32vec-build

(f32vec-build [n bv expr])

a fresh F32Vec of n elements, element i the value of expr.

(build n [i] expr), after Racket's for/flvector: i is bound to each index in turn, and expr runs outside any unsafe. The stores go through a view (f32vec-view), so the loop vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc.

nthe length (evaluated once)
ithe index name, in a vector
exprthe element at i, of type float32

A fresh F32Vec, owned by the caller.

(let [v (f32vec-build 3 [i] (:: 1.5 float32))] (f32vec-len v))   ; => 3

Since: Phase N2

defmacro

f32vec-map!

(f32vec-map! [dst bv expr])

store expr into dst[i] for every i, x bound to src[i].

(map! dst [x src] expr) stores into each slot of dst the value of expr with x bound to the element of src at the same index; (map! dst [x a y b] expr) walks two sources together. dst may be one of the sources: (map! v [x v] {x * 2}) maps in place. Every array has the same length, or a panic before the first element. The loop reads and stores through views (f32vec-view), so it vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc. expr runs outside any unsafe; an array argument that is not a name is evaluated once, and freed after the loop.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, of type float32
(let [v (f32vec-of (:: 1.5 float32) (:: 2.5 float32))] (f32vec-map! v [x v] x) (f32vec-ref v 1))   ; => (:: 2.5 float32)

Since: Phase N2

defn

f32vec-same-len__

(f32vec-same-len__ [^borrow a : F32Vec ^borrow b : F32Vec])

internal: the common length of two arrays, or a panic.

defopaque affine

I64Vec

(defopaque ^affine I64Vec : int)

a fixed-length, unboxed array of 64-bit integers (int).

Opaque handle to a struct { int64_t len; int64_t *data; void *raw; }. ^affine: freed at scope exit by its Drop instance. Use i64vec-new or i64vec-of to make one.

Since: Phase N0

defopaque

I64View

(defopaque I64View : int)

a view of a I64Vec's elements: the data pointer, for a store loop.

Made by i64vec-view, read and written by i64vec-view-ref / i64vec-view-set!. Not owned and not affine: it frees nothing, and it is valid exactly as long as the array it came from (an array never resizes, so its data never moves).

Since: Phase N2

defn

i64vec-new

(i64vec-new [n : int init : int])

allocate a I64Vec of n elements, every one init.

nelement count (>= 0; a negative or absurd n panics)
initthe value every slot starts with

A fresh I64Vec, owned by the caller and freed at scope exit.

(let [v (i64vec-new 4 7)]
  (i64vec-ref v 2))   ; => 7

Since: Phase N0

defmacro

i64vec-of

(i64vec-of [& xs])

a I64Vec holding the given elements, in order.

& xs -- zero or more elements of type int

A fresh I64Vec of length (count xs).

(let [v (i64vec-of 1 2)]
  (i64vec-len v))   ; => 2

Since: Phase N0

defn

i64vec-free

(i64vec-free [v : I64Vec])

release a I64Vec now, consuming it.

Rarely needed: a let-bound I64Vec is freed at scope exit. Call it to release a large array before the scope ends.

vthe array (consumed)
(i64vec-free v)

Since: Phase N0

definstance

Drop[I64Vec]

(definstance Drop [I64Vec])

free the array when a bound I64Vec dies unmoved.

defn

i64vec-len

(i64vec-len [^borrow v : I64Vec])

the element count of a I64Vec.

vthe array (borrowed)

The length fixed at construction.

(let [v (i64vec-new 8 7)]
  (i64vec-len v))   ; => 8

Since: Phase N0

defn

i64vec-ref

(i64vec-ref [^borrow v : I64Vec i : int])

the element at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics

The element, typed int.

(let [v (i64vec-of 1 2)]
  (i64vec-ref v 1))   ; => 2

Since: Phase N0

defn

i64vec-set!

(i64vec-set! [^borrow v : I64Vec i : int x : int])

store x at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics
xthe new element
(i64vec-set! v 0 7)

Since: Phase N0

defn

i64vec-copy

(i64vec-copy [^borrow v : I64Vec])

a fresh I64Vec with the same elements.

vthe array (borrowed)

An independent copy, owned by the caller.

(let [c (i64vec-copy v)] (i64vec-set! c 0 7))   ; v is unchanged

Since: Phase N0

defn

i64vec->vec-go__

(i64vec->vec-go__ [^borrow v : I64Vec out : (Vec int) i : int n : int] : (Vec int))

internal: push v[i..n) onto out.

defn

i64vec->vec

(i64vec->vec [^borrow v : I64Vec] : (Vec int))

copy a I64Vec into a fresh (Vec int).

vthe array (borrowed)

A growable Vec holding the same elements; the caller frees it.

(let [a (i64vec-of 1 2)
      v (i64vec->vec a)]
  (vec-len v))   ; => 2

Since: Phase N0

defn

vec->i64vec-go__

(vec->i64vec-go__ [^borrow out : I64Vec ^borrow src : (Vec int) i : int n : int] : nil)

internal: store src[i..n) into out.

defn

vec->i64vec

(vec->i64vec [^borrow src : (Vec int)] : I64Vec)

copy a (Vec int) into a fresh I64Vec.

srcthe Vec (borrowed)

A I64Vec of the same length and elements, owned by the caller.

(let [v (vec-of 1 2)
      a (vec->i64vec v)]
  (i64vec-len a))   ; => 2

Since: Phase N0

defn

i64vec-show-loop__

(i64vec-show-loop__ [^borrow v : I64Vec i : int n : int b : StringBuilder] : StringBuilder)

internal: push "e0 e1 ..." onto the builder.

defn

i64vec-show

(i64vec-show [^borrow v : I64Vec] : String)

render a I64Vec as an owned "#i64vec[a b c]" String.

vthe array (borrowed)

An owned String; release it with string/release.

(let [v (i64vec-of 1 2)]
  (i64vec-show v))   ; => String "#i64vec[1 2]"

Since: Phase N0

defn

i64vec-fill!

(i64vec-fill! [^borrow v : I64Vec x : int])

store x in every slot.

vthe array (borrowed)
xthe value
(i64vec-fill! v 1)

Since: Phase N1

defn

i64vec-copy!

(i64vec-copy! [^borrow dst : I64Vec ^borrow src : I64Vec])

copy src's elements into dst (same length, or a panic).

dstthe array written (borrowed)
srcthe array read (borrowed)
(i64vec-copy! dst src)

Since: Phase N1

defn

i64vec-scale!

(i64vec-scale! [^borrow v : I64Vec s : int])

multiply every element by s, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe factor
(i64vec-scale! v 2)

Since: Phase N1

defn

i64vec-add!

(i64vec-add! [^borrow dst : I64Vec ^borrow src : I64Vec])

dst[i] += src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array added (borrowed)
(i64vec-add! y x)

Since: Phase N1

defn

i64vec-axpy!

(i64vec-axpy! [^borrow dst : I64Vec s : int ^borrow src : I64Vec])

dst[i] += s * src[i] for every i (same length, or a panic).

Integer arithmetic wraps; the multiply and the add are not fused.

dstthe array updated (borrowed)
sthe factor
srcthe array scaled and added (borrowed)
(i64vec-axpy! y 2 x)

Since: Phase N1

defn

i64vec-sub!

(i64vec-sub! [^borrow dst : I64Vec ^borrow src : I64Vec])

dst[i] -= src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array subtracted (borrowed)
(i64vec-sub! y x)

Since: Phase N1

defn

i64vec-mul!

(i64vec-mul! [^borrow dst : I64Vec ^borrow src : I64Vec])

dst[i] *= src[i] for every i (same length, or a panic).

Element-wise, not a dot product. Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array multiplied in (borrowed)
(i64vec-mul! y x)

Since: Phase N1

defn

i64vec-add-scalar!

(i64vec-add-scalar! [^borrow v : I64Vec s : int])

add s to every element, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe value added
(i64vec-add-scalar! v 2)

Since: Phase N1

defn

i64vec-sum

(i64vec-sum [^borrow v : I64Vec])

the sum of the elements.

A float sum is computed in eight interleaved partial sums (lane k takes the elements i with i mod 8 = k), combined in one fixed tree: the same answer on every engine and machine, and vectorizable without -ffast-math. It can differ in the last bits from -sum-ordered, the left-to-right sum. An integer sum wraps modulo 2^64; a narrow element is widened to int first.

vthe array (borrowed)

A int.

(let [v (i64vec-of 1 2)] (i64vec-sum v))

Since: Phase N1

defn

i64vec-dot

(i64vec-dot [^borrow a : I64Vec ^borrow b : I64Vec])

the dot product of two arrays (same length, or a panic).

Floats use the same eight-lane order as -sum. Integers wrap modulo 2^64; an int32 product is formed in 64 bits.

athe first array (borrowed)
bthe second array (borrowed)

A int.

(let [a (i64vec-of 1 2) b (i64vec-of 2 1)] (i64vec-dot a b))

Since: Phase N1

defn

i64vec-min

(i64vec-min [^borrow v : I64Vec])

the smallest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A int.

(let [v (i64vec-of 1 2)] (i64vec-min v))   ; => 1

Since: Phase N1

defn

i64vec-max

(i64vec-max [^borrow v : I64Vec])

the largest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A int.

(let [v (i64vec-of 1 2)] (i64vec-max v))   ; => 2

Since: Phase N1

defn

i64vec-ref-unchecked

(i64vec-ref-unchecked [^borrow v : I64Vec i : int])

the element at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The loop macros (-for, -fold, ...) use it where they have already checked the index. Its body calls nothing, so a call to it carries no panic check, and a loop of such calls can vectorize.

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len

A int.

(unsafe (i64vec-ref-unchecked v 0))

Since: Phase N2

defn

i64vec-set-unchecked!

(i64vec-set-unchecked! [^borrow v : I64Vec i : int x : int])

store x at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE (see the module header).

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (i64vec-set-unchecked! v 0 1))

Since: Phase N2

defn

i64vec-view

(i64vec-view [^borrow v : I64Vec])

a view of v's elements, for a loop that stores into it.

#fx{Unsafe}: nothing ties the view to the array, so a view used after the array is freed reads freed memory. Why it exists: a store through the array (-set-unchecked!) re-reads the header's data pointer, which the store might have overwritten as far as the C compiler knows, so the loop does not vectorize; a view is that pointer, read once. -build and -map! store through one; reach for it directly only for a store loop they do not cover.

vthe array (borrowed); the view is valid while v is

A I64View.

(let [v (i64vec-of 1 2) w (unsafe (i64vec-view v))] (unsafe (i64vec-view-ref w 1)))   ; => 2

Since: Phase N2

defn

i64vec-view-ref

(i64vec-view-ref [w : I64View i : int])

the element at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The interpreter checks the index anyway, as it does for -ref-unchecked.

wthe view
izero-based index; the caller proves 0 <= i < len

A int.

(unsafe (i64vec-view-ref w 0))

Since: Phase N2

defn

i64vec-view-set!

(i64vec-view-set! [w : I64View i : int x : int])

store x at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE. The interpreter checks the index anyway.

wthe view
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (i64vec-view-set! w 0 1))

Since: Phase N2

defmacro

i64vec-for

(i64vec-for [bv & body])

run body once per element of one or two I64Vecs.

(for [x v] body...) binds x to each element of v in order; (for [x v y w] body...) walks v and w together (same length, or a panic before the first pass). No index is in scope, so none can be wrong: the reads are i64vec-ref-unchecked, the body sees plain elements, and the loop carries no bounds check or panic test -- gcc can vectorize it at -O3. An array argument that is not a name is evaluated once, and freed after.

bindings[x v] or [x v y w]
bodythe forms to run per element
(let [v (i64vec-of 1 2)] (i64vec-for [x v] (println x)))

Since: Phase N2

defmacro

i64vec-for-index

(i64vec-for-index [bv & body])

run body once per element, with its index.

(for-index [i x v] body...) binds i (read-only) and x = v[i].

bindings[i x v]
bodythe forms to run per element
(let [v (i64vec-of 1 2)] (i64vec-for-index [i x v] (println i)))

Since: Phase N2

defmacro

i64vec-fold

(i64vec-fold [bv body])

fold the elements of a I64Vec into an accumulator.

(fold [acc init x v] body): acc starts at init, and for each element x in order becomes the value of body (which sees acc and x). The result is the final acc. A float sum written this way is the strict left fold, so gcc keeps it scalar; i64vec-sum is the vectorized one.

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(let [v (i64vec-of 1 2)] (i64vec-fold [n 0 x v] (+ n 1)))   ; => 2

Since: Phase N2

defmacro

i64vec-build

(i64vec-build [n bv expr])

a fresh I64Vec of n elements, element i the value of expr.

(build n [i] expr), after Racket's for/flvector: i is bound to each index in turn, and expr runs outside any unsafe. The stores go through a view (i64vec-view), so the loop vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc.

nthe length (evaluated once)
ithe index name, in a vector
exprthe element at i, of type int

A fresh I64Vec, owned by the caller.

(let [v (i64vec-build 3 [i] 1)] (i64vec-len v))   ; => 3

Since: Phase N2

defmacro

i64vec-map!

(i64vec-map! [dst bv expr])

store expr into dst[i] for every i, x bound to src[i].

(map! dst [x src] expr) stores into each slot of dst the value of expr with x bound to the element of src at the same index; (map! dst [x a y b] expr) walks two sources together. dst may be one of the sources: (map! v [x v] {x * 2}) maps in place. Every array has the same length, or a panic before the first element. The loop reads and stores through views (i64vec-view), so it vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc. expr runs outside any unsafe; an array argument that is not a name is evaluated once, and freed after the loop.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, of type int
(let [v (i64vec-of 1 2)] (i64vec-map! v [x v] x) (i64vec-ref v 1))   ; => 2

Since: Phase N2

defn

i64vec-same-len__

(i64vec-same-len__ [^borrow a : I64Vec ^borrow b : I64Vec])

internal: the common length of two arrays, or a panic.

defopaque affine

I32Vec

(defopaque ^affine I32Vec : int)

a fixed-length, unboxed array of 32-bit integers (int32).

Opaque handle to a struct { int64_t len; int32_t *data; void *raw; }. ^affine: freed at scope exit by its Drop instance. Use i32vec-new or i32vec-of to make one.

Since: Phase N0

defopaque

I32View

(defopaque I32View : int)

a view of a I32Vec's elements: the data pointer, for a store loop.

Made by i32vec-view, read and written by i32vec-view-ref / i32vec-view-set!. Not owned and not affine: it frees nothing, and it is valid exactly as long as the array it came from (an array never resizes, so its data never moves).

Since: Phase N2

defn

i32vec-new

(i32vec-new [n : int init : int32])

allocate a I32Vec of n elements, every one init.

nelement count (>= 0; a negative or absurd n panics)
initthe value every slot starts with

A fresh I32Vec, owned by the caller and freed at scope exit.

(let [v (i32vec-new 4 (as int32 7))]
  (i32vec-ref v 2))   ; => (as int32 7)

Since: Phase N0

defmacro

i32vec-of

(i32vec-of [& xs])

a I32Vec holding the given elements, in order.

& xs -- zero or more elements of type int32

A fresh I32Vec of length (count xs).

(let [v (i32vec-of (as int32 1) (as int32 2))]
  (i32vec-len v))   ; => 2

Since: Phase N0

defn

i32vec-free

(i32vec-free [v : I32Vec])

release a I32Vec now, consuming it.

Rarely needed: a let-bound I32Vec is freed at scope exit. Call it to release a large array before the scope ends.

vthe array (consumed)
(i32vec-free v)

Since: Phase N0

definstance

Drop[I32Vec]

(definstance Drop [I32Vec])

free the array when a bound I32Vec dies unmoved.

defn

i32vec-len

(i32vec-len [^borrow v : I32Vec])

the element count of a I32Vec.

vthe array (borrowed)

The length fixed at construction.

(let [v (i32vec-new 8 (as int32 7))]
  (i32vec-len v))   ; => 8

Since: Phase N0

defn

i32vec-ref

(i32vec-ref [^borrow v : I32Vec i : int])

the element at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics

The element, typed int32.

(let [v (i32vec-of (as int32 1) (as int32 2))]
  (i32vec-ref v 1))   ; => (as int32 2)

Since: Phase N0

defn

i32vec-set!

(i32vec-set! [^borrow v : I32Vec i : int x : int32])

store x at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics
xthe new element
(i32vec-set! v 0 (as int32 7))

Since: Phase N0

defn

i32vec-copy

(i32vec-copy [^borrow v : I32Vec])

a fresh I32Vec with the same elements.

vthe array (borrowed)

An independent copy, owned by the caller.

(let [c (i32vec-copy v)] (i32vec-set! c 0 (as int32 7)))   ; v is unchanged

Since: Phase N0

defn

i32vec->vec-go__

(i32vec->vec-go__ [^borrow v : I32Vec out : (Vec int32) i : int n : int] : (Vec int32))

internal: push v[i..n) onto out.

defn

i32vec->vec

(i32vec->vec [^borrow v : I32Vec] : (Vec int32))

copy a I32Vec into a fresh (Vec int32).

vthe array (borrowed)

A growable Vec holding the same elements; the caller frees it.

(let [a (i32vec-of (as int32 1) (as int32 2))
      v (i32vec->vec a)]
  (vec-len v))   ; => 2

Since: Phase N0

defn

vec->i32vec-go__

(vec->i32vec-go__ [^borrow out : I32Vec ^borrow src : (Vec int32) i : int n : int] : nil)

internal: store src[i..n) into out.

defn

vec->i32vec

(vec->i32vec [^borrow src : (Vec int32)] : I32Vec)

copy a (Vec int32) into a fresh I32Vec.

srcthe Vec (borrowed)

A I32Vec of the same length and elements, owned by the caller.

(let [v (vec-of (as int32 1) (as int32 2))
      a (vec->i32vec v)]
  (i32vec-len a))   ; => 2

Since: Phase N0

defn

i32vec-show-loop__

(i32vec-show-loop__ [^borrow v : I32Vec i : int n : int b : StringBuilder] : StringBuilder)

internal: push "e0 e1 ..." onto the builder.

defn

i32vec-show

(i32vec-show [^borrow v : I32Vec] : String)

render a I32Vec as an owned "#i32vec[a b c]" String.

vthe array (borrowed)

An owned String; release it with string/release.

(let [v (i32vec-of (as int32 1) (as int32 2))]
  (i32vec-show v))   ; => String "#i32vec[1 2]"

Since: Phase N0

defn

i32vec-fill!

(i32vec-fill! [^borrow v : I32Vec x : int32])

store x in every slot.

vthe array (borrowed)
xthe value
(i32vec-fill! v (as int32 1))

Since: Phase N1

defn

i32vec-copy!

(i32vec-copy! [^borrow dst : I32Vec ^borrow src : I32Vec])

copy src's elements into dst (same length, or a panic).

dstthe array written (borrowed)
srcthe array read (borrowed)
(i32vec-copy! dst src)

Since: Phase N1

defn

i32vec-scale!

(i32vec-scale! [^borrow v : I32Vec s : int32])

multiply every element by s, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe factor
(i32vec-scale! v (as int32 2))

Since: Phase N1

defn

i32vec-add!

(i32vec-add! [^borrow dst : I32Vec ^borrow src : I32Vec])

dst[i] += src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array added (borrowed)
(i32vec-add! y x)

Since: Phase N1

defn

i32vec-axpy!

(i32vec-axpy! [^borrow dst : I32Vec s : int32 ^borrow src : I32Vec])

dst[i] += s * src[i] for every i (same length, or a panic).

Integer arithmetic wraps; the multiply and the add are not fused.

dstthe array updated (borrowed)
sthe factor
srcthe array scaled and added (borrowed)
(i32vec-axpy! y (as int32 2) x)

Since: Phase N1

defn

i32vec-sub!

(i32vec-sub! [^borrow dst : I32Vec ^borrow src : I32Vec])

dst[i] -= src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array subtracted (borrowed)
(i32vec-sub! y x)

Since: Phase N1

defn

i32vec-mul!

(i32vec-mul! [^borrow dst : I32Vec ^borrow src : I32Vec])

dst[i] *= src[i] for every i (same length, or a panic).

Element-wise, not a dot product. Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array multiplied in (borrowed)
(i32vec-mul! y x)

Since: Phase N1

defn

i32vec-add-scalar!

(i32vec-add-scalar! [^borrow v : I32Vec s : int32])

add s to every element, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe value added
(i32vec-add-scalar! v (as int32 2))

Since: Phase N1

defn

i32vec-sum

(i32vec-sum [^borrow v : I32Vec])

the sum of the elements.

A float sum is computed in eight interleaved partial sums (lane k takes the elements i with i mod 8 = k), combined in one fixed tree: the same answer on every engine and machine, and vectorizable without -ffast-math. It can differ in the last bits from -sum-ordered, the left-to-right sum. An integer sum wraps modulo 2^64; a narrow element is widened to int first.

vthe array (borrowed)

A int.

(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-sum v))

Since: Phase N1

defn

i32vec-dot

(i32vec-dot [^borrow a : I32Vec ^borrow b : I32Vec])

the dot product of two arrays (same length, or a panic).

Floats use the same eight-lane order as -sum. Integers wrap modulo 2^64; an int32 product is formed in 64 bits.

athe first array (borrowed)
bthe second array (borrowed)

A int.

(let [a (i32vec-of (as int32 1) (as int32 2)) b (i32vec-of (as int32 2) (as int32 1))] (i32vec-dot a b))

Since: Phase N1

defn

i32vec-min

(i32vec-min [^borrow v : I32Vec])

the smallest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A int32.

(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-min v))   ; => (as int32 1)

Since: Phase N1

defn

i32vec-max

(i32vec-max [^borrow v : I32Vec])

the largest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A int32.

(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-max v))   ; => (as int32 2)

Since: Phase N1

defn

i32vec-ref-unchecked

(i32vec-ref-unchecked [^borrow v : I32Vec i : int])

the element at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The loop macros (-for, -fold, ...) use it where they have already checked the index. Its body calls nothing, so a call to it carries no panic check, and a loop of such calls can vectorize.

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len

A int32.

(unsafe (i32vec-ref-unchecked v 0))

Since: Phase N2

defn

i32vec-set-unchecked!

(i32vec-set-unchecked! [^borrow v : I32Vec i : int x : int32])

store x at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE (see the module header).

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (i32vec-set-unchecked! v 0 (as int32 1)))

Since: Phase N2

defn

i32vec-view

(i32vec-view [^borrow v : I32Vec])

a view of v's elements, for a loop that stores into it.

#fx{Unsafe}: nothing ties the view to the array, so a view used after the array is freed reads freed memory. Why it exists: a store through the array (-set-unchecked!) re-reads the header's data pointer, which the store might have overwritten as far as the C compiler knows, so the loop does not vectorize; a view is that pointer, read once. -build and -map! store through one; reach for it directly only for a store loop they do not cover.

vthe array (borrowed); the view is valid while v is

A I32View.

(let [v (i32vec-of (as int32 1) (as int32 2)) w (unsafe (i32vec-view v))] (unsafe (i32vec-view-ref w 1)))   ; => (as int32 2)

Since: Phase N2

defn

i32vec-view-ref

(i32vec-view-ref [w : I32View i : int])

the element at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The interpreter checks the index anyway, as it does for -ref-unchecked.

wthe view
izero-based index; the caller proves 0 <= i < len

A int32.

(unsafe (i32vec-view-ref w 0))

Since: Phase N2

defn

i32vec-view-set!

(i32vec-view-set! [w : I32View i : int x : int32])

store x at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE. The interpreter checks the index anyway.

wthe view
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (i32vec-view-set! w 0 (as int32 1)))

Since: Phase N2

defmacro

i32vec-for

(i32vec-for [bv & body])

run body once per element of one or two I32Vecs.

(for [x v] body...) binds x to each element of v in order; (for [x v y w] body...) walks v and w together (same length, or a panic before the first pass). No index is in scope, so none can be wrong: the reads are i32vec-ref-unchecked, the body sees plain elements, and the loop carries no bounds check or panic test -- gcc can vectorize it at -O3. An array argument that is not a name is evaluated once, and freed after.

bindings[x v] or [x v y w]
bodythe forms to run per element
(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-for [x v] (println x)))

Since: Phase N2

defmacro

i32vec-for-index

(i32vec-for-index [bv & body])

run body once per element, with its index.

(for-index [i x v] body...) binds i (read-only) and x = v[i].

bindings[i x v]
bodythe forms to run per element
(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-for-index [i x v] (println i)))

Since: Phase N2

defmacro

i32vec-fold

(i32vec-fold [bv body])

fold the elements of a I32Vec into an accumulator.

(fold [acc init x v] body): acc starts at init, and for each element x in order becomes the value of body (which sees acc and x). The result is the final acc. A float sum written this way is the strict left fold, so gcc keeps it scalar; i32vec-sum is the vectorized one.

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-fold [n 0 x v] (+ n 1)))   ; => 2

Since: Phase N2

defmacro

i32vec-build

(i32vec-build [n bv expr])

a fresh I32Vec of n elements, element i the value of expr.

(build n [i] expr), after Racket's for/flvector: i is bound to each index in turn, and expr runs outside any unsafe. The stores go through a view (i32vec-view), so the loop vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc.

nthe length (evaluated once)
ithe index name, in a vector
exprthe element at i, of type int32

A fresh I32Vec, owned by the caller.

(let [v (i32vec-build 3 [i] (as int32 1))] (i32vec-len v))   ; => 3

Since: Phase N2

defmacro

i32vec-map!

(i32vec-map! [dst bv expr])

store expr into dst[i] for every i, x bound to src[i].

(map! dst [x src] expr) stores into each slot of dst the value of expr with x bound to the element of src at the same index; (map! dst [x a y b] expr) walks two sources together. dst may be one of the sources: (map! v [x v] {x * 2}) maps in place. Every array has the same length, or a panic before the first element. The loop reads and stores through views (i32vec-view), so it vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc. expr runs outside any unsafe; an array argument that is not a name is evaluated once, and freed after the loop.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, of type int32
(let [v (i32vec-of (as int32 1) (as int32 2))] (i32vec-map! v [x v] x) (i32vec-ref v 1))   ; => (as int32 2)

Since: Phase N2

defn

i32vec-same-len__

(i32vec-same-len__ [^borrow a : I32Vec ^borrow b : I32Vec])

internal: the common length of two arrays, or a panic.

defopaque affine

U8Vec

(defopaque ^affine U8Vec : int)

a fixed-length, unboxed array of bytes (uint8).

Opaque handle to a struct { int64_t len; uint8_t *data; void *raw; }. ^affine: freed at scope exit by its Drop instance. Use u8vec-new or u8vec-of to make one.

Since: Phase N0

defopaque

U8View

(defopaque U8View : int)

a view of a U8Vec's elements: the data pointer, for a store loop.

Made by u8vec-view, read and written by u8vec-view-ref / u8vec-view-set!. Not owned and not affine: it frees nothing, and it is valid exactly as long as the array it came from (an array never resizes, so its data never moves).

Since: Phase N2

defn

u8vec-new

(u8vec-new [n : int init : uint8])

allocate a U8Vec of n elements, every one init.

nelement count (>= 0; a negative or absurd n panics)
initthe value every slot starts with

A fresh U8Vec, owned by the caller and freed at scope exit.

(let [v (u8vec-new 4 (as uint8 200))]
  (u8vec-ref v 2))   ; => (as uint8 200)

Since: Phase N0

defmacro

u8vec-of

(u8vec-of [& xs])

a U8Vec holding the given elements, in order.

& xs -- zero or more elements of type uint8

A fresh U8Vec of length (count xs).

(let [v (u8vec-of (as uint8 1) (as uint8 2))]
  (u8vec-len v))   ; => 2

Since: Phase N0

defn

u8vec-free

(u8vec-free [v : U8Vec])

release a U8Vec now, consuming it.

Rarely needed: a let-bound U8Vec is freed at scope exit. Call it to release a large array before the scope ends.

vthe array (consumed)
(u8vec-free v)

Since: Phase N0

definstance

Drop[U8Vec]

(definstance Drop [U8Vec])

free the array when a bound U8Vec dies unmoved.

defn

u8vec-len

(u8vec-len [^borrow v : U8Vec])

the element count of a U8Vec.

vthe array (borrowed)

The length fixed at construction.

(let [v (u8vec-new 8 (as uint8 200))]
  (u8vec-len v))   ; => 8

Since: Phase N0

defn

u8vec-ref

(u8vec-ref [^borrow v : U8Vec i : int])

the element at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics

The element, typed uint8.

(let [v (u8vec-of (as uint8 1) (as uint8 2))]
  (u8vec-ref v 1))   ; => (as uint8 2)

Since: Phase N0

defn

u8vec-set!

(u8vec-set! [^borrow v : U8Vec i : int x : uint8])

store x at index i (bounds-checked).

vthe array (borrowed)
izero-based index; outside [0, len) panics
xthe new element
(u8vec-set! v 0 (as uint8 200))

Since: Phase N0

defn

u8vec-copy

(u8vec-copy [^borrow v : U8Vec])

a fresh U8Vec with the same elements.

vthe array (borrowed)

An independent copy, owned by the caller.

(let [c (u8vec-copy v)] (u8vec-set! c 0 (as uint8 200)))   ; v is unchanged

Since: Phase N0

defn

u8vec->vec-go__

(u8vec->vec-go__ [^borrow v : U8Vec out : (Vec uint8) i : int n : int] : (Vec uint8))

internal: push v[i..n) onto out.

defn

u8vec->vec

(u8vec->vec [^borrow v : U8Vec] : (Vec uint8))

copy a U8Vec into a fresh (Vec uint8).

vthe array (borrowed)

A growable Vec holding the same elements; the caller frees it.

(let [a (u8vec-of (as uint8 1) (as uint8 2))
      v (u8vec->vec a)]
  (vec-len v))   ; => 2

Since: Phase N0

defn

vec->u8vec-go__

(vec->u8vec-go__ [^borrow out : U8Vec ^borrow src : (Vec uint8) i : int n : int] : nil)

internal: store src[i..n) into out.

defn

vec->u8vec

(vec->u8vec [^borrow src : (Vec uint8)] : U8Vec)

copy a (Vec uint8) into a fresh U8Vec.

srcthe Vec (borrowed)

A U8Vec of the same length and elements, owned by the caller.

(let [v (vec-of (as uint8 1) (as uint8 2))
      a (vec->u8vec v)]
  (u8vec-len a))   ; => 2

Since: Phase N0

defn

u8vec-show-loop__

(u8vec-show-loop__ [^borrow v : U8Vec i : int n : int b : StringBuilder] : StringBuilder)

internal: push "e0 e1 ..." onto the builder.

defn

u8vec-show

(u8vec-show [^borrow v : U8Vec] : String)

render a U8Vec as an owned "#u8vec[a b c]" String.

vthe array (borrowed)

An owned String; release it with string/release.

(let [v (u8vec-of (as uint8 1) (as uint8 2))]
  (u8vec-show v))   ; => String "#u8vec[1 2]"

Since: Phase N0

defn

u8vec-fill!

(u8vec-fill! [^borrow v : U8Vec x : uint8])

store x in every slot.

vthe array (borrowed)
xthe value
(u8vec-fill! v (as uint8 1))

Since: Phase N1

defn

u8vec-copy!

(u8vec-copy! [^borrow dst : U8Vec ^borrow src : U8Vec])

copy src's elements into dst (same length, or a panic).

dstthe array written (borrowed)
srcthe array read (borrowed)
(u8vec-copy! dst src)

Since: Phase N1

defn

u8vec-add!

(u8vec-add! [^borrow dst : U8Vec ^borrow src : U8Vec])

dst[i] += src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array added (borrowed)
(u8vec-add! y x)

Since: Phase N1

defn

u8vec-sub!

(u8vec-sub! [^borrow dst : U8Vec ^borrow src : U8Vec])

dst[i] -= src[i] for every i (same length, or a panic).

Integer arithmetic wraps; dst and src may be the same array.

dstthe array updated (borrowed)
srcthe array subtracted (borrowed)
(u8vec-sub! y x)

Since: Phase N1

defn

u8vec-add-scalar!

(u8vec-add-scalar! [^borrow v : U8Vec s : uint8])

add s to every element, in place.

Integer arithmetic wraps.

vthe array (borrowed)
sthe value added
(u8vec-add-scalar! v (as uint8 2))

Since: Phase N1

defn

u8vec-sum

(u8vec-sum [^borrow v : U8Vec])

the sum of the elements.

A float sum is computed in eight interleaved partial sums (lane k takes the elements i with i mod 8 = k), combined in one fixed tree: the same answer on every engine and machine, and vectorizable without -ffast-math. It can differ in the last bits from -sum-ordered, the left-to-right sum. An integer sum wraps modulo 2^64; a narrow element is widened to int first.

vthe array (borrowed)

A int.

(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-sum v))

Since: Phase N1

defn

u8vec-min

(u8vec-min [^borrow v : U8Vec])

the smallest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A uint8.

(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-min v))   ; => (as uint8 1)

Since: Phase N1

defn

u8vec-max

(u8vec-max [^borrow v : U8Vec])

the largest element (an empty array panics).

A NaN element makes the result NaN (the first NaN, by index). Which of two equal elements (0.0 and -0.0) is returned is fixed by the reduction order, the same on every engine.

vthe array (borrowed)

A uint8.

(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-max v))   ; => (as uint8 2)

Since: Phase N1

defn

u8vec-ref-unchecked

(u8vec-ref-unchecked [^borrow v : U8Vec i : int])

the element at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The loop macros (-for, -fold, ...) use it where they have already checked the index. Its body calls nothing, so a call to it carries no panic check, and a loop of such calls can vectorize.

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len

A uint8.

(unsafe (u8vec-ref-unchecked v 0))

Since: Phase N2

defn

u8vec-set-unchecked!

(u8vec-set-unchecked! [^borrow v : U8Vec i : int x : uint8])

store x at index i, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE (see the module header).

vthe array (borrowed)
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (u8vec-set-unchecked! v 0 (as uint8 1)))

Since: Phase N2

defn

u8vec-view

(u8vec-view [^borrow v : U8Vec])

a view of v's elements, for a loop that stores into it.

#fx{Unsafe}: nothing ties the view to the array, so a view used after the array is freed reads freed memory. Why it exists: a store through the array (-set-unchecked!) re-reads the header's data pointer, which the store might have overwritten as far as the C compiler knows, so the loop does not vectorize; a view is that pointer, read once. -build and -map! store through one; reach for it directly only for a store loop they do not cover.

vthe array (borrowed); the view is valid while v is

A U8View.

(let [v (u8vec-of (as uint8 1) (as uint8 2)) w (unsafe (u8vec-view v))] (unsafe (u8vec-view-ref w 1)))   ; => (as uint8 2)

Since: Phase N2

defn

u8vec-view-ref

(u8vec-view-ref [w : U8View i : int])

the element at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). The interpreter checks the index anyway, as it does for -ref-unchecked.

wthe view
izero-based index; the caller proves 0 <= i < len

A uint8.

(unsafe (u8vec-view-ref w 0))

Since: Phase N2

defn

u8vec-view-set!

(u8vec-view-set! [w : U8View i : int x : uint8])

store x at index i of a view, NOT bounds-checked.

#fx{Unsafe}: call it inside (unsafe ...). Stores a number: no TUR_REGION_NOTE. The interpreter checks the index anyway.

wthe view
izero-based index; the caller proves 0 <= i < len
xthe new element
(unsafe (u8vec-view-set! w 0 (as uint8 1)))

Since: Phase N2

defmacro

u8vec-for

(u8vec-for [bv & body])

run body once per element of one or two U8Vecs.

(for [x v] body...) binds x to each element of v in order; (for [x v y w] body...) walks v and w together (same length, or a panic before the first pass). No index is in scope, so none can be wrong: the reads are u8vec-ref-unchecked, the body sees plain elements, and the loop carries no bounds check or panic test -- gcc can vectorize it at -O3. An array argument that is not a name is evaluated once, and freed after.

bindings[x v] or [x v y w]
bodythe forms to run per element
(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-for [x v] (println x)))

Since: Phase N2

defmacro

u8vec-for-index

(u8vec-for-index [bv & body])

run body once per element, with its index.

(for-index [i x v] body...) binds i (read-only) and x = v[i].

bindings[i x v]
bodythe forms to run per element
(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-for-index [i x v] (println i)))

Since: Phase N2

defmacro

u8vec-fold

(u8vec-fold [bv body])

fold the elements of a U8Vec into an accumulator.

(fold [acc init x v] body): acc starts at init, and for each element x in order becomes the value of body (which sees acc and x). The result is the final acc. A float sum written this way is the strict left fold, so gcc keeps it scalar; u8vec-sum is the vectorized one.

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-fold [n 0 x v] (+ n 1)))   ; => 2

Since: Phase N2

defmacro

u8vec-build

(u8vec-build [n bv expr])

a fresh U8Vec of n elements, element i the value of expr.

(build n [i] expr), after Racket's for/flvector: i is bound to each index in turn, and expr runs outside any unsafe. The stores go through a view (u8vec-view), so the loop vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc.

nthe length (evaluated once)
ithe index name, in a vector
exprthe element at i, of type uint8

A fresh U8Vec, owned by the caller.

(let [v (u8vec-build 3 [i] (as uint8 1))] (u8vec-len v))   ; => 3

Since: Phase N2

defmacro

u8vec-map!

(u8vec-map! [dst bv expr])

store expr into dst[i] for every i, x bound to src[i].

(map! dst [x src] expr) stores into each slot of dst the value of expr with x bound to the element of src at the same index; (map! dst [x a y b] expr) walks two sources together. dst may be one of the sources: (map! v [x v] {x * 2}) maps in place. Every array has the same length, or a panic before the first element. The loop reads and stores through views (u8vec-view), so it vectorizes where expr allows: at -O2 under clang, at -O3 (--release) under gcc. expr runs outside any unsafe; an array argument that is not a name is evaluated once, and freed after the loop.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, of type uint8
(let [v (u8vec-of (as uint8 1) (as uint8 2))] (u8vec-map! v [x v] x) (u8vec-ref v 1))   ; => (as uint8 2)

Since: Phase N2

defn

u8vec-same-len__

(u8vec-same-len__ [^borrow a : U8Vec ^borrow b : U8Vec])

internal: the common length of two arrays, or a panic.

defclass

NumArray

(defclass NumArray [v])

the operations every typed numeric array has, as one class.

Write a numeric algorithm once, over [V] [(NumArray V)], and it runs on F64Vec, F32Vec, I64Vec, I32Vec and U8Vec, each call going straight to that type's own function (one specialization per type, no runtime dispatch). The element type is the associated type Elem -- (Elem V) in a signature -- so a method returns the honest float32 or uint8, not a carrier word. Sum is what na-sum returns (int for the integer types, the element type for the floats) and View the type of na-view's result. Arithmetic on an element needs (Num (Elem V)), and a conversion or a constant (NumCast (Elem V)) (stdlib/typeclass.tur). Constructors stay per type (f64vec-new ...): a length alone cannot pick an instance. The loops na-for, na-fold and na-map! below work inside such a generic.

vthe array type
(type Elem : Type)
(type Sum : Type)
(type View : Type)
(na-len [^borrow a : v] : int)

the element count

(na-ref [^borrow a : v i : int] : Elem)

the element at i (bounds-checked)

(na-set! [^borrow a : v i : int x : Elem] : nil)

store x at i (bounds-checked)

(na-ref-unchecked [^borrow a : v i : int] : Elem)

the element at i, NOT bounds-checked (#fx{Unsafe})

(na-set-unchecked! [^borrow a : v i : int x : Elem] : nil)

store x at i, NOT bounds-checked (#fx{Unsafe})

(na-view [^borrow a : v] : View)

a view of a's elements (see -view) (#fx{Unsafe})

(na-view-ref [^borrow a : v w : View i : int] : Elem)

the element at i of a's view w, NOT bounds-checked (#fx{Unsafe})

(na-view-set! [^borrow a : v w : View i : int x : Elem] : nil)

store x at i of a's view w, NOT bounds-checked (#fx{Unsafe})

(na-fill! [^borrow a : v x : Elem] : nil)

store x in every slot

(na-copy! [^borrow dst : v ^borrow src : v] : nil)

copy src into dst (same length)

(na-add! [^borrow dst : v ^borrow src : v] : nil)

dst[i] += src[i] (same length)

(na-sub! [^borrow dst : v ^borrow src : v] : nil)

dst[i] -= src[i] (same length)

(na-add-scalar! [^borrow a : v s : Elem] : nil)

add s to every element

(na-sum [^borrow a : v] : Sum)

the sum (eight-lane order for floats; integers wrap)

(na-min [^borrow a : v] : Elem)

the smallest element (an empty array panics)

(na-max [^borrow a : v] : Elem)

the largest element (an empty array panics)

(na-copy [^borrow a : v] : v)

a fresh copy, owned by the caller -- free it with na-free (a generic local is not dropped yet)

(na-free [a : v] : nil)

release an array now, consuming it

(na-show [^borrow a : v] : String)

an owned "#P[a b c]" String

(defn mean [V] [(NumArray V) (NumCast (Sum V))] [^borrow a : V] : float
  {(to-float (na-sum a)) / (as float (na-len a))})
(mean (f64vec-of 1.5 2.5))   ; => 2.0

F64Vec, F32Vec, I64Vec, I32Vec, U8Vec

Since: Phase N2

definstance

NumArray[F64Vec]

(definstance NumArray [F64Vec])

delegates to the f64vec-* functions.

definstance

NumArray[F32Vec]

(definstance NumArray [F32Vec])

delegates to the f32vec-* functions.

definstance

NumArray[I64Vec]

(definstance NumArray [I64Vec])

delegates to the i64vec-* functions.

definstance

NumArray[I32Vec]

(definstance NumArray [I32Vec])

delegates to the i32vec-* functions.

definstance

NumArray[U8Vec]

(definstance NumArray [U8Vec])

delegates to the u8vec-* functions.

defn

na-same-len__

(na-same-len__ [V])

internal: the common length of two arrays, or a panic.

defmacro

na-for

(na-for [bv & body])

run body once per element of one or two arrays, in a generic.

-for over the class: (na-for [x v] body...), or (na-for [x v y w] body...) to walk two together (same length, or a panic first). The enclosing function needs (NumArray V); x is an (Elem V).

bindings[x v] or [x v y w]
bodythe forms to run per element
(defn count-pos [V] [(NumArray V) (Ord (Elem V)) (NumCast (Elem V))]
  [^borrow a : V] : int
  (let [^mut n 0]
    (na-for [x a] (when (> x (:: (from-int 0) (Elem V))) (set! n {n + 1})))
    n))

Since: Phase N2

defmacro

na-fold

(na-fold [bv body])

fold the elements of an array into an accumulator, in a generic.

-fold over the class: (na-fold [acc init x v] body).

bindings[acc init x v]
bodythe new accumulator

The final accumulator.

(na-fold [n 0 x a] {n + 1})   ; => the length, in a generic over a

Since: Phase N2

defmacro

na-map!

(na-map! [dst bv expr])

store expr into dst[i] for every i, in a generic.

-map! over the class: (na-map! dst [x src] expr) or (na-map! dst [x a y b] expr); dst may be a source. Stores through views.

dstthe array stored into (borrowed)
bindings[x src] or [x a y b]
exprthe new element, an (Elem V)
(defn double! [V] [(NumArray V) (Num (Elem V))] [^borrow a : V] : nil
  (na-map! a [x a] {x + x}))

Since: Phase N2