diff --git a/include/loki/CachedFactory.h b/include/loki/CachedFactory.h index 4fcd0a9..ec20210 100644 --- a/include/loki/CachedFactory.h +++ b/include/loki/CachedFactory.h @@ -669,8 +669,9 @@ namespace Loki typedef typename Impl::Parm14 Parm14; typedef typename Impl::Parm15 Parm15; + public: typedef typename NP::ProductReturn ProductReturn; - + private: typedef Key< Impl, IdentifierType > Key; typedef std::map< Key, ObjVector > KeyToObjVectorMap; typedef std::map< AbstractProduct*, Key > FetchedObjToKeyMap; diff --git a/include/loki/SPCachedFactory.h b/include/loki/SPCachedFactory.h new file mode 100644 index 0000000..b175c0c --- /dev/null +++ b/include/loki/SPCachedFactory.h @@ -0,0 +1,169 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 SPCACHEDFACTORY_H_ +#define SPCACHEDFACTORY_H_ + +#include +#include +#include + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class FunctionStorage +/// +/// \ingroup SmartPointerStorageGroup +/// Implementation of the StoragePolicy used by SmartPtr +//////////////////////////////////////////////////////////////////////////////// + + template + class FunctionStorage + { + public: + typedef T* StoredType; // the type of the pointee_ object + typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. + typedef T* PointerType; // type returned by operator-> + typedef T& ReferenceType; // type returned by operator* + typedef Functor< void , Seq< void* > > FunctorType; // type of the Functor to set + + FunctionStorage() : pointee_(Default()), functor_() + {} + + // The storage policy doesn't initialize the stored pointer + // which will be initialized by the OwnershipPolicy's Clone fn + FunctionStorage(const FunctionStorage& rsh) : pointee_(0), functor_(rsh.functor_) + {} + + template + FunctionStorage(const FunctionStorage& rsh) : pointee_(0), functor_(rsh.functor_) + {} + + FunctionStorage(const StoredType& p) : pointee_(p), functor_() {} + + PointerType operator->() const { return pointee_; } + + ReferenceType operator*() const { return *pointee_; } + + void Swap(FunctionStorage& rhs) + { + std::swap(pointee_, rhs.pointee_); + std::swap(functor_, rhs.functor_); + } + + void SetCallBackFunction(const FunctorType &functor) + { + functor_ = functor; + } + + // Accessors + template + friend typename FunctionStorage::PointerType GetImpl(const FunctionStorage& sp); + + template + friend const typename FunctionStorage::StoredType& GetImplRef(const FunctionStorage& sp); + + template + friend typename FunctionStorage::StoredType& GetImplRef(FunctionStorage& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + void Destroy() + { + functor_(this); + } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + // Data + StoredType pointee_; + FunctorType functor_; + }; + + template + inline typename FunctionStorage::PointerType GetImpl(const FunctionStorage& sp) + { return sp.pointee_; } + + template + inline const typename FunctionStorage::StoredType& GetImplRef(const FunctionStorage& sp) + { return sp.pointee_; } + + template + inline typename FunctionStorage::StoredType& GetImplRef(FunctionStorage& sp) + { return sp.pointee_; } + + /** + * \class SmartPointer + * \ingroup EncapsulationPolicyCachedFactoryGroup + * \brief Encapsulate the object in a SmartPtr with FunctionStorage policy + * + * Encapsulate the object in a SmartPtr with FunctionStorage policy. + * The object will come back to the Cache as soon as the smartPtr leaves the scope. + */ + template + < + class AbstractProduct, + template class OwnershipPolicy = RefCounted, + class ConversionPolicy = DisallowConversion, + template class CheckingPolicy = AssertCheck, + template class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS + > + class SmartPointer + { + private: + typedef SmartPtr< AbstractProduct,OwnershipPolicy, + ConversionPolicy, CheckingPolicy, + FunctionStorage, ConstnessPolicy > CallBackSP; + protected: + typedef CallBackSP ProductReturn; + SmartPointer() : fun(this, &SmartPointer::smartPointerCallbackFunction) {} + virtual ~SmartPointer(){}; + + ProductReturn encapsulate(AbstractProduct* pProduct) + { + CallBackSP SP(pProduct); + SP.SetCallBackFunction(fun); + return SP; + } + + AbstractProduct* release(ProductReturn &pProduct) + { + return GetImpl(pProduct); + } + + const char* name(){return "smart pointer";} + + private: + void smartPointerCallbackFunction(void* pSP) + { + CallBackSP &SP(*reinterpret_cast(pSP)); + ReleaseObject(SP); + } + virtual void ReleaseObject(ProductReturn &object)=0; + const typename CallBackSP::FunctorType fun; + }; + +} // namespace Loki + +#endif /*SPCACHEDFACTORY_H_*/ diff --git a/test/CachedFactory/CachedFactoryTest.cpp b/test/CachedFactory/CachedFactoryTest.cpp index cd67e49..4b6328a 100644 --- a/test/CachedFactory/CachedFactoryTest.cpp +++ b/test/CachedFactory/CachedFactoryTest.cpp @@ -389,6 +389,31 @@ bool testCache() } } +#include + +bool testSmartPointer() +{ + typedef CachedFactory< AbstractProduct, int, NullType, SmartPointer, AlwaysCreate, EvictRandom, SimpleStatisticPolicy > CFactory; + CFactory factory; + factory.Register(0, createProductNull); + for(int i=0;i<500;++i) + { + CFactory::ProductReturn ptr(factory.CreateObject(0)); + CFactory::ProductReturn ptr2(ptr); // check that copying the SP won't release the object twice + } + // all object should have been returned to the factory + bool outOk = factory.getOut()==0; + // one object allocater + bool allocOk = factory.getAllocated()==1; + // one missed, the first one + bool missedOk = factory.getMissed()==1; + // 500 fetched + bool fetchedOk = factory.getFetched()==500; + // 499 hit + bool hitOk = factory.getHit()==499; + return outOk && allocOk && missedOk && fetchedOk && hitOk; +} + void dispText(const char* text) { cout << endl; @@ -443,7 +468,11 @@ void reliabilityTests() dispText("Test eviction error", "An eviction should occur (Creation Policy), but all object are in use"); bool evictionTest = dispResult("eviction error test result", testAllEvictionError()); separator(); - if(cacheResult&&rateLimitedResult&&amountLimitedResult&&evictionTest) + dispText("Smart pointer", "The factory provides smart pointers, when pointers go out of scope, the object returns to Cache"); + bool spTest = dispResult("Smart Pointer test result", testSmartPointer()); + separator(); + + if(cacheResult&&rateLimitedResult&&amountLimitedResult&&evictionTest&&spTest) dispText("All tests passed successfully"); else dispText("One or more test have failed");