diff options
Diffstat (limited to 'shared/loki/CachedFactory.h')
-rw-r--r-- | shared/loki/CachedFactory.h | 1167 |
1 files changed, 1167 insertions, 0 deletions
diff --git a/shared/loki/CachedFactory.h b/shared/loki/CachedFactory.h new file mode 100644 index 00000000..15c9a801 --- /dev/null +++ b/shared/loki/CachedFactory.h @@ -0,0 +1,1167 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 by Guillaume Chatelet +// +// Code covered by the MIT License +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_CACHEDFACTORY_INC_ +#define LOKI_CACHEDFACTORY_INC_ + +// $Id: CachedFactory.h 950 2009-01-26 19:45:54Z syntheticpp $ + +#include <functional> +#include <algorithm> +#include <iostream> +#include <vector> +#include <iterator> +#include <map> +#include <cassert> +#include <loki/Key.h> + +#ifdef DO_EXTRA_LOKI_TESTS + #define D( x ) x +#else + #define D( x ) ; +#endif + +#if defined(_MSC_VER) || defined(__CYGWIN__) +#include <time.h> +#endif + +/** + * \defgroup FactoriesGroup Factories + * \defgroup CachedFactoryGroup Cached Factory + * \ingroup FactoriesGroup + * \brief CachedFactory provides an extension of a Factory with caching + * support. + * + * Once used objects are returned to the CachedFactory that manages its + * destruction. + * If your code uses lots of "long to construct/destruct objects" using the + * CachedFactory will surely speedup the execution. + */ +namespace Loki +{ +/** + * \defgroup EncapsulationPolicyCachedFactoryGroup Encapsulation policies + * \ingroup CachedFactoryGroup + * \brief Defines how the object is returned to the client + */ + /** + * \class SimplePointer + * \ingroup EncapsulationPolicyCachedFactoryGroup + * \brief No encaspulation : returns the pointer + * + * This implementation does not make any encapsulation. + * It simply returns the object's pointer. + */ + template<class AbstractProduct> + class SimplePointer + { + protected: + typedef AbstractProduct* ProductReturn; + ProductReturn encapsulate(AbstractProduct* pProduct) + { + return pProduct; + } + + AbstractProduct* release(ProductReturn &pProduct) + { + AbstractProduct* pPointer(pProduct); + pProduct=NULL; + return pPointer; + } + const char* name(){return "pointer";} + }; + +/** + * \defgroup CreationPolicyCachedFactoryGroup Creation policies + * \ingroup CachedFactoryGroup + * \brief Defines a way to limit the creation operation. + * + * For instance one may want to be alerted (Exception) when + * - Cache has created a more than X object within the last x seconds + * - Cache creation rate has increased dramatically + * . + * which may result from bad caching strategy, or critical overload + */ + /** + * \class NeverCreate + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Never allows creation. Testing purposes only. + * + * Using this policy will throw an exception. + */ + class NeverCreate + { + protected: + struct Exception : public std::exception + { + const char* what() const throw() { return "NeverFetch Policy : No Fetching allowed"; } + }; + + bool canCreate() + { + throw Exception(); + } + + void onCreate(){} + void onDestroy(){} + const char* name(){return "never";} + }; + + /** + * \class AlwaysCreate + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Always allows creation. + * + * Doesn't limit the creation in any way + */ + class AlwaysCreate + { + protected: + bool canCreate() + { + return true; + } + + void onCreate(){} + void onDestroy(){} + const char* name(){return "always";} + }; + + + /** + * \class RateLimitedCreation + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Limit in rate. + * + * This implementation will prevent from Creating more than maxCreation objects + * within byTime ms by throwing an exception. + * Could be usefull to detect prevent loads (http connection for instance). + * Use the setRate method to set the rate parameters. + * default is 10 objects in a second. + */ + // !! CAUTION !! + // The std::clock() function is not quite precise + // under linux this policy might not work. + // TODO : get a better implementation (platform dependant) + class RateLimitedCreation + { + private: + typedef std::vector< clock_t > Vector; + Vector m_vTimes; + unsigned maxCreation; + clock_t timeValidity; + clock_t lastUpdate; + + void cleanVector() + { + using namespace std; + clock_t currentTime = clock(); + D( cout << "currentTime = " << currentTime<< endl; ) + D( cout << "currentTime - lastUpdate = " << currentTime - lastUpdate<< endl; ) + if(currentTime - lastUpdate > timeValidity) + { + m_vTimes.clear(); + D( cout << " is less than time validity " << timeValidity; ) + D( cout << " so clearing vector" << endl; ) + } + else + { + D( cout << "Cleaning time less than " << currentTime - timeValidity << endl; ) + D( displayVector(); ) + Vector::iterator newEnd = remove_if(m_vTimes.begin(), m_vTimes.end(), bind2nd(less<clock_t>(), currentTime - timeValidity)); + // this rearrangement might be costly, consider optimization + // by calling cleanVector in less used onCreate function + // ... although it may not be correct + m_vTimes.erase(newEnd, m_vTimes.end()); + D( displayVector(); ) + } + lastUpdate = currentTime; + } +#ifdef DO_EXTRA_LOKI_TESTS + void displayVector() + { + std::cout << "Vector : "; + copy(m_vTimes.begin(), m_vTimes.end(), std::ostream_iterator<clock_t>(std::cout, " ")); + std::cout << std::endl; + } +#endif + protected: + RateLimitedCreation() : maxCreation(10), timeValidity(CLOCKS_PER_SEC), lastUpdate(clock()) + {} + + struct Exception : public std::exception + { + const char* what() const throw() { return "RateLimitedCreation Policy : Exceeded the authorized creation rate"; } + }; + + bool canCreate() + { + cleanVector(); + if(m_vTimes.size()>maxCreation) + throw Exception(); + else + return true; + } + + void onCreate() + { + m_vTimes.push_back(clock()); + } + + void onDestroy() + { + } + const char* name(){return "rate limited";} + public: + // set the creation rate + // No more than maxCreation within byTime milliseconds + void setRate(unsigned maxCreation, unsigned byTime) + { + assert(byTime>0); + this->maxCreation = maxCreation; + this->timeValidity = static_cast<clock_t>(byTime * CLOCKS_PER_SEC / 1000); + D( std::cout << "Setting no more than "<< maxCreation <<" creation within " << this->timeValidity <<" ms"<< std::endl; ) + } + }; + + /** + * \class AmountLimitedCreation + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Limit by number of objects + * + * This implementation will prevent from Creating more than maxCreation objects + * within byTime ms by calling eviction policy. + * Use the setRate method to set the rate parameters. + * default is 10 objects. + */ + class AmountLimitedCreation + { + private: + unsigned maxCreation; + unsigned created; + + protected: + AmountLimitedCreation() : maxCreation(10), created(0) + {} + + bool canCreate() + { + return !(created>=maxCreation); + } + + void onCreate() + { + ++created; + } + + void onDestroy() + { + --created; + } + const char* name(){return "amount limited";} + public: + // set the creation max amount + void setMaxCreation(unsigned maxCreation) + { + assert(maxCreation>0); + this->maxCreation = maxCreation; + D( std::cout << "Setting no more than " << maxCreation <<" creation" << std::endl; ) + } + }; + +/** + * \defgroup EvictionPolicyCachedFactoryGroup Eviction policies + * \ingroup CachedFactoryGroup + * \brief Gathers informations about the stored objects and choose a + * candidate for eviction. + */ + + class EvictionException : public std::exception + { + public: + const char* what() const throw() { return "Eviction Policy : trying to make room but no objects are available"; } + }; + + // The following class is intented to provide helpers to sort + // the container that will hold an eviction score + template + < + typename ST, // Score type + typename DT // Data type + > + class EvictionHelper + { + protected: + typedef typename std::map< DT, ST > HitMap; + typedef typename HitMap::iterator HitMapItr; + private: + typedef std::pair< ST, DT > SwappedPair; + typedef std::multimap< ST, DT > SwappedHitMap; + typedef typename SwappedHitMap::iterator SwappedHitMapItr; + protected: + HitMap m_mHitCount; + + // This function sorts the map according to the score + // and returns the lower bound of the sorted container + DT& getLowerBound(){ + assert(!m_mHitCount.empty()); + // inserting the swapped pair into a multimap + SwappedHitMap copyMap; + for(HitMapItr itr = m_mHitCount.begin(); itr != m_mHitCount.end(); ++itr) + copyMap.insert(SwappedPair((*itr).second, (*itr).first)); + if((*copyMap.rbegin()).first == 0) // the higher score is 0 ... + throw EvictionException(); // there is no key evict + return (*copyMap.begin()).second; + } + }; + + /** + * \class EvictLRU + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief Evicts least accessed objects first. + * + * Implementation of the Least recent used algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + * + * WARNING : If an object is heavily fetched + * (more than ULONG_MAX = UINT_MAX = 4294967295U) + * it could unfortunately be removed from the cache. + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = unsigned // default data type to use as Score Type + > + class EvictLRU : public EvictionHelper< ST , DT > + { + private: + typedef EvictionHelper< ST , DT > EH; + protected: + + virtual ~EvictLRU(){} + + // OnStore initialize the counter for the new key + // If the key already exists, the counter is reseted + void onCreate(const DT& key) + { + EH::m_mHitCount[key] = 0; + } + + void onFetch(const DT&) + { + } + + // onRelease increments the hit counter associated with the object + void onRelease(const DT& key) + { + ++(EH::m_mHitCount[key]); + } + + void onDestroy(const DT& key) + { + EH::m_mHitCount.erase(key); + } + + // this function is implemented in Cache and redirected + // to the Storage Policy + virtual void remove(DT const key)=0; + + // LRU Eviction policy + void evict() + { + remove(EH::getLowerBound()); + } + const char* name(){return "LRU";} + }; + + /** + * \class EvictAging + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief LRU aware of the time span of use + * + * Implementation of the Aging algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + * + * This method is much more costly than evict LRU so + * if you need extreme performance consider switching to EvictLRU + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = unsigned // default data type to use as Score Type + > + class EvictAging : public EvictionHelper< ST, DT > + { + private: + EvictAging(const EvictAging&); + EvictAging& operator=(const EvictAging&); + typedef EvictionHelper< ST, DT > EH; + typedef typename EH::HitMap HitMap; + typedef typename EH::HitMapItr HitMapItr; + + // update the counter + template<class T> struct updateCounter : public std::unary_function<T, void> + { + updateCounter(const DT& key): key_(key){} + void operator()(T x) + { + x.second = (x.first == key_ ? (x.second >> 1) | ( 1 << ((sizeof(ST)-1)*8) ) : x.second >> 1); + D( std::cout << x.second << std::endl; ) + } + const DT &key_; + updateCounter(const updateCounter& rhs) : key_(rhs.key_){} + private: + updateCounter& operator=(const updateCounter& rhs); + }; + protected: + EvictAging(){} + virtual ~EvictAging(){} + + // OnStore initialize the counter for the new key + // If the key already exists, the counter is reseted + void onCreate(const DT& key){ + EH::m_mHitCount[key] = 0; + } + + void onFetch(const DT&){} + + // onRelease increments the hit counter associated with the object + // Updating every counters by iterating over the map + // If the key is the key of the fetched object : + // the counter is shifted to the right and it's MSB is set to 1 + // else + // the counter is shifted to the left + void onRelease(const DT& key) + { + std::for_each(EH::m_mHitCount.begin(), EH::m_mHitCount.end(), updateCounter< typename HitMap::value_type >(key)); + } + + void onDestroy(const DT& key) + { + EH::m_mHitCount.erase(key); + } + + // this function is implemented in Cache and redirected + // to the Storage Policy + virtual void remove(DT const key)=0; + + // LRU with Aging Eviction policy + void evict() + { + remove(EH::getLowerBound()); + } + const char* name(){return "LRU with aging";} + }; + + /** + * \class EvictRandom + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief Evicts a random object + * + * Implementation of the Random algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = void // Score Type not used by this policy + > + class EvictRandom + { + private: + std::vector< DT > m_vKeys; + typedef typename std::vector< DT >::size_type size_type; + typedef typename std::vector< DT >::iterator iterator; + + protected: + + virtual ~EvictRandom(){} + + void onCreate(const DT&){ + } + + void onFetch(const DT& ){ + } + + void onRelease(const DT& key){ + m_vKeys.push_back(key); + } + + void onDestroy(const DT& key){ + using namespace std; + m_vKeys.erase(remove_if(m_vKeys.begin(), m_vKeys.end(), bind2nd(equal_to< DT >(), key)), m_vKeys.end()); + } + + // Implemented in Cache and redirected to the Storage Policy + virtual void remove(DT const key)=0; + + // Random Eviction policy + void evict() + { + if(m_vKeys.empty()) + throw EvictionException(); + size_type random = static_cast<size_type>((m_vKeys.size()*rand())/(static_cast<size_type>(RAND_MAX) + 1)); + remove(*(m_vKeys.begin()+random)); + } + const char* name(){return "random";} + }; + +/** + * \defgroup StatisticPolicyCachedFactoryGroup Statistic policies + * \ingroup CachedFactoryGroup + * \brief Gathers information about the cache. + * + * For debugging purpose this policy proposes to gather informations + * about the cache. This could be useful to determine whether the cache is + * mandatory or if the policies are well suited to the application. + */ + /** + * \class NoStatisticPolicy + * \ingroup StatisticPolicyCachedFactoryGroup + * \brief Do nothing + * + * Should be used in release code for better performances + */ + class NoStatisticPolicy + { + protected: + void onDebug(){} + void onFetch(){} + void onRelease(){} + void onCreate(){} + void onDestroy(){} + const char* name(){return "no";} + }; + + /** + * \class SimpleStatisticPolicy + * \ingroup StatisticPolicyCachedFactoryGroup + * \brief Simple statistics + * + * Provides the following informations about the cache : + * - Created objects + * - Fetched objects + * - Destroyed objects + * - Cache hit + * - Cache miss + * - Currently allocated + * - Currently out + * - Cache overall efficiency + */ + class SimpleStatisticPolicy + { + private: + unsigned allocated, created, hit, out, fetched; + protected: + SimpleStatisticPolicy() : allocated(0), created(0), hit(0), out(0), fetched(0) + { + } + + void onDebug() + { + using namespace std; + cout << "############################" << endl; + cout << "## About this cache " << this << endl; + cout << "## + Created objects : " << created << endl; + cout << "## + Fetched objects : " << fetched << endl; + cout << "## + Destroyed objects : " << created - allocated << endl; + cout << "## + Cache hit : " << hit << endl; + cout << "## + Cache miss : " << fetched - hit << endl; + cout << "## + Currently allocated : " << allocated << endl; + cout << "## + Currently out : " << out << endl; + cout << "############################" << endl; + if(fetched!=0){ + cout << "## Overall efficiency " << 100*double(hit)/fetched <<"%"<< endl; + cout << "############################" << endl; + } + cout << endl; + } + + void onFetch() + { + ++fetched; + ++out; + ++hit; + } + void onRelease() + { + --out; + } + void onCreate() + { + ++created; + ++allocated; + --hit; + } + void onDestroy() + { + --allocated; + } + + const char* name(){return "simple";} + public: + unsigned getCreated(){return created;} + unsigned getFetched(){return fetched;} + unsigned getHit(){return hit;} + unsigned getMissed(){return fetched - hit;} + unsigned getAllocated(){return allocated;} + unsigned getOut(){return out;} + unsigned getDestroyed(){return created-allocated;} + }; + + /////////////////////////////////////////////////////////////////////////// + // Cache Factory definition + /////////////////////////////////////////////////////////////////////////// + class CacheException : public std::exception + { + public: + const char* what() const throw() { return "Internal Cache Error"; } + }; + + /** + * \class CachedFactory + * \ingroup CachedFactoryGroup + * \brief Factory with caching support + * + * This class acts as a Factory (it creates objects) + * but also keeps the already created objects to prevent + * long constructions time. + * + * Note this implementation do not retain ownership. + */ + template + < + class AbstractProduct, + typename IdentifierType, + typename CreatorParmTList = NullType, + template<class> class EncapsulationPolicy = SimplePointer, + class CreationPolicy = AlwaysCreate, + template <typename , typename> class EvictionPolicy = EvictRandom, + class StatisticPolicy = NoStatisticPolicy, + template<typename, class> class FactoryErrorPolicy = DefaultFactoryError, + class ObjVector = std::vector<AbstractProduct*> + > + class CachedFactory : + protected EncapsulationPolicy<AbstractProduct>, + public CreationPolicy, public StatisticPolicy, EvictionPolicy< AbstractProduct * , unsigned > + { + private: + typedef Factory< AbstractProduct, IdentifierType, CreatorParmTList, FactoryErrorPolicy> MyFactory; + typedef FactoryImpl< AbstractProduct, IdentifierType, CreatorParmTList > Impl; + typedef Functor< AbstractProduct* , CreatorParmTList > ProductCreator; + typedef EncapsulationPolicy<AbstractProduct> NP; + typedef CreationPolicy CP; + typedef StatisticPolicy SP; + typedef EvictionPolicy< AbstractProduct* , unsigned > EP; + + typedef typename Impl::Parm1 Parm1; + typedef typename Impl::Parm2 Parm2; + typedef typename Impl::Parm3 Parm3; + typedef typename Impl::Parm4 Parm4; + typedef typename Impl::Parm5 Parm5; + typedef typename Impl::Parm6 Parm6; + typedef typename Impl::Parm7 Parm7; + typedef typename Impl::Parm8 Parm8; + typedef typename Impl::Parm9 Parm9; + typedef typename Impl::Parm10 Parm10; + typedef typename Impl::Parm11 Parm11; + typedef typename Impl::Parm12 Parm12; + typedef typename Impl::Parm13 Parm13; + typedef typename Impl::Parm14 Parm14; + typedef typename Impl::Parm15 Parm15; + + public: + typedef typename NP::ProductReturn ProductReturn; + private: + typedef Key< Impl, IdentifierType > MyKey; + typedef std::map< MyKey, ObjVector > KeyToObjVectorMap; + typedef std::map< AbstractProduct*, MyKey > FetchedObjToKeyMap; + + MyFactory factory; + KeyToObjVectorMap fromKeyToObjVector; + FetchedObjToKeyMap providedObjects; + unsigned outObjects; + + ObjVector& getContainerFromKey(MyKey key){ + return fromKeyToObjVector[key]; + } + + AbstractProduct* const getPointerToObjectInContainer(ObjVector &entry) + { + if(entry.empty()) // No object available + { // the object will be created in the calling function. + // It has to be created in the calling function because of + // the variable number of parameters for CreateObject(...) method + return NULL; + } + else + { // returning the found object + AbstractProduct* pObject(entry.back()); + assert(pObject!=NULL); + entry.pop_back(); + return pObject; + } + } + + bool shouldCreateObject(AbstractProduct * const pProduct){ + if(pProduct!=NULL) // object already exists + return false; + if(CP::canCreate()==false) // Are we allowed to Create ? + EP::evict(); // calling Eviction Policy to clean up + return true; + } + + void ReleaseObjectFromContainer(ObjVector &entry, AbstractProduct * const object) + { + entry.push_back(object); + } + + void onFetch(AbstractProduct * const pProduct) + { + SP::onFetch(); + EP::onFetch(pProduct); + ++outObjects; + } + + void onRelease(AbstractProduct * const pProduct) + { + SP::onRelease(); + EP::onRelease(pProduct); + --outObjects; + } + + void onCreate(AbstractProduct * const pProduct) + { + CP::onCreate(); + SP::onCreate(); + EP::onCreate(pProduct); + } + + void onDestroy(AbstractProduct * const pProduct) + { + CP::onDestroy(); + SP::onDestroy(); + EP::onDestroy(pProduct); + } + + // delete the object + template<class T> struct deleteObject : public std::unary_function<T, void> + { + void operator()(T x){ delete x; } + }; + + // delete the objects in the vector + template<class T> struct deleteVectorObjects : public std::unary_function<T, void> + { + void operator()(T x){ + ObjVector &vec(x.second); + std::for_each(vec.begin(), vec.end(), deleteObject< typename ObjVector::value_type>()); + } + }; + + // delete the keys of the map + template<class T> struct deleteMapKeys : public std::unary_function<T, void> + { + void operator()(T x){ delete x.first; } + }; + + protected: + virtual void remove(AbstractProduct * const pProduct) + { + typename FetchedObjToKeyMap::iterator fetchedItr = providedObjects.find(pProduct); + if(fetchedItr!=providedObjects.end()) // object is unreleased. + throw CacheException(); + bool productRemoved = false; + typename KeyToObjVectorMap::iterator objVectorItr; + typename ObjVector::iterator objItr; + for(objVectorItr=fromKeyToObjVector.begin();objVectorItr!=fromKeyToObjVector.end();++objVectorItr) + { + ObjVector &v((*objVectorItr).second); + objItr = remove_if(v.begin(), v.end(), std::bind2nd(std::equal_to<AbstractProduct*>(), pProduct)); + if(objItr != v.end()) // we found the vector containing pProduct and removed it + { + onDestroy(pProduct); // warning policies we are about to destroy an object + v.erase(objItr, v.end()); // real removing + productRemoved = true; + break; + } + } + if(productRemoved==false) + throw CacheException(); // the product is not in the cache ?! + delete pProduct; // deleting it + } + + public: + CachedFactory() : factory(), fromKeyToObjVector(), providedObjects(), outObjects(0) + { + } + + ~CachedFactory() + { + using namespace std; + // debug information + SP::onDebug(); + // cleaning the Cache + for_each(fromKeyToObjVector.begin(), fromKeyToObjVector.end(), + deleteVectorObjects< typename KeyToObjVectorMap::value_type >() + ); + if(!providedObjects.empty()) + { + // The factory is responsible for the creation and destruction of objects. + // If objects are out during the destruction of the Factory : deleting anyway. + // This might not be a good idea. But throwing an exception in a destructor is + // considered as a bad pratice and asserting might be too much. + // What to do ? Leaking memory or corrupting in use pointers ? hmm... + D( cout << "====>> Cache destructor : deleting "<< providedObjects.size()<<" in use objects <<====" << endl << endl; ) + for_each(providedObjects.begin(), providedObjects.end(), + deleteMapKeys< typename FetchedObjToKeyMap::value_type >() + ); + } + } + + /////////////////////////////////// + // Acts as the proxy pattern and // + // forwards factory methods // + /////////////////////////////////// + + bool Register(const IdentifierType& id, ProductCreator creator) + { + return factory.Register(id, creator); + } + + template <class PtrObj, typename CreaFn> + bool Register(const IdentifierType& id, const PtrObj& p, CreaFn fn) + { + return factory.Register(id, p, fn); + } + + bool Unregister(const IdentifierType& id) + { + return factory.Unregister(id); + } + + /// Return the registered ID in this Factory + std::vector<IdentifierType>& RegisteredIds() + { + return factory.RegisteredIds(); + } + + ProductReturn CreateObject(const IdentifierType& id) + { + MyKey key(id); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1) + { + MyKey key(id,p1); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2) + { + MyKey key(id,p1,p2); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3) + { + MyKey key(id,p1,p2,p3); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { + MyKey key(id,p1,p2,p3,p4); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { + MyKey key(id,p1,p2,p3,p4,p5); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { + MyKey key(id,p1,p2,p3,p4,p5,p6); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7 ) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9,Parm10 p10) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13,key.p14); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13,key.p14,key.p15); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + /// Use this function to release the object + /** + * if execution brakes in this function then you tried + * to release an object that wasn't provided by this Cache + * ... which is bad :-) + */ + void ReleaseObject(ProductReturn &object) + { + AbstractProduct* pProduct(NP::release(object)); + typename FetchedObjToKeyMap::iterator itr = providedObjects.find(pProduct); + if(itr == providedObjects.end()) + throw CacheException(); + onRelease(pProduct); + ReleaseObjectFromContainer(getContainerFromKey((*itr).second), pProduct); + providedObjects.erase(itr); + } + + /// display the cache configuration + void displayCacheType() + { + using namespace std; + cout << "############################" << endl; + cout << "## Cache configuration" << endl; + cout << "## + Encapsulation " << NP::name() << endl; + cout << "## + Creating " << CP::name() << endl; + cout << "## + Eviction " << EP::name() << endl; + cout << "## + Statistics " << SP::name() << endl; + cout << "############################" << endl; + } + }; +} // namespace Loki + +#endif // end file guardian + |