1 #ifndef HASH_TABLE_CLASS
2 #define HASH_TABLE_CLASS
70 template <
class key_type,
class contents>
124 bool find(
const key_type &key, contents * &item_found)
const;
130 contents *
find(
const key_type &key)
const
140 bool zap(
const key_type &key);
177 int c_estim_elements;
202 template <
class key_type,
class contents>
216 template <
class key_type,
class contents>
229 template <
class key_type,
class contents>
231 :
public basis::array<hash_wrapper<key_type, contents> >,
232 public virtual basis::root_object
239 int find(
const key_type &to_find) {
240 for (
int i = 0; i < this->
length(); i++) {
241 key_type *curr_key = this->
get(i)._id;
244 if (curr_key && (to_find == *curr_key))
247 return basis::common::NOT_FOUND;
253 template <
class key_type,
class contents>
259 (
hash_table<key_type, contents>::calculate_num_slots(estimated_elements)) {}
264 template <
class key_type,
class contents>
266 : c_estim_elements(estimated_elements),
267 _hasher(hasher.clone()),
272 template <
class key_type,
class contents>
275 #ifdef EXTREME_CHECKING
277 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
284 template <
class key_type,
class contents>
288 int log_2_truncated = int(log(
float(estimated_elements +
HASH_FUDGE_FACTOR)) / log(2.0));
290 int slots_needed_for_elems = (int)pow(2.0,
double(log_2_truncated + 1));
292 return slots_needed_for_elems;
296 template <
class key_type,
class contents>
300 #ifdef EXTREME_CHECKING
303 deadly_error(class_name(), func,
"source state did not verify.");
306 for (
int i = 0; i < source.
table_access().elements(); i++) {
309 for (
int j = 0; j < buck->
length(); j++) {
310 target.
add(*((*buck)[j]._id),
new contents(*((*buck)[j]._data)));
313 #ifdef EXTREME_CHECKING
315 deadly_error(class_name(), func,
"target state did not verify.");
320 template <
class key_type,
class contents>
323 #ifdef EXTREME_CHECKING
325 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
328 for (
int i = 0; i < _table->elements(); i++) {
331 for (
int j = 0; j < buck->
length(); j++) {
339 #ifdef EXTREME_CHECKING
341 deadly_error(class_name(), func,
"state did not verify afterwards.");
345 template <
class key_type,
class contents>
348 for (
int i = 0; i < _table->elements(); i++) {
351 for (
int j = 0; j < buck->
length(); j++) {
366 template <
class key_type,
class contents>
371 template <
class key_type,
class contents>
374 #ifdef EXTREME_CHECKING
376 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
383 for (
int i = 0; i < _table->elements(); i++) {
384 buckie *b = _table->borrow(i);
386 for (
int j = b->length() - 1; j >= 0; j--) {
387 key_type *k = b->use(j)._id;
388 contents *c = b->use(j)._data;
397 _table->adjust(new_hash._table->elements());
398 for (
int q = 0; q < new_hash._table->elements(); q++)
399 _table->put(q, new_hash._table->acquire(q));
401 c_estim_elements = new_hash.c_estim_elements;
403 #ifdef EXTREME_CHECKING
405 deadly_error(class_name(), func,
"state did not verify afterwards.");
409 template <
class key_type,
class contents>
412 {
return add(
new key_type(key), to_store); }
414 template <
class key_type,
class contents>
416 contents *to_store,
bool check_dupes)
418 #ifdef EXTREME_CHECKING
420 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
423 basis::un_int hashed = _hasher->hash((
const void *)key,
sizeof(key_type));
425 hashed = hashed % _table->elements();
431 _table->
put(hashed, buck);
438 int indy = buck->
find(*key);
442 #ifdef EXTREME_CHECKING
444 deadly_error(class_name(), func,
"state did not verify afterwards.");
451 (*buck)[indy]._data = to_store;
452 #ifdef EXTREME_CHECKING
454 deadly_error(class_name(), func,
"state did not verify afterwards.");
459 template <
class key_type,
class contents>
461 (
const key_type &key, contents *to_store)
462 {
return add(
new key_type(key), to_store,
false); }
464 template <
class key_type,
class contents>
466 contents * &item_found)
const
468 #ifdef EXTREME_CHECKING
470 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
474 basis::un_int hashed = _hasher->hash((
const void *)&key,
sizeof(key));
476 hashed = hashed % _table->elements();
479 if (!buck)
return false;
480 int indy = buck->
find(key);
483 item_found = (*buck)[indy]._data;
487 template <
class key_type,
class contents>
490 #ifdef EXTREME_CHECKING
492 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
495 basis::un_int hashed = _hasher->hash((
const void *)&key,
sizeof(key));
497 hashed = hashed % _table->elements();
501 int indy = buck->
find(key);
503 contents *to_return = (*buck)[indy]._data;
505 buck->
zap(indy, indy);
506 #ifdef EXTREME_CHECKING
508 deadly_error(class_name(), func,
"state did not verify afterwards.");
513 template <
class key_type,
class contents>
516 #ifdef EXTREME_CHECKING
518 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
521 basis::un_int hashed = _hasher->hash((
const void *)&key,
sizeof(key));
523 hashed = hashed % _table->elements();
526 if (!buck)
return false;
527 int indy = buck->
find(key);
534 buck->
zap(indy, indy);
537 buck = _table->acquire(hashed);
540 #ifdef EXTREME_CHECKING
542 deadly_error(class_name(), func,
"state did not verify afterwards.");
547 template <
class key_type,
class contents>
551 #ifdef EXTREME_CHECKING
553 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
557 int posn = _last_iter;
558 while (bucks_seen++ < _table->elements()) {
559 if ( (posn < 0) || (posn >= _table->elements()) )
561 buckie *b = _table->borrow(posn);
567 for (
int j = 0; j < b->length(); j++) {
568 contents *c = b->
use(j)._data;
570 #ifdef EXTREME_CHECKING
571 deadly_error(
"hash_table",
"apply",
"logic error--missing pointer");
575 if (!to_apply(*b->use(j)._id, *c, data_link))
return;
580 template <
class key_type,
class contents>
583 #ifdef EXTREME_CHECKING
585 if (!verify())
deadly_error(class_name(), func,
"state did not verify.");
589 for (
int i = 0; i < _table->elements(); i++) {
592 to_return += buck->
length();
597 #undef static_class_name
Represents a sequential, ordered, contiguous collection of objects.
@ EXPONE
synonym for EXPONENTIAL_GROWTH.
@ SIMPLE_COPY
the contents can be memcpy'd and are not deep.
@ FLUSH_INVISIBLE
blanks out allocated but inaccessible elements.
outcome put(int index, const contents &to_put)
Stores an object at the index "index" in the array.
const hash_wrapper< key_type, contents > & get(int index) const
Accesses individual objects stored in "this" at the "index" position.
int length() const
Returns the current reported length of the allocated C array.
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
contents & use(int index)
A non-constant version of get(); the returned object can be modified.
array(int number=0, const hash_wrapper< key_type, contents > *init=NULL_POINTER, int flags=EXPONENTIAL_GROWTH|FLUSH_INVISIBLE)
Constructs an array with room for "number" objects.
A clonable object knows how to make copy of itself.
Root object for any class that knows its own name.
Outcomes describe the state of completion for an operation.
int find(const key_type &to_find)
Implements hashing into buckets for quick object access.
bool apply_function(const key_type &key, contents ¤t, void *data_link)
the "apply_function" is what a user of the "apply" method must supply.
int elements() const
the number of valid items we found by traversing the hash table.
basis::outcome add(key_type *key, contents *to_store, bool check_dupes=true)
specialized add for a pre-existing pointer "key".
basis::outcome add(const key_type &key, contents *to_store)
Stores "to_store" into the table given its "key" for hashing.
internal_hash_array< key_type, contents > & table_access() const
special accessor for the copy_hash_table method only.
bool verify() const
returns true if the hash table is internally consistent.
DEFINE_CLASS_NAME("hash_table")
static int calculate_num_slots(int estimated_elements)
a helper method that lets us know what n is for how many 2^n slots we should have.
void apply(apply_function *to_apply, void *data_link)
Invokes the function "to_apply" on every entry in the table.
void rehash(int estimated_elements)
resizes the hashing structures to optimise for a new size of "estimated_elements".
contents * acquire(const key_type &key)
retrieves the contents held for "key" out of the table.
void reset()
removes all entries in the table and returns it to a pristine state.
bool find(const key_type &key, contents *&item_found) const
locates the item specified by the "key", if possible.
basis::outcome fast_dangerous_add(const key_type &key, contents *to_store)
Like the add method above, but doesn't check for duplicates.
hash_table(const hashing_algorithm &hasher, int estimated_elements)
Creates a table using the "hasher" that is ready to store "estimated_elements".
virtual ~hash_table()
destroys any objects left in the hash_table.
int estimated_elements() const
returns the size of table we're optimized for.
contents * find(const key_type &key) const
simplified form of above find() method.
bool zap(const key_type &key)
removes the entry with the "key" specified.
hash_wrapper(key_type *id=NULL_POINTER, contents *data=NULL_POINTER)
A hashing algorithm takes a key and derives a related integer from it.
virtual hashing_algorithm * clone() const =0
supports virtual construction of new algorithm objects.
virtual basis::un_int hash(const void *key_data, int key_length) const =0
returns a hash value based on the "key_data" and "key_length".
internal_hash_array(int estimated_elements)
#define deadly_error(c, f, i)
#define NULL_POINTER
The value representing a pointer to nothing.
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
The guards collection helps in testing preconditions and reporting errors.
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
unsigned int un_int
Abbreviated name for unsigned integers.
bool negative(const type &a)
negative returns true if "a" is less than zero.
A dynamic container class that holds any kind of object via pointers.
void copy_hash_table(hash_table< key_type, contents > &target, const hash_table< key_type, contents > &source)
Copies the entire hash table, given a contents type that supports copying.
const int HASH_FUDGE_FACTOR