File indexing completed on 2024-04-28 05:32:09
0001 #ifndef oxygencache_h 0002 #define oxygencache_h 0003 0004 /* 0005 * this file is part of the oxygen gtk engine 0006 * SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0007 * 0008 * SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "config.h" 0012 0013 #include <algorithm> 0014 #include <map> 0015 #include <deque> 0016 0017 namespace Oxygen 0018 { 0019 0020 //! simple firt-in first-out stl based cache 0021 /*! 0022 an stl::map is used to keep the association between key and value. 0023 an stl::list is used to keep track of the most recently used values. 0024 the list contains pointers to the keys inserted in the map, to avoid 0025 unnecessary copy constructors. 0026 the 'erase' method is used to delete objects that are removed from the cache. 0027 By default, the erase method does nothing. It must be reimplemented to deal with 0028 non default Value deletion, when, for instance, the cache is used to store pointers 0029 */ 0030 template <typename T, typename M> 0031 class SimpleCache 0032 { 0033 0034 public: 0035 0036 //!@name convernience typenames 0037 typedef T Key; 0038 typedef M Value; 0039 typedef std::map<T,M> Map; 0040 typedef typename Map::iterator iterator; 0041 typedef typename Map::const_iterator const_iterator; 0042 0043 //! creator 0044 SimpleCache( size_t size = 100, M defaultValue = M() ): 0045 _maxSize( size ), 0046 _defaultValue( defaultValue ) 0047 {} 0048 0049 //! copy constructor 0050 inline SimpleCache( const SimpleCache<T,M>& ); 0051 0052 //! destructor 0053 virtual ~SimpleCache( void ) 0054 { 0055 for( typename Map::iterator iter = _map.begin(); iter != _map.end(); iter++ ) 0056 { erase( iter->second ); } 0057 } 0058 0059 //! assignment 0060 inline SimpleCache<T, M>& operator = (const SimpleCache<T, M>& ); 0061 0062 //! clear cache 0063 virtual void clear( void ) 0064 { 0065 for( typename Map::iterator iter = _map.begin(); iter != _map.end(); iter++ ) 0066 { erase( iter->second ); } 0067 _map.clear(); 0068 _keys.clear(); 0069 } 0070 0071 //! insert pair in cache 0072 inline const M& insert( const T&, const M& ); 0073 0074 //! returns true if cache contains key 0075 /*! cannot be const, because key gets promoted when contained */ 0076 inline bool contains( const T& ); 0077 0078 //! find item in map 0079 /*! cannot be const, because key gets promoted when found */ 0080 inline iterator find( const T& ); 0081 0082 //! return value for given key, or defaultValue if not found 0083 inline const M& value( const T& ); 0084 0085 //! end 0086 inline iterator end( void ) 0087 { return _map.end(); } 0088 0089 //! end 0090 inline const_iterator end( void ) const 0091 { return _map.end(); } 0092 0093 protected: 0094 0095 //! erase value 0096 /*! 0097 by default, does nothing. Must be re-implemented with proper deletion 0098 if for istance cache is used to store pointers 0099 */ 0100 virtual void erase( M& ) 0101 {} 0102 0103 //! promote key to front of the list 0104 virtual inline void promote( const T& ); 0105 0106 //! adjust cache size 0107 inline void adjustSize( void ); 0108 0109 //! give access to key list to derived classes 0110 typedef std::deque<const T*> List; 0111 List& keys( void ) 0112 { return _keys; } 0113 0114 private: 0115 0116 //! cache maximum size 0117 size_t _maxSize; 0118 0119 //! map 0120 Map _map; 0121 0122 //! keys 0123 List _keys; 0124 0125 M _defaultValue; 0126 0127 }; 0128 0129 //______________________________________________________________________ 0130 template <typename T, typename M> 0131 SimpleCache<T,M>::SimpleCache( const SimpleCache<T,M>& other ): 0132 _maxSize( other._maxSize ), 0133 _map( other._map ) 0134 { 0135 0136 // loop over keys in other list 0137 for( typename List::const_iterator key_iter = other._keys.begin(); key_iter != other._keys.end(); key_iter++ ) 0138 { 0139 // find corresponding iterator 0140 typename Map::const_iterator iter( _map.find( **key_iter ) ); 0141 0142 // insert address of corresponding key in key list 0143 _keys.push_back( &iter->first ); 0144 } 0145 } 0146 0147 //______________________________________________________________________ 0148 template <typename T, typename M> 0149 SimpleCache<T,M>& SimpleCache<T,M>::operator = (const SimpleCache<T,M>& other ) 0150 { 0151 // clear 0152 clear(); 0153 0154 // copy max size and map 0155 _maxSize = other._maxSize; 0156 _map = other._map; 0157 0158 // loop over keys in other list 0159 for( typename List::const_iterator key_iter = other._keys.begin(); key_iter != other._keys.end(); key_iter++ ) 0160 { 0161 // find corresponding iterator 0162 typename Map::const_iterator iter( _map.find( **key_iter ) ); 0163 0164 // insert address of corresponding key in key list 0165 _keys.push_back( &iter->first ); 0166 } 0167 0168 return *this; 0169 } 0170 0171 //______________________________________________________________________ 0172 template <typename T, typename M> 0173 const M& SimpleCache<T,M>::insert( const T& key, const M& value ) 0174 { 0175 0176 typename Map::iterator iter = _map.find( key ); 0177 if( iter == _map.end() ) 0178 { 0179 0180 // insert in map, and push key in list 0181 iter = _map.insert( std::make_pair( key, value ) ).first; 0182 const Key& internal_key( iter->first ); 0183 _keys.push_front( &internal_key ); 0184 0185 } else { 0186 0187 // delete existing value 0188 erase( iter->second ); 0189 0190 // assign new value 0191 iter->second = value; 0192 0193 // move key to front of the list 0194 promote( iter->first ); 0195 0196 } 0197 0198 // adjust size 0199 adjustSize(); 0200 0201 // return newly inserted value 0202 return iter->second; 0203 0204 } 0205 0206 //______________________________________________________________________ 0207 template <typename T, typename M> 0208 bool SimpleCache<T,M>::contains( const T& key ) 0209 { 0210 typename Map::const_iterator iter = _map.find( key ); 0211 if( iter == _map.end() ) return false; 0212 else { 0213 0214 promote( iter->first ); 0215 return true; 0216 0217 } 0218 } 0219 0220 //______________________________________________________________________ 0221 template <typename T, typename M> 0222 typename SimpleCache<T,M>::iterator SimpleCache<T,M>::find( const T& key ) 0223 { 0224 typename Map::iterator iter = _map.find( key ); 0225 if( iter != _map.end() ) promote( iter->first ); 0226 return iter; 0227 } 0228 0229 //______________________________________________________________________ 0230 template <typename T, typename M> 0231 const M& SimpleCache<T,M>::value( const T& key ) 0232 { 0233 typename Map::iterator iter = _map.find( key ); 0234 if( iter == _map.end() ) return _defaultValue; 0235 else { 0236 promote( iter->first ); 0237 return iter->second; 0238 } 0239 } 0240 0241 //______________________________________________________________________ 0242 template <typename T, typename M> 0243 void SimpleCache<T,M>::promote( const T& key ) 0244 {} 0245 0246 //______________________________________________________________________ 0247 template <typename T, typename M> 0248 void SimpleCache<T,M>::adjustSize( void ) 0249 { 0250 0251 while( _keys.size() > _maxSize ) 0252 { 0253 0254 // get last key in key list 0255 const Key* key( _keys.back() ); 0256 0257 // find matching item in map 0258 typename Map::iterator iter( _map.find( *key ) ); 0259 0260 // delete value 0261 erase( iter->second ); 0262 0263 // remove item from map 0264 _map.erase( iter ); 0265 0266 // remove key from key list 0267 _keys.pop_back(); 0268 0269 } 0270 0271 } 0272 0273 0274 //! simple "most recently used" stl based cache 0275 /*! 0276 an stl::map is used to keep the association between key and value. 0277 an stl::list is used to keep track of the most recently used values. 0278 the list contains pointers to the keys inserted in the map, to avoid 0279 unnecessary copy constructors. 0280 the 'erase' method is used to delete objects that are removed from the cache. 0281 By default, the erase method does nothing. It must be reimplemented to deal with 0282 non default Value deletion, when, for instance, the cache is used to store pointers 0283 */ 0284 template <typename T, typename M> 0285 class Cache: public SimpleCache<T,M> 0286 { 0287 0288 public: 0289 0290 0291 //! creator 0292 Cache( size_t size = 100, M defaultValue = M() ): 0293 SimpleCache<T,M>( size, defaultValue ) 0294 {} 0295 0296 protected: 0297 0298 //! promote key to front of the list 0299 virtual inline void promote( const T& ); 0300 0301 }; 0302 0303 //______________________________________________________________________ 0304 template <typename T, typename M> 0305 void Cache<T,M>::promote( const T& key ) 0306 { 0307 0308 if( (!SimpleCache<T,M>::keys().empty()) ) 0309 { 0310 0311 // do nothing if key is already up front 0312 if( SimpleCache<T,M>::keys().front() == &key ) return; 0313 0314 // erase key in list 0315 typename SimpleCache<T,M>::List::iterator iter( std::find( SimpleCache<T,M>::keys().begin(), SimpleCache<T,M>::keys().end(), &key ) ); 0316 SimpleCache<T,M>::keys().erase( iter ); 0317 0318 } 0319 0320 // (re) add key up front 0321 SimpleCache<T,M>::keys().push_front( &key ); 0322 0323 } 0324 0325 } 0326 0327 #endif