// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_HASHTABLE_H
#define OB_HASHTABLE_H

#include <OB/Basic.h>
#include <OB/STLConfig.h>
#include <OB/allocator.h>

namespace OB
{

//
// The HashtableNode template
//
template<class K, class T, class H>
struct HashtableNode
{
    K key;
    T value;
    CORBA::ULong fullHash;
    HashtableNode<K, T, H>* next;

    HashtableNode()
    {
    }

    HashtableNode(const K& k, const T& val, HashtableNode<K, T, H>* n = 0)
        : key(k), value(val), next(n)
    {
        fullHash = H::hash(k);
    }
};

//
// The HashEnumerator template
//
template<class K>
class HashEnumerator
{
   K* keys_;
   CORBA::ULong length_;
   CORBA::ULong *ref_;

   void dec()
   {
       if(ref_ != 0)
       {
           (*ref_)--;
           if(*ref_ == 0)
           {
               delete []keys_;
               delete ref_;
           }
       }
   }

public:

   HashEnumerator() : keys_(0), length_(0), ref_(0)
   {
   }

   HashEnumerator(K* keys, CORBA::ULong len)
       : keys_(keys), length_(len)
   {
       ref_ = new CORBA::ULong(0);
       *ref_ = 1;
   }

   HashEnumerator(const HashEnumerator<K>& e)
   {
       keys_ = e.keys_;
       length_ = e.length_;
       ref_ = e.ref_;
       (*ref_)++;
   }

   ~HashEnumerator()
   {
       dec();
   }

   HashEnumerator<K>& operator=(const HashEnumerator<K>& e)
   {
       if(keys_ != e.keys_)
       {
           dec();
           keys_ = e.keys_;
           length_ = e.length_;
           ref_ = e.ref_;
           (*ref_)++;
       }
       return *this;
   }

   CORBA::ULong length() const
   {
       return length_;
   }

   K operator[](CORBA::ULong i)
   {
       assert(i < length_);
       return keys_[i];
   }
};

//
// The Hashtable template
//
// NOTE: *All methods are deliberately non-virtual for performance reasons*
//
template<class K, class T, class H>
class Hashtable
{
    //
    // Hide copy-constructor and assignment operator
    //
    Hashtable(const Hashtable&);
    void operator=(const Hashtable&);

    typedef HashtableNode<K, T, H> node;

    //
    // Hashtable node allocator
    //
    // COMPILERFIX: AIX VAC++ prints a bogus warning if we don't
    // add the typename keyword...
    //
#ifdef _AIX
    typename stl::allocator<node> allocator_;
#else
    stl::allocator<node> allocator_;
#endif
        
    //
    // Pre-allocated table data
    //
    node* stable_[15];

    //
    // Hashtable table data
    //
    node** table_;
    CORBA::ULong length_;
    CORBA::Float load_;
    CORBA::ULong count_;
    CORBA::ULong threshold_;

    void removeAll();
    void resize();

public:

    typedef HashEnumerator<K> Enumerator;

    //
    // Construct a table with len capacity
    //
    Hashtable(CORBA::ULong len = 15, CORBA::Float load = 0.75);

    //
    // The destructor
    //
    ~Hashtable();

    //
    // Clear the hash table
    //
    void clear();

    //
    // Returns true if the table contain the key
    //
    bool containsKey(const K& key) const;

    //
    // Put this object, with this key into the table
    //
    void put(const K& key, const T& value);

    //
    // Remove the entry with the provided key
    //
    void remove(const K& key);

    //
    // Get an object from the table given key
    //
    bool get(const K& key, T& value) const;

    //
    // Return all elements in the table
    //
    Enumerator keys() const;

    //
    // Returns the number of keys in the table
    //
    CORBA::ULong size() const;
    
    //
    // Display stats on the hash table
    //
    void displayStats(OB_STD(ostream)&);
};

//
// SynchronizedHashtable template (synchronize the Hashtable methods).
//
// NOTE: *All methods are deliberately non-virtual for performance reasons*
//
template<class K, class T, class H>
class SynchronizedHashtable : private Hashtable<K, T, H>,
			      public JTCRecursiveMutex
{
public:

    typedef HashEnumerator<K> Enumerator;

    SynchronizedHashtable(CORBA::ULong len = 15, CORBA::Float load = 0.75)
	: Hashtable<K,T,H>(len, load)
    {
    }

    ~SynchronizedHashtable() {  }

    void clear()
    { 
	JTCSynchronized sync(*this); 
	Hashtable<K,T,H>::clear(); 
    }
    
    bool containsKey(const K& key) const
    {
	JTCSynchronized sync(*this); 
	return Hashtable<K,T,H>::containsKey(key); 
    }

    void put(const K& key, const T& value)
    { 
	JTCSynchronized sync(*this); 
	Hashtable<K,T,H>::put(key, value); 
    }

    void remove(const K& key)
    { 
	JTCSynchronized sync(*this); 
	Hashtable<K,T,H>::remove(key); 
    }

    bool get(const K& key, T& value) const
    { 
	JTCSynchronized sync(*this); 
	return Hashtable<K,T,H>::get(key, value); 
    }

    Enumerator keys() const
    {
	JTCSynchronized sync(*this); 
	return Hashtable<K,T,H>::keys(); 
    }

    CORBA::ULong size() const
    { 
	JTCSynchronized sync(*this); 
	return Hashtable<K,T,H>::size(); 
    }
    
    void displayStats(OB_STD(ostream)& s)
    { 
	JTCSynchronized sync(*this); 
	Hashtable<K,T,H>::displayStats(s);
    }
};

//
// Some standard hashers
//
struct LongHasher
{
    static CORBA::ULong hash(CORBA::Long k) { return (CORBA::ULong)k; }
    static bool comp(CORBA::Long k1, CORBA::Long k2) { return k1 == k2; }
};

struct ULongHasher
{
    static CORBA::ULong hash(CORBA::ULong k) { return k; }
    static bool comp(CORBA::ULong k1, CORBA::ULong k2) { return k1 == k2; }
};

struct StringHasher
{
    static CORBA::ULong hash(const char*);
    static bool comp(const char*, const char*);
};

template<class T> class StrSeq;

struct StringSeqHasher
{
    static CORBA::ULong hash(const StrSeq< int >&);
    static bool comp(const StrSeq< int >&, const StrSeq< int >&);
};

} // End of namespace OB

//
// Include non-inline template operations
//
#if !defined(__TEMPINC)
#  include <OB/HashtableI.h>
#else
#  pragma implementation("HashtableI.h")
#endif

#endif
