/* Search. */ void * dwarf_tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *)) { /* Nothing will change, but we discard const so we can use tsearch_inner(). */ struct hs_base **proot = (struct hs_base **)rootp; struct hs_base *head = *proot; struct ts_entry *r = 0; /* inserted flag won't be set. */ int inserted = 0; /* nullme won't be set. */ struct ts_entry * nullme = 0; /* Get to actual tree. */ if (!head) { return NULL; } r = tsearch_inner(key,head,compar,only_find,&inserted,&nullme); if(!r) { return NULL; } return (void *)(&(r->keyptr)); }
/* Unlike the simple binary tree case, a fully-empty hash situation does not null the *rootp */ void * dwarf_tdelete(const void *key, void **rootp, int (*compar)(const void *, const void *)) { struct hs_base **proot = (struct hs_base **)rootp; struct hs_base *head = *proot; struct ts_entry *found = 0; /* inserted flag won't be set. */ int inserted = 0; struct ts_entry * parentp = 0; if (!head) { return NULL; } found = tsearch_inner(key,head,compar,want_delete,&inserted, &parentp); if(found) { if(parentp) { /* Delete a chain entry. */ head->record_count_--; parentp->next = found->next; /* We free our storage. It would be up to caller to do a tfind to find a record and delete content if necessary. */ free(found); return (void *)&(parentp->keyptr); } /* So found is the head of a chain. */ if(found->next) { /* Delete a chain entry, pull up to hash tab, freeing up the chain entry. */ struct ts_entry *pullup = found->next; *found = *pullup; free(pullup); head->record_count_--; return (void *)&(found->keyptr); } else { /* Delete a main hash table entry. Problem: what the heck to return as a keyptr pointer? Well, we return NULL. As in the standard tsearch, returning NULL does not mean failure! Here it just means 'empty chain somewhere'. */ head->record_count_--; found->next = 0; found->keyptr = 0; found->entryused = 0; return NULL; } } return NULL; }
/* Search and, if missing, insert. */ void * dwarf_tsearch(const void *key, void **headpin, int (*compar)(const void *, const void *)) { struct ts_entry *head = 0; struct ts_entry *root = 0; struct ts_entry *r = 0; int inserted = 0; if(!headpin) { return NULL; } head = (struct ts_entry *)*headpin; if(head) { root = head->rlink; } if(!head || !root) { if(!head) { head = allocate_ts_entry(0); } if(!head) { return NULL; } root = allocate_ts_entry(key); if(!root) { free(root); return NULL; } head->rlink = root; *headpin = head; return (void *)(&(root->keyptr)); } root = head->rlink; r = tsearch_inner(key,root,compar,&inserted); if (!r) { return NULL; } /* Was this found or inserted? Value is the same either way, but the pointer to return is not the same! */ /* Discards const. Required by the interface definition. */ return (void *)&(r->keyptr); }
/* Search and, if missing, insert. */ void * dwarf_tsearch(const void *key, void **headin, int (*compar)(const void *, const void *)) { struct hs_base **rootp = (struct hs_base **)headin; struct hs_base *head = *rootp; struct ts_entry *r = 0; int inserted = 0; /* nullme won't be set. */ struct ts_entry *nullme = 0; if (!head) { /* something is wrong here, not initialized. */ return NULL; } r = tsearch_inner(key,head,compar,want_insert,&inserted,&nullme); if (!r) { return NULL; } return (void *)&(r->keyptr); }
/* Search and, if missing, insert. */ void * dwarf_tsearch(const void *key, void **headin, int (*compar)(const void *, const void *)) { struct ts_entry **headp = (struct ts_entry **)headin; struct ts_entry *head = 0; struct ts_entry *r = 0; int inserted = 0; /* kcomparv should be ignored */ int kcomparv = 0; /* nullme won't be set. */ struct ts_entry *nullme = 0; if (!headp) { return NULL; } head = *headp; if (!head) { struct ts_entry *root = 0; head = allocate_ts_entry(0); if(!head) { return NULL; } root = allocate_ts_entry(key); if(!root) { free(head); return NULL; } head->rlink = root; /* head->llink is used for the depth, as a count */ /* head points to the special head node ... */ *headin = head; return (void *)(&(root->keyptr)); } r = tsearch_inner(key,head,compar,&inserted,&nullme,&kcomparv); if (!r) { return NULL; } return (void *)&(r->keyptr); }
static void resize_table(struct hs_base *head, int (*compar)(const void *, const void *)) { struct hs_base newhead; unsigned new_entry_index = 0; unsigned long prime_to_use = 0; /* Copy the values we have. */ newhead = *head; /* But drop the hashtab_ from new. calloc below. */ newhead.hashtab_ = 0; newhead.record_count_ = 0; new_entry_index = head->tablesize_entry_index_ +1; prime_to_use = primes[new_entry_index]; if(prime_to_use == 0) { /* Oops, too large. Leave table size as is, though it will get slow as it overfills. */ return; } newhead.tablesize_ = prime_to_use; newhead.allowed_fill_ = calculate_allowed_fill(allowed_fill_percent, prime_to_use); if( newhead.allowed_fill_< (newhead.tablesize_/2)) { /* Oops. We are in trouble. */ return; } newhead.tablesize_entry_index_ = new_entry_index; newhead.hashtab_ = calloc(sizeof(struct ts_entry),newhead.tablesize_); if(!newhead.hashtab_) { /* Oops, too large. Leave table size as is, though things will get slow as it overfills. */ free(newhead.hashtab_); return; } { /* Insert all the records from the old table into the new table. */ int fillnewfail = 0; unsigned long ix = 0; unsigned long tsize = head->tablesize_; struct ts_entry *p = &head->hashtab_[0]; for( ; ix < tsize; ix++,p++) { int inserted = 0; struct ts_entry*n = 0; if(fillnewfail) { break; } if(p->keyptr) { tsearch_inner(p->keyptr, &newhead,compar, want_insert, &inserted, 0); if(!inserted) { fillnewfail = 1; break; } } for(n = p->next; n ; n = n->next) { inserted = 0; tsearch_inner(n->keyptr, &newhead,compar, want_insert, &inserted, 0); if(!inserted) { fillnewfail = 1; break; } } } if(fillnewfail) { free(newhead.hashtab_); return; } } /* Now get rid of the chain entries of the old table. */ dwarf_tdestroy_inner(head,0,0); /* Now get rid of the old table itself. */ free(head->hashtab_); head->hashtab_ = 0; *head = newhead; return; }