commit ab100d9e70018fb8984f13d308154a79c21c0df8
parent 0d52aac1f203a648013d993675aec375d9227381
Author: William Casarin <jb55@jb55.com>
Date: Sun, 3 Nov 2024 07:18:28 -0800
add ndb_filter_eq
filter equality testing. this works because field elements are sorted
Changelog-Added: Add ndb_filter_eq for filter equality testing
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
M | src/nostrdb.c | | | 79 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/nostrdb.h | | | 4 | ++++ |
M | test.c | | | 28 | ++++++++++++++++++++++++++++ |
3 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/src/nostrdb.c b/src/nostrdb.c
@@ -1154,6 +1154,62 @@ static void sort_filter_elements(struct ndb_filter *filter,
els->elements[i] -= (uint64_t)filter->data_buf.start;
}
+static int ndb_filter_field_eq(struct ndb_filter *a_filt,
+ struct ndb_filter_elements *a_field,
+ struct ndb_filter *b_filt,
+ struct ndb_filter_elements *b_field)
+{
+ int i;
+ const char *a_str, *b_str;
+ unsigned char *a_id, *b_id;
+ uint64_t a_int, b_int;
+
+ if (a_field->count != b_field->count)
+ return 0;
+
+ if (a_field->field.type != b_field->field.type) {
+ ndb_debug("UNUSUAL: field types do not match in ndb_filter_field_eq\n");
+ return 0;
+ }
+
+ if (a_field->field.elem_type != b_field->field.elem_type) {
+ ndb_debug("UNUSUAL: field element types do not match in ndb_filter_field_eq\n");
+ return 0;
+ }
+
+ if (a_field->field.elem_type == NDB_ELEMENT_UNKNOWN) {
+ ndb_debug("UNUSUAL: field element types are unknown\n");
+ return 0;
+ }
+
+ for (i = 0; i < a_field->count; i++) {
+ switch (a_field->field.elem_type) {
+ case NDB_ELEMENT_UNKNOWN:
+ return 0;
+ case NDB_ELEMENT_STRING:
+ a_str = ndb_filter_get_string_element(a_filt, a_field, i);
+ b_str = ndb_filter_get_string_element(b_filt, b_field, i);
+ if (strcmp(a_str, b_str))
+ return 0;
+ break;
+ case NDB_ELEMENT_ID:
+ a_id = ndb_filter_get_id_element(a_filt, a_field, i);
+ b_id = ndb_filter_get_id_element(b_filt, b_field, i);
+ if (memcmp(a_id, b_id, 32))
+ return 0;
+ break;
+ case NDB_ELEMENT_INT:
+ a_int = ndb_filter_get_int_element(a_field, i);
+ b_int = ndb_filter_get_int_element(b_field, i);
+ if (a_int != b_int)
+ return 0;
+ break;
+ }
+ }
+
+ return 1;
+}
+
void ndb_filter_end_field(struct ndb_filter *filter)
{
int cur_offset;
@@ -2616,6 +2672,29 @@ ndb_filter_find_elements(struct ndb_filter *filter, enum ndb_filter_fieldtype ty
return NULL;
}
+int ndb_filter_eq(struct ndb_filter *a, struct ndb_filter *b)
+{
+ int i;
+ struct ndb_filter_elements *a_els, *b_els;
+
+ if (a->num_elements != b->num_elements)
+ return 0;
+
+ for (i = 0; i < a->num_elements; i++) {
+ a_els = ndb_filter_get_elements(a, i);
+ b_els = ndb_filter_find_elements(b, a_els->field.type);
+
+ if (b_els == NULL)
+ return 0;
+
+ if (!ndb_filter_field_eq(a, a_els, b, b_els))
+ return 0;
+ }
+
+ return 1;
+}
+
+
static uint64_t *
ndb_filter_get_elem(struct ndb_filter *filter, enum ndb_filter_fieldtype typ)
{
diff --git a/src/nostrdb.h b/src/nostrdb.h
@@ -257,6 +257,9 @@ struct ndb_filter {
int current;
// struct ndb_filter_elements offsets into elem_buf
+ //
+ // TODO(jb55): this should probably be called fields. elements are
+ // the things within fields
int elements[NDB_NUM_FILTERS];
};
@@ -492,6 +495,7 @@ int ndb_filter_init(struct ndb_filter *);
int ndb_filter_add_id_element(struct ndb_filter *, const unsigned char *id);
int ndb_filter_add_int_element(struct ndb_filter *, uint64_t integer);
int ndb_filter_add_str_element(struct ndb_filter *, const char *str);
+int ndb_filter_eq(struct ndb_filter *, struct ndb_filter *);
// filters from json
int ndb_filter_from_json(const char *, int len, struct ndb_filter *filter, unsigned char *buf, int bufsize);
diff --git a/test.c b/test.c
@@ -1662,8 +1662,36 @@ static void test_weird_note_corruption() {
ndb_destroy(ndb);
}
+static void test_filter_eq() {
+ struct ndb_filter filter, *f = &filter;
+ struct ndb_filter filter2, *f2 = &filter2;
+
+ ndb_filter_init(f);
+ assert(ndb_filter_start_field(f, NDB_FILTER_UNTIL));
+ assert(ndb_filter_add_int_element(f, 42));
+ ndb_filter_end_field(f);
+ assert(ndb_filter_start_field(f, NDB_FILTER_KINDS));
+ assert(ndb_filter_add_int_element(f, 1));
+ assert(ndb_filter_add_int_element(f, 2));
+ ndb_filter_end_field(f);
+ ndb_filter_end(f);
+
+ ndb_filter_init(f2);
+ assert(ndb_filter_start_field(f2, NDB_FILTER_KINDS));
+ assert(ndb_filter_add_int_element(f2, 2));
+ assert(ndb_filter_add_int_element(f2, 1));
+ ndb_filter_end_field(f2);
+ assert(ndb_filter_start_field(f2, NDB_FILTER_UNTIL));
+ assert(ndb_filter_add_int_element(f2, 42));
+ ndb_filter_end_field(f2);
+ ndb_filter_end(f2);
+
+ assert(ndb_filter_eq(f, f2));
+}
+
int main(int argc, const char *argv[]) {
test_parse_filter_json();
+ test_filter_eq();
test_filter_json();
test_bech32_parsing();
test_single_url_parsing();