optimized storage of attribs.

save the hash instead of the name and save a few bytes.
This commit is contained in:
Enno Rehling 2016-02-09 00:28:23 +01:00
parent f630278339
commit abc3caa6d1
8 changed files with 140 additions and 75 deletions

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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));

View file

@ -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 */

View file

@ -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;

View file

@ -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);