-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodule.jai
More file actions
156 lines (122 loc) · 4.25 KB
/
module.jai
File metadata and controls
156 lines (122 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
Stuart's Utils
This module is just a random collection of utility functions that I find myself using quite often.
Many of these are somewhat particular to the sort of dynamic type-info stuff done in gon, dyncall, data packer, and lead sheets.
I should probably put this up on my github and figure out how to do a submodule thing so that I don't have to keep duplicating all these functions.
*/
// TODO: Remove dependencies, probably. I guess it matters less over time as I just move things out of here...
#import "Reflect";
#import "Code_Format";
#load "procedure_info.jai";
#load "arrays.jai";
#load "scanner.jai";
#load "static_string.jai";
#load "static_array.jai";
#load "fixed_bit_array.jai";
#load "slot_array.jai";
#load "dynamic_procedure_call.jai";
// ========== General Purpose ==========
u0 :: void;
memzero :: (t: *$T) { memset(t, 0, size_of(T)); };
all_bytes_are_zero :: (any: Any) -> bool {
return all_bytes_are_zero(any.value_pointer, any.type.runtime_size);
}
// TODO: could be much more efficient
all_bytes_are_zero :: (data: *void, count: int) -> bool {
ptr := data.(*u8);
end := ptr + count;
while ptr < end {
if ptr.* return false;
ptr += 1;
}
return true;
}
is_valid_index :: inline (array: []$T, index: int) -> bool {
return index >= 0 && index < array.count;
}
is_within_range :: inline (value: $T, low: T, high: T) -> bool #modify {
return is_numeric(T);
} {
return value >= low && value <= high;
}
// restores the value of a variable at this time upon scope exit
// kind of like push_allocator
defer_restore :: (value: *$T) #expand {
value_before := value.*;
`defer value.* = value_before;
}
push_value_of :: (var: *$T, value: T) #expand {
value_before := var.*;
var.* = value;
`defer var.* = value_before;
}
offset_of :: inline ($T: Type, $member: string) -> int {
return #run -> int {
for type_info(T).members {
if it.name == member return it.offset_in_bytes;
}
assert(false, "Type '%' does not have member '%'", T, member);
return -1;
};
}
unreachable :: inline (loc := #caller_location) {
assert(false, "unreachable at %: line %, column %", loc.fully_pathed_filename, loc.line_number, loc.character_number);
}
// just tprint but with automatic null-termination, and returning a *u8
tprintc :: (format_string: string, args: .. Any) -> *u8 {
builder: String_Builder;
builder.allocator = temp;
print_to_builder(*builder, format_string, ..args);
append(*builder, "\0");
return builder_to_string(*builder,, temp).data;
} @PrintLike
is_within_array :: inline (array: [] $T, ptr: *T) -> bool {
// TODO: could also do check to make sure alignment is correct? Maybe as a baked parameter?
return ptr >= array.data && ptr <= array.data + array.count - 1;
}
// NOTE: this is probably slow, ideally we could just use popcount on x86
count_set_bits :: (n: int) -> int {
count := 0;
while n {
count += n & 1;
n <<= 1;
}
return count;
}
has_all_flags :: inline (e: $E, flags: E) -> bool #modify {
return is_enum_flags(E), "Type E must be an enum_flags.";
} {
return e & flags == flags;
}
has_any_flags :: inline (e: $E, flags: E) -> bool #modify {
return is_enum_flags(E), "Type E must be an enum_flags.";
} {
return e & flags != 0;
}
// just because it is nicer to read in many cases
has_flag :: has_all_flags;
// ========== Math-ish ==========
// I don't really wanna put too much math stuff in this module since that should probably get its own separate module,
// but I'm including a couple simple things that I could see myself using quite often.
delerp :: (a: float64, b: float64, val: float64) -> float64 {
high := max(a, b);
low := min(a, b);
return (val - low) / (high - low);
}
modulo :: (n: $T, d: T) -> T #modify { return T.(*Type_Info).type == .INTEGER; } {
return n % d + ifx n < 0 then d else 0;
}
// copied from Hash_Table module...
next_power_of_two :: inline (x: int) -> int {
// @Speed: This could certainly be faster.
// There is probably something in Hacker's Delight for this.
assert(x != 0);
p := 1;
while x > p p += p;
return p;
}
#scope_module
#import "Basic";
#import "String";
#import "Math";
#import "Unicode";