Source: classlib/include/classlib/tcache.h


Annotated List
Files
Globals
Hierarchy
Index
/***************************************************************************
    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.