forked from github/server
optimized storage of attribs.
save the hash instead of the name and save a few bytes.
This commit is contained in:
parent
f630278339
commit
abc3caa6d1
8 changed files with 140 additions and 75 deletions
|
@ -659,7 +659,7 @@ int read_borders(struct storage *store)
|
|||
type->read(b, store);
|
||||
if (global.data_version < NOBORDERATTRIBS_VERSION) {
|
||||
attrib *a = NULL;
|
||||
int result = a_read(store, &a, b);
|
||||
int result = read_attribs(store, &a, b);
|
||||
if (border_convert_cb) {
|
||||
border_convert_cb(b, a);
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ void write_groups(struct storage *store, const faction * f)
|
|||
}
|
||||
}
|
||||
WRITE_INT(store, 0);
|
||||
a_write(store, g->attribs, g);
|
||||
write_attribs(store, g->attribs, g);
|
||||
WRITE_SECTION(store);
|
||||
}
|
||||
WRITE_INT(store, 0);
|
||||
|
@ -241,6 +241,6 @@ void read_groups(struct storage *store, faction * f)
|
|||
if (!a->faction)
|
||||
ur_add(fid, &a->faction, resolve_faction);
|
||||
}
|
||||
a_read(store, &g->attribs, g);
|
||||
read_attribs(store, &g->attribs, g);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,6 +577,23 @@ const struct locale *lang)
|
|||
WRITE_STR(data->store, obuf);
|
||||
}
|
||||
|
||||
int read_attribs(storage *store, attrib **alist, void *owner) {
|
||||
#if RELEASE_VERSION < ATHASH_VERSION
|
||||
return a_read_orig(store, alist, owner);
|
||||
#else
|
||||
return a_read(store, alist, owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
void write_attribs(storage *store, attrib *alist, const void *owner)
|
||||
{
|
||||
#if RELEASE_VERSION < ATHASH_VERSION
|
||||
a_write_orig(store, alist, owner);
|
||||
#else
|
||||
a_write(store, alist, owner);
|
||||
#endif
|
||||
}
|
||||
|
||||
unit *read_unit(struct gamedata *data)
|
||||
{
|
||||
unit *u;
|
||||
|
@ -748,8 +765,7 @@ unit *read_unit(struct gamedata *data)
|
|||
log_error("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), u->number, u->hp);
|
||||
u->hp = u->number;
|
||||
}
|
||||
|
||||
a_read(data->store, &u->attribs, u);
|
||||
read_attribs(data->store, &u->attribs, u);
|
||||
return u;
|
||||
}
|
||||
|
||||
|
@ -823,7 +839,7 @@ void write_unit(struct gamedata *data, const unit * u)
|
|||
}
|
||||
WRITE_INT(data->store, u->hp);
|
||||
WRITE_SECTION(data->store);
|
||||
a_write(data->store, u->attribs, u);
|
||||
write_attribs(data->store, u->attribs, u);
|
||||
WRITE_SECTION(data->store);
|
||||
}
|
||||
|
||||
|
@ -982,7 +998,7 @@ static region *readregion(struct gamedata *data, int x, int y)
|
|||
read_owner(data, &r->land->ownership);
|
||||
}
|
||||
}
|
||||
a_read(data->store, &r->attribs, r);
|
||||
read_attribs(data->store, &r->attribs, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1046,7 +1062,7 @@ void writeregion(struct gamedata *data, const region * r)
|
|||
WRITE_SECTION(data->store);
|
||||
#endif
|
||||
}
|
||||
a_write(data->store, r->attribs, r);
|
||||
write_attribs(data->store, r->attribs, r);
|
||||
WRITE_SECTION(data->store);
|
||||
}
|
||||
|
||||
|
@ -1253,7 +1269,7 @@ faction *readfaction(struct gamedata * data)
|
|||
}
|
||||
}
|
||||
|
||||
a_read(data->store, &f->attribs, f);
|
||||
read_attribs(data->store, &f->attribs, f);
|
||||
read_items(data->store, &f->items);
|
||||
for (;;) {
|
||||
READ_TOK(data->store, name, sizeof(name));
|
||||
|
@ -1338,7 +1354,7 @@ void writefaction(struct gamedata *data, const faction * f)
|
|||
WRITE_INT(data->store, f->magiegebiet);
|
||||
|
||||
WRITE_INT(data->store, f->flags & FFL_SAVEMASK);
|
||||
a_write(data->store, f->attribs, f);
|
||||
write_attribs(data->store, f->attribs, f);
|
||||
WRITE_SECTION(data->store);
|
||||
write_items(data->store, f->items);
|
||||
WRITE_SECTION(data->store);
|
||||
|
@ -1451,7 +1467,7 @@ int readgame(const char *filename, bool backup)
|
|||
else {
|
||||
READ_STR(&store, NULL, 0);
|
||||
}
|
||||
a_read(&store, &global.attribs, NULL);
|
||||
read_attribs(&store, &global.attribs, NULL);
|
||||
READ_INT(&store, &turn);
|
||||
global.data_turn = turn;
|
||||
log_debug(" - reading turn %d\n", turn);
|
||||
|
@ -1512,7 +1528,7 @@ int readgame(const char *filename, bool backup)
|
|||
fno = read_faction_reference(&store);
|
||||
}
|
||||
}
|
||||
a_read(&store, &pl->attribs, pl);
|
||||
read_attribs(&store, &pl->attribs, pl);
|
||||
if (pl->id != 1094969858) { // Regatta
|
||||
addlist(&planes, pl);
|
||||
}
|
||||
|
@ -1580,7 +1596,7 @@ int readgame(const char *filename, bool backup)
|
|||
READ_STR(&store, name, sizeof(name));
|
||||
b->type = bt_find(name);
|
||||
b->region = r;
|
||||
a_read(&store, &b->attribs, b);
|
||||
read_attribs(&store, &b->attribs, b);
|
||||
if (b->type == bt_lighthouse) {
|
||||
r->flags |= RF_LIGHTHOUSE;
|
||||
}
|
||||
|
@ -1627,7 +1643,7 @@ int readgame(const char *filename, bool backup)
|
|||
if (sh->type->flags & SFL_NOCOAST) {
|
||||
sh->coast = NODIRECTION;
|
||||
}
|
||||
a_read(&store, &sh->attribs, sh);
|
||||
read_attribs(&store, &sh->attribs, sh);
|
||||
}
|
||||
|
||||
*shp = 0;
|
||||
|
@ -1777,7 +1793,7 @@ int writegame(const char *filename)
|
|||
WRITE_INT(&store, game_id());
|
||||
WRITE_SECTION(&store);
|
||||
|
||||
a_write(&store, global.attribs, NULL);
|
||||
write_attribs(&store, global.attribs, NULL);
|
||||
WRITE_SECTION(&store);
|
||||
|
||||
WRITE_INT(&store, turn);
|
||||
|
@ -1807,7 +1823,7 @@ int writegame(const char *filename)
|
|||
w = w->next;
|
||||
}
|
||||
write_faction_reference(NULL, &store); /* mark the end of the list */
|
||||
a_write(&store, pl->attribs, pl);
|
||||
write_attribs(&store, pl->attribs, pl);
|
||||
WRITE_SECTION(&store);
|
||||
}
|
||||
|
||||
|
@ -1852,7 +1868,7 @@ int writegame(const char *filename)
|
|||
WRITE_INT(&store, b->size);
|
||||
WRITE_TOK(&store, b->type->_name);
|
||||
WRITE_SECTION(&store);
|
||||
a_write(&store, b->attribs, b);
|
||||
write_attribs(&store, b->attribs, b);
|
||||
WRITE_SECTION(&store);
|
||||
}
|
||||
|
||||
|
@ -1870,7 +1886,7 @@ int writegame(const char *filename)
|
|||
assert((sh->type->flags & SFL_NOCOAST) == 0 || sh->coast == NODIRECTION);
|
||||
WRITE_INT(&store, sh->coast);
|
||||
WRITE_SECTION(&store);
|
||||
a_write(&store, sh->attribs, sh);
|
||||
write_attribs(&store, sh->attribs, sh);
|
||||
WRITE_SECTION(&store);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ extern "C" {
|
|||
void read_spellbook(struct spellbook **bookp, struct storage *store, int(*get_level)(const struct spell * sp, void *), void * cbdata);
|
||||
void write_spellbook(const struct spellbook *book, struct storage *store);
|
||||
|
||||
void write_attribs(struct storage *store, struct attrib *alist, const void *owner);
|
||||
int read_attribs(struct storage *store, struct attrib **alist, void *owner);
|
||||
|
||||
void write_unit(struct gamedata *data, const struct unit *u);
|
||||
struct unit *read_unit(struct gamedata *data);
|
||||
|
||||
|
|
|
@ -72,14 +72,14 @@ static void test_readwrite_attrib(CuTest *tc) {
|
|||
CuAssertPtrNotNull(tc, data);
|
||||
add_key(&a, 41);
|
||||
add_key(&a, 42);
|
||||
a_write(data->store, a, NULL);
|
||||
write_attribs(data->store, a, NULL);
|
||||
gamedata_close(data);
|
||||
a_removeall(&a, NULL);
|
||||
CuAssertPtrEquals(tc, 0, a);
|
||||
|
||||
data = gamedata_open(path, "rb");
|
||||
CuAssertPtrNotNull(tc, data);
|
||||
a_read(data->store, &a, NULL);
|
||||
read_attribs(data->store, &a, NULL);
|
||||
gamedata_close(data);
|
||||
CuAssertPtrNotNull(tc, find_key(a, 41));
|
||||
CuAssertPtrNotNull(tc, find_key(a, 42));
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
#define OWNER_3_VERSION 349 /* regions store last owner, not last alliance */
|
||||
#define ATTRIBOWNER_VERSION 350 /* all attrib_type functions know who owns the attribute */
|
||||
#define CRYPT_VERSION 351 /* passwords are encrypted */
|
||||
#define RELEASE_VERSION CRYPT_VERSION /* current datafile */
|
||||
#define ATHASH_VERSION 352 /* attribute-type hash, not name */
|
||||
#define RELEASE_VERSION ATHASH_VERSION /* current datafile */
|
||||
#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */
|
||||
#define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */
|
||||
|
||||
|
|
|
@ -276,15 +276,79 @@ int a_age(attrib ** p, void *owner)
|
|||
|
||||
static critbit_tree cb_deprecated = { 0 };
|
||||
|
||||
|
||||
typedef struct deprecated_s {
|
||||
unsigned int hash;
|
||||
int(*reader)(attrib *, void *, struct storage *);
|
||||
} deprecated_t;
|
||||
|
||||
void at_deprecate(const char * name, int(*reader)(attrib *, void *, struct storage *))
|
||||
{
|
||||
char buffer[64];
|
||||
size_t len = strlen(name);
|
||||
len = cb_new_kv(name, len, &reader, sizeof(reader), buffer);
|
||||
cb_insert(&cb_deprecated, buffer, len);
|
||||
deprecated_t value;
|
||||
|
||||
value.hash = __at_hashkey(name);
|
||||
value.reader = reader;
|
||||
cb_insert(&cb_deprecated, &value, sizeof(value));
|
||||
}
|
||||
|
||||
int a_read(struct storage *store, attrib ** attribs, void *owner)
|
||||
static int a_read_i(struct storage *store, attrib ** attribs, void *owner, unsigned int key) {
|
||||
int retval = AT_READ_FAIL;
|
||||
int(*reader)(attrib *, void *, struct storage *) = 0;
|
||||
attrib_type *at = at_find(key);
|
||||
attrib * na = 0;
|
||||
|
||||
if (at) {
|
||||
reader = at->read;
|
||||
na = a_new(at);
|
||||
}
|
||||
else {
|
||||
void *match;
|
||||
if (cb_find_prefix(&cb_deprecated, &key, sizeof(key), &match, 1, 0)>0) {
|
||||
deprecated_t *value = (deprecated_t *)match;
|
||||
reader = value->reader;
|
||||
}
|
||||
else {
|
||||
log_error("unknown attribute hash: %u\n", key);
|
||||
assert(at || !"attribute not registered");
|
||||
}
|
||||
}
|
||||
if (reader) {
|
||||
retval = reader(na, owner, store);
|
||||
if (na) {
|
||||
switch (retval) {
|
||||
case AT_READ_OK:
|
||||
a_add(attribs, na);
|
||||
break;
|
||||
case AT_READ_FAIL:
|
||||
a_free(na);
|
||||
break;
|
||||
default:
|
||||
assert(!"invalid return value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(!"error: no registered callback can read attribute");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int a_read(struct storage *store, attrib ** attribs, void *owner) {
|
||||
int key, retval = AT_READ_OK;
|
||||
char zText[128];
|
||||
|
||||
zText[0] = 0;
|
||||
key = -1;
|
||||
READ_INT(store, &key);
|
||||
while (key > 0 && retval == AT_READ_OK) {
|
||||
retval = a_read_i(store, attribs, owner, key);
|
||||
READ_INT(store, &key);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int a_read_orig(struct storage *store, attrib ** attribs, void *owner)
|
||||
{
|
||||
int key, retval = AT_READ_OK;
|
||||
char zText[128];
|
||||
|
@ -292,52 +356,14 @@ int a_read(struct storage *store, attrib ** attribs, void *owner)
|
|||
zText[0] = 0;
|
||||
key = -1;
|
||||
READ_TOK(store, zText, sizeof(zText));
|
||||
if (strcmp(zText, "end") == 0)
|
||||
if (strcmp(zText, "end") == 0) {
|
||||
return retval;
|
||||
else
|
||||
}
|
||||
else {
|
||||
key = __at_hashkey(zText);
|
||||
|
||||
while (key != -1) {
|
||||
int(*reader)(attrib *, void *, struct storage *) = 0;
|
||||
attrib_type *at = at_find(key);
|
||||
attrib * na = 0;
|
||||
|
||||
if (at) {
|
||||
reader = at->read;
|
||||
na = a_new(at);
|
||||
}
|
||||
else {
|
||||
void * kv = 0;
|
||||
cb_find_prefix(&cb_deprecated, zText, strlen(zText) + 1, &kv, 1, 0);
|
||||
if (kv) {
|
||||
cb_get_kv(kv, &reader, sizeof(reader));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "attribute hash: %d (%s)\n", key, zText);
|
||||
assert(at || !"attribute not registered");
|
||||
}
|
||||
}
|
||||
if (reader) {
|
||||
int i = reader(na, owner, store);
|
||||
if (na) {
|
||||
switch (i) {
|
||||
case AT_READ_OK:
|
||||
a_add(attribs, na);
|
||||
break;
|
||||
case AT_READ_FAIL:
|
||||
retval = AT_READ_FAIL;
|
||||
a_free(na);
|
||||
break;
|
||||
default:
|
||||
assert(!"invalid return value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(!"error: no registered callback can read attribute");
|
||||
}
|
||||
|
||||
}
|
||||
while (key > 0) {
|
||||
retval = a_read_i(store, attribs, owner, key);
|
||||
READ_TOK(store, zText, sizeof(zText));
|
||||
if (!strcmp(zText, "end"))
|
||||
break;
|
||||
|
@ -346,7 +372,24 @@ int a_read(struct storage *store, attrib ** attribs, void *owner)
|
|||
return retval;
|
||||
}
|
||||
|
||||
void a_write(struct storage *store, const attrib * attribs, const void *owner)
|
||||
void a_write(struct storage *store, const attrib * attribs, const void *owner) {
|
||||
const attrib *na = attribs;
|
||||
|
||||
while (na) {
|
||||
if (na->type->write) {
|
||||
assert(na->type->hashkey || !"attribute not registered");
|
||||
WRITE_INT(store, na->type->hashkey);
|
||||
na->type->write(na, owner, store);
|
||||
na = na->next;
|
||||
}
|
||||
else {
|
||||
na = na->nexttype;
|
||||
}
|
||||
}
|
||||
WRITE_INT(store, 0);
|
||||
}
|
||||
|
||||
void a_write_orig(struct storage *store, const attrib * attribs, const void *owner)
|
||||
{
|
||||
const attrib *na = attribs;
|
||||
|
||||
|
|
|
@ -72,11 +72,13 @@ extern "C" {
|
|||
extern int a_remove(attrib ** pa, attrib * at);
|
||||
extern void a_removeall(attrib ** a, const attrib_type * at);
|
||||
extern attrib *a_new(const attrib_type * at);
|
||||
int a_age(attrib ** attribs, void *owner);
|
||||
|
||||
extern int a_age(attrib ** attribs, void *owner);
|
||||
extern int a_read(struct storage *store, attrib ** attribs, void *owner);
|
||||
extern void a_write(struct storage *store, const attrib * attribs,
|
||||
const void *owner);
|
||||
int a_read_orig(struct storage *store, attrib ** attribs, void *owner);
|
||||
void a_write_orig(struct storage *store, const attrib * attribs, const void *owner);
|
||||
|
||||
int a_read(struct storage *store, attrib ** attribs, void *owner);
|
||||
void a_write(struct storage *store, const attrib * attribs, const void *owner);
|
||||
|
||||
void free_attribs(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue