sort the at_keys array, binary search.

This commit is contained in:
Enno Rehling 2017-08-20 12:58:05 +02:00
parent aac2b0a60f
commit 219a3159e8
4 changed files with 141 additions and 42 deletions

View file

@ -22,6 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <util/attrib.h>
#include <util/gamedata.h>
#include <util/log.h>
#include <storage.h>
#include <stdlib.h>
@ -30,38 +31,94 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
static void a_writekeys(const attrib *a, const void *o, storage *store) {
int i, *keys = (int *)a->data.v;
int n = 0;
if (keys) {
assert(keys[0] < 4096 && keys[0]>0);
WRITE_INT(store, keys[0]);
for (i = 0; i < keys[0]; ++i) {
n = keys[0];
}
WRITE_INT(store, n);
for (i = 0; i < n; ++i) {
WRITE_INT(store, keys[i * 2 + 1]);
WRITE_INT(store, keys[i * 2 + 2]);
}
}
static int a_readkeys(attrib * a, void *owner, gamedata *data) {
int i, *p = 0;
READ_INT(data->store, &i);
assert(i < 4096 && i>=0);
if (i == 0) {
return AT_READ_FAIL;
}
a->data.v = p = malloc(sizeof(int)*(i*2 + 1));
*p++ = i;
while (i--) {
READ_INT(data->store, p++);
if (data->version >= KEYVAL_VERSION) {
READ_INT(data->store, p++);
static int keys_lower_bound(int *base, int k, int l, int r) {
int km = k;
int *p = base + 1;
while (l != r) {
int m = (l + r) / 2;
km = p[m * 2];
if (km < k) {
if (l == m) l = r;
else l = m;
}
else {
*p++ = 1;
if (r == m) r = l;
else r = m;
}
}
return l;
}
static int a_readkeys(attrib * a, void *owner, gamedata *data) {
int i, n, *keys;
READ_INT(data->store, &n);
assert(n < 4096 && n >= 0);
if (n == 0) {
return AT_READ_FAIL;
}
keys = malloc(sizeof(int)*(n * 2 + 1));
*keys = n;
for (i = 0; i != n; ++i) {
READ_INT(data->store, keys + i * 2 + 1);
if (data->version >= KEYVAL_VERSION) {
READ_INT(data->store, keys + i * 2 + 2);
}
else {
keys[i * 2 + 2] = 1;
}
}
if (data->version < SORTKEYS_VERSION) {
int e = 1;
for (i = 1; i != n; ++i) {
int k = keys[i * 2 + 1];
int v = keys[i * 2 + 2];
int l = keys_lower_bound(keys, k, 0, e);
if (l != e) {
int km = keys[l * 2 + 1];
if (km == k) {
int vm = keys[l * 2 + 2];
if (v != vm) {
log_error("key %d has values %d and %d", k, v, vm);
}
--e;
}
else {
if (e > l) {
memmove(keys + 2 * l + 3, keys + 2 * l + 1, (e - l) * 2 * sizeof(int));
}
keys[2 * l + 1] = k;
keys[2 * l + 2] = v;
}
}
++e;
}
if (e != n) {
keys = realloc(keys, sizeof(int)*(2 * e + 1));
keys[0] = e;
}
}
a->data.v = keys;
return AT_READ_OK;
}
static int a_readkey(attrib *a, void *owner, struct gamedata *data) {
int res = a_readint(a, owner, data);
if (data->version>=KEYVAL_VERSION) {
if (data->version >= KEYVAL_VERSION) {
return AT_READ_FAIL;
}
return (res != AT_READ_FAIL) ? AT_READ_DEPR : res;
@ -101,9 +158,46 @@ attrib_type at_key = {
a_upgradekeys
};
static int* keys_get(int *base, int i)
{
int n = base[0];
assert(i >= 0 && i < n);
return base + 1 + i * 2;
}
static int *keys_update(int *base, int key, int val)
{
int *kv;
int n = base[0];
int l = keys_lower_bound(base, key, 0, n);
if (l < n) {
kv = keys_get(base, l);
if (kv[0] == key) {
kv[1] = val;
}
else {
assert(kv[0] > key);
base = realloc(base, (n * 2 + 3) * sizeof(int));
kv = keys_get(base, l);
base[0] = n + 1;
memmove(kv + 2, kv, 2 * sizeof(int) * (n - l));
kv[0] = key;
kv[1] = val;
}
}
else {
base = realloc(base, (n * 2 + 3) * sizeof(int));
base[0] = n + 1;
kv = keys_get(base, l);
kv[0] = key;
kv[1] = val;
}
return base;
}
void key_set(attrib ** alist, int key, int val)
{
int *keys, n = 0;
int *keys;
attrib *a;
assert(key != 0);
a = a_find(*alist, &at_keys);
@ -111,16 +205,16 @@ void key_set(attrib ** alist, int key, int val)
a = a_add(alist, a_new(&at_keys));
}
keys = (int *)a->data.v;
if (keys) {
n = keys[0];
if (!keys) {
a->data.v = keys = malloc(3 * sizeof(int));
keys[0] = 1;
keys[1] = key;
keys[2] = val;
}
else {
a->data.v = keys = keys_update(keys, key, val);
assert(keys[0] < 4096 && keys[0] >= 0);
}
/* TODO: too many allocations, unsorted array */
keys = realloc(keys, sizeof(int) *(2 * n + 3));
keys[0] = n + 1;
assert(keys[0] < 4096 && keys[0]>=0);
keys[2 * n + 1] = key;
keys[2 * n + 2] = val;
a->data.v = keys;
}
void key_unset(attrib ** alist, int key)
@ -129,17 +223,19 @@ void key_unset(attrib ** alist, int key)
assert(key != 0);
a = a_find(*alist, &at_keys);
if (a) {
int i, *keys = (int *)a->data.v;
int *keys = (int *)a->data.v;
if (keys) {
int n = keys[0];
assert(keys[0] < 4096 && keys[0]>0);
for (i = 0; i != n; ++i) {
if (keys[2 * i + 1] == key) {
memmove(keys + 2 * i + 1, keys + 2 * n - 1, 2 * sizeof(int));
int l = keys_lower_bound(keys, key, 0, n);
if (l < n) {
int *kv = keys_get(keys, l);
if (kv[0] == key) {
memmove(kv, kv + 2, (n - l - 1) * 2 * sizeof(int));
// TODO: realloc to smaller size?
keys[0]--;
break;
}
}
assert(keys[0] < 4096 && keys[0]>0);
}
}
}
@ -149,12 +245,14 @@ int key_get(attrib *alist, int key) {
assert(key != 0);
a = a_find(alist, &at_keys);
if (a) {
int i, *keys = (int *)a->data.v;
int *keys = (int *)a->data.v;
if (keys) {
/* TODO: binary search this! */
for (i = 0; i != keys[0]; ++i) {
if (keys[i*2+1] == key) {
return keys[i * 2 + 2];
int n = keys[0];
int l = keys_lower_bound(keys, key, 0, n);
if (l < n) {
int * kv = keys_get(keys, l);
if (kv[0] == key) {
return kv[1];
}
}
}

View file

@ -32,8 +32,8 @@ static void test_upgrade_key(CuTest *tc) {
attrib *alist = 0;
key_set_orig(&alist, 40);
key_set_orig(&alist, 41);
key_set_orig(&alist, 42);
key_set_orig(&alist, 43);
key_set_orig(&alist, 42);
key_set_orig(&alist, 44);
CuAssertPtrNotNull(tc, alist->type->upgrade);
alist->type->upgrade(&alist, alist);

View file

@ -584,7 +584,7 @@ int rroad(const region * r, direction_t d)
bool r_isforest(const region * r)
{
if (fval(r->terrain, FOREST_REGION)) {
/* needs to be covered with at leas 48% trees */
/* needs to be covered with at least 48% trees */
int mincover = (int)(r->terrain->size * 0.48);
int trees = rtrees(r, 2) + rtrees(r, 1);
return (trees * TREESIZE >= mincover);

View file

@ -35,10 +35,11 @@
#define KEYVAL_VERSION 355 /* at_keys has values */
#define NOLANDITEM_VERSION 356 /* land_region has no items */
#define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */
#define SORTKEYS_VERSION 358 /* at_keys is sorted */
/* unfinished: */
#define CRYPT_VERSION 400 /* passwords are encrypted */
#define RELEASE_VERSION NORCSPELL_VERSION /* current datafile */
#define RELEASE_VERSION SORTKEYS_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 */