// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_HASHTABLE_H
#define OB_HASHTABLE_H

template <class K, class T>
struct OBHashtableNode
{
    K key;
    T value;
    CORBA_ULong fullHash;
    OBHashtableNode<K, T>* next;

    OBHashtableNode()
    {
    }

    OBHashtableNode(K k, T val, OBHashtableNode<K, T>* n = 0)
        : key(k), value(val), next(n)
    {
        fullHash = OBHash(k);
    }
};

template <class K>
class OBHashEnumerator
{
   K* keys_;
   CORBA_ULong length_;
   CORBA_ULong *ref_;

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

public:
   OBHashEnumerator() : keys_(0), length_(0), ref_(0)
   {
   }

   OBHashEnumerator(K* keys, CORBA_ULong len)
       : keys_(keys), length_(len)
   {
       ref_ = new CORBA_ULong(0);
       *ref_ = 1;
   }

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

   ~OBHashEnumerator()
   {
       dec();
   }

   OBHashEnumerator<K>& operator=(const OBHashEnumerator<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 third template parameter is the locking strategy. This determines
// how internal hashtable methods are synchronized.  The typename must be
// specified to work around a bug in the aCC compiler on HP platforms. 
//
template <class K, class T, class LS>
#if defined(__hpux) && !defined(__GNUG__) 
class OBHashtable : public typename LS::MutexT
#else
class OBHashtable : public LS::MutexT
#endif
{
    typedef OBHashtableNode<K, T> node;

    //
    // Hashtable table data
    //
    node** table_;
    CORBA_ULong length_;
    CORBA_Float load_;
    CORBA_ULong count_;
    CORBA_ULong threshold_;

    void removeAll();
    void resize();

public:

    typedef OBHashEnumerator<K> Enumerator;

    //
    // Construct a table with len capacity
    //
    OBHashtable(CORBA_ULong len, CORBA_Float load = 0.75);

    //
    // The destructor
    //
    ~OBHashtable();

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

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

    //
    // Put this object, with this key into the table
    //
    void put(const K& key, 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;

    //
    // Display stats on the hash table
    //
    void displayStats(ostream&);
};

#ifdef HAVE_JTC

//
// This strategy fully synchronizes the hashtable.
//
class OBLockStrategySynchronized
{
    JTCSynchronized sync_;

public:

    typedef JTCRecursiveMutex MutexT;

    OBLockStrategySynchronized(const JTCRecursiveMutex& m)
	: sync_(m)
    {
    }

    ~OBLockStrategySynchronized()
    {
    }
};

#define OB_LOCK_STRATEGY_SYNCHRONIZED OBLockStrategySynchronized

#else

#define OB_LOCK_STRATEGY_SYNCHRONIZED OBLockStrategyNull

#endif

//
// This strategy doesn't synchronize internal hashtable methods.
//
class OBLockStrategyNull
{
public:

    class MutexT {};

    OBLockStrategyNull(const MutexT&) { }
    ~OBLockStrategyNull() { }
};

#if defined(HAVE_NO_EXPLICIT_TEMPLATES) && !defined(HAVE_PRAGMA_DEFINE)
#   include <OB/HashtableI.h>
#endif

#endif
