Source: classlib/include/classlib/tcache.h
|
|
|
|
/***************************************************************************
tcache.h - cache di oggetti
-------------------
begin : ven dic 7 17:40:01 CET 2001
copyright : (C) 2001 by Nicola De Nisco
email : nicola@winada.it
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "checks.h"
#include "classlib/arrays.h"
#include "classlib/queues.h"
#include "classlib/assoc.h"
#include "classlib/dict.h"
/**
template class TCAssoc
associa ad una chiave il relativo valore della cache: utilizzata da
TCache e TPriorityCache
*/
template class TCAssoc :
public TDIAssociation
{
typedef TDIAssociation Parent;
public:
TCAssoc() :
Parent()
{
}
TCAssoc( const K& k, V *v ) :
Parent( k, v )
{
}
void ReplaceValue( V* v )
{
ValueData = v;
}
};
template class TCacheIterator;
/**
template class TCache
template class TCacheIterator
Cache generica di oggetti CBuf associati a chiave CKey
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti
CBuf sono memorizzati in forma indiretta (puntatori a).
Notare il costruttore: szQue è la dimensione della cache
L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable
ossia deve avere un operatore di copia (=), uno di conronto (==) e
deve avere una funzione:
unsigned HashValue() const;
oppure deve esistere una funzione globale del tipo:
unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se
la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti
viene chiamata la funzione FillCache (ridefibile in classi derivate)
per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia-
mare la funzione Add dopo aver reperito l'oggetto associato alla
chiave, per salvarlo nella cache.
*/
template class TCache :
private TShouldDelete
{
typedef TCAssoc Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIQueueAsVector Queue;
friend class TCacheIterator;
public:
TCache( unsigned szQue = DEFAULT_QUEUE_SIZE,
unsigned szDic = DEFAULT_HASH_TABLE_SIZE ) :
que(szQue),
dic(szDic)
{
que.OwnsElements(0);
OwnsElements(1);
}
virtual ~TCache()
{
Flush();
}
int OwnsElements()
{
return TShouldDelete::OwnsElements();
}
void OwnsElements( int del )
{
TShouldDelete::OwnsElements(del);
dic.OwnsElements(del);
}
int Add( const CKey& k, CBuf* b );
const CBuf *Find( const CKey& k );
const CBuf *Fetch( const CKey& k );
void Flush( DeleteType dt = DefDelete );
virtual const CBuf *FillCache( const CKey& ) { return 0; }
void ForEach( void (*func)(CKey&, CBuf&, void *), void *args );
unsigned GetItemsInContainer() const
{
return que.GetItemsInContainer();
}
int IsEmpty() const
{
return que.IsEmpty();
}
int IsFull() const
{
return que.IsFull();
}
protected:
Queue que;
Dictionary dic;
};
template
int TCache::Add( const CKey& k, CBuf* b )
{
PRECONDITION(b != NULL);
Association* ptAss = new Association( k, b );
Association* ptFnd = dic.Find( ptAss );
if( ptFnd ) {
ptFnd->DeleteElements();
ptFnd->ReplaceValue( b );
delete ptAss;
return 0;
}
if( que.IsFull() ) {
dic.Detach( que.Get() );
}
dic.Add( ptAss );
que.Put( ptAss );
return 1;
}
template
const CBuf* TCache::Find( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return 0;
return asFound->Value();
}
template
void TCache::Flush( DeleteType dt /*= DefDelete*/ )
{
que.Flush(NoDelete);
dic.Flush(dt);
}
template
const CBuf* TCache::Fetch( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return FillCache(k);
return asFound->Value();
}
template
void TCache::ForEach( void (*func)(CKey&, CBuf&, void *), void *args )
{
TIQueueAsVectorIterator itrQue( que );
while( itrQue ) {
(*func)( (CKey&)itrQue.Current()->Key(),
(CBuf&)(*itrQue.Current()->Value()), args );
itrQue++;
}
}
/**
L'iteratore della classe TCache.
*/
template class TCacheIterator :
public TIQueueAsVectorIterator< TCAssoc >
{
typedef TCAssoc Association;
typedef TIQueueAsVectorIterator Parent;
public:
TCacheIterator( TCache& c ) : Parent( c.que )
{
}
const CKey& Key()
{
return Current()->Key();
}
const CBuf& Value()
{
return *Current()->Value();
}
};
template class TPriorityCacheIterator;
/**
template class TPriorityCache
template class TPriorityCacheIterator
Cache generica di oggetti CBuf associati a chiave CKey con priorità.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti
CBuf sono memorizzati in forma indiretta (puntatori a).
Notare il costruttore: szQue è la dimensione della cache (-1=nolimit)
L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable
ossia deve avere un operatore di copia (=), uno di conronto (==) e
deve avere una funzione:
unsigned HashValue() const;
oppure deve esistere una funzione globale del tipo:
unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se
la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti
viene chiamata la funzione FillCache (ridefibile in classi derivate)
per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia-
mare la funzione Add dopo aver reperito l'oggetto associato alla
chiave, per salvarlo nella cache.
Ridefinendo opportunamente IsPriority si può decidere se utilizzare o
o meno la priorità sulla cache. Se questa funzione restituisce != 0
ogni volta che Fetch va a buon fine, l'oggetto CBuf viene reinserito a
a priorità massima nella cache. In questo modo in caso di scaricamento
a causa riempimento, verranno scaricati gli elementi con accesso meno
frequente.
*/
template class TPriorityCache :
private TShouldDelete
{
typedef TCAssoc Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIQueueAsDoubleList Queue;
friend class TPriorityCacheIterator;
public:
TPriorityCache( unsigned szCac = DEFAULT_QUEUE_SIZE,
unsigned szDic = DEFAULT_HASH_TABLE_SIZE ) :
dic(szDic)
{
que.OwnsElements(0);
OwnsElements(1);
LimitCache = szCac;
}
virtual ~TPriorityCache()
{
Flush();
}
int OwnsElements()
{
return TShouldDelete::OwnsElements();
}
void OwnsElements( int del )
{
TShouldDelete::OwnsElements(del);
dic.OwnsElements(del);
}
virtual int Add( const CKey& k, CBuf* b );
int Detach( const CKey& k, DeleteType dt = DefDelete )
{
Association as(k,0);
que.Detach( &as, NoDelete );
return dic.Detach( &as, dt );
}
const CBuf *Find( const CKey& k );
const CBuf *Fetch( const CKey& k );
void Flush( DeleteType dt = DefDelete );
virtual const CBuf *FillCache( const CKey& ) { return 0; }
virtual int IsPriority() const { return 1; }
void ForEach( void (*func)(CKey&, CBuf&, void *),
void *args );
unsigned GetItemsInContainer() const
{
return dic.GetItemsInContainer();
}
int IsEmpty() const
{
return dic.IsEmpty();
}
int IsFull() const
{
return LimitCache == -1 || ((int)(dic.GetItemsInContainer())) < LimitCache ? 0 : 1;
}
protected:
Dictionary dic;
Queue que;
int LimitCache;
};
template
int TPriorityCache::Add( const CKey& k, CBuf* b )
{
PRECONDITION(b != NULL);
Association* ptAss = new Association( k, b );
Association* ptFnd = dic.Find( ptAss );
if( ptFnd ) {
ptFnd->DeleteElements();
ptFnd->ReplaceValue( b );
delete ptAss;
return 0;
}
if( IsFull() ) {
dic.Detach( que.Get() );
}
dic.Add( ptAss );
que.Put( ptAss );
return 1;
}
template
const CBuf* TPriorityCache::Find( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return 0;
return asFound->Value();
}
template
void TPriorityCache::Flush( DeleteType dt /*= DefDelete*/ )
{
que.Flush(NoDelete);
dic.Flush(dt);
}
template
const CBuf* TPriorityCache::Fetch( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return FillCache(k);
if( IsPriority() ) {
que.Detach(asFound,NoDelete);
que.Put(asFound);
}
return asFound->Value();
}
template
void TPriorityCache::ForEach( void (*func)(CKey&, CBuf&, void *), void *args )
{
TIQueueAsDoubleListIterator itrQue( que );
while( itrQue ) {
(*func)( (CKey&)itrQue.Current()->Key(),
(CBuf&)(*itrQue.Current()->Value()), args );
itrQue++;
}
}
/**
L'iteratore della classe TPriorityCache.
*/
template class TPriorityCacheIterator :
public TIQueueAsDoubleListIterator< TCAssoc >
{
typedef TCAssoc Association;
typedef TIQueueAsDoubleListIterator Parent;
public:
TPriorityCacheIterator( TPriorityCache& c ) : Parent( c.que )
{
}
const CKey& Key()
{
return Current()->Key();
}
const CBuf& Value()
{
return *Current()->Value();
}
};
template class TCacheArrayIterator;
/**
template class TCacheArray
template class TCacheArrayIterator
Cache generica di oggetti CBuf associati a chiave CKey
senza limitazioni sulle dimensioni, con indicizzazione.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti
CBuf sono memorizzati in forma indiretta (puntatori a).
L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable
ossia deve avere un operatore di copia (=), uno di conronto (==) e
deve avere una funzione:
unsigned HashValue() const;
oppure deve esistere una funzione globale del tipo:
unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se
la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti
viene chiamata la funzione FillCache (ridefibile in classi derivate)
per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia-
mare la funzione Add dopo aver reperito l'oggetto associato alla
chiave, per salvarlo nella cache.
L'uso dell'array consente di inserire quanti elementi si vuole nella
cache senza limiti di dimensioni, inoltre le funzioni di ricerca
ritornano l'indice dell'array piuttosto che gli oggetti CBuf relativi.
*/
template class TCacheArray :
private TShouldDelete
{
typedef TDDAssociation Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIArrayAsVector Array;
friend class TCacheArrayIterator;
public:
typedef void (*IterFunc)(CBuf&, void *);
typedef int (*CondFunc)(const CBuf&, void *);
TCacheArray( unsigned szDic = DEFAULT_HASH_TABLE_SIZE ) :
ary(100, 0, 100),
dic(szDic)
{
OwnsElements(1);
AccettaDuplicati = 0;
}
virtual ~TCacheArray()
{
Flush();
}
int OwnsElements()
{
return TShouldDelete::OwnsElements();
}
void OwnsElements( int del )
{
TShouldDelete::OwnsElements(del);
ary.OwnsElements(del);
}
int AcceptDouble()
{
return AccettaDuplicati;
}
void AcceptDouble(int Flag)
{
AccettaDuplicati = Flag ? 1 : 0;
}
int Add( const CKey& k, CBuf* b );
const CBuf *Find( const CKey& k );
int FindIndex( const CKey& k );
int Fetch( const CKey& k );
void Flush( DeleteType dt = DefDelete );
virtual int FillCache( const CKey& ) { return -1; }
CBuf *& operator []( int loc )
{
PRECONDITION( loc >= 0 && loc < ary.GetItemsInContainer() );
return ary.operator[](loc);
}
CBuf *& operator []( int loc ) const
{
PRECONDITION( loc >= 0 && loc < ary.GetItemsInContainer() );
return ary.operator[](loc);
}
void ForEach( IterFunc iter, void *args )
{
ary.ForEach(iter, args);
}
CBuf *FirstThat( CondFunc cond, void *args ) const
{
return ary.FirstThat(cond, args);
}
CBuf *LastThat( CondFunc cond, void *args ) const
{
return ary.LastThat(cond, args);
}
unsigned GetItemsInContainer() const
{
return ary.GetItemsInContainer();
}
int IsEmpty() const
{
return ary.IsEmpty();
}
protected:
Array ary;
Dictionary dic;
unsigned AccettaDuplicati : 1;
};
template
int TCacheArray::Add( const CKey& k, CBuf* b )
{
PRECONDITION(b != NULL);
Association* ptAss = new Association( k, ary.GetItemsInContainer() );
Association* ptFnd = dic.Find( ptAss );
if( ptFnd )
{
int idx = ptFnd->Value();
if( AccettaDuplicati )
{
idx = ary.GetItemsInContainer();
ary.Add( b );
}
else
{
delete ary[idx];
ary[idx] = b;
}
delete ptAss;
return idx;
}
dic.Add( ptAss );
ary.Add( b );
return ptAss->Value();
}
template
int TCacheArray::FindIndex( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return -1;
return asFound->Value();
}
template
const CBuf* TCacheArray::Find( const CKey& k )
{
int idx = FindIndex(k);
return idx == -1 ? 0 : ary[idx];
}
template
void TCacheArray::Flush( DeleteType dt /*= DefDelete*/ )
{
ary.Flush(dt);
dic.Flush(Delete);
}
template
int TCacheArray::Fetch( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return FillCache(k);
return asFound->Value();
}
/** L'iteratore di TCacheArray.
*/
template class TCacheArrayIterator :
public TIDictionaryAsHashTableIterator< TDDAssociation >
{
typedef TDDAssociation Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIArrayAsVector Array;
typedef TIDictionaryAsHashTableIterator Parent;
Array* ptArr;
public:
TCacheArrayIterator( TCacheArray& c ) : Parent( c.dic )
{
ptArr = &(c.ary);
}
const CKey& Key()
{
return Current()->Key();
}
const CBuf& Value()
{
return *(ptArr->Get(Current()->Value()));
}
};
template class TCacheBlockIterator;
/**
template class TCacheBlock
template class TCacheBlockIterator
Cache generica di oggetti CBuf associati a chiave CKey
senza limitazioni sulle dimensioni con raggruppamento dei dati
per chiave.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti
CBuf sono memorizzati in forma indiretta (puntatori a).
L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable
ossia deve avere un operatore di copia (=), uno di conronto (==) e
deve avere una funzione:
unsigned HashValue() const;
oppure deve esistere una funzione globale del tipo:
unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se
la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti
viene chiamata la funzione FillCache (ridefibile in classi derivate)
per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia-
mare la funzione Add dopo aver reperito l'oggetto associato alla
chiave, per salvarlo nella cache.
La cache associa ad ogni chiave un array di oggetti buffer: quando si
aggiuge la chiave per la prima volta viene creato l'array ed inserito
il primo elemento CBuf nell'array. Successive add con la stessa chiave
aggiungeranno all'array associato alla chiave il nuovo elemento buf.
Quando si preleva un valore dalla cache attraverso Fetch viene restituito
l'array dei valori associati alla chiave fornita.
L'array e' del tipo TIArrayAsVector (vedi TIArrayAsVector).
*/
template class TCacheBlock :
private TShouldDelete
{
typedef TIArrayAsVector Array;
typedef TCAssoc Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIDictionaryAsHashTableIterator IteratorDic;
friend class TCacheBlockIterator;
public:
TCacheBlock( unsigned szDic = DEFAULT_HASH_TABLE_SIZE ) :
dic(szDic)
{
OwnsElements(1);
}
virtual ~TCacheBlock()
{
Flush();
}
int OwnsElements()
{
return TShouldDelete::OwnsElements();
}
void OwnsElements( int del )
{
TShouldDelete::OwnsElements(del);
dic.OwnsElements(del);
}
const Array* Add( const CKey& k, CBuf* b );
const Array* Find( const CKey& k );
const Array* Fetch( const CKey& k );
void Flush( DeleteType dt = DefDelete );
virtual const Array* FillCache( const CKey& ) { return NULL; }
unsigned GetItemsInContainer() const
{
return dic.GetItemsInContainer();
}
int IsEmpty() const
{
return dic.IsEmpty();
}
protected:
Dictionary dic;
};
template
const TIArrayAsVector* TCacheBlock::Add( const CKey& k, CBuf* b )
{
PRECONDITION(b != NULL);
Association* ptFnd = dic.Find( (Association*)(&Association( k, 0 )) );
if( ptFnd ) {
// aggiunge solo il nuovo valore all'array valori
Array* ptArr = const_cast(ptFnd->Value());
ptArr->Add(b);
return ptArr;
}
// crea nuovo array, inserisce prima entry e lo aggiunge a dizionario
Array* ptArr = new Array(10,0,10);
ptArr->OwnsElements(OwnsElements());
ptArr->Add(b);
dic.Add( new Association( k, ptArr ) );
return ptArr;
}
template
const TIArrayAsVector* TCacheBlock::Find( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return 0;
return asFound->Value();
}
template
void TCacheBlock::Flush( DeleteType dt /*= DefDelete*/ )
{
dic.Flush(dt);
}
template
const TIArrayAsVector* TCacheBlock::Fetch( const CKey& k )
{
Association asFind( k, 0 );
Association* asFound = dic.Find( &asFind );
if( !asFound ) return FillCache(k);
return asFound->Value();
}
template class TCacheBlockIterator
{
typedef TIArrayAsVector Array;
typedef TIArrayAsVectorIterator IteratorArr;
typedef TCAssoc Association;
typedef TIDictionaryAsHashTable Dictionary;
typedef TIDictionaryAsHashTableIterator IteratorDic;
Array* curArray;
IteratorArr* curIterator;
IteratorDic htIter;
public:
TCacheBlockIterator( TCacheBlock& c )
: htIter(c.dic)
{
curArray = 0;
curIterator = 0;
Restart();
}
~TCacheBlockIterator()
{
if(curIterator)
delete curIterator;
}
operator int()
{
if(htIter.operator int()) return 1;
if(curIterator) return curIterator->operator int();
return 0;
}
const Association& Current()
{
return *(htIter.Current());
}
void operator ++ ()
{
Scan();
}
void operator ++ (int)
{
Scan();
}
const CKey& Key()
{
return Current().Key();
}
const CBuf& Value()
{
PRECONDITION(curIterator);
return *(curIterator->Current());
}
void Restart()
{
if(curIterator) {
delete curIterator;
curIterator = 0;
}
htIter.Restart();
if(!htIter.operator int()) return;
curArray = const_cast(htIter.Current()->Value());
if(curArray) {
curIterator = new TIArrayAsVectorIterator(*curArray);
}
}
void Scan();
};
template
void TCacheBlockIterator::Scan()
{
if(curIterator) {
curIterator->operator++(1);
if(curIterator->operator int()) return;
delete curIterator;
curIterator = 0;
curArray = 0;
}
htIter.operator++(1);
if(!htIter.operator int()) return;
curArray = const_cast(htIter.Current()->Value());
if(curArray) {
curIterator = new TIArrayAsVectorIterator(*curArray);
}
}
Generated by: nicola on gulliver.wadahome.it on Sun May 25 13:54:34 2003, using kdoc 2.0a53. |