104 Zeilen
2.5 KiB
C
104 Zeilen
2.5 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*)((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 = NULL;
|
||
|
box->last = NULL;
|
||
|
box->destructor = destructor;
|
||
|
reference->prev = NULL;
|
||
|
reference->next = NULL;
|
||
|
reference->owner = PTR_TO_RLBOX(owner);
|
||
|
reference->ref = box + RLBOX_SIZE;
|
||
|
}
|
||
|
|
||
|
// reference may not point to a valid object
|
||
|
inline void rl_set(Rl* reference, const void* owner, const Rl* copy) {
|
||
|
reference->prev = PTR_TO_RLBOX(copy->ref)->last;
|
||
|
reference->next = NULL;
|
||
|
reference->owner = PTR_TO_RLBOX(owner);
|
||
|
reference->ref = copy->ref;
|
||
|
reference->prev->next = 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(search_root(obj))
|
||
|
return;
|
||
|
|
||
|
obj->destructor(reference->ref);
|
||
|
free(obj);
|
||
|
}
|
||
|
|
||
|
//TODO foolproofed versions (with NULL, prev set, etc.)
|