C
Chris M. Thomasson
Here is the pre-alpha v-0.0.1 impl:
_____________________________________________________________________
/* Simple Circular Doubly Linked-List
______________________________________________________________*/
#include <stddef.h>
#define CONTAINS(mp_this, mp_struct, mp_member) ((void*)( \
((ptrdiff_t)(mp_this)) - offsetof(mp_struct, mp_member) \
))
struct dlink {
struct dlink* next;
struct dlink* prev;
};
static void
dlinit(
struct dlink* const self
) {
self->next = self->prev = self;
}
static void
dlprv_insert(
struct dlink* const self,
struct dlink* const prev,
struct dlink* const next
) {
next->prev = self;
self->next = next;
self->prev = prev;
prev->next = self;
}
static void
dlprv_remove(
struct dlink* const prev,
struct dlink* const next
) {
next->prev = prev;
prev->next = next;
}
#define dlgethd(mp_self) ((mp_self)->next)
#define dlgettl(mp_self) ((mp_self)->prev)
#define dlpushhd(mp_self, mp_link) ( \
dlprv_insert((mp_link), (mp_self), (mp_self)->next) \
)
#define dlpushtl(mp_self, mp_link) ( \
dlprv_insert((mp_link), (mp_self)->prev, (mp_self)) \
)
#define dlpop(mp_self) ( \
dlprv_remove((mp_self)->prev, (mp_self)->next) \
)
/* Nasty Alignment HACK! ;^(...
______________________________________________________________*/
enum aligns_hack_enum {
ALIGNS_HACK_ENUM_1, ALIGNS_HACK_ENUM_2
};
struct aligns_hack {
char char_;
short int short_;
int int_;
long intlong_;
float float_;
double double_;
long double long_double_;
void* ptr_;
void* (*fptr_) (void*);
enum aligns_hack_enum enum_;
};
struct aligner_hack {
char pad;
struct aligns_hack aligns_hack;
};
#define ALIGN_MAX offsetof(struct aligner_hack, aligns_hack)
#define ALIGN_SIZE(mp_this, mp_type, mp_align) ((mp_type)( \
(((ptrdiff_t const)(mp_this)) + (mp_align) - 1) \
& (-(mp_align)) \
))
/* Simple General Purpose Region Allocator
______________________________________________________________*/
#include <stdlib.h>
#include <errno.h>
/* nasty <errno.h> hack wrt ENOMEM!!!!!! */
#if ! defined(ENOMEM)
# define ENOMEM -666
#endif
#define REGION_SIZE (1024 * 64)
struct region {
unsigned char buf[REGION_SIZE];
size_t offset;
struct dlink dlink;
};
struct ralloc {
struct dlink regions;
};
static void*
region_prv_alloc(
struct region* const self,
size_t const size
) {
size_t const offset = self->offset;
if (offset + size <= REGION_SIZE) {
self->offset = offset + size;
return self->buf + offset;
}
return NULL;
}
static struct region*
ralloc_prv_expand(
struct ralloc* const self
) {
struct region* const region = malloc(sizeof(*region));
if (region) {
region->offset = 0;
dlpushhd(&self->regions, ®ion->dlink);
return region;
}
return NULL;
}
static int
ralloc_create(
struct ralloc* const self
) {
dlinit(&self->regions);
if (ralloc_prv_expand(self)) {
return 0;
}
return ENOMEM;
}
static void
rflush(
struct ralloc* const self
) {
struct region* region =
CONTAINS(dlgethd(&self->regions), struct region, dlink);
if (region->dlink.next != &self->regions) {
region = CONTAINS(region->dlink.next, struct region, dlink);
while (®ion->dlink != &self->regions) {
struct region* next =
CONTAINS(region->dlink.next, struct region, dlink);
dlpop(®ion->dlink);
free(region);
region = next;
}
}
region = CONTAINS(dlgethd(&self->regions), struct region, dlink);
region->offset = 0;
}
static void*
ralloc(
struct ralloc* const self,
size_t size
) {
struct region* region =
CONTAINS(dlgethd(&self->regions), struct region, dlink);
size = (size) ? ALIGN_SIZE(size, size_t, ALIGN_MAX) : ALIGN_MAX;
while (®ion->dlink != &self->regions) {
void* const mem = region_prv_alloc(region, size);
if (mem) {
return mem;
}
region = CONTAINS(region->dlink.next, struct region, dlink);
}
region = ralloc_prv_expand(self);
if (region) {
return region_prv_alloc(region, size);
}
return NULL;
}
static void
ralloc_destroy(
struct ralloc* const self
) {
rflush(self);
free(CONTAINS(dlgethd(&self->regions), struct region, dlink));
}
/* Simple Example Usage
______________________________________________________________*/
#define RUNS 10
#define DEPTH (1024 * 64)
struct node {
struct node* next;
};
static struct node* g_list = NULL;
static struct ralloc g_ralloc;
int main(void) {
if (! ralloc_create(&g_ralloc)) {
unsigned i, r;
for (r = 0; r < RUNS; ++r) {
/* create linked-list */
for (i = 0; i < DEPTH; ++i) {
struct node* n = ralloc(&g_ralloc, sizeof(*n));
if (! n) { break; }
n->next = g_list;
g_list = n;
}
/* destroy linked-list */
g_list = NULL;
rflush(&g_ralloc);
}
ralloc_destroy(&g_ralloc);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
_____________________________________________________________________
Caveats:
- Can only allocate sizes <= `REGION_SIZE'! ;^(... However, this can be
omitted by using some tricks.
- Can only free all memory in one shot.
- Cannot free individual objects; this can be omitted by using an existing
reap algorithm.
- Uses nasty alignment hack.
- Uses nasty errno hack; however, this can be omitted.
Advantages:
- Can partition regions on a per-data-structure basis.
- Can destroy memory that makes up nodes within a container without explicit
traversal.
- Can potentially help remove memory leaks.
- Do not need to free individual objects.
What do you think?
_____________________________________________________________________
/* Simple Circular Doubly Linked-List
______________________________________________________________*/
#include <stddef.h>
#define CONTAINS(mp_this, mp_struct, mp_member) ((void*)( \
((ptrdiff_t)(mp_this)) - offsetof(mp_struct, mp_member) \
))
struct dlink {
struct dlink* next;
struct dlink* prev;
};
static void
dlinit(
struct dlink* const self
) {
self->next = self->prev = self;
}
static void
dlprv_insert(
struct dlink* const self,
struct dlink* const prev,
struct dlink* const next
) {
next->prev = self;
self->next = next;
self->prev = prev;
prev->next = self;
}
static void
dlprv_remove(
struct dlink* const prev,
struct dlink* const next
) {
next->prev = prev;
prev->next = next;
}
#define dlgethd(mp_self) ((mp_self)->next)
#define dlgettl(mp_self) ((mp_self)->prev)
#define dlpushhd(mp_self, mp_link) ( \
dlprv_insert((mp_link), (mp_self), (mp_self)->next) \
)
#define dlpushtl(mp_self, mp_link) ( \
dlprv_insert((mp_link), (mp_self)->prev, (mp_self)) \
)
#define dlpop(mp_self) ( \
dlprv_remove((mp_self)->prev, (mp_self)->next) \
)
/* Nasty Alignment HACK! ;^(...
______________________________________________________________*/
enum aligns_hack_enum {
ALIGNS_HACK_ENUM_1, ALIGNS_HACK_ENUM_2
};
struct aligns_hack {
char char_;
short int short_;
int int_;
long intlong_;
float float_;
double double_;
long double long_double_;
void* ptr_;
void* (*fptr_) (void*);
enum aligns_hack_enum enum_;
};
struct aligner_hack {
char pad;
struct aligns_hack aligns_hack;
};
#define ALIGN_MAX offsetof(struct aligner_hack, aligns_hack)
#define ALIGN_SIZE(mp_this, mp_type, mp_align) ((mp_type)( \
(((ptrdiff_t const)(mp_this)) + (mp_align) - 1) \
& (-(mp_align)) \
))
/* Simple General Purpose Region Allocator
______________________________________________________________*/
#include <stdlib.h>
#include <errno.h>
/* nasty <errno.h> hack wrt ENOMEM!!!!!! */
#if ! defined(ENOMEM)
# define ENOMEM -666
#endif
#define REGION_SIZE (1024 * 64)
struct region {
unsigned char buf[REGION_SIZE];
size_t offset;
struct dlink dlink;
};
struct ralloc {
struct dlink regions;
};
static void*
region_prv_alloc(
struct region* const self,
size_t const size
) {
size_t const offset = self->offset;
if (offset + size <= REGION_SIZE) {
self->offset = offset + size;
return self->buf + offset;
}
return NULL;
}
static struct region*
ralloc_prv_expand(
struct ralloc* const self
) {
struct region* const region = malloc(sizeof(*region));
if (region) {
region->offset = 0;
dlpushhd(&self->regions, ®ion->dlink);
return region;
}
return NULL;
}
static int
ralloc_create(
struct ralloc* const self
) {
dlinit(&self->regions);
if (ralloc_prv_expand(self)) {
return 0;
}
return ENOMEM;
}
static void
rflush(
struct ralloc* const self
) {
struct region* region =
CONTAINS(dlgethd(&self->regions), struct region, dlink);
if (region->dlink.next != &self->regions) {
region = CONTAINS(region->dlink.next, struct region, dlink);
while (®ion->dlink != &self->regions) {
struct region* next =
CONTAINS(region->dlink.next, struct region, dlink);
dlpop(®ion->dlink);
free(region);
region = next;
}
}
region = CONTAINS(dlgethd(&self->regions), struct region, dlink);
region->offset = 0;
}
static void*
ralloc(
struct ralloc* const self,
size_t size
) {
struct region* region =
CONTAINS(dlgethd(&self->regions), struct region, dlink);
size = (size) ? ALIGN_SIZE(size, size_t, ALIGN_MAX) : ALIGN_MAX;
while (®ion->dlink != &self->regions) {
void* const mem = region_prv_alloc(region, size);
if (mem) {
return mem;
}
region = CONTAINS(region->dlink.next, struct region, dlink);
}
region = ralloc_prv_expand(self);
if (region) {
return region_prv_alloc(region, size);
}
return NULL;
}
static void
ralloc_destroy(
struct ralloc* const self
) {
rflush(self);
free(CONTAINS(dlgethd(&self->regions), struct region, dlink));
}
/* Simple Example Usage
______________________________________________________________*/
#define RUNS 10
#define DEPTH (1024 * 64)
struct node {
struct node* next;
};
static struct node* g_list = NULL;
static struct ralloc g_ralloc;
int main(void) {
if (! ralloc_create(&g_ralloc)) {
unsigned i, r;
for (r = 0; r < RUNS; ++r) {
/* create linked-list */
for (i = 0; i < DEPTH; ++i) {
struct node* n = ralloc(&g_ralloc, sizeof(*n));
if (! n) { break; }
n->next = g_list;
g_list = n;
}
/* destroy linked-list */
g_list = NULL;
rflush(&g_ralloc);
}
ralloc_destroy(&g_ralloc);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
_____________________________________________________________________
Caveats:
- Can only allocate sizes <= `REGION_SIZE'! ;^(... However, this can be
omitted by using some tricks.
- Can only free all memory in one shot.
- Cannot free individual objects; this can be omitted by using an existing
reap algorithm.
- Uses nasty alignment hack.
- Uses nasty errno hack; however, this can be omitted.
Advantages:
- Can partition regions on a per-data-structure basis.
- Can destroy memory that makes up nodes within a container without explicit
traversal.
- Can potentially help remove memory leaks.
- Do not need to free individual objects.
What do you think?