name: HashTable<class THashable, class TObject> : public DstrBase
synopsis:

>     g++ [flags ...] file ...

>     #include <HashTable.h>

>     HashTable(ALLOCATION alloc = SYSTEM, long initial_capacity =
>               DEF_CAPACITY, float load_factor = DEF_LOAD_FACTOR));
>     TObject* get(const THashable& key);
>     const TObject* get(const THashable& key) const;
>     boolean insert(THashable& key, TObject* value);
>     boolean keys(Vector& keys_list) const;
>     boolean values(Vector<TObject>& items_list) const;

quick start:

>     // declare a character hash table and insert a character in it
>     //
>     HashTable<String,Char> table0;
>     Char item(L'a');
>     String key(L"test_key");
>     table0.insert(key, &item);

>     // get the item out
>     //
>     if(table0.get(key)->ne(item)) {

>       // error
>       //
>     }

description:
The HashTable class is an effective way of implementing dictionary lookups since it provides an extremely fast way of inserting, deleting, and searching for items. For a good reference on hash tables, see:

T. Cormen, C. Leiserson, R. Rivest, Introduction to Algorithms, MIT Press, Boston, Massachusetts, USA, pp. 219-243, 1998.

This class uses a vector of single linked lists in SYSTEM mode to manage the HashTable.
dependencies:

- Vector
- SingleLinkedList
- Pair
- Long
- Console
- MemoryManager

public constants:

- define the class name:

      static const String CLASS_NAME = L"HashTable";

- i/o related constants:

      static const String DEF_PARAM = L"HashTable";

      static const String PARAM_NODES = L"hash_table";

      static const String PARAM_LOAD_FACTOR = L"load_factor";

- default values:

      static const float DEF_LOAD_FACTOR = 0.75;

      static const long DEF_CAPACITY = 100;

- when to compress the capacity:

      static const float LOAD_LOWER_BOUND = 0.10;

error codes:

- error code indicating HashTable class general error:

      static const long ERR = 40800;

protected data:

- define typedefs for the hash node object:

      typedef Pair< THashable, Node<TObject> > HashNode;

      typedef HashTable<THashable, TObject> Type;

- define the storage element for the hash entries:

      Vector< SingleLinkedList<HashNode> > table_d;

- define the load factor:

      Float load_factor_d;

- define the total number of items in the hash table:

      Long num_items_d;

- define the flag of memory allocation mode:

      ALLOCATION alloc_d;

- declare the debugging parameters:

      static Integral::DEBUG debug_level_d;

- define the memory manager:

      static MemoryManager mgr_d;

required public methods:

- static methods: the diagnose method is moved outside the class header file and defined in the HashTableDiagnose.h in order to avoid issues with preprocessing of the diagnose code

      static const String& name();

      static boolean diagnose(Integral::DEBUG debug_level);

- debug methods:

      static boolean setDebug(Integral::DEBUG debug_level);

      boolean debug(const unichar* message) const;

- destructor/constructor(s):

      ~HashTable();

      HashTable(ALLOCATION alloc = SYSTEM, long initial_capacity = DEF_CAPACITY, float load_factor = DEF_LOAD_FACTOR);

      HashTable(const HashTable<THashable, TObject>& copy_table);

- assign methods:

      boolean assign(const HashTable<THashable, TObject>& copy_table);

- operator= methods:

      HashTable& operator=(const HashTable<THashable, TObject>& arg);

- i/o methods: refer to the notes section for an explanation of why there are two read and write methods in this class

      long sofSize() const;

      boolean read(Sof& sof, long tag);

      boolean write(Sof& sof, long tag) const;

      boolean read(Sof& sof, long tag, const String& name);

      boolean write(Sof& sof, long tag, const String& name) const;

      boolean readData(Sof& sof, const String& pname = DEF_PARAM, long size = SofParser::FULL_OBJECT, boolean param_a = true,boolean nested_a = false);

      boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;

- equality methods:

      boolean eq(const HashTable<THashable, TObject>& compare_node) const;

- memory management methods:

      void* operator new(size_t size);

      void* operator new[](size_t size);

      void operator delete(void* ptr);

      void operator delete[](void* ptr);

      static boolean setGrowSize(long grow_size);

      boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

class-specific public methods:

- extension to required methods:

      boolean ne(const HashTable<THashable, TObject>& compare_table) const;

- hash table manipulation methods:

      TObject* get(const String& key);

      boolean insert(THashable& key, TObject* value);

      boolean remove(const THashable& key, TObject*& value);

      boolean remove(const THashable& key);

- hash table data access methods:

      boolean keys(Vector<THashable>& keys_vector) const;

      boolean values(Vector<TObject>& values) const;

- hash table property methods:

      long getCapacity() const;

      boolean setCapacity(long capacity);

      boolean setLoadFactor(float factor);

      long getNumItems() const;

      boolean isEmpty() const;

      boolean containsKey(const THashable& key);

      boolean containsValue(TObject* item);

- hash table memory allocation methods:

      ALLOCATION getAllocationMode() const;

      boolean setAllocationMode(ALLOCATION alloc) const;

private methods:

- methods to determine if the specified object is contained in the HashTable:

      boolean findKey(long& index, const THashable& key);

- method to rehash the data to a new capacity:

      boolean rehash(long new_capacity);

- methods to access the current element in the ith list:

      const THashable& getCurrKey(long i) const;

      THashable& getCurrKey(long i);

      const TObject* getCurrObject(long i) const;

      TObject* getCurrObject(long i);

      boolean setCurrObject(long i, TObject* arg);

- methods to transform to and from a single list (used in rehash & i/o methods)

      boolean getList(SingleLinkedList<HashNode>& arg_a);

      boolean assignFromList(SingleLinkedList<HashNode>& arg_a);

friend classes:

    friend class HashTableDiagnose;

examples:

- This example shows how to use a HashTable in SYSTEM mode (the default):

      #include <HashTable.h>

      int main() {

        // local variables
        //
        HashTable<String, Long> ages;
        String name;
        Long age;

        // insert 4 peoples names and ages
        //
        name.assign(L"Rick");
        age.assign(23);
        ages.insert(name, &age);

        name.assign(L"Jon");
        age.assign(26);
        ages.insert(name, &age);

        name.assign(L"Shivali");
        age.assign(24);
        ages.insert(name, &age);

        name.assign(L"Issac");
        age.assign(21);
        ages.insert(name, &age);

        // extract a name and print out the age
        //
        name.assign(L"Rick");
        ages.get(name)->debug(L"Rick's age");

        // delete Shivali's entry
        //
        name.assign(L"Shivali");
        ages.remove(name);

        // exit gracefully
        //
        Integral::exit();
      }

- This example shows how to use a HashTable in USER mode. Note that we have to allocate object memory by hand and make sure it is deleted.

      #include <HashTable.h>

      int main() {

        // local variables
        //
        HashTable<String, Long> ages(USER);
        String name;
        Long* age;

        // insert 4 peoples names and ages
        //
        name.assign(L"Rick");
        age = new Long(23);
        ages.insert(name, age);

        name.assign(L"Jon");
        age = new Long(26);
        ages.insert(name, age);

        name.assign(L"Shivali");
        age = new Long(24);
        ages.insert(name, age);

        name.assign(L"Issac");
        age = new Long(21);
        ages.insert(name, age);

        // extract a name and print out the age
        //
        name.assign(L"Rick");
        ages.get(name)->debug(L"Rick's age");

        // remove Shivali's entry
        //
        name.assign(L"Shivali");
        age = (Long*)NULL;
        ages.remove(name, age);
        delete age;

        // cleanup memory
        //
        ages.clear(Integral::FREE);
      }

notes:

- There are two memory allocation modes for HashTable as indicated by the protected member data, alloc_d. The default allocation mode is SYSTEM. In SYSTEM mode the HashTable handles allocation and deletion of the objects. In other words, the HashTable makes copies of whatever objects are passed in. In USER mode the whatever object is passed in is stored directly, so the USER must make sure that the memory is allocated and deleted.
- Note that internally the List objects will always be in SYSTEM mode. The only difference for USER and SYSTEM mode will be controlled manually via the Node class inside the HashNode.
- Unlike other classes, we have two read and write methods in dstr classes. The interface is still the same as that in other classes. The reason behind this is that we can not use "CLASS_NAME" as default argument in the read and write methods here because the data structures build the class name on the fly.