//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//-----------------------------------------------------------------------------
// Description:
//	 cdevIntHash: cdev hash table keyed by an integer
//                    Open Hash with buckets implemented by single linked lists
//    
//              Note: void *s are stored inside the table. This class
//                    will not manage these pointers. Callers have to
//                    manage these pointers
//
// Author: Danjin Wu (Modified from cdevStrHash class)
// 
// Revision History:
//   cdevIntHash.cc,v
// Revision 1.4  1997/05/15  17:17:14  chen
// fix bugs for SunOS4 using CC
//
// Revision 1.3  1996/08/26  21:23:17  akers
// Corrected dereference of NULL in getData
//
// Revision 1.2  1996/08/26  21:12:33  akers
// Added getData method to iterator
//
// Revision 1.1  1995/08/21  15:45:45  danjin
// integer hash table
//
//
//
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "cdevIntHash.h"


//======================================================================
//	class cdevIntHash implementation
//======================================================================
cdevIntHash::cdevIntHash (unsigned int max)
:tablesize(max)
{
#ifdef _TRACE_OBJECTS
  printf ("Create cdevIntHash Class Objects\n");
#endif
  // cdevSlist has a default constructor, so one can create an array of the list
  buckets = new cdevSlist[tablesize];
  assert (buckets);
}

cdevIntHash::~cdevIntHash (void)
{
#ifdef _TRACE_OBJECTS
  printf ("Delete cdevIntHash Class Objects\n");
#endif
  delete []buckets;
  buckets = 0;
}

int 
cdevIntHash::isEmpty()
{
  // if any table is non-empty, return 0
  for (int i = 0; i < tablesize; i++)
    if (!buckets[i].isEmpty())
      return 0;

  // all empty
  return 1;
}

void
cdevIntHash::deleteAllValues()
{
  // delete all values from a hash table
  // clear the elements from each of teh buckets
  for (int i = 0; i < tablesize; i++)
    buckets[i].deleteAllValues();
}

unsigned int 
cdevIntHash::hash(const cdevIntKeyItem key) const
{
  // return hashed value of key
  return (key % tablesize);
}

void
cdevIntHash::add (cdevIntKeyItem key, cdevHashItem newele)
{
  buckets[hash (key)].add (newele);
}

int
cdevIntHash::remove (cdevIntKeyItem key, cdevHashItem ele)
{
  return (buckets[hash (key)].remove (ele));
}

int
cdevIntHash::find (cdevIntKeyItem key, cdevHashItem ele) const
{
  return buckets[hash (key)].includes(ele);
}

cdevSlist&
cdevIntHash::bucketRef (cdevIntKeyItem key)
{
  return (buckets[hash (key)]);
}

//======================================================================
//	class cdevIntHashIterator implementation
//======================================================================
cdevIntHashIterator::cdevIntHashIterator (cdevIntHash& v)
:base(v), currentIndex(0), itr(0)
{
#ifdef _TRACE_OBJECTS
  printf ("Create cdevIntHashIterator Class Object \n");
#endif
  // no further initialization
}

cdevIntHashIterator::~cdevIntHashIterator (void)
{
#ifdef _TRACE_OBJECTS
  printf ("Delete cdevIntHashIterator Class Object \n");
#endif
  currentIndex = 0;
  if (itr)
    delete itr;
}

int 
cdevIntHashIterator::init (void)
{
  // initialize iterator, 
  // start search with first bucket
  currentIndex = 0; 
  itr = 0;
  return getNextIterator(); 
}

cdevHashItem 
cdevIntHashIterator::operator() (void)
{
  // return current element
  return itr!=NULL?(*itr)():NULL;
}

cdevHashItem cdevIntHashIterator::getData (void)
{
  // return current element
  return itr!=NULL?(*itr)():NULL;
}
	
int 
cdevIntHashIterator::operator ! (void)
{
  // test if there is a current element
  return itr != 0;
}

int 
cdevIntHashIterator::operator ++ (void)
{
  // see if current iterator can be advanced
  if (itr && ++(*itr)) 
    return 1;

  // if not, get next iterator
  currentIndex++;
  return getNextIterator();
}

void 
cdevIntHashIterator::operator = (cdevHashItem val)
{
  // change the current value
  (*itr) = val;
}

int 
cdevIntHashIterator::getNextIterator (void)
{
  // if there is an old iterator, delete it
  if (itr != 0) 
    delete itr;

  // now search for a new one
  for (; currentIndex < base.tablesize; currentIndex++){
    // generate a new iterator at the current point
    itr = new cdevSlistIterator (base.buckets[currentIndex]);
    assert(itr != 0);

    // if it has at least one element, we're done
    if (itr->init())
      return 1;

    // otherwise delete it, try again
    delete itr;
  }
  // all out of iterators, can quit
  itr = 0;
  return 0;
}
