Reference_Linking/rl.c

111 Zeilen
2.6 KiB
C

#include "rl.h"
#include <stdbool.h>
#include <malloc.h>
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.)