217 lines
4.9 KiB
C
217 lines
4.9 KiB
C
#ifndef UTIL_H
|
|
#define UTIL_H
|
|
|
|
#include "sys.h"
|
|
#include "string.h"
|
|
#include "memory.h"
|
|
#include "arena.h"
|
|
#include "atomic.h"
|
|
|
|
/* Utility functions and stuff that don't have a home :( */
|
|
|
|
/* ========================== *
|
|
* String utils
|
|
* ========================== */
|
|
|
|
#if 0
|
|
struct string util_file_name_from_path(struct string path);
|
|
#endif
|
|
|
|
/* FNV-1a hash function
|
|
* TODO: Something faster if necessary */
|
|
#define HASH_FNV64_SEED 0xcbf29ce484222325
|
|
INLINE u64 hash_fnv64(u64 seed, struct buffer buff)
|
|
{
|
|
u64 hash = seed;
|
|
for (u64 i = 0; i < buff.size; ++i) {
|
|
hash ^= (u8)buff.data[i];
|
|
hash *= 0x100000001b3;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
#if 0
|
|
/* FNV-1a hash function
|
|
* TODO: Something faster if necessary */
|
|
INLINE u32 hash_fnv32(struct buffer buff)
|
|
{
|
|
u32 hash = 2166136261;
|
|
for (u64 i = 0; i < buff.size; ++i) {
|
|
hash ^= (u8)buff.data[i];
|
|
hash *= 16777619;
|
|
}
|
|
return hash;
|
|
}
|
|
#endif
|
|
|
|
/* ========================== *
|
|
* Fixed Dict
|
|
*
|
|
* Simple fixed bucket-count string->value chaining dict for generic use
|
|
* ========================== */
|
|
|
|
struct fixed_dict_entry {
|
|
struct string key;
|
|
void *value;
|
|
u64 hash;
|
|
struct fixed_dict_entry *next;
|
|
};
|
|
|
|
struct fixed_dict_bucket {
|
|
struct fixed_dict_entry *entry_head;
|
|
};
|
|
|
|
struct fixed_dict {
|
|
u64 buckets_count;
|
|
struct fixed_dict_bucket *buckets;
|
|
};
|
|
|
|
INLINE struct fixed_dict fixed_dict_init(struct arena *arena, u64 buckets_count)
|
|
{
|
|
__prof;
|
|
struct fixed_dict dict = { 0 };
|
|
buckets_count = max_u64(buckets_count, 1); /* Ensure at least 1 bucket */
|
|
dict.buckets_count = buckets_count;
|
|
dict.buckets = arena_push_array_zero(arena, struct fixed_dict_bucket, buckets_count);
|
|
return dict;
|
|
}
|
|
|
|
/* arena and key must share lifetime with dict (this function does not copy the key) */
|
|
INLINE void fixed_dict_set(struct arena *arena, struct fixed_dict *dict, struct string key, void *value)
|
|
{
|
|
__prof;
|
|
|
|
u64 hash = hash_fnv64(HASH_FNV64_SEED, BUFFER_FROM_STRING(key));
|
|
u64 index = hash % dict->buckets_count;
|
|
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
|
|
|
struct fixed_dict_entry *entry = bucket->entry_head;
|
|
while (entry) {
|
|
if (hash == entry->hash && string_eq(key, entry->key)) {
|
|
/* Existing match found, replace its contents */
|
|
entry->key = key;
|
|
entry->value = value;
|
|
return;
|
|
}
|
|
entry = entry->next;
|
|
}
|
|
|
|
/* No match found, create new entry */
|
|
entry = arena_push(arena, struct fixed_dict_entry);
|
|
entry->key = key;
|
|
entry->value = value;
|
|
entry->hash = hash;
|
|
entry->next = bucket->entry_head;
|
|
|
|
bucket->entry_head = entry;
|
|
}
|
|
|
|
INLINE void *fixed_dict_get(const struct fixed_dict *dict, struct string key)
|
|
{
|
|
__prof;
|
|
|
|
u64 hash = hash_fnv64(HASH_FNV64_SEED, BUFFER_FROM_STRING(key));
|
|
u64 index = hash % dict->buckets_count;
|
|
struct fixed_dict_bucket *bucket = &dict->buckets[index];
|
|
|
|
for (struct fixed_dict_entry *entry = bucket->entry_head; entry; entry = entry->next) {
|
|
if (hash == entry->hash && string_eq(key, entry->key)) {
|
|
/* Match found */
|
|
return entry->value;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* ========================== *
|
|
* Sync flag
|
|
* ========================== */
|
|
|
|
struct sync_flag {
|
|
/* TODO: Make this a rw mutex? */
|
|
struct sys_mutex mutex;
|
|
struct sys_condition_variable cv;
|
|
struct atomic_i32 flag;
|
|
};
|
|
|
|
INLINE struct sync_flag sync_flag_alloc(void)
|
|
{
|
|
struct sync_flag sf = { 0 };
|
|
sf.mutex = sys_mutex_alloc();
|
|
sf.cv = sys_condition_variable_alloc();
|
|
return sf;
|
|
}
|
|
|
|
INLINE void sync_flag_release(struct sync_flag *sf)
|
|
{
|
|
sys_mutex_release(&sf->mutex);
|
|
sys_condition_variable_release(&sf->cv);
|
|
}
|
|
|
|
INLINE void sync_flag_set(struct sync_flag *sf)
|
|
{
|
|
__prof;
|
|
if (atomic_i32_eval_compare_exchange(&sf->flag, 0, 1) == 0) {
|
|
sys_condition_variable_signal(&sf->cv);
|
|
}
|
|
}
|
|
|
|
INLINE void sync_flag_wait(struct sync_flag *sf)
|
|
{
|
|
__prof;
|
|
while (atomic_i32_eval(&sf->flag) == 0) {
|
|
sys_mutex_lock(&sf->mutex);
|
|
{
|
|
sys_condition_variable_wait(&sf->cv, &sf->mutex);
|
|
}
|
|
sys_mutex_unlock(&sf->mutex);
|
|
}
|
|
}
|
|
|
|
/* ========================== *
|
|
* Sleep frame
|
|
* ========================== */
|
|
|
|
INLINE void sleep_frame(sys_timestamp_t last_frame_time, f64 target_dt)
|
|
{
|
|
__prof;
|
|
if (last_frame_time != 0 && target_dt > 0) {
|
|
f64 last_frame_dt = sys_timestamp_seconds(sys_timestamp() - last_frame_time);
|
|
f64 sleep_time = target_dt - last_frame_dt;
|
|
if (sleep_time > 0) {
|
|
sys_sleep_precise(sleep_time);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/* ========================== *
|
|
* Sync buffer
|
|
* ========================== */
|
|
|
|
struct sync_buff {
|
|
struct arena arena;
|
|
struct sys_mutex mutex;
|
|
};
|
|
|
|
struct sync_buff sync_buff_alloc(u64 arena_reserve)
|
|
{
|
|
}
|
|
|
|
void sync_buff_release(struct sync_buff *sb)
|
|
{
|
|
|
|
}
|
|
|
|
INLINE void sync_buff_read(void)
|
|
{
|
|
}
|
|
|
|
INLINE void sync_buff_write(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#endif
|