hashing implemented with linear probing and tombstones.

WIP: this crashes 572 in faction_getmages?
This commit is contained in:
Enno Rehling 2017-09-22 09:15:37 +02:00
parent afe4532966
commit 0c16727d41
5 changed files with 88 additions and 110 deletions

View File

@ -10,10 +10,33 @@
#include "plane.h" #include "plane.h"
#include <util/attrib.h> #include <util/attrib.h>
#include <util/gamedata.h>
#include <storage.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
void read_allies(gamedata * data, faction *f)
{
ally **sfp = &f->allies;
for (;;) {
int aid;
ally * al = ally_add(sfp, NULL);
aid = read_faction_reference(data, &al->faction, NULL);
if (aid > 0) {
int state;
READ_INT(data->store, &state);
al->status = state & HELP_ALL;
sfp = &al->next;
}
else {
break;
}
}
}
ally * ally_find(ally *al, const struct faction *f) { ally * ally_find(ally *al, const struct faction *f) {
for (; al; al = al->next) { for (; al; al = al->next) {
if (al->faction == f) return al; if (al->faction == f) return al;

View File

@ -26,7 +26,9 @@ extern "C" {
struct attrib_type; struct attrib_type;
struct plane; struct plane;
struct faction; struct faction;
struct gamedata;
struct unit; struct unit;
extern struct attrib_type at_npcfaction; extern struct attrib_type at_npcfaction;
typedef struct ally { typedef struct ally {
@ -35,6 +37,7 @@ extern "C" {
int status; int status;
} ally; } ally;
void read_allies(struct gamedata * data, struct faction *f);
ally * ally_find(ally *al, const struct faction *f); ally * ally_find(ally *al, const struct faction *f);
ally * ally_add(ally **al_p, struct faction *f); ally * ally_add(ally **al_p, struct faction *f);
void ally_remove(ally **al_p, struct faction *f); void ally_remove(ally **al_p, struct faction *f);

View File

@ -1152,31 +1152,6 @@ void write_region(gamedata *data, const region *r)
writeregion(data, r); writeregion(data, r);
} }
static ally **addally(const faction * f, ally ** sfp, int aid, int state)
{
struct faction *af = findfaction(aid);
ally *sf;
state &= ~HELP_OBSERVE;
state &= ~HELP_TRAVEL;
state &= HelpMask();
if (state == 0)
return sfp;
while (*sfp) {
sfp = &(*sfp)->next;
}
sf = ally_add(sfp, af);
if (!sf->faction) {
ur_add(aid, &sf->faction, NULL);
}
sf->status = state & HELP_ALL;
return &sf->next;
}
int get_spell_level_faction(const spell * sp, void * cbdata) int get_spell_level_faction(const spell * sp, void * cbdata)
{ {
static spellbook * common = 0; static spellbook * common = 0;
@ -1385,18 +1360,7 @@ faction *read_faction(gamedata * data)
f->options &= ~want(O_JSON); f->options &= ~want(O_JSON);
} }
sfp = &f->allies; sfp = &f->allies;
for (;;) { read_allies(data, f);
int aid = 0;
READ_INT(data->store, &aid);
if (aid > 0) {
int state;
READ_INT(data->store, &state);
sfp = addally(f, sfp, aid, state);
}
else {
break;
}
}
read_groups(data, f); read_groups(data, f);
f->spellbook = 0; f->spellbook = 0;
if (data->version >= REGIONOWNER_VERSION) { if (data->version >= REGIONOWNER_VERSION) {

View File

@ -2892,46 +2892,20 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration)
return c; return c;
} }
#define COMPAT_DEATHCLOUD
#ifdef COMPAT_DEATHCLOUD
static int dc_read_compat(struct attrib *a, void *target, gamedata *data) static int dc_read_compat(struct attrib *a, void *target, gamedata *data)
/* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */
{ {
struct storage *store = data->store; struct storage *store = data->store;
region *r = NULL;
unit *u;
int id;
int duration;
float strength;
int rx, ry;
UNUSED_ARG(a); UNUSED_ARG(a);
UNUSED_ARG(target); UNUSED_ARG(target);
READ_INT(store, &duration); READ_INT(store, NULL);
READ_FLT(store, &strength); READ_FLT(store, NULL);
READ_INT(store, &id); READ_INT(store, NULL);
u = findunit(id); READ_INT(store, NULL);
READ_INT(store, NULL);
/* this only affects really old data. no need to change: */ return AT_READ_DEPR; /* we don't care for the attribute. */
READ_INT(store, &rx);
READ_INT(store, &ry);
r = findregion(rx, ry);
if (r != NULL) {
double effect;
curse *c;
effect = strength;
c = create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration,
effect, 0);
c->data.v = r;
if (u == NULL) {
ur_add(id, &c->magician, NULL);
}
}
return AT_READ_FAIL; /* we don't care for the attribute. */
} }
#endif
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
/* Name: Todeswolke /* Name: Todeswolke
@ -6704,9 +6678,7 @@ void register_spells(void)
{ {
register_borders(); register_borders();
#ifdef COMPAT_DEATHCLOUD
at_deprecate("zauber_todeswolke", dc_read_compat); at_deprecate("zauber_todeswolke", dc_read_compat);
#endif
/* init_firewall(); */ /* init_firewall(); */
ct_register(&ct_firewall); ct_register(&ct_firewall);

View File

@ -17,69 +17,85 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/ **/
#include <platform.h> #include <platform.h>
#include <selist.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "resolve.h" #include "resolve.h"
#include "storage.h" #include "storage.h"
#include "variant.h" #include "variant.h"
typedef struct unresolved { typedef struct unresolved {
void **addr; int id;
/* address to pass to the resolve-function */
variant data;
/* information on how to resolve the missing object */ /* information on how to resolve the missing object */
resolve_fun resolve; resolve_fun resolve;
/* function to resolve the unknown object */ /* function to resolve the unknown object */
selist *addrs;
/* address to pass to the resolve-function */
} unresolved; } unresolved;
#define BLOCKSIZE 1024 #define HASHSIZE 1024 /* must be a power of 2 */
static unresolved *ur_list; static unresolved ur_hash[HASHSIZE];
static unresolved *ur_begin;
static unresolved *ur_current; int ur_key(int id) {
int h = id ^ (id >> 16);
return h & (HASHSIZE - 1);
}
void ur_add(int id, void **addr, resolve_fun fun) void ur_add(int id, void **addr, resolve_fun fun)
{ {
int h, i;
assert(id > 0);
assert(addr); assert(addr);
assert(!*addr); assert(!*addr);
if (ur_list == NULL) {
ur_list = malloc(BLOCKSIZE * sizeof(unresolved));
ur_begin = ur_current = ur_list;
}
else if (ur_current - ur_begin == BLOCKSIZE - 1) {
ur_begin = malloc(BLOCKSIZE * sizeof(unresolved));
ur_current->data.v = ur_begin;
ur_current = ur_begin;
}
ur_current->data.i = id;
ur_current->resolve = fun;
ur_current->addr = addr;
++ur_current; h = ur_key(id);
ur_current->addr = NULL; for (i = 0; i != HASHSIZE; ++i) {
ur_current->data.v = NULL; int k = h + i;
if (k >= HASHSIZE) k -= HASHSIZE;
if (ur_hash[k].id <= 0) {
ur_hash[k].id = id;
ur_hash[k].resolve = fun;
selist_push(&ur_hash[k].addrs, addr);
return;
}
if (ur_hash[k].id == id && ur_hash[k].resolve == fun) {
ur_hash[k].resolve = fun;
selist_push(&ur_hash[k].addrs, addr);
return;
}
}
assert(!"hash table is full");
}
static bool addr_cb(void *data, void *more) {
void **addr = (void **)data;
*addr = more;
return true;
} }
void resolve(int id, void *data) void resolve(int id, void *data)
{ {
unresolved *ur = ur_list; int h, i;
/* TODO: hella slow! hashing is better */ h = ur_key(id);
while (ur) {
if (ur->addr == NULL) { for (i = 0; i != HASHSIZE; ++i) {
ur = ur->data.v; int k = h + i;
free(ur_list);
ur_list = ur; if (k >= HASHSIZE) k -= HASHSIZE;
continue; if (ur_hash[k].id == 0) break;
else if (ur_hash[k].id == id) {
if (ur_hash[k].resolve) {
data = ur_hash[k].resolve(id, data);
} }
if (id == ur->data.i) { selist_foreach_ex(ur_hash[k].addrs, addr_cb, data);
if (ur->resolve) { selist_free(ur_hash[k].addrs);
*ur->addr = ur->resolve(id, data); ur_hash[k].addrs = NULL;
} ur_hash[k].id = -1;
else {
*ur->addr = data;
} }
} }
++ur;
}
free(ur_list);
ur_list = NULL;
} }