TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/host/memory/MemoryCache.cpp
Go to the documentation of this file.
00001 #include "MemoryCache.hpp"
00002 #include <tuttle/host/attribute/Image.hpp> // to know the function getReference()
00003 #include <tuttle/common/utils/global.hpp>
00004 #include <boost/foreach.hpp>
00005 
00006 #include <functional>
00007 
00008 namespace tuttle {
00009 namespace host {
00010 namespace memory {
00011 
00012 namespace  {
00013 
00014 /// Check if the cache element is kept in the cache, but is not required by someone else.
00015 bool isUnused( const CACHE_ELEMENT& cacheElement )
00016 {
00017     return cacheElement->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerHost ) < 1;
00018 }
00019 
00020 /// Functor to get the smallest unused element in cache
00021 struct UnusedDataFitSize : public std::unary_function<CACHE_ELEMENT*, void>
00022 {
00023         UnusedDataFitSize( std::size_t size )
00024                 : _sizeNeeded( size )
00025                 , _bestMatchDiff( ULONG_MAX )
00026                 , _pBestMatch()
00027         {}
00028 
00029         void operator()( const std::pair<Key, CACHE_ELEMENT>& pData )
00030         {
00031                 // used data
00032                 if( ! isUnused( pData.second ) )
00033                         return;
00034 
00035                 const std::size_t bufferSize = pData.second->getPoolData()->reservedSize();
00036 
00037                 // Check minimum amount of memory
00038                 if( _sizeNeeded > bufferSize )
00039                         return;
00040 
00041                 const std::size_t diff = bufferSize - _sizeNeeded;
00042                 if( diff >= _bestMatchDiff )
00043                         return;
00044                 _bestMatchDiff = diff;
00045                 _pBestMatch    = pData.second;
00046         }
00047 
00048         CACHE_ELEMENT bestMatch()
00049         {
00050                 return _pBestMatch;
00051         }
00052 
00053         private:
00054                 const std::size_t _sizeNeeded;
00055                 std::size_t _bestMatchDiff;
00056                 CACHE_ELEMENT _pBestMatch;
00057 };
00058 
00059 }
00060 
00061 MemoryCache& MemoryCache::operator=( const MemoryCache& cache )
00062 {
00063         if( &cache == this )
00064                 return *this;
00065         boost::mutex::scoped_lock lockerMap1( cache._mutexMap );
00066         boost::mutex::scoped_lock lockerMap2( _mutexMap );
00067         _map = cache._map;
00068         return *this;
00069 }
00070 
00071 void MemoryCache::put( const std::string& identifier, const double time, CACHE_ELEMENT pData )
00072 {
00073         boost::mutex::scoped_lock lockerMap( _mutexMap );
00074         _map[Key( identifier, time )] = pData;
00075 }
00076 
00077 CACHE_ELEMENT MemoryCache::get( const std::string& identifier, const double time ) const
00078 {
00079         boost::mutex::scoped_lock lockerMap( _mutexMap );
00080         MAP::const_iterator itr = _map.find( Key( identifier, time ) );
00081 
00082         if( itr == _map.end() )
00083                 return CACHE_ELEMENT();
00084         return itr->second;
00085 }
00086 
00087 CACHE_ELEMENT MemoryCache::get( const std::size_t& i ) const
00088 {
00089         boost::mutex::scoped_lock lockerMap( _mutexMap );
00090         MAP::const_iterator itr = _map.begin();
00091         for( unsigned int j = 0; j < i && itr != _map.end(); ++j )
00092                 ++itr;
00093 
00094         if( itr == _map.end() )
00095                 return CACHE_ELEMENT();
00096         return itr->second;
00097 }
00098 
00099 CACHE_ELEMENT MemoryCache::getUnusedWithSize( const std::size_t requestedSize ) const
00100 {
00101         boost::mutex::scoped_lock lockerMap( _mutexMap );
00102         return std::for_each( _map.begin(), _map.end(), UnusedDataFitSize( requestedSize ) ).bestMatch();
00103 }
00104 
00105 std::size_t MemoryCache::size() const
00106 {
00107         boost::mutex::scoped_lock lockerMap( _mutexMap );
00108         return _map.size();
00109 }
00110 
00111 bool MemoryCache::empty() const
00112 {
00113         boost::mutex::scoped_lock lockerMap( _mutexMap );
00114         return _map.empty();
00115 }
00116 
00117 bool MemoryCache::inCache( const CACHE_ELEMENT& pData ) const
00118 {
00119         boost::mutex::scoped_lock lockerMap( _mutexMap );
00120         return getIteratorForValue( pData ) != _map.end();
00121 }
00122 
00123 namespace {
00124 
00125 const std::string EMPTY_STRING = "";
00126 
00127 template<typename T>
00128 struct FindValuePredicate : public std::unary_function<typename T::value_type, bool>
00129 {
00130         const typename T::mapped_type & _value;
00131         FindValuePredicate( const typename T::mapped_type& value ) : _value( value ) {}
00132 
00133         bool operator()( const typename T::value_type& pair )
00134         {
00135                 return pair.second == _value;
00136         }
00137 
00138 };
00139 
00140 }
00141 
00142 MemoryCache::MAP::const_iterator MemoryCache::getIteratorForValue( const CACHE_ELEMENT& pData ) const
00143 {
00144         return std::find_if( _map.begin(), _map.end(), FindValuePredicate<MAP>( pData ) );
00145 }
00146 
00147 MemoryCache::MAP::iterator MemoryCache::getIteratorForValue( const CACHE_ELEMENT& pData )
00148 {
00149         return std::find_if( _map.begin(), _map.end(), FindValuePredicate<MAP>( pData ) );
00150 }
00151 
00152 double MemoryCache::getTime( const CACHE_ELEMENT& pData ) const
00153 {
00154         boost::mutex::scoped_lock lockerMap( _mutexMap );
00155         MAP::const_iterator itr = getIteratorForValue( pData );
00156 
00157         if( itr == _map.end() )
00158                 return 0;
00159         return itr->first._time;
00160 }
00161 
00162 const std::string& MemoryCache::getPluginName( const CACHE_ELEMENT& pData ) const
00163 {
00164         boost::mutex::scoped_lock lockerMap( _mutexMap );
00165         MAP::const_iterator itr = getIteratorForValue( pData );
00166 
00167         if( itr == _map.end() )
00168                 return EMPTY_STRING;
00169         return itr->first._identifier;
00170 }
00171 
00172 bool MemoryCache::remove( const CACHE_ELEMENT& pData )
00173 {
00174         boost::mutex::scoped_lock lockerMap( _mutexMap );
00175         const MAP::iterator itr = getIteratorForValue( pData );
00176 
00177         if( itr == _map.end() )
00178                 return false;
00179         _map.erase( itr );
00180         return true;
00181 }
00182 
00183 void MemoryCache::clearUnused()
00184 {
00185         boost::mutex::scoped_lock lockerMap( _mutexMap );
00186         for( MAP::iterator it = _map.begin(); it != _map.end(); )
00187         {
00188                 if( isUnused( it->second ) )
00189                 {
00190                         _map.erase( it++ ); // post-increment here, increments 'it' and returns a copy of the original 'it' to be used by erase()
00191                 }
00192                 else
00193                 {
00194                         ++it;
00195                 }
00196         }
00197 }
00198 
00199 void MemoryCache::clearAll()
00200 {
00201         TUTTLE_LOG_DEBUG( TUTTLE_TRACE, " - MEMORYCACHE::CLEARALL - " );
00202         boost::mutex::scoped_lock lockerMap( _mutexMap );
00203         _map.clear();
00204 }
00205 
00206 std::ostream& operator<<( std::ostream& os, const MemoryCache& v )
00207 {
00208         os << "[MemoryCache] size:" << v.size() << std::endl;
00209         BOOST_FOREACH( const MemoryCache::MAP::value_type& i, v._map )
00210         {
00211                 os  << "[MemoryCache] " << i.first
00212                         << " id:" << i.second->getId()
00213                         << " ref host:" << i.second->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerHost )
00214                         << " ref plugins:" << i.second->getReferenceCount( ofx::imageEffect::OfxhImage::eReferenceOwnerPlugin ) << std::endl;
00215         }
00216         return os;
00217 }
00218 
00219 }
00220 }
00221 }