6e0d5b4275
Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione Partners 2.0 patch 335 git-svn-id: svn://10.65.10.50/trunk@10496 c028cbd2-c16b-5b4b-a496-9718f37d4682
433 lines
10 KiB
C++
Executable File
433 lines
10 KiB
C++
Executable File
#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;
|
||
|
||
for (int 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;
|
||
}
|
||
|
||
// @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;
|
||
THash_object* o = _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;
|
||
for (int 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])
|
||
{
|
||
/* Guy ruined this
|
||
bool isnew = FALSE;
|
||
THash_object* o = _lookup(key, isnew);
|
||
if (o == NULL) error_box("INTERNAL (HASH): Unref key");
|
||
if (o->_obj == NULL) return error;
|
||
else return *(o->_obj);
|
||
*/
|
||
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 da cercarne 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();
|
||
}
|