forked from len0rd/rockbox
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
This commit is contained in:
parent
bbdeba6d8c
commit
f143fd8e36
14 changed files with 214 additions and 77 deletions
451
firmware/malloc/bysize.c
Normal file
451
firmware/malloc/bysize.c
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue