/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #ifndef INCLUDED_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX #define INCLUDED_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX // __CACHE_DIAGNOSE forces cache size to 4 and works only for OUString keys // #define __CACHE_DIAGNOSE 1 #include #include #include #include /** Implementation of a least recently used (lru) cache.
@author Daniel Boelzle */ template< class t_Key, class t_Val, class t_KeyHash > class LRU_Cache { struct CacheEntry { t_Key aKey; t_Val aVal; CacheEntry * pPred; CacheEntry * pSucc; }; typedef ::boost::unordered_map< t_Key, CacheEntry *, t_KeyHash > 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:
@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.
*/ inline ~LRU_Cache(); /** Retrieves a value from the cache. Returns default constructed value, if none was found.
@param rKey a key @return value */ inline t_Val getValue( const t_Key & rKey ) const; /** Sets a value to be cached for given key.
@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.
@param rKey a key @return true, if value is cached */ inline bool hasValue( const t_Key & rKey ) const; /** Clears the cache, thus releasing all cached elements and keys.
*/ inline void clear(); }; template< class t_Key, class t_Val, class t_KeyHash > inline LRU_Cache< t_Key, t_Val, t_KeyHash >::LRU_Cache( sal_Int32 nCachedElements ) #ifdef __CACHE_DIAGNOSE : _nCachedElements( 4 ) #else : _nCachedElements( nCachedElements ) #endif , _pBlock( 0 ) , _pHead( 0 ) , _pTail( 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 > inline LRU_Cache< t_Key, t_Val, t_KeyHash >::~LRU_Cache() { delete [] _pBlock; } template< class t_Key, class t_Val, class t_KeyHash > inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::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 > inline bool LRU_Cache< t_Key, t_Val, t_KeyHash >::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 > inline t_Val LRU_Cache< t_Key, t_Val, t_KeyHash >::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 SAL_INFO("stoc.corerefl", "> retrieved element \"" ); SAL_INFO("stoc.corerefl", "" << pEntry->aKey); SAL_INFO("stoc.corerefl", "\" from cache <" ); #endif return pEntry->aVal; } return t_Val(); } template< class t_Key, class t_Val, class t_KeyHash > inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::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()) { SAL_INFO("stoc.corerefl", "> kicking element \"" ); SAL_INFO("stoc.corerefl", "" << pEntry->aKey); SAL_INFO("stoc.corerefl", "\" from cache <" ); } #endif _aKey2Element.erase( pEntry->aKey ); _aKey2Element[ pEntry->aKey = rKey ] = pEntry; } else { pEntry = (*iFind).second; #ifdef __CACHE_DIAGNOSE SAL_INFO("stoc.corerefl", "> replacing element \"" ); SAL_INFO("stoc.corerefl", "" << pEntry->aKey); SAL_INFO("stoc.corerefl", "\" in cache <" ); #endif } pEntry->aVal = rValue; toFront( pEntry ); } } template< class t_Key, class t_Val, class t_KeyHash > inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::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 SAL_INFO("stoc.corerefl", "> cleared cache <" ); #endif } /** Template instance for OUString keys, Any values.
*/ typedef LRU_Cache< OUString, css::uno::Any, OUStringHash > LRU_CacheAnyByOUString; #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */