mirror of
https://github.com/libretro/libretro-tyrquake.git
synced 2024-11-29 03:00:27 +00:00
[PATCH] String Trees
This defines structures for an RB tree of strings. The intended use of this is for quick insertion sort of filenames for tab completion and any other uses. We use the temp hunk for (reasonably) efficient allocations - at least a little better than loading up the zone with hundreds of small allocations. Signed-off-by: Tyrann <tyrann@disenchant.net>
This commit is contained in:
parent
dd63643adf
commit
b743cd0fec
125
common/shell.c
125
common/shell.c
@ -31,6 +31,131 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#include "sys.h"
|
||||
#include "zone.h"
|
||||
|
||||
/*
|
||||
* When we want to build up temporary trees of strings for completions, file
|
||||
* listings, etc. we can use the "temp" hunk since we don't want to keep them
|
||||
* around. These allocator functions attempt to make more efficient use of the
|
||||
* hunk space by keeping the tree nodes together in blocks and allocating
|
||||
* strings right next to each other.
|
||||
*/
|
||||
static struct rb_string_node *st_node_next;
|
||||
static int st_node_space;
|
||||
static char *st_string_next;
|
||||
static int st_string_space;
|
||||
|
||||
#define ST_NODE_CHUNK 2048 /* 2kB / 16B => 128 nodes */
|
||||
#define ST_STRING_CHUNK 4096 /* 4k of strings together */
|
||||
|
||||
void
|
||||
ST_AllocInit(void)
|
||||
{
|
||||
/* Init the temp hunk */
|
||||
st_node_next = Hunk_TempAlloc(ST_NODE_CHUNK);
|
||||
st_node_space = ST_NODE_CHUNK;
|
||||
|
||||
/* Allocate string space on demand */
|
||||
st_string_space = 0;
|
||||
}
|
||||
|
||||
struct rb_string_node *
|
||||
ST_AllocNode(void)
|
||||
{
|
||||
struct rb_string_node *ret = NULL;
|
||||
|
||||
if (st_node_space < sizeof(struct rb_string_node)) {
|
||||
st_node_next = Hunk_TempAllocExtend(ST_NODE_CHUNK);
|
||||
st_node_space = st_node_next ? ST_NODE_CHUNK : 0;
|
||||
}
|
||||
if (st_node_space >= sizeof(struct rb_string_node)) {
|
||||
ret = st_node_next++;
|
||||
st_node_space -= sizeof(struct rb_string_node);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
ST_AllocString(unsigned int length)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
if (st_string_space < length) {
|
||||
/*
|
||||
* Note: might want to consider different allocation scheme here if we
|
||||
* end up wasting a lot of space. E.g. if space wasted > 16, may as
|
||||
* well use another chunk. This may cause excessive calls to
|
||||
* Cache_FreeHigh, so maybe only do it if wasting more than that
|
||||
* (32/64/?).
|
||||
*/
|
||||
Con_DPrintf("%s: %i bytes wasted\n", __func__, st_string_space);
|
||||
st_string_next = Hunk_TempAllocExtend(ST_STRING_CHUNK);
|
||||
st_string_space = st_string_next ? ST_STRING_CHUNK : 0;
|
||||
}
|
||||
if (st_string_space >= length) {
|
||||
ret = st_string_next;
|
||||
st_string_next += length;
|
||||
st_string_space -= length;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert string node "node" into rb_tree rooted at "root"
|
||||
*/
|
||||
qboolean
|
||||
ST_Insert(struct rb_string_root *root, struct rb_string_node *node)
|
||||
{
|
||||
struct rb_node **p = &root->root.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct rb_string_node *sn;
|
||||
unsigned int len;
|
||||
int cmp;
|
||||
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
sn = rb_entry(parent, struct rb_string_node, node);
|
||||
cmp = strcasecmp(node->string, sn->string);
|
||||
if (cmp < 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (cmp > 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return false; /* string already present */
|
||||
}
|
||||
root->entries++;
|
||||
len = strlen(node->string);
|
||||
if (len > root->maxlen)
|
||||
root->maxlen = len;
|
||||
rb_link_node(&node->node, parent, p);
|
||||
rb_insert_color(&node->node, &root->root);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert string into rb tree, allocating the string dynamically. If n
|
||||
* is NULL, the node structure is also allocated for the caller.
|
||||
* NOTE: These allocations are only on the Temp hunk.
|
||||
*/
|
||||
qboolean
|
||||
ST_InsertAlloc(struct rb_string_root *root, const char *s,
|
||||
struct rb_string_node *n)
|
||||
{
|
||||
qboolean ret = false;
|
||||
|
||||
if (!n)
|
||||
n = ST_AllocNode();
|
||||
if (n)
|
||||
n->string = ST_AllocString(strlen(s) + 1);
|
||||
if (n && n->string) {
|
||||
strcpy(n->string, s);
|
||||
ret = ST_Insert(root, n);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char **completions_list = NULL;
|
||||
static int num_completions = 0;
|
||||
|
||||
|
@ -21,7 +21,35 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#ifndef SHELL_H
|
||||
#define SHELL_H
|
||||
|
||||
#include "qtypes.h"
|
||||
#include "rb_tree.h"
|
||||
|
||||
/*
|
||||
* We keep track of the number of entries in the tree as well as the longest
|
||||
* entry in the tree. This info is used for displaying lists on the console.
|
||||
*/
|
||||
struct rb_string_root {
|
||||
unsigned int entries;
|
||||
unsigned int maxlen;
|
||||
struct rb_root root;
|
||||
};
|
||||
|
||||
#define RB_STRING_ROOT (struct rb_string_root) { 0, 0, RB_ROOT }
|
||||
|
||||
/*
|
||||
* String node is simply an rb_tree node using the string as the index (and
|
||||
* the only data as well).
|
||||
*/
|
||||
struct rb_string_node {
|
||||
char *string;
|
||||
struct rb_node node;
|
||||
};
|
||||
|
||||
void ST_AllocInit(void);
|
||||
qboolean ST_Insert(struct rb_string_root *root, struct rb_string_node *node);
|
||||
qboolean ST_InsertAlloc(struct rb_string_root *root, const char *s,
|
||||
struct rb_string_node *n);
|
||||
|
||||
/*
|
||||
* Set up some basic completion helpers
|
||||
* FIXME - document the API
|
||||
|
Loading…
Reference in New Issue
Block a user