summaryrefslogtreecommitdiff
path: root/firmware/malloc/bysize.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2002-05-14 08:19:57 +0000
committerDaniel Stenberg <daniel@haxx.se>2002-05-14 08:19:57 +0000
commitf143fd8e36078141efdf0ef9e590d792930637fb (patch)
tree3d7a79599dca5ecb8d1163b33da4379f86f4093a /firmware/malloc/bysize.c
parentbbdeba6d8cb2f2066e22d39c2d5937d3608fd8ed (diff)
downloadrockbox-f143fd8e36078141efdf0ef9e590d792930637fb.zip
rockbox-f143fd8e36078141efdf0ef9e590d792930637fb.tar.gz
rockbox-f143fd8e36078141efdf0ef9e590d792930637fb.tar.bz2
rockbox-f143fd8e36078141efdf0ef9e590d792930637fb.tar.xz
Moved the malloc system into the firmware/malloc/ directory, removed the
implementation files from the test/malloc/ directory, leaving only test files there. Added headers, corrected a few minor documenational errors. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@571 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/malloc/bysize.c')
-rw-r--r--firmware/malloc/bysize.c451
1 files changed, 451 insertions, 0 deletions
diff --git a/firmware/malloc/bysize.c b/firmware/malloc/bysize.c
new file mode 100644
index 0000000..c8e2759
--- /dev/null
+++ b/firmware/malloc/bysize.c
@@ -0,0 +1,451 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Daniel Stenberg
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+/*****************************************************************************
+ *
+ * Size-sorted list/tree functions.
+ *
+ * Author: Daniel Stenberg
+ * Date: March 7, 1997
+ * Version: 2.0
+ * Email: daniel@haxx.se
+ *
+ * v2.0
+ * - Added SPLAY TREE functionality.
+ *
+ * Adds and removes CHUNKS from a list or tree.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define SPLAY /* we use the splay version as that is much faster when the
+ amount of blocks grow */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef SPLAY /* these routines are for the non-splay version */
+
+struct ChunkInfo {
+ struct ChunkInfo *larger;
+ struct ChunkInfo *smaller;
+ size_t size;
+};
+
+/* the CHUNK list anchor */
+struct ChunkInfo *chunkHead=NULL;
+
+/***********************************************************************
+
+ findchunkbysize()
+
+ Find the chunk that is smaller than the input size. Returns
+ NULL if none is.
+
+ **********************************************************************/
+
+static struct ChunkInfo *findchunkbysize(size_t size)
+{
+ struct ChunkInfo *test = chunkHead;
+ struct ChunkInfo *smaller = NULL;
+ while(test && (test->size < size)) {
+ smaller = test;
+ test = test->larger;
+ }
+ return smaller;
+}
+
+/***********************************************************************
+
+ remove_chunksize()
+
+ Remove the chunk from the size-sorted list.
+ ***********************************************************************/
+
+void bmalloc_remove_chunksize(void *data)
+{
+ struct ChunkInfo *chunk = (struct ChunkInfo *)data;
+ if(chunk->smaller)
+ chunk->smaller->larger = chunk->larger;
+ else {
+ /* if this has no smaller, this is the head */
+ chunkHead = chunk->larger; /* new head */
+ }
+ if(chunk->larger)
+ chunk->larger->smaller = chunk->smaller;
+}
+
+void bmalloc_insert_bysize(char *data, size_t size)
+{
+ struct ChunkInfo *newchunk = (struct ChunkInfo *)data;
+ struct ChunkInfo *chunk = findchunkbysize ( size );
+
+ newchunk->size = size;
+
+ if(chunk) {
+ /* 'chunk' is smaller than size, append the new chunk ahead of this */
+ newchunk->smaller = chunk;
+ newchunk->larger = chunk->larger;
+ if(chunk->larger)
+ chunk->larger->smaller = newchunk;
+ chunk->larger = newchunk;
+ }
+ else {
+ /* smallest CHUNK around, append first in the list */
+ newchunk->larger = chunkHead;
+ newchunk->smaller = NULL;
+
+ if(chunkHead)
+ chunkHead->smaller = newchunk;
+ chunkHead = newchunk;
+ }
+}
+
+char *bmalloc_obtainbysize( size_t size)
+{
+ struct ChunkInfo *chunk = findchunkbysize( size );
+
+ if(!chunk) {
+ if(size <= (chunkHead->size))
+ /* there is no smaller CHUNK, use the first one (if we fit within that)
+ */
+ chunk = chunkHead;
+ }
+ else
+ /* we're on the last CHUNK that is smaller than requested, step onto
+ the bigger one */
+ chunk = chunk->larger;
+
+ if(chunk) {
+ bmalloc_remove_chunksize( chunk ); /* unlink size-wise */
+ return (char *)chunk;
+ }
+ else
+ return NULL;
+}
+
+void bmalloc_print_sizes(void)
+{
+ struct ChunkInfo *chunk = chunkHead;
+ printf("List of CHUNKS (in size order):\n");
+#if 1
+ while(chunk) {
+ printf(" START %p END %p SIZE %d\n",
+ chunk, (char *)chunk+chunk->size, chunk->size);
+ chunk = chunk->larger;
+ }
+#endif
+ printf("End of CHUNKS:\n");
+}
+
+#else /* Here follows all routines dealing with the SPLAY TREES */
+
+typedef struct tree_node Tree;
+struct tree_node {
+ Tree *smaller; /* smaller node */
+ Tree *larger; /* larger node */
+ Tree *same; /* points to a node with identical key */
+ int key; /* the "sort" key */
+};
+
+Tree *chunkHead = NULL; /* the root */
+
+#define compare(i,j) ((i)-(j))
+
+/* Set this to a key value that will *NEVER* appear otherwise */
+#define KEY_NOTUSED -1
+
+/*
+ * Splay using the key i (which may or may not be in the tree.) The starting
+ * root is t. Weight fields are maintained.
+ */
+static
+Tree * splay (int i, Tree *t)
+{
+ Tree N, *l, *r, *y;
+ int comp;
+
+ if (t == NULL)
+ return t;
+ N.smaller = N.larger = NULL;
+ l = r = &N;
+
+ for (;;) {
+ comp = compare(i, t->key);
+ if (comp < 0) {
+ if (t->smaller == NULL)
+ break;
+ if (compare(i, t->smaller->key) < 0) {
+ y = t->smaller; /* rotate smaller */
+ t->smaller = y->larger;
+ y->larger = t;
+
+ t = y;
+ if (t->smaller == NULL)
+ break;
+ }
+ r->smaller = t; /* link smaller */
+ r = t;
+ t = t->smaller;
+ }
+ else if (comp > 0) {
+ if (t->larger == NULL)
+ break;
+ if (compare(i, t->larger->key) > 0) {
+ y = t->larger; /* rotate larger */
+ t->larger = y->smaller;
+ y->smaller = t;
+ t = y;
+ if (t->larger == NULL)
+ break;
+ }
+ l->larger = t; /* link larger */
+ l = t;
+ t = t->larger;
+ }
+ else {
+ break;
+ }
+ }
+
+ l->larger = r->smaller = NULL;
+
+ l->larger = t->smaller; /* assemble */
+ r->smaller = t->larger;
+ t->smaller = N.larger;
+ t->larger = N.smaller;
+
+ return t;
+}
+
+/* Insert key i into the tree t. Return a pointer to the resulting tree or
+ NULL if something went wrong. */
+static
+Tree *insert(int i, Tree *t, Tree *new)
+{
+ if (new == NULL) {
+ return t;
+ }
+
+ if (t != NULL) {
+ t = splay(i,t);
+ if (compare(i, t->key)==0) {
+ /* it already exists one of this size */
+
+ new->same = t;
+ new->key = i;
+ new->smaller = t->smaller;
+ new->larger = t->larger;
+
+ t->smaller = new;
+ t->key = KEY_NOTUSED;
+
+ return new; /* new root node */
+ }
+ }
+
+ if (t == NULL) {
+ new->smaller = new->larger = NULL;
+ }
+ else if (compare(i, t->key) < 0) {
+ new->smaller = t->smaller;
+ new->larger = t;
+ t->smaller = NULL;
+ }
+ else {
+ new->larger = t->larger;
+ new->smaller = t;
+ t->larger = NULL;
+ }
+ new->key = i;
+
+ new->same = NULL; /* no identical node (yet) */
+
+ return new;
+}
+
+/* Finds and deletes the best-fit node from the tree. Return a pointer to the
+ resulting tree. best-fit means the smallest node that fits the requested
+ size. */
+static
+Tree *removebestfit(int i, Tree *t, Tree **removed)
+{
+ Tree *x;
+
+ if (t==NULL)
+ return NULL;
+ t = splay(i,t);
+ if(compare(i, t->key) > 0) {
+ /* too small node, try the larger chain */
+ if(t->larger)
+ t=splay(t->larger->key, t);
+ else {
+ /* fail */
+ *removed = NULL;
+ return t;
+ }
+ }
+
+ if (compare(i, t->key) <= 0) { /* found it */
+
+ /* FIRST! Check if there is a list with identical sizes */
+ x = t->same;
+ if(x) {
+ /* there is, pick one from the list */
+
+ /* 'x' is the new root node */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+ *removed = t;
+ return x; /* new root */
+ }
+
+ if (t->smaller == NULL) {
+ x = t->larger;
+ }
+ else {
+ x = splay(i, t->smaller);
+ x->larger = t->larger;
+ }
+ *removed = t;
+
+ return x;
+ }
+ else {
+ *removed = NULL; /* no match */
+ return t; /* It wasn't there */
+ }
+}
+
+
+/* Deletes the node we point out from the tree if it's there. Return a pointer
+ to the resulting tree. */
+static
+Tree *removebyaddr(Tree *t, Tree *remove)
+{
+ Tree *x;
+
+ if (!t || !remove)
+ return NULL;
+
+ if(KEY_NOTUSED == remove->key) {
+ /* just unlink ourselves nice and quickly: */
+ remove->smaller->same = remove->same;
+ if(remove->same)
+ remove->same->smaller = remove->smaller;
+ /* voila, we're done! */
+ return t;
+ }
+
+ t = splay(remove->key,t);
+
+ /* Check if there is a list with identical sizes */
+
+ x = t->same;
+ if(x) {
+ /* 'x' is the new root node */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+
+ return x; /* new root */
+ }
+
+ /* Remove the actualy root node: */
+
+ if (t->smaller == NULL) {
+ x = t->larger;
+ }
+ else {
+ x = splay(remove->key, t->smaller);
+ x->larger = t->larger;
+ }
+
+ return x;
+}
+
+#ifdef DEBUG
+static
+int printtree(Tree * t, int d, char output)
+{
+ int distance=0;
+ Tree *node;
+ int i;
+ if (t == NULL)
+ return 0;
+ distance += printtree(t->larger, d+1, output);
+ for (i=0; i<d; i++)
+ if(output)
+ printf(" ");
+
+ if(output) {
+ printf("%d[%d]", t->key, i);
+ }
+
+ for(node = t->same; node; node = node->same) {
+ distance += i; /* this has the same "virtual" distance */
+
+ if(output)
+ printf(" [+]");
+ }
+ if(output)
+ puts("");
+
+ distance += i;
+ distance += printtree(t->smaller, d+1, output);
+ return distance;
+}
+#endif
+
+/* Here follow the look-alike interface so that the tree-function names are
+ the same as the list-ones to enable easy interchange */
+
+void bmalloc_remove_chunksize(void *data)
+{
+ chunkHead = removebyaddr(chunkHead, data);
+}
+
+void bmalloc_insert_bysize(char *data, size_t size)
+{
+ chunkHead = insert(size, chunkHead, (Tree *)data);
+}
+
+char *bmalloc_obtainbysize( size_t size)
+{
+ Tree *receive;
+ chunkHead = removebestfit(size, chunkHead, &receive);
+ return (char *)receive;
+}
+
+#ifdef DEBUG
+void bmalloc_print_sizes(void)
+{
+ printtree(chunkHead, 0, 1);
+}
+#endif
+
+#endif