diff --git a/src/adb.c b/src/adb.c index 560e19f..ed896ff 100644 --- a/src/adb.c +++ b/src/adb.c @@ -472,72 +472,109 @@ struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj * return adb_r_obj(o->db, adb_ro_val(o, i), no, schema); } -int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i) +int adb_ro_cmpobj(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned mode) { - assert(o1->schema->kind == ADB_KIND_OBJECT); - assert(o1->schema == o2->schema); - assert(i > 0 && i < o1->schema->num_fields); + const struct adb_object_schema *schema = obj->schema; + int is_set, r = 0; - switch (*o1->schema->fields[i-1].kind) { + assert(schema->kind == ADB_KIND_OBJECT); + assert(schema == tmpl->schema); + + for (unsigned int i = ADBI_FIRST; i <= adb_ro_num(tmpl); i++) { + is_set = adb_ro_val(tmpl, i) != ADB_VAL_NULL; + if (mode == ADB_OBJCMP_EXACT || is_set) { + r = adb_ro_cmp(tmpl, obj, i, mode); + if (r) return r; + } + if (mode == ADB_OBJCMP_INDEX && !is_set) + return 0; + if (mode != ADB_OBJCMP_EXACT && i >= schema->num_compare) + return 0; + } + return 0; +} + +int adb_ro_cmp(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned i, unsigned mode) +{ + const struct adb_object_schema *schema = obj->schema; + + assert(schema->kind == ADB_KIND_OBJECT); + assert(schema == tmpl->schema); + assert(i > 0 && i < schema->num_fields); + + switch (*schema->fields[i-1].kind) { case ADB_KIND_BLOB: case ADB_KIND_INT: - return container_of(o1->schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare( - o1->db, adb_ro_val(o1, i), - o2->db, adb_ro_val(o2, i)); + return container_of(schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare( + tmpl->db, adb_ro_val(tmpl, i), + obj->db, adb_ro_val(obj, i)); case ADB_KIND_OBJECT: { - struct adb_obj so1, so2; - adb_ro_obj(o1, i, &so1); - adb_ro_obj(o2, i, &so2); - return so1.schema->compare(&so1, &so2); + struct adb_obj stmpl, sobj; + adb_ro_obj(tmpl, i, &stmpl); + adb_ro_obj(obj, i, &sobj); + return adb_ro_cmpobj(&stmpl, &sobj, mode); } } assert(0); } -static struct adb *__db1, *__db2; -static const struct adb_object_schema *__schema; +static struct wacmp_param { + struct adb *db1, *db2; + const struct adb_object_schema *schema; + int mode; +} __wacmp_param; static int wacmp(const void *p1, const void *p2) { + struct wacmp_param *wp = &__wacmp_param; struct adb_obj o1, o2; - adb_r_obj(__db1, *(adb_val_t *)p1, &o1, __schema); - adb_r_obj(__db2, *(adb_val_t *)p2, &o2, __schema); - return o1.schema->compare(&o1, &o2); + adb_r_obj(wp->db1, *(adb_val_t *)p1, &o1, wp->schema); + adb_r_obj(wp->db2, *(adb_val_t *)p2, &o2, wp->schema); + return adb_ro_cmpobj(&o1, &o2, wp->mode); } static int wadbcmp(const void *p1, const void *p2) { + struct wacmp_param *wp = &__wacmp_param; struct adb a1, a2; struct adb_obj o1, o2; - adb_m_blob(&a1, adb_r_blob(__db1, *(adb_val_t *)p1), 0); - adb_m_blob(&a2, adb_r_blob(__db2, *(adb_val_t *)p2), 0); - adb_r_rootobj(&a1, &o1, __schema); - adb_r_rootobj(&a2, &o2, __schema); - return __schema->compare(&o1, &o2); + adb_m_blob(&a1, adb_r_blob(wp->db1, *(adb_val_t *)p1), 0); + adb_m_blob(&a2, adb_r_blob(wp->db2, *(adb_val_t *)p2), 0); + adb_r_rootobj(&a1, &o1, wp->schema); + adb_r_rootobj(&a2, &o2, wp->schema); + return adb_ro_cmpobj(&o1, &o2, wp->mode); } -int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val) +int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl) { - adb_val_t *ndx; + const struct adb_object_schema *schema = arr->schema, *item_schema; + struct adb_obj obj; - __db1 = db; - __db2 = arr->db; - __schema = arr->schema; - assert(__schema->kind == ADB_KIND_ARRAY); - __schema = container_of(__schema->fields[0].kind, struct adb_object_schema, kind); + assert(schema->kind == ADB_KIND_ARRAY); + assert(*schema->fields[0].kind == ADB_KIND_OBJECT); + item_schema = container_of(schema->fields[0].kind, struct adb_object_schema, kind), + assert(item_schema == tmpl->schema); if (cur == 0) { - ndx = bsearch(&val, &arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp); - if (!ndx) return -1; - cur = ndx - arr->obj; - while (cur > 1 && wacmp(&val, &arr->obj[cur-1]) == 0) cur--; + unsigned m, l = ADBI_FIRST, r = adb_ra_num(arr) + 1; + while (l < r) { + m = (l + r) / 2; + if (adb_ro_cmpobj(tmpl, adb_ro_obj(arr, m, &obj), ADB_OBJCMP_INDEX) < 0) + r = m; + else + l = m + 1; + } + cur = r - 1; } else { cur++; - if (wacmp(&val, &arr->obj[cur]) != 0) - return -1; } - return cur; + for (; cur <= adb_ra_num(arr); cur++) { + adb_ro_obj(arr, cur, &obj); + if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_TEMPLATE) == 0) return cur; + if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_INDEX) != 0) return -1; + } + return -1; } /* Write interface */ @@ -939,15 +976,20 @@ adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t b) void adb_wa_sort(struct adb_obj *arr) { - assert(arr->schema->kind == ADB_KIND_ARRAY); - __db1 = __db2 = arr->db; + const struct adb_object_schema *schema = arr->schema; + assert(schema->kind == ADB_KIND_ARRAY); + __wacmp_param = (struct wacmp_param) { + .db1 = arr->db, + .db2 = arr->db, + .mode = ADB_OBJCMP_EXACT, + }; switch (*arr->schema->fields[0].kind) { case ADB_KIND_OBJECT: - __schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind); + __wacmp_param.schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind); qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp); break; case ADB_KIND_ADB: - __schema = container_of(arr->schema->fields[0].kind, struct adb_adb_schema, kind)->schema; + __wacmp_param.schema = container_of(arr->schema->fields[0].kind, struct adb_adb_schema, kind)->schema; qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wadbcmp); break; default: diff --git a/src/adb.h b/src/adb.h index 49509d4..3372c07 100644 --- a/src/adb.h +++ b/src/adb.h @@ -105,13 +105,17 @@ struct adb_sign_v0 { #define ADB_ARRAY_ITEM(_t) { { .kind = &(_t).kind } } #define ADB_FIELD(_i, _n, _t) [(_i)-1] = { .name = _n, .kind = &(_t).kind } +#define ADB_OBJCMP_EXACT 0 // match all fields +#define ADB_OBJCMP_TEMPLATE 1 // match fields set on template +#define ADB_OBJCMP_INDEX 2 // match fields until first non-set one + struct adb_object_schema { uint8_t kind; uint16_t num_fields; + uint16_t num_compare; apk_blob_t (*tostring)(struct adb_obj *, char *, size_t); int (*fromstring)(struct adb_obj *, apk_blob_t); - int (*compare)(const struct adb_obj *, const struct adb_obj *); void (*pre_commit)(struct adb_obj *); struct { @@ -192,8 +196,9 @@ adb_val_t adb_ro_val(const struct adb_obj *o, unsigned i); uint32_t adb_ro_int(const struct adb_obj *o, unsigned i); apk_blob_t adb_ro_blob(const struct adb_obj *o, unsigned i); struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj *); -int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i); -int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val); +int adb_ro_cmpobj(const struct adb_obj *o1, const struct adb_obj *o2, unsigned mode); +int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i, unsigned mode); +int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl); /* Primitive write */ void adb_w_root(struct adb *, adb_val_t); diff --git a/src/apk_adb.c b/src/apk_adb.c index 25508c1..febe359 100644 --- a/src/apk_adb.c +++ b/src/apk_adb.c @@ -341,17 +341,12 @@ fail: return -APKE_DEPENDENCY_FORMAT; } -static int dependency_cmp(const struct adb_obj *o1, const struct adb_obj *o2) -{ - return adb_ro_cmp(o1, o2, ADBI_DEP_NAME); -} - const struct adb_object_schema schema_dependency = { .kind = ADB_KIND_OBJECT, .num_fields = ADBI_DEP_MAX, + .num_compare = ADBI_DEP_NAME, .tostring = dependency_tostring, .fromstring = dependency_fromstring, - .compare = dependency_cmp, .fields = { ADB_FIELD(ADBI_DEP_NAME, "name", scalar_string), ADB_FIELD(ADBI_DEP_VERSION, "version", scalar_version), @@ -383,20 +378,10 @@ const struct adb_object_schema schema_dependency_array = { .fields = ADB_ARRAY_ITEM(schema_dependency), }; -static int pkginfo_cmp(const struct adb_obj *o1, const struct adb_obj *o2) -{ - int r; - r = adb_ro_cmp(o1, o2, ADBI_PI_NAME); - if (r) return r; - r = adb_ro_cmp(o1, o2, ADBI_PI_VERSION); - if (r) return r; - return adb_ro_cmp(o1, o2, ADBI_PI_UNIQUE_ID); -} - const struct adb_object_schema schema_pkginfo = { .kind = ADB_KIND_OBJECT, .num_fields = ADBI_PI_MAX, - .compare = pkginfo_cmp, + .num_compare = ADBI_PI_UNIQUE_ID, .fields = { ADB_FIELD(ADBI_PI_NAME, "name", scalar_string), ADB_FIELD(ADBI_PI_VERSION, "version", scalar_version), @@ -448,15 +433,10 @@ const struct adb_object_schema schema_acl = { }, }; -static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2) -{ - return adb_ro_cmp(o1, o2, ADBI_FI_NAME); -} - const struct adb_object_schema schema_file = { .kind = ADB_KIND_OBJECT, .num_fields = ADBI_FI_MAX, - .compare = file_cmp, + .num_compare = ADBI_FI_NAME, .fields = { ADB_FIELD(ADBI_FI_NAME, "name", scalar_string), ADB_FIELD(ADBI_FI_ACL, "acl", schema_acl), @@ -477,7 +457,7 @@ const struct adb_object_schema schema_file_array = { const struct adb_object_schema schema_dir = { .kind = ADB_KIND_OBJECT, .num_fields = ADBI_DI_MAX, - .compare = file_cmp, + .num_compare = ADBI_DI_NAME, .fields = { ADB_FIELD(ADBI_DI_NAME, "name", scalar_string), ADB_FIELD(ADBI_DI_ACL, "acl", schema_acl), @@ -506,15 +486,10 @@ const struct adb_object_schema schema_scripts = { }, }; -static int package_cmp(const struct adb_obj *o1, const struct adb_obj *o2) -{ - return adb_ro_cmp(o1, o2, ADBI_PKG_PKGINFO); -} - const struct adb_object_schema schema_package = { .kind = ADB_KIND_OBJECT, .num_fields = ADBI_PKG_MAX, - .compare = package_cmp, + .num_compare = ADBI_PKG_PKGINFO, .fields = { ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo), ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_dir_array), diff --git a/src/app_mkndx.c b/src/app_mkndx.c index ba01878..9e6cd7b 100644 --- a/src/app_mkndx.c +++ b/src/app_mkndx.c @@ -208,7 +208,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a adb_w_init_tmp(&tmpdb, 200); adb_wo_alloca(&tmpl, &schema_pkginfo, &tmpdb); - adb_w_init_alloca(&ctx->db, ADB_SCHEMA_INDEX, 1000); + adb_w_init_alloca(&ctx->db, ADB_SCHEMA_INDEX, 8000); adb_wo_alloca(&ndx, &schema_index, &ctx->db); adb_wo_alloca(&ctx->pkgs, &schema_pkginfo_array, &ctx->db); adb_wo_alloca(&ctx->pkginfo, &schema_pkginfo, &ctx->db); @@ -240,7 +240,6 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a if (index_mtime >= fi.mtime) { char *fname, *fend; apk_blob_t bname, bver; - adb_val_t match; int i; /* Check that it looks like a package name */ @@ -260,15 +259,13 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a adb_wo_blob(&tmpl, ADBI_PI_NAME, bname); adb_wo_blob(&tmpl, ADBI_PI_VERSION, bver); adb_wo_int(&tmpl, ADBI_PI_FILE_SIZE, fi.size); - match = adb_w_obj(&tmpl); - if ((i = adb_ra_find(&opkgs, 0, &tmpdb, match)) > 0) { + if ((i = adb_ra_find(&opkgs, 0, &tmpl)) > 0) { struct adb_obj pkg; adb_ro_obj(&opkgs, i, &pkg); val = adb_wa_append(&ctx->pkgs, adb_w_copy(&ctx->db, &odb, adb_ro_val(&opkgs, i))); found = TRUE; - break; } } if (!found) {