Begin Type_Info

Missing stuff in records, procedures, and tuples
This commit is contained in:
Ginger Bill
2016-09-07 14:03:17 +01:00
parent 455820fc84
commit 61fcfd6f3d
13 changed files with 479 additions and 1199 deletions
+30 -868
View File
@@ -1,874 +1,36 @@
// Demo 002
#load "basic.odin"
#load "game.odin"
#load "math.odin"
#thread_local tls_int: int
print_type_info_kind :: proc(info: ^Type_Info) {
using Type_Info
match type i : info {
case Named: print_string("Named\n")
case Integer: print_string("Integer\n")
case Float: print_string("Float\n")
case String: print_string("String\n")
case Boolean: print_string("Boolean\n")
case Pointer: print_string("Pointer\n")
case Procedure: print_string("Procedure\n")
case Array: print_string("Array\n")
case Slice: print_string("Slice\n")
case Vector: print_string("Vector\n")
case Struct: print_string("Struct\n")
case Union: print_string("Union\n")
case Raw_Union: print_string("RawUnion\n")
case Enum: print_string("Enum\n")
default: print_string("void\n")
}
}
main :: proc() {
// Forenotes
i: int
s: struct {
x, y, z: f32
}
p := ^s
// 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()
print_type_info_kind(type_info(i))
print_type_info_kind(type_info(s))
print_type_info_kind(type_info(p))
}
struct_compound_literals :: proc() {
Thing :: type 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 :: type enum {
APPLE, // 0
BANANA, // 1
PEAR, // 2
}
f := Fruit.APPLE
// g: int = Fruit.BANANA
g: int = Fruit.BANANA as int
}
{
Fruit1 :: type enum int {
APPLE,
BANANA,
PEAR,
}
Fruit2 :: type enum u8 {
APPLE,
BANANA,
PEAR,
}
Fruit3 :: type enum u8 {
APPLE = 1,
BANANA, // 2
PEAR = 5,
TOMATO, // 6
}
}
}
variadic_procedures :: proc() {
print_ints :: proc(args: ..int) {
for i := 0; i < len(args); i++ {
if i > 0 {
print_string(", ")
}
print_int(args[i])
}
}
print_ints(); nl()
print_ints(1); nl()
print_ints(1, 2, 3); nl()
print_prefix_f32s :: proc(prefix: string, args: ..f32) {
print_string(prefix)
print_string(": ")
for i := 0; i < len(args); i++ {
if i > 0 {
print_string(", ")
}
print_f32(args[i])
}
}
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
}
new_builtins :: proc() {
{
a := new(int)
b := new_slice(int, 12)
c := new_slice(int, 12, 16)
defer delete(a)
defer delete(b)
defer delete(c)
// NOTE(bill): These use the current context's allocator not the default allocator
// see runtime.odin
// Q: Should this be `free` rather than `delete` and should I overload it for slices too?
}
{
a: int = 123
b: type_of_val(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 = null;
y := ptr_offset(x, 100)
z := ptr_sub(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_int(min(a, b)); nl()
print_int(max(a, b)); nl()
print_int(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_int(C); nl()
print_int(D); nl()
print_int(E); nl()
}
}
match_statement :: proc() {
// NOTE(bill): `match` statements are similar to `switch` statements
// in other languages but there are few differences
{
match x := 2; x {
case 1: // cases must be constant expression
print_string("1!\n")
// break by default
case 2:
s := "2!\n"; // Each case has its own scope
print_string(s)
break // explicit break
case 3, 4: // multiple cases
print_string("3 or 4!\n")
case 5:
print_string("5!\n")
fallthrough // explicit fallthrough
default:
print_string("default!\n")
}
match x := 1.5; x {
case 1.5:
print_string("1.5!\n")
// break by default
case MATH_TAU:
print_string("τ!\n")
default:
print_string("default!\n")
}
match x := "Hello"; x {
case "Hello":
print_string("greeting\n")
// break by default
case "Goodbye":
print_string("farewell\n")
default:
print_string("???\n")
}
a := 53
match {
case a == 1:
print_string("one\n")
case a == 2:
print_string("a couple\n")
case a < 7, a == 7:
print_string("a few\n")
case a < 12: // intentional bug
print_string("several\n")
case a >= 12 && a < 100:
print_string("dozens\n")
case a >= 100 && a < 1000:
print_string("hundreds\n")
default:
print_string("a fuck ton\n")
}
// Identical to this
b := 53
if b == 1 {
print_string("one\n")
} else if b == 2 {
print_string("a couple\n")
} else if b < 7 || b == 7 {
print_string("a few\n")
} else if b < 12 { // intentional bug
print_string("several\n")
} else if b >= 12 && b < 100 {
print_string("dozens\n")
} else if b >= 100 && b < 1000 {
print_string("hundreds\n")
} else {
print_string("a fuck ton\n")
}
// However, match statements allow for `break` and `fallthrough` unlike
// an if statement
}
}
Vector3 :: type struct {
x, y, z: f32
}
print_floats :: proc(args: ..f32) {
for i := 0; i < len(args); i++ {
if i > 0 {
print_string(", ")
}
print_f32(args[i])
}
print_nl()
}
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 :: type struct {
Guid :: type int
Nested :: type struct {
MyInt :: type 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 = 78456
name = "Thing"
print_int(e.guid as int); nl()
print_string(e.name); nl()
}
{
using e: Entity
guid = 78456
name = "Thing"
print_int(e.guid as int); nl()
print_string(e.name); nl()
}
}
{
Entity :: type struct {
Guid :: type int
Nested :: type struct {
MyInt :: type 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 :: type struct {
position: Vector3
}
print_pos_1 :: proc(entity: ^Entity) {
print_string("print_pos_1: ")
print_floats(entity.position.x, entity.position.y, entity.position.z)
}
print_pos_2 :: proc(entity: ^Entity) {
using entity
print_string("print_pos_2: ")
print_floats(position.x, position.y, position.z)
}
print_pos_3 :: proc(using entity: ^Entity) {
print_string("print_pos_3: ")
print_floats(position.x, position.y, position.z)
}
print_pos_4 :: proc(using entity: ^Entity) {
using position
print_string("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 :: type struct {
position: Vector3
}
Frog :: type 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 :: type struct {
position: Vector3
}
Frog :: type struct {
using entity: Entity
jump_height: f32
}
f: Frog
f.position = Vector3{1, 2, 3}
print_pos :: proc(using entity: Entity) {
print_string("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 :: type struct {
position: Vector3
}
Frog :: type 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_string("print_pos: ")
print_floats(position.x, position.y, position.z)
}
print_pos(f.entity)
print_pos(^f)
print_pos(f)
}
{
// More efficient subtyping
Entity :: type struct {
position: Vector3
}
Frog :: type 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^++
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 :: type struct {
position: Vector3
}
Frog :: type struct {
jump_height: f32
using entity: Entity
}
f: Frog
f.jump_height = 564
e := ^f.entity
frog := e down_cast ^Frog
print_string("down_cast: ")
print_f32(frog.jump_height); nl()
// NOTE(bill): `down_cast` is unsafe and there are not check are compile time or run time
}
{
// Multiple "inheritance"
Entity :: type struct {
position: Vector3
}
Climber :: type struct {
speed: f32
}
Frog :: type struct {
using entity: Entity
using climber: Climber
}
}
}
tagged_unions :: proc() {
{
EntityKind :: type enum {
INVALID,
FROG,
GIRAFFE,
HELICOPTER,
}
Entity :: type struct {
kind: EntityKind
using data: 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 = EntityKind.FROG
e.frog.jump_height = 12
f: type_of_val(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
}
{
Entity :: type 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
}
}
using Entity
f1: Frog = Frog{12, 0xff9900}
f2: Entity = Frog{12, 0xff9900} // Implicit cast
f3 := Frog{12, 0xff9900} as Entity // 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
// Q: Allow for a non pointer version with takes a copy instead?
match type ^f -> x {
case Frog:
print_string("Frog!\n")
print_f32(x.jump_height); nl()
x.jump_height = 3
print_f32(x.jump_height); nl()
case Giraffe:
print_string("Giraffe!\n")
case Helicopter:
print_string("ROFLCOPTER!\n")
default:
print_string("invalid entity\n")
}
fp := ^f as ^Frog // Unsafe
print_f32(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 :: type struct {}
Scope :: type struct {}
Token :: type struct {}
AstNode :: type struct {}
ExactValue :: type struct {}
EntityKind :: type enum {
Invalid,
Constant,
Variable,
UsingVariable,
TypeName,
Procedure,
Builtin,
Count,
}
Entity :: type struct {
Guid :: type i64
kind: EntityKind
guid: Guid
scope: ^Scope
token: Token
type_: ^Type
using data: 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
}
UsingVariable: 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 :: type struct {}
Scope :: type struct {}
Token :: type struct {}
AstNode :: type struct {}
ExactValue :: type struct {}
EntityBase :: type struct {
Guid :: type i64
guid: Guid
scope: ^Scope
token: Token
type_: ^Type
}
Entity :: type union {
Constant: struct {
using base: EntityBase
value: ExactValue
}
Variable: struct {
using base: EntityBase
visited: bool // Cycle detection
used: bool // Variable is used
is_field: bool // Is struct field
anonymous: bool // Variable is an anonymous
}
UsingVariable: struct {
using base: EntityBase
}
TypeName: struct {
using base: EntityBase
}
Procedure: struct {
using base: EntityBase
used: bool
}
Builtin: struct {
using base: EntityBase
id: int
}
}
using Entity
e: Entity
e = Variable{
base = EntityBase{},
used = true,
anonymous = false,
}
// Q: Allow a "base" type to be added to a union?
}
{
// `Raw` unions still have uses, especially for mathematic types
Vector2 :: type raw_union {
using xy_: struct { x, y: f32 }
e: [2]f32
v: {2}f32
}
Vector3 :: type raw_union {
using xyz_: struct { x, y, z: f32 }
xy: Vector2
e: [3]f32
v: {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
// Q: If I applied using to a vector element in a raw_union,
// should that type now act as if it was a vector?
}
}
nl :: proc() { print_nl() }
+102 -224
View File
@@ -1,10 +1,68 @@
#load "win32.odin"
// IMPORTANT NOTE(bill): Do not change the order of any of this data
// The compiler relies upon this _exact_ order
Type_Info :: union {
Member :: struct {
name: string
type_: ^Type_Info
offset: int
}
Record :: struct {
fields: []Member
}
Named: struct {
name: string
base: ^Type_Info
}
Integer: struct {
bits: int
signed: bool
}
Float: struct {
bits: int
}
String: struct {}
Boolean: struct {}
Pointer: struct {
elem: ^Type_Info
}
Procedure: struct{}
Array: struct {
elem: ^Type_Info
count: int
}
Slice: struct {
elem: ^Type_Info
}
Vector: struct {
elem: ^Type_Info
count: int
}
Struct: Record
Union: Record
Raw_Union: Record
Enum: struct {
base: ^Type_Info
}
}
Any :: struct {
type_info: ^Type_Info
// pointer to the data stored
data: rawptr
}
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"
__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"
@@ -22,218 +80,29 @@ 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
}
llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
llvm_memset_64bit(data, 0, len, 1, false)
}
memory_compare :: proc(dst, src: rawptr, len: int) -> int {
s1, s2: ^byte = dst, src
// TODO(bill): make a faster `memory_compare`
a, b := slice_ptr(dst as ^byte, len), slice_ptr(src as ^byte, len)
for i := 0; i < len; i++ {
a := ptr_offset(s1, i)^
b := ptr_offset(s2, i)^
if a != b {
return (a - b) as int
if a[i] != b[i] {
return (a[i] - b[i]) 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_copy :: proc(dst, src: rawptr, len: int) #inline {
llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
llvm_memcpy_64bit(dst, src, len, 1, false)
}
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^
}
}
memory_move :: proc(dst, src: rawptr, len: int) #inline {
llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
llvm_memmove_64bit(dst, src, len, 1, false)
}
__string_eq :: proc(a, b: string) -> bool {
@@ -247,25 +116,36 @@ __string_eq :: proc(a, b: string) -> bool {
}
__string_cmp :: proc(a, b : string) -> int {
min_len := len(a)
if len(b) < min_len {
min_len = len(b)
// Translation of http://mgronhol.github.io/fast-strcmp/
n := min(len(a), len(b))
fast := n/size_of(int) + 1
offset := (fast-1)*size_of(int)
curr_block := 0
if n <= size_of(int) {
fast = 0
}
for i := 0; i < min_len; i++ {
x := a[i]
y := b[i]
if x < y {
return -1
} else if x > y {
return +1
la := slice_ptr(^a[0] as ^int, fast)
lb := slice_ptr(^b[0] as ^int, fast)
for ; curr_block < fast; curr_block++ {
if (la[curr_block] ~ lb[curr_block]) != 0 {
for pos := curr_block*size_of(int); pos < n; pos++ {
if (a[pos] ~ b[pos]) != 0 {
return a[pos] as int - b[pos] as int
}
}
}
}
for ; offset < n; offset++ {
if (a[offset] ~ b[offset]) != 0 {
return a[offset] as int - b[offset] as int
}
}
if len(a) < len(b) {
return -1
} else if len(a) > len(b) {
return +1
}
return 0
}
@@ -278,26 +158,24 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
Allocation_Mode :: type enum {
Allocation_Mode :: 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 {
Allocator :: struct {
procedure: Allocator_Proc;
data: rawptr
}
Context :: type struct {
Context :: struct {
thread_ptr: rawptr
user_data: rawptr
+3 -3
View File
@@ -42,7 +42,7 @@ INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
WNDPROC :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
WNDCLASSEXA :: type struct {
WNDCLASSEXA :: struct {
size, style: u32
wnd_proc: WNDPROC
cls_extra, wnd_extra: i32
@@ -54,7 +54,7 @@ WNDCLASSEXA :: type struct {
sm: HICON
}
MSG :: type struct {
MSG :: struct {
hwnd: HWND
message: u32
wparam: WPARAM
@@ -191,7 +191,7 @@ PROC :: type proc()
wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
PIXELFORMATDESCRIPTOR :: type struct {
PIXELFORMATDESCRIPTOR :: struct {
size,
version,
flags: u32