diff --git a/src/datastructures.c b/src/datastructures.c index a12707ef9758db93ad79dc052533b40cdd4edcbb..bd9b4ebefb4e8069a983e153decb0e3059737af6 100644 --- a/src/datastructures.c +++ b/src/datastructures.c @@ -232,6 +232,7 @@ int h_hashtable_present(const HHashTable* ht, const void* key) { } return false; } + void h_hashtable_del(HHashTable* ht, const void* key) { HHashValue hashval = ht->hashFunc(key); #ifdef CONSISTENCY_CHECK @@ -257,6 +258,7 @@ void h_hashtable_del(HHashTable* ht, const void* key) { } } } + void h_hashtable_free(HHashTable* ht) { for (size_t i = 0; i < ht->capacity; i++) { HHashTableEntry *hten, *hte = &ht->contents[i]; @@ -272,6 +274,56 @@ void h_hashtable_free(HHashTable* ht) { h_arena_free(ht->arena, ht->contents); } +// helper for hte_equal +static bool hte_same_length(HHashTableEntry *xs, HHashTableEntry *ys) { + for(; xs && ys; xs=xs->next, ys=ys->next) { + // skip NULL keys (= element not present) + if(xs->key == NULL) xs=xs->next; + if(ys->key == NULL) ys=ys->next; + } + return (xs == ys); // both NULL +} + +// helper for hte_equal: are all elements of xs present in ys? +static bool hte_subset(HEqualFunc eq, HHashTableEntry *xs, HHashTableEntry *ys) +{ + for(; xs; xs=xs->next) { + if(xs->key == NULL) continue; // element not present + + HHashTableEntry *hte; + for(hte=ys; hte; hte=hte->next) { + if(hte->key == xs->key) break; // assume an element is equal to itself + if(hte->hashval != xs->hashval) continue; // shortcut + if(eq(hte->key, xs->key)) break; + } + if(hte == NULL) return false; // element not found + } + return true; // all found +} + +// compare two lists of HHashTableEntries +static inline bool hte_equal(HEqualFunc eq, HHashTableEntry *xs, HHashTableEntry *ys) { + return (hte_same_length(xs, ys) && hte_subset(eq, xs, ys)); +} + +/* Set equality of HHashSets. + * Obviously, 'a' and 'b' must use the same equality function. + * Not strictly necessary, but we also assume the same hash function. + */ +bool h_hashset_equal(const HHashSet *a, const HHashSet *b) { + if(a->capacity == b->capacity) { + // iterate over the buckets in parallel + for(size_t i=0; i < a->capacity; i++) { + if(!hte_equal(a->equalFunc, &a->contents[i], &b->contents[i])) + return false; + } + } else { + assert_message(0, "h_hashset_equal called on sets of different capacity"); + // TODO implement general case + } + return true; +} + bool h_eq_ptr(const void *p, const void *q) { return (p==q); } diff --git a/src/internal.h b/src/internal.h index 01861f5e70189dedb3313a0db28f1ddf02f3c9a1..11836826c9771ed8d46302ec8c4f118ce14fac0f 100644 --- a/src/internal.h +++ b/src/internal.h @@ -272,6 +272,7 @@ typedef HHashTable HHashSet; #define h_hashset_empty(ht) h_hashtable_empty(ht) #define h_hashset_del(ht,el) h_hashtable_del(ht,el) #define h_hashset_free(ht) h_hashtable_free(ht) +bool h_hashset_equal(const HHashSet *a, const HHashSet *b); bool h_eq_ptr(const void *p, const void *q); HHashValue h_hash_ptr(const void *p);