Skip to content

Commit

Permalink
HASH_DEL should be able to delete a const-qualified node
Browse files Browse the repository at this point in the history
HASH_DEL doesn't need to modify the target node; in fact it should not,
because that target node is usually going straight back to `free` and
any modifications to it would be wasted effort. So, let's make that an
actual tested guarantee, and let's make it const-correct.

Inspired by the discussion in #253.
  • Loading branch information
Quuxplusone committed Dec 13, 2022
1 parent 095425f commit ca98384
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/uthash.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ do {

#define HASH_DELETE_HH(hh,head,delptrhh) \
do { \
struct UT_hash_handle *_hd_hh_del = (delptrhh); \
const struct UT_hash_handle *_hd_hh_del = (delptrhh); \
if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl->buckets, \
Expand Down
2 changes: 1 addition & 1 deletion tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ PROGS = test1 test2 test3 test4 test5 test6 test7 test8 test9 \
test66 test67 test68 test69 test70 test71 test72 test73 \
test74 test75 test76 test77 test78 test79 test80 test81 \
test82 test83 test84 test85 test86 test87 test88 test89 \
test90 test91 test92 test93 test94 test95 test96
test90 test91 test92 test93 test94 test95 test96 test97
CFLAGS += -I$(HASHDIR)
#CFLAGS += -DHASH_BLOOM=16
#CFLAGS += -O2
Expand Down
1 change: 1 addition & 0 deletions tests/README
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ test93: alt_fatal
test94: utlist with fields named other than 'next' and 'prev'
test95: utstack
test96: HASH_FUNCTION + HASH_KEYCMP
test97: deleting a const-qualified node from a hash

Other Make targets
================================================================================
Expand Down
Empty file added tests/test97.ans
Empty file.
57 changes: 57 additions & 0 deletions tests/test97.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "uthash.h"

struct item {
int payload;
UT_hash_handle hh;
};

void delete_without_modifying(struct item *head, const struct item *p)
{
struct item old;
memcpy(&old, p, sizeof(struct item)); // also copy the padding bits
assert(memcmp(&old, p, sizeof(struct item)) == 0);
assert(p->hh.tbl == head->hh.tbl); // class invariant
HASH_DEL(head, p);
assert(memcmp(&old, p, sizeof(struct item)) == 0); // unmodified by HASH_DEL
}

int main()
{
struct item *items = NULL;
struct item *found = NULL;
int fortytwo = 42;
int i;

for (i=0; i < 100; i++) {
struct item *p = (struct item *)malloc(sizeof *p);
p->payload = i;
HASH_ADD_INT(items, payload, p);
}
assert(HASH_COUNT(items) == 100);

// Delete item "42" from the hash, wherever it is.
HASH_FIND_INT(items, &fortytwo, found);
assert(found != NULL);
assert(found->payload == 42);
delete_without_modifying(items, found);

assert(HASH_COUNT(items) == 99);
HASH_FIND_INT(items, &fortytwo, found);
assert(found == NULL);

// Delete the very first item in the hash.
assert(items != NULL);
i = items->payload;
delete_without_modifying(items, items);

assert(HASH_COUNT(items) == 98);
HASH_FIND_INT(items, &i, found);
assert(found == NULL);

// leak the items, we don't care

return 0;
}

0 comments on commit ca98384

Please sign in to comment.