From 9a2a524f1e311853d08050be2dcdddc09ac7759a Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:01:29 +0200 Subject: 3.0 --- shared/loki/AbstractFactory.h | 185 +++ shared/loki/Allocator.h | 153 +++ shared/loki/AssocVector.h | 358 ++++++ shared/loki/CachedFactory.h | 1167 +++++++++++++++++++ shared/loki/CheckReturn.h | 165 +++ shared/loki/Checker.h | 516 +++++++++ shared/loki/ConstPolicy.h | 61 + shared/loki/DataGenerators.h | 113 ++ shared/loki/EmptyType.h | 49 + shared/loki/Factory.h | 1084 ++++++++++++++++++ shared/loki/Function.h | 373 +++++++ shared/loki/Functor.h | 1789 +++++++++++++++++++++++++++++ shared/loki/HierarchyGenerators.h | 291 +++++ shared/loki/Key.h | 764 +++++++++++++ shared/loki/LevelMutex.h | 1211 ++++++++++++++++++++ shared/loki/LockingPtr.h | 110 ++ shared/loki/LokiExport.h | 69 ++ shared/loki/LokiTypeInfo.h | 103 ++ shared/loki/MultiMethods.h | 415 +++++++ shared/loki/NullType.h | 34 + shared/loki/OrderedStatic.h | 225 ++++ shared/loki/Pimpl.h | 198 ++++ shared/loki/RefToValue.h | 70 ++ shared/loki/Register.h | 134 +++ shared/loki/SPCachedFactory.h | 204 ++++ shared/loki/SafeBits.h | 514 +++++++++ shared/loki/SafeFormat.h | 590 ++++++++++ shared/loki/ScopeGuard.h | 666 +++++++++++ shared/loki/Sequence.h | 49 + shared/loki/Singleton.h | 889 +++++++++++++++ shared/loki/SmallObj.cpp | 1226 ++++++++++++++++++++ shared/loki/SmallObj.h | 644 +++++++++++ shared/loki/SmartPtr.h | 1778 +++++++++++++++++++++++++++++ shared/loki/StrongPtr.h | 1697 ++++++++++++++++++++++++++++ shared/loki/Threads.h | 609 ++++++++++ shared/loki/Tuple.h | 22 + shared/loki/TypeManip.h | 284 +++++ shared/loki/TypeTraits.h | 2228 +++++++++++++++++++++++++++++++++++++ shared/loki/Typelist.h | 459 ++++++++ shared/loki/TypelistMacros.h | 353 ++++++ shared/loki/Visitor.h | 355 ++++++ shared/loki/readme.txt | 12 + shared/loki/static_check.h | 45 + 43 files changed, 22261 insertions(+) create mode 100644 shared/loki/AbstractFactory.h create mode 100644 shared/loki/Allocator.h create mode 100644 shared/loki/AssocVector.h create mode 100644 shared/loki/CachedFactory.h create mode 100644 shared/loki/CheckReturn.h create mode 100644 shared/loki/Checker.h create mode 100644 shared/loki/ConstPolicy.h create mode 100644 shared/loki/DataGenerators.h create mode 100644 shared/loki/EmptyType.h create mode 100644 shared/loki/Factory.h create mode 100644 shared/loki/Function.h create mode 100644 shared/loki/Functor.h create mode 100644 shared/loki/HierarchyGenerators.h create mode 100644 shared/loki/Key.h create mode 100644 shared/loki/LevelMutex.h create mode 100644 shared/loki/LockingPtr.h create mode 100644 shared/loki/LokiExport.h create mode 100644 shared/loki/LokiTypeInfo.h create mode 100644 shared/loki/MultiMethods.h create mode 100644 shared/loki/NullType.h create mode 100644 shared/loki/OrderedStatic.h create mode 100644 shared/loki/Pimpl.h create mode 100644 shared/loki/RefToValue.h create mode 100644 shared/loki/Register.h create mode 100644 shared/loki/SPCachedFactory.h create mode 100644 shared/loki/SafeBits.h create mode 100644 shared/loki/SafeFormat.h create mode 100644 shared/loki/ScopeGuard.h create mode 100644 shared/loki/Sequence.h create mode 100644 shared/loki/Singleton.h create mode 100644 shared/loki/SmallObj.cpp create mode 100644 shared/loki/SmallObj.h create mode 100644 shared/loki/SmartPtr.h create mode 100644 shared/loki/StrongPtr.h create mode 100644 shared/loki/Threads.h create mode 100644 shared/loki/Tuple.h create mode 100644 shared/loki/TypeManip.h create mode 100644 shared/loki/TypeTraits.h create mode 100644 shared/loki/Typelist.h create mode 100644 shared/loki/TypelistMacros.h create mode 100644 shared/loki/Visitor.h create mode 100644 shared/loki/readme.txt create mode 100644 shared/loki/static_check.h (limited to 'shared/loki') diff --git a/shared/loki/AbstractFactory.h b/shared/loki/AbstractFactory.h new file mode 100644 index 00000000..8ff518dc --- /dev/null +++ b/shared/loki/AbstractFactory.h @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// 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 author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ABSTRACTFACTORY_INC_ +#define LOKI_ABSTRACTFACTORY_INC_ + +// $Id: AbstractFactory.h 771 2006-10-27 18:05:03Z clitte_bbt $ + + +#include "Typelist.h" +#include "Sequence.h" +#include "TypeManip.h" +#include "HierarchyGenerators.h" + +#include + +/** + * \defgroup FactoriesGroup Factories + * \defgroup AbstractFactoryGroup Abstract Factory + * \ingroup FactoriesGroup + * \brief Implements an abstract object factory. + */ + +/** + * \class AbstractFactory + * \ingroup AbstractFactoryGroup + * \brief Implements an abstract object factory. + */ + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +// class template AbstractFactoryUnit +// The building block of an Abstract Factory +//////////////////////////////////////////////////////////////////////////////// + + template + class AbstractFactoryUnit + { + public: + virtual T* DoCreate(Type2Type) = 0; + virtual ~AbstractFactoryUnit() {} + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template AbstractFactory +// Defines an Abstract Factory interface starting from a typelist +//////////////////////////////////////////////////////////////////////////////// + + template + < + class TList, + template class Unit = AbstractFactoryUnit + > + class AbstractFactory : public GenScatterHierarchy + { + public: + typedef TList ProductList; + + template T* Create() + { + Unit& unit = *this; + return unit.DoCreate(Type2Type()); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template OpNewFactoryUnit +// Creates an object by invoking the new operator +//////////////////////////////////////////////////////////////////////////////// + + template + class OpNewFactoryUnit : public Base + { + typedef typename Base::ProductList BaseProductList; + + protected: + typedef typename BaseProductList::Tail ProductList; + + public: + typedef typename BaseProductList::Head AbstractProduct; + ConcreteProduct* DoCreate(Type2Type) + { + return new ConcreteProduct; + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template PrototypeFactoryUnit +// Creates an object by cloning a prototype +// There is a difference between the implementation herein and the one described +// in the book: GetPrototype and SetPrototype use the helper friend +// functions DoGetPrototype and DoSetPrototype. The friend functions avoid +// name hiding issues. Plus, GetPrototype takes a reference to pointer +// instead of returning the pointer by value. +//////////////////////////////////////////////////////////////////////////////// + + template + class PrototypeFactoryUnit : public Base + { + typedef typename Base::ProductList BaseProductList; + + protected: + typedef typename BaseProductList::Tail ProductList; + + public: + typedef typename BaseProductList::Head AbstractProduct; + + PrototypeFactoryUnit(AbstractProduct* p = 0) + : pPrototype_(p) + {} + + template + friend void DoGetPrototype(const PrototypeFactoryUnit& me, + typename Base1::ProductList::Head*& pPrototype); + + template + friend void DoSetPrototype(PrototypeFactoryUnit& me, + typename Base1::ProductList::Head* pObj); + + template + void GetPrototype(U*& p) + { return DoGetPrototype(*this, p); } + + template + void SetPrototype(U* pObj) + { DoSetPrototype(*this, pObj); } + + AbstractProduct* DoCreate(Type2Type) + { + assert(pPrototype_); + return pPrototype_->Clone(); + } + + private: + AbstractProduct* pPrototype_; + }; + + template + inline void DoGetPrototype(const PrototypeFactoryUnit& me, + typename Base::ProductList::Head*& pPrototype) + { pPrototype = me.pPrototype_; } + + template + inline void DoSetPrototype(PrototypeFactoryUnit& me, + typename Base::ProductList::Head* pObj) + { me.pPrototype_ = pObj; } + +//////////////////////////////////////////////////////////////////////////////// +// class template ConcreteFactory +// Implements an AbstractFactory interface +//////////////////////////////////////////////////////////////////////////////// + + template + < + class AbstractFact, + template class Creator = OpNewFactoryUnit, + class TList = typename AbstractFact::ProductList + > + class ConcreteFactory + : public GenLinearHierarchy< + typename TL::Reverse::Result, Creator, AbstractFact> + { + public: + typedef typename AbstractFact::ProductList ProductList; + typedef TList ConcreteProductList; + }; + +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/Allocator.h b/shared/loki/Allocator.h new file mode 100644 index 00000000..a79ee061 --- /dev/null +++ b/shared/loki/Allocator.h @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2008 by Rich Sposato +// +// 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 author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_ALLOCATOR_HPP_INCLUDED +#define LOKI_ALLOCATOR_HPP_INCLUDED + +// $Id: Allocator.h 896 2008-08-08 22:20:05Z syntheticpp $ + +// Requires project to be compiled with loki/src/SmallObj.cpp and loki/src/Singleton.cpp + +#include + + +namespace Loki +{ + + +//----------------------------------------------------------------------------- + +/** @class LokiAllocator + Adapts Loki's Small-Object Allocator for STL container classes. + This class provides all the functionality required for STL allocators, but + uses Loki's Small-Object Allocator to perform actual memory operations. + Implementation comes from a post in Loki forums (by Rasmus Ekman?). + */ +template +< + typename Type, + typename AllocT = Loki::AllocatorSingleton<> +> +class LokiAllocator +{ +public: + + typedef ::std::size_t size_type; + typedef ::std::ptrdiff_t difference_type; + typedef Type * pointer; + typedef const Type * const_pointer; + typedef Type & reference; + typedef const Type & const_reference; + typedef Type value_type; + + /// Default constructor does nothing. + inline LokiAllocator( void ) throw() { } + + /// Copy constructor does nothing. + inline LokiAllocator( const LokiAllocator & ) throw() { } + + /// Type converting allocator constructor does nothing. + template < typename Type1 > + inline LokiAllocator( const LokiAllocator< Type1 > & ) throw() { } + + /// Destructor does nothing. + inline ~LokiAllocator() throw() { } + + /// Convert an allocator to an allocator . + template < typename Type1 > + struct rebind + { + typedef LokiAllocator< Type1 > other; + }; + + /// Return address of reference to mutable element. + pointer address( reference elem ) const { return &elem; } + + /// Return address of reference to const element. + const_pointer address( const_reference elem ) const { return &elem; } + + /** Allocate an array of count elements. Warning! The true parameter in + the call to Allocate means this function can throw exceptions. This is + better than not throwing, and returning a null pointer in case the caller + assumes the return value is not null. + @param count # of elements in array. + @param hint Place where caller thinks allocation should occur. + @return Pointer to block of memory. + */ + pointer allocate( size_type count, const void * hint = 0 ) + { + (void)hint; // Ignore the hint. + void * p = AllocT::Instance().Allocate( count * sizeof( Type ), true ); + return reinterpret_cast< pointer >( p ); + } + + /// Ask allocator to release memory at pointer with size bytes. + void deallocate( pointer p, size_type size ) + { + AllocT::Instance().Deallocate( p, size * sizeof( Type ) ); + } + + /// Calculate max # of elements allocator can handle. + size_type max_size( void ) const throw() + { + // A good optimizer will see these calculations always produce the same + // value and optimize this function away completely. + const size_type max_bytes = size_type( -1 ); + const size_type bytes = max_bytes / sizeof( Type ); + return bytes; + } + + /// Construct an element at the pointer. + void construct( pointer p, const Type & value ) + { + // A call to global placement new forces a call to copy constructor. + ::new( p ) Type( value ); + } + + /// Destruct the object at pointer. + void destroy( pointer p ) + { + // If the Type has no destructor, then some compilers complain about + // an unreferenced parameter, so use the void cast trick to prevent + // spurious warnings. + (void)p; + p->~Type(); + } + +}; + +//----------------------------------------------------------------------------- + +/** All equality operators return true since LokiAllocator is basically a + monostate design pattern, so all instances of it are identical. + */ +template < typename Type > +inline bool operator == ( const LokiAllocator< Type > &, const LokiAllocator< Type > & ) +{ + return true; +} + +/** All inequality operators return false since LokiAllocator is basically a + monostate design pattern, so all instances of it are identical. + */ +template < typename Type > +inline bool operator != ( const LokiAllocator< Type > & , const LokiAllocator< Type > & ) +{ + return false; +} + +//----------------------------------------------------------------------------- + +} // namespace Loki + +#endif // LOKI_ALLOCATOR_INCLUDED diff --git a/shared/loki/AssocVector.h b/shared/loki/AssocVector.h new file mode 100644 index 00000000..905e0963 --- /dev/null +++ b/shared/loki/AssocVector.h @@ -0,0 +1,358 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// 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 author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ASSOCVECTOR_INC_ +#define LOKI_ASSOCVECTOR_INC_ + +// $Id: AssocVector.h 765 2006-10-18 13:55:32Z syntheticpp $ + + +#include +#include +#include +#include + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVectorCompare +// Used by AssocVector +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template + class AssocVectorCompare : public C + { + typedef std::pair + Data; + typedef typename C::first_argument_type first_argument_type; + + public: + AssocVectorCompare() + {} + + AssocVectorCompare(const C& src) : C(src) + {} + + bool operator()(const first_argument_type& lhs, + const first_argument_type& rhs) const + { return C::operator()(lhs, rhs); } + + bool operator()(const Data& lhs, const Data& rhs) const + { return operator()(lhs.first, rhs.first); } + + bool operator()(const Data& lhs, + const first_argument_type& rhs) const + { return operator()(lhs.first, rhs); } + + bool operator()(const first_argument_type& lhs, + const Data& rhs) const + { return operator()(lhs, rhs.first); } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVector +// An associative vector built as a syntactic drop-in replacement for std::map +// BEWARE: AssocVector doesn't respect all map's guarantees, the most important +// being: +// * iterators are invalidated by insert and erase operations +// * the complexity of insert/erase is O(N) not O(log N) +// * value_type is std::pair not std::pair +// * iterators are random +//////////////////////////////////////////////////////////////////////////////// + + + template + < + class K, + class V, + class C = std::less, + class A = std::allocator< std::pair > + > + class AssocVector + : private std::vector< std::pair, A > + , private Private::AssocVectorCompare + { + typedef std::vector, A> Base; + typedef Private::AssocVectorCompare MyCompare; + + public: + typedef K key_type; + typedef V mapped_type; + typedef typename Base::value_type value_type; + + typedef C key_compare; + typedef A allocator_type; + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename Base::reverse_iterator reverse_iterator; + typedef typename Base::const_reverse_iterator const_reverse_iterator; + + class value_compare + : public std::binary_function + , private key_compare + { + friend class AssocVector; + + protected: + value_compare(key_compare pred) : key_compare(pred) + {} + + public: + bool operator()(const value_type& lhs, const value_type& rhs) const + { return key_compare::operator()(lhs.first, rhs.first); } + }; + + // 23.3.1.1 construct/copy/destroy + + explicit AssocVector(const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base(alloc), MyCompare(comp) + {} + + template + AssocVector(InputIterator first, InputIterator last, + const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base(first, last, alloc), MyCompare(comp) + { + MyCompare& me = *this; + std::sort(begin(), end(), me); + } + + AssocVector& operator=(const AssocVector& rhs) + { + AssocVector(rhs).swap(*this); + return *this; + } + + // iterators: + // The following are here because MWCW gets 'using' wrong + iterator begin() { return Base::begin(); } + const_iterator begin() const { return Base::begin(); } + iterator end() { return Base::end(); } + const_iterator end() const { return Base::end(); } + reverse_iterator rbegin() { return Base::rbegin(); } + const_reverse_iterator rbegin() const { return Base::rbegin(); } + reverse_iterator rend() { return Base::rend(); } + const_reverse_iterator rend() const { return Base::rend(); } + + // capacity: + bool empty() const { return Base::empty(); } + size_type size() const { return Base::size(); } + size_type max_size() { return Base::max_size(); } + + // 23.3.1.2 element access: + mapped_type& operator[](const key_type& key) + { return insert(value_type(key, mapped_type())).first->second; } + + // modifiers: + std::pair insert(const value_type& val) + { + bool found(true); + iterator i(lower_bound(val.first)); + + if (i == end() || this->operator()(val.first, i->first)) + { + i = Base::insert(i, val); + found = false; + } + return std::make_pair(i, !found); + } + //Section [23.1.2], Table 69 + //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4 + iterator insert(iterator pos, const value_type& val) + { + if( (pos == begin() || this->operator()(*(pos-1),val)) && + (pos == end() || this->operator()(val, *pos)) ) + { + return Base::insert(pos, val); + } + return insert(val).first; + } + + template + void insert(InputIterator first, InputIterator last) + { for (; first != last; ++first) insert(*first); } + + void erase(iterator pos) + { Base::erase(pos); } + + size_type erase(const key_type& k) + { + iterator i(find(k)); + if (i == end()) return 0; + erase(i); + return 1; + } + + void erase(iterator first, iterator last) + { Base::erase(first, last); } + + void swap(AssocVector& other) + { + Base::swap(other); + MyCompare& me = *this; + MyCompare& rhs = other; + std::swap(me, rhs); + } + + void clear() + { Base::clear(); } + + // observers: + key_compare key_comp() const + { return *this; } + + value_compare value_comp() const + { + const key_compare& comp = *this; + return value_compare(comp); + } + + // 23.3.1.3 map operations: + iterator find(const key_type& k) + { + iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + const_iterator find(const key_type& k) const + { + const_iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + size_type count(const key_type& k) const + { return find(k) != end(); } + + iterator lower_bound(const key_type& k) + { + MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + const_iterator lower_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + iterator upper_bound(const key_type& k) + { + MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + const_iterator upper_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + std::pair equal_range(const key_type& k) + { + MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + std::pair equal_range( + const key_type& k) const + { + const MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + template + friend bool operator==(const AssocVector& lhs, + const AssocVector& rhs); + + bool operator<(const AssocVector& rhs) const + { + const Base& me = *this; + const Base& yo = rhs; + return me < yo; + } + + template + friend bool operator!=(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator>(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator>=(const AssocVector& lhs, + const AssocVector& rhs); + + template + friend bool operator<=(const AssocVector& lhs, + const AssocVector& rhs); + }; + + template + inline bool operator==(const AssocVector& lhs, + const AssocVector& rhs) + { + const std::vector, A>& me = lhs; + return me == rhs; + } + + template + inline bool operator!=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(lhs == rhs); } + + template + inline bool operator>(const AssocVector& lhs, + const AssocVector& rhs) + { return rhs < lhs; } + + template + inline bool operator>=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(lhs < rhs); } + + template + inline bool operator<=(const AssocVector& lhs, + const AssocVector& rhs) + { return !(rhs < lhs); } + + + // specialized algorithms: + template + void swap(AssocVector& lhs, AssocVector& rhs) + { lhs.swap(rhs); } + +} // namespace Loki + +#endif // end file guardian + 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 +#include +#include +#include +#include +#include +#include +#include + +#ifdef DO_EXTRA_LOKI_TESTS + #define D( x ) x +#else + #define D( x ) ; +#endif + +#if defined(_MSC_VER) || defined(__CYGWIN__) +#include +#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 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(), 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(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(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 struct updateCounter : public std::unary_function + { + 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((m_vKeys.size()*rand())/(static_cast(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 EncapsulationPolicy = SimplePointer, + class CreationPolicy = AlwaysCreate, + template class EvictionPolicy = EvictRandom, + class StatisticPolicy = NoStatisticPolicy, + template class FactoryErrorPolicy = DefaultFactoryError, + class ObjVector = std::vector + > + class CachedFactory : + protected EncapsulationPolicy, + 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 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 struct deleteObject : public std::unary_function + { + void operator()(T x){ delete x; } + }; + + // delete the objects in the vector + template struct deleteVectorObjects : public std::unary_function + { + 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 struct deleteMapKeys : public std::unary_function + { + 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(), 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 + 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& 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 + diff --git a/shared/loki/CheckReturn.h b/shared/loki/CheckReturn.h new file mode 100644 index 00000000..fbe63ed0 --- /dev/null +++ b/shared/loki/CheckReturn.h @@ -0,0 +1,165 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2007 by Rich Sposato +// 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 author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_CHECK_RETURN_INC_ +#define LOKI_CHECK_RETURN_INC_ + +// $Id$ + + +#include +#include +#include + + +namespace Loki +{ + +// ---------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// \class CheckReturn +/// +/// \par Purpose +/// C++ provides no mechanism within the language itself to force code to +/// check the return value from a function call. This simple class provides +/// a mechanism by which programmers can force calling functions to check the +/// return value. Or at least make them consciously choose to disregard the +/// return value. If the calling function fails to use or store the return +/// value, the destructor calls the OnError policy. +/// +/// \par Template Parameters +/// CheckReturn has two template parameters, Value and OnError. +/// - Value is the return type from the function. CheckReturn stores a copy of +/// it rather than a reference or pointer since return value could be local to +/// a function. CheckReturn works best when the return type is a built-in +/// primitive (bool, int, etc...) a pointer, or an enum (such as an error +/// condition enum). It can work with other types that have cheap copy +/// operations. +/// - OnError is a policy class indicating how to handle the situation when a +/// caller does not check or copy the returned value. Loki provides some +/// policy classs and you may also write your own. For example, you can write +/// a policy to create a message box when the function ignores the return value. +/// That would quickly tell you places where code ignores the function call. +/// If your write your own, you only need a templated class or struct with a +/// public function named "run" that accepts a reference to a const value. +/// +/// @par Provided Policy Classes +/// - IgnoreReturnValue Deliberately ignores when the caller ignores the return value. +/// - TriggerAssert Asserts in debug builds if the caller ignores the return value. +/// - FprintfStderr Prints out an error message if the caller ignores the return value. +/// - ThrowTheValue Throws the ignored value as an exception. +/// - ThrowLogicError Throws a logic_error exception to indicate a programming error. +//////////////////////////////////////////////////////////////////////////////// + + +template +struct IgnoreReturnValue +{ + static void run(const T&) + { + /// Do nothing at all. + } +}; + +template +struct ThrowTheValue +{ + static void run(const T & value ) + { + throw value; + } +}; + +template +struct ThrowLogicError +{ + static void run( const T & ) + { + throw ::std::logic_error( "CheckReturn: return value was not checked.\n" ); + } +}; + +template +struct TriggerAssert +{ + static void run(const T&) + { + assert( 0 ); + } +}; + +template +struct FprintfStderr +{ + static void run(const T&) + { + fprintf(stderr, "CheckReturn: return value was not checked.\n"); + } +}; + + + +template < class Value , template class OnError = TriggerAssert > +class CheckReturn +{ +public: + + /// Conversion constructor changes Value type to CheckReturn type. + inline CheckReturn( const Value & value ) : + m_value( value ), m_checked( false ) {} + + /// Copy-constructor allows functions to call another function within the + /// return statement. The other CheckReturn's m_checked flag is set since + /// its duty has been passed to the m_checked flag in this one. + inline CheckReturn( const CheckReturn & that ) : + m_value( that.m_value ), m_checked( false ) + { that.m_checked = true; } + + /// Destructor checks if return value was used. + inline ~CheckReturn( void ) + { + // If m_checked is false, then a function failed to check the + // return value from a function call. + if (!m_checked) + OnError::run(m_value); + } + + /// Conversion operator changes CheckReturn back to Value type. + inline operator Value ( void ) + { + m_checked = true; + return m_value; + } + +private: + /// Default constructor not implemented. + CheckReturn( void ); + + /// Copy-assignment operator not implemented. + CheckReturn & operator = ( const CheckReturn & that ); + + /// Copy of returned value. + Value m_value; + + /// Flag for whether calling function checked return value yet. + mutable bool m_checked; +}; + +// ---------------------------------------------------------------------------- + +} // namespace Loki + +#endif // end file guardian + +// $Log$ + diff --git a/shared/loki/Checker.h b/shared/loki/Checker.h new file mode 100644 index 00000000..19350679 --- /dev/null +++ b/shared/loki/Checker.h @@ -0,0 +1,516 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// The Loki Library +// Copyright (c) 2008 Rich Sposato +// The copyright on this file is protected under the terms of 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 author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + +/// @file Checker.h This file provides Loki's Checker facility. + + +// ---------------------------------------------------------------------------- + +#ifndef LOKI_CHECKER_H_INCLUDED +#define LOKI_CHECKER_H_INCLUDED + +#include // needed for calls to uncaught_exception. +#include + + +namespace Loki +{ + +/** @par ContractChecker and StaticChecker Overview + The ContractChecker and StaticChecker classes have two purposes: + - provide a mechanism by which programmers can determine which functions + violate class/data invariants, + - and determine which exception safety a function provides. + + @par Class & Data Invariants + The ContractChecker and StaticChecker define invariants as "expressions that + are true for particular data". They uses a function which returns true if all + data are valid, and returns false if any datum is invalid. This is called the + validator function, and the host class or function provides a pointer to it. + The validator could also assert for any invariant which fails rather than + return false. If the validator is a static member function, you can use it + with checkers in any function, but especially standalone functions and class + static functions. If the validator is a non-static member function, you can + use it only within non-static member functions. + + @par Exception Safety Levels + Years ago, David Abrahams formalized a framework for assessing the exception + safety level a function provides. His framework describes three levels of + guarantees. Any function which does not provide any of these levels is + considered unsafe. ContractChecker and StaticChecker determine a function's + safety level through the use of policy classes. Checker's policy classes can + show if a function provides any of these three guarantees. Since there is no + universal way to detect leaks, this facility provides no mechanism for finding + leaks, but users may create their own validators which do. StaticChecker's + policy classes only provide direct checking for the no-throw and invariant + guarantees. With some finesse, a programmer can write a validator for + StaticChecker that checks for the Strong guarantee. + + - No-throw guarantee: A function will not throw any exceptions. + - Strong guarantee: A function will not change data if an exception occurs. + (Which I call the no-change guarantee.) + - Basic guarantee: A function will not leak resources and data will remain + in a valid state if an exception occurs. (Which I call either the no-leak + or no-break guarantee depending on context.) + */ + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoThrow + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts if an + exception exists. Host classes can use this to show that a member function + provides the no-throw exception safety guarantees. + + @par Requirements For Host Class: + This policy imposes no requirements on a host class. + */ +template < class Host > +class CheckForNoThrow +{ +public: + + inline explicit CheckForNoThrow( const Host * ) {} + + inline bool Check( const Host * ) const + { + const bool okay = ( !::std::uncaught_exception() ); + assert( okay ); + return okay; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoChange + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts only if a + copy of the host differs from the host object when an exception occurs. Host + classes can use this policy to show which member functions provide the strong + exception guarantee. + + @par Requirements: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + equality operator. + */ + +template < class Host > +class CheckForNoChange +{ +public: + + inline explicit CheckForNoChange( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + const bool okay = ( !::std::uncaught_exception() ) + || ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoChangeOrThrow + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts either if a + copy of the host differs from the original host object, or if an exception + occurs. Host classes can use this policy to show which member functions provide + the no-throw exception guarantee, and would never change data anyway. + + @par Requirements For Host Class: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + */ + +template < class Host > +class CheckForNoChangeOrThrow +{ +public: + + inline explicit CheckForNoChangeOrThrow( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + bool okay = ( !::std::uncaught_exception() ); + assert( okay ); + okay = ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForEquality + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts if a copy of the host differs from the host object regardless of whether an exception occurs. + Host classes can use this policy to show which member functions never change + data members, and thereby provide the strong exception safety level by default. + + @par Requirements For Host Class: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + */ + +template < class Host > +class CheckForEquality +{ +public: + + inline explicit CheckForEquality( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + const bool okay = ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNothing + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker does nothing when + called. Host classes can use this to show which member functions provide + neither the strong nor no-throw exception guarantees. The best guarantee such + functions can provide is that nothing gets leaked. + + @par Requirements For Host Class: + This policy imposes no requirements on a host class. + */ + +template < class Host > +class CheckForNothing +{ +public: + inline explicit CheckForNothing( const Host * ) {} + inline bool Check( const Host * ) const { return true; } +}; + +// ---------------------------------------------------------------------------- + +/** @class ContractChecker + This class determines if a function violated any class invariant, but it also + determines if a function fulfills its contract with client code. In the + "Design by Contract" paradigm, each function has certain pre-conditions and + post-conditions which may differ from the class invariants. This asserts if a + check for an invariant fails as well as if any pre- or post-condition fails. + It also demonstrate which exception safety level a function provides. + + @par Usage + -# Implement a function that checks each class invariant. The function must + have the signature similar to the Validator type. Something like: + "bool Host::IsValid( void ) const;" + - The function should return true if everything is okay, but false if + something is wrong. + - Or it could assert if anything is wrong. + - Ideally, it should be private. + -# Implement similar functions to check for pre-conditions and post-conditions. + Functions which verify pre-conditions and post-conditions do not need to + check all class invariants, just conditions specific to certain public + functions in the host class. + -# Declare some typedef's inside the class declaration like these. Make one + typedef for each exception policy you use. I typedef'ed the CheckForNothing + policy as CheckInvariants because even if a function can't provide either the + no-throw nor the no-change policies, it should still make sure the object + remains in a valid state. + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoThrow > CheckForNoThrow; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoChange > CheckForNoChange; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForEquality > CheckForEquality; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNothing > CheckInvariants; + -# Construct a checker near the top of each member function - except in the + validator member function. Pass the this pointer and the address of your + validator function into the checker's constructor. You may also pass in pointers + to function which check pre- and post-conditions. + - If the function never throws, then use the CheckForNoThrow policy. + - If the function never changes any data members, then use CheckForEquality + policy. + - If the function's normal execution flow changes data, but must make sure + data remains unchanged when any exceptions occur, then use the + CheckForNoChange policy. + - Otherwise use the CheckInvariants policy. + -# Recompile a debug version of your program, run the program and all the unit + tests, and look for which assertions failed. + */ + +template +< + class Host, + template < class > class ExceptionPolicy +> +class ContractChecker : public ExceptionPolicy< Host > +{ + /// Shorthand for the ExceptionPolicy class. + typedef ExceptionPolicy< Host > Ep; + +public: + + /// Signature for the validation function. + typedef bool ( Host:: * Validator )( void ) const; + + /** The constructor makes sure the host is valid at the time the checker + was created, thus insuring the host object was not corrupt from the start. + @par host Pointer to host object. + @par validator Pointer to function that checks class invariants. + @par pre Optional pointer to function that checks pre-conditions. + @par post Optional pointer to function that checks post-conditions. + */ + inline ContractChecker( const Host * host, Validator validator, + Validator pre = 0, Validator post = 0 ) : + Ep( host ), + m_host( host ), + m_validator( validator ), + m_pre( pre ), + m_post( post ) + { + assert( Check() ); + if ( 0 != m_pre ) + assert( ( m_host->*( m_pre ) )() ); + } + + /** The destructor checks if any Host invariants failed, and then calls the + ExceptionPolicy's Check function to determine what to do in case of an + exception. + */ + inline ~ContractChecker( void ) + { + assert( Check() ); + if ( 0 != m_post ) + assert( ( m_host->*( m_post ) )() ); + assert( Ep::Check( m_host ) ); + } + + /** This first checks the invariants for ContractChecker, and then calls the + validator function for the host to make sure no class invariants were + broken by the host within the Host's member function body. The host + member function can call Check directly to verify the object remains valid + at any time. This does not care if the pre- and post-condition validator + pointers are null since a host class may pass in NULL pointers for either + to indicate the pre-conditions or post-conditions are the same as the + overall class invariants. + */ + inline bool Check( void ) const + { + assert( 0 != this ); + assert( 0 != m_host ); + assert( 0 != m_validator ); + // Now that this confirms the pointers to the host and validation + // functions are not null, go ahead and validate the host object. + const bool okay = ( m_host->*( m_validator ) )(); + assert( okay ); + return okay; + } + +private: + + /// Default constructor is not implemented. + ContractChecker( void ); + /// Copy constructor is not implemented. + ContractChecker( const ContractChecker & ); + /// Copy-assignment operator is not implemented. + ContractChecker & operator = ( const ContractChecker & ); + + /// Pointer to the host object. + const Host * m_host; + + /// Pointer to member function that checks Host object's invariants. + Validator m_validator; + + /// Pointer to member function that checks Host object's pre-conditions. + Validator m_pre; + + /// Pointer to member function that checks Host object's post-conditions. + Validator m_post; + +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckStaticForNoThrow + + @par Exception Safety Level: + This exception-checking policy class for StaticChecker asserts if an exception + exists. Functions can use this to show they provide the no-throw exception + safety guarantee. + */ +class CheckStaticForNoThrow +{ +public: + inline bool Check( void ) + { + const bool okay = !::std::uncaught_exception(); + assert( okay ); + return okay; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckStaticForNothing + + @par Exception Safety Level: + This exception-checking policy class for StaticChecker does nothing when called. + Functions can use this to show they might provide the weak exception guarantee. + The best guarantee such functions can provide is that nothing gets leaked. + */ +class CheckStaticForNothing +{ +public: + inline bool Check( void ) { return true; } +}; + +// ---------------------------------------------------------------------------- + +/** @class StaticChecker + This class checks if a function provides the no-throw exception safety level + and if the function violated any invariants. Invariants for stand-alone and + static functions act as pre-conditions and post-conditions. + + @par Usage + -# Implement a function that checks the invariants associated with a function, + or with the static data for a class. The function must + have the signature similar to the Validator type. Something like: + "static bool Host::StaticIsValid( void );" or "bool IsOkay( void );" + - The function should return true if everything is okay, but false if + something is wrong. + - Or it could assert if anything is wrong. + -# If the checker is for static functions within a class, declare typedef's + inside the class declaration like these. Make one typedef for each policy + you use. I typedef'ed the CheckForNothing policy as CheckInvariants because + even if a function can't provide the no-throw guarantee, it should still + make sure that static data remains in a valid state. + - typedef ::Loki::StaticChecker< ::Loki::CheckForNoThrow > CheckStaticForNoThrow; + - typedef ::Loki::StaticChecker< ::Loki::CheckForNothing > CheckStaticInvariants; + -# Construct a checker near the top of each member function - except in the + validator member function. Pass the address of your validator function into + the checker's constructor. + - If the function never throws, then use the CheckForNoThrow policy. + - Otherwise use the CheckInvariants policy. + -# Recompile a debug version of your program, run it, and see if an assertion + fails. + */ + +template +< + class ExceptionPolicy +> +class StaticChecker : public ExceptionPolicy +{ + /// Shorthand for the ExceptionPolicy class. + typedef ExceptionPolicy Ep; + +public: + + /// Signature for the validation function. + typedef bool ( * Validator )( void ); + + /** The constructor makes sure the host is valid at the time the checker + was created, thus insuring the host object was not corrupt from the start. + @par validator Pointer to function that checks class invariants. + @par pre Optional pointer to function that checks pre-conditions. + @par post Optional pointer to function that checks post-conditions. + */ + inline explicit StaticChecker( Validator validator, + Validator pre = 0, Validator post = 0 ) : + Ep(), + m_validator( validator ), + m_pre( pre ), + m_post( post ) + { + assert( Check() ); + if ( 0 != m_pre ) + assert( m_pre() ); + } + + /** The destructor checks if any Host invariants failed, and then calls the + ExceptionPolicy's Check function to determine what to do in case of an + exception. + */ + inline ~StaticChecker( void ) + { + assert( Check() ); + if ( 0 != m_post ) + assert( m_post() ); + assert( Ep::Check() ); + } + + /** This first checks its own invariants, and then calls the validator + function to make sure no invariants were broken by the function which + created this checker. That function can call Check directly to verify the + data remains valid at any time. This does not care if the pre- and post- + condition validator pointers are null since a host class may pass in NULL + pointers for either to indicate the pre-conditions or post-conditions are + the same as the overall class invariants. + */ + inline bool Check( void ) const + { + assert( 0 != this ); + assert( 0 != m_validator ); + // Now that this confirms the pointers to the host and validation + // functions are not null, go ahead and validate the host object. + const bool okay = m_validator(); + assert( okay ); + return okay; + } + +private: + + /// Default constructor is not implemented. + StaticChecker( void ); + /// Copy constructor is not implemented. + StaticChecker( const StaticChecker & ); + /// Copy-assignment operator is not implemented. + StaticChecker & operator = ( const StaticChecker & ); + + /// Pointer to member function that checks Host object's invariants. + Validator m_validator; + + /// Pointer to member function that checks Host object's pre-conditions. + Validator m_pre; + + /// Pointer to member function that checks Host object's post-conditions. + Validator m_post; + +}; + +// ---------------------------------------------------------------------------- + +}; // end namespace Loki + +#endif diff --git a/shared/loki/ConstPolicy.h b/shared/loki/ConstPolicy.h new file mode 100644 index 00000000..74c9e5aa --- /dev/null +++ b/shared/loki/ConstPolicy.h @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Richard Sposato +// Copyright (c) 2006 Peter Kümmel +// 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. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_CONST_POLICY_INC_ +#define LOKI_CONST_POLICY_INC_ + +// $Id: ConstPolicy.h 769 2006-10-26 10:58:19Z syntheticpp $ + + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// @note These policy classes are used in LockingPtr and SmartPtr to define +/// how const is propagated from the pointee. +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// \class DontPropagateConst +/// +/// \ingroup ConstGroup +/// Don't propagate constness of pointed or referred object. +//////////////////////////////////////////////////////////////////////////////// + + template< class T > + struct DontPropagateConst + { + typedef T Type; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class PropagateConst +/// +/// \ingroup ConstGroup +/// Propagate constness of pointed or referred object. +//////////////////////////////////////////////////////////////////////////////// + + template< class T > + struct PropagateConst + { + typedef const T Type; + }; + +// default will not break existing code +#ifndef LOKI_DEFAULT_CONSTNESS +#define LOKI_DEFAULT_CONSTNESS ::Loki::DontPropagateConst +#endif + +} // end namespace Loki + +#endif // end file guardian diff --git a/shared/loki/DataGenerators.h b/shared/loki/DataGenerators.h new file mode 100644 index 00000000..1c8e2df0 --- /dev/null +++ b/shared/loki/DataGenerators.h @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Data Generator by Shannon Barber +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +// Code covered by the MIT License +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_DATAGENERATORS_INC_ +#define LOKI_DATAGENERATORS_INC_ + +// $Id: DataGenerators.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +#include "Typelist.h" + +//Reference version + +/************************************************************************************ +// class template GenData +// Iteratates a Typelist, and invokes the functor GenFunc +// for each type in the list, passing a functor along the way. +// The functor is designed to be an insertion iterator which GenFunc +// can use to output information about the types in the list. +// + +Example Use + +template +struct ExtractDataType + { + some_type operator()() + { + return create_value_from_type; + } + }; + +Loki::IterateTypes gendata; +std::vector stuff; +gendata(std::back_inserter(stuff)); +*******************************************************************************/ +namespace Loki +{ + namespace TL + { + template + struct nameof_type + { + const char* operator()() + { + return typeid(T).name(); + } + }; + template + struct sizeof_type + { + size_t operator()() + { + return sizeof(T); + } + }; + template class GenFunc> + struct IterateTypes; + + template class GenFunc> + struct IterateTypes, GenFunc> + { + typedef IterateTypes head_t; + head_t head; + typedef IterateTypes tail_t; + tail_t tail; + template + void operator()(II ii) + { + head.operator()(ii); + tail.operator()(ii); + } + }; + + template class GenFunc> + struct IterateTypes + { + template + void operator()(II ii) + { + GenFunc genfunc; + *ii = genfunc(); + ++ii; //Is this even needed? + } + }; + + template