diff options
| author | Chris Heyes <rumcode@icloud.com> | 2019-11-01 19:18:33 +0000 |
|---|---|---|
| committer | Chris Heyes <rumcode@icloud.com> | 2019-11-01 19:18:33 +0000 |
| commit | 153e7525b5d64f12deb318d50aee1d9dbeb1fc8e (patch) | |
| tree | b8ac88c0788af31bcb3c5041d78306c2120714f6 /examples | |
| parent | d85893954dccc7833e3d954db641d9fd2a3c7451 (diff) | |
| parent | 44a303e5778fb8564964d53523634f34f8589489 (diff) | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/demo/demo.odin | 374 | ||||
| -rw-r--r-- | examples/old_demos/demo001.odin | 337 | ||||
| -rw-r--r-- | examples/old_demos/demo002.odin | 879 | ||||
| -rw-r--r-- | examples/old_demos/demo004.odin | 66 | ||||
| -rw-r--r-- | examples/old_demos/demo005.odin | 283 | ||||
| -rw-r--r-- | examples/old_demos/demo006.odin | 310 | ||||
| -rw-r--r-- | examples/old_demos/demo007.odin | 570 | ||||
| -rw-r--r-- | examples/old_demos/demo008.odin | 778 | ||||
| -rw-r--r-- | examples/old_demos/old_runtime.odin | 412 | ||||
| -rw-r--r-- | examples/old_stuff/demo_backup.odin | 430 |
10 files changed, 334 insertions, 4105 deletions
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 206fa4a2d..4d14973f6 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -3,14 +3,34 @@ package main import "core:fmt" import "core:mem" import "core:os" +import "core:reflect" +import "intrinsics" when os.OS == "windows" { import "core:thread" } -@(link_name="general_stuff") -general_stuff :: proc() { - fmt.println("# general_stuff"); +/* + The Odin programming language is fast, concise, readable, pragmatic and open sourced. It is designed with the intent of replacing C with the following goals: + * simplicity + * high performance + * built for modern systems + * joy of programming + + # Installing Odin + Getting Started - https://odin-lang.org/docs/install/ + Instructions for downloading and install the Odin compiler and libraries. + + # Learning Odin + Overview of Odin - https://odin-lang.org/docs/overview/ + An overview of the Odin programming language. + Frequently Asked Questions (FAQ) - https://odin-lang.org/docs/faq/ + Answers to common questions about Odin. +*/ + +@(link_name="extra_general_stuff") +extra_general_stuff :: proc() { + fmt.println("# extra_general_stuff"); { // `do` for inline statements rather than block foo :: proc() do fmt.println("Foo!"); if false do foo(); @@ -30,14 +50,12 @@ general_stuff :: proc() { i := i32(137); ptr := &i; - _ = (^f32)(ptr); + _ = (^f32)(ptr); // Call-based syntax // ^f32(ptr) == ^(f32(ptr)) - _ = cast(^f32)ptr; + _ = cast(^f32)ptr; // Operator-based syntax _ = (^f32)(ptr)^; _ = (cast(^f32)ptr)^; - - // Questions: Should there be two ways to do it? } /* @@ -50,7 +68,7 @@ general_stuff :: proc() { Foo :: struct { x: int, b: bool, - } + }; f := Foo{137, true}; x, b := expand_to_tuple(f); fmt.println(f); @@ -191,8 +209,8 @@ union_type :: proc() { } } - Vector3 :: struct {x, y, z: f32}; - Quaternion :: struct {x, y, z, w: f32}; + Vector3 :: distinct [3]f32; + Quaternion :: distinct quaternion128; // More realistic examples { @@ -209,18 +227,18 @@ union_type :: proc() { orientation: Quaternion, derived: any, - } + }; Frog :: struct { using entity: Entity, jump_height: f32, - } + }; Monster :: struct { using entity: Entity, is_robot: bool, is_zombie: bool, - } + }; // See `parametric_polymorphism` procedure for details new_entity :: proc($T: typeid) -> ^Entity { @@ -254,18 +272,18 @@ union_type :: proc() { orientation: Quaternion, derived: union {Frog, Monster}, - } + }; Frog :: struct { using entity: ^Entity, jump_height: f32, - } + }; Monster :: struct { using entity: ^Entity, is_robot: bool, is_zombie: bool, - } + }; // See `parametric_polymorphism` procedure for details new_entity :: proc($T: typeid) -> ^Entity { @@ -302,17 +320,17 @@ union_type :: proc() { /* Entity :: struct { - .. + ... derived: union{^Frog, ^Monster}, } Frog :: struct { using entity: Entity, - .. + ... } Monster :: struct { using entity: Entity, - .. + ... } new_entity :: proc(T: type) -> ^Entity { @@ -325,7 +343,7 @@ union_type :: proc() { } parametric_polymorphism :: proc() { - fmt.println("# parametric_polymorphism"); + fmt.println("\n# parametric_polymorphism"); print_value :: proc(value: $T) { fmt.printf("print_value: %T %v\n", value, value); @@ -383,13 +401,13 @@ parametric_polymorphism :: proc() { hash: u32, key: Key, value: Value, - } + }; TABLE_SIZE_MIN :: 32; Table :: struct(Key, Value: typeid) { count: int, allocator: mem.Allocator, slots: []Table_Slot(Key, Value), - } + }; // Only allow types that are specializations of a (polymorphic) slice make_slice :: proc($T: typeid/[]$E, len: int) -> T { @@ -513,7 +531,7 @@ parametric_polymorphism :: proc() { Foo1, Foo2, Foo3, - } + }; Para_Union :: union(T: typeid) {T, Error}; r: Para_Union(int); fmt.println(typeid_of(type_of(r))); @@ -521,7 +539,7 @@ parametric_polymorphism :: proc() { fmt.println(r); r = 123; fmt.println(r); - r = Error.Foo0; + r = Error.Foo0; // r = .Foo0; is allow too, see implicit selector expressions below fmt.println(r); } @@ -543,6 +561,30 @@ parametric_polymorphism :: proc() { for v, i in array { assert(v == T(i*i)); } + + // Matrix multiplication + mul :: proc(a: [$M][$N]$T, b: [N][$P]T) -> (c: [M][P]T) { + for i in 0..<M { + for j in 0..<P { + for k in 0..<N { + c[i][j] += a[i][k] * b[k][j]; + } + } + } + return; + } + + x := [2][3]f32{ + {1, 2, 3}, + {3, 2, 1}, + }; + y := [3][2]f32{ + {0, 8}, + {6, 2}, + {8, 4}, + }; + z := mul(x, y); + assert(z == {{36, 24}, {20, 32}}); } } @@ -560,7 +602,7 @@ prefix_table := [?]string{ threading_example :: proc() { when os.OS == "windows" { - fmt.println("# threading_example"); + fmt.println("\n# threading_example"); worker_proc :: proc(t: ^thread.Thread) -> int { for iteration in 1..5 { @@ -600,7 +642,7 @@ threading_example :: proc() { } array_programming :: proc() { - fmt.println("# array_programming"); + fmt.println("\n# array_programming"); { a := [3]f32{1, 2, 3}; b := [3]f32{5, 6, 7}; @@ -645,7 +687,7 @@ array_programming :: proc() { } named_proc_return_parameters :: proc() { - fmt.println("# named proc return parameters"); + fmt.println("\n# named proc return parameters"); foo0 :: proc() -> int { return 123; @@ -667,7 +709,7 @@ named_proc_return_parameters :: proc() { using_enum :: proc() { - fmt.println("# using enum"); + fmt.println("\n# using enum"); using Foo :: enum {A, B, C}; @@ -679,25 +721,25 @@ using_enum :: proc() { } map_type :: proc() { - fmt.println("# map type"); + fmt.println("\n# map type"); // enums of type u16, u32, i16 & i32 also work Enum_u8 :: enum u8 { A = 0, B = 1 << 8 - 1, - } + }; Enum_u64 :: enum u64 { A = 0, B = 1 << 64 - 1, - } + }; Enum_i8 :: enum i8 { A = 0, B = -(1 << 7), - } + }; Enum_i64 :: enum i64 { A = 0, B = -(1 << 63), - } + }; map_u8: map[Enum_u8]u8; map_u8[Enum_u8.A] = u8(Enum_u8.B); @@ -721,7 +763,7 @@ map_type :: proc() { demo_struct :: struct { member: Enum_i64, - } + }; map_string: map[string]demo_struct; map_string["Hellope!"] = demo_struct{Enum_i64.B}; @@ -734,7 +776,7 @@ map_type :: proc() { } implicit_selector_expression :: proc() { - fmt.println("# implicit selector expression"); + fmt.println("\n# implicit selector expression"); Foo :: enum {A, B, C}; @@ -762,7 +804,7 @@ implicit_selector_expression :: proc() { } explicit_procedure_overloading :: proc() { - fmt.println("# explicit procedure overloading"); + fmt.println("\n# explicit procedure overloading"); add_ints :: proc(a, b: int) -> int { x := a + b; @@ -796,14 +838,14 @@ explicit_procedure_overloading :: proc() { } complete_switch :: proc() { - fmt.println("# complete_switch"); + fmt.println("\n# complete_switch"); { // enum using Foo :: enum { A, B, C, D, - } + }; b := Foo.B; f := Foo.A; @@ -829,6 +871,8 @@ complete_switch :: proc() { } cstring_example :: proc() { + fmt.println("\n# cstring_example"); + W :: "Hellope"; X :: cstring(W); Y :: string(X); @@ -860,6 +904,8 @@ deprecated_attribute :: proc() { } bit_set_type :: proc() { + fmt.println("\n# bit_set_type"); + { using Day :: enum { Sunday, @@ -869,7 +915,7 @@ bit_set_type :: proc() { Thursday, Friday, Saturday, - } + }; Days :: distinct bit_set[Day]; WEEKEND :: Days{Sunday, Saturday}; @@ -921,6 +967,8 @@ bit_set_type :: proc() { } diverging_procedures :: proc() { + fmt.println("\n# diverging_procedures"); + // Diverging procedures may never return foo :: proc() -> ! { fmt.println("I'm a diverging procedure"); @@ -930,6 +978,8 @@ diverging_procedures :: proc() { } deferred_procedure_associations :: proc() { + fmt.println("\n# deferred_procedure_associations"); + @(deferred_out=closure) open :: proc(s: string) -> bool { fmt.println(s); @@ -945,9 +995,247 @@ deferred_procedure_associations :: proc() { } } +reflection :: proc() { + fmt.println("\n# reflection"); + + Foo :: struct { + x: int `tag1`, + y: string `json:"y_field"`, + z: bool, // no tag + }; + + id := typeid_of(Foo); + names := reflect.struct_field_names(id); + types := reflect.struct_field_types(id); + tags := reflect.struct_field_tags(id); + + assert(len(names) == len(types) && len(names) == len(tags)); + + fmt.println("Foo :: struct {"); + for tag, i in tags { + name, type := names[i], types[i]; + if tag != "" { + fmt.printf("\t%s: %T `%s`,\n", name, type, tag); + } else { + fmt.printf("\t%s: %T,\n", name, type); + } + } + fmt.println("}"); + + + for tag, i in tags { + if val, ok := reflect.struct_tag_lookup(tag, "json"); ok { + fmt.printf("json: %s -> %s\n", names[i], val); + } + } +} + +quaternions :: proc() { + fmt.println("\n# quaternions"); + + { // Quaternion operations + q := 1 + 2i + 3j + 4k; + r := quaternion(5, 6, 7, 8); + t := q * r; + fmt.printf("(%v) * (%v) = %v\n", q, r, t); + v := q / r; + fmt.printf("(%v) / (%v) = %v\n", q, r, v); + u := q + r; + fmt.printf("(%v) + (%v) = %v\n", q, r, u); + s := q - r; + fmt.printf("(%v) - (%v) = %v\n", q, r, s); + } + { // The quaternion types + q128: quaternion128; // 4xf32 + q256: quaternion256; // 4xf64 + q128 = quaternion(1, 0, 0, 0); + q256 = 1; // quaternion(1, 0, 0, 0); + } + { // Built-in procedures + q := 1 + 2i + 3j + 4k; + fmt.println("q =", q); + fmt.println("real(q) =", real(q)); + fmt.println("imag(q) =", imag(q)); + fmt.println("jmag(q) =", jmag(q)); + fmt.println("kmag(q) =", kmag(q)); + fmt.println("conj(q) =", conj(q)); + fmt.println("abs(q) =", abs(q)); + } + { // Conversion of a complex type to a quaternion type + c := 1 + 2i; + q := quaternion256(c); + fmt.println(c); + fmt.println(q); + } + { // Memory layout of Quaternions + q := 1 + 2i + 3j + 4k; + a := transmute([4]f64)q; + fmt.println("Quaternion memory layout: xyzw/(ijkr)"); + fmt.println(q); // 1.000+2.000i+3.000j+4.000k + fmt.println(a); // [2.000, 3.000, 4.000, 1.000] + } +} + +inline_for_statement :: proc() { + fmt.println("\n#inline for statements"); + + // 'inline for' works the same as if the 'inline' prefix did not + // exist but these ranged loops are explicitly unrolled which can + // be very very useful for certain optimizations + + fmt.println("Ranges"); + inline for x, i in 1..<4 { + fmt.println(x, i); + } + + fmt.println("Strings"); + inline for r, i in "Hello, 世界" { + fmt.println(r, i); + } + + fmt.println("Arrays"); + inline for elem, idx in ([4]int{1, 4, 9, 16}) { + fmt.println(elem, idx); + } + + + Foo_Enum :: enum { + A = 1, + B, + C = 6, + D, + }; + fmt.println("Enum types"); + inline for elem, idx in Foo_Enum { + fmt.println(elem, idx); + } +} + +where_clauses :: proc() { + fmt.println("\n#procedure 'where' clauses"); + + { // Sanity checks + simple_sanity_check :: proc(x: [2]int) + where len(x) > 1, + type_of(x) == [2]int { + fmt.println(x); + } + } + { // Parametric polymorphism checks + cross_2d :: proc(a, b: $T/[2]$E) -> E + where intrinsics.type_is_numeric(E) { + return a.x*b.y - a.y*b.x; + } + cross_3d :: proc(a, b: $T/[3]$E) -> T + where intrinsics.type_is_numeric(E) { + x := a.y*b.z - a.z*b.y; + y := a.z*b.x - a.x*b.z; + z := a.x*b.y - a.y*b.z; + return T{x, y, z}; + } + + a := [2]int{1, 2}; + b := [2]int{5, -3}; + fmt.println(cross_2d(a, b)); + + x := [3]f32{1, 4, 9}; + y := [3]f32{-5, 0, 3}; + fmt.println(cross_3d(x, y)); + + // Failure case + // i := [2]bool{true, false}; + // j := [2]bool{false, true}; + // fmt.println(cross_2d(i, j)); + + } + + { // Procedure groups usage + foo :: proc(x: [$N]int) -> bool + where N > 2 { + fmt.println(#procedure, "was called with the parameter", x); + return true; + } + + bar :: proc(x: [$N]int) -> bool + where 0 < N, + N <= 2 { + fmt.println(#procedure, "was called with the parameter", x); + return false; + } + + baz :: proc{foo, bar}; + + x := [3]int{1, 2, 3}; + y := [2]int{4, 9}; + ok_x := baz(x); + ok_y := baz(y); + assert(ok_x == true); + assert(ok_y == false); + } + + { // Record types + Foo :: struct(T: typeid, N: int) + where intrinsics.type_is_integer(T), + N > 2 { + x: [N]T, + y: [N-2]T, + }; + + T :: i32; + N :: 5; + f: Foo(T, N); + #assert(size_of(f) == (N+N-2)*size_of(T)); + } +} + +ranged_fields_for_array_compound_literals :: proc() { + fmt.println("\n#ranged fields for array compound literals"); + { // Normal Array Literal + foo := [?]int{1, 4, 9, 16}; + fmt.println(foo); + } + { // Indexed + foo := [?]int{ + 3 = 16, + 1 = 4, + 2 = 9, + 0 = 1, + }; + fmt.println(foo); + } + { // Ranges + i := 2; + foo := [?]int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + #assert(len(foo) == 16); + fmt.println(foo); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + } + { // Slice and Dynamic Array support + i := 2; + foo_slice := []int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + assert(len(foo_slice) == 16); + fmt.println(foo_slice); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + + foo_dynamic_array := [dynamic]int { + 0 = 123, + 5..9 = 54, + 10..<16 = i*3 + (i-1)*2, + }; + assert(len(foo_dynamic_array) == 16); + fmt.println(foo_dynamic_array); // [123, 0, 0, 0, 0, 54, 54, 54, 54, 54, 8, 8, 8, 8, 8] + } +} + main :: proc() { when true { - general_stuff(); + extra_general_stuff(); union_type(); parametric_polymorphism(); threading_example(); @@ -963,5 +1251,11 @@ main :: proc() { bit_set_type(); diverging_procedures(); deferred_procedure_associations(); + reflection(); + quaternions(); + inline_for_statement(); + where_clauses(); + ranged_fields_for_array_compound_literals(); } } + diff --git a/examples/old_demos/demo001.odin b/examples/old_demos/demo001.odin deleted file mode 100644 index a3aea1cb7..000000000 --- a/examples/old_demos/demo001.odin +++ /dev/null @@ -1,337 +0,0 @@ -import "core:fmt.odin"; -import "core:os.odin"; -import "core:mem.odin"; -// import "http_test.odin" as ht; -// import "game.odin" as game; -// import "punity.odin" as pn; - -main :: proc() { - struct_padding(); - bounds_checking(); - type_introspection(); - any_type(); - crazy_introspection(); - namespaces_and_files(); - miscellany(); - - /* - ht.run(); - game.run(); - { - init :: proc(c: ^pn.Core) {} - step :: proc(c: ^pn.Core) {} - - pn.run(init, step); - } - */ -} - -struct_padding :: proc() { - { - A :: struct { - a: u8, - b: u32, - c: u16, - } - - B :: struct { - a: [7]u8, - b: [3]u16, - c: u8, - d: u16, - } - - fmt.println("size_of(A):", size_of(A)); - fmt.println("size_of(B):", size_of(B)); - - // n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html - } - { - A :: struct #ordered { - a: u8, - b: u32, - c: u16, - } - - B :: struct #ordered { - a: [7]u8, - b: [3]u16, - c: u8, - d: u16, - } - - fmt.println("size_of(A):", size_of(A)); - fmt.println("size_of(B):", size_of(B)); - - // C-style structure layout - } - { - A :: struct #packed { - a: u8, - b: u32, - c: u16, - } - - B :: struct #packed { - a: [7]u8, - b: [3]u16, - c: u8, - d: u16, - } - - fmt.println("size_of(A):", size_of(A)); - fmt.println("size_of(B):", size_of(B)); - - // Useful for explicit layout - } - - // Member sorting by priority - // Alignment desc. - // Size desc. - // source order asc. - - /* - A :: struct { - a: u8 - b: u32 - c: u16 - } - - B :: struct { - a: [7]u8 - b: [3]u16 - c: u8 - d: u16 - } - - Equivalent too - - A :: struct #ordered { - b: u32 - c: u16 - a: u8 - } - - B :: struct #ordered { - b: [3]u16 - d: u16 - a: [7]u8 - c: u8 - } - */ -} - -bounds_checking :: proc() { - x: [4]int; - // x[-1] = 0; // Compile Time - // x[4] = 0; // Compile Time - - { - a, b := -1, 4; - // x[a] = 0; // Runtime Time - // x[b] = 0; // Runtime Time - } - - // Works for arrays, strings, slices, and related procedures & operations - - { - base: [10]int; - s := base[2..6]; - a, b := -1, 6; - - #no_bounds_check { - s[a] = 0; - // #bounds_check s[b] = 0; - } - - #no_bounds_check - if s[a] == 0 { - // Do whatever - } - - // Bounds checking can be toggled explicit - // on a per statement basis. - // _any statement_ - } -} - -type_introspection :: proc() { - { - info: ^Type_Info; - x: int; - - info = type_info_of(int); // by type - info = type_info_of(x); // by value - // See: runtime.odin - - match i in info.variant { - case Type_Info_Integer: - fmt.println("integer!"); - case Type_Info_Float: - fmt.println("float!"); - case: - fmt.println("potato!"); - } - - // Unsafe cast - integer_info := cast(^Type_Info_Integer)cast(rawptr)info; - } - - { - Vector2 :: struct { x, y: f32 } - Vector3 :: struct { x, y, z: f32 } - - v1: Vector2; - v2: Vector3; - v3: Vector3; - - t1 := type_info_of(v1); - t2 := type_info_of(v2); - t3 := type_info_of(v3); - - fmt.println(); - fmt.print("Type of v1 is:\n\t", t1); - - fmt.println(); - fmt.print("Type of v2 is:\n\t", t2); - - fmt.println("\n"); - fmt.println("t1 == t2:", t1 == t2); - fmt.println("t2 == t3:", t2 == t3); - } -} - -any_type :: proc() { - a: any; - - x: int = 123; - y: f64 = 6.28; - z: string = "Yo-Yo Ma"; - // All types can be implicit cast to `any` - a = x; - a = y; - a = z; - a = a; // This the "identity" type, it doesn't get converted - - a = 123; // Literals are copied onto the stack first - - // any has two members - // data - rawptr to the data - // type_info - pointer to the type info - - fmt.println(x, y, z); - // See: fmt.odin - // For variadic any procedures in action -} - -crazy_introspection :: proc() { - { - Fruit :: enum { - APPLE, - BANANA, - GRAPE, - MELON, - PEACH, - TOMATO, - } - - s: string; - // s = enum_to_string(Fruit.PEACH); - fmt.println(s); - - f := Fruit.GRAPE; - // s = enum_to_string(f); - fmt.println(s); - - fmt.println(f); - // See: runtime.odin - } - - - { - // NOTE(bill): This is not safe code and I would not recommend this at all - // I'd recommend you use `match type` to get the subtype rather than - // casting pointers - - Fruit :: enum { - APPLE, - BANANA, - GRAPE, - MELON, - PEACH, - TOMATO, - } - - fruit_ti := type_info_of(Fruit); - name := fruit_ti.variant.(Type_Info_Named).name; - info, _ := type_info_base(fruit_ti).variant.(Type_Info_Enum); - - fmt.printf("%s :: enum %T {\n", name, info.base); - for _, i in info.values { - fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]); - } - fmt.printf("}\n"); - - // NOTE(bill): look at that type-safe printf! - } - - { - Vector3 :: struct {x, y, z: f32} - - a := Vector3{x = 1, y = 4, z = 9}; - fmt.println(a); - b := Vector3{x = 9, y = 3, z = 1}; - fmt.println(b); - - // NOTE(bill): See fmt.odin - } - - // n.b. This pretty much "solves" serialization (to strings) -} - -// #import "test.odin" - -namespaces_and_files :: proc() { - - // test.thing() - // test.format.println() - // test.println() - /* - // Non-exporting import - #import "file.odin" - #import "file.odin" as file - #import "file.odin" as . - #import "file.odin" as _ - - // Exporting import - #include "file.odin" - */ - - // Talk about scope rules and diagram -} - -miscellany :: proc() { - /* - win32 `__imp__` prefix - #dll_import - #dll_export - - Change exported name/symbol for linking - #link_name - - Custom calling conventions - #stdcall - #fastcall - - Runtime stuff - #shared_global_scope - */ - - // assert(false) - // #assert(false) - // panic("Panic message goes here") -} - - - - diff --git a/examples/old_demos/demo002.odin b/examples/old_demos/demo002.odin deleted file mode 100644 index a790aadf3..000000000 --- a/examples/old_demos/demo002.odin +++ /dev/null @@ -1,879 +0,0 @@ -// Demo 002 -export "core:fmt.odin"; -export "core:math.odin"; -export "core:mem.odin"; -// export "game.odin" - -#thread_local tls_int: int; - -main :: proc() { - // Forenotes - - // Semicolons are now optional - // Rule for when a semicolon is expected after a statement - // - If the next token is not on the same line - // - if the next token is a closing brace } - // - Otherwise, a semicolon is needed - // - // Expections: - // for, if, match - // if x := thing(); x < 123 {} - // for i := 0; i < 123; i++ {} - - // Q: Should I use the new rule or go back to the old one without optional semicolons? - - - // #thread_local - see runtime.odin and above at `tls_int` - // #foreign_system_library - see win32.odin - - // struct_compound_literals(); - // enumerations(); - // variadic_procedures(); - // new_builtins(); - // match_statement(); - // namespacing(); - // subtyping(); - // tagged_unions(); -} - -struct_compound_literals :: proc() { - Thing :: struct { - id: int, - x: f32, - name: string, - }; - { - t1: Thing; - t1.id = 1; - - t3 := Thing{}; - t4 := Thing{1, 2, "Fred"}; - // t5 := Thing{1, 2}; - - t6 := Thing{ - name = "Tom", - x = 23, - }; - } -} - -enumerations :: proc() { - { - Fruit :: enum { - APPLE, // 0 - BANANA, // 1 - PEAR, // 2 - }; - - f := Fruit.APPLE; - // g12: int = Fruit.BANANA - g: int = cast(int)Fruit.BANANA; - // However, you can use enums are index values as _any_ integer allowed - } - { - Fruit1 :: enum int { - APPLE, - BANANA, - PEAR, - } - - Fruit2 :: enum u8 { - APPLE, - BANANA, - PEAR, - } - - Fruit3 :: enum u8 { - APPLE = 1, - BANANA, // 2 - PEAR = 5, - TOMATO, // 6 - } - } - - // Q: remove the need for `type` if it's a record (struct/enum/raw_union/union)? -} - -variadic_procedures :: proc() { - print_ints :: proc(args: ..int) { - for arg, i in args { - if i > 0 do print(", "); - print(arg); - } - } - - print_ints(); // nl() - print_ints(1); nl(); - print_ints(1, 2, 3); nl(); - - print_prefix_f32s :: proc(prefix: string, args: ..f32) { - print(prefix); - print(": "); - for arg, i in args { - if i > 0 do print(", "); - print(arg); - } - } - - print_prefix_f32s("a"); nl(); - print_prefix_f32s("b", 1); nl(); - print_prefix_f32s("c", 1, 2, 3); nl(); - - // Internally, the variadic procedures get allocated to an array on the stack, - // and this array is passed a slice - - // This is first step for a `print` procedure but I do not have an `any` type - // yet as this requires a few other things first - i.e. introspection - - // NOTE(bill): I haven't yet added the feature of expanding a slice or array into - // a variadic a parameter but it's pretty trivial to add -} - -new_builtins :: proc() { - { - a := new(int); - b := make([]int, 12); - c := make([]int, 12, 16); - - defer free(a); - defer free(b); - defer free(c); - - // NOTE(bill): These use the current context's allocator not the default allocator - // see runtime.odin - - // Q: Should this be `free` rather than `free` and should I overload it for slices too? - - push_allocator default_allocator() { - a := new(int); - defer free(a); - - // Do whatever - - } - } - - { - a: int = 123; - b: type_of(a) = 321; - - // NOTE(bill): This matches the current naming scheme - // size_of - // align_of - // offset_of - // - // size_of_val - // align_of_val - // offset_of_val - // type_of_val - } - - { - // Compile time assert - COND :: true; - #assert(COND); - // #assert(!COND) - - // Runtime assert - x := true; - assert(x); - // assert(!x); - } - - { - x: ^u32 = nil; - y := x+100; - z := y-x; - w := slice_ptr(x, 12); - t := slice_ptr(x, 12, 16); - - // NOTE(bill): These are here because I've removed: - // pointer arithmetic - // pointer indexing - // pointer slicing - - // Reason - - a: [16]int; - a[1] = 1; - b := &a; - // Auto pointer deref - // consistent with record members - assert(b[1] == 1); - - // Q: Should I add them back in at the cost of inconsitency? - } - - { - a, b := -1, 2; - print(min(a, b)); nl(); - print(max(a, b)); nl(); - print(abs(a)); nl(); - - // These work at compile time too - A :: -1; - B :: 2; - C :: min(A, B); - D :: max(A, B); - E :: abs(A); - - print(C); nl(); - print(D); nl(); - print(E); nl(); - } -} - - -match_statement :: proc() { - // NOTE(bill): `match` statements are similar to `switch` statements - // in other languages but there are few differences - - { - match x := 5; x { - case 1: // cases must be constant expression - print("1!\n"); - // break by default - - case 2: - s := "2!\n"; // Each case has its own scope - print(s); - break; // explicit break - - case 3, 4: // multiple cases - print("3 or 4!\n"); - - case 5: - print("5!\n"); - fallthrough; // explicit fallthrough - - case: - print("default!\n"); - } - - - - match x := 1.5; x { - case 1.5: - print("1.5!\n"); - // break by default - case TAU: - print("τ!\n"); - case: - print("default!\n"); - } - - - - match x := "Hello"; x { - case "Hello": - print("greeting\n"); - // break by default - case "Goodbye": - print("farewell\n"); - case: - print("???\n"); - } - - - - - - - a := 53; - match { - case a == 1: - print("one\n"); - case a == 2: - print("a couple\n"); - case a < 7, a == 7: - print("a few\n"); - case a < 12: // intentional bug - print("several\n"); - case a >= 12 && a < 100: - print("dozens\n"); - case a >= 100 && a < 1000: - print("hundreds\n"); - case: - print("a fuck ton\n"); - } - - // Identical to this - - b := 53; - if b == 1 { - print("one\n"); - } else if b == 2 { - print("a couple\n"); - } else if b < 7 || b == 7 { - print("a few\n"); - } else if b < 12 { // intentional bug - print("several\n"); - } else if b >= 12 && b < 100 { - print("dozens\n"); - } else if b >= 100 && b < 1000 { - print("hundreds\n"); - } else { - print("a fuck ton\n"); - } - - // However, match statements allow for `break` and `fallthrough` unlike - // an if statement - } -} - -Vector3 :: struct {x, y, z: f32} - -print_floats :: proc(args: ..f32) { - for arg, i in args { - if i > 0 do print(", "); - print(arg); - } - println(); -} - -namespacing :: proc() { - { - Thing :: #type struct { - x: f32, - name: string, - }; - - a: Thing; - a.x = 3; - { - Thing :: #type struct { - y: int, - test: bool, - }; - - b: Thing; // Uses this scope's Thing - b.test = true; - } - } -/* - { - Entity :: struct { - Guid :: int - Nested :: struct { - MyInt :: int - i: int - } - - CONSTANT :: 123 - - - guid: Guid - name: string - pos: Vector3 - vel: Vector3 - nested: Nested - } - - guid: Entity.Guid = Entity.CONSTANT - i: Entity.Nested.MyInt - - - - { - using Entity - guid: Guid = CONSTANT - using Nested - i: MyInt - } - - - { - using Entity.Nested - guid: Entity.Guid = Entity.CONSTANT - i: MyInt - } - - - { - e: Entity - using e - guid = 27832 - name = "Bob" - - print(e.guid as int); nl() - print(e.name); nl() - } - - { - using e: Entity - guid = 78456 - name = "Thing" - - print(e.guid as int); nl() - print(e.name); nl() - } - } - - { - Entity :: struct { - Guid :: int - Nested :: struct { - MyInt :: int - i: int - } - - CONSTANT :: 123 - - - guid: Guid - name: string - using pos: Vector3 - vel: Vector3 - using nested: ^Nested - } - - e := Entity{nested = new(Entity.Nested)} - e.x = 123 - e.i = Entity.CONSTANT - } - -*/ - - { - Entity :: struct { - position: Vector3 - } - - print_pos_1 :: proc(entity: ^Entity) { - print("print_pos_1: "); - print_floats(entity.position.x, entity.position.y, entity.position.z); - } - - print_pos_2 :: proc(entity: ^Entity) { - using entity; - print("print_pos_2: "); - print_floats(position.x, position.y, position.z); - } - - print_pos_3 :: proc(using entity: ^Entity) { - print("print_pos_3: "); - print_floats(position.x, position.y, position.z); - } - - print_pos_4 :: proc(using entity: ^Entity) { - using position; - print("print_pos_4: "); - print_floats(x, y, z); - } - - e := Entity{position = Vector3{1, 2, 3}}; - print_pos_1(&e); - print_pos_2(&e); - print_pos_3(&e); - print_pos_4(&e); - - // This is similar to C++'s `this` pointer that is implicit and only available in methods - } -} - -subtyping :: proc() { - { - // C way for subtyping/subclassing - - Entity :: struct { - position: Vector3, - } - - Frog :: struct { - entity: Entity, - jump_height: f32, - } - - f: Frog; - f.entity.position = Vector3{1, 2, 3}; - - using f.entity; - position = Vector3{1, 2, 3}; - - } - - { - // C++ way for subtyping/subclassing - - Entity :: struct { - position: Vector3 - } - - Frog :: struct { - using entity: Entity, - jump_height: f32, - } - - f: Frog; - f.position = Vector3{1, 2, 3}; - - - print_pos :: proc(using entity: Entity) { - print("print_pos: "); - print_floats(position.x, position.y, position.z); - } - - print_pos(f.entity); - // print_pos(f); - - // Subtype Polymorphism - } - - { - // More than C++ way for subtyping/subclassing - - Entity :: struct { - position: Vector3, - } - - Frog :: struct { - jump_height: f32, - using entity: ^Entity, // Doesn't have to be first member! - } - - f: Frog; - f.entity = new(Entity); - f.position = Vector3{1, 2, 3}; - - - print_pos :: proc(using entity: ^Entity) { - print("print_pos: "); - print_floats(position.x, position.y, position.z); - } - - print_pos(f.entity); - // print_pos(^f); - // print_pos(f); - } - - { - // More efficient subtyping - - Entity :: struct { - position: Vector3, - } - - Frog :: struct { - jump_height: f32, - using entity: ^Entity, - } - - MAX_ENTITES :: 64; - entities: [MAX_ENTITES]Entity; - entity_count := 0; - - next_entity :: proc(entities: []Entity, entity_count: ^int) -> ^Entity { - e := &entities[entity_count^]; - entity_count^ += 1; - return e; - } - - f: Frog; - f.entity = next_entity(entities[..], &entity_count); - f.position = Vector3{3, 4, 6}; - - using f.position; - print_floats(x, y, z); - } - - /*{ - // Down casting - - Entity :: struct { - position: Vector3, - } - - Frog :: struct { - jump_height: f32, - using entity: Entity, - } - - f: Frog; - f.jump_height = 564; - e := ^f.entity; - - frog := down_cast(^Frog)e; - print("down_cast: "); - print(frog.jump_height); nl(); - - // NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time - // Q: Should I completely remove `down_cast` as I added it in about 30 minutes - }*/ - - { - // Multiple "inheritance"/subclassing - - Entity :: struct { - position: Vector3, - } - Climber :: struct { - speed: f32, - } - - Frog :: struct { - using entity: Entity, - using climber: Climber, - } - } -} - -tagged_unions :: proc() { - { - Entity_Kind :: enum { - INVALID, - FROG, - GIRAFFE, - HELICOPTER, - } - - Entity :: struct { - kind: Entity_Kind - using data: struct #raw_union { - frog: struct { - jump_height: f32, - colour: u32, - }, - giraffe: struct { - neck_length: f32, - spot_count: int, - }, - helicopter: struct { - blade_count: int, - weight: f32, - pilot_name: string, - }, - } - } - - e: Entity; - e.kind = Entity_Kind.FROG; - e.frog.jump_height = 12; - - f: type_of(e.frog); - - // But this is very unsafe and extremely cumbersome to write - // In C++, I use macros to alleviate this but it's not a solution - } - - { - Frog :: struct { - jump_height: f32, - colour: u32, - } - Giraffe :: struct { - neck_length: f32, - spot_count: int, - } - Helicopter :: struct { - blade_count: int, - weight: f32, - pilot_name: string, - } - Entity :: union {Frog, Giraffe, Helicopter}; - - f1: Frog = Frog{12, 0xff9900}; - f2: Entity = Frog{12, 0xff9900}; // Implicit cast - f3 := cast(Entity)Frog{12, 0xff9900}; // Explicit cast - - // f3.Frog.jump_height = 12 // There are "members" of a union - - - - e, f, g, h: Entity; - f = Frog{12, 0xff9900}; - g = Giraffe{2.1, 23}; - h = Helicopter{4, 1000, "Frank"}; - - - - - // Requires a pointer to the union - // `x` will be a pointer to type of the case - - match x in &f { - case Frog: - print("Frog!\n"); - print(x.jump_height); nl(); - // x.jump_height = 3; - print(x.jump_height); nl(); - case Giraffe: - print("Giraffe!\n"); - case Helicopter: - print("ROFLCOPTER!\n"); - case: - print("invalid entity\n"); - } - - - // Q: Allow for a non pointer version with takes a copy instead? - // Or it takes the pointer the data and not a copy - - - // fp := cast(^Frog)^f; // Unsafe - // print(fp.jump_height); nl(); - - - // Internals of a tagged union - /* - struct { - data: [size_of_biggest_tag]u8, - tag_index: int, - } - */ - // This is to allow for pointer casting if needed - - - // Advantage over subtyping version - MAX_ENTITES :: 64; - entities: [MAX_ENTITES]Entity; - - entities[0] = Frog{}; - entities[1] = Helicopter{}; - // etc. - } - - - { - // Transliteration of code from this actual compiler - // Some stuff is missing - Type :: struct {}; - Scope :: struct {}; - Token :: struct {}; - AstNode :: struct {}; - ExactValue :: struct {}; - - Entity_Kind :: enum { - Invalid, - Constant, - Variable, - Using_Variable, - TypeName, - Procedure, - Builtin, - Count, - } - - Guid :: i64; - Entity :: struct { - - kind: Entity_Kind, - guid: Guid, - - scope: ^Scope, - token: Token, - type_: ^Type, - - using data: struct #raw_union { - Constant: struct { - value: ExactValue, - }, - Variable: struct { - visited: bool, // Cycle detection - used: bool, // Variable is used - is_field: bool, // Is struct field - anonymous: bool, // Variable is an anonymous - }, - Using_Variable: struct { - }, - TypeName: struct { - }, - Procedure: struct { - used: bool, - }, - Builtin: struct { - id: int, - }, - }, - } - - // Plus all the constructing procedures that go along with them!!!! - // It's a nightmare - } - - { - Type :: struct {}; - Scope :: struct {}; - Token :: struct {}; - AstNode :: struct {}; - ExactValue :: struct {}; - - - Guid :: i64; - Entity_Base :: struct { - } - - - Constant :: struct { - value: ExactValue, - } - Variable :: struct { - visited: bool, // Cycle detection - used: bool, // Variable is used - is_field: bool, // Is struct field - anonymous: bool, // Variable is an anonymous - } - Using_Variable :: struct { - } - TypeName :: struct { - } - Procedure :: struct { - used: bool, - } - Builtin :: struct { - id: int, - } - - Entity :: struct { - guid: Guid, - - scope: ^Scope, - token: Token, - type_: ^Type, - - variant: union {Constant, Variable, Using_Variable, TypeName, Procedure, Builtin}, - } - - e := Entity{ - variant = Variable{ - used = true, - anonymous = false, - }, - }; - - - - // Q: Allow a "base" type to be added to a union? - // Or even `using` on union to get the same properties? - } - - - { - // `Raw` unions still have uses, especially for mathematic types - - Vector2 :: struct #raw_union { - using xy_: struct { x, y: f32 }, - e: [2]f32, - v: [vector 2]f32, - } - - Vector3 :: struct #raw_union { - using xyz_: struct { x, y, z: f32 }, - xy: Vector2, - e: [3]f32, - v: [vector 3]f32, - } - - v2: Vector2; - v2.x = 1; - v2.e[0] = 1; - v2.v[0] = 1; - - v3: Vector3; - v3.x = 1; - v3.e[0] = 1; - v3.v[0] = 1; - v3.xy.x = 1; - } -} - -nl :: proc() { println(); } diff --git a/examples/old_demos/demo004.odin b/examples/old_demos/demo004.odin deleted file mode 100644 index c9acc9a15..000000000 --- a/examples/old_demos/demo004.odin +++ /dev/null @@ -1,66 +0,0 @@ -import "core:fmt.odin"; -import "core:utf8.odin"; -import "core:hash.odin"; -import "core:mem.odin"; - -main :: proc() { - { // New Standard Library stuff - s := "Hello"; - fmt.println(s, - utf8.valid_string(s), - hash.murmur64(cast([]u8)s)); - - // utf8.odin - // hash.odin - // - crc, fnv, fnva, murmur - // mem.odin - // - Custom allocators - // - Helpers - } - - { - arena: mem.Arena; - mem.init_arena_from_context(&arena, mem.megabytes(16)); // Uses default allocator - defer mem.destroy_arena(&arena); - - push_allocator mem.arena_allocator(&arena) { - x := new(int); - x^ = 1337; - - fmt.println(x^); - } - - /* - push_allocator x { - .. - } - - is equivalent to: - - { - prev_allocator := __context.allocator - __context.allocator = x - defer __context.allocator = prev_allocator - - .. - } - */ - - // You can also "push" a context - - c := context; // Create copy of the allocator - c.allocator = mem.arena_allocator(&arena); - - push_context c { - x := new(int); - x^ = 365; - - fmt.println(x^); - } - } - - // Backend improvements - // - Minimal dependency building (only build what is needed) - // - Numerous bugs fixed - // - Mild parsing recovery after bad syntax error -} diff --git a/examples/old_demos/demo005.odin b/examples/old_demos/demo005.odin deleted file mode 100644 index c8273b03b..000000000 --- a/examples/old_demos/demo005.odin +++ /dev/null @@ -1,283 +0,0 @@ -import "core:fmt.odin"; -import "core:utf8.odin"; -// import "core:atomic.odin"; -// import "core:hash.odin"; -// import "core:math.odin"; -// import "core:mem.odin"; -// import "core:opengl.odin"; -// import "core:os.odin"; -// import "core:sync.odin"; -// import win32 "core:sys/windows.odin"; - -main :: proc() { - // syntax(); - procedure_overloading(); -} - -syntax :: proc() { - // Cyclic type checking - // Uncomment to see the error - // A :: struct {b: B}; - // B :: struct {a: A}; - - x: int; - y := cast(f32)x; - z := transmute(u32)y; - // down_cast, union_cast are similar too - - - - // Basic directives - fmt.printf("Basic directives = %s(%d): %s\n", #file, #line, #procedure); - // NOTE: new and improved `printf` - // TODO: It does need accurate float printing - - - - // record fields use the same syntax a procedure signatures - Thing1 :: struct { - x: f32, - y: int, - z: ^[]int, - }; - Thing2 :: struct {x: f32, y: int, z: ^[]int}; - - // Slice interals are now just a `ptr+len+cap` - slice: []int; #assert(size_of(slice) == 3*size_of(int)); - - // Helper type - Help the reader understand what it is quicker - My_Int :: #type int; - My_Proc :: #type proc(int) -> f32; - - - // All declarations with : are either variable or constant - // To make these declarations syntactically consistent - v_variable := 123; - c_constant :: 123; - c_type1 :: int; - c_type2 :: []int; - c_proc :: proc() { /* code here */ }; - - -/* - x += 1; - x -= 1; - // ++ and -- have been removed - // x++; - // x--; - // Question: Should they be added again? - // They were removed as they are redundant and statements, not expressions - // like in C/C++ -*/ - - // You can now build files as a `.dll` - // `odin build_dll demo.odin` - - - // New vector syntax - u, v: [vector 3]f32; - v[0] = 123; - v.x = 123; // valid for all vectors with count 1 to 4 - - // Next part - prefixes(); -} - - -Prefix_Type :: struct {x: int, y: f32, z: rawptr}; - -#thread_local my_tls: Prefix_Type; - -prefixes :: proc() { - using var: Prefix_Type; - var.x = 123; - x = 123; - - - foo :: proc(using pt: Prefix_Type) { - } - - - - // Same as C99's `restrict` - bar :: proc(#no_alias a, b: ^int) { - // Assumes a never equals b so it can perform optimizations with that fact - } - - - when_statements(); -} - - - - - -when_statements :: proc() { - X :: 123 + 12; - Y :: X/5; - COND :: Y > 0; - - when COND { - fmt.println("Y > 0"); - } else { - fmt.println("Y <= 0"); - } - - - when false { - this_code_does_not_exist(123, 321); - but_its_syntax_is_valid(); - x :: ^^^^int; - } - - foreign_procedures(); -} - -when ODIN_OS == "windows" { - foreign_system_library win32_user "user32.lib"; -} -// NOTE: This is done on purpose for two reasons: -// * Makes it clear where the platform specific stuff is -// * Removes the need to solve the travelling salesman problem when importing files :P - -foreign_procedures :: proc() { - foreign win32_user { - ShowWindow :: proc(hwnd: rawptr, cmd_show: i32) -> i32 ---; - show_window :: proc(hwnd: rawptr, cmd_show: i32) -> i32 #link_name "ShowWindow" ---; - } - // NOTE: If that library doesn't get used, it doesn't get linked with - // NOTE: There is not link checking yet to see if that procedure does come from that library - - // See sys/windows.odin for more examples - - special_expressions(); -} - -special_expressions :: proc() { -/* - // Block expression - x := { - a: f32 = 123; - b := a-123; - c := b/a; - give c; - }; // semicolon is required as it's an expression - - y := if x < 50 { - give x; - } else { - // TODO: Type cohesion is not yet finished - give 123; - }; // semicolon is required as it's an expression -*/ - - // This is allows for inline blocks of code and will be a useful feature to have when - // macros will be implemented into the language - - loops(); -} - -loops :: proc() { - // The C-style for loop - for i := 0; i < 123; i += 1 { - break; - } - for i := 0; i < 123; { - break; - } - for false { - break; - } - for { - break; - } - - for i in 0..123 { // 123 exclusive - } - - for i in 0..123-1 { // 122 inclusive - } - - for val, idx in 12..16 { - fmt.println(val, idx); - } - - primes := [?]int{2, 3, 5, 7, 11, 13, 17, 19}; - - for p in primes { - fmt.println(p); - } - - // Pointers to arrays, slices, or strings are allowed - for _ in &primes { - // ignore the value and just iterate across it - } - - - - name := "你好,世界"; - fmt.println(name); - for r in name { - #assert(type_of(r) == rune); - fmt.printf("%r\n", r); - } - - when false { - for i, size := 0; i < name.count; i += size { - r: rune; - r, size = utf8.decode_rune(name[i..]); - fmt.printf("%r\n", r); - } - } - - procedure_overloading(); -} - - -procedure_overloading :: proc() { - THINGF :: 14451.1; - THINGI :: 14451; - - foo :: proc() { - fmt.printf("Zero args\n"); - } - foo :: proc(i: int) { - fmt.printf("int arg, i=%d\n", i); - } - foo :: proc(f: f64) { - i := cast(int)f; - fmt.printf("f64 arg, f=%d\n", i); - } - - foo(); - foo(THINGF); - // foo(THINGI); // 14451 is just a number so it could go to either procedures - foo(cast(int)THINGI); - - - - - foo :: proc(x: ^i32) -> (int, int) { - fmt.println("^int"); - return 123, cast(int)(x^); - } - foo :: proc(x: rawptr) { - fmt.println("rawptr"); - } - - - a: i32 = 123; - b: f32; - c: rawptr; - fmt.println(foo(&a)); - foo(&b); - foo(c); - // foo(nil); // nil could go to numerous types thus the ambiguity - - f: proc(); - f = foo; // The correct `foo` to chosen - f(); - - - // See math.odin and atomic.odin for more examples -} diff --git a/examples/old_demos/demo006.odin b/examples/old_demos/demo006.odin deleted file mode 100644 index c2f64151b..000000000 --- a/examples/old_demos/demo006.odin +++ /dev/null @@ -1,310 +0,0 @@ -// import "core:atomic.odin"; -import "core:hash.odin"; -import "core:mem.odin"; -import "core:opengl.odin"; -import "core:strconv.odin"; -import "core:sync.odin"; -import win32 "core:sys/windows.odin"; - -import "core:fmt.odin"; -import "core:os.odin"; -import "core:math.odin"; - - -main :: proc() { -when true { -/* - Added: - * Unexported entities and fields using an underscore prefix - - See `sync.odin` and explain - - Removed: - * Maybe/option types - * Remove `type` keyword and other "reserved" keywords - * ..< and .. removed and replace with .. (half-closed range) - - Changed: - * `#assert` and `assert` return the value of the condition for semantic reasons - * thread_local -> #thread_local - * #include -> #load - * Files only get checked if they are actually used - * match x in y {} // For type match statements - * Version numbering now starts from 0.1.0 and uses the convention: - - major.minor.patch - * Core library additions to Windows specific stuff - */ - - { - Fruit :: enum { - APPLE, - BANANA, - COCONUT, - } - fmt.println(Fruit.names); - } - - { - A :: struct {x, y: f32}; - B :: struct #align 16 {x, y: f32}; - fmt.println("align_of(A) =", align_of(A)); - fmt.println("align_of(B) =", align_of(B)); - } - - { - // Removal of ..< and .. - for i in 0..16 { - } - // Is similar to - for i := 0; i < 16; i += 1 { - } - } - - { - thing: for i in 0..10 { - for j in i+1..10 { - if j == 2 { - fmt.println(i, j); - continue thing; - } - if j == 3 { - break thing; - } - } - } - - // Works with, `for`, `for in`, `match`, `match in` - // NOTE(bill): This solves most of the problems I need `goto` for - } - - { - t := type_info_of(int); - match i in t.variant { - case Type_Info_Integer, Type_Info_Float: - fmt.println("It's a number"); - } - - - x: any = 123; - foo: match i in x { - case int, f32: - fmt.println("It's an int or f32"); - break foo; - } - } - - { - cond := true; - x: int; - if cond { - x = 3; - } else { - x = 4; - } - - - // Ternary operator - y := cond ? 3 : 4; - - FOO :: true ? 123 : 432; // Constant ternary expression - fmt.println("Ternary values:", y, FOO); - } - - { - // Slices now store a capacity - buf: [256]u8; - s: []u8; - s = buf[..0]; // == buf[0..0]; - fmt.println("count =", len(s)); - fmt.println("capacity =", cap(s)); - append(&s, 1, 2, 3); - fmt.println(s); - - s = buf[1..2..3]; - fmt.println("count =", len(s)); - fmt.println("capacity =", cap(s)); - fmt.println(s); - - clear(&s); // Sets count to zero - } - - { - Foo :: struct { - x, y, z: f32, - ok: bool, - flags: u32, - } - foo_array: [256]Foo; - foo_as_bytes: []u8 = mem.slice_to_bytes(foo_array[..]); - // Useful for things like - // os.write(handle, foo_as_bytes); - - foo_slice := mem.slice_ptr(cast(^Foo)&foo_as_bytes[0], len(foo_as_bytes)/size_of(Foo), cap(foo_as_bytes)/size_of(Foo)); - // Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone? - // And if so what would the syntax be? - // slice_transmute([]Foo, foo_as_bytes); - } - - { - Vec3 :: [vector 3]f32; - - x := Vec3{1, 2, 3}; - y := Vec3{4, 5, 6}; - fmt.println(x < y); - fmt.println(x + y); - fmt.println(x - y); - fmt.println(x * y); - fmt.println(x / y); - - for i in x { - fmt.println(i); - } - - #assert(size_of([vector 7]bool) >= size_of([7]bool)); - #assert(size_of([vector 7]i32) >= size_of([7]i32)); - // align_of([vector 7]i32) != align_of([7]i32) // this may be the case - } - - { - // fmt.* changes - // bprint* returns `string` - - data: [256]u8; - str := fmt.bprintf(data[..], "Hellope %d %s %c", 123, "others", '!'); - fmt.println(str); - } - - { - x: [dynamic]f64; - reserve(&x, 16); - defer free(x); // `free` is overloaded for numerous types - // Number literals can have underscores in them for readability - append(&x, 2_000_000.500_000, 123, 5, 7); // variadic append - - for p, i in x { - if i > 0 { fmt.print(", "); } - fmt.print(p); - } - fmt.println(); - } - - { - // Dynamic array "literals" - x := [dynamic]f64{2_000_000.500_000, 3, 5, 7}; - defer free(x); - fmt.println(x); // fmt.print* supports printing of dynamic types - clear(&x); - fmt.println(x); - } - - { - m: map[f32]int; - reserve(&m, 16); - defer free(m); - - m[1.0] = 1278; - m[2.0] = 7643; - m[3.0] = 564; - _, ok := m[3.0]; - c := m[3.0]; - assert(ok && c == 564); - - fmt.print("map["); - i := 0; - for val, key in m { - if i > 0 { - fmt.print(", "); - } - fmt.printf("%v=%v", key, val); - i += 1; - } - fmt.println("]"); - } - { - m := map[string]u32{ - "a" = 56, - "b" = 13453, - "c" = 7654, - }; - defer free(m); - - c := m["c"]; - _, ok := m["c"]; - assert(ok && c == 7654); - fmt.println(m); - - delete(&m, "c"); // deletes entry with key "c" - _, found := m["c"]; - assert(!found); - - fmt.println(m); - clear(&m); - fmt.println(m); - - // NOTE: Fixed size maps are planned but we have not yet implemented - // them as we have had no need for them as of yet - } - - { - Vector3 :: struct{x, y, z: f32}; - Quaternion :: struct{x, y, z, w: f32}; - - // Variants - Frog :: struct { - ribbit_volume: f32, - jump_height: f32, - } - Door :: struct { - openness: f32, - } - Map :: struct { - width, height: f32, - place_positions: []Vector3, - place_names: []string, - } - - Entity :: struct { - // Common Fields - id: u64, - name: string, - using position: Vector3, - orientation: Quaternion, - flags: u32, - - variant: union { Frog, Door, Map }, - } - - entity: Entity; - entity.id = 1337; - // implicit conversion from variant to base type - entity.variant = Frog{ - ribbit_volume = 0.5, - jump_height = 2.1, - /*other data */ - }; - - entity.name = "Frank"; - entity.position = Vector3{1, 4, 9}; - - match e in entity.variant { - case Frog: - fmt.println("Ribbit"); - case Door: - fmt.println("Creak"); - case Map: - fmt.println("Rustle"); - case: - fmt.println("Just a normal entity"); - } - - if frog, ok := entity.variant.(Frog); ok { - fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, entity.position); - } - - // Panics if not the correct type - frog: Frog; - frog = entity.variant.(Frog); - frog, _ = entity.variant.(Frog); // ignore error and force cast - } -} -} - diff --git a/examples/old_demos/demo007.odin b/examples/old_demos/demo007.odin deleted file mode 100644 index d19446ecb..000000000 --- a/examples/old_demos/demo007.odin +++ /dev/null @@ -1,570 +0,0 @@ -import "core:fmt.odin" -import "core:strconv.odin" -import "core:mem.odin" -import "core:bits.odin" -import "core:hash.odin" -import "core:math.odin" -import "core:os.odin" -import "core:raw.odin" -import "core:sort.odin" -import "core:strings.odin" -import "core:types.odin" -import "core:utf16.odin" -import "core:utf8.odin" - -when ODIN_OS == "windows" { - import "core:atomics.odin" - import "core:opengl.odin" - import "core:thread.odin" - import win32 "core:sys/windows.odin" -} - -general_stuff :: proc() { - { // `do` for inline statmes rather than block - foo :: proc() do fmt.println("Foo!"); - if false do foo(); - for false do foo(); - when false do foo(); - - if false do foo(); - else do foo(); - } - - { // Removal of `++` and `--` (again) - x: int; - x += 1; - x -= 1; - } - { // Casting syntaxes - i := i32(137); - ptr := &i; - - fp1 := (^f32)(ptr); - // ^f32(ptr) == ^(f32(ptr)) - fp2 := cast(^f32)ptr; - - f1 := (^f32)(ptr)^; - f2 := (cast(^f32)ptr)^; - - // Questions: Should there be two ways to do it? - } - - /* - * Remove *_val_of built-in procedures - * size_of, align_of, offset_of - * type_of, type_info_of - */ - - { // `expand_to_tuple` built-in procedure - Foo :: struct { - x: int, - b: bool, - } - f := Foo{137, true}; - x, b := expand_to_tuple(f); - fmt.println(f); - fmt.println(x, b); - fmt.println(expand_to_tuple(f)); - } - - { - // .. half-closed range - // .. open range - - for in 0..2 {} // 0, 1 - for in 0..2 {} // 0, 1, 2 - } -} - -default_struct_values :: proc() { - { - Vector3 :: struct { - x: f32, - y: f32, - z: f32, - } - v: Vector3; - fmt.println(v); - } - { - // Default values must be constants - Vector3 :: struct { - x: f32 = 1, - y: f32 = 4, - z: f32 = 9, - } - v: Vector3; - fmt.println(v); - - v = Vector3{}; - fmt.println(v); - - // Uses the same semantics as a default values in a procedure - v = Vector3{137}; - fmt.println(v); - - v = Vector3{z = 137}; - fmt.println(v); - } - - { - Vector3 :: struct { - x := 1.0, - y := 4.0, - z := 9.0, - } - stack_default: Vector3; - stack_literal := Vector3{}; - heap_one := new(Vector3); defer free(heap_one); - heap_two := new_clone(Vector3{}); defer free(heap_two); - - fmt.println("stack_default - ", stack_default); - fmt.println("stack_literal - ", stack_literal); - fmt.println("heap_one - ", heap_one^); - fmt.println("heap_two - ", heap_two^); - - - N :: 4; - stack_array: [N]Vector3; - heap_array := new([N]Vector3); defer free(heap_array); - heap_slice := make([]Vector3, N); defer free(heap_slice); - fmt.println("stack_array[1] - ", stack_array[1]); - fmt.println("heap_array[1] - ", heap_array[1]); - fmt.println("heap_slice[1] - ", heap_slice[1]); - } -} - - - - -union_type :: proc() { - { - val: union{int, bool}; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - { - // There is a duality between `any` and `union` - // An `any` has a pointer to the data and allows for any type (open) - // A `union` has as binary blob to store the data and allows only certain types (closed) - // The following code is with `any` but has the same syntax - val: any; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - - Vector3 :: struct {x, y, z: f32}; - Quaternion :: struct {x, y, z: f32, w: f32 = 1}; - - // More realistic examples - { - // NOTE(bill): For the above basic examples, you may not have any - // particular use for it. However, my main use for them is not for these - // simple cases. My main use is for hierarchical types. Many prefer - // subtyping, embedding the base data into the derived types. Below is - // an example of this for a basic game Entity. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: any, - } - - Frog :: struct { - using entity: Entity, - jump_height: f32, - } - - Monster :: struct { - using entity: Entity, - is_robot: bool, - is_zombie: bool, - } - - // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { - t := new(T); - t.derived = t^; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - } - } - - { - // NOTE(bill): A union can be used to achieve something similar. Instead - // of embedding the base data into the derived types, the derived data - // in embedded into the base type. Below is the same example of the - // basic game Entity but using an union. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: union {Frog, Monster}, - } - - Frog :: struct { - using entity: ^Entity, - jump_height: f32, - } - - Monster :: struct { - using entity: ^Entity, - is_robot: bool, - is_zombie: bool, - } - - // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { - t := new(Entity); - t.derived = T{entity = t}; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - } - - // NOTE(bill): As you can see, the usage code has not changed, only its - // memory layout. Both approaches have their own advantages but they can - // be used together to achieve different results. The subtyping approach - // can allow for a greater control of the memory layout and memory - // allocation, e.g. storing the derivatives together. However, this is - // also its disadvantage. You must either preallocate arrays for each - // derivative separation (which can be easily missed) or preallocate a - // bunch of "raw" memory; determining the maximum size of the derived - // types would require the aid of metaprogramming. Unions solve this - // particular problem as the data is stored with the base data. - // Therefore, it is possible to preallocate, e.g. [100]Entity. - - // It should be noted that the union approach can have the same memory - // layout as the any and with the same type restrictions by using a - // pointer type for the derivatives. - - /* - Entity :: struct { - .. - derived: union{^Frog, ^Monster}; - } - - Frog :: struct { - using entity: Entity; - .. - } - Monster :: struct { - using entity: Entity; - .. - - } - new_entity :: proc(T: type) -> ^Entity { - t := new(T); - t.derived = t; - return t; - } - */ - } -} - -parametric_polymorphism :: proc() { - print_value :: proc(value: $T) { - fmt.printf("print_value: %T %v\n", value, value); - } - - v1: int = 1; - v2: f32 = 2.1; - v3: f64 = 3.14; - v4: string = "message"; - - print_value(v1); - print_value(v2); - print_value(v3); - print_value(v4); - - fmt.println(); - - add :: proc(p, q: $T) -> T { - x: T = p + q; - return x; - } - - a := add(3, 4); - fmt.printf("a: %T = %v\n", a, a); - - b := add(3.2, 4.3); - fmt.printf("b: %T = %v\n", b, b); - - // This is how `new` is implemented - alloc_type :: proc(T: type) -> ^T { - t := cast(^T)alloc(size_of(T), align_of(T)); - t^ = T{}; // Use default initialization value - return t; - } - - copy_slice :: proc(dst, src: []$T) -> int { - n := min(len(dst), len(src)); - if n > 0 { - mem.copy(&dst[0], &src[0], n*size_of(T)); - } - return n; - } - - double_params :: proc(a: $A, b: $B) -> A { - return a + A(b); - } - - fmt.println(double_params(12, 1.345)); - - - - { // Polymorphic Types and Type Specialization - Table_Slot :: struct(Key, Value: type) { - occupied: bool, - hash: u32, - key: Key, - value: Value, - } - TABLE_SIZE_MIN :: 32; - Table :: struct(Key, Value: type) { - count: int, - allocator: Allocator, - slots: []Table_Slot(Key, Value), - } - - // Only allow types that are specializations of a (polymorphic) slice - make_slice :: proc(T: type/[]$E, len: int) -> T { - return make(T, len); - } - - - // Only allow types that are specializations of `Table` - allocate :: proc(table: ^$T/Table, capacity: int) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - - push_context c { - table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN)); - } - } - - expand :: proc(table: ^$T/Table) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - - push_context c { - old_slots := table.slots; - - cap := max(2*cap(table.slots), TABLE_SIZE_MIN); - allocate(table, cap); - - for s in old_slots do if s.occupied { - put(table, s.key, s.value); - } - - free(old_slots); - } - } - - // Polymorphic determination of a polymorphic struct - // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) { - put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) { - hash := get_hash(key); // Ad-hoc method which would fail in a different scope - index := find_index(table, key, hash); - if index < 0 { - if f64(table.count) >= 0.75*f64(cap(table.slots)) { - expand(table); - } - assert(table.count <= cap(table.slots)); - - hash := get_hash(key); - index = int(hash % u32(cap(table.slots))); - - for table.slots[index].occupied { - if index += 1; index >= cap(table.slots) { - index = 0; - } - } - - table.count += 1; - } - - slot := &table.slots[index]; - slot.occupied = true; - slot.hash = hash; - slot.key = key; - slot.value = value; - } - - - // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) { - find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) { - hash := get_hash(key); - index := find_index(table, key, hash); - if index < 0 { - return Value{}, false; - } - return table.slots[index].value, true; - } - - find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int { - if cap(table.slots) <= 0 do return -1; - - index := int(hash % u32(cap(table.slots))); - for table.slots[index].occupied { - if table.slots[index].hash == hash { - if table.slots[index].key == key { - return index; - } - } - - if index += 1; index >= cap(table.slots) { - index = 0; - } - } - - return -1; - } - - get_hash :: proc(s: string) -> u32 { // fnv32a - h: u32 = 0x811c9dc5; - for i in 0..len(s) { - h = (h ~ u32(s[i])) * 0x01000193; - } - return h; - } - - - table: Table(string, int); - - for i in 0..36 do put(&table, "Hellope", i); - for i in 0..42 do put(&table, "World!", i); - - found, _ := find(&table, "Hellope"); - fmt.printf("`found` is %v\n", found); - - found, _ = find(&table, "World!"); - fmt.printf("`found` is %v\n", found); - - // I would not personally design a hash table like this in production - // but this is a nice basic example - // A better approach would either use a `u64` or equivalent for the key - // and let the user specify the hashing function or make the user store - // the hashing procedure with the table - } -} - - - - -prefix_table := [?]string{ - "White", - "Red", - "Green", - "Blue", - "Octarine", - "Black", -}; - -threading_example :: proc() { - when ODIN_OS == "windows" { - unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) { - __bounds_check_error_loc(loc, index, len(array)); - array[index] = array[len(array)-1]; - pop(array); - } - ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) { - __bounds_check_error_loc(loc, index, len(array)); - copy(array[index..], array[index+1..]); - pop(array); - } - - worker_proc :: proc(t: ^thread.Thread) -> int { - for iteration in 1..5 { - fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration); - fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration); - // win32.sleep(1); - } - return 0; - } - - threads := make([]^thread.Thread, 0, len(prefix_table)); - defer free(threads); - - for i in 0..len(prefix_table) { - if t := thread.create(worker_proc); t != nil { - t.init_context = context; - t.use_init_context = true; - t.user_index = len(threads); - append(&threads, t); - thread.start(t); - } - } - - for len(threads) > 0 { - for i := 0; i < len(threads); /**/ { - if t := threads[i]; thread.is_done(t) { - fmt.printf("Thread %d is done\n", t.user_index); - thread.destroy(t); - - ordered_remove(&threads, i); - } else { - i += 1; - } - } - } - } -} - -main :: proc() { - when false { - fmt.println("\n# general_stuff"); general_stuff(); - fmt.println("\n# default_struct_values"); default_struct_values(); - fmt.println("\n# union_type"); union_type(); - fmt.println("\n# parametric_polymorphism"); parametric_polymorphism(); - fmt.println("\n# threading_example"); threading_example(); - } -} - diff --git a/examples/old_demos/demo008.odin b/examples/old_demos/demo008.odin deleted file mode 100644 index 7916cd5e9..000000000 --- a/examples/old_demos/demo008.odin +++ /dev/null @@ -1,778 +0,0 @@ -import "core:fmt.odin" -import "core:strconv.odin" -import "core:mem.odin" -import "core:bits.odin" -import "core:hash.odin" -import "core:math.odin" -import "core:math/rand.odin" -import "core:os.odin" -import "core:raw.odin" -import "core:sort.odin" -import "core:strings.odin" -import "core:types.odin" -import "core:utf16.odin" -import "core:utf8.odin" - -// File scope `when` statements -when ODIN_OS == "windows" { - import "core:atomics.odin" - import "core:thread.odin" - import win32 "core:sys/windows.odin" -} - -@(link_name="general_stuff") -general_stuff :: proc() { - fmt.println("# general_stuff"); - { // `do` for inline statements rather than block - foo :: proc() do fmt.println("Foo!"); - if false do foo(); - for false do foo(); - when false do foo(); - - if false do foo(); - else do foo(); - } - - { // Removal of `++` and `--` (again) - x: int; - x += 1; - x -= 1; - } - { // Casting syntaxes - i := i32(137); - ptr := &i; - - _ = (^f32)(ptr); - // ^f32(ptr) == ^(f32(ptr)) - _ = cast(^f32)ptr; - - _ = (^f32)(ptr)^; - _ = (cast(^f32)ptr)^; - - // Questions: Should there be two ways to do it? - } - - /* - * Remove *_val_of built-in procedures - * size_of, align_of, offset_of - * type_of, type_info_of - */ - - { // `expand_to_tuple` built-in procedure - Foo :: struct { - x: int, - b: bool, - } - f := Foo{137, true}; - x, b := expand_to_tuple(f); - fmt.println(f); - fmt.println(x, b); - fmt.println(expand_to_tuple(f)); - } - - { - // .. half-closed range - // .. open range - - for in 0..2 {} // 0, 1 - for in 0..2 {} // 0, 1, 2 - } - - { // Multiple sized booleans - - x0: bool; // default - x1: b8 = true; - x2: b16 = false; - x3: b32 = true; - x4: b64 = false; - - fmt.printf("x1: %T = %v;\n", x1, x1); - fmt.printf("x2: %T = %v;\n", x2, x2); - fmt.printf("x3: %T = %v;\n", x3, x3); - fmt.printf("x4: %T = %v;\n", x4, x4); - - // Having specific sized booleans is very useful when dealing with foreign code - // and to enforce specific alignment for a boolean, especially within a struct - } - - { // `distinct` types - // Originally, all type declarations would create a distinct type unless #type_alias was present. - // Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present. - // If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct. - - Int32 :: i32; - #assert(Int32 == i32); - - My_Int32 :: distinct i32; - #assert(My_Int32 != i32); - - My_Struct :: struct{x: int}; - #assert(My_Struct != struct{x: int}); - } -} - -default_struct_values :: proc() { - fmt.println("# default_struct_values"); - { - Vector3 :: struct { - x: f32, - y: f32, - z: f32, - } - v: Vector3; - fmt.println(v); - } - { - // Default values must be constants - Vector3 :: struct { - x: f32 = 1, - y: f32 = 4, - z: f32 = 9, - } - v: Vector3; - fmt.println(v); - - v = Vector3{}; - fmt.println(v); - - // Uses the same semantics as a default values in a procedure - v = Vector3{137}; - fmt.println(v); - - v = Vector3{z = 137}; - fmt.println(v); - } - - { - Vector3 :: struct { - x := 1.0, - y := 4.0, - z := 9.0, - } - stack_default: Vector3; - stack_literal := Vector3{}; - heap_one := new(Vector3); defer free(heap_one); - heap_two := new_clone(Vector3{}); defer free(heap_two); - - fmt.println("stack_default - ", stack_default); - fmt.println("stack_literal - ", stack_literal); - fmt.println("heap_one - ", heap_one^); - fmt.println("heap_two - ", heap_two^); - - - N :: 4; - stack_array: [N]Vector3; - heap_array := new([N]Vector3); defer free(heap_array); - heap_slice := make([]Vector3, N); defer free(heap_slice); - fmt.println("stack_array[1] - ", stack_array[1]); - fmt.println("heap_array[1] - ", heap_array[1]); - fmt.println("heap_slice[1] - ", heap_slice[1]); - } -} - - - - -union_type :: proc() { - fmt.println("\n# union_type"); - { - val: union{int, bool}; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - { - // There is a duality between `any` and `union` - // An `any` has a pointer to the data and allows for any type (open) - // A `union` has as binary blob to store the data and allows only certain types (closed) - // The following code is with `any` but has the same syntax - val: any; - val = 137; - if i, ok := val.(int); ok { - fmt.println(i); - } - val = true; - fmt.println(val); - - val = nil; - - switch v in val { - case int: fmt.println("int", v); - case bool: fmt.println("bool", v); - case: fmt.println("nil"); - } - } - - Vector3 :: struct {x, y, z: f32}; - Quaternion :: struct {x, y, z: f32, w: f32 = 1}; - - // More realistic examples - { - // NOTE(bill): For the above basic examples, you may not have any - // particular use for it. However, my main use for them is not for these - // simple cases. My main use is for hierarchical types. Many prefer - // subtyping, embedding the base data into the derived types. Below is - // an example of this for a basic game Entity. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: any, - } - - Frog :: struct { - using entity: Entity, - jump_height: f32, - } - - Monster :: struct { - using entity: Entity, - is_robot: bool, - is_zombie: bool, - } - - // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { - t := new(T); - t.derived = t^; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - } - } - - { - // NOTE(bill): A union can be used to achieve something similar. Instead - // of embedding the base data into the derived types, the derived data - // in embedded into the base type. Below is the same example of the - // basic game Entity but using an union. - - Entity :: struct { - id: u64, - name: string, - position: Vector3, - orientation: Quaternion, - - derived: union {Frog, Monster}, - } - - Frog :: struct { - using entity: ^Entity, - jump_height: f32, - } - - Monster :: struct { - using entity: ^Entity, - is_robot: bool, - is_zombie: bool, - } - - // See `parametric_polymorphism` procedure for details - new_entity :: proc(T: type) -> ^Entity { - t := new(Entity); - t.derived = T{entity = t}; - return t; - } - - entity := new_entity(Monster); - - switch e in entity.derived { - case Frog: - fmt.println("Ribbit"); - case Monster: - if e.is_robot do fmt.println("Robotic"); - if e.is_zombie do fmt.println("Grrrr!"); - } - - // NOTE(bill): As you can see, the usage code has not changed, only its - // memory layout. Both approaches have their own advantages but they can - // be used together to achieve different results. The subtyping approach - // can allow for a greater control of the memory layout and memory - // allocation, e.g. storing the derivatives together. However, this is - // also its disadvantage. You must either preallocate arrays for each - // derivative separation (which can be easily missed) or preallocate a - // bunch of "raw" memory; determining the maximum size of the derived - // types would require the aid of metaprogramming. Unions solve this - // particular problem as the data is stored with the base data. - // Therefore, it is possible to preallocate, e.g. [100]Entity. - - // It should be noted that the union approach can have the same memory - // layout as the any and with the same type restrictions by using a - // pointer type for the derivatives. - - /* - Entity :: struct { - .. - derived: union{^Frog, ^Monster}, - } - - Frog :: struct { - using entity: Entity, - .. - } - Monster :: struct { - using entity: Entity, - .. - - } - new_entity :: proc(T: type) -> ^Entity { - t := new(T); - t.derived = t; - return t; - } - */ - } -} - -parametric_polymorphism :: proc() { - fmt.println("# parametric_polymorphism"); - - print_value :: proc(value: $T) { - fmt.printf("print_value: %T %v\n", value, value); - } - - v1: int = 1; - v2: f32 = 2.1; - v3: f64 = 3.14; - v4: string = "message"; - - print_value(v1); - print_value(v2); - print_value(v3); - print_value(v4); - - fmt.println(); - - add :: proc(p, q: $T) -> T { - x: T = p + q; - return x; - } - - a := add(3, 4); - fmt.printf("a: %T = %v\n", a, a); - - b := add(3.2, 4.3); - fmt.printf("b: %T = %v\n", b, b); - - // This is how `new` is implemented - alloc_type :: proc(T: type) -> ^T { - t := cast(^T)alloc(size_of(T), align_of(T)); - t^ = T{}; // Use default initialization value - return t; - } - - copy_slice :: proc(dst, src: []$T) -> int { - return mem.copy(&dst[0], &src[0], n*size_of(T)); - } - - double_params :: proc(a: $A, b: $B) -> A { - return a + A(b); - } - - fmt.println(double_params(12, 1.345)); - - - - { // Polymorphic Types and Type Specialization - Table_Slot :: struct(Key, Value: type) { - occupied: bool, - hash: u32, - key: Key, - value: Value, - } - TABLE_SIZE_MIN :: 32; - Table :: struct(Key, Value: type) { - count: int, - allocator: Allocator, - slots: []Table_Slot(Key, Value), - } - - // Only allow types that are specializations of a (polymorphic) slice - make_slice :: proc(T: type/[]$E, len: int) -> T { - return make(T, len); - } - - - // Only allow types that are specializations of `Table` - allocate :: proc(table: ^$T/Table, capacity: int) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - - context <- c { - table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN)); - } - } - - expand :: proc(table: ^$T/Table) { - c := context; - if table.allocator.procedure != nil do c.allocator = table.allocator; - - context <- c { - old_slots := table.slots; - - cap := max(2*len(table.slots), TABLE_SIZE_MIN); - allocate(table, cap); - - for s in old_slots do if s.occupied { - put(table, s.key, s.value); - } - - free(old_slots); - } - } - - // Polymorphic determination of a polymorphic struct - // put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) { - put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) { - hash := get_hash(key); // Ad-hoc method which would fail in a different scope - index := find_index(table, key, hash); - if index < 0 { - if f64(table.count) >= 0.75*f64(len(table.slots)) { - expand(table); - } - assert(table.count <= len(table.slots)); - - hash := get_hash(key); - index = int(hash % u32(len(table.slots))); - - for table.slots[index].occupied { - if index += 1; index >= len(table.slots) { - index = 0; - } - } - - table.count += 1; - } - - slot := &table.slots[index]; - slot.occupied = true; - slot.hash = hash; - slot.key = key; - slot.value = value; - } - - - // find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) { - find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) { - hash := get_hash(key); - index := find_index(table, key, hash); - if index < 0 { - return Value{}, false; - } - return table.slots[index].value, true; - } - - find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int { - if len(table.slots) <= 0 do return -1; - - index := int(hash % u32(len(table.slots))); - for table.slots[index].occupied { - if table.slots[index].hash == hash { - if table.slots[index].key == key { - return index; - } - } - - if index += 1; index >= len(table.slots) { - index = 0; - } - } - - return -1; - } - - get_hash :: proc(s: string) -> u32 { // fnv32a - h: u32 = 0x811c9dc5; - for i in 0..len(s) { - h = (h ~ u32(s[i])) * 0x01000193; - } - return h; - } - - - table: Table(string, int); - - for i in 0..36 do put(&table, "Hellope", i); - for i in 0..42 do put(&table, "World!", i); - - found, _ := find(&table, "Hellope"); - fmt.printf("`found` is %v\n", found); - - found, _ = find(&table, "World!"); - fmt.printf("`found` is %v\n", found); - - // I would not personally design a hash table like this in production - // but this is a nice basic example - // A better approach would either use a `u64` or equivalent for the key - // and let the user specify the hashing function or make the user store - // the hashing procedure with the table - } -} - - - - -prefix_table := [?]string{ - "White", - "Red", - "Green", - "Blue", - "Octarine", - "Black", -}; - -threading_example :: proc() { - when ODIN_OS == "windows" { - fmt.println("# threading_example"); - - unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) { - __bounds_check_error_loc(loc, index, len(array)); - array[index] = array[len(array)-1]; - pop(array); - } - ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) { - __bounds_check_error_loc(loc, index, len(array)); - copy(array[index..], array[index+1..]); - pop(array); - } - - worker_proc :: proc(t: ^thread.Thread) -> int { - for iteration in 1..5 { - fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration); - fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration); - // win32.sleep(1); - } - return 0; - } - - threads := make([dynamic]^thread.Thread, 0, len(prefix_table)); - defer free(threads); - - for in prefix_table { - if t := thread.create(worker_proc); t != nil { - t.init_context = context; - t.use_init_context = true; - t.user_index = len(threads); - append(&threads, t); - thread.start(t); - } - } - - for len(threads) > 0 { - for i := 0; i < len(threads); /**/ { - if t := threads[i]; thread.is_done(t) { - fmt.printf("Thread %d is done\n", t.user_index); - thread.destroy(t); - - ordered_remove(&threads, i); - } else { - i += 1; - } - } - } - } -} - -array_programming :: proc() { - fmt.println("# array_programming"); - { - a := [3]f32{1, 2, 3}; - b := [3]f32{5, 6, 7}; - c := a * b; - d := a + b; - e := 1 + (c - d) / 2; - fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5] - } - - { - a := [3]f32{1, 2, 3}; - b := swizzle(a, 2, 1, 0); - assert(b == [3]f32{3, 2, 1}); - - c := swizzle(a, 0, 0); - assert(c == [2]f32{1, 1}); - assert(c == 1); - } - - { - Vector3 :: distinct [3]f32; - a := Vector3{1, 2, 3}; - b := Vector3{5, 6, 7}; - c := (a * b)/2 + 1; - d := c.x + c.y + c.z; - fmt.printf("%.1f\n", d); // 22.0 - - cross :: proc(a, b: Vector3) -> Vector3 { - i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1); - j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0); - return i - j; - } - - blah :: proc(a: Vector3) -> f32 { - return a.x + a.y + a.z; - } - - x := cross(a, b); - fmt.println(x); - fmt.println(blah(x)); - } -} - - -using println in import "core:fmt.odin" - -using_in :: proc() { - fmt.println("# using in"); - using print in fmt; - - println("Hellope1"); - print("Hellope2\n"); - - Foo :: struct { - x, y: int, - b: bool, - } - f: Foo; - f.x, f.y = 123, 321; - println(f); - using x, y in f; - x, y = 456, 654; - println(f); -} - -named_proc_return_parameters :: proc() { - fmt.println("# named proc return parameters"); - - foo0 :: proc() -> int { - return 123; - } - foo1 :: proc() -> (a: int) { - a = 123; - return; - } - foo2 :: proc() -> (a, b: int) { - // Named return values act like variables within the scope - a = 321; - b = 567; - return b, a; - } - fmt.println("foo0 =", foo0()); // 123 - fmt.println("foo1 =", foo1()); // 123 - fmt.println("foo2 =", foo2()); // 567 321 -} - - -enum_export :: proc() { - fmt.println("# enum #export"); - - Foo :: enum #export {A, B, C}; - - f0 := A; - f1 := B; - f2 := C; - fmt.println(f0, f1, f2); -} - -explicit_procedure_overloading :: proc() { - fmt.println("# explicit procedure overloading"); - - add_ints :: proc(a, b: int) -> int { - x := a + b; - fmt.println("add_ints", x); - return x; - } - add_floats :: proc(a, b: f32) -> f32 { - x := a + b; - fmt.println("add_floats", x); - return x; - } - add_numbers :: proc(a: int, b: f32, c: u8) -> int { - x := int(a) + int(b) + int(c); - fmt.println("add_numbers", x); - return x; - } - - add :: proc[add_ints, add_floats, add_numbers]; - - add(int(1), int(2)); - add(f32(1), f32(2)); - add(int(1), f32(2), u8(3)); - - add(1, 2); // untyped ints coerce to int tighter than f32 - add(1.0, 2.0); // untyped floats coerce to f32 tighter than int - add(1, 2, 3); // three parameters - - // Ambiguous answers - // add(1.0, 2); - // add(1, 2.0); -} - -complete_switch :: proc() { - fmt.println("# complete_switch"); - { // enum - Foo :: enum #export { - A, - B, - C, - D, - } - - b := Foo.B; - f := Foo.A; - #complete switch f { - case A: fmt.println("A"); - case B: fmt.println("B"); - case C: fmt.println("C"); - case D: fmt.println("D"); - case: fmt.println("?"); - } - } - { // union - Foo :: union {int, bool}; - f: Foo = 123; - #complete switch in f { - case int: fmt.println("int"); - case bool: fmt.println("bool"); - case: - } - } -} - - -main :: proc() { - when true { - general_stuff(); - default_struct_values(); - union_type(); - parametric_polymorphism(); - threading_example(); - array_programming(); - using_in(); - named_proc_return_parameters(); - enum_export(); - explicit_procedure_overloading(); - complete_switch(); - } -} diff --git a/examples/old_demos/old_runtime.odin b/examples/old_demos/old_runtime.odin deleted file mode 100644 index e605e7820..000000000 --- a/examples/old_demos/old_runtime.odin +++ /dev/null @@ -1,412 +0,0 @@ -#include "win32.odin" - -assume :: proc(cond: bool) #foreign "llvm.assume" - -__debug_trap :: proc() #foreign "llvm.debugtrap" -__trap :: proc() #foreign "llvm.trap" -read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter" - -bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16" -bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32" -bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64" - -byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" -byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" -byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" - -fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" -fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" - -// TODO(bill): make custom heap procedures -heap_alloc :: proc(len: int) -> rawptr #foreign "malloc" -heap_dealloc :: proc(ptr: rawptr) #foreign "free" - -memory_zero :: proc(data: rawptr, len: int) { - d := slice_ptr(data as ^byte, len) - for i := 0; i < len; i++ { - d[i] = 0 - } -} - -memory_compare :: proc(dst, src: rawptr, len: int) -> int { - s1, s2: ^byte = dst, src - for i := 0; i < len; i++ { - a := ptr_offset(s1, i)^ - b := ptr_offset(s2, i)^ - if a != b { - return (a - b) as int - } - } - return 0 -} - -memory_copy :: proc(dst, src: rawptr, n: int) #inline { - if dst == src { - return - } - - v128b :: type {4}u32 - #assert(align_of(v128b) == 16) - - d, s: ^byte = dst, src - - for ; s as uint % 16 != 0 && n != 0; n-- { - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - - if d as uint % 16 == 0 { - for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 { - (d as ^v128b)^ = (s as ^v128b)^ - } - - if n&8 != 0 { - (d as ^u64)^ = (s as ^u64)^ - d, s = ptr_offset(d, 8), ptr_offset(s, 8) - } - if n&4 != 0 { - (d as ^u32)^ = (s as ^u32)^; - d, s = ptr_offset(d, 4), ptr_offset(s, 4) - } - if n&2 != 0 { - (d as ^u16)^ = (s as ^u16)^ - d, s = ptr_offset(d, 2), ptr_offset(s, 2) - } - if n&1 != 0 { - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - return; - } - - // IMPORTANT NOTE(bill): Little endian only - LS :: proc(a, b: u32) -> u32 #inline { return a << b } - RS :: proc(a, b: u32) -> u32 #inline { return a >> b } - /* NOTE(bill): Big endian version - LS :: proc(a, b: u32) -> u32 #inline { return a >> b; } - RS :: proc(a, b: u32) -> u32 #inline { return a << b; } - */ - - w, x: u32 - - if d as uint % 4 == 1 { - w = (s as ^u32)^ - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) - n -= 3 - - for n > 16 { - d32 := d as ^u32 - s32 := ptr_offset(s, 1) as ^u32 - x = s32^; d32^ = LS(w, 24) | RS(x, 8) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 24) | RS(w, 8) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - x = s32^; d32^ = LS(w, 24) | RS(x, 8) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 24) | RS(w, 8) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 - } - - } else if d as uint % 4 == 2 { - w = (s as ^u32)^ - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) - d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) - n -= 2 - - for n > 17 { - d32 := d as ^u32 - s32 := ptr_offset(s, 2) as ^u32 - x = s32^; d32^ = LS(w, 16) | RS(x, 16) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 16) | RS(w, 16) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - x = s32^; d32^ = LS(w, 16) | RS(x, 16) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 16) | RS(w, 16) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 - } - - } else if d as uint % 4 == 3 { - w = (s as ^u32)^ - d^ = s^ - n -= 1 - - for n > 18 { - d32 := d as ^u32 - s32 := ptr_offset(s, 3) as ^u32 - x = s32^; d32^ = LS(w, 8) | RS(x, 24) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 8) | RS(w, 24) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - x = s32^; d32^ = LS(w, 8) | RS(x, 24) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - w = s32^; d32^ = LS(x, 8) | RS(w, 24) - d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) - - d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 - } - } - - if n&16 != 0 { - (d as ^v128b)^ = (s as ^v128b)^ - d, s = ptr_offset(d, 16), ptr_offset(s, 16) - } - if n&8 != 0 { - (d as ^u64)^ = (s as ^u64)^ - d, s = ptr_offset(d, 8), ptr_offset(s, 8) - } - if n&4 != 0 { - (d as ^u32)^ = (s as ^u32)^; - d, s = ptr_offset(d, 4), ptr_offset(s, 4) - } - if n&2 != 0 { - (d as ^u16)^ = (s as ^u16)^ - d, s = ptr_offset(d, 2), ptr_offset(s, 2) - } - if n&1 != 0 { - d^ = s^ - } -} - -memory_move :: proc(dst, src: rawptr, n: int) #inline { - d, s: ^byte = dst, src - if d == s { - return - } - if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s { - memory_copy(d, s, n) - return - } - - // TODO(bill): Vectorize the shit out of this - if d < s { - if s as int % size_of(int) == d as int % size_of(int) { - for d as int % size_of(int) != 0 { - if n == 0 { - return - } - n-- - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - di, si := d as ^int, s as ^int - for n >= size_of(int) { - di^ = si^ - di, si = ptr_offset(di, 1), ptr_offset(si, 1) - n -= size_of(int) - } - } - for ; n > 0; n-- { - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - } else { - if s as int % size_of(int) == d as int % size_of(int) { - for ptr_offset(d, n) as int % size_of(int) != 0 { - if n == 0 { - return - } - n-- - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - for n >= size_of(int) { - n -= size_of(int) - di := ptr_offset(d, n) as ^int - si := ptr_offset(s, n) as ^int - di^ = si^ - } - for ; n > 0; n-- { - d^ = s^ - d, s = ptr_offset(d, 1), ptr_offset(s, 1) - } - } - for n > 0 { - n-- - dn := ptr_offset(d, n) - sn := ptr_offset(s, n) - dn^ = sn^ - } - } -} - -__string_eq :: proc(a, b: string) -> bool { - if len(a) != len(b) { - return false - } - if ^a[0] == ^b[0] { - return true - } - return memory_compare(^a[0], ^b[0], len(a)) == 0 -} - -__string_cmp :: proc(a, b : string) -> int { - min_len := len(a) - if len(b) < min_len { - min_len = len(b) - } - for i := 0; i < min_len; i++ { - x := a[i] - y := b[i] - if x < y { - return -1 - } else if x > y { - return +1 - } - } - - if len(a) < len(b) { - return -1 - } else if len(a) > len(b) { - return +1 - } - return 0 -} - -__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) } -__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 } -__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 } -__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } -__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 } - - - - -Allocation_Mode :: type enum { - ALLOC, - DEALLOC, - DEALLOC_ALL, - RESIZE, -} - - - -Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr - -Allocator :: type struct { - procedure: Allocator_Proc; - data: rawptr -} - - -Context :: type struct { - thread_ptr: rawptr - - user_data: rawptr - user_index: int - - allocator: Allocator -} - -#thread_local context: Context - -DEFAULT_ALIGNMENT :: 2*size_of(int) - - -__check_context :: proc() { - if context.allocator.procedure == null { - context.allocator = __default_allocator() - } - if context.thread_ptr == null { - // TODO(bill): - // context.thread_ptr = current_thread_pointer() - } -} - - -alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) } - -alloc_align :: proc(size, alignment: int) -> rawptr #inline { - __check_context() - a := context.allocator - return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0) -} - -dealloc :: proc(ptr: rawptr) #inline { - __check_context() - a := context.allocator - _ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0) -} -dealloc_all :: proc(ptr: rawptr) #inline { - __check_context() - a := context.allocator - _ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0) -} - - -resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) } -resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline { - __check_context() - a := context.allocator - return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0) -} - - - -default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { - if old_memory == null { - return alloc_align(new_size, alignment) - } - - if new_size == 0 { - dealloc(old_memory) - return null - } - - if new_size == old_size { - return old_memory - } - - new_memory := alloc_align(new_size, alignment) - if new_memory == null { - return null - } - - memory_copy(new_memory, old_memory, min(old_size, new_size)); - dealloc(old_memory) - return new_memory -} - - -__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, flags: u64) -> rawptr { - using Allocation_Mode - match mode { - case ALLOC: - return heap_alloc(size) - case RESIZE: - return default_resize_align(old_memory, old_size, size, alignment) - case DEALLOC: - heap_dealloc(old_memory) - case DEALLOC_ALL: - // NOTE(bill): Does nothing - } - - return null -} - -__default_allocator :: proc() -> Allocator { - return Allocator{ - __default_allocator_proc, - null, - } -} - - - - -__assert :: proc(msg: string) { - file_write(file_get_standard(File_Standard.ERROR), msg as []byte) - // TODO(bill): Which is better? - // __trap() - __debug_trap() -} diff --git a/examples/old_stuff/demo_backup.odin b/examples/old_stuff/demo_backup.odin deleted file mode 100644 index b8bbbb02d..000000000 --- a/examples/old_stuff/demo_backup.odin +++ /dev/null @@ -1,430 +0,0 @@ -import ( - "fmt.odin"; - "atomics.odin"; - "bits.odin"; - "decimal.odin"; - "hash.odin"; - "math.odin"; - "mem.odin"; - "opengl.odin"; - "os.odin"; - "raw.odin"; - "strconv.odin"; - "strings.odin"; - "sync.odin"; - "sort.odin"; - "types.odin"; - "utf8.odin"; - "utf16.odin"; -/* -*/ -) - - -general_stuff :: proc() { - // Complex numbers - a := 3 + 4i; - b: complex64 = 3 + 4i; - c: complex128 = 3 + 4i; - d := complex(2, 3); - - e := a / conj(a); - fmt.println("(3+4i)/(3-4i) =", e); - fmt.println(real(e), "+", imag(e), "i"); - - - // C-style variadic procedures - foreign __llvm_core { - // The variadic part allows for extra type checking too which C does not provide - c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---; - } - str := "%d\n\x00"; - // c_printf(&str[0], i32(789456123)); - - - Foo :: struct { - x: int; - y: f32; - z: string; - } - foo := Foo{123, 0.513, "A string"}; - x, y, z := expand_to_tuple(foo); - fmt.println(x, y, z); - #assert(type_of(x) == int); - #assert(type_of(y) == f32); - #assert(type_of(z) == string); - - - // By default, all variables are zeroed - // This can be overridden with the "uninitialized value" - // This is similar to `nil` but applied to everything - undef_int: int = ---; - - - // Context system is now implemented using Implicit Parameter Passing (IPP) - // The previous implementation was Thread Local Storage (TLS) - // IPP has the advantage that it works on systems without TLS and that you can - // link the context to the stack frame and thus look at previous contexts - // - // It does mean that a pointer is implicitly passed procedures with the default - // Odin calling convention (#cc_odin) - // This can be overridden with something like #cc_contextless or #cc_c if performance - // is worried about - -} - -foreign_blocks :: proc() { - // See sys/windows.odin -} - -default_arguments :: proc() { - hello :: proc(a: int = 9, b: int = 9) do fmt.printf("a is %d; b is %d\n", a, b); - fmt.println("\nTesting default arguments:"); - hello(1, 2); - hello(1); - hello(); -} - -named_arguments :: proc() { - Colour :: enum { - Red, - Orange, - Yellow, - Green, - Blue, - Octarine, - }; - using Colour; - - make_character :: proc(name, catch_phrase: string, favourite_colour, least_favourite_colour: Colour) { - fmt.println(); - fmt.printf("My name is %v and I like %v. %v\n", name, favourite_colour, catch_phrase); - } - - make_character("Frank", "¡Ay, caramba!", Blue, Green); - - - // As the procedures have more and more parameters, it is very easy - // to get many of the arguments in the wrong order especialy if the - // types are the same - make_character("¡Ay, caramba!", "Frank", Green, Blue); - - // Named arguments help to disambiguate this problem - make_character(catch_phrase = "¡Ay, caramba!", name = "Frank", - least_favourite_colour = Green, favourite_colour = Blue); - - - // The named arguments can be specifed in any order. - make_character(favourite_colour = Octarine, catch_phrase = "U wot m8!", - least_favourite_colour = Green, name = "Dennis"); - - - // NOTE: You cannot mix named arguments with normal values - /* - make_character("Dennis", - favourite_colour = Octarine, catch_phrase = "U wot m8!", - least_favourite_colour = Green); - */ - - - // Named arguments can also aid with default arguments - numerous_things :: proc(s: string, a := 1, b := 2, c := 3.14, - d := "The Best String!", e := false, f := 10.3/3.1, g := false) { - g_str := g ? "true" : "false"; - fmt.printf("How many?! %s: %v\n", s, g_str); - } - - numerous_things("First"); - numerous_things(s = "Second", g = true); - - - // Default values can be placed anywhere, not just at the end like in other languages - weird :: proc(pre: string, mid: int = 0, post: string) { - fmt.println(pre, mid, post); - } - - weird("How many things", 42, "huh?"); - weird(pre = "Prefix", post = "Pat"); - -} - - -default_return_values :: proc() { - foo :: proc(x: int) -> (first: string = "Hellope", second := "world!") { - match x { - case 0: return; - case 1: return "Goodbye"; - case 2: return "Goodbye", "cruel world.."; - case 3: return second = "cruel world..", first = "Goodbye"; - } - - return second = "my old friend."; - } - - fmt.printf("%s %s\n", foo(0)); - fmt.printf("%s %s\n", foo(1)); - fmt.printf("%s %s\n", foo(2)); - fmt.printf("%s %s\n", foo(3)); - fmt.printf("%s %s\n", foo(4)); - fmt.println(); - - - // A more "real" example - Error :: enum { - None, - WhyTheNumberThree, - TenIsTooBig, - }; - - Entity :: struct { - name: string; - id: u32; - } - - some_thing :: proc(input: int) -> (result: ^Entity = nil, err := Error.None) { - match { - case input == 3: return err = Error.WhyTheNumberThree; - case input >= 10: return err = Error.TenIsTooBig; - } - - e := new(Entity); - e.id = u32(input); - - return result = e; - } -} - -call_location :: proc() { - amazing :: proc(n: int, using loc := #caller_location) { - fmt.printf("%s(%d:%d) just asked to do something amazing.\n", - fully_pathed_filename, line, column); - fmt.printf("Normal -> %d\n", n); - fmt.printf("Amazing -> %d\n", n+1); - fmt.println(); - } - - loc := #location(main); - fmt.println("`main` is located at", loc); - - fmt.println("This line is located at", #location()); - fmt.println(); - - amazing(3); - amazing(4, #location(call_location)); - - // See _preload.odin for the implementations of `assert` and `panic` - -} - - -explicit_parametric_polymorphic_procedures :: proc() { - // This is how `new` is actually implemented, see _preload.odin - alloc_type :: proc(T: type) -> ^T do return cast(^T)alloc(size_of(T), align_of(T)); - - int_ptr := alloc_type(int); - defer free(int_ptr); - int_ptr^ = 137; - fmt.println(int_ptr, int_ptr^); - - // Named arguments work too! - another_ptr := alloc_type(T = f32); - defer free(another_ptr); - - - add :: proc(T: type, args: ..T) -> T { - res: T; - for arg in args do res += arg; - return res; - } - - fmt.println("add =", add(int, 1, 2, 3, 4, 5, 6)); - - swap :: proc(T: type, a, b: ^T) { - tmp := a^; - a^ = b^; - b^ = tmp; - } - - a, b: int = 3, 4; - fmt.println("Pre-swap:", a, b); - swap(int, &a, &b); - fmt.println("Post-swap:", a, b); - a, b = b, a; // Or use this syntax for this silly example case - - - Vector2 :: struct {x, y: f32;}; - { - // A more complicated example using subtyping - // Something like this could be used in a game - - Entity :: struct { - using position: Vector2; - flags: u64; - id: u64; - derived: any; - } - - Rock :: struct { - using entity: Entity; - heavy: bool; - } - Door :: struct { - using entity: Entity; - open: bool; - } - Monster :: struct { - using entity: Entity; - is_robot: bool; - is_zombie: bool; - } - - new_entity :: proc(T: type, x, y: f32) -> ^T { - result := new(T); - result.derived = result^; - result.x = x; - result.y = y; - - return result; - } - - entities: [dynamic]^Entity; - - rock := new_entity(Rock, 3, 5); - - // Named arguments work too! - door := new_entity(T = Door, x = 3, y = 6); - - // And named arguments can be any order - monster := new_entity( - y = 1, - x = 2, - T = Monster, - ); - - append(&entities, rock, door, monster); - - fmt.println("Subtyping"); - for entity in entities { - match e in entity.derived { - case Rock: fmt.println("Rock", e.x, e.y); - case Door: fmt.println("Door", e.x, e.y); - case Monster: fmt.println("Monster", e.x, e.y); - } - } - } - { - Entity :: struct { - using position: Vector2; - flags: u64; - id: u64; - variant: union { Rock, Door, Monster }; - } - - Rock :: struct { - using entity: ^Entity; - heavy: bool; - } - Door :: struct { - using entity: ^Entity; - open: bool; - } - Monster :: struct { - using entity: ^Entity; - is_robot: bool; - is_zombie: bool; - } - - new_entity :: proc(T: type, x, y: f32) -> ^T { - result := new(Entity); - result.variant = T{entity = result}; - result.x = x; - result.y = y; - - return cast(^T)&result.variant; - } - - entities: [dynamic]^Entity; - - rock := new_entity(Rock, 3, 5); - - // Named arguments work too! - door := new_entity(T = Door, x = 3, y = 6); - - // And named arguments can be any order - monster := new_entity( - y = 1, - x = 2, - T = Monster, - ); - - append(&entities, rock, door, monster); - - fmt.println("Union"); - for entity in entities { - match e in entity.variant { - case Rock: fmt.println("Rock", e.x, e.y); - case Door: fmt.println("Door", e.x, e.y); - case Monster: fmt.println("Monster", e.x, e.y); - } - } - } -} - - -implicit_polymorphic_assignment :: proc() { - yep :: proc(p: proc(x: int)) { - p(123); - } - - frank :: proc(x: $T) do fmt.println("frank ->", x); - tim :: proc(x, y: $T) do fmt.println("tim ->", x, y); - yep(frank); - // yep(tim); -} - - - - -main :: proc() { -/* - foo :: proc(x: i64, y: f32) do fmt.println("#1", x, y); - foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y); - foo :: proc(x: type) do fmt.println("#3", type_info(x)); - - f :: foo; - - f(y = 3785.1546, x = 123); - f(x = int, y = 897.513); - f(x = f32); - - general_stuff(); - foreign_blocks(); - default_arguments(); - named_arguments(); - default_return_values(); - call_location(); - explicit_parametric_polymorphic_procedures(); - implicit_polymorphic_assignment(); - - - // Command line argument(s)! - // -opt=0,1,2,3 -*/ -/* - program := "+ + * - /"; - accumulator := 0; - - for token in program { - match token { - case '+': accumulator += 1; - case '-': accumulator -= 1; - case '*': accumulator *= 2; - case '/': accumulator /= 2; - case: // Ignore everything else - } - } - - fmt.printf("The program \"%s\" calculates the value %d\n", - program, accumulator); -*/ -} |