//-----------------------------------------------------------------------------
// 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.
//
// CEBAF Data Acquisition Group, 12000 Jefferson Ave., Newport News, VA 23606
// Email: coda@cebaf.gov  Tel: (804) 249-7101  Fax: (804) 249-7363
//-----------------------------------------------------------------------------
// 
// Description:
//	 cdevStrHash: cdev hash table keyed by a variable length string
//                    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
// 
//              Note: this is unsafe C++ practice. Use at your own risk
//              
//            Reason: It is so difficult to use a template class inside
//                    a shared library. (Cfront based C++ compiler cannot
//                    instantiate a template class during compilation time
//	
// Author:  Jie Chen
//       CEBAF Data Acquisition Group
//
// Revision History:
//   cdevStrHash.cc,v
// Revision 1.5  1997/05/15  17:17:15  chen
// fix bugs for SunOS4 using CC
//
// Revision 1.4  1996/08/26  21:23:18  akers
// Corrected dereference of NULL in getData
//
// Revision 1.3  1996/08/26  21:12:36  akers
// Added getData method to iterator
//
// Revision 1.2  1995/07/05  18:38:48  chen
// add simple str hash function
//
// Revision 1.1  1995/06/30  15:08:29  chen
// string hash table
//
//
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "cdevStrHash.h"

//======================================================================
//      A simple string hash fucntion for cdevDevice and caChannel
//           Its implementation will be changed for release 1.1
//======================================================================
unsigned int cdevStrHashFunc (char *src)
{
  unsigned int hash = 0, g;

  for (int i = 0; src[i] != '\0'; i++){
    hash = (hash << 4) + src[i];
    // assume 32 bit integer
    if (g = hash & 0xf0000000){
      hash ^= g >> 24;
      hash ^= g;
    }
  }
  return hash;
}


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

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

int 
cdevStrHash::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
cdevStrHash::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 
cdevStrHash::hash(const cdevKeyItem& key) const
{
  // return hashed value of key
  return ((*hashCode_)(key) % tablesize);
}

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

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

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

cdevSlist&
cdevStrHash::bucketRef (cdevKeyItem key)
{
  return (buckets[hash (key)]);
}

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

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

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

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

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

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

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

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

int 
cdevStrHashIterator::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;
}
