diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2023-03-28 15:14:02 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2023-03-28 15:14:02 +0200 |
| commit | 3c493194c99f01ec6f3f5f8cde5ee7cba49c671d (patch) | |
| tree | 3be45a0ae3897f2b2a05432ad547693f2f9c52bd /misc | |
| parent | 692764aad334aa99e7dafd117d14b9a331a13e22 (diff) | |
Remove old deprecated demos
They're so outdated they'll likely lead to confusion now.
Diffstat (limited to 'misc')
| -rw-r--r-- | misc/old_demos/demo001.odin | 337 | ||||
| -rw-r--r-- | misc/old_demos/demo002.odin | 879 | ||||
| -rw-r--r-- | misc/old_demos/demo004.odin | 66 | ||||
| -rw-r--r-- | misc/old_demos/demo005.odin | 283 | ||||
| -rw-r--r-- | misc/old_demos/demo006.odin | 310 | ||||
| -rw-r--r-- | misc/old_demos/demo007.odin | 570 | ||||
| -rw-r--r-- | misc/old_demos/demo008.odin | 778 | ||||
| -rw-r--r-- | misc/old_demos/old_runtime.odin | 412 | ||||
| -rw-r--r-- | misc/old_stuff/demo_backup.odin | 430 |
9 files changed, 0 insertions, 4065 deletions
diff --git a/misc/old_demos/demo001.odin b/misc/old_demos/demo001.odin deleted file mode 100644 index a3aea1cb7..000000000 --- a/misc/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/misc/old_demos/demo002.odin b/misc/old_demos/demo002.odin deleted file mode 100644 index a790aadf3..000000000 --- a/misc/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/misc/old_demos/demo004.odin b/misc/old_demos/demo004.odin deleted file mode 100644 index c9acc9a15..000000000 --- a/misc/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/misc/old_demos/demo005.odin b/misc/old_demos/demo005.odin deleted file mode 100644 index c8273b03b..000000000 --- a/misc/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/misc/old_demos/demo006.odin b/misc/old_demos/demo006.odin deleted file mode 100644 index c2f64151b..000000000 --- a/misc/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/misc/old_demos/demo007.odin b/misc/old_demos/demo007.odin deleted file mode 100644 index d19446ecb..000000000 --- a/misc/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/misc/old_demos/demo008.odin b/misc/old_demos/demo008.odin deleted file mode 100644 index a122414e7..000000000 --- a/misc/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`, or `proc`, 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/misc/old_demos/old_runtime.odin b/misc/old_demos/old_runtime.odin deleted file mode 100644 index e605e7820..000000000 --- a/misc/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/misc/old_stuff/demo_backup.odin b/misc/old_stuff/demo_backup.odin deleted file mode 100644 index b8bbbb02d..000000000 --- a/misc/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); -*/ -} |