/* This function returns the key in the hash corresponding to the key, or NULL * if it is not in the hash. This function is useful when the key you supplied * is dynamically allocated and you don't have a pointer to it anywhere except * in the hash itself. * Arguments: * Key to look for. */ void * khash_get_key(khash *self, void *key) { int index = khash_locate_key(self, key); if (index == -1) return NULL; return self->cell_array[index].key; }
/* This function removes the key / value pair from the hash (if any). * Arguments: * Key to remove. */ void khash_remove(khash *self, void *key) { int index = khash_locate_key(self, key); int gap_position = index; int scanned_pos = index; /* Key is not present in the hash. */ if(index == -1) return; /* We must ensure that other keys remain contiguous when we remove a key. * The situation where we need to move a key up is when the position of the * key given by key_func() is farther than the actual position of the key in * the hash, counting from the position of the gap. Picture: * * The key wants to be here. (Distance between gap and pos wanted is far.) * A gap is here. (So we move the key here.) * The key is here. (Distance between gap and key is close.) * * In this situation, we don't move: * The gap is here. * The key wants to be here. (Distance between gap and pos wanted is short.) * The key is here. (Distance between gap and key is far.) * * If the gap position matches the wanted pos, we must move the key to fill * the gap. * * So here's the plan: * First we locate the key to remove. Removing it causes a gap. We start * scanning the keys coming next. If we meet a NULL, we're done. If we meet * a key, we check where it wants to be. If it wants to be before the gap, * we move it there. Then the gap is now at the position of the key we * moved, and we continue at the next position. Otherwise, we just continue * with the next position. */ while (1) { int wanted_pos_dist; int key_dist; /* Scan the next position. */ scanned_pos = (scanned_pos + 1) % self->alloc_size; /* We're done. Just set the gap to NULL. */ if (self->cell_array[scanned_pos].key == NULL) { self->cell_array[gap_position].key = NULL; break; } /* Calculate the distances. */ wanted_pos_dist = khash_dist(gap_position, self->key_func(self->cell_array[scanned_pos].key) % self->alloc_size, self->alloc_size); key_dist = khash_dist(gap_position, scanned_pos, self->alloc_size); /* Situations where we must move key (and value). */ if (wanted_pos_dist > key_dist || wanted_pos_dist == 0) { self->cell_array[gap_position].key = self->cell_array[scanned_pos].key; self->cell_array[gap_position].value = self->cell_array[scanned_pos].value; gap_position = scanned_pos; } } /* Decrement the usage count. */ self->size--; }
/* This function returns true if the key is in the hash. * Arguments: * Key to look for. */ int khash_exist(khash *self, void *key) { return (khash_locate_key(self, key) != -1); }