redesign list api

This commit is contained in:
Andrei Alexeyev 2017-11-21 16:45:01 +02:00
parent adc176e472
commit 7b53d9e731
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
21 changed files with 356 additions and 275 deletions

View file

@ -55,6 +55,7 @@ set(SRCs
enemy.c
item.c
list.c
refs.c
hashtable.c
boss.c
plrmodes.c

View file

@ -26,14 +26,14 @@ AniPlayer* aniplayer_create_copy(AniPlayer *src) {
void aniplayer_free(AniPlayer *plr) {
plr->queuesize = 0; // prevent aniplayer_reset from messing with the queue, since we're going to wipe all of it anyway
delete_all_elements((void **)&plr->queue,delete_element);
list_free_all((List**)&plr->queue);
aniplayer_reset(plr);
}
void aniplayer_reset(AniPlayer *plr) { // resets to a neutral state with empty queue.
plr->stdrow = 0;
if(plr->queuesize > 0) { // abort the animation in the fastest fluent way.
delete_all_elements((void **)&plr->queue->next,delete_element);
list_free_all((List**)&plr->queue->next);
plr->queuesize = 1;
plr->queue->delay = 0;
}
@ -46,7 +46,7 @@ void aniplayer_copy(AniPlayer *dst, AniPlayer *src) {
}
AniSequence *aniplayer_queue(AniPlayer *plr, int row, int loops, int delay) {
AniSequence *s = create_element_at_end((void **)&plr->queue,sizeof(AniSequence));
AniSequence *s = (AniSequence*)list_append((List**)&plr->queue, calloc(1, sizeof(AniSequence)));
plr->queuesize++;
s->row = row;
@ -81,7 +81,7 @@ void aniplayer_update(AniPlayer *plr) {
} else if(s->delay > 0) {
s->delay--;
} else {
delete_element((void **)&plr->queue,plr->queue);
free(list_pop((List**)&plr->queue));
plr->queuesize--;
plr->clock = 0;
}

View file

@ -29,7 +29,7 @@ static struct enqueued_sound {
static void play_sound_internal(const char *name, bool is_ui, int cooldown, bool replace, int delay) {
if(delay > 0) {
struct enqueued_sound *s = create_element((void**)&sound_queue, sizeof(struct enqueued_sound));
struct enqueued_sound *s = (struct enqueued_sound*)list_push((List**)&sound_queue, malloc(sizeof(struct enqueued_sound)));
s->time = global.frames + delay;
s->name = strdup(name);
s->cooldown = cooldown;
@ -53,17 +53,19 @@ static void play_sound_internal(const char *name, bool is_ui, int cooldown, bool
(snd->impl, is_ui ? SNDGROUP_UI : SNDGROUP_MAIN);
}
static void discard_enqueued_sound(void **queue, void *vsnd) {
struct enqueued_sound *snd = vsnd;
static void* discard_enqueued_sound(List **queue, List *vsnd, void *arg) {
struct enqueued_sound *snd = (struct enqueued_sound*)vsnd;
free(snd->name);
delete_element(queue, snd);
free(list_unlink(queue, vsnd));
return NULL;
}
static void play_enqueued_sound(void **queue, void *vsnd) {
struct enqueued_sound *snd = vsnd;
static void* play_enqueued_sound(List **queue, List *vsnd, void *arg) {
struct enqueued_sound *snd = (struct enqueued_sound*)vsnd;
play_sound_internal(snd->name, false, snd->cooldown, snd->replace, 0);
free(snd->name);
delete_element(queue, snd);
free(list_unlink(queue, vsnd));
return NULL;
}
void play_sound(const char *name) {
@ -111,7 +113,7 @@ void reset_sounds(void) {
}
}
delete_all_elements((void**)&sound_queue, discard_enqueued_sound);
list_foreach((List**)&sound_queue, discard_enqueued_sound, NULL);
}
void update_sounds(void) {
@ -129,7 +131,7 @@ void update_sounds(void) {
next = (struct enqueued_sound*)s->chain.next;
if(s->time <= global.frames) {
play_enqueued_sound((void**)&sound_queue, s);
play_enqueued_sound((List**)&sound_queue, (List*)s, NULL);
}
}
}

View file

@ -239,7 +239,7 @@ static ConfigEntry* config_get_unknown_entry(const char *name) {
}
}
l = create_element((void**)&unknowndefs, sizeof(ConfigEntryList));
l = (ConfigEntryList*)list_push((List**)&unknowndefs, malloc(sizeof(ConfigEntryList)));
e = &l->entry;
memset(e, 0, sizeof(ConfigEntry));
stralloc(&e->name, name);
@ -252,17 +252,18 @@ static void config_set_unknown(const char *name, const char *val) {
stralloc(&config_get_unknown_entry(name)->val.s, val);
}
static void config_delete_unknown_entry(void **list, void *lentry) {
static void* config_delete_unknown_entry(List **list, List *lentry, void *arg) {
ConfigEntry *e = &((ConfigEntryList*)lentry)->entry;
free(e->name);
free(e->val.s);
free(list_unlink(list, lentry));
delete_element(list, lentry);
return NULL;
}
static void config_delete_unknown_entries(void) {
delete_all_elements((void**)&unknowndefs, config_delete_unknown_entry);
list_foreach((List**)&unknowndefs, config_delete_unknown_entry, NULL);
}
void config_save(void) {

View file

@ -32,7 +32,8 @@ Enemy *create_enemy_p(Enemy **enemies, complex pos, int hp, EnemyVisualRule visu
log_fatal("Tried to spawn an enemy while in drawing code");
}
Enemy *e = (Enemy *)create_element((void **)enemies, sizeof(Enemy));
// XXX: some code relies on the insertion logic
Enemy *e = (Enemy*)list_insert((List**)enemies, malloc(sizeof(Enemy)));
e->moving = false;
e->dir = 0;
@ -55,8 +56,8 @@ Enemy *create_enemy_p(Enemy **enemies, complex pos, int hp, EnemyVisualRule visu
return e;
}
void _delete_enemy(void **enemies, void* enemy) {
Enemy *e = (Enemy *)enemy;
void* _delete_enemy(List **enemies, List* enemy, void *arg) {
Enemy *e = (Enemy*)enemy;
if(e->hp <= 0 && e->hp > ENEMY_IMMUNE) {
play_sound("enemydeath");
@ -74,18 +75,19 @@ void _delete_enemy(void **enemies, void* enemy) {
PARTICLE("blast", e->pos, 0, blast_timeout, { 15 }, .draw_rule = GrowFade);
}
e->logic_rule(enemy, EVENT_DEATH);
e->logic_rule(e, EVENT_DEATH);
del_ref(enemy);
delete_element((void **)enemies, enemy);
free(list_unlink(enemies, enemy));
return NULL;
}
void delete_enemy(Enemy **enemies, Enemy* enemy) {
_delete_enemy((void**) enemies, enemy);
_delete_enemy((List**)enemies, (List*)enemy, NULL);
}
void delete_enemies(Enemy **enemies) {
delete_all_elements((void **)enemies, _delete_enemy);
list_foreach((List**)enemies, _delete_enemy, NULL);
}
static void draw_enemy(Enemy *e) {

View file

@ -69,7 +69,7 @@ static bool events_invoke_handler(SDL_Event *event, EventHandler *handler) {
return false;
}
static int handler_container_prio_func(void *h) {
static int handler_container_prio_func(List *h) {
return ((EventHandler*)((ListContainer*)h)->data)->priority;
}
@ -130,11 +130,12 @@ static bool events_invoke_handlers(SDL_Event *event, ListContainer *h_list, Even
// merge the array into the list copy, respecting priority
for(EventHandler *h = h_array; h->proc; ++h) {
create_container_at_priority(
list_insert_at_priority(
&merged_list,
list_wrap_container(h),
real_priority(h->priority),
handler_container_prio_func
)->data = h;
);
}
// iterate over the merged list
@ -144,7 +145,7 @@ static bool events_invoke_handlers(SDL_Event *event, ListContainer *h_list, Even
}
}
delete_all_elements((void**)&merged_list, delete_element);
list_free_all((List**)&merged_list);
return result;
}
@ -174,7 +175,12 @@ void events_register_handler(EventHandler *handler) {
}
assert(handler_alloc->priority > EPRIO_DEFAULT);
create_container_at_priority(&global_handlers, handler_alloc->priority, handler_container_prio_func)->data = handler_alloc;
list_insert_at_priority(
(List**)&global_handlers,
(List*)list_wrap_container(handler_alloc),
handler_alloc->priority,
handler_container_prio_func
);
log_debug("Registered handler: %p %u", *(void**)&handler_alloc->proc, handler_alloc->priority);
}
@ -187,7 +193,7 @@ void events_unregister_handler(EventHandlerProc proc) {
if(h->proc == proc) {
free(c->data);
delete_element((void**)&global_handlers, c);
free(list_unlink(&global_handlers, c));
return;
}
}

View file

@ -33,6 +33,7 @@
#include "laser.h"
#include "dialog.h"
#include "list.h"
#include "refs.h"
#include "config.h"
#include "fbo.h"
#include "vbo.h"

View file

@ -149,20 +149,21 @@ void hashtable_unlock(Hashtable *ht) {
hashtable_idle_state(ht);
}
static void hashtable_delete_callback(void **vlist, void *velem, void *vht) {
static void* hashtable_delete_callback(List **vlist, List *velem, void *vht) {
Hashtable *ht = vht;
HashtableElement *elem = velem;
HashtableElement *elem = (HashtableElement*)velem;
if(ht->free_func) {
ht->free_func(elem->key);
}
delete_element(vlist, velem);
free(list_unlink(vlist, velem));
return NULL;
}
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);
list_foreach((List**)(ht->table + i), hashtable_delete_callback, ht);
}
ht->num_elements = 0;
@ -220,7 +221,7 @@ static bool hashtable_set_internal(Hashtable *ht, HashtableElement **table, size
ht->free_func(e->key);
}
delete_element((void**)&elems, e);
free(list_unlink((List**)&elems, (List*)e));
ht->num_elements--;
if(elems) {
@ -239,7 +240,7 @@ static bool hashtable_set_internal(Hashtable *ht, HashtableElement **table, size
collisions_updated = !collisions_updated;
}
elem = create_element((void**)&elems, sizeof(HashtableElement));
elem = (HashtableElement*)list_push((List**)&elems, malloc(sizeof(HashtableElement)));
ht->copy_func(&elem->key, key);
elem->hash = ht->hash_func(elem->key);
elem->data = data;
@ -346,7 +347,7 @@ 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));
ListContainer *c = (ListContainer*)list_push(list, list_wrap_container(NULL));
ht->copy_func(&c->data, key);
}
@ -362,7 +363,7 @@ void hashtable_unset_deferred_now(Hashtable *ht, ListContainer **list) {
ht->free_func(c->data);
}
delete_element((void**)list, c);
free(list_unlink(list, c));
}
}

View file

@ -26,6 +26,11 @@ static Texture* item_tex(ItemType type) {
return get_tex(map[type]);
}
static int item_prio(List *litem) {
Item *item = (Item*)litem;
return item->type;
}
Item* create_item(complex pos, complex v, ItemType type) {
if((creal(pos) < 0 || creal(pos) > VIEWPORT_W)) {
// we need this because we clamp the item position to the viewport boundary during motion
@ -33,18 +38,7 @@ Item* create_item(complex pos, complex v, ItemType type) {
return NULL;
}
Item *e, **d, **dest = &global.items;
for(e = *dest; e && e->next; e = e->next)
if(e->prev && type < e->type)
break;
if(e == NULL)
d = dest;
else
d = &e;
Item *i = create_element((void **)d, sizeof(Item));
Item *i = (Item*)list_insert_at_priority((List**)&global.items, malloc(sizeof(Item)), type, item_prio);
i->pos = pos;
i->pos0 = pos;
i->v = v;
@ -56,7 +50,7 @@ Item* create_item(complex pos, complex v, ItemType type) {
}
void delete_item(Item *item) {
delete_element((void **)&global.items, item);
free(list_unlink((List**)&global.items, (List*)item));
}
Item* create_bpoint(complex pos) {
@ -95,7 +89,7 @@ void draw_items(void) {
}
void delete_items(void) {
delete_all_elements((void **)&global.items, delete_element);
list_free_all((List**)&global.items);
}
void move_item(Item *i) {

View file

@ -11,7 +11,7 @@
#include "list.h"
Laser *create_laser(complex pos, float time, float deathtime, Color color, LaserPosRule prule, LaserLogicRule lrule, complex a0, complex a1, complex a2, complex a3) {
Laser *l = create_element((void **)&global.lasers, sizeof(Laser));
Laser *l = (Laser*)list_push((List**)&global.lasers, malloc(sizeof(Laser)));
l->birthtime = global.frames;
l->timespan = time;
@ -168,18 +168,23 @@ void draw_lasers(int bgpass) {
}
}
void _delete_laser(void **lasers, void *laser) {
Laser *l = laser;
void* _delete_laser(List **lasers, List *laser, void *arg) {
Laser *l = (Laser*)laser;
if(l->lrule)
l->lrule(l, EVENT_DEATH);
del_ref(laser);
delete_element(lasers, laser);
free(list_unlink(lasers, laser));
return NULL;
}
void delete_laser(Laser **lasers, Laser *laser) {
_delete_laser((List**)lasers, (List*)laser, NULL);
}
void delete_lasers(void) {
delete_all_elements((void **)&global.lasers, _delete_laser);
list_foreach((List**)&global.lasers, _delete_laser, NULL);
}
void process_lasers(void) {
@ -218,7 +223,7 @@ void process_lasers(void) {
if(global.frames - laser->birthtime > laser->deathtime + laser->timespan*laser->speed) {
del = laser;
laser = laser->next;
_delete_laser((void **)&global.lasers, del);
delete_laser(&global.lasers, del);
} else {
laser = laser->next;
}

View file

@ -6,41 +6,57 @@
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "list.h"
#include <stdlib.h>
#include <stdio.h>
#define LIST_NO_MACROS
#include "list.h"
#include "global.h"
void *_FREEREF;
void *create_element(void **dest, size_t size) {
List* list_insert(List **dest, List *elem) {
assert(dest != NULL);
assert(size > 0);
assert(elem != NULL);
List *e = calloc(1, size);
List **d = (List **)dest;
elem->prev = *dest;
e->prev = *d;
if(*dest != NULL) {
elem->next = (*dest)->next;
if(*d != NULL) {
e->next = (*d)->next;
if((*d)->next)
(*d)->next->prev = e;
if((*dest)->next) {
(*dest)->next->prev = elem;
}
(*d)->next = e;
(*dest)->next = elem;
} else {
*d = e;
elem->next = NULL;
*dest = elem;
}
return e;
return elem;
}
void* create_element_at_end(void **dest, size_t size) {
List* list_push(List **dest, List *elem) {
assert(dest != NULL);
assert(elem != NULL);
if(*dest) {
(*dest)->prev = elem;
}
elem->next = *dest;
elem->prev = NULL;
*dest = elem;
return elem;
}
List* list_append(List **dest, List *elem) {
assert(dest != NULL);
assert(elem != NULL);
if(*dest == NULL) {
return create_element((void **)dest,size);
return list_insert(dest, elem);
}
List *end = NULL;
@ -48,17 +64,16 @@ void* create_element_at_end(void **dest, size_t size) {
end = e;
}
return create_element((void **)&end,size);
return list_insert(&end, elem);
}
void* create_element_at_priority(void **list_head, size_t size, int prio, int (*prio_func)(void*)) {
List* list_insert_at_priority(List **list_head, List *elem, int prio, ListPriorityFunc prio_func) {
assert(list_head != NULL);
assert(size > 0);
assert(elem != NULL);
assert(prio_func != NULL);
List *elem = calloc(1, size);
if(!*list_head) {
elem->prev = elem->next = NULL;
*list_head = elem;
return elem;
}
@ -93,126 +108,54 @@ void* create_element_at_priority(void **list_head, size_t size, int prio, int (*
return elem;
}
ListContainer* create_container(ListContainer **dest) {
return create_element((void**)dest, sizeof(ListContainer));
}
ListContainer* create_container_at_priority(ListContainer **list_head, int prio, int (*prio_func)(void*)) {
return create_element_at_priority((void**)list_head, sizeof(ListContainer), prio, prio_func);
}
void delete_element(void **dest, void *e) {
if(((List *)e)->prev != NULL)
((List *)((List *)e)->prev)->next = ((List *)e)->next;
if(((List *)e)->next != NULL)
((List *)((List *)e)->next)->prev = ((List *)e)->prev;
if(*dest == e)
*dest = ((List *)e)->next;
free(e);
}
void delete_all_elements(void **dest, void (callback)(void **, void *)) {
void *e = *dest;
void *tmp;
while(e != 0) {
tmp = e;
e = ((List *)e)->next;
callback(dest, tmp);
List* list_unlink(List **dest, List *elem) {
if(elem->prev != NULL) {
elem->prev->next = elem->next;
}
*dest = NULL;
}
void delete_all_elements_witharg(void **dest, void (callback)(void **, void *, void *), void *arg) {
void *e = *dest;
void *tmp;
while(e != 0) {
tmp = e;
e = ((List *)e)->next;
callback(dest, tmp, arg);
if(elem->next != NULL) {
elem->next->prev = elem->prev;
}
*dest = NULL;
if(*dest == elem) {
*dest = elem->next;
}
return elem;
}
#ifdef DEBUG
// #define DEBUG_REFS
#endif
List* list_pop(List **dest) {
return list_unlink(dest, *dest);
}
#ifdef DEBUG_REFS
#define REFLOG(...) log_debug(__VA_ARGS__);
#else
#define REFLOG(...)
#endif
void* list_foreach(List **dest, ListForeachCallback callback, void *arg) {
List *e = *dest;
int add_ref(void *ptr) {
int i, firstfree = -1;
while(e != 0) {
void *ret;
List *tmp = e;
e = e->next;
for(i = 0; i < global.refs.count; i++) {
if(global.refs.ptrs[i].ptr == ptr) {
global.refs.ptrs[i].refs++;
REFLOG("increased refcount for %p (ref %i): %i", ptr, i, global.refs.ptrs[i].refs);
return i;
} else if(firstfree < 0 && global.refs.ptrs[i].ptr == FREEREF) {
firstfree = i;
if((ret = callback(dest, tmp, arg)) != NULL) {
return ret;
}
}
if(firstfree >= 0) {
global.refs.ptrs[firstfree].ptr = ptr;
global.refs.ptrs[firstfree].refs = 1;
REFLOG("found free ref for %p: %i", ptr, firstfree);
return firstfree;
}
global.refs.ptrs = realloc(global.refs.ptrs, (++global.refs.count)*sizeof(Reference));
global.refs.ptrs[global.refs.count - 1].ptr = ptr;
global.refs.ptrs[global.refs.count - 1].refs = 1;
REFLOG("new ref for %p: %i", ptr, global.refs.count - 1);
return global.refs.count - 1;
return NULL;
}
void del_ref(void *ptr) {
int i;
for(i = 0; i < global.refs.count; i++)
if(global.refs.ptrs[i].ptr == ptr)
global.refs.ptrs[i].ptr = NULL;
void* list_callback_free_element(List **dest, List *elem, void *arg) {
list_unlink(dest, elem);
free(elem);
return NULL;
}
void free_ref(int i) {
if(i < 0)
return;
global.refs.ptrs[i].refs--;
REFLOG("decreased refcount for %p (ref %i): %i", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
if(global.refs.ptrs[i].refs <= 0) {
global.refs.ptrs[i].ptr = FREEREF;
global.refs.ptrs[i].refs = 0;
REFLOG("ref %i is now free", i);
}
void list_free_all(List **dest) {
list_foreach(dest, list_callback_free_element, NULL);
}
void free_all_refs(void) {
int inuse = 0;
int inuse_unique = 0;
for(int i = 0; i < global.refs.count; i++) {
if(global.refs.ptrs[i].refs) {
inuse += global.refs.ptrs[i].refs;
inuse_unique += 1;
}
}
if(inuse) {
log_warn("%i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
}
free(global.refs.ptrs);
memset(&global.refs, 0, sizeof(RefArray));
ListContainer* list_wrap_container(void *data) {
ListContainer *c = calloc(1, sizeof(ListContainer));
c->data = data;
return c;
}

View file

@ -8,19 +8,6 @@
#pragma once
/* I got annoyed of the code doubling caused by simple linked lists,
* so i do some void-magic here to save the lines.
*/
#include <stdlib.h>
void* create_element(void **dest, size_t size);
void* create_element_at_end(void **dest, size_t size);
void* create_element_at_priority(void **list_head, size_t size, int prio, int (*prio_func)(void*));
void delete_element(void **dest, void *e);
void delete_all_elements(void **dest, void (callback)(void **, void *));
void delete_all_elements_witharg(void **dest, void (callback)(void **, void *, void *), void *arg);
typedef struct List {
struct List *next;
struct List *prev;
@ -32,23 +19,37 @@ typedef struct ListContainer {
void *data;
} ListContainer;
ListContainer* create_container(ListContainer **dest);
ListContainer* create_container_at_priority(ListContainer **list_head, int prio, int (*prio_func)(void*));
typedef void* (*ListForeachCallback)(List **head, List *elem, void *arg);
typedef int (*ListPriorityFunc)(List *elem);
typedef struct {
void *ptr;
int refs;
} Reference;
List* list_insert(List **dest, List *elem);
List* list_push(List **dest, List *elem);
List* list_append(List **dest, List *elem);
List* list_insert_at_priority(List **dest, List *elem, int prio, ListPriorityFunc prio_func);
List* list_pop(List **dest);
List* list_unlink(List **dest, List *elem);
void* list_foreach(List **dest, ListForeachCallback callback, void *arg);
void* list_callback_free_element(List **dest, List *elem, void *arg);
void list_free_all(List **dest);
ListContainer* list_wrap_container(void *data);
typedef struct {
Reference *ptrs;
int count;
} RefArray;
// type-generic macros
extern void *_FREEREF;
#define FREEREF &_FREEREF
#define REF(p) (global.refs.ptrs[(int)(p)].ptr)
int add_ref(void *ptr);
void del_ref(void *ptr);
void free_ref(int i);
void free_all_refs(void);
#ifndef LIST_NO_MACROS
#define LIST_CAST(expr,ptrlevel) (_Generic((expr), \
ListContainer ptrlevel: (List ptrlevel)(expr), \
void ptrlevel: (List ptrlevel)(expr), \
List ptrlevel: (expr) \
))
#define list_insert(dest,elem) list_insert(LIST_CAST(dest, **), LIST_CAST(elem, *))
#define list_push(dest,elem) list_push(LIST_CAST(dest, **), LIST_CAST(elem, *))
#define list_append(dest,elem) list_append(LIST_CAST(dest, **), LIST_CAST(elem, *))
#define list_insert_at_priority(dest,elem,prio,prio_func) list_insert_at_priority(LIST_CAST(dest, **), LIST_CAST(elem, *), prio, prio_func)
#define list_pop(dest) list_pop(LIST_CAST(dest, **))
#define list_unlink(dest,elem) list_unlink(LIST_CAST(dest, **), LIST_CAST(elem, *))
#define list_foreach(dest,callback,arg) list_foreach(LIST_CAST(dest, **), callback, arg)
#define list_free_all(dest) list_free_all(LIST_CAST(dest, **))
#endif // LIST_NO_MACROS

View file

@ -181,8 +181,8 @@ noreturn void _taisei_log_fatal(LogLevel lvl, const char *funcname, const char *
log_abort(NULL);
}
static void delete_logger(void **loggers, void *logger) {
Logger *l = logger;
static void* delete_logger(List **loggers, List *logger, void *arg) {
Logger *l = (Logger*)logger;
#if HAVE_STDIO_H
if(l->out->type == SDL_RWOPS_STDFILE) {
@ -191,7 +191,9 @@ static void delete_logger(void **loggers, void *logger) {
#endif
SDL_RWclose(l->out);
delete_element(loggers, logger);
free(list_unlink(loggers, logger));
return NULL;
}
void log_init(LogLevel lvls, LogLevel backtrace_lvls) {
@ -201,7 +203,7 @@ void log_init(LogLevel lvls, LogLevel backtrace_lvls) {
}
void log_shutdown(void) {
delete_all_elements((void**)&loggers, delete_logger);
list_foreach((List**)&loggers, delete_logger, NULL);
SDL_DestroyMutex(log_mutex);
log_mutex = NULL;
}
@ -220,7 +222,7 @@ void log_add_output(LogLevel levels, SDL_RWops *output) {
return;
}
Logger *l = create_element((void**)&loggers, sizeof(Logger));
Logger *l = (Logger*)list_append((List**)&loggers, malloc(sizeof(Logger)));
l->levels = levels;
l->out = output;
}

View file

@ -248,7 +248,7 @@ static void progress_read(SDL_RWops *file) {
default:
log_warn("Unknown command %x (%u bytes). Will preserve as-is and not interpret", cmd, cmdsize);
UnknownCmd *c = create_element((void**)&progress.unknown, sizeof(UnknownCmd));
UnknownCmd *c = (UnknownCmd*)list_append((List**)&progress.unknown, malloc(sizeof(UnknownCmd)));
c->cmd = cmd;
c->size = cmdsize;
c->data = malloc(cmdsize);
@ -448,7 +448,14 @@ static void progress_prepare_cmd_stage_playinfo(size_t *bufsize, void **arg) {
StageProgress *p = stage_get_progress_from_info(stg, d, false);
if(p && (p->num_played || p->num_cleared)) {
struct cmd_stage_playinfo_data_elem *e = create_element((void**)&data->elems, sizeof(struct cmd_stage_playinfo_data_elem));
struct cmd_stage_playinfo_data_elem *e = (
(struct cmd_stage_playinfo_data_elem*)
list_push(
(List**)&data->elems,
malloc(sizeof(struct cmd_stage_playinfo_data_elem))
)
);
e->stage = stg->id; data->size += sizeof(uint16_t);
e->diff = d; data->size += sizeof(uint8_t);
e->num_played = p->num_played; data->size += sizeof(uint32_t);
@ -482,7 +489,7 @@ static void progress_write_cmd_stage_playinfo(SDL_RWops *vfile, void **arg) {
}
cleanup:
delete_all_elements((void**)&data->elems, delete_element);
list_free_all((List**)&data->elems);
free(data);
}
@ -694,12 +701,13 @@ void progress_save(void) {
SDL_RWclose(file);
}
static void delete_unknown_cmd(void **dest, void *elem) {
UnknownCmd *cmd = elem;
static void* delete_unknown_cmd(List **dest, List *elem, void *arg) {
UnknownCmd *cmd = (UnknownCmd*)elem;
free(cmd->data);
delete_element(dest, cmd);
free(list_unlink(dest, elem));
return NULL;
}
void progress_unload(void) {
delete_all_elements((void**)&progress.unknown, delete_unknown_cmd);
list_foreach((void**)&progress.unknown, delete_unknown_cmd, NULL);
}

View file

@ -97,8 +97,8 @@ int projectile_prio_rawfunc(Texture *tex, complex size) {
return -rint(creal(s) * cimag(s));
}
int projectile_prio_func(void *vproj) {
Projectile *proj = vproj;
int projectile_prio_func(List *vproj) {
Projectile *proj = (Projectile*)vproj;
return projectile_prio_rawfunc(proj->tex, proj->size);
}
@ -107,8 +107,9 @@ static Projectile* _create_projectile(ProjArgs *args) {
log_fatal("Tried to spawn a projectile while in drawing code");
}
Projectile *p = create_element_at_priority(
(void**)args->dest, sizeof(Projectile),
Projectile *p = (Projectile*)list_insert_at_priority(
(List**)args->dest,
malloc(sizeof(Projectile)),
projectile_prio_rawfunc(args->texture_ptr, args->size),
projectile_prio_func
);
@ -155,21 +156,21 @@ Projectile* _proj_attach_dbginfo(Projectile *p, DebugInfo *dbg) {
}
#endif
void _delete_projectile(void **projs, void *proj) {
Projectile *p = proj;
static void* _delete_projectile(List **projs, List *proj, void *arg) {
Projectile *p = (Projectile*)proj;
p->rule(p, EVENT_DEATH);
del_ref(proj);
delete_element(projs, proj);
free(list_unlink(projs, proj));
return NULL;
}
void delete_projectile(Projectile **projs, Projectile *proj) {
_delete_projectile((void **)projs, proj);
_delete_projectile((List**)projs, (List*)proj, NULL);
}
void delete_projectiles(Projectile **projs) {
delete_all_elements((void **)projs, _delete_projectile);
list_foreach((List**)projs, _delete_projectile, NULL);
}
int collision_projectile(Projectile *p) {

91
src/refs.c Normal file
View file

@ -0,0 +1,91 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "global.h"
#include "refs.h"
void *_FREEREF;
#ifdef DEBUG
// #define DEBUG_REFS
#endif
#ifdef DEBUG_REFS
#define REFLOG(...) log_debug(__VA_ARGS__);
#else
#define REFLOG(...)
#endif
int add_ref(void *ptr) {
int i, firstfree = -1;
for(i = 0; i < global.refs.count; i++) {
if(global.refs.ptrs[i].ptr == ptr) {
global.refs.ptrs[i].refs++;
REFLOG("increased refcount for %p (ref %i): %i", ptr, i, global.refs.ptrs[i].refs);
return i;
} else if(firstfree < 0 && global.refs.ptrs[i].ptr == FREEREF) {
firstfree = i;
}
}
if(firstfree >= 0) {
global.refs.ptrs[firstfree].ptr = ptr;
global.refs.ptrs[firstfree].refs = 1;
REFLOG("found free ref for %p: %i", ptr, firstfree);
return firstfree;
}
global.refs.ptrs = realloc(global.refs.ptrs, (++global.refs.count)*sizeof(Reference));
global.refs.ptrs[global.refs.count - 1].ptr = ptr;
global.refs.ptrs[global.refs.count - 1].refs = 1;
REFLOG("new ref for %p: %i", ptr, global.refs.count - 1);
return global.refs.count - 1;
}
void del_ref(void *ptr) {
int i;
for(i = 0; i < global.refs.count; i++)
if(global.refs.ptrs[i].ptr == ptr)
global.refs.ptrs[i].ptr = NULL;
}
void free_ref(int i) {
if(i < 0)
return;
global.refs.ptrs[i].refs--;
REFLOG("decreased refcount for %p (ref %i): %i", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
if(global.refs.ptrs[i].refs <= 0) {
global.refs.ptrs[i].ptr = FREEREF;
global.refs.ptrs[i].refs = 0;
REFLOG("ref %i is now free", i);
}
}
void free_all_refs(void) {
int inuse = 0;
int inuse_unique = 0;
for(int i = 0; i < global.refs.count; i++) {
if(global.refs.ptrs[i].refs) {
inuse += global.refs.ptrs[i].refs;
inuse_unique += 1;
}
}
if(inuse) {
log_warn("%i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
}
free(global.refs.ptrs);
memset(&global.refs, 0, sizeof(RefArray));
}

27
src/refs.h Normal file
View file

@ -0,0 +1,27 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2017, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2017, Andrei Alexeyev <akari@alienslab.net>.
*/
#pragma once
typedef struct {
void *ptr;
int refs;
} Reference;
typedef struct {
Reference *ptrs;
int count;
} RefArray;
extern void *_FREEREF;
#define FREEREF &_FREEREF
#define REF(p) (global.refs.ptrs[(int)(p)].ptr)
int add_ref(void *ptr);
void del_ref(void *ptr);
void free_ref(int i);
void free_all_refs(void);

View file

@ -36,7 +36,7 @@ static void postprocess_load_callback(const char *key, const char *value, void *
PostprocessShader *current = *slist;
if(!strcmp(key, "@shader")) {
current = create_element((void**)slist, sizeof(PostprocessShader));
current = (PostprocessShader*)list_append((List**)slist, malloc(sizeof(PostprocessShader)));
current->uniforms = NULL;
current->shader = get_resource(RES_SHADER, value, ldata->resflags)->shader;
log_debug("Shader added: %s (prog: %u)", value, current->shader->prog);
@ -102,7 +102,7 @@ static void postprocess_load_callback(const char *key, const char *value, void *
}
}
PostprocessShaderUniform *uni = create_element((void**)&current->uniforms, sizeof(PostprocessShaderUniform));
PostprocessShaderUniform *uni = (PostprocessShaderUniform*)list_append((List**)&current->uniforms, malloc(sizeof(PostprocessShaderUniform)));
uni->loc = uniloc(current->shader, name);
uni->type = utype;
uni->size = usize;
@ -127,20 +127,22 @@ PostprocessShader* postprocess_load(const char *path, ResourceFlags flags) {
return list;
}
static void delete_uniform(void **dest, void *data) {
PostprocessShaderUniform *uni = data;
static void* delete_uniform(List **dest, List *data, void *arg) {
PostprocessShaderUniform *uni = (PostprocessShaderUniform*)data;
free(uni->values.v);
delete_element(dest, data);
free(list_unlink(dest, data));
return NULL;
}
static void delete_shader(void **dest, void *data) {
PostprocessShader *ps = data;
delete_all_elements((void**)&ps->uniforms, delete_uniform);
delete_element(dest, data);
static void* delete_shader(List **dest, List *data, void *arg) {
PostprocessShader *ps = (PostprocessShader*)data;
list_foreach((List**)&ps->uniforms, delete_uniform, NULL);
free(list_unlink(dest, data));
return NULL;
}
void postprocess_unload(PostprocessShader **list) {
delete_all_elements((void**)list, delete_shader);
list_foreach((List**)list, delete_shader, NULL);
}
void postprocess(PostprocessShader *ppshaders, FBO **primfbo, FBO **auxfbo, PostprocessPrepareFuncPtr prepare, PostprocessDrawFuncPtr draw) {

View file

@ -13,7 +13,7 @@
static StageText *textlist = NULL;
StageText* stagetext_add(const char *text, complex pos, Alignment align, TTF_Font *font, Color clr, int delay, int lifetime, int fadeintime, int fadeouttime) {
StageText *t = create_element((void**)&textlist, sizeof(StageText));
StageText *t = (StageText*)list_append((List**)&textlist, malloc(sizeof(StageText)));
t->rendered_text = fontrender_render(&resources.fontren, text, font);
t->pos = pos;
t->align = align;
@ -44,13 +44,14 @@ StageText* stagetext_add_numeric(int n, complex pos, Alignment align, TTF_Font *
return t;
}
static void stagetext_delete(StageText **dest, StageText *txt) {
SDL_FreeSurface(txt->rendered_text);
delete_element((void**)dest, txt);
static void* stagetext_delete(List **dest, List *txt, void *arg) {
SDL_FreeSurface(((StageText*)txt)->rendered_text);
free(list_unlink(dest, txt));
return NULL;
}
void stagetext_free(void) {
delete_all_elements((void**)&textlist, (void (*)(void **, void *))stagetext_delete);
list_foreach((List**)&textlist, stagetext_delete, NULL);
}
static void stagetext_draw_single(StageText *txt) {
@ -59,7 +60,7 @@ static void stagetext_draw_single(StageText *txt) {
}
if(global.frames > txt->time.spawn + txt->time.life) {
stagetext_delete(&textlist, txt);
stagetext_delete((List**)&textlist, (List*)txt, NULL);
return;
}
@ -95,8 +96,7 @@ void stagetext_draw(void) {
}
static void stagetext_table_push(StageTextTable *tbl, StageText *txt, bool update_pos) {
ListContainer *c = create_container(&tbl->elems);
c->data = txt;
list_append(&tbl->elems, list_wrap_container(txt));
if(update_pos) {
tbl->pos += txt->rendered_text->h / resources.fontren.quality * I;
@ -126,7 +126,7 @@ void stagetext_end_table(StageTextTable *tbl) {
((StageText*)c->data)->pos += ofs;
}
delete_all_elements((void**)&tbl->elems, delete_element);
list_free_all(&tbl->elems);
}
static void stagetext_table_add_label(StageTextTable *tbl, const char *title) {

View file

@ -66,14 +66,15 @@ void vfs_init(void) {
}
}
static void call_shutdown_hook(void **vlist, void *vhook) {
vfs_shutdownhook_t *hook = vhook;
static void* call_shutdown_hook(List **vlist, List *vhook, void *arg) {
vfs_shutdownhook_t *hook = (vfs_shutdownhook_t*)vhook;
hook->func(hook->arg);
delete_element(vlist, vhook);
free(list_unlink(vlist, vhook));
return NULL;
}
void vfs_shutdown(void) {
delete_all_elements((void**)&shutdown_hooks, call_shutdown_hook);
list_foreach((List**)&shutdown_hooks, call_shutdown_hook, NULL);
vfs_decref(vfs_root);
vfs_tls_free(vfs_tls_fallback);
@ -84,7 +85,7 @@ void vfs_shutdown(void) {
}
void vfs_hook_on_shutdown(VFSShutdownHandler func, void *arg) {
vfs_shutdownhook_t *hook = create_element_at_end((void**)&shutdown_hooks, sizeof(vfs_shutdownhook_t));
vfs_shutdownhook_t *hook = (vfs_shutdownhook_t*)list_append((List**)&shutdown_hooks, malloc(sizeof(vfs_shutdownhook_t)));
hook->func = func;
hook->arg = arg;
}

View file

@ -13,15 +13,16 @@
static bool vfs_union_mount_internal(VFSNode *unode, const char *mountpoint, VFSNode *mountee, VFSInfo info, bool seterror);
static void vfs_union_delete_callback(void **list, void *elem) {
ListContainer *c = elem;
static void* vfs_union_delete_callback(List **list, List *elem, void *arg) {
ListContainer *c = (ListContainer*)elem;
VFSNode *n = c->data;
vfs_decref(n);
delete_element(list, elem);
free(list_unlink(list, elem));
return NULL;
}
static void vfs_union_free(VFSNode *node) {
delete_all_elements((void**)&node->_members_, vfs_union_delete_callback);
list_foreach(&node->_members_, vfs_union_delete_callback, NULL);
}
static VFSNode* vfs_union_locate(VFSNode *node, const char *path) {
@ -157,16 +158,7 @@ static bool vfs_union_mount_internal(VFSNode *unode, const char *mountpoint, VFS
return false;
}
ListContainer *c = NULL, *p = unode->_members_;
create_container(&c)->data = mountee;
c->next = p;
if(p) {
p->prev = c;
}
unode->_members_ = c;
list_push(&unode->_members_, list_wrap_container(mountee));
unode->_primary_member_ = mountee;
return true;