Skip to content

Instantly share code, notes, and snippets.

@vassvik
Last active September 25, 2017 08:14
Show Gist options
  • Save vassvik/0a08ce59b678a77579db9392df983306 to your computer and use it in GitHub Desktop.
Save vassvik/0a08ce59b678a77579db9392df983306 to your computer and use it in GitHub Desktop.
Odin vector types and bulk operations
// Vectors are similar to arrays, but they are allow for bulk operations to all of its elements.
// Thet are meant to map to hardware level vector instructions but they can be any arbitrary length.
// Vector types only allow numeric and logical types (integers, floats, complex numbers, booleans).
// A vector type is composed as: `[vector size]T`.
// Almost all operators that work on the base type also work on the vector type.
// Exceptions are comparisons for bool vectors, shifts are for integer vectors.
fmt.println("complex operations");
c1 := [vector 2]complex64{1.0 + 3.14i, 3.0 - 5.0i};
c2 := [vector 2]complex64{-1.0 + 1i, -13 - 3.5i};
fmt.printf("c1 = %v\n", c1);
fmt.printf("c2 = %v\n", c2);
fmt.printf("c1 + c2 = %v\n", c1 + c2);
fmt.printf("c1 - c2 = %v\n", c1 - c2);
fmt.printf("c1 * c2 = %v\n", c1 * c2);
fmt.printf("c1 / c2 = %v\n", c1 / c2);
fmt.println();
fmt.println("float operations");
v1 := [vector 2]f32{1.0, 2.0};
v2 := [vector 2]f32{3.0, 5.0};
fmt.printf("v1 = %v\n", v1);
fmt.printf("v2 = %v\n", v2);
fmt.printf("v1 + v2 = %v\n", v1 + v2);
fmt.printf("v1 - v2 = %v\n", v1 - v2);
fmt.printf("v1 * v2 = %v\n", v1 * v2);
fmt.printf("v1 / v2 = %v\n", v1 / v2);
fmt.println();
fmt.println("int operations");
i1 := [vector 3]int{7, -13, 17};
i2 := [vector 3]int{3, 5, -7};
fmt.printf("i1 = %v\n", i1);
fmt.printf("i2 = %v\n", i2);
fmt.printf("i1 + i2 = %v\n", i1 + i2);
fmt.printf("i1 - i2 = %v\n", i1 - i2);
fmt.printf("i1 * i2 = %v\n", i1 * i2);
fmt.printf("i1 / i2 = %v\n", i1 / i2);
fmt.printf("i1 %% i2 = %v\n", i1 % i2);
fmt.printf("i1 %%%% i2 = %v\n", i1 %% i2);
fmt.printf("i1 & i2 = %v\n", i1 & i2);
fmt.printf("i1 | i2 = %v\n", i1 | i2);
fmt.printf("i1 ~ i2 = %v\n", i1 ~ i2); // XOR
fmt.printf("~i1 = %v\n", ~i1);
fmt.printf("~i2 = %v\n", ~i2);
fmt.println();
fmt.println("bool operations");
b1 := [vector 4]bool{false, false, true, true};
b2 := [vector 4]bool{false, true, false, true};
fmt.printf("b1 = %v\n", b1);
fmt.printf("b2 = %v\n", b2);
fmt.printf("b1 == b2 = %v\n", b1 == b2);
fmt.printf("b1 != b2 = %v\n", b1 != b2);
fmt.printf("b1 & b2 = %v\n", b1 & b2);
fmt.printf("b1 | b2 = %v\n", b1 | b2);
fmt.printf("b1 ~ b2 = %v\n", b1 ~ b2); // XOR
fmt.printf("!b1 = %v\n", !b1);
fmt.printf("!b2 = %v\n", !b2);
fmt.printf("~b1 = %v\n", ~b1);
fmt.printf("~b2 = %v\n", ~b2);
// fmt.printf("b1 && b2 = %v\n", b1 && b2); // Currently bugged
// fmt.printf("b1 || b2 = %v\n", b1 || b2); // Currently bugged
fmt.println();
// Note that while the vectors are typically initialized with the struct initialization syntax,
// there is also a shorthand to broadcast a single value to all elements
fmt.println([vector 2]f32{1.0});
fmt.println([vector 10]f32{0.0});
// if vector types are smaller than 16 bytes they will round up to the nearest power-of-two that is less than or equal to 16 bytes
// otherwise they will round up to the closest multiple of 16 bytes (to fit in 128 bit SIMD registers)
fmt.printf("size_of([vector 1]f32) = %d\n", size_of([vector 1]f32));
fmt.printf("size_of([vector 2]f32) = %d\n", size_of([vector 2]f32));
fmt.printf("size_of([vector 3]f32) = %d\n", size_of([vector 3]f32));
fmt.printf("size_of([vector 4]f32) = %d\n", size_of([vector 4]f32));
fmt.printf("size_of([vector 5]f32) = %d\n", size_of([vector 5]f32));
fmt.printf("size_of([vector 8]f32) = %d\n", size_of([vector 8]f32));
fmt.printf("size_of([vector 9]f32) = %d\n", size_of([vector 9]f32));
fmt.printf("size_of([vector 12]f32) = %d\n", size_of([vector 12]f32));
fmt.printf("size_of([vector 13]f32) = %d\n", size_of([vector 13]f32));
fmt.printf("size_of([vector 16]f32) = %d\n", size_of([vector 16]f32));
fmt.printf("size_of([vector 17]f32) = %d\n", size_of([vector 17]f32));
fmt.printf("size_of([vector 20]f32) = %d\n", size_of([vector 20]f32));
fmt.printf("size_of([vector 21]f32) = %d\n", size_of([vector 21]f32));
fmt.printf("size_of([vector 24]f32) = %d\n", size_of([vector 24]f32));
fmt.printf("size_of([vector 25]f32) = %d\n", size_of([vector 25]f32));
fmt.printf("size_of([vector 28]f32) = %d\n", size_of([vector 28]f32));
fmt.printf("size_of([vector 29]f32) = %d\n", size_of([vector 29]f32));
fmt.printf("size_of([vector 32]f32) = %d\n", size_of([vector 32]f32));
fmt.println();
fmt.printf("size_of([vector 1]bool) = %d\n", size_of([vector 1]bool));
fmt.printf("size_of([vector 2]bool) = %d\n", size_of([vector 2]bool));
fmt.printf("size_of([vector 3]bool) = %d\n", size_of([vector 3]bool));
fmt.printf("size_of([vector 4]bool) = %d\n", size_of([vector 4]bool));
fmt.printf("size_of([vector 5]bool) = %d\n", size_of([vector 5]bool));
fmt.printf("size_of([vector 8]bool) = %d\n", size_of([vector 8]bool));
fmt.printf("size_of([vector 9]bool) = %d\n", size_of([vector 9]bool));
fmt.printf("size_of([vector 16]bool) = %d\n", size_of([vector 16]bool));
fmt.printf("size_of([vector 17]bool) = %d\n", size_of([vector 17]bool));
fmt.printf("size_of([vector 32]bool) = %d\n", size_of([vector 32]bool));
fmt.printf("size_of([vector 33]bool) = %d\n", size_of([vector 33]bool));
fmt.printf("size_of([vector 48]bool) = %d\n", size_of([vector 48]bool));
fmt.printf("size_of([vector 49]bool) = %d\n", size_of([vector 49]bool));
fmt.printf("size_of([vector 64]bool) = %d\n", size_of([vector 64]bool));
fmt.printf("size_of([vector 65]bool) = %d\n", size_of([vector 65]bool));
fmt.printf("size_of([vector 80]bool) = %d\n", size_of([vector 80]bool));
fmt.printf("size_of([vector 81]bool) = %d\n", size_of([vector 81]bool));
fmt.printf("size_of([vector 96]bool) = %d\n", size_of([vector 96]bool));
fmt.printf("size_of([vector 97]bool) = %d\n", size_of([vector 97]bool));
fmt.printf("size_of([vector 112]bool) = %d\n", size_of([vector 112]bool));
fmt.printf("size_of([vector 113]bool) = %d\n", size_of([vector 113]bool));
fmt.printf("size_of([vector 128]bool) = %d\n", size_of([vector 128]bool));
fmt.println();
// the individual components of vectors whose length are smaller than or equal to 4
// can be accessed by x, y, z and w, respectively:
v4 := [vector 4]f32{1.0, 2.0, 3.0, 4.0};
fmt.printf("v4.x, v4.y, v4.z, v4.w = %v %v %v %v\n", v4.x, v4.y, v4.z, v4.w);
fmt.println();
// you can additionally index vectors using the regular [] syntax.
// these are bounds checked, unless explicitly deactivated with #no_bounds_check
v10 := [vector 10]f32{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0};
fmt.printf("v10[2], v10[7], v10[9] = %v %v %v\n", v10[2], v10[7], v10[9]);
fmt.println();
// while you cannot explicitly take address the address of an element in a vector, you can use the following trick:
Thing :: struct {
using v: [vector 4]f32, // this makes the Vec4 type "array-like" such that you can index it with [].
};
v := Thing{[vector 4]f32{1.0, 2.0, 3.0, 4.0}}; // you cannot initialize anonymous members at the moment
fmt.printf("v.x, v.y, v.z, v.w = %v %v %v %v\n", v.x, v.y, v.z, v.w);
fmt.printf("v[0], v[1], v[2], v[3] = %v %v %v %v\n", v[0], v[1], v[2], v[3]);
fmt.printf("&v[0], &v[1], &v[2], &v[3] = %p %p %p %p\n", &v[0], &v[1], &v[2], &v[3]);
fmt.println();
// you can swizzle vectors by using the built in `swizzle` procedure
fmt.printf("swizzle(v4, 3, 1, 2) = %v, type %T]\n", swizzle(v4, 3, 1, 2), swizzle(v4, 3, 1, 2));
fmt.printf("swizzle(v4, 3, 1) = %v, type %T]\n", swizzle(v4, 3, 1), swizzle(v4, 3, 1));
fmt.printf("swizzle(v4, 0, 0, 0, 0) = %v, type %T]\n", swizzle(v4, 0, 0, 0, 0), swizzle(v4, 0, 0, 0, 0));
fmt.println();
// it is often useful to create an alias for the type to make the initialization syntax cleaner
Vec4 :: [vector 4]f32;
a := Vec4{4.0, 3.0, 2.0, 1.0};
b := Vec4{1.0, 2.0, 3.0, 4.0};
fmt.printf("a + b = %v\n", a + b);
fmt.println();
// note that an aliased type is a distinct type and is distinct from the base type, so you cannot mix and match them.
// on the other hand, you can create *specialized* polymorphic procedures that work on any type that is derived from the same vector type
do_stuff :: proc(v: $T/[vector 4]f32) {
fmt.printf("v = %v\n", v);
}
do_stuff(a);
do_stuff(v4);
fmt.println();
// you can also cast between them:
c := cast(Vec4)v4;
fmt.printf("c = %v\n", c);
fmt.println();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment