#pragma once #include "Zeit.h" #include "HashMap.h" namespace Framework { enum class CacheCleanupStrategy { LONGEST_NOT_USED, OLDEST, RANDOM }; template struct CacheEntry { __int64 created; __int64 lastUsed; T value; }; template class CacheIterator { private: MapIterator> delegate; public: CacheIterator( MapIterator> delegate ) : delegate( delegate ) {} CacheIterator( const CacheIterator< K, T >& it ) { delegate = it.delegate; } CacheIterator< K, T >& operator=( CacheIterator< K, T > r ) { delegate = r.delegate; return *this; } bool hasNext() { return delegate.hasNext(); } MapEntry operator*() { return MapEntry( delegate.operator->().getKey(), delegate.operator->().getValue().value ); } CacheIterator< K, T > next() { return CacheIterator( delegate.next() ); } operator bool() { return delegate; } operator MapEntry() { return MapEntry( delegate->getKey(), delegate->getValue().value ); } CacheIterator< K, T >& operator++() //! prefix { ++delegate; return *this; } CacheIterator< K, T > operator++( int ) //! postfix { CacheIterator< K, T > temp( *this ); ++delegate; return temp; } MapEntry< K, T > operator->() { return MapEntry( delegate->getKey(), delegate->getValue().value ); } void set( MapEntry val ) { time_t zeit = time( 0 ); delegate.set( MapEntry>( val.getKey(), CacheEntry{ zeit, zeit, val.getValue() } ) ); } bool operator!=( CacheIterator< K, T >& r ) { return delegate != r.delegate; } }; template class Cache : public virtual ReferenceCounter { private: HashMap>* cache; CacheCleanupStrategy cleanup; int maxSize; void removeOneElement() { switch( cleanup ) { case CacheCleanupStrategy::LONGEST_NOT_USED: { K key; __int64 t = -1; for( MapEntry> e : *cache ) { if( t < 0 || t > e.getValue().lastUsed ) { t = e.getValue().lastUsed; key = e.getKey(); } } if( t >= 0 ) cache->remove( key ); break; } case CacheCleanupStrategy::OLDEST: { K key; __int64 t = -1; for( MapEntry> e : *cache ) { if( t < 0 || t > e.getValue().created ) { t = e.getValue().created; key = e.getKey(); } } if( t >= 0 ) cache->remove( key ); break; } case CacheCleanupStrategy::RANDOM: { int size = cache->getSize(); int index = (int)(((double)rand() / RAND_MAX) * size); auto it = cache->begin(); for( int i = 0; i < index; i++ ) ++it; cache->remove( it.operator->().getKey() ); break; } } } public: Cache( int size, std::function hash, CacheCleanupStrategy cleanup ) : ReferenceCounter(), cleanup( cleanup ), maxSize( size ) { cache = new HashMap>( size, hash ); } ~Cache() { cache->release(); } void put( K key, T value ) { time_t zeit = time( 0 ); if( cache->getSize() >= maxSize && !cache->has( key ) ) removeOneElement(); cache->put( key, { zeit, zeit, value } ); } void remove( K key ) { cache->remove( key ); } T get( K key ) const { CacheEntry entry = cache->get( key ); entry.lastUsed = time( 0 ); cache->put( key, entry ); return entry.value; } bool has( K key ) const { return cache->has( key ); } int getCurrentSize() const { return cache->getSize(); } int getMaxSize() const { return maxSize; } void reset() const { cache->leeren(); } CacheIterator begin() { return CacheIterator( cache->begin() ); } CacheIterator end() { return CacheIterator( cache->end() ); } }; }