-
Notifications
You must be signed in to change notification settings - Fork 0
/
flib.h
316 lines (286 loc) · 10.9 KB
/
flib.h
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#include <stdarg.h> // va_args
// sometimes i get tired of writing "unsigned"...
typedef unsigned char byte;
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef unsigned long long ullong;
#define array_length(x) \
((sizeof(x) / sizeof(*(x))))
#define countof(x) \
array_length(x)
// iterate through an array
// example:
// int r[] = {1, 2, 3, 4};
// for_each(int, x, r)
// printf("value %d in index %d\n", *x, index);
#define for_each(type, x, arr) \
for (type *x = (arr); x < (arr) + array_length(arr); x++)
// iterate through an array up to n elements.
#define for_each_n(type, x, arr, n) \
for (type *x = (arr); x < (arr) + min(array_length(arr), (n)); x++)
// iterate through an array in reverse order.
#define for_each_reverse(type, x, arr) \
for (type *x = (arr) + array_length(arr) - 1; x >= (arr); x--)
// iterate through an array in reverse order up to n elements.
#define for_each_reverse_n(type, x, arr, n) \
for (type *x = (arr) + array_length(arr) - 1; x >= (arr) + array_length(arr) - (n); x--)
// alternative version for for_each. you can use
// index to know what index you currently are.
// example:
// int r[] = {1, 2, 3, 4};
// each(int *x, r)
// printf("value %d in index %d\n", *x, index);
#define each(item, array) \
for (unsigned long long keep = 1, index = 0; keep && index < countof(array); keep = !keep, index++) \
for(item = (array) + index; keep; keep = !keep)
// iterate array up to max elements.
#define eachn(item, array, max) \
for (unsigned long long keep = 1, index = 0; keep && index < (max); keep = !keep, index++) \
for(item = (array) + index; keep; keep = !keep)
// same as for_each_reverse. iterate through an array in reverse order.
#define rev(item, array) \
for (unsigned long long keep = 1, index = countof(array) - 1; keep && (long long) index != -1; keep = !keep, index--) \
for(item = (array) + index; keep; keep = !keep)
// iterate array in reverse order up to max elements.
#define revn(item, array, max) \
for (unsigned long long keep = 1, index = countof(array) - 1, max2 = (max); keep && max2 != 0; keep = !keep, index--, max2--) \
for(item = (array) + index; keep; keep = !keep)
// profile a block of code
// BEFORE the block gets executed, the function unsigned long long profile_start(const char *name)
// will be called. this function should return a timer or a number that later can
// be used to tell how much the block of code took to execute.
// AFTER the block gets executed, the function profile_end(const char *name, unsigned long long diff)
// will be called. this function receives the name of the block plus the start number
// returned by profile_start.
// example:
// unsigned long long profile_start(const char *name)
// {
// return time(0);
// }
// void profile_end(const char *name, unsigned long long start_time)
// {
// printf("block of code %s took %ld seconds to run.\n", name, time(0) - start_time);
// }
// int main(void)
// {
// profile("some name") some_expensive_operation();
// profile("some other name") {
// some_expensive_operation();
// some_expensive_operation();
// break; // don't return, otherwise profile_end won't be called.
// some_expensive_operation();
// }
// return 0;
// }
#define profile(name) \
for (unsigned long long _start = profile_start(name), _run_parent = 1; _run_parent; (profile_end(name, _start), _run_parent = 0)) \
for (int _run_child = 1; _run_child; _run_child = 0)
#define profilef \
profile(__FUNCTION__)
#define nl "\n"
#define abs(x) \
((x) < 0 ? (-(x)) : (x))
#define min(a, b) \
((a) < (b) ? (a) : (b))
#define max(a, b) \
((a) > (b) ? (a) : (b))
#define clamp(x, a, b) \
(min(max((x), min((a), (b))), max((a), (b))))
#define lerp(x, a, b) \
((a) * (1 - (x)) + ((b) * (x)))
#define sqr(x) \
((x) * (x))
// coroutine/fiber/green-thread/task
// example:
// void my_coroutine(struct coroutine *ctx)
// {
// coroutine(ctx) {
// // on first call, this will be executed.
// // then exit.
// yield(1);
// // on second call, this will be executed.
// // then exit.
// yield(2)
// // third call, this chunk will execute, restarting
// // the coroutine state to start from the beginning.
// reset;
// }
// }
#define coroutine(ctx) \
struct coroutine *__coro = (ctx); \
switch (__coro->state) \
case 0:
// yield and update the state of the coroutine.
// id must be unique.
// id could be replaced with __LINE__ if you don't
// hot-reload your code. if you do though, you
// can't since any change can update your line
// numbers and produce incorrect results.
#define yield(id) \
do { \
__coro->state = (id); \
return; \
case (id):; \
} while (0)
// sleep and yield until timeout has past.
// dt = how much time has past (if you are writing
// a game, this would be the delta time of each
// frame)
#define syield(id, _timeout, dt) \
do { \
__coro->timeout = (_timeout); \
yield(id); \
__coro->timeout -= (dt); \
if (__coro->timeout > 0) \
return; \
} while(0)
// reset the coroutine state to start from the beginning.
#define reset \
do { \
*__coro = (struct coroutine){0}; \
} while (0)
// str format using fixed array as destination.
#define strf_ex(dest, format, ...) \
(strf((dest), sizeof(dest), (format), __VA_ARGS__))
#define id_get_ex(dest, ids) \
(id_get((dest), (ids), array_length(ids)))
typedef union v2 {
struct { float x, y; };
struct { float w, h; };
float f[2];
} v2;
struct coroutine {
unsigned int state;
float timeout;
};
// fast inverse square root.
// https://en.wikipedia.org/wiki/Fast_inverse_square_root
float q_rsqrt(float number);
v2 v2_add(v2 x1, v2 x2);
v2 v2_sub(v2 x1, v2 x2);
v2 v2_scale(v2 x, float n);
// get normalized/direction from src to dest.
v2 v2_direction_to(v2 src, v2 dest);
v2 v2_normalize(v2 x);
float v2_dot(v2 x1, v2 x2);
float v2_sqr_length(v2 x);
float v2_sqr_distance(v2 src, v2 dest);
// check circle c1 with radius r1 collides with circle c2 with radius r2.
int cc_hit(v2 c1, v2 c2, float r1, float r2);
// check if point p is inside circle c with radius r.
int cp_hit(v2 c, float r, v2 p);
// check if point p is inside rectangle r with width w and height h.
int rp_hit(v2 r, float w, float h, v2 p);
// check rectangle r1 collides with rectangle r2.
int rr_hit(v2 r1, v2 r2, float w1, float h1, float w2, float h2);
// check if string src starts with match.
// both strings need to be null terminated.
// src and match can be null.
int str_starts_with(char *src, char *match);
int str_starts_with_n(char *src, char *match, unsigned int n);
// check if string src ends with match.
// both strings need to be null terminated.
// src and match can be null.
int str_ends_with(char *src, char *match);
int str_ends_with_n(char *src, char *match, unsigned int n);
// check if string a and b are equal.
// both strings need to be null terminated.
// a and b can be null.
int str_equals(char *a, char *b);
int str_equals_n(char *a, char *b, unsigned int n);
// get length of src.
// src must be null terminated.
// src can be null.
unsigned int str_length(char *src);
// convert integer x to string.
// dest can be null.
// dest will be null terminated.
// the amount of characters written is returned (including null terminator)
unsigned int str_int(char *dest, int x, unsigned int base, unsigned int n);
// convert double x to string.
// dest can be null.
// dest will be null terminated.
// the amount of characters written is returned (including null terminator)
unsigned int str_double(char *dest, double x, unsigned int n);
// parse int from src and store it in dest.
// dest can be null.
// returns the number of bytes scanned.
unsigned int str_parse_int(int *dest, char *src);
unsigned int str_parse_double(double *dest, char *src);
// build a hash from a string.
unsigned int str_hash(char *src);
// write up to n bytes of formatted string into dest.
// dest will be null terminated.
// returns number of bytes used/written (INCLUDING null terminator)
//
// formats:
// %% = escapes % and only writes one %.
// %c = writes character.
// %s = writes strings up to null terminator.
// %*s = writes n bytes of string.
// example: strf(dest, n, "%*s", 2, "lorem")
// only writes 2 bytes/chars, meaning, "lo"
// %x = writes hexadecimal.
// %d = writes int.
// %f = writes float/double with 2 decimals.
// %v = writes vector with format "(x:y)"
// %? = use custom function to do the writting. IMPORTANT, make sure
// your function returns the proper amount of bytes written,
// INCLUDING the null terminator.
// example: strf(dest, n, "%?", custom_func, pointer_to_val);
// unsigned int custom_func(char *dest, void *v, usize n)
// {
// // write to dest and return how many bytes were written.
// unsigned int written = ...
// return written;
// }
unsigned int strf(char *dest, unsigned int n, char *format, ...);
unsigned int vstrf(char *dest, unsigned int n, char *format, va_list va);
// scan string from src using the pattern from pattern
// if the string doesn't conform to the pattern,
// the function will return at the first mismatch.
//
// formats:
// %d = reads integer
// %f = reads double
// %*s = reads up to n bytes of string or first space or tab
// if the entire string can't be read/stored
// into the buffer, what can be stored will be stored
// and the rest is discarded. the string is guaranteed
// to be null terminated.
//
// example:
// int i = 0;
// double d = 0;
// char str[4] = {0};
// str_scan("int is 42, double is 42.5, str is randomstring", "int is %d, double is %f, str is %*s", &i, &d, (uint) sizeof(str), str);
//
// after this call, i will be 42, d will be 42.5, and str will be "ran" (notice the last byte was used for the null terminator)
//
// returns how many bytes were parsed/scanned from src.
unsigned int vstr_scan(char *src, char *pattern, va_list va);
unsigned int str_scan(char *src, char *pattern, ...);
// get a reusable id from ids without exceeding n ids.
// example, if you have a list of ids like [1, 2, 3]
// the first time you call this function, you will get 1.
// the second time 2. now let's say you are done with number 1.
// this id (1) will get recycled with id_recycle. when you
// call id_get again, you won't get 3, but instead, you
// will get 1, since this id got recycled and it's ready to be used again.
// if you call the function again, now you will get 3.
// 0 = error: no more space left; dest is null or ids is null.
// 1 = success, using recycled id.
// 2 = success, using new id.
int id_get(unsigned int *dest, unsigned int *ids, unsigned int n);
// mark the id as done so it can be recycled when
// id_get gets called again.
void id_recycle(unsigned int *ids, unsigned int id);
// random integer.
// seed can be null in which case, a hard coded
// seed will be used instead.
unsigned int random_int(unsigned int *seed);
// random integer between lower and upper.
// seed can be null.
unsigned int random_int_ex(unsigned int *seed, unsigned int lower, unsigned int upper);