#include "rl.h" #include #include struct RlBox { bool marked; Rl* first; Rl* last; Destructor destructor; }; #define RLBOX_SIZE sizeof(struct RlBox) #define PTR_TO_RLBOX(ptr) ((struct RlBox*)(((void*)ptr) - RLBOX_SIZE)) inline void rl_alloc(Rl* reference, const void* owner, const size_t size, const Destructor destructor) { struct RlBox* box = (struct RlBox*) malloc(RLBOX_SIZE + size); box->marked = false; box->first = reference; box->last = reference; box->destructor = destructor; reference->prev = NULL; reference->next = NULL; reference->owner = owner ? PTR_TO_RLBOX(owner) : NULL; reference->ref = (void*)box + RLBOX_SIZE; } inline void rl_set(Rl* reference, const void* owner, const Rl* copy) { struct RlBox* obj = PTR_TO_RLBOX(copy->ref); reference->prev = obj->last; reference->next = NULL; reference->owner = owner ? PTR_TO_RLBOX(owner) : NULL; reference->ref = copy->ref; obj->last->next = reference; obj->last = reference; } static void unmark(struct RlBox* obj) { if(!obj->marked) return; obj->marked = false; Rl* ref = obj->first; while(ref) { unmark(ref->owner); ref = ref->next; } } static bool search_root(struct RlBox* obj) { if(obj->marked) return false; obj->marked = true; Rl* ref = obj->first; while(ref) { if(!ref->owner || search_root(ref->owner)) { // mark reversal Rl* prev = ref->prev; while(prev) { unmark(prev->owner); prev = ref->prev; } obj->marked = false; // reordering if(ref != obj->first) { if(ref->next) ref->next->prev = ref->prev; else obj->last = ref->prev; ref->prev->next = ref->next; obj->first->prev = ref; obj->first = ref; } return true; } ref = ref->next; } return false; } inline void rl_free(Rl* reference) { struct RlBox* obj = PTR_TO_RLBOX(reference->ref); if(obj->first != reference) { if(reference->next) reference->next->prev = reference->prev; else obj->last = reference->prev; reference->prev->next = reference->next; return; } if(reference->next) { obj->first = reference->next; reference->next->prev = NULL; if(search_root(obj)) return; } obj->destructor(reference->ref); free(obj); } //TODO foolproofed versions (with NULL, prev set, etc.)