| /************************************************************** |
| * |
| * 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 _LRU_CACHE_HXX_ |
| #define _LRU_CACHE_HXX_ |
| |
| // __CACHE_DIAGNOSE forces cache size to 4 and works only for OUString keys |
| // #define __CACHE_DIAGNOSE 1 |
| |
| #include <osl/mutex.hxx> |
| #include "rtl/ustring.hxx" |
| |
| #include <hash_map> |
| |
| /** Implementation of a least recently used (lru) cache. |
| <br> |
| @author Daniel Boelzle |
| */ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| class LRU_Cache |
| { |
| struct CacheEntry |
| { |
| t_Key aKey; |
| t_Val aVal; |
| CacheEntry * pPred; |
| CacheEntry * pSucc; |
| }; |
| typedef ::std::hash_map< t_Key, CacheEntry *, t_KeyHash, t_KeyEqual > t_Key2Element; |
| |
| mutable ::osl::Mutex _aCacheMutex; |
| sal_Int32 _nCachedElements; |
| t_Key2Element _aKey2Element; |
| |
| CacheEntry * _pBlock; |
| mutable CacheEntry * _pHead; |
| mutable CacheEntry * _pTail; |
| inline void toFront( CacheEntry * pEntry ) const; |
| |
| public: |
| /** Constructor: |
| <br> |
| @param nCachedElements number of elements to be cached; default param set to 128 |
| */ |
| inline LRU_Cache( sal_Int32 nCachedElements = 128 ); |
| /** Destructor: releases all cached elements and keys. |
| <br> |
| */ |
| inline ~LRU_Cache(); |
| |
| /** Retrieves a value from the cache. Returns default constructed value, |
| if none was found. |
| <br> |
| @param rKey a key |
| @return value |
| */ |
| inline t_Val getValue( const t_Key & rKey ) const; |
| /** Sets a value to be cached for given key. |
| <br> |
| @param rKey a key |
| @param rValue a value |
| */ |
| inline void setValue( const t_Key & rKey, const t_Val & rValue ); |
| /** Tests whether a value is cached for given key. |
| <br> |
| @param rKey a key |
| @return true, if value is cached |
| */ |
| inline sal_Bool hasValue( const t_Key & rKey ) const; |
| /** Clears the cache, thus releasing all cached elements and keys. |
| <br> |
| */ |
| inline void clear(); |
| }; |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::LRU_Cache( sal_Int32 nCachedElements ) |
| #ifdef __CACHE_DIAGNOSE |
| : _nCachedElements( 4 ) |
| #else |
| : _nCachedElements( nCachedElements ) |
| #endif |
| , _pBlock( 0 ) |
| { |
| if (_nCachedElements > 0) |
| { |
| _pBlock = new CacheEntry[_nCachedElements]; |
| _pHead = _pBlock; |
| _pTail = _pBlock + _nCachedElements -1; |
| for ( sal_Int32 nPos = _nCachedElements; nPos--; ) |
| { |
| _pBlock[nPos].pPred = _pBlock + nPos -1; |
| _pBlock[nPos].pSucc = _pBlock + nPos +1; |
| } |
| } |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::~LRU_Cache() |
| { |
| delete [] _pBlock; |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::toFront( CacheEntry * pEntry ) const |
| { |
| if (pEntry != _pHead) |
| { |
| // cut out element |
| if (pEntry == _pTail) |
| { |
| _pTail = pEntry->pPred; |
| } |
| else |
| { |
| pEntry->pSucc->pPred = pEntry->pPred; |
| pEntry->pPred->pSucc = pEntry->pSucc; |
| } |
| // push to front |
| _pHead->pPred = pEntry; |
| pEntry->pSucc = _pHead; |
| _pHead = pEntry; |
| } |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline sal_Bool LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::hasValue( const t_Key & rKey ) const |
| { |
| ::osl::MutexGuard aGuard( _aCacheMutex ); |
| const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) ); |
| return (iFind != _aKey2Element.end()); |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline t_Val LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::getValue( const t_Key & rKey ) const |
| { |
| ::osl::MutexGuard aGuard( _aCacheMutex ); |
| const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) ); |
| if (iFind != _aKey2Element.end()) |
| { |
| CacheEntry * pEntry = (*iFind).second; |
| toFront( pEntry ); |
| #ifdef __CACHE_DIAGNOSE |
| OSL_TRACE( "> retrieved element \"" ); |
| OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| OSL_TRACE( "\" from cache <\n" ); |
| #endif |
| return pEntry->aVal; |
| } |
| return t_Val(); |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::setValue( |
| const t_Key & rKey, const t_Val & rValue ) |
| { |
| ::osl::MutexGuard aGuard( _aCacheMutex ); |
| if (_nCachedElements > 0) |
| { |
| const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) ); |
| |
| CacheEntry * pEntry; |
| if (iFind == _aKey2Element.end()) |
| { |
| pEntry = _pTail; // erase last element |
| #ifdef __CACHE_DIAGNOSE |
| if (pEntry->aKey.getLength()) |
| { |
| OSL_TRACE( "> kicking element \"" ); |
| OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| OSL_TRACE( "\" from cache <\n" ); |
| } |
| #endif |
| _aKey2Element.erase( pEntry->aKey ); |
| _aKey2Element[ pEntry->aKey = rKey ] = pEntry; |
| } |
| else |
| { |
| pEntry = (*iFind).second; |
| #ifdef __CACHE_DIAGNOSE |
| OSL_TRACE( "> replacing element \"" ); |
| OSL_TRACE( ::rtl::OUStringToOString( pEntry->aKey, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| OSL_TRACE( "\" in cache <\n" ); |
| #endif |
| } |
| pEntry->aVal = rValue; |
| toFront( pEntry ); |
| } |
| } |
| //__________________________________________________________________________________________________ |
| template< class t_Key, class t_Val, class t_KeyHash, class t_KeyEqual > |
| inline void LRU_Cache< t_Key, t_Val, t_KeyHash, t_KeyEqual >::clear() |
| { |
| ::osl::MutexGuard aGuard( _aCacheMutex ); |
| _aKey2Element.clear(); |
| for ( sal_Int32 nPos = _nCachedElements; nPos--; ) |
| { |
| _pBlock[nPos].aKey = t_Key(); |
| _pBlock[nPos].aVal = t_Val(); |
| } |
| _nCachedElements = 0; |
| #ifdef __CACHE_DIAGNOSE |
| OSL_TRACE( "> cleared cache <\n" ); |
| #endif |
| } |
| |
| //================================================================================================== |
| struct FctHashOUString : public ::std::unary_function< const ::rtl::OUString &, size_t > |
| { |
| size_t operator()( const ::rtl::OUString & rKey ) const |
| { return rKey.hashCode(); } |
| }; |
| |
| /** Template instance for OUString keys, Any values.<br> |
| */ |
| typedef LRU_Cache< ::rtl::OUString, ::com::sun::star::uno::Any, |
| FctHashOUString, ::std::equal_to< ::rtl::OUString > > |
| LRU_CacheAnyByOUString; |
| |
| |
| #endif |