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