#ifndef _STDEX_LHASH_TABLE_H_
#define _STDEX_LHASH_TABLE_H_

/***************************************************************************
 *
 * Hash table implemented as a vector of iterators into an slist, with
 * "chunky" insertion, so that all equal items are adjacent.
 *
 * This class is intended primarily to be used as an underlying
 * implementation. As it is currently written, there are public
 * methods, since that facilitates testing. It may be that the better
 * course is to make all methods protected or private, and then
 * require that interface classes be derived or friends.
 * 
 * There is a subtle change from the "standard meaning" for the methods
 * lower_bound(key) and upper_bound(key).
 * Since hash tables are intrinsically unordered, we have relaxed the 
 * meaning very slightly so that:
 *    lower_bound(key) returns an iterator which points either
 *	"just past" the hash table slot where key would have been but was not
 *	   or
 *	the "first" iterator which references something EQ to key.
 *
 *    upper_bound(key) returns an iterator which points either
 *	"just past" the hash table slot where key would have been but was not
 *	   or
 *	"just past" the "last" iterator which references something EQ to key
 *
 * Note that all items which are EQ to each other are in consecutive
 * iterator locations. Thus, while equal_range(key) is useful, no other
 * range (except the entire range of the hash table) is likely to be
 * meaningful.
 *
 ***************************************************************************
 *
 * $Id: lhash.h,v 7.13 1996/03/20 17:58:12 jims Exp $
 *
 * (c) Copyright 1989 - 1996 Rogue Wave Software, Inc.
 * ALL RIGHTS RESERVED
 *
 * The software and information contained herein are proprietary to, and
 * comprise valuable trade secrets of, Rogue Wave Software, Inc., which
 * intends to preserve as trade secrets such software and information.
 * This software is furnished pursuant to a written license agreement and
 * may be used, copied, transmitted, and stored only in accordance with
 * the terms of such license and with the inclusion of the above copyright
 * notice.  This software and information or any other copies thereof may
 * not be provided or otherwise made available to any other person.
 *
 * Notwithstanding any other lease or license that may pertain to, or
 * accompany the delivery of, this computer software and information, the
 * rights of the Government regarding its use, reproduction and disclosure
 * are as set forth in Section 52.227-19 of the FARS Computer
 * Software-Restricted Rights clause.
 * 
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7013.
 * Contractor/Manufacturer is Rogue Wave Software, Inc.,
 * P.O. Box 2328, Corvallis, Oregon 97339.
 *
 * This computer software and information is distributed with "restricted
 * rights."  Use, duplication or disclosure is subject to restrictions as
 * set forth in NASA FAR SUP 18-52.227-79 (April 1985) "Commercial
 * Computer Software-Restricted Rights (April 1985)."  If the Clause at
 * 18-52.227-74 "Rights in Data General" is specified in the contract,
 * then the "Alternate III" clause applies.
 *
 ***************************************************************************
 *
 * $Log: lhash.h,v $
 * Revision 7.13  1996/03/20 17:58:12  jims
 * Convert results of size() and capacity() to float
 * before calculating fill_ratio
 *
 * Revision 7.12  1996/03/14 23:35:28  pearson
 * #2825 - Assign false to an automatic variable before returning it in
 *         degenerative_compare, to suppress warnings when compiling
 *         under Borland 4.52
 *
 * Revision 7.11  1996/02/19 12:34:12  jims
 * Port to Stdlib 1.2
 *
 * Revision 7.10  1996/02/07 02:42:30  jims
 * Standard library extensions now in directory rw/stdex
 *
 * Revision 7.9  1996/01/29 19:50:51  pearson
 * Specify receiver for calls to operator!= to prevent ambiguity between
 * class operator and C++ Std. Lib. global templated operator!=
 *
 * Revision 7.8  1995/11/17 08:09:19  jims
 * Make iterator::operator*() const
 *
 * Revision 7.7  1995/10/20 06:02:09  jims
 * Port to microsoft: remove default params from ctors and make
 * key_hash() and key_equal() "const" member functions
 *
 * Revision 7.6  1995/09/21  00:19:11  griswolf
 * Fix postincrement iterators.
 * provide methods key_equal() and key_hash().
 *
 * Revision 7.5  1995/09/18  18:31:19  griswolf
 * Fix several minor typos.
 *
 * Revision 7.4  1995/09/12  19:23:40  griswolf
 * Change to #include slist.h
 *
 * Revision 7.3  1995/09/05  19:35:43  jims
 * Update header section
 *
 * Revision 7.2  1995/08/31  12:03:51  jims
 * next rev
 *
 * Revision 7.1  1995/08/29  09:16:50  jims
 * Port to sgi and Borland
 *
 * Revision 1.2  1995/08/28  22:31:00  griswolf
 * miscellaneous changes to get past the compiler.
 *
 * Revision 1.1  1995/08/25  20:29:30  griswolf
 * Initial revision
 *
 */

#include <memory>
#include <vector>            // stl vector
#include <iterator>          // stl forward_iterator for the tags
#include "rw/stdex/slist.h"  // value based slist

// because finding a match requires an "equalitor" the class is
// templatized on "EQ"
// because there must be a hash function, the class is templatized
// on "Hash"

template <class T, class Hash, class EQ > //, class Allocator>
class LHashTable 
{
public:
  struct bucket_t {
    bool 			valid_;
    rw_slist<pair<T,unsigned long> >::iterator chain_;
    		operator bool() const { return valid_; }
    bucket_t() : valid_(false) {}
    bucket_t(bool v, const rw_slist<pair<T,unsigned long> >::iterator& c)
      : valid_(v), chain_(c) {}
    bool&	valid() { return valid_; }
    rw_slist<pair<T,unsigned long> >::iterator& chain() {return chain_;}
    rw_slist<pair<T,unsigned long> >::iterator chain() const {return chain_;}
  };

///// typdefs /////
  // shorthand typedefs
  typedef pair<T,unsigned long>		    node_t;
  typedef rw_slist<node_t>		    list_t;
//  typedef pair<bool,list_t::iterator>	    bucket_t;
  typedef vector<bucket_t,allocator>	    table_t;

  // "all the usual" typedefs
  typedef list_t::size_type		    size_type;
  typedef list_t::difference_type	    difference_type;
  typedef T				    value_type;
  typedef T&				    reference;
  typedef const T&			    const_reference;
  typedef allocator_interface<allocator, rw_slist<node_t> >   list_allocator_type;
  typedef allocator_interface<allocator, vector<bucket_t,allocator> >
                                                            vector_allocator_type;
  typedef EQ				    key_equal_type;
  typedef Hash				    key_hash_type;

  ///// nested Iterator classes //////////////////////////////////////////
									//
  class ConstIterator;							//
  class Iterator : public forward_iterator<T,difference_type> {		//
    friend LHashTable<T,Hash,EQ>;					//
    list_t::iterator iter_;						//
    friend ConstIterator;						//
  public:								//
    Iterator() {}							//
    Iterator(const rw_slist<node_t>::iterator& i) : iter_(i) {}		//
    Iterator(const Iterator& i) : iter_(i.iter_) {}			//
    ~Iterator() {}							//
									//
    reference	        operator*()  const { return (*iter_).first; }   //    
    Iterator&		operator++()       { ++iter_; return *this; }	//
    Iterator		operator++(int)					//
    { Iterator t(*this); ++(*this); return t; }				//
									//
    bool		operator==(const Iterator& rhs) const		//
    { return iter_ == rhs.iter_; }					//
    									//
    bool		operator==(const ConstIterator& rhs) const	//
    { return rhs == *this; }						//
    									//

 //   Dot operator used here to access != to prevent conflict with 
 //   C++ Std. Lib's templated != operator					

    bool		operator!=(const Iterator& rhs) const		//
    { return iter_.operator!=(rhs.iter_); }				//
									//
    bool		operator!=(const ConstIterator& rhs) const	//
    { return rhs != *this; }						//
    									//
    Iterator&		operator=(const Iterator& rhs) 			//
    { iter_ = rhs.iter_; return *this; }				//
  };									//
    									//
  class ConstIterator : public forward_iterator<T,difference_type> {	//
    list_t::iterator iter_;						//
    friend LHashTable<T,Hash,EQ>;					//
  public:								//
    ConstIterator() {}							//
    ConstIterator(const rw_slist<node_t>::iterator& i) : iter_(i)	//
    {}									//
    ConstIterator(const ConstIterator& i) : iter_(i.iter_) {}		//
    ConstIterator(const Iterator& i) : iter_(i.iter_) {}		//
    ~ConstIterator() {}							//
									//
    const_reference		operator*() const			//
    { return (*iter_).first; }						//
    ConstIterator&		operator++() { ++iter_; return *this; }	//
    ConstIterator		operator++(int)				//
    { ConstIterator t(*this); ++(*this); return t; }			//
									//
    bool		operator==(const ConstIterator& rhs) const	//
    { return iter_ == rhs.iter_; }					//
    									//
    bool		operator==(const Iterator& rhs) const		//
    { return iter_ == rhs.iter_; }					//
    									//

 //  Dot operator used here to access != to prevent conflict with 
 //  C++ Std. Lib's templated != operator	

    bool		operator!=(const ConstIterator& rhs) const	//
    { return iter_.operator!=(rhs.iter_); }				//


 //  Dot operator used here to access != to prevent conflict with 
 //  C++ Std. Lib's templated != operator	

    bool		operator!=(const Iterator& rhs) const		//
    { return iter_.operator!=(rhs.iter_); }				//
									//
    ConstIterator&		operator=(const ConstIterator& rhs) 	//
    { iter_ = rhs.iter_; return *this; }				//
									//
    ConstIterator&		operator=(const Iterator& rhs)	 	//
    { iter_ = rhs.iter_; return *this; }				//
  };									//
  ///// end of nested Iterator classes ///////////////////////////////////
      

  typedef Iterator iterator; // users may not alter table directly
  typedef ConstIterator const_iterator;

  /*
   * There is no standard specification for hash tables in the STL,
   * but they are more similar to Associative Containers than anything
   * else.  STL containers are supposed to have a typedef key_compare
   * for their comparitors.  Since items in a hash table are not ordered
   * in that way, we are providing a trivial comparitor that always
   * returns false (from STL's point of view that means everything is
   * equivalent).  This is mainly to guard against over-achieving
   * compilers that insist on compiling even those template functions 
   * that are never used.  This will help in using hashed collections
   * in code that makes use of their commonality of interface with
   * the standard Associative Containers.
   */

   struct degenerative_compare : public binary_function<T, T, bool>
   {
     bool operator() (const T&, const T&) const {

#ifndef __TURBOC__
        return false;
#else
        RWBoolean tmpry = false;
        return tmpry;
#endif

     }
   };

   typedef degenerative_compare key_compare;
   
///// constructors /////
/*
 * Unsolved problem with msvc precludes the default params 
 * commented out below.
 */
  
  LHashTable(size_type   /* sz = 1024 */,
             const Hash& /*h = Hash()*/,
             const EQ&   /*equals = EQ()*/);

  LHashTable(const LHashTable<T,Hash,EQ>&);

  LHashTable(ConstIterator first, ConstIterator bound, size_type /*sz=1024*/,
	    const Hash& /*h = Hash()*/, const EQ& /*equals = EQ()*/
	   );

  LHashTable(const T* first, const T* bound,size_type /*sz=1024*/,
	    const Hash& /*h = Hash()*/, const EQ& /*equals = EQ()*/
	   );

  ~LHashTable() { clear(); delete table_; delete list_; }

///// operators /////
  LHashTable<T,Hash,EQ>& operator=(const LHashTable<T,Hash,EQ>& t);

  bool		operator==(const LHashTable<T,Hash,EQ>& t) const
  { return size() == t.size() && testEqual(t); }

///// various public methods /////
  Iterator
    begin()
    { return Iterator(list_->begin()); }

  ConstIterator
    begin() const
    { return ConstIterator(list_->begin()); }

  size_type
    capacity() const { return table_->size(); } // number of buckets

  void
    clear();

  size_type
    count(LHashTable<T,Hash,EQ>::const_reference) const;

  bool
    empty() const { return size() == 0; }

  Iterator
    end()
    { return Iterator(list_->end()); }

  ConstIterator
    end() const
    { return ConstIterator(list_->end()); }

  pair<Iterator,Iterator>
    equal_range(LHashTable<T,Hash,EQ>::const_reference key)
{
  table_t::iterator slot = index(key);
  list_t::iterator lower = list_->end();
  list_t::iterator upper = list_->end();
  bool hit;
  if(*slot) {
    lower = chunkyLowerBound((*slot).chain(), list_->end(), key, hit);
    upper = lower;
    if(hit)
      upper = chunkyUpperBound(lower,list_->end(), key);
  }
  return pair<Iterator,Iterator>(lower,upper);
}

  pair<ConstIterator,ConstIterator>
    equal_range(LHashTable<T,Hash,EQ>::const_reference key) const
{
  table_t::const_iterator slot = index(key);
  list_t::iterator lower = list_->end();
  list_t::iterator upper = list_->end();
  bool hit;
  if(*slot) {
    lower = chunkyLowerBound((*slot).chain(), list_->end(), key, hit);
    upper = lower;
    if(hit)
      upper = chunkyUpperBound(lower,list_->end(), key);
  }
  return pair<ConstIterator,ConstIterator>(lower,upper);
}

  LHashTable<T,Hash,EQ>::size_type
    erase(LHashTable<T,Hash,EQ>::const_reference key);

  Iterator
    erase(Iterator);	// return successor to erased item

  ConstIterator
    erase(ConstIterator);	// return successor to erased item

  Iterator			//  return successor to range
    erase(Iterator first, Iterator bound);

  ConstIterator			//  return successor to range
    erase(ConstIterator first, ConstIterator bound);

  Iterator			//  return successor to range
    erase(pair<Iterator,Iterator> range)
    { return erase(range.first, range.second); }

  float
    fill_ratio() const { return ((float)size())/((float)capacity()); }

  Iterator
    find(LHashTable<T,Hash,EQ>::const_reference);

  ConstIterator
    find(LHashTable<T,Hash,EQ>::const_reference) const;

  bool
    insertMaybe(
		LHashTable<T,Hash,EQ>::const_reference key,
		Iterator& ret, // holds returned iterator
		bool isSingle
		);
  size_type
    insertMaybe(
		ConstIterator first,
		ConstIterator bound,
		Iterator& ret, // holds returned iterator
		bool isSingle
		)
  {
    size_type count(0);
    while(first != bound)  {
      count += (insertMaybe(*first,ret,isSingle)) ? 1 : 0;
      ++first;
    }
    return count;
  }

  size_type
    insertMaybe(
		const T* first,
		const T* bound,
		Iterator& ret, // holds returned iterator
		bool isSingle
		)
  {
    size_type count(0);
    while(first != bound) 
      count += (insertMaybe(*first++,ret,isSingle)) ? 1 : 0;
    return count;
  }

  Iterator
    lower_bound(LHashTable<T,Hash,EQ>::const_reference);

  ConstIterator
    lower_bound(LHashTable<T,Hash,EQ>::const_reference) const;

//  resize() fills a new table with data, rehashing everything, 
//  except that resize(0) is a no-op.
  void
    resize(LHashTable<T,Hash,EQ>::size_type);

  size_type
    size() const { return list_->size(); }

  void
    swap(LHashTable<T,Hash,EQ>& t);
  
  Iterator
    upper_bound(LHashTable<T,Hash,EQ>::const_reference);

  ConstIterator
    upper_bound(LHashTable<T,Hash,EQ>::const_reference) const;

  key_hash_type
    key_hash() const { return hash_; }

  key_equal_type
    key_equal() const { return eq_; }

//////////////////////////////////////////////////////////////////////////
///// protected and private methods //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

protected:

  list_t::iterator
    chunkyLowerBound(
		     list_t::iterator start,
		     list_t::iterator bound,
		     const_reference key,
		     bool& hit
		    ) const
{
  hit = false;
  size_type slot = ((*start).second) % capacity();
  while(start != bound && ((*start).second)%capacity() == slot) {
    if(eq_((*start).first,key)) {
      hit = true;
      break;
    }
    ++start;
  }
  return start;
}

  list_t::iterator
    chunkyUpperBound(
		     list_t::iterator start,
		     list_t::iterator bound,
		     const_reference key
		    ) const
{
  size_type slot = ((*start).second) % capacity();
  bool dum;
  start = chunkyLowerBound(start, bound, key, dum);

  while(start != bound && ((*start).second)%capacity() == slot) {
    if(! eq_((*start).first,key))
      break;
    ++start;
  }
  return start;
}

  table_t::iterator
    index(unsigned long hv) const
    { return table_->begin() + (hv % capacity()); }

  table_t::iterator
    index(const_reference t) const    { return index(hash_(t)); }

  bool
    testEqual(const LHashTable<T,Hash,EQ>& t) const;

private:
  rw_slist<node_t>			*list_;
  vector<bucket_t,allocator>		*table_;
  EQ					eq_;
  Hash					hash_;
  list_allocator_type			listAllocator;
  vector_allocator_type			vectorAllocator;
//////// for debugging ////////
public:
  void
    idump() const;
};

#ifdef RW_COMPILE_INSTANTIATE
#include "rw/stdex/lhash.cc"
#endif

#endif /* _STDEX_LHASH_TABLE_H_ */

