//=-- Table.h - Define an associative array or dictionary ----------*- C++ -*-=
//
//  This file defines a standard Table class that is used to associate unique
//  keys with values.  This is currently implemented with a hash table to
//  provide good performance.  (The actual implementation of the hash table is
//  in the ChainedHashTable.h file)
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=
//
#ifndef TABLE_H
#define TABLE_H

#include <iostream.h>         // Uses the IOStream libraries...
#include <assert.h>

#include "ChainedHashTable.h"

template <class Key, class Value>
class MSAPI Table : public Object {
  typedef DataPair<Key,Value> Pair;
public :

  typedef ChainedHashTableIterator<Key,Value> Iterator;

  inline Table(unsigned int (*HashFn)(const Key &,int) = 0, int Size=17) 
          : HTable(HashFn, Size) {
    DefaultSet = 0;
  }

  inline Table(const Table<Key, Value> &T) : Object(T) {
    Copy(T);
  }

  // Copy a table
  inline void operator= (const Table<Key,Value> &T) { 
    Copy(T); 
  }

  inline void Copy(const Table<Key,Value> &T) { 
    HTable.Copy(T.HTable); 
    DefaultSet = T.DefaultSet;
    Default = T.Default;
  }

  inline void ConvertToList(LinkedList<Pair> &L) {
    HTable.ConvertToList(L);
  }

  inline int InTable(const Key &K) const {
    return HTable.InTable(K);
  }

  // Square brackets - Return the value associated with the key, or set the key
  //   to a new value.  Can be used on either the left or right side of the 
  //   equation.
  Value &operator[] (const Key &K) {
    Value *Entry = HTable.GetEntry(K);
    if (Entry) return *Entry;

    HTable.Set(K, Default);
    return *HTable.GetEntry(K);
  }

  // Square brackets - Returns the value associated with the key.  Only 
  //   suitable for use on the right side of the equation...
  inline Value operator[] (const Key &K) const {
    Value *Entry = HTable.GetEntry(K);
    if (Entry) return *Entry;

    assert(DefaultSet == 0);     // Unless the programmer explicitly set a 
    return Default;              //   default value, die...
  }

  inline Value &operator() (const Key &K, Value &Def) {
    Value *Entry = HTable.GetEntry(K);
    if (Entry) return *Entry;
    return Def;
  }

  inline Value operator() (const Key &K, const Value &Def) const {
    Value *Entry = HTable.GetEntry(K);
    if (Entry) return *Entry;
    return Def;
  }

  void SetElementTo(const Key &K, const Value &Val) {
    // Try to remove it, if it's not there, this harmlessly fails.
    HTable.Remove(K);
    HTable.Set(K, Val);
  }

  void SetDefault(const Value &D) { 
    DefaultSet = 1;
    Default = D; 
  }

  inline void Clear() { 
    HTable.Clear(); 
  }

  inline Iterator GetStart() const { 
    return HTable.GetStartItr(); 
  }

  virtual ostream &print(ostream &s) const {
    Iterator TI = GetStart();
    for (; TI; TI++) {
      s << '(' << TI.GetKey() << ',' << TI.GetValue() << ") ";
    }

    return s << endl;
  }

  // Make it Object compliant
  int Compare(const Object &) const { return 0; }

  inline int GetNumElements() const {
    return HTable.GetNumElements();
  }

  // Get the status of the default specification...
  void GetDefaultState(int &defaultSet, Value &defaultRet) const {
	defaultSet = DefaultSet;
	defaultRet = Default;
  }
  
private :
  ChainedHashTable<Key, Value> HTable;
  int DefaultSet;
  Value Default;
};

#endif

