forked from github/server
rt_find and it_find use new improved critbit-tree
critbit update testing the test suite
This commit is contained in:
parent
f47f83ceca
commit
7f7c883583
|
@ -1,6 +1,3 @@
|
|||
/* this file should only be included by laws.c, never compiled on its own
|
||||
* (it does not even include all the headers needed to do so).
|
||||
**/
|
||||
#include <platform.h>
|
||||
#include <kernel/types.h>
|
||||
#include "laws.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void market_curse(CuTest * tc)
|
||||
static void test_market_curse(CuTest * tc)
|
||||
{
|
||||
region *r;
|
||||
building *b;
|
||||
|
@ -26,16 +26,21 @@ static void market_curse(CuTest * tc)
|
|||
faction *f;
|
||||
int x, y;
|
||||
const char *names[4] = { "herb", "herbs", "balm", "balms" };
|
||||
terrain_type *terrain;
|
||||
resource_type *hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED);
|
||||
item_type *htype = new_itemtype(hres, ITF_HERB, 0, 0);
|
||||
resource_type *lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED);
|
||||
item_type *ltype = new_itemtype(lres, ITF_NONE, 0, 0);
|
||||
luxury_type *lux = new_luxurytype(ltype, 0);
|
||||
const terrain_type *terrain;
|
||||
resource_type *hres, *lres;
|
||||
item_type *htype, *ltype;
|
||||
luxury_type *lux;
|
||||
building_type *btype;
|
||||
race *rc = rc_add(rc_new("human"));
|
||||
|
||||
free_gamedata();
|
||||
test_cleanup();
|
||||
test_create_world();
|
||||
|
||||
hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED);
|
||||
htype = new_itemtype(hres, ITF_HERB, 0, 0);
|
||||
lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED);
|
||||
ltype = new_itemtype(lres, ITF_NONE, 0, 0);
|
||||
lux = new_luxurytype(ltype, 0);
|
||||
|
||||
set_param(&global.parameters, "rules.region_owners", "1");
|
||||
|
||||
|
@ -43,12 +48,16 @@ static void market_curse(CuTest * tc)
|
|||
btype->_name = "market";
|
||||
bt_register(btype);
|
||||
|
||||
terrain = test_create_terrain("plain", LAND_REGION | WALK_INTO);
|
||||
terrain = get_terrain("plain");
|
||||
|
||||
for (x = 0; x != 3; ++x) {
|
||||
for (y = 0; y != 3; ++y) {
|
||||
r = new_region(x, y, NULL, 0);
|
||||
terraform_region(r, terrain);
|
||||
r = findregion(x, y);
|
||||
if (!r) {
|
||||
r = test_create_region(x, y, terrain);
|
||||
} else {
|
||||
terraform_region(r, terrain);
|
||||
}
|
||||
rsetpeasants(r, 5000);
|
||||
r_setdemand(r, lux, 0);
|
||||
rsetherbtype(r, htype);
|
||||
|
@ -59,8 +68,8 @@ static void market_curse(CuTest * tc)
|
|||
b->flags |= BLD_WORKING;
|
||||
b->size = b->type->maxsize;
|
||||
|
||||
f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0);
|
||||
u = create_unit(r, f, 1, f->race, 0, 0, 0);
|
||||
f = test_create_faction(0);
|
||||
u = test_create_unit(f, r);
|
||||
u_set_building(u, b);
|
||||
|
||||
do_markets();
|
||||
|
@ -72,6 +81,6 @@ static void market_curse(CuTest * tc)
|
|||
CuSuite *get_market_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, market_curse);
|
||||
SUITE_ADD_TEST(suite, test_market_curse);
|
||||
return suite;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
/* util includes */
|
||||
#include <util/attrib.h>
|
||||
#include <util/base36.h>
|
||||
#include <util/critbit.h>
|
||||
#include <util/event.h>
|
||||
#include <util/functions.h>
|
||||
#include <util/goodies.h>
|
||||
|
@ -55,13 +56,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
resource_type *resourcetypes;
|
||||
static critbit_tree cb_resources;
|
||||
static critbit_tree cb_items;
|
||||
luxury_type *luxurytypes;
|
||||
potion_type *potiontypes;
|
||||
|
||||
#define IMAXHASH 127
|
||||
static item_type *itemtypes[IMAXHASH];
|
||||
|
||||
static int res_changeaura(unit * u, const resource_type * rtype, int delta)
|
||||
{
|
||||
assert(rtype != NULL);
|
||||
|
@ -173,14 +172,13 @@ resource_type *new_resourcetype(const char **names, const char **appearances,
|
|||
|
||||
void it_register(item_type * itype)
|
||||
{
|
||||
int hash = hashstring(itype->rtype->_name[0]);
|
||||
int key = hash % IMAXHASH;
|
||||
item_type **p_itype = &itemtypes[key];
|
||||
while (*p_itype && *p_itype != itype)
|
||||
p_itype = &(*p_itype)->next;
|
||||
if (*p_itype == NULL) {
|
||||
itype->rtype->itype = itype;
|
||||
*p_itype = itype;
|
||||
char buffer[64];
|
||||
const char * name = itype->rtype->_name[0];
|
||||
size_t len = strlen(name);
|
||||
|
||||
assert(len<sizeof(buffer)-sizeof(itype));
|
||||
cb_new_kv(name, &itype, sizeof(itype), buffer);
|
||||
if (cb_insert(&cb_items, buffer, len+1+sizeof(itype))) {
|
||||
rt_register(itype->rtype);
|
||||
}
|
||||
}
|
||||
|
@ -294,16 +292,13 @@ potion_type *new_potiontype(item_type * itype, int level)
|
|||
|
||||
void rt_register(resource_type * rtype)
|
||||
{
|
||||
resource_type **prtype = &resourcetypes;
|
||||
char buffer[64];
|
||||
const char * name = rtype->_name[0];
|
||||
size_t len = strlen(name);
|
||||
|
||||
if (!rtype->hashkey) {
|
||||
rtype->hashkey = hashstring(rtype->_name[0]);
|
||||
}
|
||||
while (*prtype && *prtype != rtype)
|
||||
prtype = &(*prtype)->next;
|
||||
if (*prtype == NULL) {
|
||||
*prtype = rtype;
|
||||
}
|
||||
assert(len<sizeof(buffer)-sizeof(rtype));
|
||||
cb_new_kv(name, &rtype, sizeof(rtype), buffer);
|
||||
cb_insert(&cb_resources, buffer, len+1+sizeof(rtype));
|
||||
}
|
||||
|
||||
const resource_type *item2resource(const item_type * itype)
|
||||
|
@ -347,17 +342,13 @@ const potion_type *resource2potion(const resource_type * rtype)
|
|||
|
||||
resource_type *rt_find(const char *name)
|
||||
{
|
||||
unsigned int hash = hashstring(name);
|
||||
resource_type *rtype;
|
||||
const void * matches;
|
||||
resource_type *result = 0;
|
||||
|
||||
for (rtype = resourcetypes; rtype; rtype = rtype->next) {
|
||||
if (rtype->hashkey == hash && !strcmp(rtype->_name[0], name))
|
||||
break;
|
||||
if (cb_find_prefix(&cb_resources, name, strlen(name)+1, &matches, 1, 0)) {
|
||||
cb_get_kv(matches, &result, sizeof(result));
|
||||
}
|
||||
if (!rtype) {
|
||||
log_warning("rt_find: unknown resource '%s'\n", name);
|
||||
}
|
||||
return rtype;
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char *it_aliases[][2] = {
|
||||
|
@ -387,23 +378,13 @@ static const char *it_alias(const char *zname)
|
|||
item_type *it_find(const char *zname)
|
||||
{
|
||||
const char *name = it_alias(zname);
|
||||
unsigned int hash = hashstring(name);
|
||||
item_type *itype;
|
||||
unsigned int key = hash % IMAXHASH;
|
||||
const void * matches;
|
||||
item_type *result = 0;
|
||||
|
||||
for (itype = itemtypes[key]; itype; itype = itype->next) {
|
||||
if (itype->rtype->hashkey == hash
|
||||
&& strcmp(itype->rtype->_name[0], name) == 0) {
|
||||
break;
|
||||
}
|
||||
if (cb_find_prefix(&cb_items, name, strlen(name)+1, &matches, 1, 0)) {
|
||||
cb_get_kv(matches, &result, sizeof(result));
|
||||
}
|
||||
if (itype == NULL) {
|
||||
for (itype = itemtypes[key]; itype; itype = itype->next) {
|
||||
if (strcmp(itype->rtype->_name[1], name) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return itype;
|
||||
return result;
|
||||
}
|
||||
|
||||
item **i_find(item ** i, const item_type * it)
|
||||
|
@ -1066,10 +1047,11 @@ int change_money(unit * u, int v)
|
|||
}
|
||||
|
||||
static local_names *rnames;
|
||||
|
||||
#define CB_BATCHSIZE 16
|
||||
const resource_type *findresourcetype(const char *name,
|
||||
const struct locale *lang)
|
||||
{
|
||||
const void * matches[CB_BATCHSIZE];
|
||||
local_names *rn = rnames;
|
||||
variant token;
|
||||
|
||||
|
@ -1079,21 +1061,30 @@ const resource_type *findresourcetype(const char *name,
|
|||
rn = rn->next;
|
||||
}
|
||||
if (!rn) {
|
||||
const resource_type *rtl = resourcetypes;
|
||||
rn = calloc(sizeof(local_names), 1);
|
||||
int m, offset = 0;
|
||||
rn = (local_names *)calloc(1, sizeof(local_names));
|
||||
rn->next = rnames;
|
||||
rn->lang = lang;
|
||||
while (rtl) {
|
||||
token.v = (void *)rtl;
|
||||
addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token);
|
||||
addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token);
|
||||
rtl = rtl->next;
|
||||
}
|
||||
do {
|
||||
m = cb_find_prefix(&cb_resources, "", 1, matches, CB_BATCHSIZE, offset);
|
||||
if (m) {
|
||||
int i;
|
||||
offset += m;
|
||||
for (i=0;i!=m;++i) {
|
||||
resource_type *rtype;
|
||||
cb_get_kv(matches[i], &rtype, sizeof(rtype));
|
||||
token.v = (void *)rtype;
|
||||
addtoken(&rn->names, locale_string(lang, rtype->_name[0]), token);
|
||||
addtoken(&rn->names, locale_string(lang, rtype->_name[1]), token);
|
||||
}
|
||||
}
|
||||
} while (m==CB_BATCHSIZE);
|
||||
rnames = rn;
|
||||
}
|
||||
|
||||
if (findtoken(rn->names, name, &token) == E_TOK_NOMATCH)
|
||||
return NULL;
|
||||
if (findtoken(rn->names, name, &token) == E_TOK_NOMATCH) {
|
||||
return 0;
|
||||
}
|
||||
return (const resource_type *)token.v;
|
||||
}
|
||||
|
||||
|
@ -1103,64 +1094,43 @@ attrib_type at_showitem = {
|
|||
|
||||
static local_names *inames;
|
||||
|
||||
void init_itemnames(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; localenames[i]; ++i) {
|
||||
const struct locale *lang = find_locale(localenames[i]);
|
||||
boolean exist = false;
|
||||
local_names *in = inames;
|
||||
|
||||
while (in != NULL) {
|
||||
if (in->lang == lang) {
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
in = in->next;
|
||||
}
|
||||
if (in == NULL)
|
||||
in = calloc(sizeof(local_names), 1);
|
||||
in->next = inames;
|
||||
in->lang = lang;
|
||||
|
||||
if (!exist) {
|
||||
int key;
|
||||
for (key = 0; key != IMAXHASH; ++key) {
|
||||
const item_type *itl;
|
||||
for (itl = itemtypes[key]; itl; itl = itl->next) {
|
||||
variant var;
|
||||
const char *iname = locale_string(lang, itl->rtype->_name[0]);
|
||||
if (findtoken(in->names, iname, &var) == E_TOK_NOMATCH
|
||||
|| var.v != itl) {
|
||||
var.v = (void *)itl;
|
||||
addtoken(&in->names, iname, var);
|
||||
addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]),
|
||||
var);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inames = in;
|
||||
}
|
||||
}
|
||||
|
||||
const item_type *finditemtype(const char *name, const struct locale *lang)
|
||||
{
|
||||
const void * matches[CB_BATCHSIZE];
|
||||
local_names *in = inames;
|
||||
variant var;
|
||||
variant token;
|
||||
|
||||
while (in != NULL) {
|
||||
while (in) {
|
||||
if (in->lang == lang)
|
||||
break;
|
||||
in = in->next;
|
||||
}
|
||||
if (in == NULL) {
|
||||
init_itemnames();
|
||||
for (in = inames; in->lang != lang; in = in->next) ;
|
||||
if (!in) {
|
||||
int m, offset = 0;
|
||||
in = (local_names *)calloc(1, sizeof(local_names));
|
||||
in->next = inames;
|
||||
in->lang = lang;
|
||||
do {
|
||||
m = cb_find_prefix(&cb_items, "", 1, matches, CB_BATCHSIZE, offset);
|
||||
if (m) {
|
||||
int i;
|
||||
offset += m;
|
||||
for (i=0;i!=m;++i) {
|
||||
item_type *itype;
|
||||
cb_get_kv(matches[i], &itype, sizeof(itype));
|
||||
token.v = (void *)itype;
|
||||
addtoken(&in->names, locale_string(lang, itype->rtype->_name[0]), token);
|
||||
addtoken(&in->names, locale_string(lang, itype->rtype->_name[1]), token);
|
||||
}
|
||||
}
|
||||
} while (m==CB_BATCHSIZE);
|
||||
inames = in;
|
||||
}
|
||||
if (findtoken(in->names, name, &var) == E_TOK_NOMATCH)
|
||||
return NULL;
|
||||
return (const item_type *)var.v;
|
||||
|
||||
if (findtoken(in->names, name, &token) == E_TOK_NOMATCH) {
|
||||
return 0;
|
||||
}
|
||||
return (const item_type *)token.v;
|
||||
}
|
||||
|
||||
static void init_resourcelimit(attrib * a)
|
||||
|
@ -1197,31 +1167,38 @@ static item *default_spoil(const struct race *rc, int size)
|
|||
}
|
||||
|
||||
#ifndef DISABLE_TESTS
|
||||
int free_itype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||
item_type *itype;
|
||||
cb_get_kv(match, &itype, sizeof(itype));
|
||||
free(itype->construction);
|
||||
free(itype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) {
|
||||
resource_type *rtype;
|
||||
cb_get_kv(match, &rtype, sizeof(rtype));
|
||||
free(rtype->_name[0]);
|
||||
free(rtype->_name[1]);
|
||||
free(rtype->_appearance[0]);
|
||||
free(rtype->_appearance[1]);
|
||||
free(rtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_clear_resources(void)
|
||||
{
|
||||
int i;
|
||||
memset((void *)olditemtype, 0, sizeof(olditemtype));
|
||||
memset((void *)oldresourcetype, 0, sizeof(oldresourcetype));
|
||||
memset((void *)oldpotiontype, 0, sizeof(oldpotiontype));
|
||||
|
||||
for (i=0;i!=IMAXHASH;++i) {
|
||||
item_type * itype = itemtypes[i];
|
||||
if (itype) {
|
||||
itemtypes[i] = 0;
|
||||
free(itype->construction);
|
||||
free(itype);
|
||||
}
|
||||
}
|
||||
cb_foreach(&cb_items, "", 0, free_itype_cb, 0);
|
||||
cb_clear(&cb_items);
|
||||
cb_foreach(&cb_resources, "", 0, free_rtype_cb, 0);
|
||||
cb_clear(&cb_resources);
|
||||
|
||||
while (resourcetypes) {
|
||||
resource_type * rtype = resourcetypes;
|
||||
resourcetypes = rtype->next;
|
||||
free(rtype->_name[0]);
|
||||
free(rtype->_name[1]);
|
||||
free(rtype->_appearance[0]);
|
||||
free(rtype->_appearance[1]);
|
||||
free(rtype);
|
||||
}
|
||||
resourcetypes = 0;
|
||||
r_hp = 0;
|
||||
init_resources();
|
||||
r_hp = r_silver = r_aura = r_permaura = r_unit = 0;
|
||||
i_silver = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -69,15 +69,13 @@ extern "C" {
|
|||
rtype_name name;
|
||||
/* --- pointers --- */
|
||||
struct attrib *attribs;
|
||||
struct resource_type *next;
|
||||
unsigned int hashkey;
|
||||
struct item_type *itype;
|
||||
struct potion_type *ptype;
|
||||
struct luxury_type *ltype;
|
||||
struct weapon_type *wtype;
|
||||
struct armor_type *atype;
|
||||
} resource_type;
|
||||
extern resource_type *resourcetypes;
|
||||
|
||||
extern const char *resourcename(const resource_type * rtype, int flags);
|
||||
extern const resource_type *findresourcetype(const char *name,
|
||||
const struct locale *lang);
|
||||
|
@ -142,12 +140,9 @@ extern "C" {
|
|||
#if SCORE_MODULE
|
||||
int score;
|
||||
#endif
|
||||
struct item_type *next;
|
||||
} item_type;
|
||||
|
||||
extern const item_type *finditemtype(const char *name,
|
||||
const struct locale *lang);
|
||||
extern void init_itemnames(void);
|
||||
extern const item_type *finditemtype(const char *name, const struct locale *lang);
|
||||
|
||||
typedef struct luxury_type {
|
||||
struct luxury_type *next;
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
|
||||
void test_resource_type(CuTest * tc)
|
||||
{
|
||||
resource_type *rtype, *rherp;
|
||||
resource_type *rtype;
|
||||
const char *names[2] = { 0 , 0 };
|
||||
|
||||
CuAssertPtrEquals(tc, 0, rt_find("herpderp"));
|
||||
|
||||
names[0] = "herpderp";
|
||||
rtype = new_resourcetype(names, NULL, RTF_NONE);
|
||||
new_resourcetype(names, NULL, RTF_NONE);
|
||||
names[0] = "herp";
|
||||
rherp = new_resourcetype(names, NULL, RTF_NONE);
|
||||
names[0] = "herpes";
|
||||
rtype = new_resourcetype(names, NULL, RTF_NONE);
|
||||
names[0] = "herpes";
|
||||
new_resourcetype(names, NULL, RTF_NONE);
|
||||
|
||||
CuAssertPtrEquals(tc, rherp, rt_find("herp"));
|
||||
CuAssertPtrEquals(tc, rtype, rt_find("herp"));
|
||||
}
|
||||
|
||||
CuSuite *get_item_suite(void)
|
||||
|
|
18
src/tests.c
18
src/tests.c
|
@ -4,6 +4,7 @@
|
|||
#include <platform.h>
|
||||
#include "tests.h"
|
||||
|
||||
#include "tests_test.c"
|
||||
#include <util/base36_test.c>
|
||||
#include <util/functions_test.c>
|
||||
#include <util/quicklist_test.c>
|
||||
|
@ -38,22 +39,26 @@ int RunAllTests(void)
|
|||
int flags = log_flags;
|
||||
|
||||
log_flags = LOG_FLUSH | LOG_CPERROR;
|
||||
init_resources();
|
||||
|
||||
/* self-test */
|
||||
CuSuiteAddSuite(suite, get_tests_suite());
|
||||
/* util */
|
||||
CuSuiteAddSuite(suite, get_base36_suite());
|
||||
CuSuiteAddSuite(suite, get_quicklist_suite());
|
||||
CuSuiteAddSuite(suite, get_functions_suite());
|
||||
CuSuiteAddSuite(suite, get_umlaut_suite());
|
||||
/* kernel */
|
||||
CuSuiteAddSuite(suite, get_curse_suite());
|
||||
CuSuiteAddSuite(suite, get_market_suite());
|
||||
CuSuiteAddSuite(suite, get_item_suite());
|
||||
CuSuiteAddSuite(suite, get_move_suite());
|
||||
CuSuiteAddSuite(suite, get_reports_suite());
|
||||
CuSuiteAddSuite(suite, get_ship_suite());
|
||||
CuSuiteAddSuite(suite, get_building_suite());
|
||||
CuSuiteAddSuite(suite, get_spell_suite());
|
||||
CuSuiteAddSuite(suite, get_laws_suite());
|
||||
CuSuiteAddSuite(suite, get_battle_suite());
|
||||
/* gamecode */
|
||||
CuSuiteAddSuite(suite, get_market_suite());
|
||||
CuSuiteAddSuite(suite, get_laws_suite());
|
||||
|
||||
CuSuiteRun(suite);
|
||||
CuSuiteSummary(suite, output);
|
||||
|
@ -157,9 +162,12 @@ void test_create_world(void)
|
|||
building_type *btype;
|
||||
ship_type *stype;
|
||||
item_type * itype;
|
||||
const char * names[2] = { "horse", "horse_p" };
|
||||
const char * horses[2] = { "horse", "horse_p" };
|
||||
|
||||
itype = test_create_itemtype(names);
|
||||
init_resources();
|
||||
assert(!olditemtype[I_HORSE]);
|
||||
|
||||
itype = test_create_itemtype(horses);
|
||||
olditemtype[I_HORSE] = itype;
|
||||
|
||||
t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#include <kernel/item.h>
|
||||
#include <kernel/region.h>
|
||||
|
||||
#include <cutest/CuTest.h>
|
||||
|
||||
static void test_recreate_world(CuTest * tc)
|
||||
{
|
||||
test_cleanup();
|
||||
CuAssertPtrEquals(tc, 0, it_find("money"));
|
||||
CuAssertPtrEquals(tc, 0, it_find("horse"));
|
||||
test_create_world();
|
||||
CuAssertPtrNotNull(tc, it_find("money"));
|
||||
CuAssertPtrNotNull(tc, it_find("horse"));
|
||||
CuAssertPtrNotNull(tc, findregion(0, 0));
|
||||
test_cleanup();
|
||||
CuAssertPtrEquals(tc, 0, it_find("money"));
|
||||
CuAssertPtrEquals(tc, 0, it_find("horse"));
|
||||
CuAssertPtrEquals(tc, 0, findregion(0, 0));
|
||||
}
|
||||
|
||||
CuSuite *get_tests_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_recreate_world);
|
||||
return suite;
|
||||
}
|
|
@ -85,6 +85,7 @@ void cb_clear(critbit_tree * cb)
|
|||
{
|
||||
if (cb->root) {
|
||||
cb_free_node(cb->root);
|
||||
cb->root = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,6 +167,36 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen)
|
|||
}
|
||||
}
|
||||
|
||||
static void * cb_find_top_i(critbit_tree * cb, const void * key, size_t keylen)
|
||||
{
|
||||
void *ptr, *top = 0;
|
||||
assert(key);
|
||||
|
||||
if (!cb->root) {
|
||||
return 0;
|
||||
}
|
||||
for (ptr=cb->root, top=cb->root;;) {
|
||||
void * last = ptr;
|
||||
if (decode_pointer(&ptr)==INTERNAL_NODE) {
|
||||
struct critbit_node * node = (struct critbit_node *)ptr;
|
||||
int branch;
|
||||
if (keylen<=node->byte) {
|
||||
break;
|
||||
} else {
|
||||
unsigned char * bytes = (unsigned char *)key;
|
||||
top = last;
|
||||
branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8;
|
||||
ptr = node->child[branch];
|
||||
}
|
||||
} else {
|
||||
/* we reached an external node before exhausting the key length */
|
||||
top = last;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return top;
|
||||
}
|
||||
|
||||
static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const void ** results, int numresults, int * offset, int next)
|
||||
{
|
||||
assert(next<=numresults);
|
||||
|
@ -196,34 +227,45 @@ static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const v
|
|||
|
||||
int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset)
|
||||
{
|
||||
void *ptr, *top = 0;
|
||||
assert(key);
|
||||
|
||||
if (!cb->root || !numresults) {
|
||||
return 0;
|
||||
}
|
||||
for (ptr=cb->root, top=cb->root;;) {
|
||||
void * last = ptr;
|
||||
if (decode_pointer(&ptr)==INTERNAL_NODE) {
|
||||
struct critbit_node * node = (struct critbit_node *)ptr;
|
||||
int branch;
|
||||
if (keylen<=node->byte) {
|
||||
break;
|
||||
} else {
|
||||
unsigned char * bytes = (unsigned char *)key;
|
||||
top = last;
|
||||
branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8;
|
||||
ptr = node->child[branch];
|
||||
}
|
||||
} else {
|
||||
/* we reached an external node before exhausting the key length */
|
||||
top = last;
|
||||
break;
|
||||
if (numresults>0) {
|
||||
void *top = cb_find_top_i(cb, key, keylen);
|
||||
if (top) {
|
||||
/* recursively add all children except the ones from [0-offset) of top to the results */
|
||||
return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cb_foreach_i(void * ptr, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (decode_pointer(&ptr)==INTERNAL_NODE) {
|
||||
struct critbit_node * node = (struct critbit_node *)ptr;
|
||||
result = cb_foreach_i(node->child[0], key, keylen, match_cb, data);
|
||||
if (!result) {
|
||||
result = cb_foreach_i(node->child[1], key, keylen, match_cb, data);
|
||||
}
|
||||
} else {
|
||||
/* reached an external node */
|
||||
void * match;
|
||||
size_t len;
|
||||
|
||||
from_external_node(ptr, &match, &len);
|
||||
if (len>=keylen && memcmp(key, match, keylen)==0) {
|
||||
return match_cb(match, key, keylen, data);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data)
|
||||
{
|
||||
void *top = cb_find_top_i(cb, key, keylen);
|
||||
if (top) {
|
||||
/* recursively add all children except the ones from [0-offset) of top to the results */
|
||||
return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0);
|
||||
return cb_foreach_i(top, key, keylen, match_cb, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen);
|
|||
const void * cb_find(critbit_tree * cb, const void * key, size_t keylen);
|
||||
int cb_erase(critbit_tree * cb, const void * key, size_t keylen);
|
||||
int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset);
|
||||
int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data);
|
||||
void cb_clear(critbit_tree * cb);
|
||||
|
||||
#define cb_insert_str(cb, key) \
|
||||
|
|
Loading…
Reference in New Issue