diff options
| author | Daniel Stenberg <daniel@haxx.se> | 2002-05-14 08:19:57 +0000 |
|---|---|---|
| committer | Daniel Stenberg <daniel@haxx.se> | 2002-05-14 08:19:57 +0000 |
| commit | f143fd8e36078141efdf0ef9e590d792930637fb (patch) | |
| tree | 3d7a79599dca5ecb8d1163b33da4379f86f4093a /firmware/malloc/bysize.c | |
| parent | bbdeba6d8cb2f2066e22d39c2d5937d3608fd8ed (diff) | |
| download | rockbox-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.c | 451 |
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 |