454 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			454 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
#include <stdlib.h>
 | 
						||
#include <assoc.h>
 | 
						||
 | 
						||
// @ccost:(INTERNAL) HASH_SIZE | 883 | Dimensione della tabella hash
 | 
						||
const int HASH_SIZE = 883;
 | 
						||
 | 
						||
THash_object::~THash_object()
 | 
						||
{ 
 | 
						||
  if (_obj != NULL) 
 | 
						||
    delete _obj; 
 | 
						||
}
 | 
						||
 | 
						||
TArray& TAssoc_array::bucket(int index)
 | 
						||
{
 | 
						||
  TArray* arr = (TArray*)_bucket.objptr(index);
 | 
						||
  if (arr == NULL)
 | 
						||
  {
 | 
						||
    arr = new TArray;
 | 
						||
    _bucket.add(arr, index);
 | 
						||
  }
 | 
						||
  return *arr;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Cerca l'oggetto con chiave <p k>
 | 
						||
//
 | 
						||
// @rdesc Ritorna l'oggetto corrispondente alla chiave passate come parametro.
 | 
						||
//        <nl>Il parametro <p isnew> assume il valore TRUE se si tratta di un
 | 
						||
//        nuovo oggetto.
 | 
						||
THash_object* TAssoc_array::_lookup(
 | 
						||
  const char* k,  // @parm Chiave da cercare
 | 
						||
  bool& isnew,    // @parm Viene assegnato TRUE se si tratta di una nuova chiave
 | 
						||
  bool insert)    // @parm Permette di inserire la chiave
 | 
						||
 | 
						||
  // @comm Ricerca all'interno della tabella hash l'oggetto con la chiave <p k>,
 | 
						||
  //       nel caso non venga trovato <p isnew> ritorna TRUE (si tratta di un
 | 
						||
  //       oggetto nuovo) e viene inserito nella tabella se il parametro <p insert>
 | 
						||
  //       e' settato a TRUE.
 | 
						||
{
 | 
						||
  const TFixed_string key(k);
 | 
						||
  const word hv = key.hash() % HASH_SIZE;
 | 
						||
  TArray& arr = bucket(hv);
 | 
						||
  THash_object* o = NULL;
 | 
						||
  isnew = FALSE;
 | 
						||
  int i;
 | 
						||
 | 
						||
  for (i = 0; i < arr.items(); i++)
 | 
						||
  {
 | 
						||
    THash_object* ob = (THash_object*)arr.objptr(i);
 | 
						||
    if (ob->_key == key)
 | 
						||
    { o = ob; break; }
 | 
						||
    if (ob->_key > key)
 | 
						||
      break;
 | 
						||
  }
 | 
						||
 | 
						||
  if (o == NULL) 
 | 
						||
  { 
 | 
						||
    if (insert)
 | 
						||
    {
 | 
						||
      o = new THash_object(key);
 | 
						||
      arr.insert(o,i); 
 | 
						||
      _cnt++;
 | 
						||
    }
 | 
						||
    isnew = TRUE;
 | 
						||
  }
 | 
						||
  
 | 
						||
  return o;
 | 
						||
}
 | 
						||
 | 
						||
void TAssoc_array::destroy()
 | 
						||
{
 | 
						||
  _bucket.destroy();
 | 
						||
  _cnt = _row = _col = 0; 
 | 
						||
  _rowitem = _colitem = 0;
 | 
						||
}
 | 
						||
 | 
						||
TObject* TAssoc_array::first_item()
 | 
						||
{
 | 
						||
  _rowitem = _colitem = 0;
 | 
						||
  return succ_item();
 | 
						||
}
 | 
						||
 | 
						||
TObject* TAssoc_array::last_item()
 | 
						||
{
 | 
						||
  _rowitem = _bucket.last();      
 | 
						||
  if( _rowitem < 0 )           
 | 
						||
    return NULL;
 | 
						||
  _colitem = bucket(_rowitem).items() - 1;
 | 
						||
  return pred_item( );
 | 
						||
}
 | 
						||
 | 
						||
TObject* TAssoc_array::succ_item()
 | 
						||
{
 | 
						||
  const TArray* arr = (const TArray*)_bucket.objptr(_rowitem);
 | 
						||
  while (_rowitem < HASH_SIZE)
 | 
						||
  {
 | 
						||
    if (arr && (int)_colitem < arr->items()) 
 | 
						||
      break;
 | 
						||
    _rowitem = _bucket.succ(_rowitem);
 | 
						||
    if (_rowitem < HASH_SIZE)
 | 
						||
    {
 | 
						||
      arr = (TArray*)_bucket.objptr(_rowitem);
 | 
						||
      _colitem = 0;
 | 
						||
    }  
 | 
						||
  }
 | 
						||
  if (_rowitem >= HASH_SIZE)
 | 
						||
    return NULL;
 | 
						||
  THash_object* o = (THash_object*)arr->objptr(_colitem++);
 | 
						||
  return (o == NULL || o->_obj == NULL) ? NULL : o->_obj;
 | 
						||
}
 | 
						||
 | 
						||
TObject* TAssoc_array::pred_item()
 | 
						||
{
 | 
						||
  const TArray* arr = (const TArray*)_bucket.objptr(_rowitem);
 | 
						||
  while (_rowitem >= 0)
 | 
						||
  {
 | 
						||
    if (arr && (int)_colitem >= 0) 
 | 
						||
      break;
 | 
						||
    _rowitem = _bucket.pred(_rowitem);
 | 
						||
    if (_rowitem >= 0)
 | 
						||
    {
 | 
						||
      arr = (TArray*)_bucket.objptr(_rowitem);
 | 
						||
      _colitem = arr->items()-1;
 | 
						||
    }  
 | 
						||
  }
 | 
						||
  if (_rowitem < 0 )
 | 
						||
    return NULL;
 | 
						||
  
 | 
						||
  THash_object* o = (THash_object*)arr->objptr(_colitem--);
 | 
						||
  return (o == NULL || o->_obj == NULL) ? NULL : o->_obj;
 | 
						||
}
 | 
						||
 | 
						||
THash_object* TAssoc_array::random_hash_object()
 | 
						||
{
 | 
						||
  THash_object* o = NULL;
 | 
						||
  if (items() > 0)
 | 
						||
  {
 | 
						||
    int bucket = rand() % _bucket.size();
 | 
						||
    if (_bucket.objptr(bucket) == NULL)
 | 
						||
      bucket = _bucket.succ(bucket);
 | 
						||
    if (_bucket.objptr(bucket) == NULL)
 | 
						||
      bucket = _bucket.pred(bucket);
 | 
						||
    const TArray* arr = (const TArray*)_bucket.objptr(bucket);
 | 
						||
    if (arr != NULL)
 | 
						||
    {
 | 
						||
      const int item = rand() % arr->size();
 | 
						||
      o = (THash_object*)arr->objptr(item);
 | 
						||
      if (o != NULL)
 | 
						||
      {
 | 
						||
        _rowitem = bucket;
 | 
						||
        _colitem = item;
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
  return o;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Aggiunge un oggetto all'array.
 | 
						||
// @rdesc Ritorna TRUE se esisteva gia' un elemento con la stessa chiave
 | 
						||
bool TAssoc_array::add(
 | 
						||
  const char* key,  // @parm Chiave d'ordinamento
 | 
						||
  TObject* obj,     // @parm Oggetto da inserire (default=NULL)
 | 
						||
  bool force)       // @parm Permette di forzare l'inserimento se esiste gia'
 | 
						||
  //       un oggetto con la stessa chiave
 | 
						||
 | 
						||
  // @parm const TObject | &obj | Indirizzo dell'oggetto da aggiungere
 | 
						||
  //
 | 
						||
  // @syntax add(const char* key, TObject* obj, bool force)
 | 
						||
  // @syntax add(const char* key, const TObject& obj, bool force)
 | 
						||
  //
 | 
						||
  // @comm Se l'oggetto da aggiungere esite gia' la chiave guarda il parametro <p force>:
 | 
						||
  //       <nl>se <p force> = TRUE  lo sostituisce e ritorna TRUE,
 | 
						||
  //       <nl>se <p force> = FALSE non sostituisce e ritorna TRUE,
 | 
						||
  //       <nl>altrimenti ritorna FALSE.
 | 
						||
  //       <nl><nl>Nel caso l'oggetto da aggiungere venga passato per indirizzo
 | 
						||
  //       la funzione aggiunge una copia dell'oggetto e quindi deve essere
 | 
						||
  //       definita <mf TObject::dup>
 | 
						||
{
 | 
						||
  bool isnew = FALSE;
 | 
						||
  THash_object* o = _lookup(key,isnew,TRUE);
 | 
						||
  if (!isnew)
 | 
						||
  {
 | 
						||
    if (force) 
 | 
						||
    { 
 | 
						||
      if (o->_obj != NULL) 
 | 
						||
        delete o->_obj;
 | 
						||
      o->_obj = obj; 
 | 
						||
    }
 | 
						||
    return TRUE;
 | 
						||
  }
 | 
						||
  o->_obj = obj;
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
bool TAssoc_array::add(const char* key, const TObject& obj, bool force)
 | 
						||
{ 
 | 
						||
  // Non inserire l'Hash_object se non lo trovi (ci pensa la add sotto)
 | 
						||
  bool isnew = FALSE;
 | 
						||
  _lookup(key,isnew,FALSE); 
 | 
						||
  if (!isnew && !force)
 | 
						||
    return TRUE;
 | 
						||
  return add(key,obj.dup(),force);
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Elimina un oggetto.
 | 
						||
// @rdesc Ritorna il risultato dell'operazione
 | 
						||
//
 | 
						||
// @flag TRUE | Eliminazione avvenuta
 | 
						||
// @flag FALSE | L'oggetto non e' stato trovato
 | 
						||
bool TAssoc_array::remove(
 | 
						||
  const char* k) // @parm Chiave dell'oggetto da eliminare
 | 
						||
 | 
						||
// @comm Cerca nella tabella hash l'oggetto con chiave <p k> e lo elimina.
 | 
						||
  
 | 
						||
{
 | 
						||
  const TFixed_string key(k);
 | 
						||
  const word hv = key.hash() % HASH_SIZE;
 | 
						||
  TArray& arr = bucket(hv);
 | 
						||
  THash_object* o = NULL;
 | 
						||
  int i;
 | 
						||
  
 | 
						||
  for (i = 0; i < arr.items(); i++)
 | 
						||
  {
 | 
						||
    THash_object* ob = (THash_object*)&arr[i];
 | 
						||
    if (ob->_key == key)
 | 
						||
    { o = ob; break; }
 | 
						||
    if (ob->_key > key)
 | 
						||
      break;
 | 
						||
  }
 | 
						||
  if (o != NULL) 
 | 
						||
  { 
 | 
						||
    arr.destroy(i,TRUE); 
 | 
						||
    _cnt--; 
 | 
						||
    return TRUE; 
 | 
						||
  }
 | 
						||
  return FALSE;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Trova l'oggetto indicizzato
 | 
						||
//
 | 
						||
// @rdesc Ritorna l'oggetto cercato. Se l'oggetto non viene trovato 
 | 
						||
//        ritorna un errore
 | 
						||
TObject& TAssoc_array::find(
 | 
						||
  const char* key) const // @parm Chiave dell'oggetto da trovare
 | 
						||
 | 
						||
 | 
						||
  // @comm Cerca l'oggetto indicizzato con chiave <p key>. Viene controllato se
 | 
						||
  //       non c'e' (normalmente si usa operator[key])
 | 
						||
{
 | 
						||
  TObject* o = objptr(key);
 | 
						||
  CHECKS(o, "Can't find hash object with key ", key);
 | 
						||
  return *o;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Ritorna l'oggetto con chiave <p key>
 | 
						||
// @rdesc Se l'oggetto esiste ne ritorna il puntatore, altrimenti ritorna NULL
 | 
						||
TObject* TAssoc_array::objptr(
 | 
						||
  const char* key) const // @parm Chiave dell'oggetto da ritornare
 | 
						||
{
 | 
						||
  bool isnew = FALSE; 
 | 
						||
  THash_object* o = ((TAssoc_array*)this)->_lookup(key,isnew);
 | 
						||
  return o ? o->_obj : NULL;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Controlla l'esistenza di una chiave
 | 
						||
//
 | 
						||
// @rdesc Ritorna il risultato della ricerca
 | 
						||
//
 | 
						||
// @flag TRUE | Se la chiave esiste
 | 
						||
// @flag FALSE | Se la chiave non esiste
 | 
						||
bool TAssoc_array::is_key(
 | 
						||
  const char* key) const // @parm Chiave di cui cercare l'esistenza
 | 
						||
{ 
 | 
						||
  bool isnew = FALSE; 
 | 
						||
  THash_object* o = ((TAssoc_array *)this)->_lookup(key,isnew);
 | 
						||
  return o != NULL;
 | 
						||
}                           
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Ritorna solo l'oggetto
 | 
						||
//
 | 
						||
// @rdesc Ritorna il puntatore all'oggetto (se diverso da NULL), altrimenti
 | 
						||
//        ritorna error object
 | 
						||
TObject* TAssoc_array::get()
 | 
						||
// @xref <mf TAssoc_array::get_hashobj>
 | 
						||
{
 | 
						||
  const TArray* arr = (const TArray*)_bucket.objptr(_row);
 | 
						||
  while(_row < HASH_SIZE)
 | 
						||
  {
 | 
						||
    if (arr && (int)_col < arr->items()) 
 | 
						||
      break;            
 | 
						||
    _row = _bucket.succ(_row);  
 | 
						||
    arr = (const TArray*)_bucket.objptr(_row);
 | 
						||
    _col = 0;
 | 
						||
  }
 | 
						||
  if (_row >= HASH_SIZE)
 | 
						||
  { 
 | 
						||
    _row = 0; 
 | 
						||
    return NULL; 
 | 
						||
  }
 | 
						||
  THash_object* o = (THash_object*)arr->objptr(_col++);
 | 
						||
  return (o == NULL || o->_obj == NULL) ? &error_object : o->_obj;
 | 
						||
}
 | 
						||
 | 
						||
// @doc EXTERNAL
 | 
						||
 | 
						||
// @mfunc Ritorna l'oggetto e la relativa chiave
 | 
						||
//
 | 
						||
// @rdesc Se l'oggetto esiste ne ritorna il puntatore, altrimenti ritorna NULL
 | 
						||
THash_object* TAssoc_array::get_hashobj()
 | 
						||
 | 
						||
  // @comm Se l'oggetto viene trovato viene richiamata la funzione
 | 
						||
  //       <mf TAssoc_array::objptr>
 | 
						||
  //
 | 
						||
  // @xref <mf TAssoc_array::get>
 | 
						||
{
 | 
						||
  const TArray* arr = (const TArray*)_bucket.objptr(_row);
 | 
						||
  while(_row < HASH_SIZE)
 | 
						||
  {
 | 
						||
    if (arr && (int)_col < arr->items()) 
 | 
						||
      break;            
 | 
						||
    _row = _bucket.succ(_row);
 | 
						||
    arr = (const TArray*)_bucket.objptr(_row);
 | 
						||
    _col = 0;
 | 
						||
  }
 | 
						||
  if (_row >= HASH_SIZE)
 | 
						||
  { 
 | 
						||
    _row = 0; 
 | 
						||
    return NULL; 
 | 
						||
  }
 | 
						||
  return (THash_object*)arr->objptr(_col++);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
// mette chiavi e opzionalmente valori (come stringa) nel
 | 
						||
// TString_array passato                                                      
 | 
						||
int TAssoc_array::get_keys(TString_array& kl, bool add_values)
 | 
						||
{                                                            
 | 
						||
  kl.destroy(); 
 | 
						||
  restart();
 | 
						||
  THash_object* o = NULL;  
 | 
						||
  TString tmp(80);
 | 
						||
  while ((o = get_hashobj()))
 | 
						||
  {
 | 
						||
    TToken_string* tt = new TToken_string(o->key());
 | 
						||
    if (add_values)
 | 
						||
    {         
 | 
						||
      tmp = "";
 | 
						||
      tmp << o->obj();
 | 
						||
      tt->add(tmp);
 | 
						||
    }              
 | 
						||
    kl.add(tt);
 | 
						||
  }
 | 
						||
  restart(); 
 | 
						||
  return kl.items();
 | 
						||
}
 | 
						||
  
 | 
						||
// @doc INTERNAL
 | 
						||
 | 
						||
// @mfunc Copia tutto l'array e ne duplica gli elementi
 | 
						||
//
 | 
						||
TAssoc_array & TAssoc_array::copy(const TAssoc_array & a) // @parm Array associativo sorgente
 | 
						||
{                   
 | 
						||
  destroy();
 | 
						||
  TAssoc_array& from = (TAssoc_array&)a;
 | 
						||
  from.restart();
 | 
						||
  for (THash_object* obj = from.get_hashobj(); obj; obj = from.get_hashobj())
 | 
						||
    add(obj->key(), obj->obj(), TRUE);
 | 
						||
  return * this;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
// TCache
 | 
						||
// Un simpatico contenitore che pu<70> dimenticare i contenuti
 | 
						||
// a patto che riusciate a fornire un metodo per ricrearli!
 | 
						||
///////////////////////////////////////////////////////////
 | 
						||
 | 
						||
TObject* TCache::key2obj(const char* key)
 | 
						||
{
 | 
						||
	NFCHECK("Pure key2obj function not implemented");
 | 
						||
	return new TString(key); // Place holder
 | 
						||
}
 | 
						||
 | 
						||
void TCache::discarding(const THash_object* obj)
 | 
						||
{ 
 | 
						||
	// Nothing to do normally
 | 
						||
}
 | 
						||
 | 
						||
TObject* TCache::objptr(const TString& key)
 | 
						||
{
 | 
						||
  const int hv = key.hash() % _data.size();
 | 
						||
  THash_object* ho = (THash_object*)_data.objptr(hv);
 | 
						||
	TObject* obj = NULL;
 | 
						||
	if (ho != NULL && ho->key() == key)
 | 
						||
	{
 | 
						||
		obj = &ho->obj();
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{
 | 
						||
		obj = key2obj(key);
 | 
						||
		if (obj != NULL)
 | 
						||
		{
 | 
						||
			if (ho != NULL)
 | 
						||
			{
 | 
						||
			  discarding(ho);
 | 
						||
			  _data.destroy(hv);
 | 
						||
			}
 | 
						||
			ho = new THash_object(key, obj);
 | 
						||
			_data.add(ho, hv);
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return obj;
 | 
						||
}
 | 
						||
 | 
						||
TObject* TCache::objptr(size_t s)
 | 
						||
{
 | 
						||
	TString16 key; key.format("%10lu", s);
 | 
						||
	return objptr(key);
 | 
						||
}
 | 
						||
 | 
						||
void TCache::destroy()
 | 
						||
{
 | 
						||
	for (int i = _data.last(); i >= 0; i--)
 | 
						||
	{
 | 
						||
		THash_object* ho = (THash_object*)_data.objptr(i);
 | 
						||
		if (ho != NULL)
 | 
						||
		{
 | 
						||
			discarding(ho);
 | 
						||
		  _data.destroy(i);
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
TCache::TCache(size_t size) : _data(size > 0 ? size : HASH_SIZE)
 | 
						||
{ }
 | 
						||
 | 
						||
TCache::~TCache()
 | 
						||
{
 | 
						||
	destroy();
 | 
						||
}
 |