/media/libnestegg/src/halloc.c
http://github.com/zpao/v8monkey · C · 254 lines · 149 code · 44 blank · 61 comment · 22 complexity · 666028427f11727fabbec80a0ef9bacf MD5 · raw file
- /*
- * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved.
- *
- * Hierarchical memory allocator, 1.2.1
- * http://swapped.cc/halloc
- */
- /*
- * The program is distributed under terms of BSD license.
- * You can obtain the copy of the license by visiting:
- *
- * http://www.opensource.org/licenses/bsd-license.php
- */
- #include <stdlib.h> /* realloc */
- #include <string.h> /* memset & co */
- #include "halloc.h"
- #include "align.h"
- #include "hlist.h"
- /*
- * block control header
- */
- typedef struct hblock
- {
- #ifndef NDEBUG
- #define HH_MAGIC 0x20040518L
- long magic;
- #endif
- hlist_item_t siblings; /* 2 pointers */
- hlist_head_t children; /* 1 pointer */
- max_align_t data[1]; /* not allocated, see below */
-
- } hblock_t;
- #define sizeof_hblock offsetof(hblock_t, data)
- /*
- *
- */
- realloc_t halloc_allocator = NULL;
- #define allocator halloc_allocator
- /*
- * static methods
- */
- static void _set_allocator(void);
- static void * _realloc(void * ptr, size_t n);
- static int _relate(hblock_t * b, hblock_t * p);
- static void _free_children(hblock_t * p);
- /*
- * Core API
- */
- void * halloc(void * ptr, size_t len)
- {
- hblock_t * p;
- /* set up default allocator */
- if (! allocator)
- {
- _set_allocator();
- assert(allocator);
- }
- /* calloc */
- if (! ptr)
- {
- if (! len)
- return NULL;
- p = allocator(0, len + sizeof_hblock);
- if (! p)
- return NULL;
- #ifndef NDEBUG
- p->magic = HH_MAGIC;
- #endif
- hlist_init(&p->children);
- hlist_init_item(&p->siblings);
- return p->data;
- }
- p = structof(ptr, hblock_t, data);
- assert(p->magic == HH_MAGIC);
- /* realloc */
- if (len)
- {
- p = allocator(p, len + sizeof_hblock);
- if (! p)
- return NULL;
- hlist_relink(&p->siblings);
- hlist_relink_head(&p->children);
-
- return p->data;
- }
- /* free */
- _free_children(p);
- hlist_del(&p->siblings);
- allocator(p, 0);
- return NULL;
- }
- void hattach(void * block, void * parent)
- {
- hblock_t * b, * p;
-
- if (! block)
- {
- assert(! parent);
- return;
- }
- /* detach */
- b = structof(block, hblock_t, data);
- assert(b->magic == HH_MAGIC);
- hlist_del(&b->siblings);
- if (! parent)
- return;
- /* attach */
- p = structof(parent, hblock_t, data);
- assert(p->magic == HH_MAGIC);
-
- /* sanity checks */
- assert(b != p); /* trivial */
- assert(! _relate(p, b)); /* heavy ! */
- hlist_add(&p->children, &b->siblings);
- }
- /*
- * malloc/free api
- */
- void * h_malloc(size_t len)
- {
- return halloc(0, len);
- }
- void * h_calloc(size_t n, size_t len)
- {
- void * ptr = halloc(0, len*=n);
- return ptr ? memset(ptr, 0, len) : NULL;
- }
- void * h_realloc(void * ptr, size_t len)
- {
- return halloc(ptr, len);
- }
- void h_free(void * ptr)
- {
- halloc(ptr, 0);
- }
- char * h_strdup(const char * str)
- {
- size_t len = strlen(str);
- char * ptr = halloc(0, len + 1);
- return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL;
- }
- /*
- * static stuff
- */
- static void _set_allocator(void)
- {
- void * p;
- assert(! allocator);
-
- /*
- * the purpose of the test below is to check the behaviour
- * of realloc(ptr, 0), which is defined in the standard
- * as an implementation-specific. if it returns zero,
- * then it's equivalent to free(). it can however return
- * non-zero, in which case it cannot be used for freeing
- * memory blocks and we'll need to supply our own version
- *
- * Thanks to Stan Tobias for pointing this tricky part out.
- */
- allocator = realloc;
- if (! (p = malloc(1)))
- /* hmm */
- return;
-
- if ((p = realloc(p, 0)))
- {
- /* realloc cannot be used as free() */
- allocator = _realloc;
- free(p);
- }
- }
- static void * _realloc(void * ptr, size_t n)
- {
- /*
- * free'ing realloc()
- */
- if (n)
- return realloc(ptr, n);
- free(ptr);
- return NULL;
- }
- static int _relate(hblock_t * b, hblock_t * p)
- {
- hlist_item_t * i;
- if (!b || !p)
- return 0;
- /*
- * since there is no 'parent' pointer, which would've allowed
- * O(log(n)) upward traversal, the check must use O(n) downward
- * iteration of the entire hierarchy; and this can be VERY SLOW
- */
- hlist_for_each(i, &p->children)
- {
- hblock_t * q = structof(i, hblock_t, siblings);
- if (q == b || _relate(b, q))
- return 1;
- }
- return 0;
- }
- static void _free_children(hblock_t * p)
- {
- hlist_item_t * i, * tmp;
-
- #ifndef NDEBUG
- /*
- * this catches loops in hierarchy with almost zero
- * overhead (compared to _relate() running time)
- */
- assert(p && p->magic == HH_MAGIC);
- p->magic = 0;
- #endif
- hlist_for_each_safe(i, tmp, &p->children)
- {
- hblock_t * q = structof(i, hblock_t, siblings);
- _free_children(q);
- allocator(q, 0);
- }
- }