Implement Robin Hood hashing (#200)

* Implement Robin Hood hashing

This replaces the previous separate chaining implementation. This
approach is more memory-efficient, cache-friendly, and puts much less
stress on the memory allocator.

* Replace crc32 with fnva1

Also attempt to make the compiler pre-hash as much stuff as possible at
build time.
This commit is contained in:
Andrei Alexeyev 2020-03-17 10:09:49 +02:00 committed by GitHub
parent 15593ab207
commit 0fdea86be1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 472 additions and 375 deletions

View file

@ -72,13 +72,6 @@ option(
description : 'Build statically linked executable'
)
option(
'intel_intrin',
type : 'boolean',
value : true,
description : 'Use some x86-specific intrinsics for optimizations where appropriate (if possible). Note that this is not equivalent to e.g. supplying -march in CFLAGS'
)
option(
'debug_opengl',
type : 'boolean',

View file

@ -13,15 +13,3 @@
#define HT_IMPL
#include "hashtable_predefs.inc.h"
uint32_t (*htutil_hashfunc_string)(uint32_t crc, const char *str);
void htutil_init(void) {
if(SDL_HasSSE42()) {
log_info("Using SSE4.2-accelerated CRC32 as the string hash function");
htutil_hashfunc_string = crc32str_sse42;
} else {
log_info("Using software fallback CRC32 as the string hash function");
htutil_hashfunc_string = crc32str;
}
}

View file

@ -18,12 +18,9 @@
*/
typedef uint32_t hash_t;
/*
* htutil_init
*
* One-time setup function.
*/
void htutil_init(void);
#define HT_HASH_LIVE_BIT ((hash_t)(1) << (sizeof(hash_t) * CHAR_BIT - 1))
typedef hash_t ht_size_t;
/*
* htutil_hashfunc_uint32
@ -55,7 +52,25 @@ INLINE hash_t htutil_hashfunc_uint64(uint64_t x) {
*
* Hash function for null-terminated strings.
*/
extern uint32_t (*htutil_hashfunc_string)(uint32_t crc, const char *str);
INLINE uint32_t htutil_hashfunc_string(const char *str) {
// FNV1a hash
//
// Not looking for '\0' in the for loop because apparently compilers optimize this better.
// Both GCC and clang can fold this entire function into a constant with a constant str.
// GCC fails that if strlen is not used.
uint32_t hash = 0x811c9dc5;
uint32_t prime = 0x1000193;
size_t len = strlen(str);
for(int i = 0; i < len; ++i) {
uint8_t value = str[i];
hash = hash ^ value;
hash *= prime;
}
return hash;
}
// Import public declarations for the predefined hashtable types.
#define HT_DECL

View file

@ -231,7 +231,7 @@
* but may improve performance. Must be a power of 2.
*/
#ifndef HT_MIN_SIZE
#define HT_MIN_SIZE 32
#define HT_MIN_SIZE 4
#endif
static_assert((HT_MIN_SIZE & (~HT_MIN_SIZE + 1)) == HT_MIN_SIZE, "HT_MIN_SIZE must be power of two");
@ -333,10 +333,11 @@ struct HT_TYPE(key_list) {
* All of these fields are to be considered private.
*/
struct HT_BASETYPE {
HT_TYPE(element) **table;
size_t num_elements;
size_t table_size;
size_t hash_mask;
HT_TYPE(element) *elements;
ht_size_t num_elements_occupied;
ht_size_t num_elements_allocated;
ht_size_t max_psl;
hash_t hash_mask;
#ifdef HT_THREAD_SAFE
struct {
@ -358,8 +359,8 @@ struct HT_TYPE(iter) {
bool has_data;
struct {
size_t bucketnum;
HT_TYPE(element) *elem;
ht_size_t i;
ht_size_t remaining;
} private;
};
@ -426,17 +427,28 @@ HT_DECLARE_FUNC(void, unlock, (HT_BASETYPE *ht))
* Retrieve a value associated with [key]. If there is no association, [fallback] will
* be returned instead.
*/
HT_DECLARE_FUNC(HT_TYPE(value), get, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback))
HT_DECLARE_FUNC(HT_TYPE(value), get_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) fallback))
attr_nonnull(1);
attr_nonnull(1)
INLINE HT_DECLARE_FUNC(HT_TYPE(value), get, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback)) {
return HT_FUNC(get_prehashed)(ht, key, HT_FUNC_HASH_KEY(key), fallback);
}
#ifdef HT_THREAD_SAFE
/*
* ht_XXX_value_t ht_XXX_get_unsafe(ht_XXX_t *ht, ht_XXX_const_key_t key, ht_XXX_const_value_t fallback);
*
* A non-thread-safe version of ht_XXX_get().
*/
HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback))
HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) fallback))
attr_nonnull(1);
attr_nonnull(1)
INLINE HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback)) {
return HT_FUNC(get_unsafe_prehashed)(ht, key, HT_FUNC_HASH_KEY(key), fallback);
}
#endif // HT_THREAD_SAFE
/*
@ -447,17 +459,28 @@ HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key)
*
* Returns true if an entry is found, false otherwise.
*/
HT_DECLARE_FUNC(bool, lookup, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value))
HT_DECLARE_FUNC(bool, lookup_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) *out_value))
attr_nonnull(1) attr_nodiscard;
attr_nonnull(1) attr_nodiscard
INLINE HT_DECLARE_FUNC(bool, lookup, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value)) {
return HT_FUNC(lookup_prehashed)(ht, key, HT_FUNC_HASH_KEY(key), out_value);
}
#ifdef HT_THREAD_SAFE
/*
* bool ht_XXX_lookup_unsafe(ht_XXX_t *ht, ht_XXX_const_key_t key, ht_XXX_value_t *out_value);
*
* A non-thread-safe version of ht_XXX_lookup().
*/
HT_DECLARE_FUNC(bool, lookup_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value))
HT_DECLARE_FUNC(bool, lookup_unsafe_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) *out_value))
attr_nonnull(1) attr_nodiscard;
attr_nonnull(1) attr_nodiscard
INLINE HT_DECLARE_FUNC(bool, lookup_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value)) {
return HT_FUNC(lookup_unsafe_prehashed)(ht, key, HT_FUNC_HASH_KEY(key), out_value);
}
#endif // HT_THREAD_SAFE
/*
@ -497,9 +520,13 @@ HT_DECLARE_FUNC(bool, set, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(val
* With HT_THREAD_SAFE defined, this is an atomic operation: the algorithm holds
* a write lock for its whole duration.
*/
HT_DECLARE_FUNC(bool, try_set, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) value, HT_TYPE(value) (*value_transform)(HT_TYPE(value)), HT_TYPE(value) *out_value))
HT_DECLARE_FUNC(bool, try_set_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) value, HT_TYPE(value) (*value_transform)(HT_TYPE(value)), HT_TYPE(value) *out_value))
attr_nonnull(1) attr_nodiscard;
INLINE HT_DECLARE_FUNC(bool, try_set, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) value, HT_TYPE(value) (*value_transform)(HT_TYPE(value)), HT_TYPE(value) *out_value)) {
return HT_FUNC(try_set_prehashed)(ht, key, HT_FUNC_HASH_KEY(key), value, value_transform, out_value);
}
/*
* bool ht_XXX_unset(ht_XXX_t *ht, ht_XXX_const_key_t key);
*
@ -594,20 +621,65 @@ HT_DECLARE_FUNC(void, iter_next, (HT_TYPE(iter) *iter))
HT_DECLARE_FUNC(void, iter_end, (HT_TYPE(iter) *iter))
attr_nonnull(1);
/*
* hash_t ht_XXX_hash(ht_XXX_const_key_t key);
*
* Compute the key's hash, suitable to pass to _prehashed functions.
*/
INLINE HT_DECLARE_FUNC(hash_t, hash, (HT_TYPE(const_key) key)) {
return HT_FUNC_HASH_KEY(key);
}
#endif // HT_DECL
/*******************\
* Implementations *
\*******************/
// #define HT_IMPL
#ifdef HT_IMPL
struct HT_TYPE(element) {
LIST_INTERFACE(HT_TYPE(element));
HT_TYPE(key) key;
HT_TYPE(value) value;
HT_TYPE(key) key;
hash_t hash;
};
inline
HT_DECLARE_PRIV_FUNC(ht_size_t, get_psl, (ht_size_t zero_idx, ht_size_t actual_idx, ht_size_t num_allocated)) {
// returns the probe sequence length from zero_idx to actual_idx
if(actual_idx < zero_idx) {
return num_allocated - zero_idx + actual_idx;
}
return actual_idx - zero_idx;
}
HT_DECLARE_PRIV_FUNC(ht_size_t, get_element_psl, (HT_BASETYPE *ht, HT_TYPE(element) *e)) {
return HT_PRIV_FUNC(get_psl)(e->hash & ht->hash_mask, e - ht->elements, ht->num_elements_allocated);
}
HT_DECLARE_PRIV_FUNC(void, dump, (HT_BASETYPE *ht)) {
#if 0
log_debug(" -- begin dump of hashtable %p --", (void*)ht);
for(ht_size_t i = 0; i < ht->num_elements_allocated; ++i) {
HT_TYPE(element) *e = ht->elements + i;
if(e->hash & HT_HASH_LIVE_BIT) {
ht_size_t psl = HT_PRIV_FUNC(get_element_psl)(ht, e);
log_debug("%.4i. 0x%08x [%"HT_KEY_FMT"] ==> [%"HT_VALUE_FMT"] PSL: %u", i, e->hash, HT_KEY_PRINTABLE(e->key), HT_VALUE_PRINTABLE(e->value), psl);
assert(psl <= ht->max_psl);
} else {
log_debug("%.4i. 0x%08x -- empty --", i, e->hash);
}
}
log_debug("Max PSL: %u", ht->max_psl);
log_debug(" -- end dump of hashtable %p --", (void*)ht);
#endif
}
HT_DECLARE_PRIV_FUNC(void, begin_write, (HT_BASETYPE *ht)) {
#ifdef HT_THREAD_SAFE
SDL_LockMutex(ht->sync.mutex);
@ -666,12 +738,12 @@ HT_DECLARE_FUNC(void, unlock, (HT_BASETYPE *ht)) {
#endif // HT_THREAD_SAFE
HT_DECLARE_FUNC(void, create, (HT_BASETYPE *ht)) {
size_t size = HT_MIN_SIZE;
ht_size_t size = HT_MIN_SIZE;
ht->table = calloc(size, sizeof(HT_TYPE(element) *));
ht->table_size = size;
ht->elements = calloc(size, sizeof(*ht->elements));
ht->num_elements_allocated = size;
ht->num_elements_occupied = 0;
ht->hash_mask = size - 1;
ht->num_elements = 0;
#ifdef HT_THREAD_SAFE
ht->sync.writing = false;
@ -687,53 +759,84 @@ HT_DECLARE_FUNC(void, destroy, (HT_BASETYPE *ht)) {
SDL_DestroyCond(ht->sync.cond);
SDL_DestroyMutex(ht->sync.mutex);
#endif
free(ht->table);
free(ht->elements);
}
HT_DECLARE_PRIV_FUNC(HT_TYPE(element)*, find_element, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash)) {
HT_TYPE(element) *elems = ht->table[hash & ht->hash_mask];
hash_t hash_mask = ht->hash_mask;
ht_size_t i = hash & hash_mask;
ht_size_t zero_idx = i;
ht_size_t probe_len = 0;
ht_size_t max_probe_len = ht->max_psl;
hash |= HT_HASH_LIVE_BIT;
for(HT_TYPE(element) *e = elems; e; e = e->next) {
if(hash == e->hash && HT_FUNC_KEYS_EQUAL(key, e->key)) {
HT_TYPE(element) *elements = ht->elements;
// log_debug("%p %08x [%"HT_KEY_FMT"]", (void*)ht, hash, HT_KEY_PRINTABLE(key));
for(;;) {
HT_TYPE(element) *e = elements + i;
hash_t e_hash = e->hash;
// log_debug("i=%u :: %08x", i, e_hash);
if(e_hash == hash && HT_FUNC_KEYS_EQUAL(key, e->key)) {
// log_debug("found at %u (probe_len = %u)", i, probe_len);
assert(probe_len == HT_PRIV_FUNC(get_element_psl)(ht, e));
return e;
}
}
return NULL;
if(!(e_hash & HT_HASH_LIVE_BIT)) {
// log_debug("not found (probe_len = %u)", probe_len);
return NULL;
}
ht_size_t e_probe_len = HT_PRIV_FUNC(get_element_psl)(ht, e);
assert(probe_len == HT_PRIV_FUNC(get_psl)(zero_idx, i, ht->num_elements_allocated));
if(probe_len > e_probe_len) {
// log_debug("[%"HT_KEY_FMT"] probe len at %u lower than current (%u < %u), bailing", HT_KEY_PRINTABLE(key), i, e_probe_len, probe_len);
return NULL;
}
if(++probe_len > max_probe_len) {
// log_debug("max PSL reached, bailing (%u)", max_probe_len);
return NULL;
}
i = (i + 1) & hash_mask;
}
}
HT_DECLARE_FUNC(HT_TYPE(value), get, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_TYPE(element) *elem;
HT_DECLARE_FUNC(HT_TYPE(value), get_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) fallback)) {
assert(hash == HT_FUNC_HASH_KEY(key));
HT_TYPE(value) value;
HT_PRIV_FUNC(begin_read)(ht);
elem = HT_PRIV_FUNC(find_element)(ht, key, hash);
value = elem ? elem->value : fallback;
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
value = e ? e->value : fallback;
HT_PRIV_FUNC(end_read)(ht);
return value;
}
#ifdef HT_THREAD_SAFE
HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) fallback)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_TYPE(element) *elem = HT_PRIV_FUNC(find_element)(ht, key, hash);
return elem ? elem->value : fallback;
HT_DECLARE_FUNC(HT_TYPE(value), get_unsafe_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) fallback)) {
assert(hash == HT_FUNC_HASH_KEY(key));
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
return e ? e->value : fallback;
}
#endif // HT_THREAD_SAFE
HT_DECLARE_FUNC(bool, lookup, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_TYPE(element) *elem;
HT_DECLARE_FUNC(bool, lookup_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) *out_value)) {
assert(hash == HT_FUNC_HASH_KEY(key));
bool found = false;
HT_PRIV_FUNC(begin_read)(ht);
elem = HT_PRIV_FUNC(find_element)(ht, key, hash);
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
if(elem != NULL) {
if(e != NULL) {
if(out_value != NULL) {
*out_value = elem->value;
*out_value = e->value;
}
found = true;
@ -745,13 +848,13 @@ HT_DECLARE_FUNC(bool, lookup, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(
}
#ifdef HT_THREAD_SAFE
HT_DECLARE_FUNC(bool, lookup_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) *out_value)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_TYPE(element) *elem = HT_PRIV_FUNC(find_element)(ht, key, hash);
HT_DECLARE_FUNC(bool, lookup_unsafe_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) *out_value)) {
assert(hash == HT_FUNC_HASH_KEY(key));
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
if(elem != NULL) {
if(e != NULL) {
if(out_value != NULL) {
*out_value = elem->value;
*out_value = e->value;
}
return true;
@ -761,19 +864,18 @@ HT_DECLARE_FUNC(bool, lookup_unsafe, (HT_BASETYPE *ht, HT_TYPE(const_key) key, H
}
#endif // HT_THREAD_SAFE
HT_DECLARE_PRIV_FUNC(void*, delete_callback, (List **vlist, List *velem, void *vht)) {
HT_TYPE(element) *elem = (HT_TYPE(element) *) velem;
HT_FUNC_FREE_KEY(elem->key);
free(list_unlink(vlist, velem));
return NULL;
}
HT_DECLARE_PRIV_FUNC(void, unset_all, (HT_BASETYPE *ht)) {
for(size_t i = 0; i < ht->table_size; ++i) {
list_foreach((ht->table + i), HT_PRIV_FUNC(delete_callback), ht);
}
for(ht_size_t i = 0; i < ht->num_elements_allocated; ++i) {
HT_TYPE(element) *e = ht->elements + i;
if(e->hash & HT_HASH_LIVE_BIT) {
HT_FUNC_FREE_KEY(e->key);
e->hash = 0;
ht->num_elements = 0;
if(--ht->num_elements_occupied == 0) {
break;
}
}
}
}
HT_DECLARE_FUNC(void, unset_all, (HT_BASETYPE *ht)) {
@ -782,19 +884,36 @@ HT_DECLARE_FUNC(void, unset_all, (HT_BASETYPE *ht)) {
HT_PRIV_FUNC(end_write)(ht);
}
HT_DECLARE_PRIV_FUNC(void, unset_with_backshift, (HT_BASETYPE *ht, HT_TYPE(element) *e)) {
HT_TYPE(element) *elements = ht->elements;
hash_t hash_mask = ht->hash_mask;
HT_FUNC_FREE_KEY(e->key);
--ht->num_elements_occupied;
ht_size_t idx = e - elements;
for(;;) {
idx = (idx + 1) & hash_mask;
HT_TYPE(element) *next_e = elements + idx;
if(HT_PRIV_FUNC(get_element_psl)(ht, next_e) < 1) {
e->hash = 0;
return;
}
*e = *next_e;
e = next_e;
}
}
HT_DECLARE_FUNC(bool, unset, (HT_BASETYPE *ht, HT_TYPE(const_key) key)) {
HT_TYPE(element) *elem;
hash_t hash = HT_FUNC_HASH_KEY(key);
bool success = false;
HT_PRIV_FUNC(begin_write)(ht);
elem = HT_PRIV_FUNC(find_element)(ht, key, hash);
if(elem) {
HT_TYPE(element) **elist = ht->table + (hash & ht->hash_mask);
HT_FUNC_FREE_KEY(elem->key);
free(list_unlink(elist, elem));
--ht->num_elements;
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
if(e != NULL) {
HT_PRIV_FUNC(unset_with_backshift)(ht, e);
success = true;
}
HT_PRIV_FUNC(end_write)(ht);
@ -807,23 +926,68 @@ HT_DECLARE_FUNC(void, unset_list, (HT_BASETYPE *ht, const HT_TYPE(key_list) *key
for(const HT_TYPE(key_list) *i = key_list; i; i = i->next) {
hash_t hash = HT_FUNC_HASH_KEY(i->key);
HT_TYPE(element) *elem = HT_PRIV_FUNC(find_element)(ht, i->key, hash);
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, i->key, hash);
if(elem) {
HT_TYPE(element) **elist = ht->table + (hash & ht->hash_mask);
HT_FUNC_FREE_KEY(elem->key);
free(list_unlink(elist, elem));
--ht->num_elements;
if(e != NULL) {
HT_PRIV_FUNC(unset_with_backshift)(ht, e);
}
}
HT_PRIV_FUNC(end_write)(ht);
}
HT_DECLARE_PRIV_FUNC(HT_TYPE(element)*, insert, (
HT_TYPE(element) *insertion_elem,
HT_TYPE(element) *elements,
hash_t hash_mask,
ht_size_t *p_max_psl
)) {
HT_TYPE(element) *e, *target = NULL, temp_elem;
ht_size_t idx = insertion_elem->hash & hash_mask;
for(;;) {
e = elements + idx;
if(!(e->hash & HT_HASH_LIVE_BIT)) {
*e = *insertion_elem;
if(target == NULL) {
target = e;
}
ht_size_t psl = HT_PRIV_FUNC(get_psl)(e->hash & hash_mask, idx, hash_mask + 1);
if(*p_max_psl < psl) {
*p_max_psl = psl;
}
break;
}
ht_size_t e_probe_len = HT_PRIV_FUNC(get_psl)(e->hash & hash_mask, idx, hash_mask + 1);
ht_size_t i_probe_len = HT_PRIV_FUNC(get_psl)(insertion_elem->hash & hash_mask, idx, hash_mask + 1);
if(e_probe_len < i_probe_len) {
// log_debug("SWAP %u (%u < %u)", idx, e_probe_len, i_probe_len);
temp_elem = *e;
*e = *insertion_elem;
if(target == NULL) {
target = e;
}
*insertion_elem = temp_elem;
ht_size_t psl = HT_PRIV_FUNC(get_psl)(e->hash & hash_mask, idx, hash_mask + 1);
if(*p_max_psl < psl) {
*p_max_psl = psl;
}
}
idx = (idx + 1) & hash_mask;
}
return target;
}
HT_DECLARE_PRIV_FUNC(bool, set, (
HT_BASETYPE *ht,
HT_TYPE(element) **table,
size_t hash_mask,
hash_t hash,
HT_TYPE(const_key) key,
HT_TYPE(value) value,
@ -831,24 +995,35 @@ HT_DECLARE_PRIV_FUNC(bool, set, (
bool allow_overwrite,
HT_TYPE(value) *out_value
)) {
size_t idx = hash & hash_mask;
HT_TYPE(element) **elems = table + idx, *elem = NULL;
for(HT_TYPE(element) *e = *elems; e; e = e->next) {
if(hash == e->hash && HT_FUNC_KEYS_EQUAL(key, e->key)) {
if(!allow_overwrite) {
if(out_value != NULL) {
*out_value = e->value;
}
return false;
HT_TYPE(element) *e = HT_PRIV_FUNC(find_element)(ht, key, hash);
if(e) {
if(!allow_overwrite) {
if(out_value != NULL) {
*out_value = e->value;
}
elem = e;
break;
return false;
}
if(transform_value != NULL) {
value = transform_value(value);
}
if(out_value != NULL) {
*out_value = value;
}
e->value = value;
// log_debug("[%"HT_KEY_FMT"] ==> [%"HT_VALUE_FMT"] (replace)", HT_KEY_PRINTABLE(key), HT_VALUE_PRINTABLE(value));
return true;
}
// log_debug("[%"HT_KEY_FMT"] ==> [%"HT_VALUE_FMT"]", HT_KEY_PRINTABLE(key), HT_VALUE_PRINTABLE(value));
// log_debug(" *** BEFORE ***");
HT_PRIV_FUNC(dump)(ht);
if(transform_value != NULL) {
value = transform_value(value);
}
@ -857,91 +1032,98 @@ HT_DECLARE_PRIV_FUNC(bool, set, (
*out_value = value;
}
if(elem == NULL) {
elem = malloc(sizeof(*elem));
HT_FUNC_COPY_KEY(&elem->key, key);
elem->hash = hash; // HT_FUNC_HASH_KEY(elem->key);
elem->value = value;
list_push(elems, elem);
++ht->num_elements;
return true;
}
HT_TYPE(element) insertion_elem;
insertion_elem.value = value;
HT_FUNC_COPY_KEY(&insertion_elem.key, key);
insertion_elem.hash = hash | HT_HASH_LIVE_BIT;
e = HT_PRIV_FUNC(insert)(&insertion_elem, ht->elements, ht->hash_mask, &ht->max_psl);
assume(e != NULL);
elem->value = value;
return false;
++ht->num_elements_occupied;
// log_debug(" *** AFTER ***");
HT_PRIV_FUNC(dump)(ht);
// log_debug(" *** END SET ***");
assert(HT_PRIV_FUNC(find_element)(ht, key, hash) == e);
assert(e->value == value);
return true;
}
HT_DECLARE_PRIV_FUNC(void, check_elem_count, (HT_BASETYPE *ht)) {
#ifdef DEBUG
size_t num_elements = 0;
for(size_t i = 0; i < ht->table_size; ++i) {
for(HT_TYPE(element) *e = ht->table[i]; e; e = e->next) {
ht_size_t num_elements = 0;
for(ht_size_t i = 0; i < ht->num_elements_allocated; ++i) {
if(ht->elements[i].hash & HT_HASH_LIVE_BIT) {
++num_elements;
}
}
assert(num_elements == ht->num_elements);
assert(num_elements == ht->num_elements_occupied);
#endif // DEBUG
}
HT_DECLARE_PRIV_FUNC(void, resize, (HT_BASETYPE *ht, size_t new_size)) {
assert(new_size != ht->table_size);
HT_TYPE(element) **new_table = calloc(new_size, sizeof(*new_table));
size_t new_hash_mask = new_size - 1;
size_t num_elements = ht->num_elements;
assert(new_size != ht->num_elements_allocated);
HT_TYPE(element) *old_elements = ht->elements;
ht_size_t old_size = ht->num_elements_allocated;
HT_PRIV_FUNC(check_elem_count)(ht);
for(size_t i = 0; i < ht->table_size; ++i) {
for(HT_TYPE(element) *e = ht->table[i]; e; e = e->next) {
HT_PRIV_FUNC(set)(ht, new_table, new_hash_mask, e->hash, e->key, e->value, NULL, true, NULL);
HT_TYPE(element) *new_elements = calloc(new_size, sizeof(*ht->elements));
ht->max_psl = 0;
for(ht_size_t i = 0; i < old_size; ++i) {
HT_TYPE(element) *e = old_elements + i;
if(e->hash & HT_HASH_LIVE_BIT) {
HT_PRIV_FUNC(insert)(e, new_elements, new_size - 1, &ht->max_psl);
}
}
HT_PRIV_FUNC(unset_all)(ht);
ht->num_elements = num_elements;
ht->elements = new_elements;
ht->num_elements_allocated = new_size;
ht->hash_mask = new_size - 1;
free(ht->table);
ht->table = new_table;
free(old_elements);
/*
log_debug(
"Resized hashtable at %p: %"PRIuMAX" -> %"PRIuMAX"",
(void*)ht, (uintmax_t)ht->table_size, (uintmax_t)new_size
(void*)ht, (uintmax_t)old_size, (uintmax_t)new_size
);
*/
ht->table_size = new_size;
ht->hash_mask = new_hash_mask;
HT_PRIV_FUNC(dump)(ht);
HT_PRIV_FUNC(check_elem_count)(ht);
}
HT_DECLARE_PRIV_FUNC(bool, maybe_resize, (HT_BASETYPE *ht)) {
if(
ht->num_elements_occupied == ht->num_elements_allocated || ht->max_psl > 5
) {
HT_PRIV_FUNC(resize)(ht, ht->num_elements_allocated * 2);
return true;
}
return false;
}
HT_DECLARE_FUNC(bool, set, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) value)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_PRIV_FUNC(begin_write)(ht);
bool result = HT_PRIV_FUNC(set)(ht, ht->table, ht->hash_mask, hash, key, value, NULL, true, NULL);
if(ht->num_elements == ht->table_size) {
HT_PRIV_FUNC(resize)(ht, ht->table_size * 2);
assert(ht->num_elements == ht->table_size / 2);
}
bool result = HT_PRIV_FUNC(set)(ht, hash, key, value, NULL, true, NULL);
HT_PRIV_FUNC(maybe_resize)(ht);
HT_PRIV_FUNC(end_write)(ht);
return result;
}
HT_DECLARE_FUNC(bool, try_set, (HT_BASETYPE *ht, HT_TYPE(const_key) key, HT_TYPE(value) value, HT_TYPE(value) (*value_transform)(HT_TYPE(value)), HT_TYPE(value) *out_value)) {
hash_t hash = HT_FUNC_HASH_KEY(key);
HT_DECLARE_FUNC(bool, try_set_prehashed, (HT_BASETYPE *ht, HT_TYPE(const_key) key, hash_t hash, HT_TYPE(value) value, HT_TYPE(value) (*value_transform)(HT_TYPE(value)), HT_TYPE(value) *out_value)) {
assert(hash == HT_FUNC_HASH_KEY(key));
HT_PRIV_FUNC(begin_write)(ht);
bool result = HT_PRIV_FUNC(set)(ht, ht->table, ht->hash_mask, hash, key, value, value_transform, false, out_value);
if(ht->num_elements == ht->table_size) {
HT_PRIV_FUNC(resize)(ht, ht->table_size * 2);
assert(ht->num_elements == ht->table_size / 2);
}
bool result = HT_PRIV_FUNC(set)(ht, hash, key, value, value_transform, false, out_value);
HT_PRIV_FUNC(maybe_resize)(ht);
HT_PRIV_FUNC(end_write)(ht);
return result;
}
@ -951,50 +1133,50 @@ HT_DECLARE_FUNC(void*, foreach, (HT_BASETYPE *ht, HT_TYPE(foreach_callback) call
HT_PRIV_FUNC(begin_read)(ht);
for(size_t i = 0; i < ht->table_size; ++i) {
for(HT_TYPE(element) *e = ht->table[i]; e; e = e->next) {
ret = callback(e->key, e->value, arg);
if(ret != NULL) {
goto end;
for(ht_size_t i = 0, remaining = ht->num_elements_occupied; remaining; ++i) {
HT_TYPE(element) *e = ht->elements + i;
if(e->hash & HT_HASH_LIVE_BIT) {
if((ret = callback(e->key, e->value, arg))) {
break;
}
--remaining;
}
}
end:
HT_PRIV_FUNC(end_read)(ht);
return ret;
}
HT_DECLARE_PRIV_FUNC(void, iter_advance, (HT_BASETYPE *ht, HT_TYPE(iter) *iter)) {
while(!iter->private.elem) {
if(++iter->private.bucketnum == ht->table_size) {
iter->has_data = false;
return;
}
iter->private.elem = ht->table[iter->private.bucketnum];
}
iter->key = iter->private.elem->key;
iter->value = iter->private.elem->value;
}
HT_DECLARE_FUNC(void, iter_begin, (HT_BASETYPE *ht, HT_TYPE(iter) *iter)) {
HT_PRIV_FUNC(begin_read)(ht);
memset(iter, 0, sizeof(*iter));
iter->hashtable = ht;
iter->private.elem = *ht->table;
iter->has_data = true;
HT_PRIV_FUNC(iter_advance)(ht, iter);
iter->private.remaining = ht->num_elements_occupied;
iter->has_data = iter->private.remaining;
HT_FUNC(iter_next)(iter);
}
HT_DECLARE_FUNC(void, iter_next, (HT_TYPE(iter) *iter)) {
if(!iter->has_data) {
HT_BASETYPE *ht = iter->hashtable;
if(!iter->private.remaining) {
iter->has_data = false;
return;
}
iter->private.elem = iter->private.elem->next;
HT_PRIV_FUNC(iter_advance)(iter->hashtable, iter);
for(;;) {
ht_size_t i = iter->private.i++;
assert(i < ht->num_elements_allocated);
HT_TYPE(element) *e = ht->elements + i;
if(e->hash & HT_HASH_LIVE_BIT) {
--iter->private.remaining;
iter->key = e->key;
iter->value = e->value;
return;
}
}
return;
}
@ -1040,3 +1222,7 @@ HT_DECLARE_FUNC(void, iter_end, (HT_TYPE(iter) *iter)) {
#undef _HT_NAME_INNER2
#undef _HT_PRIV_NAME_INNER1
#undef _HT_PRIV_NAME_INNER2
#undef HT_KEY_FMT
#undef HT_KEY_PRINTABLE
#undef HT_VALUE_FMT
#undef HT_VALUE_PRINTABLE

View file

@ -20,8 +20,12 @@
#define HT_VALUE_TYPE void*
#define HT_FUNC_FREE_KEY(key) free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(0, key)
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT "p"
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#define HT_VALUE_CONST
#include "hashtable_incproxy.inc.h"
@ -36,8 +40,12 @@
#define HT_VALUE_TYPE void*
#define HT_FUNC_FREE_KEY(key) free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(0, key)
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT "p"
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#define HT_VALUE_CONST
#define HT_THREAD_SAFE
@ -53,8 +61,12 @@
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_FREE_KEY(key) free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(0, key)
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#include "hashtable_incproxy.inc.h"
@ -68,8 +80,12 @@
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_FREE_KEY(key) free(key)
#define HT_FUNC_KEYS_EQUAL(key1, key2) (!strcmp(key1, key2))
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(0, key)
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_string(key)
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = strdup(src))
#define HT_KEY_FMT "s"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#define HT_THREAD_SAFE
#include "hashtable_incproxy.inc.h"
@ -83,6 +99,10 @@
#define HT_KEY_TYPE int64_t
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_uint64((uint64_t)(key))
#define HT_KEY_FMT PRIi64
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#include "hashtable_incproxy.inc.h"
/*
@ -94,6 +114,10 @@
#define HT_KEY_TYPE int64_t
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_uint64((uint64_t)(key))
#define HT_KEY_FMT PRIi64
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_THREAD_SAFE
#include "hashtable_incproxy.inc.h"
@ -107,6 +131,10 @@
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_uint64((uintptr_t)(key))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = (void*)(src))
#define HT_KEY_FMT "p"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#include "hashtable_incproxy.inc.h"
@ -120,6 +148,10 @@
#define HT_VALUE_TYPE int64_t
#define HT_FUNC_HASH_KEY(key) htutil_hashfunc_uint64((uintptr_t)(key))
#define HT_FUNC_COPY_KEY(dst, src) (*(dst) = (void*)(src))
#define HT_KEY_FMT "p"
#define HT_KEY_PRINTABLE(key) (key)
#define HT_VALUE_FMT PRIi64
#define HT_VALUE_PRINTABLE(val) (val)
#define HT_KEY_CONST
#define HT_THREAD_SAFE
#include "hashtable_incproxy.inc.h"
@ -177,21 +209,36 @@
#define ht_get(ht, key, default) \
_HT_GENERIC(*(ht), get) (ht, key, default)
#define ht_get_prehashed(ht, key, hash, default) \
_HT_GENERIC(*(ht), get_prehashed) (ht, key, hash, default)
#define ht_get_unsafe(ht, key, default) \
_HT_GENERIC_TS(*(ht), get_unsafe) (ht, key, default)
#define ht_get_unsafe_prehashed(ht, key, hash, default) \
_HT_GENERIC_TS(*(ht), get_unsafe_prehashed) (ht, key, hash, default)
#define ht_lookup(ht, key, out_value) \
_HT_GENERIC(*(ht), lookup) (ht, key, out_value)
#define ht_lookup_prehashed(ht, key, hash, out_value) \
_HT_GENERIC(*(ht), lookup_prehashed) (ht, key, hash, out_value)
#define ht_lookup_unsafe(ht, key, out_value) \
_HT_GENERIC_TS(*(ht), lookup_unsafe) (ht, key, out_value)
#define ht_lookup_unsafe_prehashed(ht, key, hash, out_value) \
_HT_GENERIC_TS(*(ht), lookup_unsafe_prehashed) (ht, key, hash, out_value)
#define ht_set(ht, key, value) \
_HT_GENERIC(*(ht), set) (ht, key, value)
#define ht_try_set(ht, key, value, value_transform, out_value) \
_HT_GENERIC(*(ht), try_set) (ht, key, value, value_transform, out_value)
#define ht_try_set_prehashed(ht, key, hash, value, value_transform, out_value) \
_HT_GENERIC(*(ht), try_set_prehashed) (ht, key, hash, value, value_transform, out_value)
#define ht_unset(ht, key) \
_HT_GENERIC(*(ht), unset) (ht, key)

View file

@ -212,7 +212,6 @@ int main(int argc, char **argv) {
MainContext *ctx = calloc(1, sizeof(*ctx));
setlocale(LC_ALL, "C");
htutil_init();
init_log();
stage_init_array(); // cli_args depends on this

View file

@ -52,14 +52,6 @@ if host_machine.system() == 'windows'
config.set('__USE_MINGW_ANSI_STDIO', 1)
endif
use_intel_intrin = get_option('intel_intrin') and cc.links('''
#include <immintrin.h>
__attribute__((target("sse4.2")))
int main(int argc, char **argv) {
return _mm_crc32_u8(argc, 42);
}
''', name : 'SSE 4.2 intrinsics test')
taisei_src = files(
'aniplayer.c',
'boss.c',
@ -123,8 +115,6 @@ if host_machine.system() == 'nx'
)
endif
sse42_src = []
subdir('audio')
subdir('dialog')
subdir('eventloop')
@ -137,22 +127,6 @@ subdir('stages')
subdir('util')
subdir('vfs')
if use_intel_intrin
sse42_lib = static_library(
'taisei_sse42',
sse42_src,
c_args : taisei_c_args + ['-msse4.2'],
install : false
)
sse42_dep = declare_dependency(link_with: sse42_lib)
taisei_deps += sse42_dep
config.set('TAISEI_BUILDCONF_USE_SSE42', true)
message('SSE 4.2 intrinsics will be used')
elif get_option('intel_intrin')
config.set('TAISEI_BUILDCONF_USE_SSE42', false)
warning('SSE 4.2 intrinsics can not be used')
endif
configure_file(configuration : config, output : 'build_config.h')
taisei_src += [

View file

@ -374,8 +374,8 @@ ShaderProgram* r_shader_current(void) {
return B.shader_current();
}
Uniform* r_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
return B.shader_uniform(prog, uniform_name);
Uniform* _r_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash) {
return B.shader_uniform(prog, uniform_name, uniform_name_hash);
}
UniformType r_uniform_type(Uniform *uniform) {
@ -911,7 +911,7 @@ void _r_uniform_sampler_ptr(const char *uniform, Texture *tex) {
void _r_uniform_ptr_sampler(Uniform *uniform, const char *tex) {
ASSERT_UTYPE(uniform, UNIFORM_SAMPLER);
if(uniform) B.uniform(uniform, 0, 1, (Texture*[]) { get_tex(tex) });
if(uniform) B.uniform(uniform, 0, 1, (Texture*[]) { r_texture_get(tex) });
}
void _r_uniform_sampler(const char *uniform, const char *tex) {
@ -934,7 +934,7 @@ void _r_uniform_ptr_sampler_array(Uniform *uniform, uint offset, uint count, con
const char **vptr = values;
do {
*aptr++ = get_tex(*vptr++);
*aptr++ = r_texture_get(*vptr++);
} while(aptr < aend);
B.uniform(uniform, 0, 1, arr);

View file

@ -480,7 +480,7 @@ const char* r_shader_program_get_debug_label(ShaderProgram *prog) attr_nonnull(1
void r_shader_ptr(ShaderProgram *prog) attr_nonnull(1);
ShaderProgram* r_shader_current(void) attr_returns_nonnull;
Uniform* r_shader_uniform(ShaderProgram *prog, const char *uniform_name) attr_nonnull(1, 2);
Uniform* _r_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash) attr_nonnull(1, 2);
UniformType r_uniform_type(Uniform *uniform);
void r_uniform_ptr_unsafe(Uniform *uniform, uint offset, uint count, void *data);
@ -826,6 +826,11 @@ Texture* r_texture_get(const char *name) {
return get_resource_data(RES_TEXTURE, name, RESF_DEFAULT | RESF_UNSAFE);
}
attr_deprecated("Use r_texture_get")
INLINE Texture *get_tex(const char *name) {
return r_texture_get(name);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
@ -858,6 +863,11 @@ void r_shader(const char *prog) {
r_shader_ptr(r_shader_get(prog));
}
INLINE
Uniform* r_shader_uniform(ShaderProgram *prog, const char *name) {
return _r_shader_uniform(r_shader_current(), name, ht_str2ptr_hash(name));
}
INLINE
Uniform* r_shader_current_uniform(const char *name) {
return r_shader_uniform(r_shader_current(), name);

View file

@ -55,7 +55,7 @@ typedef struct RendererFuncs {
void (*shader)(ShaderProgram *prog);
ShaderProgram* (*shader_current)(void);
Uniform* (*shader_uniform)(ShaderProgram *prog, const char *uniform_name);
Uniform* (*shader_uniform)(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash);
void (*uniform)(Uniform *uniform, uint offset, uint count, const void *data);
UniformType (*uniform_type)(Uniform *uniform);

View file

@ -16,8 +16,8 @@
static Uniform *sampler_uniforms;
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
return ht_get(&prog->uniforms, uniform_name, NULL);
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash) {
return ht_get_prehashed(&prog->uniforms, uniform_name, uniform_name_hash, NULL);
}
UniformType gl33_uniform_type(Uniform *uniform) {

View file

@ -54,7 +54,7 @@ void gl33_shader_program_destroy(ShaderProgram *prog);
void gl33_shader_program_set_debug_label(ShaderProgram *prog, const char *label);
const char* gl33_shader_program_get_debug_label(ShaderProgram *prog);
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name);
Uniform *gl33_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash);
UniformType gl33_uniform_type(Uniform *uniform);
void gl33_uniform(Uniform *uniform, uint offset, uint count, const void *data);
void gl33_unref_texture_from_samplers(Texture *tex);

View file

@ -55,7 +55,7 @@ static const char* null_shader_program_get_debug_label(ShaderProgram *prog) { re
static void null_shader(ShaderProgram *prog) { }
static ShaderProgram* null_shader_current(void) { return (void*)&placeholder; }
static Uniform* null_shader_uniform(ShaderProgram *prog, const char *uniform_name) {
static Uniform* null_shader_uniform(ShaderProgram *prog, const char *uniform_name, hash_t uniform_name_hash) {
return NULL;
}

View file

@ -956,10 +956,6 @@ static inline void adjust_xpos(Font *font, const uint32_t *ucs4text, Alignment a
}
}
Font* get_font(const char *font) {
return get_resource_data(RES_FONT, font, RESF_DEFAULT);
}
ShaderProgram* text_get_default_shader(void) {
return globals.default_shader;
}

View file

@ -76,8 +76,9 @@ typedef struct TextParams {
Alignment align;
} TextParams;
Font* get_font(const char *font)
attr_nonnull(1);
INLINE Font *get_font(const char *font) {
return get_resource_data(RES_FONT, font, RESF_DEFAULT);
}
ShaderProgram* text_get_default_shader(void)
attr_returns_nonnull;

View file

@ -98,10 +98,10 @@ static void* valfunc_begin_load_resource(void* arg) {
return ires;
}
static bool try_begin_load_resource(ResourceType type, const char *name, InternalResource **out_ires) {
static bool try_begin_load_resource(ResourceType type, const char *name, hash_t hash, InternalResource **out_ires) {
ResourceHandler *handler = get_handler(type);
struct valfunc_arg arg = { type };
return ht_try_set(&handler->private.mapping, name, &arg, valfunc_begin_load_resource, (void**)out_ires);
return ht_try_set_prehashed(&handler->private.mapping, name, hash, &arg, valfunc_begin_load_resource, (void**)out_ires);
}
static void load_resource_finish(InternalResource *ires, void *opaque, const char *path, const char *name, char *allocated_path, char *allocated_name, ResourceFlags flags);
@ -326,21 +326,21 @@ static void load_resource_finish(InternalResource *ires, void *opaque, const cha
free(allocated_name);
}
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags) {
Resource *_get_resource(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) {
InternalResource *ires;
Resource *res;
if(flags & RESF_UNSAFE) {
// FIXME: I'm not sure we actually need this functionality.
ires = ht_get_unsafe(&get_handler(type)->private.mapping, name, NULL);
ires = ht_get_unsafe_prehashed(&get_handler(type)->private.mapping, name, hash, NULL);
if(ires != NULL && ires->status == RES_STATUS_LOADED) {
return &ires->res;
}
}
if(try_begin_load_resource(type, name, &ires)) {
if(try_begin_load_resource(type, name, hash, &ires)) {
SDL_LockMutex(ires->mutex);
if(!(flags & RESF_PRELOAD)) {
@ -379,8 +379,8 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
}
}
void* get_resource_data(ResourceType type, const char *name, ResourceFlags flags) {
Resource *res = get_resource(type, name, flags);
void *_get_resource_data(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) {
Resource *res = _get_resource(type, name, hash, flags);
if(res) {
return res->data;
@ -395,7 +395,7 @@ void preload_resource(ResourceType type, const char *name, ResourceFlags flags)
InternalResource *ires;
if(try_begin_load_resource(type, name, &ires)) {
if(try_begin_load_resource(type, name, ht_str2ptr_hash(name), &ires)) {
SDL_LockMutex(ires->mutex);
load_resource(ires, NULL, name, flags | RESF_PRELOAD, !env_get("TAISEI_NOASYNC", false));
SDL_UnlockMutex(ires->mutex);

View file

@ -106,14 +106,26 @@ void init_resources(void);
void load_resources(void);
void free_resources(bool all);
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags);
void* get_resource_data(ResourceType type, const char *name, ResourceFlags flags);
Resource *_get_resource(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) attr_nonnull_all;
void *_get_resource_data(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) attr_nonnull_all;
attr_nonnull_all
INLINE Resource *get_resource(ResourceType type, const char *name, ResourceFlags flags) {
return _get_resource(type, name, ht_str2ptr_hash(name), flags);
}
attr_nonnull_all
INLINE void *get_resource_data(ResourceType type, const char *name, ResourceFlags flags) {
return _get_resource_data(type, name, ht_str2ptr_hash(name), flags);
}
void preload_resource(ResourceType type, const char *name, ResourceFlags flags);
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) attr_sentinel;
void* resource_for_each(ResourceType type, void* (*callback)(const char *name, Resource *res, void *arg), void *arg);
void *resource_for_each(ResourceType type, void *(*callback)(const char *name, Resource *res, void *arg), void *arg);
void resource_util_strip_ext(char *path);
char* resource_util_basename(const char *prefix, const char *path);
const char* resource_util_filename(const char *path);
char *resource_util_basename(const char *prefix, const char *path);
const char *resource_util_filename(const char *path);
#endif // IGUARD_resource_resource_h

View file

@ -150,11 +150,7 @@ void* load_sprite_end(void *opaque, const char *path, uint flags) {
return spr;
}
Sprite* get_sprite(const char *name) {
return get_resource(RES_SPRITE, name, RESF_DEFAULT | RESF_UNSAFE)->data;
}
Sprite* prefix_get_sprite(const char *name, const char *prefix) {
Sprite *prefix_get_sprite(const char *name, const char *prefix) {
uint plen = strlen(prefix);
char buf[plen + strlen(name) + 1];
strcpy(buf, prefix);

View file

@ -58,16 +58,19 @@ INLINE FloatOffset sprite_padded_offset(const Sprite *restrict spr) {
return o;
}
char* sprite_path(const char *name);
void* load_sprite_begin(const char *path, uint flags);
void* load_sprite_end(void *opaque, const char *path, uint flags);
char *sprite_path(const char *name);
void *load_sprite_begin(const char *path, uint flags);
void *load_sprite_end(void *opaque, const char *path, uint flags);
bool check_sprite_path(const char *path);
void draw_sprite(float x, float y, const char *name);
void draw_sprite_p(float x, float y, Sprite *spr);
Sprite* get_sprite(const char *name);
Sprite* prefix_get_sprite(const char *name, const char *prefix);
INLINE Sprite *get_sprite(const char *name) {
return get_resource_data(RES_SPRITE, name, RESF_DEFAULT | RESF_UNSAFE);
}
Sprite *prefix_get_sprite(const char *name, const char *prefix);
extern ResourceHandler sprite_res_handler;

View file

@ -497,19 +497,6 @@ static void *load_texture_end(void *opaque, const char *path, uint flags) {
return texture;
}
Texture *get_tex(const char *name) {
return r_texture_get(name);
}
Texture *prefix_get_tex(const char *name, const char *prefix) {
uint plen = strlen(prefix);
char buf[plen + strlen(name) + 1];
strcpy(buf, prefix);
strcpy(buf + plen, name);
Texture *tex = get_tex(buf);
return tex;
}
static void free_texture(Texture *tex) {
r_texture_destroy(tex);
}

View file

@ -31,9 +31,6 @@ void fill_screen_p(Texture *tex);
void loop_tex_line_p(cmplx a, cmplx b, float w, float t, Texture *texture);
void loop_tex_line(cmplx a, cmplx b, float w, float t, const char *texture);
Texture *get_tex(const char *name);
Texture *prefix_get_tex(const char *name, const char *prefix);
extern ResourceHandler texture_res_handler;
#define TEX_PATH_PREFIX "res/gfx/"

View file

@ -22,7 +22,6 @@
#include "util/kvparser.h"
#include "util/miscmath.h"
// #include "util/pngcruft.h"
#include "util/sse42.h"
#include "util/stringops.h"
// FIXME: might not be the best place for these

View file

@ -268,7 +268,7 @@ typedef cmplx64 cmplx;
#define attr_designated_init
#endif
#define INLINE static inline attr_must_inline __attribute__((gnu_inline, artificial))
#define INLINE static inline attr_must_inline __attribute__((gnu_inline))
#ifdef USE_GNU_EXTENSIONS
#define ASSUME_ALIGNED(expr, alignment) (__extension__ ({ \

View file

@ -23,10 +23,6 @@ util_opus_src = files(
'opuscruft.c',
)
sse42_src += files(
'sse42.c',
)
if is_developer_build
util_src += files('debug.c')
endif

View file

@ -1,23 +0,0 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include <immintrin.h>
#include "sse42.h"
uint32_t crc32str_sse42(uint32_t crc, const char *str) {
const uint8_t *s = (const uint8_t*)str;
while(*s) {
crc = _mm_crc32_u8(crc, *s++);
}
return crc;
}

View file

@ -1,20 +0,0 @@
/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#ifndef IGUARD_util_sse42_h
#define IGUARD_util_sse42_h
#include "taisei.h"
#ifdef TAISEI_BUILDCONF_USE_SSE42
uint32_t crc32str_sse42(uint32_t crc, const char *str) attr_hot attr_pure;
#else
#define crc32str_sse42 crc32str
#endif
#endif // IGUARD_util_sse42_h

View file

@ -247,63 +247,6 @@ char* strtok_r(char *str, const char *delim, char **nextp) {
return ret;
}
static uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t crc32str(uint32_t crc, const char *str) {
const uint8_t *p = (uint8_t*)str;
crc = crc ^ ~0U;
while(*p) {
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
}
return crc ^ ~0U;
}
size_t filename_timestamp(char *buf, size_t buf_size, SystemTime systime) {
assert(buf_size >= FILENAME_TIMESTAMP_MIN_BUF_SIZE);

View file

@ -65,8 +65,6 @@ char* ucs4_to_utf8_alloc(const uint32_t *ucs4) attr_nonnull(1) attr_returns_allo
uint32_t utf8_getch(const char **src) attr_nonnull(1);
uint32_t crc32str(uint32_t crc, const char *str);
void format_huge_num(uint digits, uint64_t num, size_t bufsize, char buf[bufsize]);
void hexdigest(uint8_t *input, size_t input_size, char *output, size_t output_size);