forked from github/server
sort the at_keys array, binary search.
This commit is contained in:
parent
aac2b0a60f
commit
219a3159e8
4 changed files with 141 additions and 42 deletions
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue