Add or_break and or_continue constructs

This commit is contained in:
gingerBill
2023-09-30 15:04:17 +01:00
parent 4e97b83312
commit 648b83d6ea
11 changed files with 401 additions and 82 deletions
+145 -73
View File
@@ -1786,19 +1786,7 @@ range_statements_with_multiple_return_values :: proc() {
data[i] = i32(i*i)
}
{
it := make_my_iterator(data)
for val in my_iterator(&it) {
fmt.println(val)
}
}
{
it := make_my_iterator(data)
for val, idx in my_iterator(&it) {
fmt.println(val, idx)
}
}
{
{ // Manual Style
it := make_my_iterator(data)
for {
val, _, cond := my_iterator(&it)
@@ -1808,6 +1796,25 @@ range_statements_with_multiple_return_values :: proc() {
fmt.println(val)
}
}
{ // or_break
it := make_my_iterator(data)
loop: for {
val, _ := my_iterator(&it) or_break loop
fmt.println(val)
}
}
{ // first value
it := make_my_iterator(data)
for val in my_iterator(&it) {
fmt.println(val)
}
}
{ // first and second value
it := make_my_iterator(data)
for val, idx in my_iterator(&it) {
fmt.println(val, idx)
}
}
}
@@ -2072,7 +2079,7 @@ or_else_operator :: proc() {
// have optional ok semantics
v: union{int, f64}
i: int
i = v.(int) or_else 123
i = v.(int) or_else 123
i = v.? or_else 123 // Type inference magic
assert(i == 123)
@@ -2178,6 +2185,70 @@ or_return_operator :: proc() {
foo_2()
}
or_break_and_or_continue_operators :: proc() {
fmt.println("\n#'or_break' and 'or_continue'")
// The concept of 'or_break' and 'or_continue' is very similar to that of 'or_return'.
// The difference is that unlike 'or_return', the value does not get returned from
// the current procedure but rather discarded if it is 'false' or not 'nil', and then
// the specified branch (i.e. break or_continue).
// The or branch expression can be labelled if a specific statement needs to be used.
Error :: enum {
None,
Something_Bad,
Something_Worse,
The_Worst,
Your_Mum,
}
caller_1 :: proc() -> Error {
return .Something_Bad
}
caller_2 :: proc() -> (int, Error) {
return 123, .Something_Worse
}
caller_3 :: proc() -> (int, int, Error) {
return 123, 345, .None
}
for { // common approach
err := caller_1()
if err != nil {
break
}
}
for { // or_break approach
caller_1() or_break
}
for { // or_break approach with multiple values
n := caller_2() or_break
_ = n
}
loop: for { // or_break approach with named label
n := caller_2() or_break loop
_ = n
}
for { // or_continue
x, y := caller_3() or_continue
_, _ = x, y
break
}
continue_loop: for { // or_continue with named label
x, y := caller_3() or_continue continue_loop
_, _ = x, y
break
}
}
arbitrary_precision_mathematics :: proc() {
fmt.println("\n# core:math/big")
@@ -2258,98 +2329,98 @@ matrix_type :: proc() {
fmt.println("\n# matrix type")
// A matrix is a mathematical type built into Odin. It is a regular array of numbers,
// arranged in rows and columns
{
// The following represents a matrix that has 2 rows and 3 columns
m: matrix[2, 3]f32
m = matrix[2, 3]f32{
1, 9, -13,
20, 5, -6,
}
// Element types of integers, float, and complex numbers are supported by matrices.
// There is no support for booleans, quaternions, or any compound type.
// Indexing a matrix can be used with the matrix indexing syntax
// This mirrors othe type usages: type on the left, usage on the right
elem := m[1, 2] // row 1, column 2
assert(elem == -6)
// Scalars act as if they are scaled identity matrices
// and can be assigned to matrices as them
b := matrix[2, 2]f32{}
f := f32(3)
b = f
fmt.println("b", b)
fmt.println("b == f", b == f)
}
}
{ // Matrices support multiplication between matrices
a := matrix[2, 3]f32{
2, 3, 1,
4, 5, 0,
}
b := matrix[3, 2]f32{
1, 2,
3, 4,
5, 6,
}
fmt.println("a", a)
fmt.println("b", b)
c := a * b
#assert(type_of(c) == matrix[2, 2]f32)
fmt.tprintln("c = a * b", c)
fmt.tprintln("c = a * b", c)
}
{ // Matrices support multiplication between matrices and arrays
m := matrix[4, 4]f32{
1, 2, 3, 4,
5, 5, 4, 2,
0, 1, 3, 0,
1, 2, 3, 4,
5, 5, 4, 2,
0, 1, 3, 0,
0, 1, 4, 1,
}
v := [4]f32{1, 5, 4, 3}
// treating 'v' as a column vector
fmt.println("m * v", m * v)
// treating 'v' as a row vector
fmt.println("v * m", v * m)
// Support with non-square matrices
s := matrix[2, 4]f32{ // [4][2]f32
2, 4, 3, 1,
7, 8, 6, 5,
2, 4, 3, 1,
7, 8, 6, 5,
}
w := [2]f32{1, 2}
r: [4]f32 = w * s
fmt.println("r", r)
}
{ // Component-wise operations
{ // Component-wise operations
// if the element type supports it
// Not support for '/', '%', or '%%' operations
a := matrix[2, 2]i32{
1, 2,
3, 4,
}
b := matrix[2, 2]i32{
-5, 1,
9, -7,
}
c0 := a + b
c1 := a - b
c2 := a & b
@@ -2359,9 +2430,9 @@ matrix_type :: proc() {
// component-wise multiplication
// since a * b would be a standard matrix multiplication
c6 := hadamard_product(a, b)
c6 := hadamard_product(a, b)
fmt.println("a + b", c0)
fmt.println("a - b", c1)
fmt.println("a & b", c2)
@@ -2370,23 +2441,23 @@ matrix_type :: proc() {
fmt.println("a &~ b", c5)
fmt.println("hadamard_product(a, b)", c6)
}
{ // Submatrix casting square matrices
// Casting a square matrix to another square matrix with same element type
// is supported.
// is supported.
// If the cast is to a smaller matrix type, the top-left submatrix is taken.
// If the cast is to a larger matrix type, the matrix is extended with zeros
// everywhere and ones in the diagonal for the unfilled elements of the
// everywhere and ones in the diagonal for the unfilled elements of the
// extended matrix.
mat2 :: distinct matrix[2, 2]f32
mat4 :: distinct matrix[4, 4]f32
m2 := mat2{
1, 3,
2, 4,
}
m4 := mat4(m2)
assert(m4[2, 2] == 1)
assert(m4[3, 3] == 1)
@@ -2394,7 +2465,7 @@ matrix_type :: proc() {
fmt.println("m4", m4)
fmt.println("mat2(m4)", mat2(m4))
assert(mat2(m4) == m2)
b4 := mat4{
1, 2, 0, 0,
3, 4, 0, 0,
@@ -2403,43 +2474,43 @@ matrix_type :: proc() {
}
fmt.println("b4", matrix_flatten(b4))
}
{ // Casting non-square matrices
// Casting a matrix to another matrix is allowed as long as they share
// Casting a matrix to another matrix is allowed as long as they share
// the same element type and the number of elements (rows*columns).
// Matrices in Odin are stored in column-major order, which means
// the casts will preserve this element order.
mat2x4 :: distinct matrix[2, 4]f32
mat4x2 :: distinct matrix[4, 2]f32
x := mat2x4{
1, 3, 5, 7,
1, 3, 5, 7,
2, 4, 6, 8,
}
y := mat4x2(x)
fmt.println("x", x)
fmt.println("y", y)
}
// TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored
// in column-major format
// e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement)
// Column-major is used in order to utilize (SIMD) vector instructions effectively on
// Column-major is used in order to utilize (SIMD) vector instructions effectively on
// modern hardware, if possible.
//
// Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization
// properties whilst keeping zero padding (either between columns or at the end of the type).
//
//
// Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance.
// Padding between columns was not taken even if that would have allowed each column to be loaded
// individually into a SIMD register with the correct alignment properties.
//
// Padding between columns was not taken even if that would have allowed each column to be loaded
// individually into a SIMD register with the correct alignment properties.
//
// Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element.
// This is because matrices are stored as values (not a reference type), and thus operations on them will
// be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows.
// Built-in Procedures (Compiler Level)
// transpose(m)
// transposes a matrix
@@ -2454,13 +2525,13 @@ matrix_type :: proc() {
// Example:
// m := matrix[2, 2]f32{
// x0, x1,
// y0, y1,
// y0, y1,
// }
// array: [4]f32 = matrix_flatten(m)
// assert(array == {x0, y0, x1, y1})
// conj(x)
// conjugates the elements of a matrix for complex element types only
// Built-in Procedures (Runtime Level) (all square matrix procedures)
// determinant(m)
// adjugate(m)
@@ -2474,8 +2545,8 @@ matrix_type :: proc() {
main :: proc() {
/*
For More Odin Examples - https://github.com/odin-lang/examples
This repository contains examples of how certain things can be accomplished
in idiomatic Odin, allowing you learn its semantics, as well as how to use
This repository contains examples of how certain things can be accomplished
in idiomatic Odin, allowing you learn its semantics, as well as how to use
parts of the core and vendor package collections.
*/
@@ -2513,7 +2584,8 @@ main :: proc() {
relative_data_types()
or_else_operator()
or_return_operator()
or_break_and_or_continue_operators()
arbitrary_precision_mathematics()
matrix_type()
}
}
}