Merge branch 'master' into rebalance

This commit is contained in:
Andrei "Akari" Alexeyev 2017-03-29 15:41:31 +03:00
commit 02469cf722
13 changed files with 296 additions and 100 deletions

View file

@ -5,7 +5,7 @@ varying vec4 TexCoord0;
void main(void) {
gl_Position = ftransform();
TexCoord0 = gl_TextureMatrix[0] * gl_MultiTexCoord0;
TexCoord0 = gl_MultiTexCoord0;
}
%% -- FRAG
@ -25,7 +25,7 @@ void main(void) {
pos += (f*0.05*sin(10.0*(length(f)+t)))*(1.0-t);
pos = clamp(pos,0.0,1.0);
vec4 texel = texture2D(tex, pos);
vec4 texel = texture2D(tex, (gl_TextureMatrix[0]*vec4(pos,0.0,1.0)).xy);
texel.a *= clamp((texture2D(trans, pos).r+0.5)*2.5*t-0.5, 0.0, 1.0);
gl_FragColor = vec4(color,1.0)*texel;

View file

@ -127,7 +127,7 @@ endif()
message(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}")
set(DEBUG_FLAGS "-ggdb -fsanitize=undefined -fno-sanitize-recover=undefined -fsanitize-recover=float-divide-by-zero -fno-omit-frame-pointer")
set(DEBUG_FLAGS "-ggdb -fsanitize=undefined -fsanitize-recover=float-divide-by-zero -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG ${DEBUG_FLAGS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${DEBUG_FLAGS}")

View file

@ -32,6 +32,8 @@ struct Hashtable {
HTFreeFunc free_func;
SDL_atomic_t cur_operation;
SDL_atomic_t num_operations;
size_t num_elements;
bool dynamic_size;
};
enum {
@ -50,12 +52,38 @@ typedef struct HashtableIterator {
* Generic functions
*/
Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func, HTCopyFunc copy_func, HTFreeFunc free_func) {
assert(size > 0);
static size_t constraint_size(size_t size) {
if(size < HT_MIN_SIZE)
return HT_MIN_SIZE;
if(size > HT_MAX_SIZE)
return HT_MAX_SIZE;
return size;
}
Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func, HTCopyFunc copy_func, HTFreeFunc free_func) {
Hashtable *ht = malloc(sizeof(Hashtable));
if(size == HT_DYNAMIC_SIZE) {
size = constraint_size(0);
ht->dynamic_size = true;
} else {
size = constraint_size(size);
ht->dynamic_size = false;
}
if(!cmp_func) {
cmp_func = hashtable_cmpfunc_ptr;
}
if(!copy_func) {
copy_func = hashtable_copyfunc_ptr;
}
ht->table = calloc(size, sizeof(HashtableElement*));
ht->table_size = size;
ht->num_elements = 0;
ht->cmp_func = cmp_func;
ht->hash_func = hash_func;
ht->copy_func = copy_func;
@ -68,6 +96,7 @@ Hashtable* hashtable_new(size_t size, HTCmpFunc cmp_func, HTHashFunc hash_func,
return ht;
}
static bool hashtable_try_enter_state(Hashtable *ht, int state, bool mutex) {
SDL_atomic_t *ptr = &ht->cur_operation;
@ -109,15 +138,18 @@ static void hashtable_delete_callback(void **vlist, void *velem, void *vht) {
delete_element(vlist, velem);
}
void hashtable_unset_all(Hashtable *ht) {
assert(ht != NULL);
hashtable_enter_state(ht, HT_OP_WRITE, true);
static void hashtable_unset_all_internal(Hashtable *ht) {
for(size_t i = 0; i < ht->table_size; ++i) {
delete_all_elements_witharg((void**)(ht->table + i), hashtable_delete_callback, ht);
}
ht->num_elements = 0;
}
void hashtable_unset_all(Hashtable *ht) {
assert(ht != NULL);
hashtable_enter_state(ht, HT_OP_WRITE, true);
hashtable_unset_all_internal(ht);
hashtable_idle_state(ht);
}
@ -132,14 +164,6 @@ void hashtable_free(Hashtable *ht) {
free(ht);
}
static bool hashtable_compare(Hashtable *ht, void *key1, void *key2) {
if(ht->cmp_func) {
return ht->cmp_func(key1, key2);
}
return (key1 == key2);
}
void* hashtable_get(Hashtable *ht, void *key) {
assert(ht != NULL);
@ -148,7 +172,7 @@ void* hashtable_get(Hashtable *ht, void *key) {
HashtableElement *elems = ht->table[hash % ht->table_size];
for(HashtableElement *e = elems; e; e = e->next) {
if(hash == e->hash && hashtable_compare(ht, key, e->key)) {
if(hash == e->hash && ht->cmp_func(key, e->key)) {
hashtable_idle_state(ht);
return e->data;
}
@ -158,40 +182,134 @@ void* hashtable_get(Hashtable *ht, void *key) {
return NULL;
}
void hashtable_set(Hashtable *ht, void *key, void *data) {
assert(ht != NULL);
static bool hashtable_set_internal(Hashtable *ht, HashtableElement **table, size_t table_size, hash_t hash, void *key, void *data) {
bool collisions_updated = false;
size_t idx = hash % table_size;
hash_t hash = ht->hash_func(key);
size_t idx = hash % ht->table_size;
hashtable_enter_state(ht, HT_OP_WRITE, true);
HashtableElement *elems = ht->table[idx], *elem;
HashtableElement *elems = table[idx], *elem;
for(HashtableElement *e = elems; e; e = e->next) {
if(hash == e->hash && hashtable_compare(ht, key, e->key)) {
if(hash == e->hash && ht->cmp_func(key, e->key)) {
if(ht->free_func) {
ht->free_func(e->key);
}
delete_element((void**)&elems, e);
ht->num_elements--;
if(elems) {
// we have just deleted an element from a bucket that had collisions.
collisions_updated = true;
}
break;
}
}
if(data) {
elem = create_element((void**)&elems, sizeof(HashtableElement));
if(ht->copy_func) {
ht->copy_func(&elem->key, key);
} else {
elem->key = key;
if(elems) {
// we are adding an element to a non-empty bucket.
// normally this is a new collision, unless we are replacing an existing element.
collisions_updated = !collisions_updated;
}
elem = create_element((void**)&elems, sizeof(HashtableElement));
ht->copy_func(&elem->key, key);
elem->hash = ht->hash_func(elem->key);
elem->data = data;
ht->num_elements++;
}
ht->table[idx] = elems;
table[idx] = elems;
return collisions_updated;
}
static int hashtable_check_collisions_with_new_size(Hashtable *ht, size_t size) {
int *ctable = calloc(sizeof(int), size);
int cols = 0;
for(size_t i = 0; i < ht->table_size; ++i) {
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
size_t idx = e->hash % size;
++ctable[idx];
if(ctable[idx] > 1) {
++cols;
}
}
}
free(ctable);
return cols;
}
static size_t hashtable_find_optimal_size(Hashtable *ht) {
size_t best_size = ht->table_size;
int col_tolerance = min(HT_COLLISION_TOLERANCE + 1, max(ht->num_elements / 2, 1));
int min_cols = 0;
for(size_t s = best_size; s < HT_MAX_SIZE; s += HT_RESIZE_STEP) {
int cols = hashtable_check_collisions_with_new_size(ht, s);
if(cols < col_tolerance) {
log_debug("Optimal size for %p is %llu (%i collisions)", (void*)ht, (unsigned long long)s, cols);
return s;
}
if(cols < min_cols) {
min_cols = cols;
best_size = s;
}
}
log_debug("Optimal size for %p is %llu (%i collisions)", (void*)ht, (unsigned long long)best_size, min_cols);
return best_size;
}
static void hashtable_resize_internal(Hashtable *ht, size_t new_size) {
new_size = constraint_size(new_size);
if(new_size == ht->table_size) {
return;
}
HashtableElement **new_table = calloc(new_size, sizeof(HashtableElement*));
for(size_t i = 0; i < ht->table_size; ++i) {
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
hashtable_set_internal(ht, new_table, new_size, e->hash, e->key, e->data);
}
}
hashtable_unset_all_internal(ht);
free(ht->table);
ht->table = new_table;
log_debug("Resized hashtable at %p: %llu -> %llu",
(void*)ht, (unsigned long long)ht->table_size, (unsigned long long)new_size);
ht->table_size = new_size;
}
void hashtable_resize(Hashtable *ht, size_t new_size) {
hashtable_enter_state(ht, HT_OP_WRITE, true);
hashtable_resize_internal(ht, new_size);
hashtable_idle_state(ht);
}
void hashtable_set(Hashtable *ht, void *key, void *data) {
assert(ht != NULL);
hash_t hash = ht->hash_func(key);
hashtable_enter_state(ht, HT_OP_WRITE, true);
bool update = hashtable_set_internal(ht, ht->table, ht->table_size, hash, key, data);
if(ht->dynamic_size && update) {
hashtable_resize_internal(ht, hashtable_find_optimal_size(ht));
}
hashtable_idle_state(ht);
}
@ -202,14 +320,8 @@ void hashtable_unset(Hashtable *ht, void *key) {
void hashtable_unset_deferred(Hashtable *ht, void *key, ListContainer **list) {
assert(ht != NULL);
ListContainer *c = create_element((void**)list, sizeof(ListContainer));
if(ht->copy_func) {
ht->copy_func(&c->data, key);
} else {
c->data = key;
}
ht->copy_func(&c->data, key);
}
void hashtable_unset_deferred_now(Hashtable *ht, ListContainer **list) {
@ -295,9 +407,7 @@ bool hashtable_cmpfunc_string(void *str1, void *str2) {
}
hash_t hashtable_hashfunc_string(void *vstr) {
const char *str = vstr;
size_t len = strlen(str);
return adler32(0, (const Bytef*)str, (uInt)len);
return crc32str(0, (const char*)vstr);
}
void hashtable_copyfunc_string(void **dst, void *src) {
@ -337,10 +447,44 @@ void* hashtable_iter_free_data(void *key, void *data, void *arg) {
return NULL;
}
bool hashtable_cmpfunc_ptr(void *p1, void *p2) {
return p1 == p2;
}
void hashtable_copyfunc_ptr(void **dst, void *src) {
*dst = src;
}
/*
* Diagnostic functions
*/
void hashtable_get_stats(Hashtable *ht, HashtableStats *stats) {
assert(ht != NULL);
assert(stats != NULL);
memset(stats, 0, sizeof(HashtableStats));
for(size_t i = 0; i < ht->table_size; ++i) {
int elems = 0;
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
++elems;
++stats->num_elements;
}
if(elems > 1) {
stats->collisions += elems - 1;
}
if(!elems) {
++stats->free_buckets;
} else if(elems > stats->max_per_bucket) {
stats->max_per_bucket = elems;
}
}
}
size_t hashtable_get_approx_overhead(Hashtable *ht) {
size_t o = sizeof(Hashtable) + sizeof(HashtableElement*) * ht->table_size;
@ -352,35 +496,20 @@ size_t hashtable_get_approx_overhead(Hashtable *ht) {
}
void hashtable_print_stringkeys(Hashtable *ht) {
int free_buckets = 0;
int max_elems = 0;
int total = 0;
int collisions = 0;
HashtableStats stats;
hashtable_get_stats(ht, &stats);
log_debug("------ %p:", (void*)ht);
for(size_t i = 0; i < ht->table_size; ++i) {
int elems = 0;
log_debug("[bucket %lu] %p", (unsigned long)i, (void*)ht->table[i]);
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
log_debug(" -- %s (%lu): %p", (char*)e->key, (unsigned long)e->hash, e->data);
++elems;
++total;
}
if(elems > 1) {
collisions += elems - 1;
}
if(!elems) {
++free_buckets;
} else if(elems > max_elems) {
max_elems = elems;
}
}
log_debug("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead",
total, free_buckets, collisions, max_elems,
stats.num_elements, stats.free_buckets, stats.collisions, stats.max_per_bucket,
(unsigned long int)hashtable_get_approx_overhead(ht));
}

View file

@ -15,10 +15,24 @@
#include "list.h"
#define HT_MIN_SIZE 15
#define HT_MAX_SIZE 4095
#define HT_COLLISION_TOLERANCE 5
#define HT_DYNAMIC_SIZE 0
#define HT_RESIZE_STEP 1
typedef struct Hashtable Hashtable;
typedef struct HashtableIterator HashtableIterator;
typedef struct HashtableStats HashtableStats;
typedef uint32_t hash_t;
struct HashtableStats {
unsigned int free_buckets;
unsigned int collisions;
unsigned int max_per_bucket;
unsigned int num_elements;
};
typedef bool (*HTCmpFunc)(void *key1, void *key2);
typedef hash_t (*HTHashFunc)(void *key);
typedef void (*HTCopyFunc)(void **dstkey, void *srckey);
@ -52,11 +66,14 @@ void hashtable_unset_string(Hashtable *ht, const char *key);
void hashtable_unset_deferred_string(Hashtable *ht, const char *key);
void* hashtable_iter_free_data(void *key, void *data, void *arg);
bool hashtable_cmpfunc_ptr(void *p1, void *p2);
void hashtable_copyfunc_ptr(void **dst, void *src);
int hashtable_test(void);
void hashtable_print_stringkeys(Hashtable *ht);
size_t hashtable_get_approx_overhead(Hashtable *ht);
void hashtable_get_stats(Hashtable *ht, HashtableStats *stats);
void hashtable_lock(Hashtable *ht);
void hashtable_unlock(Hashtable *ht);

View file

@ -130,6 +130,9 @@ int main(int argc, char **argv) {
const char *replay_path = NULL;
int replay_stage = 0;
init_paths();
init_log();
if(argc >= 2 && !strcmp(argv[1], "replay")) {
if(argc < 3) {
tsfprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
@ -147,8 +150,6 @@ int main(int argc, char **argv) {
}
}
init_paths();
init_log();
log_args(argc, argv);
if(run_tests()) {

View file

@ -51,10 +51,6 @@ troll2:
if(info) {
stage_loop(info);
} else {
for(StageInfo *s = stages; s->type == STAGE_STORY; ++s) {
s->procs->preload();
}
for(StageInfo *s = stages; s->type == STAGE_STORY; ++s) {
stage_loop(s);
}

View file

@ -189,14 +189,10 @@ static int replay_write_stage(ReplayStage *stg, SDL_RWops *file) {
}
int replay_write(Replay *rpy, SDL_RWops *file, bool compression) {
uint8_t *u8_p;
uint16_t version = REPLAY_STRUCT_VERSION;
int i, j;
for(u8_p = replay_magic_header; *u8_p; ++u8_p) {
SDL_WriteU8(file, *u8_p);
}
uint16_t version = REPLAY_STRUCT_VERSION;
SDL_RWwrite(file, replay_magic_header, sizeof(replay_magic_header), 1);
if(compression) {
version |= REPLAY_VERSION_COMPRESSION_BIT;
@ -276,12 +272,14 @@ static void replay_read_string(SDL_RWops *file, char **ptr) {
}
static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, size_t *ofs) {
for(uint8_t *u8_p = replay_magic_header; *u8_p; ++u8_p) {
++(*ofs);
if(SDL_ReadU8(file) != *u8_p) {
log_warn("Incorrect header");
return false;
}
uint8_t header[sizeof(replay_magic_header)];
(*ofs) += sizeof(header);
SDL_RWread(file, header, sizeof(header), 1);
if(memcmp(header, replay_magic_header, sizeof(header))) {
log_warn("Incorrect header");
return false;
}
CHECKPROP(rpy->version = SDL_ReadLE16(file), u);
@ -590,14 +588,10 @@ int replay_test(void) {
return 0;
}
uint8_t *u8_p, *buf = malloc(sz + headsz);
uint8_t *buf = malloc(sz + headsz);
SDL_RWops *handle = SDL_RWFromMem(buf, sz + headsz);
// SDL_RWwrite(handle, replay_magic_header, 1, sizeof(replay_magic_header));
for(u8_p = replay_magic_header; *u8_p; ++u8_p) {
SDL_WriteU8(handle, *u8_p);
}
SDL_RWwrite(handle, replay_magic_header, sizeof(replay_magic_header), 1);
SDL_WriteLE16(handle, REPLAY_STRUCT_VERSION);
SDL_WriteLE16(handle, 4);

View file

@ -57,7 +57,7 @@ void fontrenderer_draw(FontRenderer *f, const char *text,TTF_Font *font) {
assert(surf != NULL);
if(surf->w > FONTREN_MAXW || surf->h > FONTREN_MAXH) {
log_fatal("Text drawn (%dx%d) is too big for the internal buffer (%dx%d).", surf->pitch, surf->h, FONTREN_MAXW, FONTREN_MAXH);
log_fatal("Text drawn (\"%s\" %dx%d) is too big for the internal buffer (%dx%d).", text, surf->w, surf->h, FONTREN_MAXW, FONTREN_MAXH);
}
f->tex.w = surf->w;
f->tex.h = surf->h;

View file

@ -18,9 +18,9 @@ typedef enum {
} Alignment;
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
// Size of the buffer used by the font renderer. No text larger than this can be drawn.
enum {
FONTREN_MAXW = 512,
FONTREN_MAXW = 1024,
FONTREN_MAXH = 512
};

View file

@ -127,6 +127,8 @@ static int load_resource_async_thread(void *vdata) {
static Resource* load_resource_finish(void *opaque, ResourceHandler *handler, const char *path, const char *name, char *allocated_path, char *allocated_name, ResourceFlags flags);
bool resource_sdl_event(SDL_Event *evt) {
assert(SDL_ThreadID() == main_thread_id);
if(evt->type != sdlevent_finalize_load) {
return false;
}
@ -134,7 +136,6 @@ bool resource_sdl_event(SDL_Event *evt) {
ResourceAsyncLoadData *data = evt->user.data1;
if(!data) {
free(data);
return true;
}
@ -333,30 +334,28 @@ void preload_resources(ResourceType type, ResourceFlags flags, const char *first
}
void init_resources(void) {
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
register_handler(
RES_TEXTURE, TEX_PATH_PREFIX, load_texture_begin, load_texture_end, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, 227
RES_TEXTURE, TEX_PATH_PREFIX, load_texture_begin, load_texture_end, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, HT_DYNAMIC_SIZE
);
register_handler(
RES_ANIM, ANI_PATH_PREFIX, load_animation_begin, load_animation_end, free, NULL, animation_path, check_animation_path, 23
RES_ANIM, ANI_PATH_PREFIX, load_animation_begin, load_animation_end, free, NULL, animation_path, check_animation_path, HT_DYNAMIC_SIZE
);
register_handler(
RES_SHADER, SHA_PATH_PREFIX, load_shader_begin, load_shader_end, unload_shader, NULL, shader_path, check_shader_path, 29
RES_SHADER, SHA_PATH_PREFIX, load_shader_begin, load_shader_end, unload_shader, NULL, shader_path, check_shader_path, HT_DYNAMIC_SIZE
);
register_handler(
RES_MODEL, MDL_PATH_PREFIX, load_model_begin, load_model_end, unload_model, NULL, model_path, check_model_path, 17
RES_MODEL, MDL_PATH_PREFIX, load_model_begin, load_model_end, unload_model, NULL, model_path, check_model_path, HT_DYNAMIC_SIZE
);
register_handler(
RES_SFX, SFX_PATH_PREFIX, load_sound_begin, load_sound_end, unload_sound, NULL, sound_path, check_sound_path, 16
RES_SFX, SFX_PATH_PREFIX, load_sound_begin, load_sound_end, unload_sound, NULL, sound_path, check_sound_path, HT_DYNAMIC_SIZE
);
register_handler(
RES_BGM, BGM_PATH_PREFIX, load_music_begin, load_music_end, unload_music, NULL, music_path, check_music_path, 16
RES_BGM, BGM_PATH_PREFIX, load_music_begin, load_music_end, unload_music, NULL, music_path, check_music_path, HT_DYNAMIC_SIZE
);
main_thread_id = SDL_ThreadID();

View file

@ -533,7 +533,8 @@ void elly_unbound(Boss *b, int t) {
AT(100) {
int i;
Enemy *e, *last = NULL, *first, *middle;
Enemy *e, *last = NULL, *first = NULL, *middle = NULL;
for(i = 0; i < 6; i++) {
e = create_enemy3c(b->pos, ENEMY_IMMUNE, Baryon, baryon_unfold, 1.5*cexp(2.0*I*M_PI/6*i), i != 0 ? add_ref(last) : 0, i);
if(i == 0)

View file

@ -491,3 +491,60 @@ static void png_warning_handler(png_structp png_ptr, png_const_charp warning_msg
void png_setup_error_handlers(png_structp png) {
png_set_error_fn(png, NULL, png_error_handler, png_warning_handler);
}
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;
}

View file

@ -116,6 +116,8 @@ void tsfprintf(FILE *out, const char *restrict fmt, ...) __attribute__((format(p
int getenvint(const char *v) __attribute__((pure));
void png_setup_error_handlers(png_structp png);
uint32_t crc32str(uint32_t crc, const char *str);
noreturn void _ts_assert_fail(const char *cond, const char *func, const char *file, int line, bool use_log);
#undef assert