text: /**************************************************************
   * 
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   * 
   *************************************************************/
  
  
  #ifndef _SWCACHE_HXX
  #define _SWCACHE_HXX
  
  
  
  /*
   * Es werden Pointer auf Objekte verwaltet. Diese werden in einem einfachen
   * PtrArray verwaltet.
   * Angelegt (new) werden die Objekte von Cache-Zugriffsklassen, zuerstoert
   * werden die Objekte vom Cache.
   *
   * Auf die Objekte kann wahlweise per Index in das Array oder per Suche
   * zugegriffen werden. Soll per Index zugegriffen werden, so obliegt die
   * Verwaltung des Index dem Anwender des Cache.
   *
   * Fuer die verwalteten Cache-Objekte gibt es eine Basisklasse, von dieser
   * sind spezifische Klassen abzuleiten.
   * In der Basisklasse werden die Cache-Objekte eines Cache doppelt verkettet,
   * das ermoeglich die Implementierung eines LRU-Algorithmus.
   *
   * Der LRU kann in der Cache-Basisklasse manipuliert werden, indem ein
   * virtueller First-Pointer gesetzt wird. Dieser kann auf den echten ersten
   * plus einem Ofst gesetzt werden. Dadurch kann man den Anfangsbereich des
   * Cache sichern und so dafuer sorgen, dass man waehrend bestimmter
   * Operationen nicht den Cache versaut. Beispiel: Der Idle-Handler sollte nicht
   * den Cache fuer den sichtbaren Bereich vernichten.
   *
   * Der Cache kann in der Groesse erweitert und wieder verkleinert werden.
   * Beispiel: Fuer jede neue Shell wird der Cache fuer FormatInfo vergrossert
   * und beim Destruieren der Shell wieder verkleinert.
   *
   */
  
  #ifdef DBG_UTIL
  #ifndef _STRING_HXX //autogen
  #include <tools/string.hxx>
  #endif
  #endif
  
  #ifndef _SVSTDARR_HXX
  #define _SVSTDARR_USHORTS
  #include <svl/svstdarr.hxx>
  #endif
  
  class SwCacheObj;
  
  SV_DECL_PTRARR_DEL(SwCacheObjArr,SwCacheObj*,1,1)
  
  class SwCache : public SwCacheObjArr
  {
  	SvUShorts aFreePositions;		//Freie Positionen fuer das Insert wenn
  									//die Maximalgrenze nicht erreicht ist.
  									//Immer wenn ein Objekt ausgetragen wird,
  									//so wird seine Position hier eingetragen.
  
  	SwCacheObj *pRealFirst;			//_immer_ der echte LRU-erste
  	SwCacheObj *pFirst;				//der virtuelle erste.
  	SwCacheObj *pLast;
  
  	const sal_uInt16 nMax;				//Mehr sollen nicht aufgenommen werden,
  									//der Cache kann aber dynamisch um jeweils
  									//nMax vergroessert werden.
  		  sal_uInt16 nCurMax;			//Mehr werden nicht aufgenommen.
  
  
  	void DeleteObj( SwCacheObj *pObj );
  
  #ifdef DBG_UTIL
  	ByteString aName;
  	long nAppend;			//Anzahl der Eintragungen durch Erweiterung.
  	long nInsertFree;		//Anzahl der Eintragungen auf freie Plaetze.
  	long nReplace;			//Anzahl der Ersetzungen durch ein neues Objekt
  	long nGetSuccess;		//Anzahl der Erfolgreichen Get's
  	long nGetFail;			//Anzahl der nicht Erfolgreichen Get's
  	long nToTop;			//Anzahl der Umsortierungen (LRU)
  	long nDelete;			//Anzahl der Loeschungen (von Aussen)
  	long nGetSeek;			//Anzahl der Get's ohne Index
  	long nAverageSeekCnt;	//Anzahl der Seek's fuer alle Get's ohne Index
  	long nFlushCnt;			//Anzahl von Flush-Aufrufen.
  	long nFlushedObjects;	//Anzahl der wg. Flush vernichteten Objekte
  	long nIncreaseMax;		//Anzahl Cache-Erweiterungen
  	long nDecreaseMax;		//Anzahl Cache-Verkleinerungen
  
  	void Check();			//Wird bei swcache.cxx mit DEBUG aktiv!
  #endif
  
  public:
  
  	//nur sal_uInt8 hineinstecken!!!
  #ifdef DBG_UTIL
  	SwCache( const sal_uInt16 nInitSize, const sal_uInt16 nGrowSize,
  			const ByteString &rNm );
  	~SwCache();
  #else
  	SwCache( const sal_uInt16 nInitSize, const sal_uInt16 nGrowSize );
  #endif
  
  	void Flush( const sal_uInt8 nPercent = 100 );
  
  	//bToTop == sal_False -> Keine LRU-Umsortierung!
  	SwCacheObj *Get( const void *pOwner, const sal_Bool bToTop = sal_True );
  	SwCacheObj *Get( const void *pOwner, const sal_uInt16 nIndex,
  					 const sal_Bool bToTop = sal_True );
  	void ToTop( SwCacheObj *pObj );
  
  	sal_Bool Insert( SwCacheObj *pNew );
  	void Delete( const void *pOwner );
  //	void Delete( const void *pOwner, const sal_uInt16 nIndex );
  
  	void SetLRUOfst( const sal_uInt16 nOfst );		//nOfst sagt wieviele unangetastet
  												//bleiben sollen.
  	void ResetLRUOfst() { pFirst = pRealFirst; }
  
  	inline void IncreaseMax( const sal_uInt16 nAdd );
  	inline void DecreaseMax( const sal_uInt16 nSub );
  	sal_uInt16 GetCurMax() const { return nCurMax; }
  	inline SwCacheObj *First() { return pRealFirst; }
  	inline SwCacheObj *Last()  { return pLast; }
  	inline SwCacheObj *Next( SwCacheObj *pCacheObj);
  };
  
  //Cache-Manipulation auf die sichere Art.
  class SwSaveSetLRUOfst
  {
  	SwCache &rCache;
  public:
  	SwSaveSetLRUOfst( SwCache &rC, const sal_uInt16 nOfst )
  		: rCache( rC ) 			{ rCache.SetLRUOfst( nOfst );  }
  
  	~SwSaveSetLRUOfst()			{ rCache.ResetLRUOfst(); }
  };
  
  //Das allgemeine CacheObjekt. Anwender des Cache muessen eine Klasse vom
  //CacheObjekt ableiten und dort die Nutzdaten unterbringen.
  
  class SwCacheObj
  {
  	friend class SwCache;	//Der darf alles
  
  	SwCacheObj *pNext;		//Fuer die LRU-Verkettung.
  	SwCacheObj *pPrev;
  
  	sal_uInt16 nCachePos;		//Position im Cache-Array.
  
  	sal_uInt8		nLock;
  
  	inline SwCacheObj *GetNext() { return pNext; }
  	inline SwCacheObj *GetPrev() { return pPrev; }
  	inline void SetNext( SwCacheObj *pNew )	 { pNext = pNew; }
  	inline void SetPrev( SwCacheObj *pNew )  { pPrev = pNew; }
  
  	inline void   SetCachePos( const sal_uInt16 nNew ) { nCachePos = nNew; }
  
  protected:
  	const void *pOwner;
  	inline void SetOwner( const void *pNew ) { pOwner = pNew; }
  
  public:
  
  	SwCacheObj( const void *pOwner );
  	virtual ~SwCacheObj();
  
  	inline const void *GetOwner() const { return pOwner; }
  	inline sal_Bool IsOwner( const void *pNew ) const;
  
  	inline sal_uInt16 GetCachePos() const { return nCachePos; }
  	inline void Invalidate()		  { pOwner = 0; }
  
  	inline sal_Bool IsLocked() const { return 0 != nLock; }
  
  #ifndef DBG_UTIL
  	inline void Lock() { ++nLock; }
  	inline void Unlock() { --nLock; }
  #else
  	void Lock();
  	void Unlock();
  #endif
  
  	SwCacheObj *Next() { return pNext; }
  	SwCacheObj *Prev() { return pPrev; }
  
  };
  
  //Zugriffsklasse fuer den Cache. Im CTor wird das CacheObjekt erzeugt.
  //Wenn der Cache keines herausrueckt wird der Member zunaechst auf 0 gesetzt.
  //Beim Get wird dann eines erzeugt und, falls moeglich, in den Cache
  //eingetragen.
  //Anwender der des Cache muessen eine Klasse vom Access ableiten um
  //fuer Typsicherheit zu sorgen, die Basisklasse sollte fuer das Get aber immer
  //gerufen werden, ein Abgeleitetes Get sollte nur der Typsicherheit dienen.
  //Cache-Objekte werden stets gelockt solange die Instanz lebt.
  
  class SwCacheAccess
  {
  	SwCache &rCache;
  
  	void _Get();
  
  protected:
  	SwCacheObj *pObj;
  	const void *pOwner;		//Kann ggf. in NewObj benutzt werden.
  
  	virtual SwCacheObj *NewObj() = 0;
  
  	inline SwCacheObj *Get();
  
  	inline SwCacheAccess( SwCache &rCache, const void *pOwner, sal_Bool bSeek = sal_True );
  	inline SwCacheAccess( SwCache &rCache, const void *pOwner, const sal_uInt16 nIndex );
  
  public:
  	virtual ~SwCacheAccess();
  
  	virtual sal_Bool IsAvailable() const;
  
  	//Abkuerzung fuer diejenigen, die wissen, das die Ableitung das IsAvailable
  	//nicht ueberladen haben.
  	sal_Bool IsAvail() const { return pObj != 0; }
  };
  
  inline void SwCache::IncreaseMax( const sal_uInt16 nAdd )
  {
      nCurMax = nCurMax + sal::static_int_cast< sal_uInt16 >(nAdd);
  #ifdef DBG_UTIL
  	++nIncreaseMax;
  #endif
  }
  inline void SwCache::DecreaseMax( const sal_uInt16 nSub )
  {
  	if ( nCurMax > nSub )
  		nCurMax = nCurMax - sal::static_int_cast< sal_uInt16 >(nSub);
  #ifdef DBG_UTIL
  	++nDecreaseMax;
  #endif
  }
  
  inline sal_Bool SwCacheObj::IsOwner( const void *pNew ) const
  {
  	return pOwner && pOwner == pNew;
  }
  
  inline SwCacheObj *SwCache::Next( SwCacheObj *pCacheObj)
  {
  	if ( pCacheObj )
  		return pCacheObj->GetNext();
  	else
  		return NULL;
  }
  
  inline SwCacheAccess::SwCacheAccess( SwCache &rC, const void *pOwn, sal_Bool bSeek ) :
  	rCache( rC ),
  	pObj( 0 ),
  	pOwner( pOwn )
  {
  	if ( bSeek && pOwner && 0 != (pObj = rCache.Get( pOwner )) )
  		pObj->Lock();
  }
  
  inline SwCacheAccess::SwCacheAccess( SwCache &rC, const void *pOwn,
  							  const sal_uInt16 nIndex ) :
  	rCache( rC ),
  	pObj( 0 ),
  	pOwner( pOwn )
  {
  	if ( pOwner && 0 != (pObj = rCache.Get( pOwner, nIndex )) )
  		pObj->Lock();
  }
  
  inline SwCacheObj *SwCacheAccess::Get()
  {
  	if ( !pObj )
  		_Get();
  	return pObj;
  }
  
  
  #endif
  