xref: /trunk/main/stoc/source/tdmanager/lrucache.hxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir #ifndef _LRU_CACHE_HXX_
28*cdf0e10cSrcweir #define _LRU_CACHE_HXX_
29*cdf0e10cSrcweir 
30*cdf0e10cSrcweir // __CACHE_DIAGNOSE forces cache size to 4 and works only for OUString keys
31*cdf0e10cSrcweir //  #define __CACHE_DIAGNOSE 1
32*cdf0e10cSrcweir 
33*cdf0e10cSrcweir #include <osl/mutex.hxx>
34*cdf0e10cSrcweir #include "rtl/ustring.hxx"
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <hash_map>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir 
39*cdf0e10cSrcweir /** Implementation of a least recently used (lru) cache.
40*cdf0e10cSrcweir     <br>
41*cdf0e10cSrcweir     @author Daniel Boelzle
42*cdf0e10cSrcweir */
43*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
44*cdf0e10cSrcweir class LRU_Cache
45*cdf0e10cSrcweir {
46*cdf0e10cSrcweir     struct CacheEntry
47*cdf0e10cSrcweir     {
48*cdf0e10cSrcweir         t_Key               aKey;
49*cdf0e10cSrcweir         t_Val               aVal;
50*cdf0e10cSrcweir         CacheEntry *        pPred;
51*cdf0e10cSrcweir         CacheEntry *        pSucc;
52*cdf0e10cSrcweir     };
53*cdf0e10cSrcweir     typedef ::std::hash_map< t_Key, CacheEntry *, t_KeyHash, t_KeyEqual > t_Key2Element;
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir     mutable ::osl::Mutex        _aCacheMutex;
56*cdf0e10cSrcweir     sal_Int32                   _nCachedElements;
57*cdf0e10cSrcweir     t_Key2Element               _aKey2Element;
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir     CacheEntry *                _pBlock;
60*cdf0e10cSrcweir     mutable CacheEntry *        _pHead;
61*cdf0e10cSrcweir     mutable CacheEntry *        _pTail;
62*cdf0e10cSrcweir     inline void toFront( CacheEntry * pEntry ) const;
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir public:
65*cdf0e10cSrcweir     /** Constructor:
66*cdf0e10cSrcweir         <br>
67*cdf0e10cSrcweir         @param nCachedElements number of elements to be cached; default param set to 128
68*cdf0e10cSrcweir     */
69*cdf0e10cSrcweir     inline LRU_Cache( sal_Int32 nCachedElements = 128 );
70*cdf0e10cSrcweir     /** Destructor: releases all cached elements and keys.
71*cdf0e10cSrcweir         <br>
72*cdf0e10cSrcweir     */
73*cdf0e10cSrcweir     inline ~LRU_Cache();
74*cdf0e10cSrcweir 
75*cdf0e10cSrcweir     /** Retrieves a value from the cache. Returns default constructed value,
76*cdf0e10cSrcweir         if none was found.
77*cdf0e10cSrcweir         <br>
78*cdf0e10cSrcweir         @param rKey a key
79*cdf0e10cSrcweir         @return value
80*cdf0e10cSrcweir     */
81*cdf0e10cSrcweir     inline t_Val getValue( t_Key const & rKey ) const;
82*cdf0e10cSrcweir     /** Sets a value to be cached for given key.
83*cdf0e10cSrcweir         <br>
84*cdf0e10cSrcweir         @param rKey a key
85*cdf0e10cSrcweir         @param rValue a value
86*cdf0e10cSrcweir     */
87*cdf0e10cSrcweir     inline void setValue( t_Key const & rKey, t_Val const & rValue );
88*cdf0e10cSrcweir     /** Tests whether a value is cached for given key.
89*cdf0e10cSrcweir         <br>
90*cdf0e10cSrcweir         @param rKey a key
91*cdf0e10cSrcweir         @return true, if value is cached
92*cdf0e10cSrcweir     */
93*cdf0e10cSrcweir     inline sal_Bool hasValue( t_Key const & rKey ) const;
94*cdf0e10cSrcweir     /** Clears the cache, thus releasing all cached elements and keys.
95*cdf0e10cSrcweir         <br>
96*cdf0e10cSrcweir     */
97*cdf0e10cSrcweir     inline void clear();
98*cdf0e10cSrcweir };
99*cdf0e10cSrcweir //__________________________________________________________________________________________________
100*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
101*cdf0e10cSrcweir inline LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::LRU_Cache( sal_Int32 nCachedElements )
102*cdf0e10cSrcweir #ifdef __CACHE_DIAGNOSE
103*cdf0e10cSrcweir     : _nCachedElements( 4 )
104*cdf0e10cSrcweir #else
105*cdf0e10cSrcweir     : _nCachedElements( nCachedElements )
106*cdf0e10cSrcweir #endif
107*cdf0e10cSrcweir     , _pBlock( 0 )
108*cdf0e10cSrcweir {
109*cdf0e10cSrcweir     if (_nCachedElements > 0)
110*cdf0e10cSrcweir     {
111*cdf0e10cSrcweir         _pBlock = new CacheEntry[_nCachedElements];
112*cdf0e10cSrcweir         _pHead  = _pBlock;
113*cdf0e10cSrcweir         _pTail  = _pBlock + _nCachedElements -1;
114*cdf0e10cSrcweir         for ( sal_Int32 nPos = _nCachedElements; nPos--; )
115*cdf0e10cSrcweir         {
116*cdf0e10cSrcweir             _pBlock[nPos].pPred = _pBlock + nPos -1;
117*cdf0e10cSrcweir             _pBlock[nPos].pSucc = _pBlock + nPos +1;
118*cdf0e10cSrcweir         }
119*cdf0e10cSrcweir     }
120*cdf0e10cSrcweir }
121*cdf0e10cSrcweir //__________________________________________________________________________________________________
122*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
123*cdf0e10cSrcweir inline LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::~LRU_Cache()
124*cdf0e10cSrcweir {
125*cdf0e10cSrcweir     delete [] _pBlock;
126*cdf0e10cSrcweir }
127*cdf0e10cSrcweir //__________________________________________________________________________________________________
128*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
129*cdf0e10cSrcweir inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::toFront(
130*cdf0e10cSrcweir     CacheEntry * pEntry ) const
131*cdf0e10cSrcweir {
132*cdf0e10cSrcweir     if (pEntry != _pHead)
133*cdf0e10cSrcweir     {
134*cdf0e10cSrcweir         // cut out element
135*cdf0e10cSrcweir         if (pEntry == _pTail)
136*cdf0e10cSrcweir         {
137*cdf0e10cSrcweir             _pTail = pEntry->pPred;
138*cdf0e10cSrcweir         }
139*cdf0e10cSrcweir         else
140*cdf0e10cSrcweir         {
141*cdf0e10cSrcweir             pEntry->pSucc->pPred = pEntry->pPred;
142*cdf0e10cSrcweir             pEntry->pPred->pSucc = pEntry->pSucc;
143*cdf0e10cSrcweir         }
144*cdf0e10cSrcweir         // push to front
145*cdf0e10cSrcweir         _pHead->pPred = pEntry;
146*cdf0e10cSrcweir         pEntry->pSucc = _pHead;
147*cdf0e10cSrcweir         _pHead        = pEntry;
148*cdf0e10cSrcweir     }
149*cdf0e10cSrcweir }
150*cdf0e10cSrcweir //__________________________________________________________________________________________________
151*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
152*cdf0e10cSrcweir inline sal_Bool LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::hasValue(
153*cdf0e10cSrcweir     t_Key const & rKey ) const
154*cdf0e10cSrcweir {
155*cdf0e10cSrcweir     ::osl::MutexGuard aGuard( _aCacheMutex );
156*cdf0e10cSrcweir     typename t_Key2Element::const_iterator const iFind( _aKey2Element.find( rKey ) );
157*cdf0e10cSrcweir     return (iFind != _aKey2Element.end());
158*cdf0e10cSrcweir }
159*cdf0e10cSrcweir //__________________________________________________________________________________________________
160*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
161*cdf0e10cSrcweir inline t_Val LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::getValue(
162*cdf0e10cSrcweir     t_Key const & rKey ) const
163*cdf0e10cSrcweir {
164*cdf0e10cSrcweir     ::osl::MutexGuard aGuard( _aCacheMutex );
165*cdf0e10cSrcweir     const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) );
166*cdf0e10cSrcweir     if (iFind != _aKey2Element.end())
167*cdf0e10cSrcweir     {
168*cdf0e10cSrcweir         CacheEntry * pEntry = (*iFind).second;
169*cdf0e10cSrcweir         toFront( pEntry );
170*cdf0e10cSrcweir #ifdef __CACHE_DIAGNOSE
171*cdf0e10cSrcweir         OSL_TRACE( "> retrieved element \"" );
172*cdf0e10cSrcweir         OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() );
173*cdf0e10cSrcweir         OSL_TRACE( "\" from cache <\n" );
174*cdf0e10cSrcweir #endif
175*cdf0e10cSrcweir         return pEntry->aVal;
176*cdf0e10cSrcweir     }
177*cdf0e10cSrcweir     return t_Val();
178*cdf0e10cSrcweir }
179*cdf0e10cSrcweir //__________________________________________________________________________________________________
180*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
181*cdf0e10cSrcweir inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::setValue(
182*cdf0e10cSrcweir     t_Key const & rKey, t_Val const & rValue )
183*cdf0e10cSrcweir {
184*cdf0e10cSrcweir     if (_nCachedElements > 0)
185*cdf0e10cSrcweir     {
186*cdf0e10cSrcweir         ::osl::MutexGuard aGuard( _aCacheMutex );
187*cdf0e10cSrcweir         typename t_Key2Element::const_iterator const iFind( _aKey2Element.find( rKey ) );
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir         CacheEntry * pEntry;
190*cdf0e10cSrcweir         if (iFind == _aKey2Element.end())
191*cdf0e10cSrcweir         {
192*cdf0e10cSrcweir             pEntry = _pTail; // erase last element
193*cdf0e10cSrcweir #ifdef __CACHE_DIAGNOSE
194*cdf0e10cSrcweir             if (pEntry->aKey.getLength())
195*cdf0e10cSrcweir             {
196*cdf0e10cSrcweir                 OSL_TRACE( "> kicking element \"" );
197*cdf0e10cSrcweir                 OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() );
198*cdf0e10cSrcweir                 OSL_TRACE( "\" from cache <\n" );
199*cdf0e10cSrcweir             }
200*cdf0e10cSrcweir #endif
201*cdf0e10cSrcweir             _aKey2Element.erase( pEntry->aKey );
202*cdf0e10cSrcweir             _aKey2Element[ pEntry->aKey = rKey ] = pEntry;
203*cdf0e10cSrcweir         }
204*cdf0e10cSrcweir         else
205*cdf0e10cSrcweir         {
206*cdf0e10cSrcweir             pEntry = (*iFind).second;
207*cdf0e10cSrcweir #ifdef __CACHE_DIAGNOSE
208*cdf0e10cSrcweir             OSL_TRACE( "> replacing element \"" );
209*cdf0e10cSrcweir             OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() );
210*cdf0e10cSrcweir             OSL_TRACE( "\" in cache <\n" );
211*cdf0e10cSrcweir #endif
212*cdf0e10cSrcweir         }
213*cdf0e10cSrcweir         pEntry->aVal = rValue;
214*cdf0e10cSrcweir         toFront( pEntry );
215*cdf0e10cSrcweir     }
216*cdf0e10cSrcweir }
217*cdf0e10cSrcweir //__________________________________________________________________________________________________
218*cdf0e10cSrcweir template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual >
219*cdf0e10cSrcweir inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::clear()
220*cdf0e10cSrcweir {
221*cdf0e10cSrcweir     ::osl::MutexGuard aGuard( _aCacheMutex );
222*cdf0e10cSrcweir     _aKey2Element.clear();
223*cdf0e10cSrcweir     for ( sal_Int32 nPos = _nCachedElements; nPos--; )
224*cdf0e10cSrcweir     {
225*cdf0e10cSrcweir         _pBlock[nPos].aKey = t_Key();
226*cdf0e10cSrcweir         _pBlock[nPos].aVal = t_Val();
227*cdf0e10cSrcweir     }
228*cdf0e10cSrcweir #ifdef __CACHE_DIAGNOSE
229*cdf0e10cSrcweir     OSL_TRACE( "> cleared cache <\n" );
230*cdf0e10cSrcweir #endif
231*cdf0e10cSrcweir }
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir //==================================================================================================
234*cdf0e10cSrcweir struct FctHashOUString : public ::std::unary_function< ::rtl::OUString const &, size_t >
235*cdf0e10cSrcweir {
236*cdf0e10cSrcweir     size_t operator()( ::rtl::OUString const & rKey ) const
237*cdf0e10cSrcweir         { return (size_t)rKey.hashCode(); }
238*cdf0e10cSrcweir };
239*cdf0e10cSrcweir 
240*cdf0e10cSrcweir /** Template instance for OUString keys, Any values.<br>
241*cdf0e10cSrcweir */
242*cdf0e10cSrcweir typedef LRU_Cache< ::rtl::OUString, ::com::sun::star::uno::Any,
243*cdf0e10cSrcweir                    FctHashOUString, ::std::equal_to< ::rtl::OUString > >
244*cdf0e10cSrcweir     LRU_CacheAnyByOUString;
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir #endif
248