/* Copyright (c) 2014, Google Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define _BSD_SOURCE #include #include #include #include struct dummy_lhash_node { char *s; struct dummy_lhash_node *next; }; struct dummy_lhash { struct dummy_lhash_node *head; }; static void dummy_lh_free(struct dummy_lhash *lh) { struct dummy_lhash_node *cur, *next; for (cur = lh->head; cur != NULL; cur = next) { next = cur->next; free(cur->s); free(cur); } } static size_t dummy_lh_num_items(const struct dummy_lhash *lh) { size_t count = 0; struct dummy_lhash_node *cur; for (cur = lh->head; cur != NULL; cur = cur->next) { count++; } return count; } static char *dummy_lh_retrieve(struct dummy_lhash *lh, const char *s) { struct dummy_lhash_node *cur; for (cur = lh->head; cur != NULL; cur = cur->next) { if (strcmp(cur->s, s) == 0) { return cur->s; } } return NULL; } static int dummy_lh_insert(struct dummy_lhash *lh, char **old_data, char *s) { struct dummy_lhash_node *node, *cur; for (cur = lh->head; cur != NULL; cur = cur->next) { if (strcmp(cur->s, s) == 0) { *old_data = cur->s; cur->s = s; return 1; } } node = malloc(sizeof(struct dummy_lhash_node)); *old_data = NULL; node->s = s; node->next = lh->head; lh->head = node; return 1; } static char *dummy_lh_delete(struct dummy_lhash *lh, const void *s) { struct dummy_lhash_node *cur, **next_ptr; char *ret; next_ptr = &lh->head; for (cur = lh->head; cur != NULL; cur = cur->next) { if (strcmp(cur->s, s) == 0) { ret = cur->s; *next_ptr = cur->next; free(cur); return ret; } next_ptr = &cur->next; } return NULL; } static char *rand_string(void) { unsigned len = 1 + (rand() % 3); char *ret = malloc(len + 1); unsigned i; for (i = 0; i < len; i++) { ret[i] = '0' + (rand() & 7); } ret[i] = 0; return ret; } int main(int argc, char **argv) { _LHASH *lh = lh_new(NULL, NULL); struct dummy_lhash dummy_lh = {NULL}; unsigned i; for (i = 0; i < 100000; i++) { unsigned action; char *s, *s1, *s2; if (dummy_lh_num_items(&dummy_lh) != lh_num_items(lh)) { fprintf(stderr, "Length mismatch\n"); return 1; } action = rand() % 3; switch (action) { case 0: s = rand_string(); s1 = (char *)lh_retrieve(lh, s); s2 = dummy_lh_retrieve(&dummy_lh, s); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_retrieve failure\n"); abort(); } free(s); break; case 1: s = rand_string(); lh_insert(lh, (void **)&s1, s); dummy_lh_insert(&dummy_lh, &s2, strdup(s)); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_insert failure\n"); abort(); } if (s1) { free(s1); } if (s2) { free(s2); } break; case 2: s = rand_string(); s1 = lh_delete(lh, s); s2 = dummy_lh_delete(&dummy_lh, s); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_insert failure\n"); abort(); } if (s1) { free(s1); } if (s2) { free(s2); } free(s); break; default: abort(); } } lh_doall(lh, free); lh_free(lh); dummy_lh_free(&dummy_lh); printf("PASS\n"); return 0; }