#include "copyright.h"
/****************************************************************** 
 *
 * cacheclass.c --
 *
 *     Implementation of caching class.
 *
 *
 * $Author: mstoufer $
 * $Source: /home/g2/src/projects/NetLogger/src/nlv/old/cacheclass.c,v $
 * $RCSfile: cacheclass.c,v $
 * $Revision: 1.1.1.1 $
 * $Locker:  $
 * $Date: 2000/12/05 19:52:33 $
 *
 * Modification history
 * --------------------
 *
 * Jun 25 -- Add ReentrantExamine, ReentrantRemove, ReentrantClear
 *           in order to allow more efficient processing of
 *           multiple elements.
 *
 ****************************************************************** 
 */
static char rcsid[] = "$Id: cacheclass.c,v 1.1.1.1 2000/12/05 19:52:33 mstoufer Exp $";

#include "cacheclass.h"
#include <string.h>

/*========= DATA =====================================================*/

#define T Nlv_ca
struct Nlv_ca {
  void **data;
  int capacity;
  int size;
  int cur;
  int changed;
};

#define FILE_ERR_CODE 300
extern Nlv_err eobj;

/*========= FUNCTIONS ================================================*/

/*
 *----------------------------------------------------------------------
 *
 * New -- Allocate new object.
 *
 * Calls: malloc
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

T Nlv_caNew( )
{
  T this = (T)malloc( sizeof (struct Nlv_ca));
  this->size     = 0;
  this->capacity = 0;
  this->cur      = 0;
  this->changed  = 0;
  return this;
}


/*
 *----------------------------------------------------------------------
 *
 * Add -- Add data to cache.
 *
 * Calls:
 *
 * Algorithm: if ( size < capacity ) put data in [size] and increment.
 *
 *----------------------------------------------------------------------
 */

int Nlv_caAdd( T this, void* d)
{
  if ( this->size < this->capacity ) {
    this->data[ this->size++ ] = d;
    return 0;
  }
  else
    return -1;
}

/*
 *----------------------------------------------------------------------
 *
 * Remove -- Remove first matching data from cache.
 *
 * Calls: Nlv_filterFn
 *
 * Algorithm: Work from beginning of cache, make data contiguous
 *            when done.
 *
 *----------------------------------------------------------------------
 */

void* Nlv_caRemove( T this, Nlv_filterFn filter, void *filterData )
{
  int i, j;
  void *ret;

  /* Find it */
  for ( i=0; i < this->size; i++ ) {
    if ( this->data[i] && (filter == NULL || filter( filterData, this->data[i] )) )
      break;
  }
  if ( i == this->size )
    return 0;

  /* Remember it, bibble with array */
  this->changed = 1;
  ret = this->data[i];
  this->size--;
  if ( this->cur > i )
    this->cur--;
  for ( j = i; j < this->size; j++ )
    this->data[j] = this->data[j+1];

  return ret;
} 

/*
 *----------------------------------------------------------------------
 *
 * ReentrantRemove -- Remove first matching data from cache, starting
 *                    at 'pos'. Mark as removed by making NULL.
 *
 * Calls: Nlv_filterFn
 *
 * Algorithm: Work from 'pos', do NOT make data contiguous
 *            when done (mark element removed).
 *
 *----------------------------------------------------------------------
 */

void* Nlv_caReentrantRemove( T this, Nlv_filterFn filter, void *filterData )
{
  int i;
  void *ret;

  /* Find it */
  for ( i=this->cur; i < this->size; i++ ) {
    if ( this->data[i] && (filter == NULL || filter(filterData, this->data[i])) )
      break;
  }
  if ( i >= this->size ) {
    this->cur = this->size;
    return NULL;
  }
  this->cur = i+1;
  this->changed = 1;
  ret = this->data[i];
  this->data[i] = NULL;

  return ret;
}

/*
 *----------------------------------------------------------------------
 *
 * ReentrantExamine -- Return first matching data from cache, starting
 *                     at 'pos'. Do not modify cache.
 *
 * Calls: Nlv_filterFn
 *
 * Algorithm: Work from 'pos'.
 *
 *----------------------------------------------------------------------
 */

void* Nlv_caReentrantExamine( T this, Nlv_filterFn filter, void *filterData)
{
  void *ret;
  int i;

  /* Find it */
  for ( i=this->cur; i < this->size; i++ ) {
    if ( this->data[i] )
      if ( filter == NULL || filter(filterData, this->data[i]) )
	break;
  }
  this->cur = i+1;
  if ( i == this->size )
    return NULL;

  return this->data[i];
}

/*
 *----------------------------------------------------------------------
 *
 * ReentrantClear -- Re-set 'cur' to 0, consolidate array by
 *                   eliminating all NULL entries.
 *
 * Calls    :
 *
 * Algorithm: Simple. Modify 'size' by # removed when done.
 *
 *----------------------------------------------------------------------
 */

void Nlv_caReentrantClear( T this )
{
  int i, numNull = 0;

  for ( i=0; i < this->size; i++ )
    if ( this->data[i] )
      this->data[i - numNull] = this->data[i];
    else
      numNull++;
  this->size   -= numNull;
  this->cur     = 0;
  this->changed = 0;
}

/*
 *----------------------------------------------------------------------
 *
 * SetCapacity -- Size/re-size cache maximum capacity.
 *
 * Calls    : malloc or realloc
 *
 * Algorithm: Never re-size to less than current data in cache.
 *            Negative arguments are checked run-time errors.
 *
 *----------------------------------------------------------------------
 */

void  Nlv_caSetCapacity( T this, int sz )
{
  char *func = "Nlv_caSetCapacity";
  if ( sz < 0 )
    Nlv_errPrintString( eobj, func, "Request for negative cache size");

  /* First time */
  if ( this->capacity == 0 ) {
    this->data = (void *)malloc( sz * sizeof(void *) );
    this->size = 0;
    this->capacity = sz;
  }
  /* Second+ time */
  else if ( sz > this->size ) {
    this->data     = (void *)realloc( this->data, sz );
    if ( NULL == this->data )
      Nlv_errPrintString( eobj, func, "Request for negative cache size");
    this->capacity = sz;
  }
}


/*
 *----------------------------------------------------------------------
 *
 * GetSize -- Get number of data records in cache.
 *
 * Calls:
 *
 * Algorithm:
 *
 *----------------------------------------------------------------------
 */

int   Nlv_caGetSize( T this )
{
  return this->size;
}


/*
 *----------------------------------------------------------------------
 *
 * IsFull -- Is there space for more entries in the cache?
 *
 * Calls:
 *
 * Algorithm: Check size vs. capacity
 *
 *----------------------------------------------------------------------
 */

int  Nlv_caIsFull( T this )
{
  if ( this->size == this->capacity )
    return 1;
  else
    return 0;
}

#undef T
#undef FILE_ERR_CODE
