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:
parent
15593ab207
commit
0fdea86be1
28 changed files with 472 additions and 375 deletions
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 += [
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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/"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ ({ \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue