camera_cnn

Unnamed repository; edit this file 'description' to name the repository.
git clone anongit@rnpnr.xyz:camera_cnn.git
Log | Files | Refs | Feed | LICENSE

util.c (9814B)


      1 /* See LICENSE for license details. */
      2 #define zero_struct(s) mem_clear(s, 0, sizeof(*s))
      3 function void *
      4 mem_clear(void *restrict p_, u8 c, uz size)
      5 {
      6 	u8 *p = p_;
      7 	while (size) p[--size] = c;
      8 	return p;
      9 }
     10 
     11 function void
     12 mem_copy(void *restrict dest, void *restrict src, uz n)
     13 {
     14 	u8 *s = src, *d = dest;
     15 	for (; n; n--) *d++ = *s++;
     16 }
     17 
     18 function u8 *
     19 arena_aligned_start(Arena a, uz alignment)
     20 {
     21 	uz padding = -(uintptr_t)a.beg & (alignment - 1);
     22 	u8 *result = a.beg + padding;
     23 	return result;
     24 }
     25 
     26 function u8 *
     27 arena_commit(Arena *a, sz size)
     28 {
     29 	assert(a->end - a->beg >= size);
     30 	u8 *result = a->beg;
     31 	a->beg += size;
     32 	return result;
     33 }
     34 
     35 function void
     36 arena_pop(Arena *a, sz length)
     37 {
     38 	a->beg -= length;
     39 }
     40 
     41 #define push_array(a, t, n) (t *)arena_alloc(a, sizeof(t), _Alignof(t), n)
     42 #define push_struct(a, t)   (t *)arena_alloc(a, sizeof(t), _Alignof(t), 1)
     43 function void *
     44 arena_alloc(Arena *a, uz len, uz align, uz count)
     45 {
     46 	void *result = 0;
     47 	if (a->beg) {
     48 		u8 *start = arena_aligned_start(*a, align);
     49 		sz available = a->end - start;
     50 		assert((available >= 0 && count <= (uz)available / len));
     51 		a->beg = start + count * len;
     52 		/* TODO: Performance? */
     53 		result = mem_clear(start, 0, count * len);
     54 	}
     55 	return result;
     56 }
     57 
     58 enum { DA_INITIAL_CAP = 4 };
     59 #define da_reserve(a, s, n) \
     60   (s)->data = da_reserve_((a), (s)->data, &(s)->capacity, (s)->count + n, \
     61                           _Alignof(typeof(*(s)->data)), sizeof(*(s)->data))
     62 
     63 #define da_push(a, s) \
     64   ((s)->count == (s)->capacity  \
     65     ? da_reserve(a, s, 1u),     \
     66       (s)->data + (s)->count++  \
     67     : (s)->data + (s)->count++)
     68 
     69 function void *
     70 da_reserve_(Arena *a, void *data, sz *capacity, sz needed, uz align, uz size)
     71 {
     72 	uz cap = (uz)*capacity;
     73 
     74 	/* NOTE(rnp): handle both 0 initialized DAs and DAs that need to be moved (they started
     75 	 * on the stack or someone allocated something in the middle of the arena during usage) */
     76 	if (!data || a->beg != (u8 *)data + cap * size) {
     77 		void *copy = arena_alloc(a, size, align, cap);
     78 		if (data) mem_copy(copy, data, cap * size);
     79 		data = copy;
     80 	}
     81 
     82 	if (!cap) cap = DA_INITIAL_CAP;
     83 	while (cap < needed) cap *= 2;
     84 	arena_alloc(a, size, align, cap - (uz)*capacity);
     85 	*capacity = (sz)cap;
     86 	return data;
     87 }
     88 
     89 function u32
     90 utf8_encode(u8 *out, u32 cp)
     91 {
     92 	u32 result = 1;
     93 	if (cp <= 0x7F) {
     94 		out[0] = cp & 0x7F;
     95 	} else if (cp <= 0x7FF) {
     96 		result = 2;
     97 		out[0] = ((cp >>  6) & 0x1F) | 0xC0;
     98 		out[1] = ((cp >>  0) & 0x3F) | 0x80;
     99 	} else if (cp <= 0xFFFF) {
    100 		result = 3;
    101 		out[0] = ((cp >> 12) & 0x0F) | 0xE0;
    102 		out[1] = ((cp >>  6) & 0x3F) | 0x80;
    103 		out[2] = ((cp >>  0) & 0x3F) | 0x80;
    104 	} else if (cp <= 0x10FFFF) {
    105 		result = 4;
    106 		out[0] = ((cp >> 18) & 0x07) | 0xF0;
    107 		out[1] = ((cp >> 12) & 0x3F) | 0x80;
    108 		out[2] = ((cp >>  6) & 0x3F) | 0x80;
    109 		out[3] = ((cp >>  0) & 0x3F) | 0x80;
    110 	} else {
    111 		out[0] = '?';
    112 	}
    113 	return result;
    114 }
    115 
    116 function UnicodeDecode
    117 utf16_decode(u16 *data, sz length)
    118 {
    119 	UnicodeDecode result = {.cp = U32_MAX};
    120 	if (length) {
    121 		result.consumed = 1;
    122 		result.cp = data[0];
    123 		if (length > 1 && BETWEEN(data[0], 0xD800, 0xDBFF)
    124 		               && BETWEEN(data[1], 0xDC00, 0xDFFF))
    125 		{
    126 			result.consumed = 2;
    127 			result.cp = ((data[0] - 0xD800u) << 10) | ((data[1] - 0xDC00u) + 0x10000u);
    128 		}
    129 	}
    130 	return result;
    131 }
    132 
    133 function u32
    134 utf16_encode(u16 *out, u32 cp)
    135 {
    136 	u32 result = 1;
    137 	if (cp == U32_MAX) {
    138 		out[0] = '?';
    139 	} else if (cp < 0x10000) {
    140 		out[0] = (u16)cp;
    141 	} else {
    142 		u32 value = cp - 0x10000;
    143 		out[0] = (u16)(0xD800u + (value >> 10u));
    144 		out[1] = (u16)(0xDC00u + (value & 0x3FFu));
    145 		result = 2;
    146 	}
    147 	return result;
    148 }
    149 
    150 function Stream
    151 stream_alloc(Arena *a, u32 cap)
    152 {
    153 	Stream result = {.cap = cap};
    154 	result.data = push_array(a, u8, cap);
    155 	return result;
    156 }
    157 
    158 function str8
    159 stream_to_str8(Stream *s)
    160 {
    161 	str8 result = str8("");
    162 	if (!s->errors) result = (str8){.len = s->widx, .data = s->data};
    163 	return result;
    164 }
    165 
    166 function void
    167 stream_reset(Stream *s, u32 index)
    168 {
    169 	s->errors = s->cap <= index;
    170 	if (!s->errors)
    171 		s->widx = index;
    172 }
    173 
    174 function void
    175 stream_commit(Stream *s, sz count)
    176 {
    177 	s->errors |= !BETWEEN(s->widx + count, 0, s->cap);
    178 	if (!s->errors)
    179 		s->widx += count;
    180 }
    181 
    182 function void
    183 stream_append(Stream *s, void *data, sz count)
    184 {
    185 	s->errors |= (s->cap - s->widx) < count;
    186 	if (!s->errors) {
    187 		mem_copy(s->data + s->widx, data, (u32)count);
    188 		s->widx += count;
    189 	}
    190 }
    191 
    192 function void
    193 stream_append_byte(Stream *s, u8 b)
    194 {
    195 	stream_append(s, &b, 1);
    196 }
    197 
    198 function void
    199 stream_append_str8(Stream *s, str8 str)
    200 {
    201 	stream_append(s, str.data, (u32)str.len);
    202 }
    203 
    204 #define stream_append_str8s(s, ...) stream_append_str8s_(s, (str8 []){__VA_ARGS__}, \
    205                                                          sizeof((str8 []){__VA_ARGS__}) / sizeof(str8))
    206 function void
    207 stream_append_str8s_(Stream *s, str8 *strs, sz count)
    208 {
    209 	for (sz i = 0; i < count; i++)
    210 		stream_append(s, strs[i].data, (u32)strs[i].len);
    211 }
    212 
    213 function void
    214 stream_append_u64_width(Stream *s, u64 n, u64 min_width)
    215 {
    216 	u8 tmp[64];
    217 	u8 *end = tmp + sizeof(tmp);
    218 	u8 *beg = end;
    219 	min_width = MIN(sizeof(tmp), min_width);
    220 
    221 	do { *--beg = '0' + (n % 10); } while (n /= 10);
    222 	while (end - beg > 0 && end - beg < min_width)
    223 		*--beg = '0';
    224 
    225 	stream_append(s, beg, end - beg);
    226 }
    227 
    228 function void
    229 stream_append_u64(Stream *s, u64 n)
    230 {
    231 	stream_append_u64_width(s, n, 0);
    232 }
    233 
    234 function void
    235 stream_append_s64(Stream *s, s64 n)
    236 {
    237 	if (n < 0) {
    238 		stream_append_byte(s, '-');
    239 		n *= -1;
    240 	}
    241 	stream_append_u64(s, (u64)n);
    242 }
    243 
    244 function void
    245 stream_append_f64(Stream *s, f64 f, s64 prec)
    246 {
    247 	if (f < 0) {
    248 		stream_append_byte(s, '-');
    249 		f *= -1;
    250 	}
    251 
    252 	/* NOTE: round last digit */
    253 	f += 0.5f / (float)prec;
    254 
    255 	if (f >= (f64)(-1UL >> 1)) {
    256 		stream_append_str8(s, str8("inf"));
    257 	} else {
    258 		u64 integral = (u64)f;
    259 		u64 fraction = (u64)((f - (f64)integral) * (f64)prec);
    260 		stream_append_u64(s, integral);
    261 		stream_append_byte(s, '.');
    262 		for (s64 i = prec / 10; i > 1; i /= 10) {
    263 			if (i > fraction)
    264 				stream_append_byte(s, '0');
    265 		}
    266 		stream_append_u64(s, fraction);
    267 	}
    268 }
    269 
    270 function Stream
    271 arena_stream(Arena a)
    272 {
    273 	Stream result = {0};
    274 	result.data   = a.beg;
    275 	result.cap    = (u32)(a.end - a.beg);
    276 	return result;
    277 }
    278 
    279 function str8
    280 arena_stream_commit_zero(Arena *a, Stream *s)
    281 {
    282 	b32 error = s->errors || s->widx == s->cap;
    283 	if (!error)
    284 		s->data[s->widx] = 0;
    285 	str8 result = stream_to_str8(s);
    286 	arena_commit(a, result.len + 1);
    287 	return result;
    288 }
    289 
    290 function str8
    291 arena_stream_commit(Arena *a, Stream *s)
    292 {
    293 	assert(s->data == a->beg);
    294 	str8 result = stream_to_str8(s);
    295 	arena_commit(a, result.len);
    296 	return result;
    297 }
    298 
    299 /* NOTE(rnp): FNV-1a hash */
    300 function u64
    301 str8_hash(str8 v)
    302 {
    303 	u64 h = 0x3243f6a8885a308d; /* digits of pi */
    304 	for (; v.len; v.len--) {
    305 		h ^= v.data[v.len - 1] & 0xFF;
    306 		h *= 1111111111111111111; /* random prime */
    307 	}
    308 	return h;
    309 }
    310 
    311 function b32
    312 c_str_equal(const char *a, const char *b)
    313 {
    314 	b32 result = 0;
    315 	if (a && b) {
    316 		while (*a && *b && *a == *b) { a++, b++; }
    317 		result = *a == 0 && *b == 0;
    318 	}
    319 	return result;
    320 }
    321 
    322 
    323 function str8
    324 c_str_to_str8(char *cstr)
    325 {
    326 	str8 result = {.data = (u8 *)cstr};
    327 	if (cstr) while (*cstr) { cstr++; }
    328 	result.len = (u8 *)cstr - result.data;
    329 	return result;
    330 }
    331 
    332 /* NOTE(rnp): returns < 0 if byte is not found */
    333 function sz
    334 str8_scan_backwards(str8 s, u8 byte)
    335 {
    336 	sz result = s.len;
    337 	while (result && s.data[result - 1] != byte) result--;
    338 	result--;
    339 	return result;
    340 }
    341 
    342 function str8
    343 str8_trim_trailing(str8 s, u8 byte)
    344 {
    345 	str8 result = s;
    346 	while (result.len >= 1 && result.data[result.len - 1] == byte) result.len--;
    347 	return result;
    348 }
    349 
    350 function str8
    351 str8_cut_head(str8 s, sz cut)
    352 {
    353 	str8 result = s;
    354 	if (cut > 0) {
    355 		result.data += cut;
    356 		result.len  -= cut;
    357 	}
    358 	return result;
    359 }
    360 
    361 function str8
    362 str8_alloc(Arena *a, sz len)
    363 {
    364 	str8 result = {.data = push_array(a, u8, (uz)len), .len = len};
    365 	return result;
    366 }
    367 
    368 function str8
    369 str16_to_str8(Arena *a, str16 in)
    370 {
    371 	str8 result = str8("");
    372 	if (in.len) {
    373 		sz commit = in.len * 4;
    374 		sz length = 0;
    375 		u8 *data = arena_commit(a, commit + 1);
    376 		u16 *beg = in.data;
    377 		u16 *end = in.data + in.len;
    378 		while (beg < end) {
    379 			UnicodeDecode decode = utf16_decode(beg, end - beg);
    380 			length += utf8_encode(data + length, decode.cp);
    381 			beg    += decode.consumed;
    382 		}
    383 		data[length] = 0;
    384 		result = (str8){.len = length, .data = data};
    385 		arena_pop(a, commit - length);
    386 	}
    387 	return result;
    388 }
    389 
    390 function str16
    391 str8_to_str16(Arena *a, str8 in)
    392 {
    393 	str16 result = {0};
    394 	if (in.len) {
    395 		sz required = 2 * in.len + 1;
    396 		u16 *data   = push_array(a, u16, (uz)required);
    397 		sz length   = 0;
    398 		/* TODO(rnp): utf8_decode */
    399 		for (sz i = 0; i < in.len; i++) {
    400 			u32 cp  = in.data[i];
    401 			length += utf16_encode(data + length, cp);
    402 		}
    403 		result = (str16){.len = length, .data = data};
    404 		arena_pop(a, required - length);
    405 	}
    406 	return result;
    407 }
    408 
    409 function str8
    410 push_str8(Arena *a, str8 str)
    411 {
    412 	str8 result = str8_alloc(a, str.len);
    413 	mem_copy(result.data, str.data, (uz)result.len);
    414 	return result;
    415 }
    416 
    417 function str8
    418 push_str8_zero(Arena *a, str8 str)
    419 {
    420 	str8 result  = str8_alloc(a, str.len + 1);
    421 	result.len  -= 1;
    422 	mem_copy(result.data, str.data, (uz)result.len);
    423 	return result;
    424 }
    425 
    426 function f64
    427 parse_f64(str8 s)
    428 {
    429 	f64 integral = 0, fractional = 0, sign = 1;
    430 
    431 	if (s.len && *s.data == '-') {
    432 		sign = -1;
    433 		s.data++;
    434 		s.len--;
    435 	}
    436 
    437 	while (s.len && *s.data != '.') {
    438 		integral *= 10;
    439 		integral += *s.data - '0';
    440 		s.data++;
    441 		s.len--;
    442 	}
    443 
    444 	if (*s.data == '.') { s.data++; s.len--; }
    445 
    446 	while (s.len) {
    447 		assert(s.data[s.len - 1] != '.');
    448 		fractional /= 10;
    449 		fractional += (f64)(s.data[--s.len] - '0') / 10.0;
    450 	}
    451 	f64 result = sign * (integral + fractional);
    452 	return result;
    453 }
    454 
    455 function FileWatchDirectory *
    456 lookup_file_watch_directory(FileWatchContext *ctx, u64 hash)
    457 {
    458 	FileWatchDirectory *result = 0;
    459 	for (u32 i = 0; i < ctx->count; i++) {
    460 		FileWatchDirectory *test = ctx->data + i;
    461 		if (test->hash == hash) {
    462 			result = test;
    463 			break;
    464 		}
    465 	}
    466 	return result;
    467 }