move directory: MSVC->include/noncc

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@157 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
syntheticpp 2005-07-20 08:40:01 +00:00
parent 33e8c0a9d2
commit 339dcd4233
52 changed files with 22874 additions and 0 deletions

View file

@ -0,0 +1,223 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Feb 20, 2003
// replaced pointer-dummy parameters with Type2Type-parameters.
// See readme.txt (notes: C) if you don't know why the dummy parameters are needed
//
// replaced all template template parameters with 'normal' parameters
// For each Factory-Unit there is now a wrapper-class (non template class)
// containing a nested template class called In which
// provides a typedef (type) to the real unit-class.
// Use one of the wrapper-classes to instantiate a factory.
//
// Covariant return types had to go, too.
#ifndef ABSTRACTFACTORY_INC_
#define ABSTRACTFACTORY_INC_
#include "Typelist.h"
#include "TypeManip.h"
#include "HierarchyGenerators.h"
#include "MSVC6Helpers.h"
#include <cassert>
#define ETAS_HELPER(Type) (::Loki::Type2Type<Type>())
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template AbstractFactoryUnit
// The building block of an Abstract Factory
////////////////////////////////////////////////////////////////////////////////
template <class T>
class AbstractFactoryUnit
{
public:
virtual T* DoCreate(Type2Type<T>) = 0;
virtual ~AbstractFactoryUnit() {}
};
// Wrapper for AbstractFactoryUnit.
struct AbstractFactoryUnitWrapper
{
template <class T>
struct In
{
typedef AbstractFactoryUnit<T> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template AbstractFactory
// Defines an Abstract Factory interface starting from a typelist
////////////////////////////////////////////////////////////////////////////////
// VC 6.0 changes:
// Because the VC 6.0 does not support explicit template argument specification (14.8.1)
// the member-function Create takes a dummy argument of type Type2Type<T> whose sole
// responsibility is to help the compiler in deducing the type of T.
// Using this port the call:
// ConcProduct* p = aFactory.Create<ConcProduct>();
// therefore becomes:
// ConcProduct* p = aFactory.Create(Type2Type<ConcProduct>());
template
<
class TList,
class Unit = AbstractFactoryUnitWrapper
>
class AbstractFactory : public GenScatterHierarchy<TList, Unit>
{
public:
typedef TList ProductList;
template <class T> T* Create(Type2Type<T>)
{
ApplyInnerType<Unit, T>::type& unit = *this;
return unit.DoCreate(Type2Type<T>());
}
};
////////////////////////////////////////////////////////////////////////////////
// class template OpNewFactoryUnit
// Creates an object by invoking the new operator
////////////////////////////////////////////////////////////////////////////////
template <class ConcreteProduct, class Base>
class OpNewFactoryUnit : public Base
{
typedef typename Base::ProductList BaseProductList;
protected:
typedef typename BaseProductList::Tail ProductList;
public:
typedef typename BaseProductList::Head AbstractProduct;
// VC does not support covariant return types
AbstractProduct* DoCreate(Type2Type<AbstractProduct>)
{
return new ConcreteProduct;
}
};
// Wrapper for OpNewFactoryUnit
struct OpNewFactoryUnitWrapper
{
template <class T, class Base>
struct In
{
typedef OpNewFactoryUnit<T, Base> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// 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 ConcreteProduct, class Base>
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)
{}
friend void DoGetPrototype(const PrototypeFactoryUnit& me,
AbstractProduct*& pPrototype)
{ pPrototype = me.pPrototype_; }
friend void DoSetPrototype(PrototypeFactoryUnit& me,
AbstractProduct* pObj)
{ me.pPrototype_ = pObj; }
template <class U>
void GetPrototype(U*& p)
{ return DoGetPrototype(*this, p); }
template <class U>
void SetPrototype(U* pObj)
{ DoSetPrototype(*this, pObj); }
AbstractProduct* DoCreate(Type2Type<AbstractProduct>)
{
assert(pPrototype_);
// vc does not support covariant return types thus
// Clone *always* returns a base-pointer.
// if DoCreate is called from a ConcreteFactory-object we
// need to down-cast.
// Is the static_cast always safe?
return static_cast<AbstractProduct*>(pPrototype_->Clone());
}
private:
AbstractProduct* pPrototype_;
};
// Wrapper for PrototypeFactoryUnit
struct PrototypeFactoryUnitWrapper
{
template <class T, class Base>
struct In
{
typedef PrototypeFactoryUnit<T, Base> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template ConcreteFactory
// Implements an AbstractFactory interface
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractFact,
class Creator = OpNewFactoryUnit,
class TList = /*VC 6.0 does not like typename here*/ AbstractFact::ProductList
>
class ConcreteFactory
: public GenLinearHierarchy<
typename TL::Reverse<TList>::Result, Creator, AbstractFact>
{
public:
typedef typename AbstractFact::ProductList ProductList;
typedef TList ConcreteProductList;
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 24, 2002: ported by Benjamin Kaufmann to MSVC 6.0
// Feb 20, 2003: replaced pointer-dummy parameters with Type2Type-parameters. B.K.
// September 25, 2004: Fixed bug in PrototypeFactoryUnit::GetPrototype, thanks
// to a bug report submitted by funcall.
////////////////////////////////////////////////////////////////////////////////
#endif // ABSTRACTFACTORY_INC_

View file

@ -0,0 +1,335 @@
////////////////////////////////////////////////////////////////////////////////
// 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 ASSOCVECTOR_INC_
#define ASSOCVECTOR_INC_
#include <algorithm>
#include <functional>
#include <vector>
#include <utility>
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template AssocVectorCompare
// Used by AssocVector
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class Value, class C>
class AssocVectorCompare : public C
{
typedef std::pair<typename C::first_argument_type, Value>
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<K, V> not std::pair<const K, V>
// * iterators are random
////////////////////////////////////////////////////////////////////////////////
template
<
class K,
class V,
class C = std::less<K>,
class A = std::allocator< std::pair<K, V> >
>
class AssocVector
: private std::vector< std::pair<K, V>, A >
, private Private::AssocVectorCompare<V, C>
{
typedef std::vector<std::pair<K, V>, A> Base;
typedef Private::AssocVectorCompare<V, C> 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<value_type, value_type, bool>
, 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 <class InputIterator>
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<iterator, bool> insert(const value_type& val)
{
bool found(true);
iterator i(lower_bound(val.first));
if (i == end() || operator()(val.first, i->first))
{
i = Base::insert(i, val);
found = false;
}
return std::make_pair(i, !found);
}
iterator insert(iterator pos, const value_type& val)
{
if (pos != end() && operator()(*pos, val) &&
(pos == end() - 1 ||
!operator()(val, pos[1]) &&
operator()(pos[1], val)))
{
return Base::insert(pos, val);
}
return insert(val).first;
}
template <class InputIterator>
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)
{
using std::swap;
Base::swap(other);
MyCompare& me = *this;
MyCompare& rhs = other;
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() && 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() && 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<iterator, iterator> equal_range(const key_type& k)
{
MyCompare& me = *this;
return std::equal_range(begin(), end(), k, me);
}
std::pair<const_iterator, const_iterator> equal_range(
const key_type& k) const
{
const MyCompare& me = *this;
return std::equal_range(begin(), end(), k, me);
}
friend bool operator==(const AssocVector& lhs, const AssocVector& rhs)
{
const Base& me = lhs;
return me == rhs;
}
bool operator<(const AssocVector& rhs) const
{
const Base& me = *this;
const Base& yo = rhs;
return me < yo;
}
friend bool operator!=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(lhs == rhs); }
friend bool operator>(const AssocVector& lhs, const AssocVector& rhs)
{ return rhs < lhs; }
friend bool operator>=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(lhs < rhs); }
friend bool operator<=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(rhs < lhs); }
};
// specialized algorithms:
template <class K, class V, class C, class A>
void swap(AssocVector<K, V, C, A>& lhs, AssocVector<K, V, C, A>& rhs)
{ lhs.swap(rhs); }
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// May 20, 2001: change operator= - credit due to Cristoph Koegl
// June 11, 2001: remove paren in equal_range - credit due to Cristoph Koegl
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// January 22, 2002: fixed operator= - credit due to Tom Hyer
// June 25, 2002: fixed template insert() - credit due to Robert Minsk
// June 27, 2002: fixed member swap() - credit due to David Brookman
////////////////////////////////////////////////////////////////////////////////
#endif // ASSOCVECTOR_INC_

View file

@ -0,0 +1,150 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Mar 04, 2003
// MSVC 6.0 version
#ifndef DATAGENERATORS_H
#define DATAGENERATORS_H
#include "Typelist.h"
#include "MSVC6Helpers.h"
namespace Loki
{
namespace TL
{
template<typename T>
struct nameof_type
{
const char* operator()()
{
return typeid(T).name();
}
};
template<typename T>
struct sizeof_type
{
size_t operator()()
{
return sizeof(T);
}
};
// wrappers to workaround the need for template template parameters
struct nameof_type_wrapper
{
template <class T>
struct In
{
typedef nameof_type<T> type;
};
};
struct sizeof_type_wrapper
{
template <class T>
struct In
{
typedef sizeof_type<T> type;
};
};
template <class TList, class GenFunc>
struct IterateTypes;
namespace Private
{
// Specialization for a general typelist
template <unsigned Tag>
struct IterateTypesImpl
{
template <class TList, class GenFunc>
struct In
{
typedef typename TList::Head T1;
typedef typename TList::Tail T2;
typedef IterateTypes<T1, GenFunc> head_t;
head_t head;
typedef IterateTypes<T2, GenFunc> tail_t;
tail_t tail;
template<class II>
void operator()(II ii)
{
head.operator()(ii);
tail.operator()(ii);
}
protected:
~In() {}
};
};
// Specialization for a single type
template <>
struct IterateTypesImpl<TL::Private::NoneList_ID>
{
template <class AtomicType, class GenFunc>
struct In
{
template<class II>
void operator()(II ii)
{
typedef typename Loki::ApplyInnerType<GenFunc, AtomicType>::type gFunc;
gFunc genfunc;
*ii = genfunc();
++ii; //Is this even needed?
}
protected:
~In() {}
};
};
// Specialization for NullType
template <>
struct IterateTypesImpl<TL::Private::NullType_ID>
{
template <class T, class GenFunc>
struct In
{
template<class II>
void operator()(II ii)
{}
protected:
~In() {}
};
};
} // end ns Private
template <class TList, class GenFunc>
struct IterateTypes : public
Private::IterateTypesImpl
<
TL::Private::IsTypelist<TList>::type_id
>::template In<TList, GenFunc>
{};
template<typename Types, class UnitFunc, typename II>
void iterate_types(II ii)
{
Loki::TL::IterateTypes<Types, UnitFunc> it;
it(ii);
}
}//ns TL
}//ns Loki
#endif //DATAGENERATORS_H
////////////////////////////////////////////////////////////////////////////////
// Change log:
// 9/20/02 Named changed from GenData to IterateTypes
// 10/8/02 insertion iterators are passed-by-value, not by-reference (oops)
// 03/04/03 ported by Benjamin Kaufmann to MSVC 6.0
// 03/06/03 added protected destructors to private implementation classes B.K.
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef EMPTYTYPE_INC_
#define EMPTYTYPE_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class EmptyType
// Used as a class type that doesn't hold anything
// Useful as a strawman class
////////////////////////////////////////////////////////////////////////////////
class EmptyType {};
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // EMPTYTYPE_INC_

151
include/noncc/MSVC/1200/Factory.h Executable file
View file

@ -0,0 +1,151 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Last update: Feb 22, 2003
//
//
// The default error policy is no longer a template-class
#ifndef FACTORY_INC_
#define FACTORY_INC_
#include "LokiTypeInfo.h"
#include "AssocVector.h"
#include <exception>
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template DefaultFactoryError
// Manages the "Unknown Type" error in an object factory
////////////////////////////////////////////////////////////////////////////////
struct DefaultFactoryError
{
struct Exception : public std::exception
{
const char* what() const throw() { return "Unknown Type"; }
};
template <typename IdentifierType, class AbstractProduct>
static AbstractProduct* OnUnknownType(IdentifierType s,Type2Type<AbstractProduct>)
{
throw Exception();
return (AbstractProduct*) 0;
}
};
////////////////////////////////////////////////////////////////////////////////
// class template Factory
// Implements a generic object factory
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractProduct,
typename IdentifierType,
typename ProductCreator = AbstractProduct* (*)(),
class FactoryErrorPolicy = DefaultFactoryError
>
class Factory
: public FactoryErrorPolicy
{
public:
bool Register(const IdentifierType& id, ProductCreator creator)
{
return associations_.insert(
IdToProductMap::value_type(id, creator)).second;
}
bool Unregister(const IdentifierType& id)
{
return associations_.erase(id) == 1;
}
AbstractProduct* CreateObject(const IdentifierType& id)
{
typename IdToProductMap::iterator i = associations_.find(id);
if (i != associations_.end())
{
return (i->second)();
}
return OnUnknownType(id, Type2Type<AbstractProduct>());
}
private:
typedef AssocVector<IdentifierType, ProductCreator> IdToProductMap;
IdToProductMap associations_;
};
////////////////////////////////////////////////////////////////////////////////
// class template CloneFactory
// Implements a generic cloning factory
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractProduct,
class ProductCreator =
AbstractProduct* (*)(const AbstractProduct*),
class FactoryErrorPolicy = DefaultFactoryError
>
class CloneFactory
: public FactoryErrorPolicy
{
public:
bool Register(const TypeInfo& ti, ProductCreator creator)
{
return associations_.insert(
IdToProductMap::value_type(ti, creator)).second;
}
bool Unregister(const TypeInfo& id)
{
return associations_.erase(id) == 1;
}
AbstractProduct* CreateObject(const AbstractProduct* model)
{
if (model == 0) return 0;
typename IdToProductMap::iterator i =
associations_.find(typeid(*model));
if (i != associations_.end())
{
return (i->second)(model);
}
return OnUnknownType(TypeInfo(typeid(*model)),Type2Type<AbstractProduct>());
}
private:
typedef AssocVector<TypeInfo, ProductCreator> IdToProductMap;
IdToProductMap associations_;
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 08, 2002: replaced const_iterator with iterator so that self-modifying
// ProductCreators are supported. Also, added a throw() spec to what().
// Credit due to Jason Fischl.
// Oct 24, 2002: ported to MSVC 6 by Benjamin Kaufmann.
// Note: The default error policy is no longer a template-class.
// Feb 22, 2003: Added missing parameter to OnUnknownType B.K.
////////////////////////////////////////////////////////////////////////////////
#endif // FACTORY_INC_

2332
include/noncc/MSVC/1200/Functor.h Executable file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,520 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Mar 08, 2003
#ifndef HIERARCHYGENERATORS_INC_
#define HIERARCHYGENERATORS_INC_
#define IS_TYPELIST(TList) TL::Private::IsTypelist<TList>
#include "Typelist.h"
#include "TypeTraits.h"
#include "EmptyType.h"
#include "MSVC6Helpers.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template GenScatterHierarchy
// Generates a scattered hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of one arg):
// GenScatterHierarchy<TList, Model>
// The generated class inherits all classes generated by instantiating the
// template 'Model' with the types contained in TList
////////////////////////////////////////////////////////////////////////////////
// VC 6.0 changes:
// * Unit is no longer a template template parameter.
// * For every concrete unit-template there must be a normal class containing
// a nested-template class called In. In should only contain a typedef to the
// concrete Unit.
//
// Using the originial library one would write something like this:
// class Foo {};
// template <class T> struct TestUnit {};
// void Func(TestUnit<Foo>);
// int main()
// {
// GenScatterHierarchy<Typelist<Foo, NullType>, TestUnit> obj;
// Func(obj); // calls Func(TestUnit<Foo>)
// }
//
// Using this port the code would become:
// class Foo {};
// template <class T> struct TestUnit {};
// struct TestUnitWrapper
// {
// template <class T> struct In {typedef TestUnit<T> type};
// };
// void Func(TestUnit<Foo>);
// int main()
// {
// GenScatterHierarchy<Typelist<Foo, NullType>, TestUnitWrapper> obj;
// Func(obj); // calls Func(TestUnit<Foo>)
// }
//
// Not very nice, i know :-(
//
// See "Metaprogramming VC++ - more of Loki ported" from Mat Marcus
// (http://lists.boost.org/MailArchives/boost/msg20915.php)
//
// Update:
// -------
// The first version of GenScatterHierarchy did not work with typelists
// containing equal types. The MSVC 6.0 erroneously complains about
// inaccessible base-classes (error C2584).
// This new version adds Dummy-classes to the left branch of the generated
// hierarchy to workaround this VC-Bug.
// It creates hierarchies like this:
//
// Holder<int> NullType
// \ /
//Holder<int> GenScatter<int> GenScatter<NullType>
// \ \ /
//VC_InaccessibleBase InheritFromTo
// \ |
//GenScatter<int> GenScatter<TYPELIST_1(int)>
// \ /
// InheritFromTo
// |
// |
//GenScatter<TYPELIST_2(int, int)>
//
// Of course this version of GenScatterHierarchy generates a lot more
// classes (5*n) than Alexandrescu's original implementation (3*n)
//
template <class TList, class Unit> class GenScatterHierarchy;
namespace Private
{
template <class T, class U>
struct InheritFromTwo : public T, public U
{
};
template <int tag>
struct GenScatterImpl;
// Specialization for a general typelist
template <>
struct GenScatterImpl<TL::Private::Typelist_ID>
{
template <class T, class MetaFunctionWrapper>
struct In : public GenScatterHierarchy<typename T::Head,MetaFunctionWrapper>
{
typedef
InheritFromTwo < VC_InaccessibleBase<GenScatterHierarchy<typename T::Head,
MetaFunctionWrapper>, typename T::Tail>,
GenScatterHierarchy<typename T::Tail,
MetaFunctionWrapper>
> type;
typedef VC_InaccessibleBase<GenScatterHierarchy<typename T::Head, MetaFunctionWrapper>,typename T::Tail> LeftBase;
typedef GenScatterHierarchy<typename T::Tail, MetaFunctionWrapper> RightBase;
};
};
// Specialization for a typelist with only one element
template <>
struct GenScatterImpl<TL::Private::AtomList_ID>
{
template <class T, class MetaFunctionWrapper>
struct In : public GenScatterHierarchy<typename T::Head,MetaFunctionWrapper>
{
// for the last Holder-class no dummy class is needed.
typedef
InheritFromTwo < GenScatterHierarchy<typename T::Head,
MetaFunctionWrapper>,
GenScatterHierarchy<NullType,
MetaFunctionWrapper>
> type;
typedef GenScatterHierarchy<typename T::Head, MetaFunctionWrapper> LeftBase;
typedef GenScatterHierarchy<NullType, MetaFunctionWrapper> RightBase;
};
};
// Specialization for a single type
template <>
struct GenScatterImpl<TL::Private::NoneList_ID>
{
template <class AtomicType, class MetaFunctionWrapper>
struct In
{
typedef typename
ApplyInnerType<MetaFunctionWrapper, AtomicType>::type type;
typedef type LeftBase;
typedef EmptyType RightBase;
//typedef AtomicType::THIS_SELECTED bla;
};
};
// Specialization for NullType
template <>
struct GenScatterImpl<TL::Private::NullType_ID>
{
template <class NullTypeList, class MetaFunctionWrapper>
struct In
{
typedef EmptyType type;
typedef type LeftBase;
typedef type RightBase;
};
};
} // end namespace Private
template <class T, class Unit>
class GenScatterHierarchy : public Private::GenScatterImpl
<
IS_TYPELIST(T)::type_id
>::template In<T, Unit>::type
{
public:
typedef typename Select
<
TL::Private::IsTypelist<T>::value, T, void
>::Result TList;
typedef typename Private::GenScatterImpl
<
IS_TYPELIST(T)::type_id
>::template In<T, Unit>::LeftBase LeftBase;
typedef typename Private::GenScatterImpl
<
IS_TYPELIST(T)::type_id
>::template In<T, Unit>::RightBase RightBase;
template <typename U> struct Rebind
{
typedef ApplyInnerType<Unit, U>::type Result;
};
};
////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
// T is a type in the typelist used to generate H):
// Field<T>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
////////////////////////////////////////////////////////////////////////////////
template <class T, class TList, class UnitWrapper>
typename ApplyInnerType<UnitWrapper, T>::type&
Field(GenScatterHierarchy<TList, UnitWrapper>& obj,Type2Type<T>* = (Type2Type<T>*)0)
{
return obj;
}
template <class T, class TList, class UnitWrapper>
const typename ApplyInnerType<UnitWrapper, T>::type&
Field(const GenScatterHierarchy<TList, UnitWrapper>& obj, Type2Type<T>* = (Type2Type<T>*)0)
{
return obj;
}
////////////////////////////////////////////////////////////////////////////////
// function template TupleUnit
// The building block of tuples
////////////////////////////////////////////////////////////////////////////////
template <class T>
struct TupleUnit
{
T value_;
operator T&() { return value_; }
operator const T&() const { return value_; }
};
////////////////////////////////////////////////////////////////////////////////
// class template Tuple
// Implements a tuple class that holds a number of values and provides field
// access to them via the Field function (below)
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
struct TupleUnitWrapper
{
template <class T>
struct In
{
typedef TupleUnit<T> type;
};
};
}
template <class TList>
struct Tuple : public GenScatterHierarchy<TList, Private::TupleUnitWrapper>
{
};
////////////////////////////////////////////////////////////////////////////////
// helper class template FieldHelper
// See Field below
////////////////////////////////////////////////////////////////////////////////
template <unsigned int i>
struct FieldHelper
{
template<class H, class Unit>
struct In
{
private:
typedef typename TL::TypeAt<typename H::TList, i>::Result ElementType;
typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
enum { isConst = TypeTraits<H>::isConst };
typedef typename Select
<
isConst,
const typename H::RightBase,
typename H::RightBase
>
::Result RightBase;
typedef typename Select
<
IsEqualType<UnitType, TupleUnit<ElementType> >::value,
ElementType,
UnitType
>
::Result UnqualifiedResultType;
public:
typedef typename Select
<
isConst,
const UnqualifiedResultType,
UnqualifiedResultType
>
::Result ResultType;
// Must be a template, don't know why.
// If Do is not a template and H& is used as parameter
// MSVC will give a linker error.
template <class T>
static ResultType& Do(H& obj, T*)
{
//typedef typename T::RightBase RightBase;
//RightBase& rightBase = obj;
RightBase& rightBase = obj;
return FieldHelper<i - 1>::template In<RightBase, Unit>::Do(rightBase, (int*)0);
}
};
};
template <>
struct FieldHelper<0>
{
template<class H, class Unit>
struct In
{
private:
typedef typename H::TList::Head ElementType;
typedef typename ApplyInnerType<Unit, ElementType>::type UnitType;
enum { isConst = TypeTraits<H>::isConst };
typedef typename Select
<
isConst,
const typename H::LeftBase,
typename H::LeftBase
>
::Result LeftBase;
typedef typename Select
<
IsEqualType<UnitType, TupleUnit<ElementType> >::value,
ElementType,
UnitType
>
::Result UnqualifiedResultType;
public:
typedef typename Select
<
isConst,
const UnqualifiedResultType,
UnqualifiedResultType
>
::Result ResultType;
public:
template <class T>
static ResultType& Do(H& obj, T*)
{
LeftBase& leftBase = obj;
return leftBase;
}
};
};
////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
// i is the index of a type in the typelist used to generate H):
// Field<i>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
// and T is the i-th type in the typelist
////////////////////////////////////////////////////////////////////////////////
/*
template <unsigned int i, class TList, class UnitWrapper>
typename FieldHelper<i>::template In<GenScatterHierarchy<TList, UnitWrapper>,UnitWrapper>::ResultType&
Field(GenScatterHierarchy<TList, UnitWrapper>& obj, Int2Type<i>)
{
typedef typename GenScatterHierarchy<TList, UnitWrapper> H;
return FieldHelper<i>::template In<H, UnitWrapper>::Do(obj, (int*)0);
}
*/
template <unsigned int i, class TList, class UnitWrapper>
typename FieldHelper<i>::template In<GenScatterHierarchy<TList, UnitWrapper>,UnitWrapper>::ResultType&
Field(GenScatterHierarchy<TList, UnitWrapper>& obj, Int2Type<i>* = (Int2Type<i>*)0)
{
typedef typename GenScatterHierarchy<TList, UnitWrapper> H;
return FieldHelper<i>::template In<H, UnitWrapper>::Do(obj, (int*)0);
}
////////////////////////////////////////////////////////////////////////////////
// class template GenLinearHierarchy
// Generates a linear hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of two args):
// GenScatterHierarchy<TList, Model>
////////////////////////////////////////////////////////////////////////////////
// VC 6.0 changes:
// see GenScatterHierarchy
template
<
class TList,
class Unit,
class Root = EmptyType
>
class GenLinearHierarchy;
namespace Private
{
template <typename TListTag>
struct GenLinearHierarchyHelper
{
template<class TList, class Unit, class Root>
struct In
{
typedef typename TList::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <>
struct GenLinearHierarchyHelper<TL::Private::Typelist_tag>
{
template<class TList, class Unit, class Root>
struct In
{
private:
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
public:
typedef typename
ApplyInnerType2<Unit, Head, GenLinearHierarchy<Tail, Unit, Root> >::type Result;
};
};
template <>
struct GenLinearHierarchyHelper<TL::Private::NullType_tag>
{
template<class TList, class Unit, class Root>
struct In
{
private:
typedef typename TList::Head Head;
public:
typedef typename ApplyInnerType2<Unit,Head, Root>::type Result;
};
};
template <class T, class U, class Root>
struct Wrap
{
struct Dummy {};
typedef typename T::Tail Tail;
// create the hierarchy
typedef typename Private::GenLinearHierarchyHelper
<
typename TL::Private::IsTypelist<Tail>::type_tag
>
::template In<T, U, Root>::Result TempType;
typedef Private::VC_Base_Workaround<TempType, Dummy> type;
// this is nothing more than a typedef to the created hierarchy (TempType).
// But if we try to inherit directly from TempType VC 6.0
// will produce a "Error C2516. : is not a legal base class."
typedef typename type::LeftBase Base;
};
} // namespace Private
// Trying to inherit from LinBase will result in "Error C2516. : is not a legal base class."
// Private::Wrap introduces some levels of indirections which will
// make the vc happy.
template
<
class TList,
class Unit,
class Root
>
class GenLinearHierarchy : public Private::Wrap<TList, Unit, Root>::Base
{
ASSERT_TYPELIST(TList); // TList must not be NullType
public:
typedef typename Private::GenLinearHierarchyHelper
<
typename TL::Private::IsTypelist<typename TList::Tail>::type_tag
>
::template In<TList, Unit, Root>::Result LinBase;
};
} // namespace Loki
#if defined (_MSC_VER) && _MSC_VER <= 1300
#define FIELD(Obj, Nr) \
Field(Obj, (Int2Type<Nr>*)0)
#else
#define FIELD(Obj, Nr) \
Field<Nr>(Obj)
#endif
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// September 16, 2002: Fixed dependent template, using "::template" syntax. T.S.
// Oct 24, 2002: ported by Benjamin Kaufmann to MSVC 6
// Dec 08, 2002: Fixed problems with MSVC6-Version of GenScatterHierarchy when
// used with typelists containing equal types. B.K.
// New Version is ugly :-(
// Dec 08, 2002: Interface changed for Field-Function. The old version does not
// work correctly due to the "Explicitly Specified Template
// Functions Not Overloaded Correctly"-Bug
// (Microsoft KB Article - 240871). B.K.
// Mar 08, 2003: New transparent workaround for Field-Functions. The FIELD-Macro
// is no longer needed. B.K.
////////////////////////////////////////////////////////////////////////////////
#undef IS_TYPELIST
#endif // HIERARCHYGENERATORS_INC_

View file

@ -0,0 +1,106 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef LOKITYPEINFO_INC_
#define LOKITYPEINFO_INC_
#include <typeinfo>
#include <cassert>
#include "Typelist.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class TypeInfo
// Purpose: offer a first-class, comparable wrapper over std::type_info
////////////////////////////////////////////////////////////////////////////////
class TypeInfo
{
public:
// Constructors
TypeInfo(); // needed for containers
TypeInfo(const std::type_info&); // non-explicit
// Access for the wrapped std::type_info
const std::type_info& Get() const;
// Compatibility functions
bool before(const TypeInfo& rhs) const;
const char* name() const;
private:
const std::type_info* pInfo_;
};
// Implementation
inline TypeInfo::TypeInfo()
{
class Nil {};
pInfo_ = &typeid(Nil);
assert(pInfo_);
}
inline TypeInfo::TypeInfo(const std::type_info& ti)
: pInfo_(&ti)
{ assert(pInfo_); }
inline bool TypeInfo::before(const TypeInfo& rhs) const
{
assert(pInfo_);
return pInfo_->before(*rhs.pInfo_) != 0;
}
inline const std::type_info& TypeInfo::Get() const
{
assert(pInfo_);
return *pInfo_;
}
inline const char* TypeInfo::name() const
{
assert(pInfo_);
return pInfo_->name();
}
// Comparison operators
inline bool operator==(const TypeInfo& lhs, const TypeInfo& rhs)
{ return (lhs.Get() == rhs.Get()) != 0; }
inline bool operator<(const TypeInfo& lhs, const TypeInfo& rhs)
{ return lhs.before(rhs); }
inline bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs == rhs); }
inline bool operator>(const TypeInfo& lhs, const TypeInfo& rhs)
{ return rhs < lhs; }
inline bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs > rhs); }
inline bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs < rhs); }
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // LOKITYPEINFO_INC_

View file

@ -0,0 +1,177 @@
// Last update: Mar 06, 2003
// Added VoidWrap
// Added qualification ::Loki::Private:: to types from the Private-Namespace
// Thanks to Adi Shavit
#ifndef MSVC6HELPERS__H
#define MSVC6HELPERS__H
#if !defined (_MSC_VER) || _MSC_VER >= 1300
#error "please use this header only with MSVC 6.0"
#endif
#include "TypeManip.h"
namespace Loki
{
namespace Private
{
template <class T, class U>
struct VC_InaccessibleBase : public T
{};
// workaround for the "Error C2516. : is not a legal base class"
// Use VC_Base_Workaround's LeftBase instead of the
// alleged illegal base class.
template <class T, class U>
struct VC_Base_Workaround : public T, public U
{
typedef T LeftBase;
};
// MSVC 6.0 does not allow the return of
// expressions of type "cv void" in a functions with a return
// type of cv void (6.6.3).
// Functor.h uses this Type as a workaround.
struct VoidAsType {};
// workaround for error C2182: '__formal' illegal use of type 'void'
// when trying to use void as default value of a template parameter.
// Instead of template<class T = void> class bla {};
// simply write template <class T = VoidWrap::type> class bla {};
// and the VC 6.0 will be happy.
struct VoidWrap
{
typedef void type;
};
// workarounds for template template parameters
////////////////////////////////////////////////////////////////////////////////
// class template AlwaysFalse
// Invocation: AlwaysFalse<T>::value
// value will always by 0 (false)
////////////////////////////////////////////////////////////////////////////////
template< typename T >
struct AlwaysFalse
{
enum { value = false };
};
////////////////////////////////////////////////////////////////////////////////
// class template ApplyImpl1
// Invocation: ApplyImpl1<T>::template Result<T1>
// T must be a nontemplate type with a nested class template named In.
// The class template is a helper for the Apply1-Template
////////////////////////////////////////////////////////////////////////////////
template <class TypeWithNestedTemplate>
struct ApplyImpl1
{
template<bool flag>
struct VC_WORKAROUND : public TypeWithNestedTemplate {};
struct VC_WORKAROUND<true>
{ template<class> struct In; };
template< typename T1 > struct Result : public
VC_WORKAROUND< ::Loki::Private::AlwaysFalse<TypeWithNestedTemplate>::value >::template In<T1>
{
typedef VC_WORKAROUND< ::Loki::Private::AlwaysFalse<TypeWithNestedTemplate>::value >::template In<T1> Base;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template ApplyImpl2
// Invocation: ApplyImpl2<T>::template Result<T1, T2>
// T must be a nontemplate type with a nested class template named In.
// The class template is a helper for the Apply2-Template
////////////////////////////////////////////////////////////////////////////////
template <class TypeWithNestedTemplate>
struct ApplyImpl2
{
template<bool flag>
struct VC_WORKAROUND : public TypeWithNestedTemplate {};
struct VC_WORKAROUND<true>
{template<class T, class U> struct In; };
template< typename T1, typename T2 > struct Result : public
VC_WORKAROUND< ::Loki::Private::AlwaysFalse<TypeWithNestedTemplate>::value >::template In<T1, T2>
{
};
};
} // end of namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template Apply1
// Invocation: Apply1<T, U>
// Applies the type U to the inner template In of type T
// The class template Apply1 helps to emulate template template parameters
// i first saw this technique in boost's mpl library.
////////////////////////////////////////////////////////////////////////////////
template<typename F, typename T1>
struct Apply1 : ::Loki::Private::ApplyImpl1<F>::template Result<T1>
{
typedef typename ::Loki::Private::ApplyImpl1<F>::template Result<T1>::Base Base;
};
////////////////////////////////////////////////////////////////////////////////
// class template Apply2
// Invocation: Apply2<T, U, V>
// Applies the types U and V to the inner template In of type T
// The class template Apply2 helps to emulate template template parameters
// i first saw this technique in boost's mpl library.
////////////////////////////////////////////////////////////////////////////////
template<typename F, typename T1, typename T2>
struct Apply2 : ::Loki::Private::ApplyImpl2<F>::template Result<T1, T2>
{
};
////////////////////////////////////////////////////////////////////////////////
// class template ApplyInnerType
// Invocation: ApplyInnerType<Wrapper, U>::type
// Applies the type U to the the inner template 'In' of type Wrapper and typedefs
// the resulting type to 'type'
// The class template ApplyInnerType helps to emulate template template parameters
// i first saw this technique in boost's mpl library.
////////////////////////////////////////////////////////////////////////////////
template <class Wrapper, class T>
struct ApplyInnerType
{
template<bool> struct Wrapper_VC : Wrapper {};
template<> struct Wrapper_VC<true>
{ template<class X> struct In; };
typedef typename
Wrapper_VC< ::Loki::Private::AlwaysFalse<Wrapper>::value>::template In<T>::type type;
};
////////////////////////////////////////////////////////////////////////////////
// class template ApplyInnerType2
// Invocation: ApplyInnerType2<Wrapper, U, V>::type
// Applies the types U and V to the the inner template 'In' of type Wrapper and typedefs
// the resulting type to 'type'
// The class template ApplyInnerType helps to emulate template template parameters
// i first saw this technique in boost's mpl library.
////////////////////////////////////////////////////////////////////////////////
template <class Wrapper, class T, class V>
struct ApplyInnerType2
{
template<bool> struct Wrapper_VC : Wrapper {};
template<> struct Wrapper_VC<true>
{ template<class X, class Y> struct In; };
typedef typename
Wrapper_VC< ::Loki::Private::AlwaysFalse<Wrapper>::value>::template In<T, V>::type type;
};
template <class Wrapper, class T, class U, class V, class W>
struct ApplyInnerType4
{
template<bool> struct Wrapper_VC : Wrapper {};
template<> struct Wrapper_VC<true>
{ template<class W, class X, class Y, class Z> struct In; };
typedef typename
Wrapper_VC< ::Loki::Private::AlwaysFalse<Wrapper>::value>::template In<T, U, V, W>::type type;
};
}
#endif

View file

@ -0,0 +1,848 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: Mar 21, 2003
// Added a new explicit template argument specification workaround for
// FnDispatcher::Add which is more compliant with other
// explicit template argument specification workarounds used in this port.
//
// Example usage:
// --------------
// Using the original library one writes:
// typedef FnDispatcher<Shape> Dispatcher;
// void Hatch(Rectangle& lhs, Poly& rhs) {...}
//
// Dispatcher dis;
// disp.Add<Rectangle, Poly, &Hatch>();
//
// Using this port the example either becomes:
// dis.Add(Dispatcher::Add<Rectangle, Poly, &Hatch>());
// or alternatively
// Dispatcher::AddI<Rectangle, Poly, &Hatch>()(dis);
//
// All dispatchers now have void as default value for return types.
// All dispatchers now support void as return type.
//
//
// The port now uses Tye2Type-parameters instead of plain pointers as
// a workaround of VC's explicit template argument specification bug.
//
// For example:
// The original declaration of BasicDispatcher::Add looks like this:
//
// template <class SomeLhs, class SomeRhs>
// void Add(CallbackType fun);
//
// and you call it like this:
// obj.Add<Type1, Type2>(yourFun);
//
// This port uses:
//
// template <class SomeLhs, class SomeRhs>
// void Add(CallbackType fun, Type2Type<SomeLhs>, Type2Type<SomeRhs>);
//
// and you call it like this:
// obj.Add(yourFun, Type2Type<Type1>(), Type2Type<Type2>());
#ifndef MULTIMETHODS_INC_
#define MULTIMETHODS_INC_
#include "Typelist.h"
#include "LokiTypeInfo.h"
#include "Functor.h"
#include "AssocVector.h"
////////////////////////////////////////////////////////////////////////////////
// IMPORTANT NOTE:
// The double dispatchers implemented below differ from the excerpts shown in
// the book - they are simpler while respecting the same interface.
////////////////////////////////////////////////////////////////////////////////
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// Implementation helpers for StaticDispatcher
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class SomeLhs, class SomeRhs, class Executor, typename ResultType>
struct InvocationTraitsBase
{
protected:
template <class R>
struct BaseImpl
{
static ResultType
DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type<false>)
{
return exec.Fire(lhs, rhs);
}
static ResultType DoDispatch( SomeLhs& lhs, SomeRhs& rhs,
Executor& exec, Int2Type<true>)
{
return exec.Fire(rhs, lhs);
}
};
template <>
struct BaseImpl<void>
{
static ResultType
DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type<false>)
{
exec.Fire(lhs, rhs);
}
static ResultType DoDispatch( SomeLhs& lhs, SomeRhs& rhs,
Executor& exec, Int2Type<true>)
{
exec.Fire(rhs, lhs);
}
};
public:
typedef BaseImpl<ResultType> Base;
};
template <class SomeLhs, class SomeRhs, class Executor, typename ResultType>
struct InvocationTraits : public InvocationTraitsBase
<SomeLhs, SomeRhs, Executor, ResultType>::Base
{
};
template<class Executor, class BaseLhs, class TypesLhs, bool symmetric,
class BaseRhs, class TypesRhs, typename ResultType>
class StaticDispatcherBase
{
private:
// Base for ResultType != void
template <class R>
class In
{
template <class SomeLhs>
static ResultType DispatchRhs( SomeLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ return exec.OnError(lhs, rhs); }
template <class Head, class Tail, class SomeLhs>
static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p2 = dynamic_cast<Head*>(&rhs))
{
Int2Type<(symmetric &&
int(TL::IndexOf<TypesRhs, Head>::value) <
int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
typedef Private::InvocationTraits<
SomeLhs, Head, Executor, ResultType> CallTraits;
return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
}
return DispatchRhs(lhs, rhs, exec, Tail());
}
static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ return exec.OnError(lhs, rhs); }
template <class Head, class Tail>
static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p1 = dynamic_cast<Head*>(&lhs))
{
return DispatchRhs(*p1, rhs, exec, TypesRhs());
}
return DispatchLhs(lhs, rhs, exec, Tail());
}
protected:
~In() {}
public:
static ResultType Go( BaseLhs& lhs, BaseRhs& rhs,
Executor exec)
{ return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
}; // In<R>
// Base for ResultType == void
template <>
class In<void>
{
template <class SomeLhs>
static ResultType DispatchRhs( SomeLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ exec.OnError(lhs, rhs); }
template <class Head, class Tail, class SomeLhs>
static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p2 = dynamic_cast<Head*>(&rhs))
{
Int2Type<(symmetric &&
int(TL::IndexOf<TypesRhs, Head>::value) <
int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
typedef Private::InvocationTraits<
SomeLhs, Head, Executor, void> CallTraits;
CallTraits::DoDispatch(lhs, *p2, exec, i2t);
return;
}
DispatchRhs(lhs, rhs, exec, Tail());
}
static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ exec.OnError(lhs, rhs); }
template <class Head, class Tail>
static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p1 = dynamic_cast<Head*>(&lhs))
{
DispatchRhs(*p1, rhs, exec, TypesRhs());
return;
}
DispatchLhs(lhs, rhs, exec, Tail());
}
protected:
~In<void>() {}
public:
static ResultType Go( BaseLhs& lhs, BaseRhs& rhs,
Executor exec)
{ DispatchLhs(lhs, rhs, exec, TypesLhs()); }
}; // In<void>
public:
typedef In<ResultType> Base;
}; // StaticDispatcherBase
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template StaticDispatcher
// Implements an automatic static double dispatcher based on two typelists
////////////////////////////////////////////////////////////////////////////////
template
<
class Executor,
class BaseLhs,
class TypesLhs,
bool symmetric = true,
class BaseRhs = BaseLhs,
class TypesRhs = TypesLhs,
typename ResultType = Loki::Private::VoidWrap::type
>
class StaticDispatcher : public ::Loki::Private::StaticDispatcherBase
<
Executor, BaseLhs, TypesLhs, symmetric,
BaseRhs, TypesRhs, ResultType
>::Base
{
public:
// member functions moved to base class
// static ResultType Go( BaseLhs& lhs, BaseRhs& rhs,
// Executor exec)
};
////////////////////////////////////////////////////////////////////////////////
// Implementation helpers for BasicDispatcher
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class BaseLhs, class BaseRhs, typename ResultType,
typename CallbackType>
class BasicDispatcherBase
{
private:
// Common (independent of the result type) code for BasicDispatcher
class Common
{
private:
void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
{
callbackMap_[KeyType(lhs, rhs)] = fun;
}
bool DoRemove(TypeInfo lhs, TypeInfo rhs)
{
return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
}
protected:
typedef std::pair<TypeInfo,TypeInfo> KeyType;
typedef CallbackType MappedType;
typedef AssocVector<KeyType, MappedType> MapType;
MapType callbackMap_;
~Common() {}
public:
template <class SomeLhs, class SomeRhs>
void Add(CallbackType fun, ::Loki::Type2Type<SomeLhs>,
::Loki::Type2Type<SomeRhs>)
{
DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
}
template <class SomeLhs, class SomeRhs>
bool Remove(::Loki::Type2Type<SomeLhs>, ::Loki::Type2Type<SomeRhs>)
{
return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
}
}; // Common
template <class R> // Base for ResultType != void
class In : public Common
{
public:
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
typename MapType::key_type k(typeid(lhs),typeid(rhs));
typename MapType::iterator i = Common::callbackMap_.find(k);
if (i == Common::callbackMap_.end())
{
throw std::runtime_error("Function not found");
}
return (i->second)(lhs, rhs);
}
protected:
~In() {}
}; // In
template <> // Base for ResultType == void
class In<void> : public Common
{
public:
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
typename MapType::key_type k(typeid(lhs),typeid(rhs));
typename MapType::iterator i = Common::callbackMap_.find(k);
if (i == Common::callbackMap_.end())
{
throw std::runtime_error("Function not found");
}
(i->second)(lhs, rhs);
}
protected:
~In<void>() {}
}; // In
public:
typedef In<ResultType> Base;
}; // BasicDispatcherBase
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template BasicDispatcher
// Implements a logarithmic double dispatcher for functors (or functions)
// Doesn't offer automated casts or symmetry
////////////////////////////////////////////////////////////////////////////////
template
<
class BaseLhs,
class BaseRhs = BaseLhs,
typename ResultType = Loki::Private::VoidWrap::type,
typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
>
class BasicDispatcher : public ::Loki::Private::BasicDispatcherBase
<
BaseLhs, BaseRhs, ResultType, CallbackType
>::Base
{
public:
// member functions moved to base class
// template <class SomeLhs, class SomeRhs>
// void Add(CallbackType fun, ::Loki::Type2Type<SomeLhs>,
// ::Loki::Type2Type<SomeRhs>)
//
// template <class SomeLhs, class SomeRhs>
// bool Remove(::Loki::Type2Type<SomeLhs>, ::Loki::Type2Type<SomeRhs>)
//
// ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
};
struct BasicDispatcherWrapper
{
template <class T, class U, class V, class W>
struct In
{
typedef BasicDispatcher<T, U, V, W> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template StaticCaster
// Implementation of the CastingPolicy used by FunctorDispatcher
////////////////////////////////////////////////////////////////////////////////
template <class To, class From>
struct StaticCaster
{
static To& Cast(From& obj)
{
return static_cast<To&>(obj);
}
};
struct StaticCasterWrapper
{
template <class T, class U>
struct In
{
typedef StaticCaster<T, U> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template DynamicCaster
// Implementation of the CastingPolicy used by FunctorDispatcher
////////////////////////////////////////////////////////////////////////////////
template <class To, class From>
struct DynamicCaster
{
static To& Cast(From& obj)
{
return dynamic_cast<To&>(obj);
}
};
struct DynamicCasterWrapper
{
template <class T, class U>
struct In
{
typedef DynamicCaster<T, U> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template Private::FnDispatcherHelper
// Implements trampolines and argument swapping used by FnDispatcher
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class BaseLhs, class BaseRhs, typename ResultType,
class DispatcherBackend>
class FnDispatcherBase
{
private:
// Implementation for ResultType != void
template <class R>
class In
{
public:
ApplyInnerType4<DispatcherBackend, BaseLhs, BaseRhs, ResultType,
ResultType (*)(BaseLhs&, BaseRhs&)>::type backEnd_;
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
return backEnd_.Go(lhs, rhs);
}
protected:
~In() {}
}; // In
// Implementation for ResultType == void
template <>
class In<void>
{
public:
ApplyInnerType4<DispatcherBackend, BaseLhs, BaseRhs, ResultType,
ResultType (*)(BaseLhs&, BaseRhs&)>::type backEnd_;
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
backEnd_.Go(lhs, rhs);
}
protected:
~In<void>() {}
}; // In<void>
public:
typedef In<ResultType> Base;
}; // FnDispatcherBase
template< class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs,
class ResultType, class CastLhs, class CastRhs,
void (*Callback)(SomeLhs&, SomeRhs&)>
class FnDispatcherHelperBase
{
private:
template <class R>
class In
{
public:
static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs)
{
return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
{
return Trampoline(lhs, rhs);
}
protected:
~In() {}
};
template <>
class In<void>
{
public:
static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs)
{
Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
{
Trampoline(lhs, rhs);
}
protected:
~In<void>() {}
};
public:
typedef In<ResultType> Base;
};
template
<
class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs,
typename ResultType, class CastLhs, class CastRhs,
ResultType (*Callback)(SomeLhs&, SomeRhs&)
>
struct FnDispatcherHelper : public FnDispatcherHelperBase
<
BaseLhs, BaseRhs, SomeLhs, SomeRhs,
ResultType, CastLhs, CastRhs, Callback
>::Base
{};
}
////////////////////////////////////////////////////////////////////////////////
// class template FnDispatcher
// Implements an automatic logarithmic double dispatcher for functions
// Features automated conversions
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class BaseRhs = BaseLhs,
typename ResultType = Loki::Private::VoidWrap::type,
class CastingPolicy = DynamicCasterWrapper,
class DispatcherBackend = BasicDispatcherWrapper>
class FnDispatcher : public ::Loki::Private::FnDispatcherBase
<
BaseLhs, BaseRhs,
ResultType, DispatcherBackend
>::Base
{
typedef typename ::Loki::Private::FnDispatcherBase
<
BaseLhs, BaseRhs, ResultType, DispatcherBackend
>::Base Base;
public:
template <class SomeLhs, class SomeRhs>
void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&),
::Loki::Type2Type<SomeLhs>,
::Loki::Type2Type<SomeRhs>)
{
Base::backEnd_.Add(pFun, ::Loki::Type2Type<SomeLhs>(),
::Loki::Type2Type<SomeRhs>());
}
// two different workarounds for FnDispatcher::Add
// Using the first one writes:
// DisType dispatcher;
// dispatcher.Add(DisType::Etas<SomeLhs, SomeRhs, &AFunc>());
// using the second workaround the call becomes:
// DisType dispatcher;
// DisTyp::AddI<SomeLhs, SomeRhs, &AFunc>()(dispatcher);
// Helper-class for the first workaround.
// When calling FnDispatcher::Add provide an object of this type
// as argument.
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&), bool symmetric = false>
struct Etas
{
typedef Private::FnDispatcherHelper<
BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType,
ApplyInnerType2<CastingPolicy, SomeLhs,BaseLhs>::type,
ApplyInnerType2<CastingPolicy,SomeRhs,BaseRhs>::type,
callback> Local;
enum {sym = symmetric};
typedef SomeLhs Lhs;
typedef SomeRhs Rhs;
};
// EtasType has to be a template parameter. If one tries to use
// a parameter of type Etas the MSVC 6.0 won't generate correct
// code.
template <class EtasType>
void Add(EtasType EtasObj)
{
typedef typename EtasType::Local Local;
typedef typename EtasType::Lhs SomeLhs;
typedef typename EtasType::Rhs SomeRhs;
Add(&Local::Trampoline, ::Loki::Type2Type<SomeLhs>(),
::Loki::Type2Type<SomeRhs>());
if (EtasType::sym)
{
Add(&Local::TrampolineR, ::Loki::Type2Type<SomeRhs>(),
::Loki::Type2Type<SomeLhs>());
}
}
// alternative workaround for FnDispatcher::Add
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&), bool symmetric = false>
struct AddI
{
void operator()(FnDispatcher<BaseLhs, BaseRhs, ResultType,
CastingPolicy,DispatcherBackend>& f)
{
typedef Private::FnDispatcherHelper<
BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType,
ApplyInnerType2<CastingPolicy, SomeLhs,BaseLhs>::type,
ApplyInnerType2<CastingPolicy,SomeRhs,BaseRhs>::type,
callback> Local;
f.Add(&Local::Trampoline, ::Loki::Type2Type<SomeLhs>(),
::Loki::Type2Type<SomeRhs>());
if (symmetric)
{
f.Add(&Local::TrampolineR, ::Loki::Type2Type<SomeRhs>(),
::Loki::Type2Type<SomeLhs>());
}
}
};
template <class SomeLhs, class SomeRhs>
void Remove(::Loki::Type2Type<SomeLhs>, ::Loki::Type2Type<SomeRhs>)
{
Base::backEnd_.Remove(::Loki::Type2Type<SomeLhs>(),
::Loki::Type2Type<SomeRhs>());
}
// moved to base class
// ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
};
////////////////////////////////////////////////////////////////////////////////
// class template FunctorDispatcherAdaptor
// permits use of FunctorDispatcher under gcc.2.95.2/3
///////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs,
typename ResultType, class CastLhs, class CastRhs, class Fun, bool SwapArgs>
class FunctorDispatcherHelperBase
{
template <class R>
class In
{
Fun fun_;
ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>)
{
return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>)
{
return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
public:
In(const Fun& fun) : fun_(fun) {}
ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
{
return Fire(lhs,rhs,Int2Type<SwapArgs>());
}
};
template <>
class In<void>
{
Fun fun_;
ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>)
{
fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>)
{
fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
public:
In<void>(const Fun& fun) : fun_(fun) {}
ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
{
Fire(lhs,rhs,Int2Type<SwapArgs>());
}
};
public:
typedef In<ResultType> Base;
}; // FunctorDispatcherHelperBase
template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs,
typename ResultType, class CastLhs, class CastRhs, class Fun, bool SwapArgs>
class FunctorDispatcherHelper : public FunctorDispatcherHelperBase
<
BaseLhs, BaseRhs, SomeLhs, SomeRhs,
ResultType, CastLhs, CastRhs, Fun,
SwapArgs
>::Base
{
private:
typedef typename FunctorDispatcherHelperBase
<
BaseLhs, BaseRhs, SomeLhs, SomeRhs,
ResultType, CastLhs, CastRhs, Fun, SwapArgs
>::Base Base;
public:
FunctorDispatcherHelper(const Fun& f) : Base(f)
{}
};
template <typename ResultType, class BaseLhs, class BaseRhs,
class DispatcherBackend>
class FunctorDispatcherBase
{
private:
class Common
{
protected:
typedef TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList;
typedef Functor<ResultType, ArgsList, DEFAULT_THREADING> FunctorType;
ApplyInnerType4<DispatcherBackend,BaseLhs, BaseRhs, ResultType,
FunctorType>::type backEnd_;
~Common() {}
};
template <class R>
class In : public Common
{
public:
typedef typename Common::ArgsList ArgsList;
typedef typename Common::FunctorType FunctorType;
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
return Common::backEnd_.Go(lhs, rhs);
}
protected:
In() {}
};
template <>
class In<void> : public Common
{
public:
typedef typename Common::ArgsList ArgsList;
typedef typename Common::FunctorType FunctorType;
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
Common::backEnd_.Go(lhs, rhs);
}
protected:
In<void>() {}
};
public:
typedef In<ResultType> Base;
};
}
////////////////////////////////////////////////////////////////////////////////
// class template FunctorDispatcher
// Implements a logarithmic double dispatcher for functors
// Features automated casting
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class BaseRhs = BaseLhs,
typename ResultType = Loki::Private::VoidWrap::type,
class CastingPolicy = DynamicCasterWrapper,
class DispatcherBackend = BasicDispatcherWrapper>
class FunctorDispatcher : public ::Loki::Private::FunctorDispatcherBase
<
ResultType, BaseLhs, BaseRhs, DispatcherBackend
>::Base
{
typedef typename ::Loki::Private::FunctorDispatcherBase
<
ResultType, BaseLhs, BaseRhs, DispatcherBackend
>::Base Base;
public:
typedef Base::ArgsList ArgsList;
typedef Base::FunctorType FunctorType;
template <class SomeLhs, class SomeRhs, class Fun>
void Add(const Fun& fun, ::Loki::Type2Type<SomeLhs>,
::Loki::Type2Type<SomeRhs>)
{
typedef typename ApplyInnerType2<CastingPolicy,SomeLhs, BaseLhs>::type CastOne;
typedef typename ApplyInnerType2<CastingPolicy,SomeRhs, BaseRhs>::type CastTwo;
typedef typename
Private::FunctorDispatcherHelper
<
BaseLhs, BaseRhs, SomeLhs, SomeRhs,
ResultType,CastOne,CastTwo,Fun, false
>::Base Adapter;
Base::backEnd_.Add(FunctorType(Adapter(fun), Loki::Disambiguate()),
Type2Type<SomeLhs>(), Type2Type<SomeRhs>());
}
template <class SomeLhs, class SomeRhs, class Fun>
void Add(const Fun& fun, ::Loki::Type2Type<SomeLhs>,
::Loki::Type2Type<SomeRhs>, bool symmetric)
{
Add(fun, Type2Type<SomeLhs>(), Type2Type<SomeRhs>());
if (symmetric)
{
// Note: symmetry only makes sense where BaseLhs==BaseRhs
typedef typename ApplyInnerType2<CastingPolicy,SomeLhs, BaseLhs>::type CastOne;
typedef typename ApplyInnerType2<CastingPolicy,SomeRhs, BaseLhs>::type CastTwo;
typedef typename
Private::FunctorDispatcherHelper
<
BaseLhs, BaseRhs, SomeLhs, SomeRhs,
ResultType,CastOne,CastTwo,Fun, true
>::Base AdapterR;
Base::backEnd_.Add(FunctorType(AdapterR(fun), Loki::Disambiguate()),
Type2Type<SomeRhs>(), Type2Type<SomeLhs>());
}
}
template <class SomeLhs, class SomeRhs>
void Remove(::Loki::Type2Type<SomeLhs>, ::Loki::Type2Type<SomeRhs>)
{
Base::backEnd_.Remove(Type2Type<SomeLhs>(), Type2Type<SomeRhs>());
}
// moved to base class
// ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
// Oct 28, 2002: ported by Benjamin Kaufmann to MSVC 6
// Feb 19, 2003: replaced pointer-Dummies with Type2Type-Parameters and added
// support for return type void. B.K.
// Mar 06, 2003: Changed default values for return types to void.
// Added protected destructors to private implementation classes B.K.
// Mar 20. 2003: Fixed Bugs in FnDispatcherHelperBase, FnDispatcher::Add and
// FunctorDispatcher::Add.
// New Interface for FnDispatcher::Add.B.K.
// Mar 21, 2003: Added new explicit template argument specification workaround
// for FnDispatcher::Add B.K.
////////////////////////////////////////////////////////////////////////////////
#endif

View file

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef NULLTYPE_INC_
#define NULLTYPE_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class NullType
// Used as a placeholder for "no type here"
// Useful as an end marker in typelists
////////////////////////////////////////////////////////////////////////////////
class NullType {};
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // NULLTYPE_INC_

View file

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: Oct 06, 2002
#include "Singleton.h"
using namespace Loki::Private;
Loki::Private::TrackerArray Loki::Private::pTrackerArray = 0;
unsigned int Loki::Private::elements = 0;
////////////////////////////////////////////////////////////////////////////////
// function AtExitFn
// Ensures proper destruction of objects with longevity
////////////////////////////////////////////////////////////////////////////////
void Loki::Private::AtExitFn()
{
assert(elements > 0 && pTrackerArray != 0);
// Pick the element at the top of the stack
LifetimeTracker* pTop = pTrackerArray[elements - 1];
// Remove that object off the stack
// Don't check errors - realloc with less memory
// can't fail
pTrackerArray = static_cast<TrackerArray>(VC_BROKEN_STD::realloc(
pTrackerArray, sizeof(*pTrackerArray) * --elements));
// Destroy the element
delete pTop;
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 06 2002: ported by Benjamin Kaufmann to VC 6.0
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,498 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: Feb 24, 2003
#ifndef SINGLETON_INC_
#define SINGLETON_INC_
#include "Threads.h"
#include "MSVC6Helpers.h" // for apply-template
#include <algorithm>
#include <stdexcept>
#include <cassert>
#include <cstdlib>
#include <new>
#if _MSC_VER <= 1200
#define VC_BROKEN_STD
#else
#define VC_BROKEN_STD std
#endif
namespace Loki
{
namespace Private
{
////////////////////////////////////////////////////////////////////////////////
// class LifetimeTracker
// Helper class for SetLongevity
////////////////////////////////////////////////////////////////////////////////
class LifetimeTracker
{
public:
LifetimeTracker(unsigned int x) : longevity_(x)
{}
virtual ~LifetimeTracker() = 0;
static bool Compare(const LifetimeTracker* lhs,
const LifetimeTracker* rhs)
{
return rhs->longevity_ > lhs->longevity_;
}
private:
unsigned int longevity_;
};
// Definition required
inline LifetimeTracker::~LifetimeTracker() {}
// Helper data
typedef LifetimeTracker** TrackerArray;
extern TrackerArray pTrackerArray;
extern unsigned int elements;
// Helper destroyer function
template <typename T>
struct Deleter
{
static void Delete(T* pObj)
{ delete pObj; }
};
// Concrete lifetime tracker for objects of type T
template <typename T, typename Destroyer>
class ConcreteLifetimeTracker : public LifetimeTracker
{
public:
ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
: LifetimeTracker(longevity)
, pTracked_(p)
, destroyer_(d)
{}
~ConcreteLifetimeTracker()
{ destroyer_(pTracked_); }
private:
T* pTracked_;
Destroyer destroyer_;
};
void AtExitFn(); // declaration needed below
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// function template SetLongevity
// Assigns an object a longevity; ensures ordered destructions of objects
// registered thusly during the exit sequence of the application
////////////////////////////////////////////////////////////////////////////////
template <typename T, typename Destroyer>
void SetLongevity(T* pDynObject, unsigned int longevity,
Destroyer d = Private::Deleter<T>::Delete)
{
using namespace Private;
TrackerArray pNewArray = static_cast<TrackerArray>(
VC_BROKEN_STD::realloc(pTrackerArray, sizeof(*pTrackerArray) * (elements + 1)));
if (!pNewArray) throw std::bad_alloc();
// Delayed assignment for exception safety
pTrackerArray = pNewArray;
LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
pDynObject, longevity, d);
// Insert a pointer to the object into the queue
TrackerArray pos = std::upper_bound(
pTrackerArray,
pTrackerArray + elements,
p,
LifetimeTracker::Compare);
std::copy_backward(
pos,
pTrackerArray + elements,
pTrackerArray + elements + 1);
*pos = p;
++elements;
// Register a call to AtExitFn
VC_BROKEN_STD::atexit(Private::AtExitFn);
}
////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a straight call to the new operator
////////////////////////////////////////////////////////////////////////////////
struct CreateUsingNew
{
template <class T>
static T* Create(const volatile T* p = 0)
{
return new T;
}
template <class T>
static void Destroy(T* p)
{ delete p; }
};
////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a call to std::malloc, followed by a call to the
// placement new operator
////////////////////////////////////////////////////////////////////////////////
struct CreateUsingMalloc
{
template <class T>
static T* Create(const volatile T* dummy = 0)
{
void* p = VC_BROKEN_STD::malloc(sizeof(T));
if (!p) return 0;
return new(p) T;
}
template <class T>
static void Destroy(T* p)
{
p->~T();
VC_BROKEN_STD::free(p);
}
};
////////////////////////////////////////////////////////////////////////////////
// class template CreateStatic
// Implementation of the CreationPolicy used by SingletonHolder
// Creates an object in static memory
// Implementation is slightly nonportable because it uses the MaxAlign trick
// (an union of all types to ensure proper memory alignment). This trick is
// nonportable in theory but highly portable in practice.
////////////////////////////////////////////////////////////////////////////////
struct CreateStatic
{
#ifdef _MSC_VER
#pragma warning( push )
// alignment of a member was sensitive to packing
#pragma warning( disable : 4121 )
#endif // _MSC_VER
template <class T>
union MaxAlign
{
char t_[sizeof(T)];
short int shortInt_;
int int_;
long int longInt_;
float float_;
double double_;
long double longDouble_;
struct Test;
int Test::* pMember_;
int (Test::*pMemberFn_)(int);
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif // _MSC_VER
template <class T>
static T* Create(const volatile T* p = 0)
{
static MaxAlign<T> staticMemory_;
return new(&staticMemory_) T;
}
template <class T>
static void Destroy(T* p)
{
p->~T();
}
};
////////////////////////////////////////////////////////////////////////////////
// class template DefaultLifetime
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules
// Forwards to std::atexit
////////////////////////////////////////////////////////////////////////////////
namespace
{
void Thrower(const char* s) {throw std::logic_error(s); }
}
struct DefaultLifetime
{
template <class T>
static void ScheduleDestruction(T*, void (*pFun)())
{ VC_BROKEN_STD::atexit(pFun); }
template <class T>
static void OnDeadReference(const volatile T* p = 0 )
{
// the throw will yield a C1001-internal compiler error.
// The new level of indirection solves the problem
// throw std::logic_error("Dead Reference Detected");
Thrower("Dead Reference Detected");
}
};
////////////////////////////////////////////////////////////////////////////////
// class template PhoenixSingleton
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules, and it allows object
// recreation by not throwing an exception from OnDeadReference
////////////////////////////////////////////////////////////////////////////////
class PhoenixSingleton
{
private:
template <class T>
struct StaticData
{
static bool destroyedOnce_;
};
public:
template <class T>
static void ScheduleDestruction(T*, void (*pFun)())
{
#ifndef ATEXIT_FIXED
if (!StaticData<T>::destroyedOnce_)
#endif
VC_BROKEN_STD::atexit(pFun);
}
template <class T>
static void OnDeadReference(const volatile T* p = 0 )
{
#ifndef ATEXIT_FIXED
StaticData<T>::destroyedOnce_ = true;
#endif
}
};
#ifndef ATEXIT_FIXED
template <class T>
bool ::Loki::PhoenixSingleton::StaticData<T>::destroyedOnce_ = false;
#endif
////////////////////////////////////////////////////////////////////////////////
// class template Adapter
// Helper for SingletonWithLongevity below
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class T>
struct Adapter
{
void operator()(T*) { pFun_(); return ; }
void (*pFun_)();
};
}
////////////////////////////////////////////////////////////////////////////////
// class template SingletonWithLongevity
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction in order of their longevities
// Assumes a visible function GetLongevity(T*) that returns the longevity of the
// object
////////////////////////////////////////////////////////////////////////////////
class SingletonWithLongevity
{
public:
template <class T>
static void ScheduleDestruction(T* pObj, void (*pFun)())
{
Private::Adapter<T> adapter;
adapter.pFun_ = pFun ;
SetLongevity(pObj, GetLongevity(pObj), adapter);
}
template <class T>
static void OnDeadReference(const volatile T* p = 0 )
{
// the throw will yield a C1001-internal compiler error.
// The new level of indirection solves the problem
// throw std::logic_error("Dead Reference Detected");
Thrower("Dead Reference Detected");
}
};
////////////////////////////////////////////////////////////////////////////////
// class template NoDestroy
// Implementation of the LifetimePolicy used by SingletonHolder
// Never destroys the object
////////////////////////////////////////////////////////////////////////////////
struct NoDestroy
{
template <class T>
static void ScheduleDestruction(T*, void (*)())
{}
template <class T>
static void OnDeadReference(const volatile T* p = 0)
{}
};
////////////////////////////////////////////////////////////////////////////////
// class template SingletonHolder
// Provides Singleton amenities for a type T
// To protect that type from spurious instantiations, you have to protect it
// yourself.
////////////////////////////////////////////////////////////////////////////////
template
<
typename T,
class CreationPolicy = CreateUsingNew,
class LifetimePolicy = DefaultLifetime,
class ThreadingModel = SingleThreaded
>
class SingletonHolder
{
public:
static T& Instance();
private:
// Helpers
static void MakeInstance();
static void DestroySingleton();
// Protection
SingletonHolder();
// Data
typedef typename Apply1<ThreadingModel, T*>::VolatileType VolatileType;
static VolatileType pInstance_;
static bool destroyed_;
};
////////////////////////////////////////////////////////////////////////////////
// SingletonHolder's data
////////////////////////////////////////////////////////////////////////////////
template
<
class T,
class C,
class L,
class M
>
typename SingletonHolder<T, C, L, M>::VolatileType
SingletonHolder<T, C, L, M>::pInstance_;
template
<
class T,
class C,
class L,
class M
>
bool SingletonHolder<T, C, L, M>::destroyed_;
////////////////////////////////////////////////////////////////////////////////
// SingletonHolder::Instance
////////////////////////////////////////////////////////////////////////////////
template
<
class T,
class CreationPolicy,
class LifetimePolicy,
class ThreadingModel
>
inline T& SingletonHolder<T, CreationPolicy,
LifetimePolicy, ThreadingModel>::Instance()
{
if (!pInstance_)
{
MakeInstance();
}
return *pInstance_;
}
////////////////////////////////////////////////////////////////////////////////
// SingletonHolder::MakeInstance (helper for Instance)
////////////////////////////////////////////////////////////////////////////////
template
<
class T,
class CreationPolicy,
class LifetimePolicy,
class ThreadingModel
>
void SingletonHolder<T, CreationPolicy,
LifetimePolicy, ThreadingModel>::MakeInstance()
{
//typename Apply1<ThreadingModel, T>::Lock guard;
typename Apply1<ThreadingModel, SingletonHolder>::Lock guard;
(void)guard;
if (!pInstance_)
{
if (destroyed_)
{
LifetimePolicy::OnDeadReference(pInstance_);
destroyed_ = false;
}
pInstance_ = CreationPolicy::Create(pInstance_);
LifetimePolicy::ScheduleDestruction(pInstance_,
&DestroySingleton);
}
}
template
<
class T,
class CreationPolicy,
class L,
class M
>
void SingletonHolder<T, CreationPolicy, L, M>::DestroySingleton()
{
assert(!destroyed_);
CreationPolicy::Destroy(pInstance_);
pInstance_ = 0;
destroyed_ = true;
}
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// May 21, 2001: Correct the volatile qualifier - credit due to Darin Adler
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 06 2002: ported by Benjamin Kaufmann to MSVC 6.0
// Feb 24, 2003: changed parameter name of CreateUsingMalloc::Create,
// changed SingletonHolder::MakeInstance in accordance with
// Bug-report #691687 B.K.
////////////////////////////////////////////////////////////////////////////////
#endif // SINGLETON_INC_

View file

@ -0,0 +1,420 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: March 20, 2001
#include "SmallObj.h"
#include <cassert>
#include <algorithm>
using namespace Loki;
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Init
// Initializes a chunk object
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Init(VC_BROKEN_STD::size_t blockSize, unsigned char blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
assert((blockSize * blocks) / blockSize == blocks);
pData_ = new unsigned char[blockSize * blocks];
Reset(blockSize, blocks);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Reset
// Clears an already allocated chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Reset(VC_BROKEN_STD::size_t blockSize, unsigned char blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
assert((blockSize * blocks) / blockSize == blocks);
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
unsigned char* p = pData_;
for (; i != blocks; p += blockSize)
{
*p = ++i;
}
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Release
// Releases the data managed by a chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Release()
{
delete[] pData_;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Allocate
// Allocates a block from a chunk
////////////////////////////////////////////////////////////////////////////////
void* FixedAllocator::Chunk::Allocate(VC_BROKEN_STD::size_t blockSize)
{
if (!blocksAvailable_) return 0;
assert((firstAvailableBlock_ * blockSize) / blockSize ==
firstAvailableBlock_);
unsigned char* pResult =
pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Deallocate
// Dellocates a block from a chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Deallocate(void* p, VC_BROKEN_STD::size_t blockSize)
{
assert(p >= pData_);
unsigned char* toRelease = static_cast<unsigned char*>(p);
// Alignment check
assert((toRelease - pData_) % blockSize == 0);
*toRelease = firstAvailableBlock_;
firstAvailableBlock_ = static_cast<unsigned char>(
(toRelease - pData_) / blockSize);
// Truncation check
assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
++blocksAvailable_;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::FixedAllocator
// Creates a FixedAllocator object of a fixed block size
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::FixedAllocator(VC_BROKEN_STD::size_t blockSize)
: blockSize_(blockSize)
, allocChunk_(0)
, deallocChunk_(0)
{
assert(blockSize_ > 0);
prev_ = next_ = this;
VC_BROKEN_STD::size_t numBlocks = DEFAULT_CHUNK_SIZE / blockSize;
if (numBlocks > UCHAR_MAX) numBlocks = UCHAR_MAX;
else if (numBlocks == 0) numBlocks = 8 * blockSize;
numBlocks_ = static_cast<unsigned char>(numBlocks);
assert(numBlocks_ == numBlocks);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::FixedAllocator(const FixedAllocator&)
// Creates a FixedAllocator object of a fixed block size
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::FixedAllocator(const FixedAllocator& rhs)
: blockSize_(rhs.blockSize_)
, numBlocks_(rhs.numBlocks_)
, chunks_(rhs.chunks_)
{
prev_ = &rhs;
next_ = rhs.next_;
rhs.next_->prev_ = this;
rhs.next_ = this;
allocChunk_ = rhs.allocChunk_
? &chunks_.front() + (rhs.allocChunk_ - &rhs.chunks_.front())
: 0;
deallocChunk_ = rhs.deallocChunk_
? &chunks_.front() + (rhs.deallocChunk_ - &rhs.chunks_.front())
: 0;
}
FixedAllocator& FixedAllocator::operator=(const FixedAllocator& rhs)
{
FixedAllocator copy(rhs);
copy.Swap(*this);
return *this;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::~FixedAllocator
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::~FixedAllocator()
{
if (prev_ != this)
{
prev_->next_ = next_;
next_->prev_ = prev_;
return;
}
assert(prev_ == next_);
Chunks::iterator i = chunks_.begin();
for (; i != chunks_.end(); ++i)
{
assert(i->blocksAvailable_ == numBlocks_);
i->Release();
}
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Swap
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Swap(FixedAllocator& rhs)
{
using namespace std;
swap(blockSize_, rhs.blockSize_);
swap(numBlocks_, rhs.numBlocks_);
chunks_.swap(rhs.chunks_);
swap(allocChunk_, rhs.allocChunk_);
swap(deallocChunk_, rhs.deallocChunk_);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Allocate
// Allocates a block of fixed size
////////////////////////////////////////////////////////////////////////////////
void* FixedAllocator::Allocate()
{
if (allocChunk_ == 0 || allocChunk_->blocksAvailable_ == 0)
{
Chunks::iterator i = chunks_.begin();
for (;; ++i)
{
if (i == chunks_.end())
{
// Initialize
chunks_.reserve(chunks_.size() + 1);
Chunk newChunk;
newChunk.Init(blockSize_, numBlocks_);
chunks_.push_back(newChunk);
allocChunk_ = &chunks_.back();
deallocChunk_ = &chunks_.front();
break;
}
if (i->blocksAvailable_ > 0)
{
allocChunk_ = &*i;
break;
}
}
}
assert(allocChunk_ != 0);
assert(allocChunk_->blocksAvailable_ > 0);
return allocChunk_->Allocate(blockSize_);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Deallocate
// Deallocates a block previously allocated with Allocate
// (undefined behavior if called with the wrong pointer)
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Deallocate(void* p)
{
assert(!chunks_.empty());
assert(&chunks_.front() <= deallocChunk_);
assert(&chunks_.back() >= deallocChunk_);
deallocChunk_ = VicinityFind(p);
assert(deallocChunk_);
DoDeallocate(p);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::VicinityFind (internal)
// Finds the chunk corresponding to a pointer, using an efficient search
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::Chunk* FixedAllocator::VicinityFind(void* p)
{
assert(!chunks_.empty());
assert(deallocChunk_);
const VC_BROKEN_STD::size_t chunkLength = numBlocks_ * blockSize_;
Chunk* lo = deallocChunk_;
Chunk* hi = deallocChunk_ + 1;
Chunk* loBound = &chunks_.front();
Chunk* hiBound = &chunks_.back() + 1;
// Special case: deallocChunk_ is the last in the array
if (hi == hiBound) hi = 0;
for (;;)
{
if (lo)
{
if (p >= lo->pData_ && p < lo->pData_ + chunkLength)
{
return lo;
}
if (lo == loBound) lo = 0;
else --lo;
}
if (hi)
{
if (p >= hi->pData_ && p < hi->pData_ + chunkLength)
{
return hi;
}
if (++hi == hiBound) hi = 0;
}
}
assert(false);
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::DoDeallocate (internal)
// Performs deallocation. Assumes deallocChunk_ points to the correct chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::DoDeallocate(void* p)
{
assert(deallocChunk_->pData_ <= p);
assert(deallocChunk_->pData_ + numBlocks_ * blockSize_ > p);
// call into the chunk, will adjust the inner list but won't release memory
deallocChunk_->Deallocate(p, blockSize_);
if (deallocChunk_->blocksAvailable_ == numBlocks_)
{
// deallocChunk_ is completely free, should we release it?
Chunk& lastChunk = chunks_.back();
if (&lastChunk == deallocChunk_)
{
// check if we have two last chunks empty
if (chunks_.size() > 1 &&
deallocChunk_[-1].blocksAvailable_ == numBlocks_)
{
// Two free chunks, discard the last one
lastChunk.Release();
chunks_.pop_back();
allocChunk_ = deallocChunk_ = &chunks_.front();
}
return;
}
if (lastChunk.blocksAvailable_ == numBlocks_)
{
// Two free blocks, discard one
lastChunk.Release();
chunks_.pop_back();
allocChunk_ = deallocChunk_;
}
else
{
// move the empty chunk to the end
std::swap(*deallocChunk_, lastChunk);
allocChunk_ = &chunks_.back();
}
}
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::SmallObjAllocator
// Creates an allocator for small objects given chunk size and maximum 'small'
// object size
////////////////////////////////////////////////////////////////////////////////
SmallObjAllocator::SmallObjAllocator(
VC_BROKEN_STD::size_t chunkSize,
VC_BROKEN_STD::size_t maxObjectSize)
: pLastAlloc_(0), pLastDealloc_(0)
, chunkSize_(chunkSize), maxObjectSize_(maxObjectSize)
{
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::Allocate
// Allocates 'numBytes' memory
// Uses an internal pool of FixedAllocator objects for small objects
////////////////////////////////////////////////////////////////////////////////
void* SmallObjAllocator::Allocate(VC_BROKEN_STD::size_t numBytes)
{
if (numBytes > maxObjectSize_) return operator new(numBytes);
if (pLastAlloc_ && pLastAlloc_->BlockSize() == numBytes)
{
return pLastAlloc_->Allocate();
}
Pool::iterator i = std::lower_bound(pool_.begin(), pool_.end(), numBytes);
if (i == pool_.end() || i->BlockSize() != numBytes)
{
i = pool_.insert(i, FixedAllocator(numBytes));
pLastDealloc_ = &*pool_.begin();
}
pLastAlloc_ = &*i;
return pLastAlloc_->Allocate();
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::Deallocate
// Deallocates memory previously allocated with Allocate
// (undefined behavior if you pass any other pointer)
////////////////////////////////////////////////////////////////////////////////
void SmallObjAllocator::Deallocate(void* p, VC_BROKEN_STD::size_t numBytes)
{
if (numBytes > maxObjectSize_) {operator delete(p); return;}
if (pLastDealloc_ && pLastDealloc_->BlockSize() == numBytes)
{
pLastDealloc_->Deallocate(p);
return;
}
Pool::iterator i = std::lower_bound(pool_.begin(), pool_.end(), numBytes);
assert(i != pool_.end());
assert(i->BlockSize() == numBytes);
pLastDealloc_ = &*i;
pLastDealloc_->Deallocate(p);
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20: fix exception safety issue in FixedAllocator::Allocate
// (thanks to Chris Udazvinis for pointing that out)
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Aug 02, 2002: Fix in VicinityFind sent by Pavel Vozenilek
// Oct 11, 2002: ported by Benjamin Kaufmann to VC 6.0
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,196 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Jan 12, 2003
// changed SmallObject's op new from
// static void* operator new(VC_BROKEN_STD::size_t size);
// to
// static void* operator new(VC_BROKEN_STD::size_t size,
// VC_BROKEN_STD::size_t dummy = 0);
// and removed the ugly #pragma warning(disable:4291)"
// Thanks to M.Yamada for the hint
#ifndef SMALLOBJ_INC_
#define SMALLOBJ_INC_
#include "Threads.h"
#include "Singleton.h"
#include "MSVC6Helpers.h" // for apply-template
#include <cstddef>
#include <vector>
#ifndef DEFAULT_CHUNK_SIZE
#define DEFAULT_CHUNK_SIZE 4096
#endif
#ifndef MAX_SMALL_OBJECT_SIZE
#define MAX_SMALL_OBJECT_SIZE 64
#endif
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class FixedAllocator
// Offers services for allocating fixed-sized objects
////////////////////////////////////////////////////////////////////////////////
class FixedAllocator
{
public: // VC7 access control BUG
class Chunk
{
friend FixedAllocator;
void Init(VC_BROKEN_STD::size_t blockSize, unsigned char blocks);
void* Allocate(VC_BROKEN_STD::size_t blockSize);
void Deallocate(void* p, VC_BROKEN_STD::size_t blockSize);
void Reset(VC_BROKEN_STD::size_t blockSize, unsigned char blocks);
void Release();
unsigned char* pData_;
unsigned char
firstAvailableBlock_,
blocksAvailable_;
};
private:
// Internal functions
void DoDeallocate(void* p);
Chunk* VicinityFind(void* p);
// Data
VC_BROKEN_STD::size_t blockSize_;
unsigned char numBlocks_;
typedef std::vector<Chunk> Chunks;
Chunks chunks_;
Chunk* allocChunk_;
Chunk* deallocChunk_;
// For ensuring proper copy semantics
mutable const FixedAllocator* prev_;
mutable const FixedAllocator* next_;
public:
// Create a FixedAllocator able to manage blocks of 'blockSize' size
explicit FixedAllocator(VC_BROKEN_STD::size_t blockSize = 0);
FixedAllocator(const FixedAllocator&);
FixedAllocator& operator=(const FixedAllocator&);
~FixedAllocator();
void Swap(FixedAllocator& rhs);
// Allocate a memory block
void* Allocate();
// Deallocate a memory block previously allocated with Allocate()
// (if that's not the case, the behavior is undefined)
void Deallocate(void* p);
// Returns the block size with which the FixedAllocator was initialized
VC_BROKEN_STD::size_t BlockSize() const
{ return blockSize_; }
// Comparison operator for sorting
bool operator<(VC_BROKEN_STD::size_t rhs) const
{ return BlockSize() < rhs; }
};
////////////////////////////////////////////////////////////////////////////////
// class SmallObjAllocator
// Offers services for allocating small-sized objects
////////////////////////////////////////////////////////////////////////////////
class SmallObjAllocator
{
public:
SmallObjAllocator(
VC_BROKEN_STD::size_t chunkSize,
VC_BROKEN_STD::size_t maxObjectSize);
void* Allocate(VC_BROKEN_STD::size_t numBytes);
void Deallocate(void* p, VC_BROKEN_STD::size_t size);
private:
SmallObjAllocator(const SmallObjAllocator&);
SmallObjAllocator& operator=(const SmallObjAllocator&);
typedef std::vector<FixedAllocator> Pool;
Pool pool_;
FixedAllocator* pLastAlloc_;
FixedAllocator* pLastDealloc_;
VC_BROKEN_STD::size_t chunkSize_;
VC_BROKEN_STD::size_t maxObjectSize_;
};
////////////////////////////////////////////////////////////////////////////////
// class SmallObject
// Base class for polymorphic small objects, offers fast
// allocations/deallocations
////////////////////////////////////////////////////////////////////////////////
template
<
class ThreadingModel = DEFAULT_THREADING,
VC_BROKEN_STD::size_t chunkSize = DEFAULT_CHUNK_SIZE,
VC_BROKEN_STD::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE
>
class SmallObject : public
Apply1<ThreadingModel, SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >
{
typedef typename Apply1<ThreadingModel, SmallObject<ThreadingModel,
chunkSize, maxSmallObjectSize> > MyThreadingModel;
struct MySmallObjAllocator : public SmallObjAllocator
{
MySmallObjAllocator()
: SmallObjAllocator(chunkSize, maxSmallObjectSize)
{}
};
// The typedef below would make things much simpler,
// but MWCW won't like it
// typedef SingletonHolder<MySmallObjAllocator/*, CreateStatic,
// DefaultLifetime, ThreadingModel*/> MyAllocator;
public:
static void* operator new(VC_BROKEN_STD::size_t size, VC_BROKEN_STD::size_t dummy = 0)
{
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return SingletonHolder<MySmallObjAllocator, CreateStatic,
PhoenixSingleton>::Instance().Allocate(size);
#else
return ::operator new(size);
#endif
}
static void operator delete(void* p, VC_BROKEN_STD::size_t size)
{
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0)
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
SingletonHolder<MySmallObjAllocator, CreateStatic,
PhoenixSingleton>::Instance().Deallocate(p, size);
#else
::operator delete(p, size);
#endif
}
virtual ~SmallObject() {}
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 11, 2002: ported by Benjamin Kaufmann to MSVC 6.0
////////////////////////////////////////////////////////////////////////////////
#endif // SMALLOBJ_INC_

1498
include/noncc/MSVC/1200/SmartPtr.h Executable file

File diff suppressed because it is too large Load diff

228
include/noncc/MSVC/1200/Threads.h Executable file
View file

@ -0,0 +1,228 @@
#ifndef THREADS_H_
#define THREADS_H_
////////////////////////////////////////////////////////////////////////////////
// macro DEFAULT_THREADING
// Selects the default threading model for certain components of Loki
// If you don't define it, it defaults to single-threaded
// All classes in Loki have configurable threading model; DEFAULT_THREADING
// affects only default template arguments
////////////////////////////////////////////////////////////////////////////////
// Last update: Mar 26, 2003
// note: In this VC 6 port all template policies become non-templates with
// either member-template functions or a nested template struct named In
// Changed wrong ctor/dtor names in ObjectLevelLockable.
// Thanks to Adi Shavit for pointing that out
#ifndef DEFAULT_THREADING
#define DEFAULT_THREADING /**/ ::Loki::SingleThreaded
#endif
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template SingleThreaded
// Implementation of the ThreadingModel policy used by various classes
// Implements a single-threaded model; no synchronization
////////////////////////////////////////////////////////////////////////////////
class SingleThreaded
{
public:
template <class Host>
struct In
{
struct Lock
{
Lock() {}
explicit Lock(const SingleThreaded&) {}
};
typedef Host VolatileType;
typedef int IntType;
static IntType AtomicAdd(volatile IntType& lval, IntType val)
{ return lval += val; }
static IntType AtomicSubtract(volatile IntType& lval, IntType val)
{ return lval -= val; }
static IntType AtomicMultiply(volatile IntType& lval, IntType val)
{ return lval *= val; }
static IntType AtomicDivide(volatile IntType& lval, IntType val)
{ return lval /= val; }
static IntType AtomicIncrement(volatile IntType& lval)
{ return ++lval; }
static IntType AtomicDecrement(volatile IntType& lval)
{ return --lval; }
// The following function uses the undefined variable val.
// Moreover I couldn't find the function in the orginial loki-lib.
// I therefore commented the function out
/*
static IntType AtomicDivide(volatile IntType& lval)
{ return lval /= val; }
*/
static void AtomicAssign(volatile IntType & lval, IntType val)
{ lval = val; }
static void AtomicAssign(IntType & lval, volatile IntType & val)
{ lval = val; }
};
};
#ifdef _WINDOWS_
////////////////////////////////////////////////////////////////////////////////
// class template ObjectLevelLockable
// Implementation of the ThreadingModel policy used by various classes
// Implements a object-level locking scheme
////////////////////////////////////////////////////////////////////////////////
struct ObjectLevelLockable
{
template <class Host>
struct In
{
private:
CRITICAL_SECTION mtx_;
public:
In()
{
::InitializeCriticalSection(&mtx_);
}
~In()
{
::DeleteCriticalSection(&mtx_);
}
class Lock;
friend class Lock;
class Lock
{
ObjectLevelLockable::In<Host>& host_;
Lock(const Lock&);
Lock& operator=(const Lock&);
//Lock(); // buggy design
public:
explicit Lock(ObjectLevelLockable::In<Host>& host) : host_(host)
{
::EnterCriticalSection(&host_.mtx_);
}
~Lock()
{
::LeaveCriticalSection(&host_.mtx_);
}
};
typedef volatile Host VolatileType;
typedef LONG IntType;
static IntType AtomicIncrement(volatile IntType& lval)
{ return InterlockedIncrement(&const_cast<IntType&>(lval)); }
static IntType AtomicDecrement(volatile IntType& lval)
{ return InterlockedDecrement(&const_cast<IntType&>(lval)); }
static void AtomicAssign(volatile IntType& lval, IntType val)
{ InterlockedExchange(&const_cast<IntType&>(lval), val); }
static void AtomicAssign(IntType& lval, volatile IntType& val)
{ InterlockedExchange(&lval, val); }
};
};
struct ClassLevelLockable
{
template <class Host>
struct In
{
public:
struct Initializer;
friend struct Initializer;
struct Initializer
{
CRITICAL_SECTION mtx_;
Initializer()
{
::InitializeCriticalSection(&mtx_);
}
~Initializer()
{
::DeleteCriticalSection(&mtx_);
}
};
static Initializer initializer_;
public:
class Lock;
friend class Lock;
class Lock
{
Lock(const Lock&);
Lock& operator=(const Lock&);
public:
Lock()
{
::EnterCriticalSection(&initializer_.mtx_);
}
explicit Lock(ClassLevelLockable&)
{
::EnterCriticalSection(&initializer_.mtx_);
}
~Lock()
{
::LeaveCriticalSection(&initializer_.mtx_);
}
};
typedef volatile Host VolatileType;
typedef LONG IntType;
static IntType AtomicIncrement(volatile IntType& lval)
{ return InterlockedIncrement(&const_cast<IntType&>(lval)); }
static IntType AtomicDecrement(volatile IntType& lval)
{ return InterlockedDecrement(&const_cast<IntType&>(lval)); }
static void AtomicAssign(volatile IntType& lval, IntType val)
{ InterlockedExchange(&const_cast<IntType&>(lval), val); }
static void AtomicAssign(IntType& lval, volatile IntType& val)
{ InterlockedExchange(&lval, val); }
};
};
template <class Host>
typename Loki::ClassLevelLockable::template In<Host>::Initializer
Loki::ClassLevelLockable::template In<Host>::initializer_;
#endif
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 06, 2002: ported by Benjamin Kaufmann to MSVC 6.0
// Feb 20, 2003: corrected constructor parameter in ObjectLevelLockable::Lock
// Mar 26, 2003: added Loki-Namespace-Qualification to definition of
// ClassLevelLockable's static member.
////////////////////////////////////////////////////////////////////////////////
#endif

22
include/noncc/MSVC/1200/Tuple.h Executable file
View file

@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
////////////////////////////////////////////////////////////////////////////////
// This file is intentionally left empty
// Due to compiler limitations, its contents has been moved to
// HierarchyGenerators.h
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,269 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: Oct 17, 2002
#include "static_check.h"
#ifndef TYPEMANIP_INC_
#define TYPEMANIP_INC_
namespace Loki
{
namespace Private
{
typedef char YES;
struct NO {char dummy[3];};
}
////////////////////////////////////////////////////////////////////////////////
// class template Int2Type
// Converts each integral constant into a unique type
// Invocation: Int2Type<v> where v is a compile-time constant integral
// Defines 'value', an enum that evaluates to v
////////////////////////////////////////////////////////////////////////////////
template <int v>
struct Int2Type
{
Int2Type() {}
enum { value = v };
};
////////////////////////////////////////////////////////////////////////////////
// class template Type2Type
// Converts each type into a unique, insipid type
// Invocation Type2Type<T> where T is a type
// Defines the type OriginalType which maps back to T
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct Type2Type
{
typedef T OriginalType;
Type2Type() {};
};
////////////////////////////////////////////////////////////////////////////////
// class template Select
// Selects one of two types based upon a boolean constant
// Invocation: Select<flag, T, U>::Result
// where:
// flag is a compile-time boolean constant
// T and U are types
// Result evaluates to T if flag is true, and to U otherwise.
////////////////////////////////////////////////////////////////////////////////
// VC6 compatible version
namespace Private
{
template <bool>
struct SelectImpl
{
template <class T, class U>
struct In
{
typedef T Result;
};
};
template <>
struct SelectImpl<false>
{
template <class T, class U>
struct In
{
typedef U Result;
};
};
} // end of namespace private
template <bool flag, typename T, typename U>
struct Select
{
typedef typename Private::SelectImpl<flag>::template In<T, U>::Result Result;
};
////////////////////////////////////////////////////////////////////////////////
// class template IsEqualType
// Returns true if the two given types are equal
// Invocation: IsEqualType<T, U>::value
// where:
// T and U are types
// Result evaluates to true if U == T (types equal)
////////////////////////////////////////////////////////////////////////////////
// This template is not in the original Loki-Library
template <class T, class U>
struct IsEqualType
{
private:
static Private::YES check(Type2Type<T>);
static Private::NO check(...);
public:
enum {value = sizeof(check(Type2Type<U>())) == sizeof(Private::YES)};
};
////////////////////////////////////////////////////////////////////////////////
// Helper types Small and Big - guarantee that sizeof(Small) < sizeof(Big)
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
typedef char Small;
class Big { char dummy[2]; };
// IsVoid from Rani Sharoni's VC 7 port
template<typename T>
struct IsVoid
{
enum { value =
IsEqualType<T, void>::value ||
IsEqualType<T, const void>::value ||
IsEqualType<T, volatile void>::value ||
IsEqualType<T, const volatile void>::value
};
};
}
//
// is one type convertable to another?
//
// is_convertible from Rani Sharoni's VC 7 port.
template <class T, class U>
class is_convertible
{
struct VoidReplace {};
typedef typename Select
<
Private::IsVoid<T>::value,
VoidReplace, T
>
::Result T1;
typedef typename Select
<
Private::IsVoid<U>::value,
VoidReplace, U
>
::Result U1;
static Private::Big Test(...);
static Private::Small Test(U1);
static T1 MakeT();
public:
enum { exists = sizeof(Test(MakeT())) == sizeof(Private::Small) };
};
////////////////////////////////////////////////////////////////////////////////
// class template Conversion
// Figures out the conversion relationships between two types
// Invocations (T and U are types):
// a) Conversion<T, U>::exists
// returns (at compile time) true if there is an implicit conversion from T
// to U (example: Derived to Base)
// b) Conversion<T, U>::exists2Way
// returns (at compile time) true if there are both conversions from T
// to U and from U to T (example: int to char and back)
// c) Conversion<T, U>::sameType
// returns (at compile time) true if T and U represent the same type
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
// Conversion-Template from Rani Sharoni's VC 7 port.
template <class T, class U>
struct Conversion
{
enum { exists = (is_convertible<T,U>::exists) };
enum { exists2Way = (exists && is_convertible<U, T>::exists) };
enum { sameType = (IsEqualType<T, U>::value) };
};
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclass
// Invocation: SuperSubclass<B, D>::value where B and D are types.
// Returns true if B is a public base of D, or if B and D are aliases of the
// same type.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template <class T, class U>
struct SuperSubclass
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
};
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclassStrict
// Invocation: SuperSubclassStrict<B, D>::value where B and D are types.
// Returns true if B is a public base of D.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template<class T,class U>
struct SuperSubclassStrict
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType &&
!::Loki::Conversion<const volatile T*, const volatile U*>::sameType) };
};
////////////////////////////////////////////////////////////////////////////////
// macro SUPERSUBCLASS
// Invocation: SUPERSUBCLASS(B, D) where B and D are types.
// Returns true if B is a public base of D, or if B and D are aliases of the
// same type.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
#define SUPERSUBCLASS(T, U) \
(::Loki::Conversion<const volatile U*, const volatile T*>::exists && \
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType)
////////////////////////////////////////////////////////////////////////////////
// macro SUPERSUBCLASS
// Invocation: SUPERSUBCLASS(B, D) where B and D are types.
// Returns true if B is a public base of D.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
#define SUPERSUBCLASS_STRICT(T, U) \
(SUPERSUBCLASS(T, U) && \
!::Loki::Conversion<const volatile T *, const volatile U *>::sameType)
template <unsigned i>
struct TypeTag
{
struct Inner {char c[i];};
typedef Inner X;
STATIC_SIZE_ASSERT(X, i);
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
// Sept 29, 2002: ported by Benjamin Kaufmann to MSVC 6
////////////////////////////////////////////////////////////////////////////////
#endif // TYPEMANIP_INC_

View file

@ -0,0 +1,471 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: Feb 16, 2003
// Added isFunctionPointer to TypeTraits.
//
// This VC 6 port of TypeTraits is based on Rani Sharoni's Loki VC 7 port.
// Reference, pointer, array, const and volatile detection is based on
// boost's type traits.
// see http://www.boost.org/libs/type_traits/
//
// The code for Enum- and pointer-to-member-function detection is based on
// ideas from M. Yamada - many thanks :)
//
// AdjReference has moved to namespace-scope. Explicit specialization is
// only allowed there.
//
// known bugs:
// assert(TypeTraits<const void>::isConst == 1) fails.
// assert(TypeTraits<volatile void>::isVolatile == 1) fails.
// assert(TypeTraits<const volatile void>::isConst == 1) fails.
// assert(TypeTraits<const volatile void>::isVolatile == 1) fails.
// This is because the VC 6 does not differentiate
// between void, const void, volatile void and const volatile void.
#ifndef TYPETRAITS_INC_
#define TYPETRAITS_INC_
//
// Ignore forcing value to bool 'true' or 'false' (performance warning)
//
#ifdef _MSC_VER
#include <cctype> // for wchar_t
#pragma warning (disable: 4800)
#endif
#include "Typelist.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomUnsignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomUnsignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in unsigned
// integral type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomUnsignedInt
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomSignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomSignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in signed
// integral type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomSignedInt
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomFloat
// Offers a means to integrate nonstandard floating point types with the
// TypeTraits class template defined below.
// Invocation: IsCustomFloat<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in
// floating point type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomFloat
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// Helper types for class template TypeTraits defined below
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
typedef TYPELIST_4(unsigned char, unsigned short int,
unsigned int, unsigned long int) StdUnsignedInts;
typedef TYPELIST_4(signed char, short int,
int, long int) StdSignedInts;
typedef TYPELIST_3(bool, char, wchar_t) StdOtherInts;
typedef TYPELIST_3(float, double, long double) StdFloats;
}
////////////////////////////////////////////////////////////////////////////////
// class template TypeTraits
// Figures out various properties of any given type
// Invocations (T is a type):
// a) TypeTraits<T>::isPointer
// returns (at compile time) true if T is a pointer type
// b) TypeTraits<T>::PointeeType
// returns the type to which T points is T is a pointer type, NullType otherwise
// a) TypeTraits<T>::isReference
// returns (at compile time) true if T is a reference type
// b) TypeTraits<T>::ReferredType
// returns the type to which T refers is T is a reference type, NullType
// otherwise
// c) TypeTraits<T>::isMemberPointer
// returns (at compile time) true if T is a pointer to member type
// d) TypeTraits<T>::isStdUnsignedInt
// returns (at compile time) true if T is a standard unsigned integral type
// e) TypeTraits<T>::isStdSignedInt
// returns (at compile time) true if T is a standard signed integral type
// f) TypeTraits<T>::isStdIntegral
// returns (at compile time) true if T is a standard integral type
// g) TypeTraits<T>::isStdFloat
// returns (at compile time) true if T is a standard floating-point type
// h) TypeTraits<T>::isStdArith
// returns (at compile time) true if T is a standard arithmetic type
// i) TypeTraits<T>::isStdFundamental
// returns (at compile time) true if T is a standard fundamental type
// j) TypeTraits<T>::isUnsignedInt
// returns (at compile time) true if T is a unsigned integral type
// k) TypeTraits<T>::isSignedInt
// returns (at compile time) true if T is a signed integral type
// l) TypeTraits<T>::isIntegral
// returns (at compile time) true if T is a integral type
// m) TypeTraits<T>::isFloat
// returns (at compile time) true if T is a floating-point type
// n) TypeTraits<T>::isArith
// returns (at compile time) true if T is a arithmetic type
// o) TypeTraits<T>::isFundamental
// returns (at compile time) true if T is a fundamental type
// p) TypeTraits<T>::ParameterType
// returns the optimal type to be used as a parameter for functions that take Ts
// q) TypeTraits<T>::isConst
// returns (at compile time) true if T is a const-qualified type
// r) TypeTraits<T>::NonConstType
// removes the 'const' qualifier from T, if any
// s) TypeTraits<T>::isVolatile
// returns (at compile time) true if T is a volatile-qualified type
// t) TypeTraits<T>::NonVolatileType
// removes the 'volatile' qualifier from T, if any
// u) TypeTraits<T>::UnqualifiedType
// removes both the 'const' and 'volatile' qualifiers from T, if any
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
// const-detection based on boost's
// Type-Traits. See: boost\type_traits\is_const.hpp
YES IsConstTester(const volatile void*);
NO IsConstTester(volatile void *);
template <bool is_ref, bool array>
struct IsConstImpl
{
template <class T> struct In {enum {value=0};};
};
template <>
struct IsConstImpl<false,false>
{
template <typename T> struct In
{
static T* t;
enum {value = sizeof(YES) == sizeof(IsConstTester(t))};
};
};
template <>
struct IsConstImpl<false,true>
{
template <typename T> struct In
{
static T t;
enum { value = sizeof(YES) == sizeof(IsConstTester(&t)) };
};
};
// this volatile-detection approach is based on boost's
// Type-Traits. See: boost\type_traits\is_volatile.hpp
YES IsVolatileTester(void const volatile*);
NO IsVolatileTester(void const*);
template <bool is_ref, bool array>
struct IsVolatileImpl
{
template <typename T> struct In
{
enum {value = 0};
};
};
template <>
struct IsVolatileImpl<false,false>
{
template <typename T> struct In
{
static T* t;
enum {value = sizeof(YES) == sizeof(IsVolatileTester(t))};
};
};
template <>
struct IsVolatileImpl<false,true>
{
template <typename T> struct In
{
static T t;
enum {value = sizeof(YES) == sizeof(IsVolatileTester(&t))};
};
};
template<bool IsRef>
struct AdjReference
{
template<typename U>
struct In { typedef U const & Result; };
};
template<>
struct AdjReference<true>
{
template<typename U>
struct In { typedef U Result; };
};
struct PointerHelper
{
PointerHelper(const volatile void*);
};
template <class T>
NO EnumDetection(T);
template <class T>
YES EnumDetection(...);
YES IsPointer(PointerHelper);
NO IsPointer(...);
// With the VC 6. Rani Sharoni's approach to detect references unfortunately
// results in an error C1001: INTERNAL COMPILER-ERROR
//
// this reference-detection approach is based on boost's
// Type-Traits. See: boost::composite_traits.h
//
// is_reference_helper1 is a function taking a Type2Type<T> returning
// a pointer to a function taking a Type2Type<T> returning a T&.
// This function can only be used if T is not a reference-Type.
// If T is a reference Type the return type would be
// a function taking a Type2Type<T> returning a reference to a T-reference.
// That is illegal, therefore is_reference_helper1(...) is used for
// references.
// In order to detect a reference, use the return-type of is_reference_helper1
// with is_reference_helper2.
//
template <class U>
U&(* IsReferenceHelper1(::Loki::Type2Type<U>) )(::Loki::Type2Type<U>);
NO IsReferenceHelper1(...);
template <class U>
NO IsReferenceHelper2(U&(*)(::Loki::Type2Type<U>));
YES IsReferenceHelper2(...);
template <class U, class Z>
YES IsPointer2Member(Z U::*);
NO IsPointer2Member(...);
// this array-detection approach is based on boost's
// Type-Traits. See: boost::array_traits.hpp
// This function can only be used for non-array-types, because
// functions can't return arrays.
template<class U>
U(* IsArrayTester1(::Loki::Type2Type<U>) )(::Loki::Type2Type<U>);
char IsArrayTester1(...);
template<class U>
NO IsArrayTester2(U(*)(::Loki::Type2Type<U>));
YES IsArrayTester2(...);
// Helper functions for function-pointer detection.
// The code uses the fact, that arrays of functions are not allowed.
// Of course TypeTraits first makes sure that U is neither void
// nor a reference.type.
// The idea for this code is from D Vandevoorde's & N. Josuttis'
// book "C++ Templates".
template<class U>
NO IsFunctionPtrTester1(U*, U(*)[1] = 0);
YES IsFunctionPtrTester1(...);
}
template <typename T>
class TypeTraits
{
public:
enum { isVoid = Private::IsVoid<T>::value};
enum { isStdUnsignedInt =
TL::IndexOf<Private::StdUnsignedInts, T>::value >= 0 };
enum { isStdSignedInt =
TL::IndexOf<Private::StdSignedInts, T>::value >= 0 };
enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt ||
TL::IndexOf<Private::StdOtherInts, T>::value >= 0 };
enum { isStdFloat = TL::IndexOf<Private::StdFloats, T>::value >= 0 };
enum { isStdArith = isStdIntegral || isStdFloat };
enum { isStdFundamental = isStdArith || isStdFloat || isVoid };
enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<T>::value };
enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<T>::value };
enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt };
enum { isFloat = isStdFloat || IsCustomFloat<T>::value };
enum { isArith = isIntegral || isFloat };
enum { isFundamental = isStdFundamental || isArith || isFloat };
enum { isArray = sizeof(Private::YES)
== sizeof(Private::IsArrayTester2(
Private::IsArrayTester1(::Loki::Type2Type<T>()))
)
};
enum { isReference = sizeof(Private::YES)
== sizeof(Private::IsReferenceHelper2(
Private::IsReferenceHelper1(::Loki::Type2Type<T>()))
) && !isVoid
};
enum { isConst = Private::IsConstImpl
<isReference, isArray>::template In<T>::value
};
enum { isVolatile = Private::IsVolatileImpl
<isReference, isArray>::template In<T>::value
};
private:
typedef typename Private::AdjReference<isReference || isVoid>::
template In<T>::Result AdjType;
struct is_scalar
{
private:
struct BoolConvert { BoolConvert(bool); };
static Private::YES check(BoolConvert);
static Private::NO check(...);
struct NotScalar {};
typedef typename Select
<
isVoid || isReference || isArray,
NotScalar, T
>
::Result RetType;
// changed to RetType& to allow testing of abstract classes
static RetType& get();
public:
enum { value = sizeof(check(get())) == sizeof(Private::YES) };
}; // is_scalar
public:
enum { isScalar = is_scalar::value};
typedef typename Select
<
isScalar || isArray, T, AdjType
>
::Result ParameterType;
private:
typedef typename Loki::Select
<
isScalar,
T,
int
>::Result TestType;
static TestType MakeT();
enum { isMemberPointerTemp = sizeof(Private::YES)
== sizeof(Private::IsPointer2Member(MakeT()))
};
public:
enum {isPointer = sizeof(Private::YES)
== sizeof(Private::IsPointer(MakeT()))};
private:
typedef typename Loki::Select
<
isVoid || isReference || !isPointer,
int*,
T
>::Result MayBeFuncPtr;
public:
// enum types are the only scalar types that can't be initialized
// with 0.
// Because we replace all non scalars with int,
// template <class T>
// YES EnumDetection(...);
// will only be selected for enums.
enum { isEnum = sizeof(Private::YES)
== sizeof (Private::EnumDetection<TestType>(0))
};
enum { isMemberFunctionPointer = isScalar && !isArith && !isPointer &&
!isMemberPointerTemp && !isEnum
};
enum { isMemberPointer = isMemberPointerTemp || isMemberFunctionPointer};
enum { isFunctionPointer = sizeof(Private::YES)
== sizeof(
Private::IsFunctionPtrTester1(MayBeFuncPtr(0))
) && !isMemberPointer
};
//
// We get is_class for free
// BUG - fails with functions types (ICE) and unknown size array
// (but works for other incomplete types)
// (the boost one (Paul Mensonides) is better)
//
enum { isClass =
!isScalar &&
!isArray &&
!isReference &&
!isVoid &&
!isEnum
};
};
}
#ifdef _MSC_VER
#pragma warning (default: 4800)
#endif
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
// Oct 05, 2002: ported by Benjamin Kaufmann to MSVC 6
// Jan 31, 2003: fixed bugs in scalar and array detection.
// Added isMemberFuncPointer and isEnum. B.K.
//
// Feb 16, 2003: fixed bug in reference-Detection. Renamed isMemberFuncPointer
// to isMemberFunctionPointer. Added isFunctionPointer, replaced
// all occurrences of Private::Wrap with Loki::Type2Type and
// cleaned up the TypeTraits-class. B.K.
////////////////////////////////////////////////////////////////////////////////
#endif // TYPETRAITS_INC_

1148
include/noncc/MSVC/1200/Typelist.h Executable file

File diff suppressed because it is too large Load diff

520
include/noncc/MSVC/1200/Visitor.h Executable file
View file

@ -0,0 +1,520 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Mar 06, 2003
//
// Like the original library, this port now uses void as
// default value for return types.
//
// This new of visitor.h handles void returns transparently. See
// readme.txt for an explanation of the used technique.
// However there are still two sets of macros. One for return type = void
// (DEFINE_VISITABLE_VOID, DEFINE_CYCLIC_VISITABLE_VOID) and one for return
// type != void (DEFINE_VISITABLE, DEFINE_CYCLIC_VISITABLE)
//
// If you prefer the old version of visitor.h which uses a different set of
// visitor classes for the return type void, define the macro
// USE_VISITOR_OLD_VERSION.
//
#ifdef USE_VISITOR_OLD_VERSION
#include "VisitorOld.h"
#else
#ifndef VISITOR_INC_
#define VISITOR_INC_
#include "Typelist.h"
#include "HierarchyGenerators.h"
#include "MSVC6Helpers.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitor
// The base class of any Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
class BaseVisitor
{
public:
virtual ~BaseVisitor() {}
};
////////////////////////////////////////////////////////////////////////////////
// class template Visitor
// The building block of Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
template <class T, typename R = Loki::Private::VoidWrap::type >
class Visitor;
////////////////////////////////////////////////////////////////////////////////
// class template Visitor (specialization)
// This specialization is not present in the book. It makes it easier to define
// Visitors for multiple types in a shot by using a typelist. Example:
//
// class SomeVisitor :
// public BaseVisitor // required
// public Visitor<TYPELIST_2(RasterBitmap, Paragraph)>,
// public Visitor<Paragraph>
// {
// public:
// void Visit(RasterBitmap&); // visit a RasterBitmap
// void Visit(Paragraph &); // visit a Paragraph
// };
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
// helper for Visitor's the left base class
template <unsigned int ListId>
struct VisitorImplLeft
{
template <class TList, class R>
struct In
{
typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
// helper for Visitor's the right base class
template <unsigned int ListId>
struct VisitorImplRight
{
template <class TList, class R>
struct In
{
typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
// simulates specialization
// class Visitor<Head, R>
template <>
struct VisitorImplLeft<TL::Private::NoneList_ID>
{
template <class T, class R>
struct In
{
struct Result
{
typedef R ReturnType;
virtual ReturnType Visit(T&) = 0;
};
};
};
// simulates the left base class for the specialization
// class Visitor<Typelist<Head, Tail>, R>
template <>
struct VisitorImplLeft<TL::Private::Typelist_ID>
{
template <class TList, class R>
struct In
{
typedef Visitor<typename TList::Head, R> Result;
};
};
template <>
struct VisitorImplRight<TL::Private::NoneList_ID>
{
template <class TList, class R>
struct In
{
struct Result {};
};
};
// simulates the right base class for the specialization
// class Visitor<Typelist<Head, Tail>, R>
template <>
struct VisitorImplRight<TL::Private::Typelist_ID>
{
template <class TList, class R>
struct In
{
typedef Visitor<typename TList::Tail, R> Result;
};
};
template <>
struct VisitorImplRight<TL::Private::AtomList_ID>
{
template <class TList, class R>
struct In
{
struct Result {};
};
};
// MSVC 6.0 will complain if we try to let Visitor inherit
// directly from VisitorImplLeft/VisitorImplRight
template <class T, class R>
struct VisitorImplLeftWrap
{
struct Dummy{};
typedef typename VisitorImplLeft
<
TL::Private::IsTypelist<T>::type_id == TL::Private::AtomList_ID ?
TL::Private::Typelist_ID :
TL::Private::IsTypelist<T>::type_id
>::template In<T, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
template <class T, class R>
struct VisitorImplRightWrap
{
struct Dummy{};
typedef typename VisitorImplRight
<
TL::Private::IsTypelist<T>::type_id
>::template In<T, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
}
template <class T, typename R>
class Visitor : public Private::VisitorImplLeftWrap<T, R>::Result,
public Private::VisitorImplRightWrap<T, R>::Result
{
public:
typedef R ReturnType;
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitorImpl
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class TList, typename R = Loki::Private::VoidWrap::type >
class BaseVisitorImpl;
namespace Private
{
template <unsigned int ListTag>
struct BaseVisitorImplHelper
{
template <typename T, typename R>
struct In
{
typedef typename T::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::Private::Typelist_ID>
{
template <typename TList, typename R>
struct In
{
typedef BaseVisitorImpl<TList, R> Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::Private::NullType_ID>
{
template <typename TList, typename R>
struct In
{
struct Result {};
};
};
template <class T, class R>
struct BaseVisitorImplWrap
{
struct Dummy {};
typedef typename BaseVisitorImplHelper
<
TL::Private::IsTypelist<typename T::Tail>::
type_id == TL::Private::AtomList_ID ?
TL::Private::Typelist_ID :
TL::Private::IsTypelist<typename T::Tail>::type_id
>::template In<typename T::Tail, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
template <class TList, class R>
struct BaseVisitorImplBase : public Visitor<typename TList::Head, R>,
public Private::BaseVisitorImplWrap<TList, R>::Result
{
ASSERT_TYPELIST(TList);
virtual R Visit(typename TList::Head&)
{ return R(); }
protected:
~BaseVisitorImplBase() {}
};
template <class TList, class R>
struct BaseVisitorImplVoidBase : public Visitor<typename TList::Head, R>,
public Private::BaseVisitorImplWrap<TList, R>::Result
{
ASSERT_TYPELIST(TList);
virtual R Visit(typename TList::Head&)
{ }
protected:
~BaseVisitorImplVoidBase() {}
};
}
template <class TList, typename R>
class BaseVisitorImpl : public Select
<
Private::IsVoid<R>::value,
Private::BaseVisitorImplVoidBase<TList,R>,
Private::BaseVisitorImplBase<TList, R>
>::Result
{
ASSERT_TYPELIST(TList);
public:
// using BaseVisitorImpl<Tail, R>::Visit;
};
////////////////////////////////////////////////////////////////////////////////
// class template DefaultCatchAll
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename Visited>
struct DefaultCatchAll
{
static R OnUnknownVisitor(Visited&, BaseVisitor&)
{ return R(); }
};
template <typename R, typename Visited>
struct DefaultCatchAllVoid
{
static R OnUnknownVisitor(Visited&, BaseVisitor&)
{ }
};
// template template parameter workaround.
// use Wrapper-Classes like this to instantiate BaseVisitable
struct DefaultCatchAllWrapper
{
template <class R, class Visited>
struct In
{
typedef typename Select<Private::IsVoid<R>::value,
DefaultCatchAllVoid<R, Visited>,
DefaultCatchAll<R, Visited>
>::Result type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template NonStrictVisitor
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class T, class Base>
struct NonStrictVisitorUnit : public Base
{
typedef typename Base::ReturnType ReturnType;
ReturnType Visit(T&)
{
return ReturnType();
}
};
template <class T, class Base>
struct NonStrictVisitorUnitVoid : public Base
{
typedef typename Base::ReturnType ReturnType;
ReturnType Visit(T&)
{}
};
struct NonStrictVisitorUnitWrapper
{
template <class T, class B>
struct In
{
typedef typename B::ReturnType R;
typedef typename Select<Private::IsVoid<R>::value,
NonStrictVisitorUnitVoid<T, B>,
NonStrictVisitorUnit<T, B>
>::Result type;
};
};
template <class TList, typename R = Loki::Private::VoidWrap::type>
class NonStrictVisitor
: public GenLinearHierarchy<
TList,
NonStrictVisitorUnitWrapper,
Visitor<TList, R> >
{
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitable
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class R, class CatchAll>
class BaseVisitableBase
{
typedef R ReturnType;
protected:
template <class T>
static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
{
typedef ApplyInnerType2<CatchAll, R, T>::type CatchA;
// Apply the Acyclic Visitor
if (Visitor<T, R>* p = dynamic_cast<Visitor<T, R>*>(&guest))
{
return p->Visit(visited);
}
return CatchA::OnUnknownVisitor(visited, guest);
}
~BaseVisitableBase() {}
};
template <class R, class CatchAll>
class BaseVisitableVoidBase
{
typedef R ReturnType;
protected:
template <class T>
static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
{
typedef ApplyInnerType2<CatchAll, R, T>::type CatchA;
// Apply the Acyclic Visitor
if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest))
{
p->Visit(visited);
return;
}
CatchA::OnUnknownVisitor(visited, guest);
}
~BaseVisitableVoidBase() {}
};
}
template
<
typename R = Loki::Private::VoidWrap::type,
class CatchAll = DefaultCatchAllWrapper
>
class BaseVisitable : public Select<Private::IsVoid<R>::value,
Private::BaseVisitableVoidBase<R, CatchAll>,
Private::BaseVisitableBase<R, CatchAll>
>::Result
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {}
virtual ReturnType Accept(BaseVisitor&) = 0;
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_VISITABLE
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_VISITABLE() \
virtual ReturnType Accept(Loki::BaseVisitor& guest) \
{ return AcceptImpl(*this, guest); }
#define DEFINE_VISITABLE_VOID() \
virtual ReturnType Accept(Loki::BaseVisitor& guest) \
{ AcceptImpl(*this, guest); }
////////////////////////////////////////////////////////////////////////////////
// class template CyclicVisitor
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <typename R, class TList>
class CyclicVisitorBase : public Visitor<TList, R>
{
public:
template <class Visited>
ReturnType GenericVisit(Visited& host)
{
Visitor<Visited, ReturnType>& subObj = *this;
return subObj.Visit(host);
}
protected:
~CyclicVisitorBase() {}
};
template <class TList>
class CyclicVisitorVoidBase : public Visitor<TList, void>
{
public:
template <class Visited>
ReturnType GenericVisit(Visited& host)
{
Visitor<Visited, ReturnType>& subObj = *this;
subObj.Visit(host);
}
protected:
~CyclicVisitorVoidBase() {}
};
}
template <typename R, class TList>
class CyclicVisitor : public Select<Private::IsVoid<R>::value,
Private::CyclicVisitorVoidBase<TList>,
Private::CyclicVisitorBase<R, TList>
>::Result
{
public:
typedef R ReturnType;
// using Visitor<TList, R>::Visit;
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_CYCLIC_VISITABLE
// Put it in every class that you want to make visitable by a cyclic visitor
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_CYCLIC_VISITABLE(SomeVisitor) \
virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \
{ return guest.GenericVisit(*this); }
#define DEFINE_CYCLIC_VISITABLE_VOID(SomeVisitor) \
virtual void Accept(SomeVisitor& guest) \
{ guest.GenericVisit(*this); }
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20: add default argument DefaultCatchAll to BaseVisitable
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 27, 2002: ported by Benjamin Kaufmann to MSVC 6.0
// Feb 23, 2003: Removed special visitor classes for return type void.
// Added Loki:: qualification to Accept's Paramter (in the macro) B.K.
// Mar 06, 2003: Changed default values for return types to void.
// Added protected destructors to private implementation classes B.K.
////////////////////////////////////////////////////////////////////////////////
#endif // VISITOR_INC_
#endif

View file

@ -0,0 +1,521 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Feb 23, 2003
//
//
// The original visitor implementation depends heavily on the possibility
// to return an expression of type "cv void" from a functions with a return
// type of cv void (6.6.3).
// Unfortunately the MSVC 6.0 does not allow that. Because I could not think
// of any transparent workaround I decided to create a set of complete new
// classes for the void-case.
// Of course this is a very unattractive solution :-(
// If you know of a better solution, please let me know.
//
// The MSVC 6.0 does not allow void to be a default value for a template parameter.
// I therefore changed all defaults to int.
#ifndef VISITOR_INC_
#define VISITOR_INC_
#include "Typelist.h"
#include "HierarchyGenerators.h"
#include "MSVC6Helpers.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitor
// The base class of any Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
class BaseVisitor
{
public:
virtual ~BaseVisitor() {}
};
////////////////////////////////////////////////////////////////////////////////
// class template Visitor
// The building block of Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
template <class T, typename R = int/* = void */ >
class Visitor;
////////////////////////////////////////////////////////////////////////////////
// class template Visitor (specialization)
// This specialization is not present in the book. It makes it easier to define
// Visitors for multiple types in a shot by using a typelist. Example:
//
// class SomeVisitor :
// public BaseVisitor // required
// public Visitor<TYPELIST_2(RasterBitmap, Paragraph)>,
// public Visitor<Paragraph>
// {
// public:
// void Visit(RasterBitmap&); // visit a RasterBitmap
// void Visit(Paragraph &); // visit a Paragraph
// };
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
// helper for Visitor's the left base class
template <unsigned int ListId>
struct VisitorImplLeft
{
template <class TList, class R>
struct In
{
typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
// helper for Visitor's the right base class
template <unsigned int ListId>
struct VisitorImplRight
{
template <class TList, class R>
struct In
{
typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
// simulates specialization
// class Visitor<Head, R>
template <>
struct VisitorImplLeft<TL::Private::NoneList_ID>
{
template <class T, class R>
struct In
{
struct Result
{
typedef R ReturnType;
virtual ReturnType Visit(T&) = 0;
};
};
};
// simulates the left base class for the specialization
// class Visitor<Typelist<Head, Tail>, R>
template <>
struct VisitorImplLeft<TL::Private::Typelist_ID>
{
template <class TList, class R>
struct In
{
typedef Visitor<typename TList::Head, R> Result;
};
};
template <>
struct VisitorImplRight<TL::Private::NoneList_ID>
{
template <class TList, class R>
struct In
{
struct Result {};
};
};
// simulates the right base class for the specialization
// class Visitor<Typelist<Head, Tail>, R>
template <>
struct VisitorImplRight<TL::Private::Typelist_ID>
{
template <class TList, class R>
struct In
{
typedef Visitor<typename TList::Tail, R> Result;
};
};
template <>
struct VisitorImplRight<TL::Private::AtomList_ID>
{
template <class TList, class R>
struct In
{
struct Result {};
};
};
// MSVC 6.0 will complain if we try to let Visitor inherit
// directly from VisitorImplLeft/VisitorImplRight
template <class T, class R>
struct VisitorImplLeftWrap
{
struct Dummy{};
typedef typename VisitorImplLeft
<
TL::Private::IsTypelist<T>::type_id == TL::Private::AtomList_ID ?
TL::Private::Typelist_ID :
TL::Private::IsTypelist<T>::type_id
>::template In<T, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
template <class T, class R>
struct VisitorImplRightWrap
{
struct Dummy{};
typedef typename VisitorImplRight
<
TL::Private::IsTypelist<T>::type_id
>::template In<T, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
}
template <class T, typename R>
class Visitor : public Private::VisitorImplLeftWrap<T, R>::Result,
public Private::VisitorImplRightWrap<T, R>::Result
{
public:
typedef R ReturnType;
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitorImpl
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class TList, typename R = int /* = void */ > class BaseVisitorImpl;
// class for the void-case
template <class TList> class BaseVisitorImplVoid;
namespace Private
{
template <unsigned int ListTag>
struct BaseVisitorImplHelper
{
template <typename T, typename R>
struct In
{
typedef typename T::ERROR_WRONG_SPECIALIZATION_SELECTED Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::Private::Typelist_ID>
{
template <typename TList, typename R>
struct In
{
typedef typename Loki::Select<
IsVoid<R>::value,
BaseVisitorImplVoid<TList>,
BaseVisitorImpl<TList, R>
>::Result Result;
//typedef BaseVisitorImpl<TList, R> Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::Private::NullType_ID>
{
template <typename TList, typename R>
struct In
{
struct Result {};
};
};
template <class T, class R>
struct BaseVisitorImplWrap
{
struct Dummy {};
typedef typename BaseVisitorImplHelper
<
TL::Private::IsTypelist<typename T::Tail>::
type_id == TL::Private::AtomList_ID ?
TL::Private::Typelist_ID :
TL::Private::IsTypelist<typename T::Tail>::type_id
>::template In<typename T::Tail, R>::Result TempType;
typedef VC_Base_Workaround<TempType, Dummy> Workaround;
typedef Workaround::LeftBase Result;
};
}
template <class TList, typename R>
class BaseVisitorImpl : public Visitor<typename TList::Head, R>,
public Private::BaseVisitorImplWrap<TList, R>::Result
{
ASSERT_TYPELIST(TList);
public:
// using BaseVisitorImpl<Tail, R>::Visit;
virtual R Visit(typename TList::Head&)
{ return R(); }
};
// class for the void-case
template <class TList>
class BaseVisitorImplVoid : public Visitor<typename TList::Head, void>,
public Private::BaseVisitorImplWrap<TList, void>::Result
{
ASSERT_TYPELIST(TList);
public:
// using BaseVisitorImpl<Tail, R>::Visit;
virtual void Visit(typename TList::Head&)
{}
};
////////////////////////////////////////////////////////////////////////////////
// class template DefaultCatchAll
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename Visited>
struct DefaultCatchAll
{
static R OnUnknownVisitor(Visited&, BaseVisitor&)
{ return R(); }
};
// template template parameter workaround.
// use Wrapper-Classes like this to instantiate BaseVisitable
struct DefaultCatchAllWrapper
{
template <class R, class Visited>
struct In
{
typedef DefaultCatchAll<R, Visited> type;
};
};
template <typename R, typename Visited>
struct DefaultCatchAllVoid
{
static R OnUnknownVisitor(Visited&, BaseVisitor&)
{}
};
struct DefaultCatchAllVoidWrapper
{
template <class R, class Visited>
struct In
{
typedef DefaultCatchAllVoid<R, Visited> type;
};
};
////////////////////////////////////////////////////////////////////////////////
// class template NonStrictVisitor
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class T, class Base>
struct NonStrictVisitorUnit : public Base
{
typedef typename Base::ReturnType ReturnType;
ReturnType Visit(T&)
{
return ReturnType();
}
};
struct NonStrictVisitorUnitWrapper
{
template <class T, class B>
struct In
{
typedef NonStrictVisitorUnit<T, B> type;
};
};
template <class TList, typename R = int /* = void */>
class NonStrictVisitor
: public GenLinearHierarchy<
TList,
NonStrictVisitorUnitWrapper,
Visitor<TList, R> >
{
};
template <class T, class Base>
struct NonStrictVisitorUnitVoid : public Base
{
typedef void ReturnType;
ReturnType Visit(T&)
{
}
};
struct NonStrictVisitorUnitVoidWrapper
{
template <class T, class B>
struct In
{
typedef NonStrictVisitorUnitVoid<T, B> type;
};
};
template <class TList>
class NonStrictVisitorVoid
: public GenLinearHierarchy<
TList,
NonStrictVisitorUnitVoidWrapper,
Visitor<TList, void> >
{
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitable
////////////////////////////////////////////////////////////////////////////////
template
<
typename R = int/* = void */,
class CatchAll = DefaultCatchAllWrapper
>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {}
virtual ReturnType Accept(BaseVisitor&) = 0;
protected: // give access only to the hierarchy
template <class T>
static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
{
typedef ApplyInnerType2<CatchAll, R, T>::type CatchA;
// Apply the Acyclic Visitor
if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest))
{
return p->Visit(visited);
}
return CatchA::OnUnknownVisitor(visited, guest);
}
};
// class for the void-case
template
<
class CatchAll = DefaultCatchAllVoidWrapper
>
class BaseVisitableVoid
{
public:
typedef void ReturnType;
virtual ~BaseVisitableVoid() {}
virtual ReturnType Accept(BaseVisitor&) = 0;
protected: // give access only to the hierarchy
template <class T>
static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
{
typedef ApplyInnerType2<CatchAll, void, T>::type CatchA;
// Apply the Acyclic Visitor
if (Visitor<T, void>* p = dynamic_cast<Visitor<T, void>*>(&guest))
{
p->Visit(visited);
}
CatchA::OnUnknownVisitor(visited, guest);
}
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_VISITABLE
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_VISITABLE() \
virtual ReturnType Accept(Loki::BaseVisitor& guest) \
{ return AcceptImpl(*this, guest); }
#define DEFINE_VISITABLE_VOID() \
virtual void Accept(Loki::BaseVisitor& guest) \
{ AcceptImpl(*this, guest); }
////////////////////////////////////////////////////////////////////////////////
// class template CyclicVisitor
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
template <typename R, class TList>
class CyclicVisitor : public Visitor<TList, R>
{
public:
typedef R ReturnType;
// using Visitor<TList, R>::Visit;
template <class Visited>
ReturnType GenericVisit(Visited& host)
{
Visitor<Visited, ReturnType>& subObj = *this;
return subObj.Visit(host);
}
};
template <class TList>
class CyclicVisitorVoid : public Visitor<TList, void>
{
public:
typedef void ReturnType;
// using Visitor<TList, R>::Visit;
template <class Visited>
ReturnType GenericVisit(Visited& host)
{
Visitor<Visited, ReturnType>& subObj = *this;
subObj.Visit(host);
}
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_CYCLIC_VISITABLE
// Put it in every class that you want to make visitable by a cyclic visitor
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_CYCLIC_VISITABLE(SomeVisitor) \
virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \
{ return guest.GenericVisit(*this); }
#define DEFINE_CYCLIC_VISITABLE_VOID(SomeVisitor) \
virtual void Accept(SomeVisitor& guest) \
{ guest.GenericVisit(*this); }
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20: add default argument DefaultCatchAll to BaseVisitable
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Oct 27, 2002: ported by Benjamin Kaufmann to MSVC 6.0
// Feb 23, 2003: Removed superfluous implementation classes and added Loki::
// qualification to Accept's Paramter (in the macro) B.K.
////////////////////////////////////////////////////////////////////////////////
#endif // VISITOR_INC_

View file

@ -0,0 +1,708 @@
Loki VC 6.0 Port or how to produce C1001 - Internal Compiler Errors
-------------------------------------------------------------------
Version: 0.5e
Introduction/Compatibility:
---------------------------
This is a partial MSVC 6.0 Sp5 compatible port of Andrei Alexandrescu's excellent Loki Library.
Because I could not retain the originial interface in all places, this port is not
compatible to the original library and therefore code using this port *cannot* generally be
used together with the original lib.
This is, of course, a great pity.
So if you know of a complete and full interface-compatible VC 6.0
port or if you know how to improve this port, please let me know.
Contact:
--------
For any suggestions, bug reports, comments and questions please email me to
Hume@c-plusplus.de
Using this port:
----------------
To use this port, simply extract the files from the archive, give your compiler access to
their path, and include them appropriately in your code via #include.
If you use the small object allocator directly or indirectly (through the Functor class)
you must add SmallObj.cpp to your project/makefile.
If you use Singletons with longevity you must add Singleton.cpp to your project/makefile.
Fixes:
------
Mar 18, 2004:
-------------
* In SmartPtr.h: Added operator=-workaround for pointer-assignment
* In Functor.h: Changed value parameter to reference parameter
in FunctorBase and FunctorVoidBase Ctors.
Mar 21, 2003:
-------------
* In MultiMethods.h: Added a new explicit template argument specification (ETAS)-workaround
for FnDispatcher::Add which is more compliant with other
ETAS-workarounds used in this port.
Mar 20, 2003:
-------------
* In MultiMethods.h: Fixed bugs in FnDispatcher and FunctorDispatcher.
Fixing FnDispatcher led to an Interface change (see section "Interface changes").
Mar 08, 2003:
-------------
* In HierarchyGenerators.h: implemented transparent workaround for
'explicit template argument specification for nonmeber functions'-bug.
The Field-Functions can now be called as in the original lib.
Mar 06, 2003:
-------------
* In SmartPointer.h: Added helper-macros for convenient specialization
of std::less for Smart-Pointers.
* I found a way to use void as a default value for template parameters.
Therefore I changed MultiMethods.h and Visitor.h accordingly.
Feb 2003:
---------
* created new versions of Functor.h, Visitor.h and MultiMethods.h that
now can handle void return types transparently.
* ported SmartPtr's Ownership-Policy RefCountedMT
* Added isFunctionPointer to TypeTraits.
* Replaced all pointer-type dummy-parameters needed as a workaround
for VC's 'explicit template argument specification'-bug with Typ2Type-dummy
parameters.
* fixed the problems with BindFirst (Functor.h) that led to
C1001-Internal compiler errors.
* fixed numerous other bugs.
Jan 30, 2003:
-------------
* In TypeTraits.h: Fixed bugs in TypeTraits' scalar and array detection.
const and volatile detection is now based on techniques from boost's type traits
(see http://www.boost.org/libs/type_traits/)
Added Enum- and pointer-to-member-function-detection code.
Thanks to M. Yamada.
Jan 12, 2003:
-------------
* changed the signature of SmallObject's op new. Now it
matches the corresponding op delete.
Thanks to M.Yamada for the hint and the solution.
Dec 08, 2002:
-------------
* In HierarchyGenerators.h: Sergey Khachatrian reported a bug
in GenScatterHierarchy when used with a typelist containing
equal types (e.g. GenScatterHierarchy<TYPELIST_2(int, int), UnitWrapper>
resp. Tuple<TYPELIST_2(int, int)>)
Fixing the bug I found another MSVC6-Problem in the Field-function.
The workaround for this problems results in an interface change.
please refer to the section "Interface changes" below for further information.
Dec 03, 2002
-------------
* In MSVC6Helpers.h: The original version failed to qualify some types from the
Private-Namespace.
Thanks to Adi Shavit for pointing that out
* In Threads.h: Changed wrong ctor/dtor names in ObjectLevelLockable.
Thanks to Adi Shavit for pointing that out
Nov 19, 2002:
-------------
* In SmartPtr.h: Changed template ctors. See Notes.
Notes:
------
The original Loki Lib uses some pretty advanced (resp. new) C++ features like:
A. partial template specialization.
B. template template parameters.
C. explicit template argument specification for member- and nonmeber functions.
D. covariant return types.
E. Template parameters with default type void
F. return statements with an expression of type cv void in functions with a return type of cv void.
Unfortunately the MSVC 6.0 supports neither of them.
A. I used various techniques to simulate partial template specialization. In some cases
these techniques allowed me to retain the original interfaces but often that was not
possible (or better: i did not find a proper solution). In any case it led
to increasing code complexity :-)
B. One way to simulate template template parameters is to replace the template class with
a normal class containing a nested template class. You then move the original functionality
to the nested class.
The problem with this approach is MSVC's 'dependent template typedef bug'.
MSVC 6.0 does not allow something like this:
[code]
template <class APolicy, class T>
struct Foo
{
// error C2903: 'In' : symbol is neither a class template nor a function template
typedef typename APolicy::template In<T> type;
};
[/code]
To make a long story short, I finally decided to use boost::mpl's apply-technique to
simulate template template parameters. This approach works fine with MSVC 6.0. But be warned,
this technique uses not valid C++.
Of course, replacing template template parameters always results in some interface changes.
C. I added dummy-Parameters to (Member-)Functions that depend on explicit template
argument specification. These dummy-Parameters help the compiler in deducing the template
parameters that otherwise need to be explicitly specified.
Example:
[code]
struct Foo
{
template <class T>
T Func();
};
[/code]
becomes
[code]
struct Foo
{
template <class T>
T Func(Type2Type<T>);
};
[/code]
in this port.
Update:
-------
The MSVC 6.0 sometimes does not overload normal functions depending
on explicit argument specification correctly (see: Microsoft KB Article - 240871)
The following code demonstrates the problem:
[code]
template <unsigned i, class T>
void BugDemonstration(T p)
{
printf("BugDemonstration called with i = %d\n", i);
}
int main()
{
GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
// will always print: "BugDemonstration called with i = 2";
BugDemonstration<0>(Bla);
BugDemonstration<1>(Bla);
BugDemonstration<2>(Bla);
}
[/code]
Fortunately there is a transparent workaround for this problem. Simply add
a dummy-parameter with a proper default value:
[code]
template <unsigned i, class T>
void BugDemonstration(T p, Int2Type<i>* = (Int2Type<i>*)0)
{
printf("BugDemonstration called with i = %d\n", i);
}
int main()
{
GenScatterHierarchy<TYPELIST_3(int, int, int), TestUnitWrapper> Bla;
// will now work correctly
BugDemonstration<0>(Bla);
BugDemonstration<1>(Bla);
BugDemonstration<2>(Bla);
}
[/code]
Unfortunately adding dummy-parameters does not always work.
For example for one of FnDispatcher's Add-member-functions you have to explicitly
specify two type- and one non-type parameter.
[code]
template </*...*/typename ResultType/*...*/>
class FnDispatcher
{
public:
//...
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&)>
void Add(){/*...*/}
};
//...
FnDispatcher<Shape> dis;
dis.Add<Poly, Poly, &AFunc>();
[/code]
Using dummy-parameters as workaround FnDispatcher::Add would become something
like this:
[code]
template<class S1, class S2, class R, R (*)(S1&,S2&)>
struct Helper {};
template </*...*/typename ResultType/*...*/>
class FnDispatcher
{
public:
//...
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&)>
void Add(Helper<SomeLhs, SomeRhs, ResultType, callback>)
{}
};
//...
FnDispatcher<void> f;
f.Add(Helper<Rectangle, Rectangle, void, &Func>());
[/code]
This compiles fine, but alas Add never gets called. I don't know what happens,
I only know that the MSVC 6.0 won't generate code for a function call.
In situations like that, instead of dummy-Parameters I used nested template-classes
with overloaded function-operator as a workaround.
[code]
template </*...*/typename ResultType/*...*/>
class FnDispatcher
{
public:
// the member-function Add becomes a member-template-class
// with overloaded function operator.
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&)>
struct AddI
{
void operator()(FnDispatcher<ResultType>& o) {/*...*/}
};
};
//...
FnDispatcher<void> f;
FnDispatcher<void>::AddI<Rectangle, Rectangle, &Func>()(f);
[/code]
If you know of a better workaround, please let me know.
Update:
-------
The problem in the example above is Add's nontype-function-pointer-Parameter.
If one changes this parameter to a type-parameter the problem vanishes.
The example above then becomes:
[code]
template </*...*/typename ResultType/*...*/>
class FnDispatcher
{
public:
// Etas stands for explicit template argument specification.
// Do whatever you need to do with callback in this class.
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&), bool symmetric = false>
struct Etas
{/*...*/};
// EtasType has to be a template parameter. If one tries to use
// a parameter of type Etas the MSVC 6.0 won't generate correct
// code.
template <class EtasType>
void Add(EtasType EtasObj)
{/*...*/}
};
//...
typedef FnDispatcher<void> DisType;
DisType f;
f.Add(DisType::Etas<Rectangle, Rectangle, &Func>());
[/code]
The port provides both workarounds but the use of the second should be preferred,
because it betters fits to the rest of the port's workarounds.
D. Virtual functions that use covariant return types (e.g. return a pointer to Derived)
in the original library were changed so that they have exactly the
same return type as the original virtual function (e.g. return a pointer to Base).
E. The MSVC 6.0 does not allow code like this:
[code]
// error C2182: '__formal' illegal use of type 'void'
template <class T, class R = void>
struct Blub {};
[/code]
Interestingly enough you can have void as default type by simply using another
level of indirection:
[code]
struct VoidWrap
{
typedef void type;
};
template <class T, class R = VoidWrap::type>
struct Blub
{};
[/code]
F. To workaround void returns I did the following:
From every original class I moved those functions that potentially
produce void returns to new classes. One for the general case and
one for the void case.
In the class for the general case I implemented the functions in the original way.
In the class for the void case I removed the return statements and therefore the
potential void return.
Depending on the return type, the original class inherits from the
corresponding new class and thus gets the proper implementation of
the previously removed functions.
For example:
[code]
template <class R> struct Foo
{
R Func() { return R(); }
};
[/code]
becomes:
[code]
namespace Private
{
template <class R> struct FooBase
{
R Func() {return R();}
};
struct FooVoidBase
{
typedef void R;
R Func() {}
};
}
template <class R>
struct Foo : public Select<IsVoid<R>::value, FooVoidBase, FooBase<R> >::Result
{};
[/code]
The MSVC 6 allows explicit template specialization in class scope.
In contrast the C++ Standards only allows explicit template specialization
in namespace scope. Using the non-compliant feature, the implementation
of the example above becomes a little less complicated:
[code]
namespace Private
{
struct FooBase
{
template <class R>
struct In
{
R Func() {return R();}
};
template <>
struct In<void>
{;
void Func() {}
};
};
}
template <class R>
struct Foo : Private::FooBase::In<R>
{};
[/code]
Please note that *all* new base classes are only meant as a hidden
implementation detail.
You should never use any of them directly or indirectly. In particular don't
make use of the possible derived-to-base conversion.
In the old version of Functor.h I changed a ResultType of type void to
VoidAsType (an udt). This change is transparent to the user of Functor.
Some words to template-ctors resp. template assignment operators:
The MSVC 6.0 introduces an order-dependency for template ctor
resp. template assignemt operators.
If you need both a copy-ctor and a template copy ctor (same for copy-assignment), then
you *must* write the templated version first.
So instead of
[code]
template <class T>
struct Foo
{
Foo(const Foo&)
{}
template <class U>
Foo(const Foo<U>& r)
{}
};
[/code]
you *need* to write:
[code]
template <class T>
struct Foo
{
template <class U>
Foo(const Foo<U>& r)
{}
Foo(const Foo& r)
{}
};
[/code]
Many thanks to Nelson Elói for pointing that out and for providing me
with this solution.
The above solution unfortunately does not work if the template ctor does not have
the form of a copy-ctor. If you write something like this (as in the functor-class):
[code]
template <class T>
struct Foo
{
template <class Fun>
Foo(Fun r)
{}
Foo(const Foo& r)
{}
};
[/code]
then the VC will no longer find a copy-ctor.
Because of this, i can't use Nelson Elói's solution in Functor.h
Interface changes:
------------------
1. In Threads.h:
* Thread-Policies changed from class templates to normal classes containing a
nested class template 'In'.
consequences:
This change is not very dramatic because it won't break code using this port when
switching to the original library (only new Thread-Policies must be changed)
2. In Singleton.h:
* The Creation- and Lifetime-Policies are no longer class templates. Instead they all use
Member-Templates.
consequences:
Again this change will only break new Policies when switching to the
original library.
3. In Functor.h:
* No covariant return types.
consequences:
DoClone always returns a FunctorImplBase<R, ThreadingModel>* where R is the functor's return
type and ThreadingModel its current ThreadingModel.
4. TypeTraits.h
* Because VC 6.0 lacks partial template specialization, the TypeTraits-Class
fails to provide the following typedefs:
PointeeType, ReferredType, NonVolatileType and UnqualifiedType.
* Since the VC 6 does not differentiate
between void, const void, volatile void and const volatile void the following
assertions will fail:
assert(TypeTraits<const void>::isConst == 1)
assert(TypeTraits<volatile void>::isVolatile == 1)
assert(TypeTraits<const volatile void>::isConst == 1)
assert(TypeTraits<const volatile void>::isVolatile == 1)
* This port adds isEnum, isMemberFunctionPointer and isFunctionPointer.
5. HierarchyGenerator.h
* I used Mat Marcus' approach to port GenScatterHierarchy.
See http://lists.boost.org/MailArchives/boost/msg20915.php) for the consequences.
* Same for GenLinearHierarchy
* Unit is no longer a template template parameter.
consequences:
For every concrete unit-template there must be a normal class containing
a nested-template class called 'In'. 'In' should only contain a typedef to the
concrete Unit.
Update:
The port's original version of GenScatterHierarchy does not work when used
with typelists containing equal types.
The problem is due to a VC bug. The VC fails to compile code similar
to this, although it is perfectly legal.
[code]
template <class T>
class Wrapper
{};
template <class T>
struct B : public Wrapper<T>
{};
// ERROR: 'A<T>' : direct base 'Wrapper<T>' is inaccessible; already a base of 'B<T>'
template <class T>
class A : public B<T>, public Wrapper<T>
{};
[/code]
Unfortunately my workaround has a big drawback.
GenScatterHierarchy now has to generate a lot more classes.
Alexandrescu's original implementation generates 3*n classes (n - number of types in the typelist)
The old version of my port creates 4 * n + 1
The new version will create 5 * n
The fix also reveals the "Explicitly Specified Template Functions Not Overloaded Correctly"-Bug
(Microsoft KB Article - 240871) in the Field-Function taking a nontype int Parameter.
See Notes (section C) for the description of the workaround.
I also added a macro FIELD. Using this macro one can write
FIELD(obj, 0)
6. Factory.h
* The Error-Policy for Factory and CloneFactory is no longer a template template parameter.
Use a class with member-templates instead.
consequences:
This change will only break new Policies when switching to the
original library.
7. AbstractFactory.h
* no covariant return types
* no template template parameters
For every concrete Factory-Unit there must be a normal class containing
a nested-template class called 'In'. 'In' shall contain a typedef to the
concrete Factory-Unit.
* Added a dummy-Parameter to AbstractFactory::Create (see C.)
Calling syntax changed from:
ConcProduct* p = aFactory.Create<ConcProduct>();
to
ConcProduct* p = aFactory.Create(Type2Type<ConcProduct>());
8. SmartPtr.h
* no template template parameters.
(see 7.for a description of the consequences)
* This port does not specialize std::less
Update:
-------
The port provides some helper-macros for convenient specialization
of std::less for Smart-Pointers.
If, for example, you want to use a Smart-Pointer as the key of a std::map,
you can do it like this:
[code]
#include <map>
#include <loki/SmartPtr.h>
SMARTPTR_SPECIALIZE_LESS(Apple)
class Apple {};
int main()
{
std::map<SmartPointer<Apple>, int> m;
//...
}
[/code]
9. Visitor.h
* no template template parameters
(see 7.for a description of the consequences)
* This port fails to correctly support void return types. As a workaround it provides
a set of complete new classes (and macros) for void. Default arguments of type void
were replaced by arguments of type int.
Update:
-------
In the new version of Visitor.h there are no longer extra classes for void.
Instead the original classes are now able to handle the return type void.
However there are still two sets of macros. One for return type = void
(DEFINE_VISITABLE_VOID, DEFINE_CYCLIC_VISITABLE_VOID) and one for return
type != void (DEFINE_VISITABLE, DEFINE_CYCLIC_VISITABLE)
10. MultiMethods.h
* replaced all template template parameters with 'normal' parameters (see 7.
for a description of the consequences)
* This port does not support functions with return type void.
* dummy parameters were added to functions that otherwise would depend on
explicit template argument specification (14.8.1).
Update:
-------
* The port now supports functions with return type void.
Some words to BasicDispatcher:
------------------------------
You can't use a (namespace level) template function as callback-function
for BasicDispatcher. This is because using the VC 6.0 you can't explicity
specify the template-paramters when adding the concrete function instance
to the dispatcher.
Normaly you can write something like this:
[code]
template <class DerivedShape1, class DerivedShape2>
int HatchShapes(Shape&, Shape&) {...}
typedef ::Loki::BasicDispatcher<Shape> Dispatcher;
void Func(Dispatcher& x)
{
x.Add(&HatchShapes<Circle, Rectangle>);
}
[/code]
Using the VC 6.0 this is not possible, because there is no
way to specify the types for DerivedShape1 and DerivedShape2 (at least
I know of no way).
As a workaround use a helper-template class in conjunction with
a static member function:
[code]
template <class DerivedShape1, class DerivedShape2>
struct Hatch_Helper
{
int HatchShapes(Shape&, Shape&) {...}
};
typedef ::Loki::BasicDispatcher<Shape> Dispatcher;
void Func(Dispatcher& x)
{
x.Add(&Hatch_Helper<Circle, Rectangle>::HatchShapes);
}
[/code]
Some words to FnDispatcher:
---------------------------
The trampoline-Versions of FnDispatcher::Add differ
from the original library.
Using the original library one writes:
[code]
typedef FnDispatcher<Shape> Dispatcher;
void Hatch(Rectangle& lhs, Poly& rhs) {...}
Dispatcher dis;
disp.Add<Rectangle, Poly, &Hatch>();
[/code]
Using this port the last line either becomes:
[code]
disp.Add(Dispatcher::Etas<Rectangle, Poly, &Hatch>());
[/code]
or
[code]
Dispatcher::AddI<Rectangle, Poly, &Hatch>()(dis);
[/code]
More info:
----------
The original Loki library can be found here: http://moderncppdesign.com
For Rani Sharoni's VC 7.0 port see: http://www.geocities.com/rani_sharoni/LokiPort.html

View file

@ -0,0 +1,63 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef STATIC_CHECK_INC_
#define STATIC_CHECK_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// Helper structure for the STATIC_CHECK macro
////////////////////////////////////////////////////////////////////////////////
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
namespace Private
{
template<int x> struct static_assert_test{};
template <bool x> struct SizeError;
template <> struct SizeError<true>{};
}
}
#define STATIC_SIZE_ASSERT(Type, ExpSize) \
typedef ::Loki::Private::static_assert_test<sizeof(::Loki::Private::SizeError \
< (bool) (sizeof(Type) == ExpSize) >)> static_assert_typedef_
////////////////////////////////////////////////////////////////////////////////
// macro STATIC_CHECK
// Invocation: STATIC_CHECK(expr, id)
// where:
// expr is a compile-time integral or pointer expression
// id is a C++ identifier that does not need to be defined
// If expr is zero, id will appear in a compile-time error message.
////////////////////////////////////////////////////////////////////////////////
#define STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20, 2001: add extra parens to STATIC_CHECK - it looked like a fun
// definition
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // STATIC_CHECK_INC_

View file

@ -0,0 +1,167 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef ABSTRACTFACTORY_INC_
#define ABSTRACTFACTORY_INC_
#include "Typelist.h"
#include "TypeManip.h"
#include "HierarchyGenerators.h"
#include <cassert>
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template AbstractFactoryUnit
// The building block of an Abstract Factory
////////////////////////////////////////////////////////////////////////////////
template <class T>
class AbstractFactoryUnit
{
public:
virtual T* DoCreate(Type2Type<T>) = 0;
virtual ~AbstractFactoryUnit() {}
};
////////////////////////////////////////////////////////////////////////////////
// class template AbstractFactory
// Defines an Abstract Factory interface starting from a typelist
////////////////////////////////////////////////////////////////////////////////
template
<
class TList,
template <class> class Unit = AbstractFactoryUnit
>
class AbstractFactory : public GenScatterHierarchy<TList, Unit>
{
public:
typedef TList ProductList;
template <class T> T* Create()
{
Unit<T>& unit = *this;
return unit.DoCreate(Type2Type<T>());
}
};
////////////////////////////////////////////////////////////////////////////////
// class template OpNewFactoryUnit
// Creates an object by invoking the new operator
////////////////////////////////////////////////////////////////////////////////
template <class ConcreteProduct, class Base>
class OpNewFactoryUnit : public Base
{
typedef typename Base::ProductList BaseProductList;
protected:
typedef typename BaseProductList::Tail ProductList;
public:
typedef typename BaseProductList::Head AbstractProduct;
ConcreteProduct* DoCreate(Type2Type<AbstractProduct>)
{
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 ConcreteProduct, class Base>
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)
{}
friend void DoGetPrototype(const PrototypeFactoryUnit& me,
AbstractProduct*& pPrototype)
{ pPrototype = me.pPrototype_; }
friend void DoSetPrototype(PrototypeFactoryUnit& me,
AbstractProduct* pObj)
{ me.pPrototype_ = pObj; }
template <class U>
void GetPrototype(U*& p)
{ return DoGetPrototype(*this, p); }
template <class U>
void SetPrototype(U* pObj)
{ DoSetPrototype(*this, pObj); }
AbstractProduct* DoCreate(Type2Type<AbstractProduct>)
{
assert(pPrototype_);
return pPrototype_->Clone();
}
private:
AbstractProduct* pPrototype_;
};
////////////////////////////////////////////////////////////////////////////////
// class template ConcreteFactory
// Implements an AbstractFactory interface
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractFact,
template <class, class> class Creator = OpNewFactoryUnit,
class TList = typename AbstractFact::ProductList
>
class ConcreteFactory
: public GenLinearHierarchy<
typename TL::Reverse<TList>::Result, Creator, AbstractFact>
{
public:
typedef typename AbstractFact::ProductList ProductList;
typedef TList ConcreteProductList;
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
// September 25, 2004: Fixed bug in PrototypeFactoryUnit::GetPrototype, thanks
// to a bug report submitted by funcall.
////////////////////////////////////////////////////////////////////////////////
#endif // ABSTRACTFACTORY_INC_

View file

@ -0,0 +1,335 @@
////////////////////////////////////////////////////////////////////////////////
// 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 ASSOCVECTOR_INC_
#define ASSOCVECTOR_INC_
#include <algorithm>
#include <functional>
#include <vector>
#include <utility>
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template AssocVectorCompare
// Used by AssocVector
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class Value, class C>
class AssocVectorCompare : public C
{
typedef std::pair<typename C::first_argument_type, Value>
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<K, V> not std::pair<const K, V>
// * iterators are random
////////////////////////////////////////////////////////////////////////////////
template
<
class K,
class V,
class C = std::less<K>,
class A = std::allocator< std::pair<K, V> >
>
class AssocVector
: private std::vector< std::pair<K, V>, A >
, private Private::AssocVectorCompare<V, C>
{
typedef std::vector<std::pair<K, V>, A> Base;
typedef Private::AssocVectorCompare<V, C> 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<value_type, value_type, bool>
, 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 <class InputIterator>
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<iterator, bool> 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);
}
iterator insert(iterator pos, const value_type& val)
{
if (pos != end() && this->operator()(*pos, val) &&
(pos == end() - 1 ||
!this->operator()(val, pos[1]) &&
this->operator()(pos[1], val)))
{
return Base::insert(pos, val);
}
return insert(val).first;
}
template <class InputIterator>
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)
{
using std::swap;
Base::swap(other);
MyCompare& me = *this;
MyCompare& rhs = other;
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<iterator, iterator> equal_range(const key_type& k)
{
MyCompare& me = *this;
return std::equal_range(begin(), end(), k, me);
}
std::pair<const_iterator, const_iterator> equal_range(
const key_type& k) const
{
const MyCompare& me = *this;
return std::equal_range(begin(), end(), k, me);
}
friend bool operator==(const AssocVector& lhs, const AssocVector& rhs)
{
const Base& me = lhs;
return me == rhs;
}
bool operator<(const AssocVector& rhs) const
{
const Base& me = *this;
const Base& yo = rhs;
return me < yo;
}
friend bool operator!=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(lhs == rhs); }
friend bool operator>(const AssocVector& lhs, const AssocVector& rhs)
{ return rhs < lhs; }
friend bool operator>=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(lhs < rhs); }
friend bool operator<=(const AssocVector& lhs, const AssocVector& rhs)
{ return !(rhs < lhs); }
};
// specialized algorithms:
template <class K, class V, class C, class A>
void swap(AssocVector<K, V, C, A>& lhs, AssocVector<K, V, C, A>& rhs)
{ lhs.swap(rhs); }
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// May 20, 2001: change operator= - credit due to Cristoph Koegl
// June 11, 2001: remove paren in equal_range - credit due to Cristoph Koegl
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// January 22, 2002: fixed operator= - credit due to Tom Hyer
// June 25, 2002: fixed template insert() - credit due to Robert Minsk
// June 27, 2002: fixed member swap() - credit due to David Brookman
////////////////////////////////////////////////////////////////////////////////
#endif // ASSOCVECTOR_INC_

View file

@ -0,0 +1,231 @@
////////////////////////////////////////////////////////////////////////////////
// The Loki Library
// Data Generator by Mr. 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Oct 10, 2002
#pragma once
#include "Typelist.h"
//MSVC7 version
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template IterateTypes
////////////////////////////////////////////////////////////////////////////////
namespace TL
{
template<typename T>
struct nameof_type
{
const char* operator()()
{
return typeid(T).name();
}
};
template<typename T>
struct sizeof_type
{
size_t operator()()
{
return sizeof(T);
}
};
template <class TList, template <typename> class UnitFunc>
struct IterateTypes;
namespace Private
{
// for some reason VC7 needs the base definition altough not in use
template <typename TListTag>
struct IterateTypesHelper1
{
template <typename T, template <typename> class GenFunc>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <typename TListTag>
struct IterateTypesHelper2
{
template <typename T, template <typename> class GenFunc>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <>
struct IterateTypesHelper1<TL::Typelist_tag>
{
template <class TList, template <typename> class GenFunc>
struct In
{
typedef IterateTypes<typename TList::Head, GenFunc> Result;
};
};
template <>
struct IterateTypesHelper2<TL::Typelist_tag>
{
template <class TList, template <typename> class GenFunc>
struct In
{
typedef IterateTypes<typename TList::Tail, GenFunc> Result;
};
};
template <>
struct IterateTypesHelper1<TL::NoneList_tag>
{
template <typename AtomicType, template <typename> class GenFunc>
struct In
{
struct Result
{
typedef GenFunc<AtomicType> genfunc_t;
template<class II>
void operator()(II ii)
{
genfunc_t gen;
//warning C4267: 'argument' : conversion from 'size_t' to 'const std::_Vbase', possible loss of data
#pragma warning(push)
#pragma warning(disable: 4267)
//TODOSGB
*ii = gen();
#pragma warning(pop)
++ii;
}
template<class II, class P1>
void operator()(II ii, P1 p1)
{
genfunc_t gen;
*ii = gen(p1);
++ii;
}
};
};
};
template <>
struct IterateTypesHelper2<TL::NoneList_tag>
{
template <typename AtomicType, template <typename> class GenFunc>
struct In
{
struct Result
{
template<class II> void operator()(II) {}
template<class II, class P1> void operator()(II, P1) {}
};
};
};
template <>
struct IterateTypesHelper1<TL::NullType_tag>
{
template <class TList, template <typename> class GenFunc>
struct In
{
struct Result
{
template<class II> void operator()(II) {}
template<class II, class P1> void operator()(II, P1) {}
};
};
};
template <>
struct IterateTypesHelper2<TL::NullType_tag>
{
template <class TList, template <typename> class GenFunc>
struct In
{
struct Result
{
template<class II> void operator()(II) {}
template<class II, class P1> void operator()(II, P1) {}
};
};
};
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template IterateTypes
// Iteratates a Typelist, and invokes the ctor of GenFunc<T>
// for each type in the list, passing a functor along the way.
// The functor is designed to be an insertion iterator which GenFunc<T>
// can use to output information about the types in the list.
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class GenFunc>
struct IterateTypes
{
public:
typedef typename Private::IterateTypesHelper1
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, GenFunc>::Result head_t;
typedef typename Private::IterateTypesHelper2
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, GenFunc>::Result tail_t;
head_t head;
tail_t tail;
template<class II>
void operator()(II ii)
{
this->head.operator()(ii);
this->tail.operator()(ii);
}
template<class II, class P1>
void operator()(II ii, P1 p1)
{
this->head.operator()(ii, p1);
this->tail.operator()(ii, p1);
}
};
//UnitFunc is really a template-template parameter, but MSVC7
// chokes on the correct defintion. Oddly enough, it works correctly
// with the 'undecorated' template parameter declaraion!
//template <class> class UnitFunc
template<typename Types, class UnitFunc, typename II>
void iterate_types(II ii)
{
Loki::TL::IterateTypes<Types, UnitFunc> it;
it(ii);
}
}//ns TL
}//ns Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// Aug 17, 2002: Ported to MSVC7 by Rani Sharoni
// Aug 18, 2002: Removed ctor(II), replaced with operator(II) Shannon Barber
// Oct 10, 2002: Changed II (insertion iterator) from pass-by-reference to pass-by-value
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef EMPTYTYPE_INC_
#define EMPTYTYPE_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class EmptyType
// Used as a class type that doesn't hold anything
// Useful as a strawman class
////////////////////////////////////////////////////////////////////////////////
class EmptyType {};
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // EMPTYTYPE_INC_

143
include/noncc/MSVC/1300/Factory.h Executable file
View file

@ -0,0 +1,143 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef FACTORY_INC_
#define FACTORY_INC_
#include "LokiTypeInfo.h"
#include "AssocVector.h"
#include <exception>
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template DefaultFactoryError
// Manages the "Unknown Type" error in an object factory
////////////////////////////////////////////////////////////////////////////////
template <typename IdentifierType, class AbstractProduct>
struct DefaultFactoryError
{
struct Exception : public std::exception
{
const char* what() const throw() { return "Unknown Type"; }
};
static AbstractProduct* OnUnknownType(IdentifierType)
{
throw Exception();
}
};
////////////////////////////////////////////////////////////////////////////////
// class template Factory
// Implements a generic object factory
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractProduct,
typename IdentifierType,
typename ProductCreator = AbstractProduct* (*)(),
template<typename, class>
class FactoryErrorPolicy = DefaultFactoryError
>
class Factory
: public FactoryErrorPolicy<IdentifierType, AbstractProduct>
{
public:
bool Register(const IdentifierType& id, ProductCreator creator)
{
return associations_.insert(
IdToProductMap::value_type(id, creator)).second;
}
bool Unregister(const IdentifierType& id)
{
return associations_.erase(id) == 1;
}
AbstractProduct* CreateObject(const IdentifierType& id)
{
typename IdToProductMap::iterator i = associations_.find(id);
if (i != associations_.end())
{
return (i->second)();
}
return OnUnknownType(id);
}
private:
typedef AssocVector<IdentifierType, ProductCreator> IdToProductMap;
IdToProductMap associations_;
};
////////////////////////////////////////////////////////////////////////////////
// class template CloneFactory
// Implements a generic cloning factory
////////////////////////////////////////////////////////////////////////////////
template
<
class AbstractProduct,
class ProductCreator =
AbstractProduct* (*)(const AbstractProduct*),
template<typename, class>
class FactoryErrorPolicy = DefaultFactoryError
>
class CloneFactory
: public FactoryErrorPolicy<TypeInfo, AbstractProduct>
{
public:
bool Register(const TypeInfo& ti, ProductCreator creator)
{
return associations_.insert(
IdToProductMap::value_type(ti, creator)).second;
}
bool Unregister(const TypeInfo& id)
{
return associations_.erase(id) == 1;
}
AbstractProduct* CreateObject(const AbstractProduct* model)
{
if (model == 0) return 0;
typename IdToProductMap::iterator i =
associations_.find(typeid(*model));
if (i != associations_.end())
{
return (i->second)(model);
}
return OnUnknownType(typeid(*model));
}
private:
typedef AssocVector<TypeInfo, ProductCreator> IdToProductMap;
IdToProductMap associations_;
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // FACTORY_INC_

1358
include/noncc/MSVC/1300/Functor.h Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,423 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifdef _MSC_VER
#pragma once
#pragma warning( push )
// 'class1' : base-class 'class2' is already a base-class of 'class3'
#pragma warning( disable : 4584 )
#endif // _MSC_VER
#ifndef HIERARCHYGENERATORS_INC_
#define HIERARCHYGENERATORS_INC_
#include "Typelist.h"
#include "TypeTraits.h"
#include "EmptyType.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template GenScatterHierarchy
// Generates a scattered hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of one arg):
// GenScatterHierarchy<TList, Model>
// The generated class inherits all classes generated by instantiating the
// template 'Model' with the types contained in TList
////////////////////////////////////////////////////////////////////////////////
template <typename T, template <typename> class Unit>
class GenScatterHierarchy;
namespace Private
{
// for some reason VC7 needs the base definition altough not in use
template <typename TListTag>
struct GenScatterHierarchyHelper1
{
template <typename T, template <typename> class Unit>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <typename TListTag>
struct GenScatterHierarchyHelper2
{
template <typename T, template <typename> class Unit>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <>
struct GenScatterHierarchyHelper1<TL::Typelist_tag>
{
template <class TList, template <typename> class Unit>
struct In
{
typedef GenScatterHierarchy<typename TList::Head, Unit> Result;
};
};
template <>
struct GenScatterHierarchyHelper2<TL::Typelist_tag>
{
template <class TList, template <typename> class Unit>
struct In
{
typedef GenScatterHierarchy<typename TList::Tail, Unit> Result;
};
};
template <>
struct GenScatterHierarchyHelper1<TL::NoneList_tag>
{
template <typename AtomicType, template <typename> class Unit>
struct In { typedef Unit<AtomicType> Result; };
};
template <>
struct GenScatterHierarchyHelper2<TL::NoneList_tag>
{
template <typename AtomicType, template <typename> class Unit>
struct In { struct Result {}; };
};
template <>
struct GenScatterHierarchyHelper1<TL::NullType_tag>
{
template <class TList, template <typename> class Unit>
struct In { struct Result {}; };
};
template <>
struct GenScatterHierarchyHelper2<TL::NullType_tag>
{
template <class TList, template <typename> class Unit>
struct In { struct Result {}; };
};
} // namespace Private
template <typename T, template <typename> class Unit>
class GenScatterHierarchy
: public Private::GenScatterHierarchyHelper1
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, Unit>::Result
, public Private::GenScatterHierarchyHelper2
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, Unit>::Result
{
public:
typedef typename Private::GenScatterHierarchyHelper1
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, Unit>::Result LeftBase;
typedef typename Private::GenScatterHierarchyHelper2
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, Unit>::Result RightBase;
typedef typename Select
<
TL::is_Typelist<T>::value, T, void
>
::Result TList;
template <typename T> struct Rebind
{
typedef Unit<T> Result;
};
};
////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
// T is a type in the typelist used to generate H):
// Field<T>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
////////////////////////////////////////////////////////////////////////////////
template <class T, class H>
typename H::template Rebind<T>::Result &
Field(H& obj)
{
return obj;
}
template <class T, class H>
typename H::template Rebind<T>::Result const &
Field(H const & obj)
{
return obj;
}
////////////////////////////////////////////////////////////////////////////////
// function template TupleUnit
// The building block of tuples
////////////////////////////////////////////////////////////////////////////////
template <class T>
struct TupleUnit
{
T value_;
operator T&() { return value_; }
operator const T&() const { return value_; }
};
////////////////////////////////////////////////////////////////////////////////
// class template Tuple
// Implements a tuple class that holds a number of values and provides field
// access to them via the Field function (below)
////////////////////////////////////////////////////////////////////////////////
template <class TList>
struct Tuple : public GenScatterHierarchy<TList, TupleUnit>
{
};
////////////////////////////////////////////////////////////////////////////////
// helper class template FieldHelper
// See Field below
////////////////////////////////////////////////////////////////////////////////
template <unsigned int i>
struct FieldHelper
{
template<class H>
struct In
{
private:
typedef typename TL::TypeAt<typename H::TList, i>::Result ElementType;
typedef typename H::template Rebind<ElementType>::Result UnitType;
enum { isConst = TypeTraits<H>::isConst };
typedef typename Select
<
isConst,
const typename H::RightBase,
typename H::RightBase
>
::Result RightBase;
typedef typename Select
<
IsSameType<UnitType, TupleUnit<ElementType> >::value,
ElementType,
UnitType
>
::Result UnqualifiedResultType;
public:
typedef typename Select
<
isConst,
const UnqualifiedResultType,
UnqualifiedResultType
>
::Result ResultType;
static ResultType& Do(H& obj)
{
RightBase& rightBase = obj;
return FieldHelper<i - 1>::template In<RightBase>::Do(rightBase);
}
};
};
template <>
struct FieldHelper<0>
{
template<class H>
struct In
{
private:
typedef typename H::TList::Head ElementType;
typedef typename H::template Rebind<ElementType>::Result UnitType;
enum { isConst = TypeTraits<H>::isConst };
typedef typename Select
<
isConst,
const typename H::LeftBase,
typename H::LeftBase
>
::Result LeftBase;
typedef typename Select
<
IsSameType<UnitType, TupleUnit<ElementType> >::value,
ElementType,
UnitType
>
::Result UnqualifiedResultType;
public:
typedef typename Select
<
isConst,
const UnqualifiedResultType,
UnqualifiedResultType
>
::Result ResultType;
static ResultType& Do(H& obj)
{
LeftBase& leftBase = obj;
return leftBase;
}
};
};
////////////////////////////////////////////////////////////////////////////////
// function template Field
// Accesses a field in an object of a type generated with GenScatterHierarchy
// Invocation (obj is an object of a type H generated with GenScatterHierarchy,
// i is the index of a type in the typelist used to generate H):
// Field<i>(obj)
// returns a reference to Unit<T>, where Unit is the template used to generate H
// and T is the i-th type in the typelist
////////////////////////////////////////////////////////////////////////////////
template <unsigned int i, class H>
typename FieldHelper<i>::template In<H>::ResultType&
Field(H& obj)
{
return FieldHelper<i>::template In<H>::Do(obj);
}
////////////////////////////////////////////////////////////////////////////////
// class template GenLinearHierarchy
// Generates a linear hierarchy starting from a typelist and a template
// Invocation (TList is a typelist, Model is a template of two args):
// GenLinearHierarchy<TList, Model, Root>
////////////////////////////////////////////////////////////////////////////////
template
<
class TList,
template <class AtomicType, class UnitBase> class Unit,
class Root = EmptyType
>
class GenLinearHierarchy;
namespace Private
{
template <typename TListTag>
struct GenLinearHierarchyHelper
{
template<class TList, template <class, class> class Unit, class Root>
struct In
{
typedef typename TList::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <>
struct GenLinearHierarchyHelper<TL::Typelist_tag>
{
template<class TList, template <class, class> class Unit, class Root>
struct In
{
private:
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
public:
typedef Unit< Head, GenLinearHierarchy<Tail, Unit, Root> > Result;
};
};
template <>
struct GenLinearHierarchyHelper<TL::NullType_tag>
{
template<class TList, template <class, class> class Unit, class Root>
struct In
{
private:
typedef typename TList::Head Head;
public:
typedef Unit<Head, Root> Result;
};
};
} // namespace Private
template
<
class TList,
template <class AtomicType, class UnitBase> class Unit,
class Root
>
class GenLinearHierarchy
: public Private::GenLinearHierarchyHelper
<
typename TL::is_Typelist<typename TList::Tail>::type_tag
>
::template In<TList, Unit, Root>::Result
{
ASSERT_TYPELIST(TList); // TList must not be NullType
public:
typedef typename Private::GenLinearHierarchyHelper
<
typename TL::is_Typelist<typename TList::Tail>::type_tag
>
::template In<TList, Unit, Root>::Result LinBase;
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // HIERARCHYGENERATORS_INC_
#ifdef _MSC_VER
#pragma warning( pop )
#endif // _MSC_VER

View file

@ -0,0 +1,107 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef LOKITYPEINFO_INC_
#define LOKITYPEINFO_INC_
#include <typeinfo>
#include <cassert>
#include "Typelist.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class TypeInfo
// Purpose: offer a first-class, comparable wrapper over std::type_info
////////////////////////////////////////////////////////////////////////////////
class TypeInfo
{
public:
// Constructors
TypeInfo(); // needed for containers
TypeInfo(const std::type_info&); // non-explicit
// Access for the wrapped std::type_info
const std::type_info& Get() const;
// Compatibility functions
bool before(const TypeInfo& rhs) const;
const char* name() const;
private:
const std::type_info* pInfo_;
};
// Implementation
inline TypeInfo::TypeInfo()
{
class Nil {};
pInfo_ = &typeid(Nil);
assert(pInfo_);
}
inline TypeInfo::TypeInfo(const std::type_info& ti)
: pInfo_(&ti)
{ assert(pInfo_); }
inline bool TypeInfo::before(const TypeInfo& rhs) const
{
assert(pInfo_);
return pInfo_->before(*rhs.pInfo_) != 0;
}
inline const std::type_info& TypeInfo::Get() const
{
assert(pInfo_);
return *pInfo_;
}
inline const char* TypeInfo::name() const
{
assert(pInfo_);
return pInfo_->name();
}
// Comparison operators
inline bool operator==(const TypeInfo& lhs, const TypeInfo& rhs)
{ return (lhs.Get() == rhs.Get()) != 0; }
inline bool operator<(const TypeInfo& lhs, const TypeInfo& rhs)
{ return lhs.before(rhs); }
inline bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs == rhs); }
inline bool operator>(const TypeInfo& lhs, const TypeInfo& rhs)
{ return rhs < lhs; }
inline bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs > rhs); }
inline bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs)
{ return !(lhs < rhs); }
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // LOKITYPEINFO_INC_

112
include/noncc/MSVC/1300/MinMax.h Executable file
View file

@ -0,0 +1,112 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef MINMAX_INC_
#define MINMAX_INC_
#include "Typelist.h"
#include "TypeTraits.h"
namespace Private
{
typedef TYPELIST_14(
const bool,
const char,
const signed char,
const unsigned char,
const wchar_t,
const short int,
const unsigned short int,
const int,
const unsigned int,
const long int,
const unsigned long int,
const float,
const double,
const long double)
ArithTypes;
}
template <class L, class R>
class MinMaxTraits
{
typedef typename Loki::Select<Loki::Conversion<R, L>::exists,
L, R>::Result
T1;
enum { pos1 = Loki::TL::IndexOf<Private::ArithTypes, const L>::value };
enum { pos2 = Loki::TL::IndexOf<Private::ArithTypes, const R>::value };
typedef Loki::Select<pos1 != -1 && pos1 < pos2, R, T1>::Result T2;
enum { rConst = Loki::TypeTraits<R>::isConst >=
Loki::TypeTraits<L>::isConst };
enum { l2r = rConst && Loki::Conversion<
typename Loki::TypeTraits<L>::NonConstType&,
typename Loki::TypeTraits<R>::NonConstType&>::exists };
typedef typename Loki::Select<l2r, R&, T2>::Result T3;
enum { lConst = Loki::TypeTraits<L>::isConst >=
Loki::TypeTraits<R>::isConst };
enum { r2l = lConst && Loki::Conversion<
typename Loki::TypeTraits<R>::NonConstType&,
typename Loki::TypeTraits<L>::NonConstType&>::exists };
public:
typedef typename Loki::Select<r2l, L&, T3>::Result Result;
};
template <class L, class R>
typename MinMaxTraits<L, R>::Result
Min(L& lhs, R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<const L, R>::Result
Min(const L& lhs, R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<L, const R>::Result
Min(L& lhs, const R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<const L, const R>::Result
Min(const L& lhs, const R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<L, R>::Result
Max(L& lhs, R& rhs)
{ if (lhs > rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<const L, R>::Result
Max(const L& lhs, R& rhs)
{ if (lhs > rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<L, const R>::Result
Max(L& lhs, const R& rhs)
{ if (lhs > rhs) return lhs; return rhs; }
template <class L, class R>
typename MinMaxTraits<const L, const R>::Result
Max(const L& lhs, const R& rhs)
{ if (lhs > rhs) return lhs; return rhs; }
#endif // MINMAX_INC_

View file

@ -0,0 +1,418 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef MULTIMETHODS_INC_
#define MULTIMETHODS_INC_
#include "Typelist.h"
#include "LokiTypeInfo.h"
#include "Functor.h"
#include "AssocVector.h"
////////////////////////////////////////////////////////////////////////////////
// IMPORTANT NOTE:
// The double dispatchers implemented below differ from the excerpts shown in
// the book - they are simpler while respecting the same interface.
////////////////////////////////////////////////////////////////////////////////
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template InvocationTraits (helper)
// Helps implementing optional symmetry
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class SomeLhs, class SomeRhs,
class Executor, typename ResultType>
struct InvocationTraits
{
static ResultType
DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
Executor& exec, Int2Type<false>)
{
return exec.Fire(lhs, rhs);
}
static ResultType
DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
Executor& exec, Int2Type<true>)
{
return exec.Fire(rhs, lhs);
}
};
}
////////////////////////////////////////////////////////////////////////////////
// class template StaticDispatcher
// Implements an automatic static double dispatcher based on two typelists
////////////////////////////////////////////////////////////////////////////////
template
<
class Executor,
class BaseLhs,
class TypesLhs,
bool symmetric = true,
class BaseRhs = BaseLhs,
class TypesRhs = TypesLhs,
typename ResultType = void
>
class StaticDispatcher
{
template <class SomeLhs>
static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ return exec.OnError(lhs, rhs); }
template <class Head, class Tail, class SomeLhs>
static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p2 = dynamic_cast<Head*>(&rhs))
{
Int2Type<(symmetric &&
int(TL::IndexOf<TypesRhs, Head>::value) <
int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
typedef Private::InvocationTraits<
SomeLhs, Head, Executor, ResultType> CallTraits;
return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
}
return DispatchRhs(lhs, rhs, exec, Tail());
}
static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
Executor exec, NullType)
{ return exec.OnError(lhs, rhs); }
template <class Head, class Tail>
static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
Executor exec, Typelist<Head, Tail>)
{
if (Head* p1 = dynamic_cast<Head*>(&lhs))
{
return DispatchRhs(*p1, rhs, exec, TypesRhs());
}
return DispatchLhs(lhs, rhs, exec, Tail());
}
public:
static ResultType Go(BaseLhs& lhs, BaseRhs& rhs,
Executor exec)
{ return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
};
////////////////////////////////////////////////////////////////////////////////
// class template BasicDispatcher
// Implements a logarithmic double dispatcher for functors (or functions)
// Doesn't offer automated casts or symmetry
////////////////////////////////////////////////////////////////////////////////
template
<
class BaseLhs,
class BaseRhs = BaseLhs,
typename ResultType = void,
typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
>
class BasicDispatcher
{
typedef std::pair<TypeInfo,TypeInfo> KeyType;
typedef CallbackType MappedType;
typedef AssocVector<KeyType, MappedType> MapType;
MapType callbackMap_;
void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun);
bool DoRemove(TypeInfo lhs, TypeInfo rhs);
public:
template <class SomeLhs, class SomeRhs>
void Add(CallbackType fun)
{
DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
}
template <class SomeLhs, class SomeRhs>
bool Remove()
{
return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
}
ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
};
// Non-inline to reduce compile time overhead...
template <class BaseLhs, class BaseRhs,
typename ResultType, typename CallbackType>
void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
{
callbackMap_[KeyType(lhs, rhs)] = fun;
}
template <class BaseLhs, class BaseRhs,
typename ResultType, typename CallbackType>
bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
::DoRemove(TypeInfo lhs, TypeInfo rhs)
{
return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
}
template <class BaseLhs, class BaseRhs,
typename ResultType, typename CallbackType>
ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
::Go(BaseLhs& lhs, BaseRhs& rhs)
{
typename MapType::key_type k(typeid(lhs),typeid(rhs));
typename MapType::iterator i = callbackMap_.find(k);
if (i == callbackMap_.end())
{
throw std::runtime_error("Function not found");
}
return (i->second)(lhs, rhs);
}
////////////////////////////////////////////////////////////////////////////////
// class template StaticCaster
// Implementation of the CastingPolicy used by FunctorDispatcher
////////////////////////////////////////////////////////////////////////////////
template <class To, class From>
struct StaticCaster
{
static To& Cast(From& obj)
{
return static_cast<To&>(obj);
}
};
////////////////////////////////////////////////////////////////////////////////
// class template DynamicCaster
// Implementation of the CastingPolicy used by FunctorDispatcher
////////////////////////////////////////////////////////////////////////////////
template <class To, class From>
struct DynamicCaster
{
static To& Cast(From& obj)
{
return dynamic_cast<To&>(obj);
}
};
////////////////////////////////////////////////////////////////////////////////
// class template Private::FnDispatcherHelper
// Implements trampolines and argument swapping used by FnDispatcher
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class BaseLhs, class BaseRhs,
class SomeLhs, class SomeRhs,
typename ResultType,
class CastLhs, class CastRhs,
ResultType (*Callback)(SomeLhs&, SomeRhs&)>
struct FnDispatcherHelper
{
static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs)
{
return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
{
return Trampoline(lhs, rhs);
}
};
}
////////////////////////////////////////////////////////////////////////////////
// class template FnDispatcher
// Implements an automatic logarithmic double dispatcher for functions
// Features automated conversions
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class BaseRhs = BaseLhs,
typename ResultType = void,
template <class, class> class CastingPolicy = DynamicCaster,
template <class, class, class, class>
class DispatcherBackend = BasicDispatcher>
class FnDispatcher
{
DispatcherBackend<BaseLhs, BaseRhs, ResultType,
ResultType (*)(BaseLhs&, BaseRhs&)> backEnd_;
public:
template <class SomeLhs, class SomeRhs>
void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&))
{
return backEnd_.Add<SomeLhs, SomeRhs>(pFun);
}
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&)>
void Add()
{
typedef Private::FnDispatcherHelper<
BaseLhs, BaseRhs,
SomeLhs, SomeRhs,
ResultType,
CastingPolicy<SomeLhs,BaseLhs>,
CastingPolicy<SomeRhs,BaseRhs>,
callback> Local;
Add<SomeLhs, SomeRhs>(&Local::Trampoline);
}
template <class SomeLhs, class SomeRhs,
ResultType (*callback)(SomeLhs&, SomeRhs&),
bool symmetric>
void Add()
{
typedef Private::FnDispatcherHelper<
BaseLhs, BaseRhs,
SomeLhs, SomeRhs,
ResultType,
CastingPolicy<SomeLhs,BaseLhs>,
CastingPolicy<SomeRhs,BaseRhs>,
callback> Local;
Add<SomeLhs, SomeRhs>(&Local::Trampoline);
if (symmetric)
{
Add<SomeRhs, SomeLhs>(&Local::TrampolineR);
}
}
template <class SomeLhs, class SomeRhs>
void Remove()
{
backEnd_.Remove<SomeLhs, SomeRhs>();
}
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
return backEnd_.Go(lhs, rhs);
}
};
////////////////////////////////////////////////////////////////////////////////
// class template FunctorDispatcherAdaptor
// permits use of FunctorDispatcher under gcc.2.95.2/3
///////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class BaseLhs, class BaseRhs,
class SomeLhs, class SomeRhs,
typename ResultType,
class CastLhs, class CastRhs,
class Fun, bool SwapArgs>
class FunctorDispatcherHelper
{
Fun fun_;
ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>)
{
return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>)
{
return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
}
public:
FunctorDispatcherHelper(const Fun& fun) : fun_(fun) {}
ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
{
return Fire(lhs,rhs,Int2Type<SwapArgs>());
}
};
}
////////////////////////////////////////////////////////////////////////////////
// class template FunctorDispatcher
// Implements a logarithmic double dispatcher for functors
// Features automated casting
////////////////////////////////////////////////////////////////////////////////
template <class BaseLhs, class BaseRhs = BaseLhs,
typename ResultType = void,
template <class, class> class CastingPolicy = DynamicCaster,
template <class, class, class, class>
class DispatcherBackend = BasicDispatcher>
class FunctorDispatcher
{
typedef TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList;
typedef Functor<ResultType, ArgsList, DEFAULT_THREADING> FunctorType;
DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_;
public:
template <class SomeLhs, class SomeRhs, class Fun>
void Add(const Fun& fun)
{
typedef Private::FunctorDispatcherHelper<
BaseLhs, BaseRhs,
SomeLhs, SomeRhs,
ResultType,
CastingPolicy<SomeLhs, BaseLhs>,
CastingPolicy<SomeRhs, BaseRhs>,
Fun, false> Adapter;
backEnd_.Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun)));
}
template <class SomeLhs, class SomeRhs, bool symmetric, class Fun>
void Add(const Fun& fun)
{
Add<SomeLhs,SomeRhs>(fun);
if (symmetric)
{
// Note: symmetry only makes sense where BaseLhs==BaseRhs
typedef Private::FunctorDispatcherHelper<
BaseLhs, BaseLhs,
SomeLhs, SomeRhs,
ResultType,
CastingPolicy<SomeLhs, BaseLhs>,
CastingPolicy<SomeRhs, BaseLhs>,
Fun, true> AdapterR;
backEnd_.Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
}
}
template <class SomeLhs, class SomeRhs>
void Remove()
{
backEnd_.Remove<SomeLhs, SomeRhs>();
}
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
{
return backEnd_.Go(lhs, rhs);
}
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif

View file

@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef NULLTYPE_INC_
#define NULLTYPE_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class NullType
// Used as a placeholder for "no type here"
// Useful as an end marker in typelists
////////////////////////////////////////////////////////////////////////////////
class NullType
{
public:
struct Head { private: Head(); };
struct Tail { private: Tail(); };
};
}
///////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // NULLTYPE_INC_

View file

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#include "Singleton.h"
using namespace Loki::Private;
Loki::Private::TrackerArray Loki::Private::pTrackerArray = 0;
unsigned int Loki::Private::elements = 0;
////////////////////////////////////////////////////////////////////////////////
// function AtExitFn
// Ensures proper destruction of objects with longevity
////////////////////////////////////////////////////////////////////////////////
void C_CALLING_CONVENTION_QUALIFIER Loki::Private::AtExitFn()
{
assert(elements > 0 && pTrackerArray != 0);
// Pick the element at the top of the stack
LifetimeTracker* pTop = pTrackerArray[elements - 1];
// Remove that object off the stack
// Don't check errors - realloc with less memory
// can't fail
pTrackerArray = static_cast<TrackerArray>(std::realloc(
pTrackerArray, sizeof(*pTrackerArray) * --elements));
// Destroy the element
delete pTop;
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,442 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef SINGLETON_INC_
#define SINGLETON_INC_
#include "Threads.h"
#include <algorithm>
#include <stdexcept>
#include <cassert>
#include <cstdlib>
#include <new>
#ifdef _MSC_VER
#define C_CALLING_CONVENTION_QUALIFIER __cdecl
#else
#define C_CALLING_CONVENTION_QUALIFIER
#endif
namespace Loki
{
typedef void (C_CALLING_CONVENTION_QUALIFIER *atexit_pfn_t)();
namespace Private
{
////////////////////////////////////////////////////////////////////////////////
// class LifetimeTracker
// Helper class for SetLongevity
////////////////////////////////////////////////////////////////////////////////
class LifetimeTracker
{
public:
LifetimeTracker(unsigned int x) : longevity_(x)
{}
virtual ~LifetimeTracker() = 0;
static bool Compare(const LifetimeTracker* lhs,
const LifetimeTracker* rhs)
{
return lhs->longevity_ > rhs->longevity_;
}
private:
unsigned int longevity_;
};
// Definition required
inline LifetimeTracker::~LifetimeTracker() {}
// Helper data
typedef LifetimeTracker** TrackerArray;
extern TrackerArray pTrackerArray;
extern unsigned int elements;
// Helper destroyer function
template <typename T>
struct Deleter
{
static void Delete(T* pObj)
{ delete pObj; }
};
// Concrete lifetime tracker for objects of type T
template <typename T, typename Destroyer>
class ConcreteLifetimeTracker : public LifetimeTracker
{
public:
ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d)
: LifetimeTracker(longevity)
, pTracked_(p)
, destroyer_(d)
{}
~ConcreteLifetimeTracker()
{ destroyer_(pTracked_); }
private:
T* pTracked_;
Destroyer destroyer_;
};
void C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// function template SetLongevity
// Assigns an object a longevity; ensures ordered destructions of objects
// registered thusly during the exit sequence of the application
////////////////////////////////////////////////////////////////////////////////
template <typename T, typename Destroyer>
void SetLongevity(T* pDynObject, unsigned int longevity,
Destroyer d = Private::Deleter<T>::Delete)
{
using namespace Private;
TrackerArray pNewArray = static_cast<TrackerArray>(
std::realloc(pTrackerArray, sizeof(*pTrackerArray) * (elements + 1)));
if (!pNewArray) throw std::bad_alloc();
// Delayed assignment for exception safety
pTrackerArray = pNewArray;
LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>(
pDynObject, longevity, d);
// Insert a pointer to the object into the queue
TrackerArray pos = std::upper_bound(
pTrackerArray,
pTrackerArray + elements,
p,
LifetimeTracker::Compare);
std::copy_backward(
pos,
pTrackerArray + elements,
pTrackerArray + elements + 1);
*pos = p;
++elements;
// Register a call to AtExitFn
std::atexit(Private::AtExitFn);
}
////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a straight call to the new operator
////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateUsingNew
{
static T* Create()
{ return new T; }
static void Destroy(T* p)
{ delete p; }
};
////////////////////////////////////////////////////////////////////////////////
// class template CreateUsingNew
// Implementation of the CreationPolicy used by SingletonHolder
// Creates objects using a call to std::malloc, followed by a call to the
// placement new operator
////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateUsingMalloc
{
static T* Create()
{
void* p = std::malloc(sizeof(T));
if (!p) return 0;
return new(p) T;
}
static void Destroy(T* p)
{
p->~T();
std::free(p);
}
};
////////////////////////////////////////////////////////////////////////////////
// class template CreateStatic
// Implementation of the CreationPolicy used by SingletonHolder
// Creates an object in static memory
// Implementation is slightly nonportable because it uses the MaxAlign trick
// (an union of all types to ensure proper memory alignment). This trick is
// nonportable in theory but highly portable in practice.
////////////////////////////////////////////////////////////////////////////////
template <class T> struct CreateStatic
{
#ifdef _MSC_VER
#pragma warning( push )
// alignment of a member was sensitive to packing
#pragma warning( disable : 4121 )
#endif // _MSC_VER
union MaxAlign
{
char t_[sizeof(T)];
short int shortInt_;
int int_;
long int longInt_;
float float_;
double double_;
long double longDouble_;
struct Test;
int Test::* pMember_;
int (Test::*pMemberFn_)(int);
};
#ifdef _MSC_VER
#pragma warning( pop )
#endif // _MSC_VER
static T* Create()
{
static MaxAlign staticMemory_;
return new(&staticMemory_) T;
}
static void Destroy(T* p)
{
p->~T();
}
};
////////////////////////////////////////////////////////////////////////////////
// class template DefaultLifetime
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules
// Forwards to std::atexit
////////////////////////////////////////////////////////////////////////////////
template <class T>
struct DefaultLifetime
{
static void ScheduleDestruction(T*, atexit_pfn_t pFun)
{ std::atexit(pFun); }
static void OnDeadReference()
{ throw std::logic_error("Dead Reference Detected"); }
};
////////////////////////////////////////////////////////////////////////////////
// class template PhoenixSingleton
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction as per C++ rules, and it allows object
// recreation by not throwing an exception from OnDeadReference
////////////////////////////////////////////////////////////////////////////////
template <class T>
class PhoenixSingleton
{
public:
static void ScheduleDestruction(T*, atexit_pfn_t pFun)
{
#ifndef ATEXIT_FIXED
if (!destroyedOnce_)
#endif
std::atexit(pFun);
}
static void OnDeadReference()
{
#ifndef ATEXIT_FIXED
destroyedOnce_ = true;
#endif
}
private:
#ifndef ATEXIT_FIXED
static bool destroyedOnce_;
#endif
};
#ifndef ATEXIT_FIXED
template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false;
#endif
////////////////////////////////////////////////////////////////////////////////
// class template Adapter
// Helper for SingletonWithLongevity below
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
template <class T>
struct Adapter
{
void operator()(T*) { return pFun_(); }
atexit_pfn_t pFun_;
};
}
////////////////////////////////////////////////////////////////////////////////
// class template SingletonWithLongevity
// Implementation of the LifetimePolicy used by SingletonHolder
// Schedules an object's destruction in order of their longevities
// Assumes a visible function GetLongevity(T*) that returns the longevity of the
// object
////////////////////////////////////////////////////////////////////////////////
template <class T>
class SingletonWithLongevity
{
public:
static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun)
{
Private::Adapter<T> adapter = { pFun };
SetLongevity(pObj, GetLongevity(pObj), adapter);
}
static void OnDeadReference()
{ throw std::logic_error("Dead Reference Detected"); }
};
////////////////////////////////////////////////////////////////////////////////
// class template NoDestroy
// Implementation of the LifetimePolicy used by SingletonHolder
// Never destroys the object
////////////////////////////////////////////////////////////////////////////////
template <class T>
struct NoDestroy
{
static void ScheduleDestruction(T*, atexit_pfn_t)
{}
static void OnDeadReference()
{}
};
////////////////////////////////////////////////////////////////////////////////
// class template SingletonHolder
// Provides Singleton amenities for a type T
// To protect that type from spurious instantiations, you have to protect it
// yourself.
////////////////////////////////////////////////////////////////////////////////
template
<
class ClientType,
class ThreadingModelType,
class PtrInstanceType
>
class SingletonHolderStaticData
{
friend ClientType; // illegal (11.4/2) but works with VC
static PtrInstanceType s_pInstance;
static bool s_destroyed;
};
template<class C, class M, class P>
P SingletonHolderStaticData<C, M, P>::s_pInstance;
template<class C, class M, class P>
bool SingletonHolderStaticData<C, M, P>::s_destroyed;
template
<
typename T,
template <class> class CreationPolicy = CreateUsingNew,
template <class> class LifetimePolicy = DefaultLifetime,
template <class> class ThreadingModel = SingleThreaded
>
class SingletonHolder
{
typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
typedef SingletonHolderStaticData
<
SingletonHolder,
ThreadingModel<T>,
PtrInstanceType
>
MySingletonHolderStaticData;
public:
static T& Instance()
{
if (!pInstance_())
{
MakeInstance();
}
return *pInstance_();
}
private:
// Helpers
static void MakeInstance()
{
typename ThreadingModel<SingletonHolder>::Lock guard;
(void)guard;
if (!pInstance_())
{
if (destroyed_())
{
LifetimePolicy<T>::OnDeadReference();
destroyed_() = false;
}
pInstance_() = CreationPolicy<T>::Create();
LifetimePolicy<T>::ScheduleDestruction
(
pInstance_(),
&DestroySingleton
);
}
}
static void C_CALLING_CONVENTION_QUALIFIER DestroySingleton()
{
assert(!destroyed_());
CreationPolicy<T>::Destroy(pInstance_());
pInstance_() = 0;
destroyed_() = true;
}
// Protection
SingletonHolder();
// Data
static PtrInstanceType &pInstance_()
{
return MySingletonHolderStaticData::s_pInstance;
}
static bool &destroyed_()
{
return MySingletonHolderStaticData::s_destroyed;
}
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// May 21, 2001: Correct the volatile qualifier - credit due to Darin Adler
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // SINGLETON_INC_

View file

@ -0,0 +1,612 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// $Header$
#include "SmallObj.h"
#include <cassert>
#include <vector>
#include <algorithm>
#include <functional>
using namespace Loki;
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class FixedAllocator
// Offers services for allocating fixed-sized objects
////////////////////////////////////////////////////////////////////////////////
class FixedAllocator
{
private:
struct Chunk
{
bool Init( std::size_t blockSize, unsigned char blocks );
void* Allocate(std::size_t blockSize);
void Deallocate(void* p, std::size_t blockSize);
void Reset(std::size_t blockSize, unsigned char blocks);
void Release();
inline bool HasBlock( unsigned char * p, std::size_t chunkLength ) const
{ return ( pData_ <= p ) && ( p < pData_ + chunkLength ); }
inline bool HasAvailable( unsigned char numBlocks ) const
{ return ( blocksAvailable_ == numBlocks ); }
inline bool IsFilled( void ) const
{ return ( 0 == blocksAvailable_ ); }
unsigned char* pData_;
unsigned char
firstAvailableBlock_,
blocksAvailable_;
};
// Internal functions
void DoDeallocate(void* p);
bool MakeNewChunk( void );
Chunk * VicinityFind( void * p );
/// Not implemented.
FixedAllocator(const FixedAllocator&);
/// Not implemented.
FixedAllocator& operator=(const FixedAllocator&);
// Data
std::size_t blockSize_;
unsigned char numBlocks_;
typedef std::vector<Chunk> Chunks;
typedef Chunks::iterator ChunkIter;
typedef Chunks::const_iterator ChunkCIter;
Chunks chunks_;
Chunk* allocChunk_;
Chunk* deallocChunk_;
Chunk * emptyChunk_;
public:
// Create a FixedAllocator able to manage blocks of 'blockSize' size
FixedAllocator();
~FixedAllocator();
void Initialize( std::size_t blockSize, std::size_t pageSize );
// Allocate a memory block
void * Allocate( void );
// Deallocate a memory block previously allocated with Allocate()
// (if that's not the case, the behavior is undefined)
bool Deallocate( void * p, bool doChecks );
// Returns the block size with which the FixedAllocator was initialized
inline std::size_t BlockSize() const
{ return blockSize_; }
};
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Init
// Initializes a chunk object
////////////////////////////////////////////////////////////////////////////////
bool FixedAllocator::Chunk::Init( std::size_t blockSize, unsigned char blocks )
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
const std::size_t allocSize = blockSize * blocks;
assert( allocSize / blockSize == blocks);
#ifdef USE_NEW_TO_ALLOCATE
// If this new operator fails, it will throw, and the exception will get
// caught one layer up.
pData_ = new unsigned char[ allocSize ];
#else
// malloc can't throw, so its only way to indicate an error is to return
// a NULL pointer, so we have to check for that.
pData_ = static_cast< unsigned char * >( ::malloc( allocSize ) );
if ( NULL == pData_ ) return false;
#endif
Reset( blockSize, blocks );
return true;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Reset
// Clears an already allocated chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Reset(std::size_t blockSize, unsigned char blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
assert((blockSize * blocks) / blockSize == blocks);
firstAvailableBlock_ = 0;
blocksAvailable_ = blocks;
unsigned char i = 0;
unsigned char* p = pData_;
for (; i != blocks; p += blockSize)
{
*p = ++i;
}
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Release
// Releases the data managed by a chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Release()
{
assert( NULL != pData_ );
#ifdef USE_NEW_TO_ALLOCATE
delete [] pData_;
#else
::free( static_cast< void * >( pData_ ) );
#endif
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Allocate
// Allocates a block from a chunk
////////////////////////////////////////////////////////////////////////////////
void* FixedAllocator::Chunk::Allocate(std::size_t blockSize)
{
if ( IsFilled() ) return NULL;
assert((firstAvailableBlock_ * blockSize) / blockSize ==
firstAvailableBlock_);
unsigned char * pResult = pData_ + (firstAvailableBlock_ * blockSize);
firstAvailableBlock_ = *pResult;
--blocksAvailable_;
return pResult;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Chunk::Deallocate
// Dellocates a block from a chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Chunk::Deallocate(void* p, std::size_t blockSize)
{
assert(p >= pData_);
unsigned char* toRelease = static_cast<unsigned char*>(p);
// Alignment check
assert((toRelease - pData_) % blockSize == 0);
*toRelease = firstAvailableBlock_;
firstAvailableBlock_ = static_cast<unsigned char>(
(toRelease - pData_) / blockSize);
// Truncation check
assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize);
++blocksAvailable_;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::FixedAllocator
// Creates a FixedAllocator object of a fixed block size
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::FixedAllocator()
: blockSize_( 0 )
, allocChunk_( NULL )
, deallocChunk_( NULL )
, emptyChunk_( NULL )
{
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::~FixedAllocator
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::~FixedAllocator()
{
for ( ChunkIter i( chunks_.begin() ); i != chunks_.end(); ++i )
i->Release();
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Initialize
// Initializes the operational constraints for the FixedAllocator
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::Initialize( std::size_t blockSize, std::size_t pageSize )
{
assert( blockSize > 0 );
assert( pageSize >= blockSize );
blockSize_ = blockSize;
std::size_t numBlocks = pageSize / blockSize;
if (numBlocks > UCHAR_MAX) numBlocks = UCHAR_MAX;
else if ( numBlocks < 8 ) numBlocks = 8;
numBlocks_ = static_cast<unsigned char>(numBlocks);
assert(numBlocks_ == numBlocks);
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::MakeNewChunk
// Allocates a new Chunk for a FixedAllocator.
////////////////////////////////////////////////////////////////////////////////
bool FixedAllocator::MakeNewChunk( void )
{
bool allocated = false;
try
{
// Calling chunks_.reserve *before* creating and initializing the new
// Chunk means that nothing is leaked by this function in case an
// exception is thrown from reserve.
chunks_.reserve( chunks_.size() + 1 );
Chunk newChunk;
allocated = newChunk.Init( blockSize_, numBlocks_ );
if ( allocated )
chunks_.push_back( newChunk );
}
catch ( ... )
{
allocated = false;
}
if ( !allocated ) return false;
allocChunk_ = &chunks_.back();
deallocChunk_ = &chunks_.front();
return true;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Allocate
// Allocates a block of fixed size
////////////////////////////////////////////////////////////////////////////////
void * FixedAllocator::Allocate( void )
{
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
if ( ( NULL == allocChunk_ ) || allocChunk_->IsFilled() )
{
if ( NULL != emptyChunk_ )
{
allocChunk_ = emptyChunk_;
emptyChunk_ = NULL;
}
else
{
for ( ChunkIter i( chunks_.begin() ); ; ++i )
{
if ( chunks_.end() == i )
{
if ( !MakeNewChunk() )
return NULL;
break;
}
if ( !i->IsFilled() )
{
allocChunk_ = &*i;
break;
}
}
}
}
else if ( allocChunk_ == emptyChunk_)
// detach emptyChunk_ from allocChunk_, because after
// calling allocChunk_->Allocate(blockSize_); the chunk
// isn't any more empty
emptyChunk_ = NULL;
assert( allocChunk_ != NULL );
assert( !allocChunk_->IsFilled() );
void *place = allocChunk_->Allocate(blockSize_);
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
return place;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::Deallocate
// Deallocates a block previously allocated with Allocate
// (undefined behavior if called with the wrong pointer)
////////////////////////////////////////////////////////////////////////////////
bool FixedAllocator::Deallocate( void * p, bool doChecks )
{
if ( doChecks )
{
assert(!chunks_.empty());
assert(&chunks_.front() <= deallocChunk_);
assert(&chunks_.back() >= deallocChunk_);
assert( &chunks_.front() <= allocChunk_ );
assert( &chunks_.back() >= allocChunk_ );
}
Chunk * foundChunk = VicinityFind( p );
if ( doChecks )
{
assert( NULL != foundChunk );
}
else if ( NULL == foundChunk )
return false;
deallocChunk_ = foundChunk;
DoDeallocate(p);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::VicinityFind (internal)
// Finds the chunk corresponding to a pointer, using an efficient search
////////////////////////////////////////////////////////////////////////////////
FixedAllocator::Chunk * FixedAllocator::VicinityFind( void * p )
{
if ( chunks_.empty() ) return NULL;
assert(deallocChunk_);
unsigned char * pc = static_cast< unsigned char * >( p );
const std::size_t chunkLength = numBlocks_ * blockSize_;
Chunk* lo = deallocChunk_;
Chunk* hi = deallocChunk_ + 1;
Chunk* loBound = &chunks_.front();
Chunk* hiBound = &chunks_.back() + 1;
// Special case: deallocChunk_ is the last in the array
if (hi == hiBound) hi = NULL;
for (;;)
{
if (lo)
{
if ( lo->HasBlock( pc, chunkLength ) ) return lo;
if ( lo == loBound )
{
lo = NULL;
if ( NULL == hi ) break;
}
else --lo;
}
if (hi)
{
if ( hi->HasBlock( pc, chunkLength ) ) return hi;
if ( ++hi == hiBound )
{
hi = NULL;
if ( NULL == lo ) break;
}
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
// FixedAllocator::DoDeallocate (internal)
// Performs deallocation. Assumes deallocChunk_ points to the correct chunk
////////////////////////////////////////////////////////////////////////////////
void FixedAllocator::DoDeallocate(void* p)
{
assert( deallocChunk_->HasBlock( static_cast< unsigned char * >( p ),
numBlocks_ * blockSize_ ) );
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
// call into the chunk, will adjust the inner list but won't release memory
deallocChunk_->Deallocate(p, blockSize_);
if ( deallocChunk_->HasAvailable( numBlocks_ ) )
{
assert( emptyChunk_ != deallocChunk_ );
// deallocChunk_ is empty, but a Chunk is only released if there are 2
// empty chunks. Since emptyChunk_ may only point to a previously
// cleared Chunk, if it points to something else besides deallocChunk_,
// then FixedAllocator currently has 2 empty Chunks.
if ( NULL != emptyChunk_ )
{
// If last Chunk is empty, just change what deallocChunk_
// points to, and release the last. Otherwise, swap an empty
// Chunk with the last, and then release it.
Chunk * lastChunk = &chunks_.back();
if ( lastChunk == deallocChunk_ )
deallocChunk_ = emptyChunk_;
else if ( lastChunk != emptyChunk_ )
std::swap( *emptyChunk_, *lastChunk );
assert( lastChunk->HasAvailable( numBlocks_ ) );
lastChunk->Release();
chunks_.pop_back();
allocChunk_ = deallocChunk_;
}
emptyChunk_ = deallocChunk_;
}
// prove either emptyChunk_ points nowhere, or points to a truly empty Chunk.
assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) );
}
////////////////////////////////////////////////////////////////////////////////
// GetOffset
// Calculates index into array where a FixedAllocator of numBytes is located.
////////////////////////////////////////////////////////////////////////////////
inline std::size_t GetOffset( std::size_t numBytes, std::size_t alignment )
{
const std::size_t alignExtra = alignment-1;
return ( numBytes + alignExtra ) / alignment;
}
////////////////////////////////////////////////////////////////////////////////
// DefaultAllocator
// Call to default allocator when SmallObjAllocator decides not to handle request.
////////////////////////////////////////////////////////////////////////////////
void * DefaultAllocator( std::size_t numBytes, bool doThrow )
{
#ifdef USE_NEW_TO_ALLOCATE
return doThrow ? ::operator new( numBytes ) :
::operator new( numBytes, std::nothrow_t() );
#else
void * p = ::malloc( numBytes );
if ( doThrow && ( NULL == p ) )
throw std::bad_alloc();
return p;
#endif
}
////////////////////////////////////////////////////////////////////////////////
// DefaultDeallocator
// Call to default deallocator when SmallObjAllocator decides not to handle request.
////////////////////////////////////////////////////////////////////////////////
void DefaultDeallocator( void * p )
{
#ifdef USE_NEW_TO_ALLOCATE
::operator delete( p );
#else
::free( p );
#endif
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::SmallObjAllocator
// Creates a SmallObjAllocator, and all the FixedAllocators within it. Each
// FixedAllocator is then initialized to use the correct Chunk size.
////////////////////////////////////////////////////////////////////////////////
SmallObjAllocator::SmallObjAllocator( std::size_t pageSize,
std::size_t maxObjectSize, std::size_t objectAlignSize ) :
pool_( NULL ),
maxSmallObjectSize_( maxObjectSize ),
objectAlignSize_( objectAlignSize )
{
assert( 0 != objectAlignSize );
const std::size_t allocCount = GetOffset( maxObjectSize, objectAlignSize );
pool_ = new FixedAllocator[ allocCount ];
for ( std::size_t i = 0; i < allocCount; ++i )
pool_[ i ].Initialize( ( i+1 ) * objectAlignSize, pageSize );
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::~SmallObjAllocator
// Deletes all memory consumed by SmallObjAllocator.
// This deletes all the FixedAllocator's in the pool.
////////////////////////////////////////////////////////////////////////////////
SmallObjAllocator::~SmallObjAllocator( void )
{
delete [] pool_;
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::Allocate
// Handles request to allocate numBytes for 1 object.
// This acts in constant-time - except for the calls to DefaultAllocator
// and sometimes FixedAllocator::Allocate. It throws bad_alloc only if the
// doThrow parameter is true and can't allocate another block. Otherwise, it
// provides the no-throw exception safety level.
////////////////////////////////////////////////////////////////////////////////
void * SmallObjAllocator::Allocate( std::size_t numBytes, bool doThrow )
{
if ( numBytes > GetMaxObjectSize() )
return DefaultAllocator( numBytes, doThrow );
assert( NULL != pool_ );
if ( 0 == numBytes ) numBytes = 1;
const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
assert( index < allocCount );
FixedAllocator & allocator = pool_[ index ];
assert( allocator.BlockSize() >= numBytes );
assert( allocator.BlockSize() < numBytes + GetAlignment() );
void * place = allocator.Allocate();
if ( ( NULL == place ) && doThrow )
{
#if _MSC_VER
throw std::bad_alloc( "could not allocate small object" );
#else
// GCC did not like a literal string passed to std::bad_alloc.
// so just throw the default-constructed exception.
throw std::bad_alloc();
#endif
}
return place;
}
////////////////////////////////////////////////////////////////////////////////
// SmallObjAllocator::Deallocate
// Handles request to deallocate numBytes for 1 object.
// This will act in constant-time - except for the calls to DefaultDeallocator
// and sometimes FixedAllocator::Deallocate. It will never throw.
////////////////////////////////////////////////////////////////////////////////
void SmallObjAllocator::Deallocate( void * p, std::size_t numBytes )
{
if ( NULL == p ) return;
if ( numBytes > GetMaxObjectSize() )
{
DefaultDeallocator( p );
return;
}
assert( NULL != pool_ );
if ( 0 == numBytes ) numBytes = 1;
const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1;
const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() );
assert( index < allocCount );
FixedAllocator & allocator = pool_[ index ];
assert( allocator.BlockSize() >= numBytes );
assert( allocator.BlockSize() < numBytes + GetAlignment() );
const bool found = allocator.Deallocate( p, true );
assert( found );
}
}; // end namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20: fix exception safety issue in FixedAllocator::Allocate
// (thanks to Chris Udazvinis for pointing that out)
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Aug 02, 2002: Fix in VicinityFind sent by Pavel Vozenilek
// Nov 26, 2004: Re-implemented by Rich Sposato.
// Jun 22, 2005: Fix in FixedAllocator::Allocate by Chad Lehman
////////////////////////////////////////////////////////////////////////////////
// $Log$
// Revision 1.1 2005/07/20 08:40:01 syntheticpp
// move directory: MSVC->include/noncc
//
// Revision 1.9 2005/07/20 00:34:15 rich_sposato
// Fixed overflow bug in calculating number of blocks per Chunk.
//

View file

@ -0,0 +1,165 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Last update: Nov 26, 2004
#ifndef SMALLOBJ_INC_
#define SMALLOBJ_INC_
#include "Threads.h"
#include "Singleton.h"
#include <cstddef>
#include <new> // needed for std::nothrow_t parameter.
#ifndef DEFAULT_CHUNK_SIZE
#define DEFAULT_CHUNK_SIZE 4096
#endif
#ifndef MAX_SMALL_OBJECT_SIZE
#define MAX_SMALL_OBJECT_SIZE 256
#endif
#ifndef LOKI_DEFAULT_OBJECT_ALIGNMENT
#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4
#endif
namespace Loki
{
class FixedAllocator;
class SmallObjAllocator
{
public:
SmallObjAllocator( std::size_t pageSize, std::size_t maxObjectSize,
std::size_t objectAlignSize );
~SmallObjAllocator( void );
void * Allocate( std::size_t size, bool doThrow );
void Deallocate( void * p, std::size_t size );
inline std::size_t GetMaxObjectSize() const { return maxSmallObjectSize_; }
inline std::size_t GetAlignment() const { return objectAlignSize_; }
private:
Loki::FixedAllocator * pool_;
std::size_t maxSmallObjectSize_;
std::size_t objectAlignSize_;
};
////////////////////////////////////////////////////////////////////////////////
// class SmallObject
// Base class for polymorphic small objects, offers fast allocations &
// deallocations. Destructor is virtual and public.
////////////////////////////////////////////////////////////////////////////////
template
<
template <class> class ThreadingModel = DEFAULT_THREADING,
std::size_t chunkSize = DEFAULT_CHUNK_SIZE,
std::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE,
std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT
>
class SmallObject : public ThreadingModel<
SmallObject< ThreadingModel, chunkSize, maxSmallObjectSize, objectAlignSize > >
{
typedef ThreadingModel< SmallObject<ThreadingModel,
chunkSize, maxSmallObjectSize, objectAlignSize > > MyThreadingModel;
struct MySmallObjAllocator : public SmallObjAllocator
{
MySmallObjAllocator()
: SmallObjAllocator( chunkSize, maxSmallObjectSize, objectAlignSize )
{}
};
// The typedef below would make things much simpler,
// but MWCW won't like it
// typedef SingletonHolder<MySmallObjAllocator/*, CreateStatic,
// NoDestroy, ThreadingModel*/> MyAllocator;
public:
#if (MAX_SMALL_OBJECT_SIZE != 0) && (DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0)
/// Throwing single-object new.
static void * operator new ( std::size_t size ) throw ( std::bad_alloc )
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return SingletonHolder< MySmallObjAllocator, CreateStatic,
NoDestroy >::Instance().Allocate( size, true );
}
/// Non-throwing single-object new.
static void * operator new ( std::size_t size, const std::nothrow_t & ) throw ()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
return SingletonHolder< MySmallObjAllocator, CreateStatic,
NoDestroy >::Instance().Allocate( size, false );
}
/// Placement single-object new.
static void * operator new ( std::size_t size, void * place )
{
return ::operator new( size, place );
}
/// Single-object delete.
static void operator delete ( void * p, std::size_t size ) throw ()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
SingletonHolder< MySmallObjAllocator, CreateStatic,
NoDestroy >::Instance().Deallocate( p, size );
}
/// Non-throwing single-object delete.
static void operator delete ( void * p, std::size_t size,
const std::nothrow_t & ) throw()
{
typename MyThreadingModel::Lock lock;
(void)lock; // get rid of warning
SingletonHolder< MySmallObjAllocator, CreateStatic,
NoDestroy >::Instance().Deallocate( p, size );
}
/// Placement single-object delete.
static void operator delete ( void * p, void * place )
{
::operator delete ( p, place );
}
#endif // #if default template parameters are not zero
virtual ~SmallObject() {}
}; // end class SmallObject
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// Nov. 26, 2004: re-implemented by Rich Sposato.
////////////////////////////////////////////////////////////////////////////////
#endif // SMALLOBJ_INC_

1331
include/noncc/MSVC/1300/SmartPtr.h Executable file

File diff suppressed because it is too large Load diff

199
include/noncc/MSVC/1300/Threads.h Executable file
View file

@ -0,0 +1,199 @@
#ifndef THREADS_H_
#define THREADS_H_
////////////////////////////////////////////////////////////////////////////////
// macro DEFAULT_THREADING
// Selects the default threading model for certain components of Loki
// If you don't define it, it defaults to single-threaded
// All classes in Loki have configurable threading model; DEFAULT_THREADING
// affects only default template arguments
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef DEFAULT_THREADING
#define DEFAULT_THREADING /**/ ::Loki::SingleThreaded
#endif
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template SingleThreaded
// Implementation of the ThreadingModel policy used by various classes
// Implements a single-threaded model; no synchronization
////////////////////////////////////////////////////////////////////////////////
template <class Host>
class SingleThreaded
{
public:
struct Lock
{
Lock() {}
explicit Lock(const SingleThreaded&) {}
};
typedef Host VolatileType;
typedef int IntType;
static IntType AtomicAdd(volatile IntType& lval, IntType val)
{ return lval += val; }
static IntType AtomicSubtract(volatile IntType& lval, IntType val)
{ return lval -= val; }
static IntType AtomicMultiply(volatile IntType& lval, IntType val)
{ return lval *= val; }
static IntType AtomicDivide(volatile IntType& lval, IntType val)
{ return lval /= val; }
static IntType AtomicIncrement(volatile IntType& lval)
{ return ++lval; }
static IntType AtomicDecrement(volatile IntType& lval)
{ return --lval; }
static void AtomicAssign(volatile IntType & lval, IntType val)
{ lval = val; }
static void AtomicAssign(IntType & lval, volatile IntType & val)
{ lval = val; }
};
#ifdef _WINDOWS_
////////////////////////////////////////////////////////////////////////////////
// class template ObjectLevelLockable
// Implementation of the ThreadingModel policy used by various classes
// Implements a object-level locking scheme
////////////////////////////////////////////////////////////////////////////////
template <class Host>
class ObjectLevelLockable
{
mutable CRITICAL_SECTION mtx_;
public:
ObjectLevelLockable()
{
::InitializeCriticalSection(&mtx_);
}
~ObjectLevelLockable()
{
::DeleteCriticalSection(&mtx_);
}
class Lock;
friend class Lock;
class Lock
{
ObjectLevelLockable const& host_;
Lock(const Lock&);
Lock& operator=(const Lock&);
public:
explicit Lock(const ObjectLevelLockable& host) : host_(host)
{
::EnterCriticalSection(&host_.mtx_);
}
~Lock()
{
::LeaveCriticalSection(&host_.mtx_);
}
};
typedef volatile Host VolatileType;
typedef LONG IntType;
static IntType AtomicIncrement(volatile IntType& lval)
{ return InterlockedIncrement(&const_cast<IntType&>(lval)); }
static IntType AtomicDecrement(volatile IntType& lval)
{ return InterlockedDecrement(&const_cast<IntType&>(lval)); }
static void AtomicAssign(volatile IntType& lval, IntType val)
{ InterlockedExchange(&const_cast<IntType&>(lval), val); }
static void AtomicAssign(IntType& lval, volatile IntType& val)
{ InterlockedExchange(&lval, val); }
};
template <class Host>
class ClassLevelLockable
{
struct Initializer
{
CRITICAL_SECTION mtx_;
Initializer()
{
::InitializeCriticalSection(&mtx_);
}
~Initializer()
{
::DeleteCriticalSection(&mtx_);
}
};
static Initializer initializer_;
public:
class Lock;
friend class Lock;
class Lock
{
Lock(const Lock&);
Lock& operator=(const Lock&);
public:
Lock()
{
::EnterCriticalSection(&initializer_.mtx_);
}
explicit Lock(const ClassLevelLockable&)
{
::EnterCriticalSection(&initializer_.mtx_);
}
~Lock()
{
::LeaveCriticalSection(&initializer_.mtx_);
}
};
typedef volatile Host VolatileType;
typedef LONG IntType;
static IntType AtomicIncrement(volatile IntType& lval)
{ return InterlockedIncrement(&const_cast<IntType&>(lval)); }
static IntType AtomicDecrement(volatile IntType& lval)
{ return InterlockedDecrement(&const_cast<IntType&>(lval)); }
static void AtomicAssign(volatile IntType& lval, IntType val)
{ InterlockedExchange(&const_cast<IntType&>(lval), val); }
static void AtomicAssign(IntType& lval, volatile IntType& val)
{ InterlockedExchange(&lval, val); }
};
template <class Host>
typename ClassLevelLockable<Host>::Initializer
ClassLevelLockable<Host>::initializer_;
#endif
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif

View file

@ -0,0 +1,245 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef TYPEMANIP_INC_
#define TYPEMANIP_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template Int2Type
// Converts each integral constant into a unique type
// Invocation: Int2Type<v> where v is a compile-time constant integral
// Defines 'value', an enum that evaluates to v
////////////////////////////////////////////////////////////////////////////////
template <int v>
struct Int2Type
{
enum { value = v };
};
////////////////////////////////////////////////////////////////////////////////
// class template Type2Type
// Converts each type into a unique, insipid type
// Invocation Type2Type<T> where T is a type
// Defines the type OriginalType which maps back to T
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct Type2Type
{
typedef T OriginalType;
Type2Type(){} // VC7
};
////////////////////////////////////////////////////////////////////////////////
// class template Select
// Selects one of two types based upon a boolean constant
// Invocation: Select<flag, T, U>::Result
// where:
// flag is a compile-time boolean constant
// T and U are types
// Result evaluates to T if flag is true, and to U otherwise.
////////////////////////////////////////////////////////////////////////////////
template <bool flag, typename T, typename U>
struct Select
{
private:
template<bool>
struct In
{ typedef T Result; };
template<>
struct In<false>
{ typedef U Result; };
public:
typedef typename In<flag>::Result Result;
};
////////////////////////////////////////////////////////////////////////////////
// class template IsSameType
// Return true iff two given types are the same
// Invocation: IsSameType<T, U>::value
// where:
// T and U are types
// Result evaluates to true iff U == T (types equal)
////////////////////////////////////////////////////////////////////////////////
template <typename T, typename U>
struct IsSameType
{
private:
template<typename>
struct In
{ enum { value = false }; };
template<>
struct In<T>
{ enum { value = true }; };
public:
enum { value = In<U>::value };
};
////////////////////////////////////////////////////////////////////////////////
// Helper types Small and Big - guarantee that sizeof(Small) < sizeof(Big)
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
typedef char Small;
class Big { char dummy[2]; };
template<typename T>
struct IsVoid
{
enum { result =
IsSameType<T, void>::value ||
IsSameType<T, const void>::value ||
IsSameType<T, volatile void>::value ||
IsSameType<T, const volatile void>::value
};
};
}
//
// is one type convertable to another?
//
template <class T, class U>
class is_convertible
{
struct VoidReplace {};
typedef typename Select
<
Private::IsVoid<T>::result,
VoidReplace, T
>
::Result T1;
typedef typename Select
<
Private::IsVoid<U>::result,
VoidReplace, U
>
::Result U1;
static Private::Big Test(...);
static Private::Small Test(U1);
static T1 MakeT();
public:
enum { exists = sizeof(Test(MakeT())) == sizeof(Private::Small) };
};
////////////////////////////////////////////////////////////////////////////////
// class template Conversion
// Figures out the conversion relationships between two types
// Invocations (T and U are types):
// a) Conversion<T, U>::exists
// returns (at compile time) true if there is an implicit conversion from T
// to U (example: Derived to Base)
// b) Conversion<T, U>::exists2Way
// returns (at compile time) true if there are both conversions from T
// to U and from U to T (example: int to char and back)
// c) Conversion<T, U>::sameType
// returns (at compile time) true if T and U represent the same type
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template <class T, class U>
struct Conversion
{
enum { exists = (is_convertible<T,U>::exists) };
enum { exists2Way = (exists && is_convertible<U, T>::exists) };
enum { sameType = (IsSameType<T, U>::value) };
};
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclass
// Invocation: SuperSubclass<B, D>::value where B and D are types.
// Returns true if B is a public base of D, or if B and D are aliases of the
// same type.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template <class T, class U>
struct SuperSubclass
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType) };
};
////////////////////////////////////////////////////////////////////////////////
// class template SuperSubclassStrict
// Invocation: SuperSubclassStrict<B, D>::value where B and D are types.
// Returns true if B is a public base of D.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
////////////////////////////////////////////////////////////////////////////////
template<class T,class U>
struct SuperSubclassStrict
{
enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists &&
!::Loki::Conversion<const volatile T*, const volatile void*>::sameType &&
!::Loki::Conversion<const volatile T*, const volatile U*>::sameType) };
};
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// macro SUPERSUBCLASS
// Invocation: SUPERSUBCLASS(B, D) where B and D are types.
// Returns true if B is a public base of D, or if B and D are aliases of the
// same type.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
// Deprecated: Use SuperSubclass class template instead.
////////////////////////////////////////////////////////////////////////////////
#define SUPERSUBCLASS(T, U) \
::Loki::SuperSubclass<T,U>::value
////////////////////////////////////////////////////////////////////////////////
// macro SUPERSUBCLASS_STRICT
// Invocation: SUPERSUBCLASS(B, D) where B and D are types.
// Returns true if B is a public base of D.
//
// Caveat: might not work if T and U are in a private inheritance hierarchy.
// Deprecated: Use SuperSubclassStrict class template instead.
////////////////////////////////////////////////////////////////////////////////
#define SUPERSUBCLASS_STRICT(T, U) \
::Loki::SuperSubclassStrict<T,U>::value
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
// October 10, 2002: Commented IsSameType template (not a Loki-template - yet). MKH
// October 12, 2002: Added SuperSubclass and SuperSubclassStrict templates.
// The corresponding macros are deprecated. T.S.
////////////////////////////////////////////////////////////////////////////////
#endif // TYPEMANIP_INC_

View file

@ -0,0 +1,370 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
//TODOSGB None of the parameter types are defined inside of TypeTraits, e.g. PointeeType, ReferredType, etc...
#ifndef TYPETRAITS_INC_
#define TYPETRAITS_INC_
#include "Typelist.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomUnsignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomUnsignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in unsigned
// integral type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomUnsignedInt
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomSignedInt
// Offers a means to integrate nonstandard built-in unsigned integral types
// (such as unsigned __int64 or unsigned long long int) with the TypeTraits
// class template defined below.
// Invocation: IsCustomSignedInt<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in signed
// integral type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomSignedInt
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// class template IsCustomFloat
// Offers a means to integrate nonstandard floating point types with the
// TypeTraits class template defined below.
// Invocation: IsCustomFloat<T> where T is any type
// Defines 'value', an enum that is 1 iff T is a custom built-in
// floating point type
// Specialize this class template for nonstandard unsigned integral types
// and define value = 1 in those specializations
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct IsCustomFloat
{
enum { value = 0 };
};
////////////////////////////////////////////////////////////////////////////////
// Helper types for class template TypeTraits defined below
////////////////////////////////////////////////////////////////////////////////
namespace Private
{
typedef TYPELIST_4(unsigned char, unsigned short int,
unsigned int, unsigned long int) StdUnsignedInts;
typedef TYPELIST_4(signed char, short int,
int, long int) StdSignedInts;
typedef TYPELIST_3(bool, char, wchar_t) StdOtherInts;
typedef TYPELIST_3(float, double, long double) StdFloats;
}
namespace Private
{
template<typename T>
class IsArray
{
template <typename> struct Type2Type2 {};
typedef char (&yes)[1];
typedef char (&no) [2];
template<typename U, size_t N>
static void vc7_need_this_for_is_array(Type2Type2<U(*)[N]>);
template<typename U, size_t N>
static yes is_array1(Type2Type2<U[N]>*);
static no is_array1(...);
template<typename U>
static yes is_array2(Type2Type2<U[]>*);
static no is_array2(...);
public:
enum {
value =
sizeof(is_array1((Type2Type2<T>*)0)) == sizeof(yes) ||
sizeof(is_array2((Type2Type2<T>*)0)) == sizeof(yes)
};
};
} // Private Namespace
////////////////////////////////////////////////////////////////////////////////
// class template TypeTraits
// Figures out various properties of any given type
// Invocations (T is a type):
// a) TypeTraits<T>::isPointer
// returns (at compile time) true if T is a pointer type
// b) TypeTraits<T>::PointeeType
// returns the type to which T points is T is a pointer type, NullType otherwise
// a) TypeTraits<T>::isReference
// returns (at compile time) true if T is a reference type
// b) TypeTraits<T>::ReferredType
// returns the type to which T refers is T is a reference type, NullType
// otherwise
// c) TypeTraits<T>::isMemberPointer
// returns (at compile time) true if T is a pointer to member type
// d) TypeTraits<T>::isStdUnsignedInt
// returns (at compile time) true if T is a standard unsigned integral type
// e) TypeTraits<T>::isStdSignedInt
// returns (at compile time) true if T is a standard signed integral type
// f) TypeTraits<T>::isStdIntegral
// returns (at compile time) true if T is a standard integral type
// g) TypeTraits<T>::isStdFloat
// returns (at compile time) true if T is a standard floating-point type
// h) TypeTraits<T>::isStdArith
// returns (at compile time) true if T is a standard arithmetic type
// i) TypeTraits<T>::isStdFundamental
// returns (at compile time) true if T is a standard fundamental type
// j) TypeTraits<T>::isUnsignedInt
// returns (at compile time) true if T is a unsigned integral type
// k) TypeTraits<T>::isSignedInt
// returns (at compile time) true if T is a signed integral type
// l) TypeTraits<T>::isIntegral
// returns (at compile time) true if T is a integral type
// m) TypeTraits<T>::isFloat
// returns (at compile time) true if T is a floating-point type
// n) TypeTraits<T>::isArith
// returns (at compile time) true if T is a arithmetic type
// o) TypeTraits<T>::isFundamental
// returns (at compile time) true if T is a fundamental type
// p) TypeTraits<T>::ParameterType
// returns the optimal type to be used as a parameter for functions that take Ts
// q) TypeTraits<T>::isConst
// returns (at compile time) true if T is a const-qualified type
// r) TypeTraits<T>::NonConstType
// removes the 'const' qualifier from T, if any
// s) TypeTraits<T>::isVolatile
// returns (at compile time) true if T is a volatile-qualified type
// t) TypeTraits<T>::NonVolatileType
// removes the 'volatile' qualifier from T, if any
// u) TypeTraits<T>::UnqualifiedType
// removes both the 'const' and 'volatile' qualifiers from T, if any
////////////////////////////////////////////////////////////////////////////////
template <typename T>
class TypeTraits
{
typedef char (&yes)[1];
typedef char (&no) [2];
template<typename U>
static yes is_reference(Type2Type<U&>);
static no is_reference(...);
template<typename U>
static yes is_pointer1(Type2Type<U*>);
static no is_pointer1(...);
template<typename U>
static yes is_pointer2(Type2Type<U const *>);
static no is_pointer2(...);
template<typename U>
static yes is_pointer3(Type2Type<U volatile *>);
static no is_pointer3(...);
template<typename U>
static yes is_pointer4(Type2Type<U const volatile *>);
static no is_pointer4(...);
template<typename U, typename V>
static yes is_pointer2member(Type2Type<U V::*>);
static no is_pointer2member(...);
template<typename U>
static yes is_const(Type2Type<const U>);
static no is_const(...);
template<typename U>
static yes is_volatile(Type2Type<volatile U>);
static no is_volatile(...);
public:
//
// VC7 BUG - will not detect reference to function
//
enum {
isReference =
sizeof(is_reference(Type2Type<T>())) == sizeof(yes)
};
//
// VC7 BUG - will not detect pointer to function
//
enum {
isPointer =
sizeof(is_pointer1(Type2Type<T>())) == sizeof(yes) ||
sizeof(is_pointer2(Type2Type<T>())) == sizeof(yes) ||
sizeof(is_pointer3(Type2Type<T>())) == sizeof(yes) ||
sizeof(is_pointer4(Type2Type<T>())) == sizeof(yes)
};
enum {
isMemberPointer =
sizeof(is_pointer2member(Type2Type<T>())) == sizeof(yes)
};
enum {
isArray = Private::IsArray<T>::value
};
enum {
isVoid =
IsSameType<T, void>::value ||
IsSameType<T, const void>::value ||
IsSameType<T, volatile void>::value ||
IsSameType<T, const volatile void>::value
};
enum { isStdUnsignedInt =
TL::IndexOf<Private::StdUnsignedInts, T>::value >= 0 };
enum { isStdSignedInt =
TL::IndexOf<Private::StdSignedInts, T>::value >= 0 };
enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt ||
TL::IndexOf<Private::StdOtherInts, T>::value >= 0 };
enum { isStdFloat = TL::IndexOf<Private::StdFloats, T>::value >= 0 };
enum { isStdArith = isStdIntegral || isStdFloat };
enum { isStdFundamental = isStdArith || isStdFloat || isVoid };
enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<T>::value };
enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<T>::value };
enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt };
enum { isFloat = isStdFloat || IsCustomFloat<T>::value };
enum { isArith = isIntegral || isFloat };
enum { isFundamental = isStdFundamental || isArith || isFloat };
enum {
isConst =
sizeof(is_const(Type2Type<T>())) == sizeof(yes)
};
enum {
isVolatile =
sizeof(is_volatile(Type2Type<T>())) == sizeof(yes)
};
private:
// is_scalar include functions types
struct is_scalar
{
private:
struct BoolConvert { BoolConvert(bool); };
static yes check(BoolConvert);
static no check(...);
struct NotScalar {};
typedef typename Select
<
isVoid || isReference || isArray,
NotScalar, T
>
::Result RetType;
static RetType& get();
public:
//
// Ignore forcing value to bool 'true' or 'false' (performance warning)
//
#ifdef _MSC_VER
#pragma warning (disable: 4800)
#endif
enum { value = sizeof(check(get())) == sizeof(yes) };
#ifdef _MSC_VER
#pragma warning (default: 4800)
#endif
}; // is_scalar
private:
template<bool IsRef>
struct AdjReference
{
template<typename U>
struct In { typedef U const & Result; };
};
template<>
struct AdjReference<true>
{
template<typename U>
struct In { typedef U Result; };
};
typedef typename AdjReference<isReference || isVoid>::
template In<T>::Result AdjType;
public:
enum { isScalar = is_scalar::value };
typedef typename Select
<
isScalar || isArray, T, AdjType
>
::Result ParameterType;
//
// We get is_class for free
// BUG - fails with functions types (ICE) and unknown size array
// (but works for other incomplete types)
// (the boost one (Paul Mensonides) is better)
//
enum { isClass =
!isScalar &&
!isArray &&
!isReference &&
!isVoid
};
};
}
////////////////////////////////////////////////////////////////////////////////
// Change log:
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif // TYPETRAITS_INC_

1062
include/noncc/MSVC/1300/Typelist.h Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
// Last update: June 20, 2001
#ifdef _MSC_VER
# pragma once
#else
# error "Visual C++ specific header !"
#endif
#ifndef VC_ALIGNMENT_INC_
#define VC_ALIGNMENT_INC_
#include "Typelist.h"
#include "static_check.h"
////////////////////////////////////////////////////////////////////////////////
// class template MaxAlign
// Computes the maximum alignof for all types in a typelist
// Usage: MaxAlign<TList>::result
////////////////////////////////////////////////////////////////////////////////
template <class TList> struct VC_MaxAlign;
template <>
struct VC_MaxAlign< ::Loki::NullType >
{
enum { result = 0 };
};
template <class TList>
struct VC_MaxAlign
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
private:
enum { headResult = __alignof(Head) };
enum { tailResult = VC_MaxAlign<Tail>::result };
public:
enum { result = headResult > tailResult ?
headResult : tailResult };
};
////////////////////////////////////////////////////////////////////////////////
// class VC_AlignedPODBase
// Defines a host of protected types used by VC_AlignedPOD (defined later)
// Could be just part of VC_AlignedPOD itself, but making it separate ought to
// reduce compile times
////////////////////////////////////////////////////////////////////////////////
class VC_AlignedPODBase
{
protected:
template<unsigned AlignmentSize>
struct AlignedPod
{
STATIC_CHECK(AlignmentSize == 0, BadAlignmentSize_OnlyUpTo128);
};
//
// I used the macro because align(#)
// only works with Integer literals
//
#define ALIGNED_POD(_size_) \
template<> struct AlignedPod<_size_> { \
__declspec(align(_size_)) struct type { char X[_size_]; }; \
enum { alignment = __alignof(type) }; }; \
STATIC_CHECK((_size_ == sizeof(AlignedPod<_size_>::type)), SizeofNotEqualSize); \
STATIC_CHECK((_size_ == (AlignedPod<_size_>::alignment)), SizeofNotEqualAlignof)
ALIGNED_POD(1);
ALIGNED_POD(2);
ALIGNED_POD(4);
ALIGNED_POD(8);
ALIGNED_POD(16);
ALIGNED_POD(32);
ALIGNED_POD(64);
ALIGNED_POD(128);
// can be up to 8192 - is it realistic?
#undef ALIGNED_POD
};
////////////////////////////////////////////////////////////////////////////////
// class template VC_AlignedPOD
// Computes the alignment of all types in a typelist
////////////////////////////////////////////////////////////////////////////////
template <typename TList>
class VC_AlignedPOD : VC_AlignedPODBase
{
enum { maxAlign = VC_MaxAlign<TList>::result };
public:
typedef typename AlignedPod<maxAlign>::type Result;
};
#endif // VC_ALIGNMENT_INC_

864
include/noncc/MSVC/1300/Variant.h Executable file
View file

@ -0,0 +1,864 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, 2002 by Andrei Alexandrescu
// 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 VARIANT_INC_
#define VARIANT_INC_
#include <cstddef>
#include <memory>
#include <typeinfo>
#include "Visitor.h"
#include "Typelist.h"
#include "static_check.h"
//
// At the moment there is no namespace for Variant
//
#ifdef _MSC_VER
# include "VC_Alignment.h"
#endif
////////////////////////////////////////////////////////////////////////////////
// class template ConfigurableUnion
// Builds a union that contains each type in a typelist
// Usage: ConfigurableUnion<TList> is the very type
////////////////////////////////////////////////////////////////////////////////
template <class U> union ConfigurableUnion;
template <> union ConfigurableUnion< ::Loki::NullType >
{
};
template <class TList>
union ConfigurableUnion
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
public:
Head head_;
ConfigurableUnion<Tail> tail_;
};
////////////////////////////////////////////////////////////////////////////////
// class template MaxSize
// Computes the maximum sizeof for all types in a typelist
// Usage: MaxSize<TList>::result
////////////////////////////////////////////////////////////////////////////////
template <class TList> struct MaxSize;
template <>
struct MaxSize< ::Loki::NullType >
{
enum { result = 0 };
};
template <class TList>
struct MaxSize
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
private:
enum { headResult = sizeof(Head) };
enum { tailResult = MaxSize<Tail>::result };
public:
enum { result = headResult > tailResult ?
headResult : tailResult };
};
////////////////////////////////////////////////////////////////////////////////
// class AlignedPODBase
// Defines a host of protected types used by AlignedPOD (defined later)
// Could be just part of AlignedPOD itself, but making it separate ought to
// reduce compile times
////////////////////////////////////////////////////////////////////////////////
class AlignedPODBase
{
protected:
template <class TList, std::size_t size>
struct ComputeAlignBound
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
private:
template<class TList1>
struct In
{
private:
typedef typename TList1::Head Head1;
typedef typename TList1::Tail Tail1;
typedef typename ComputeAlignBound<Tail1, size>::Result TailResult;
public:
typedef typename ::Loki::Select
<
sizeof(Head1) <= size,
::Loki::Typelist<Head1, TailResult>,
TailResult
>
::Result Result;
};
template<>
struct In< ::Loki::NullType >
{
typedef ::Loki::NullType Result;
};
public:
typedef typename In<TList>::Result Result;
};
template <typename U> struct Structify
{ U dummy_; };
class Unknown;
// VC7: fatal error C1067: compiler limit :
// debug information module size exceeded
// Therfore I decreased the list to 26 without
// changing the rage of detectable alignment
typedef TYPELIST_26(
char,
wchar_t,
short int,
int,
long int,
float,
double,
long double,
char*,
void*,
Unknown (*)(Unknown),
Unknown* Unknown::*,
Unknown (Unknown::*)(Unknown),
Structify<char>,
Structify<wchar_t>,
Structify<short int>,
Structify<int>,
Structify<long int>,
Structify<float>,
Structify<double>,
Structify<long double>,
Structify<char*>,
Structify<void*>,
Structify<Unknown (*)(Unknown)>,
Structify<Unknown* Unknown::*>,
Structify<Unknown (Unknown::*)(Unknown)>
)
TypesOfAllAlignments;
};
////////////////////////////////////////////////////////////////////////////////
// class template AlignedPOD
// Computes the alignment of all types in a typelist
// Usage: ConfigurableUnion<TList> is the very type
////////////////////////////////////////////////////////////////////////////////
template <typename TList>
class AlignedPOD : private AlignedPODBase
{
enum { maxSize = MaxSize<TList>::result };
typedef typename ComputeAlignBound
<
TypesOfAllAlignments,
maxSize
>
::Result AlignTypes;
public:
typedef ConfigurableUnion<AlignTypes> Result;
};
////////////////////////////////////////////////////////////////////////////////
// class template MakeConst
// Given a typelist TList, returns a typelist that contains the types in TList
// adding a const qualifier to each.
// Usage: MakeConst<TList>::Result
////////////////////////////////////////////////////////////////////////////////
template <class TList> struct MakeConst;
template <> struct MakeConst< ::Loki::NullType >
{
typedef ::Loki::NullType Result; // terminator is not const
};
template <class TList>
struct MakeConst
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Head;
typedef typename TList::Tail Tail;
private:
typedef typename MakeConst<Tail>::Result NewTail;
public:
typedef ::Loki::Typelist<const Head, NewTail> Result;
};
////////////////////////////////////////////////////////////////////////////////
// class template Converter
// Supports the Variant-to-Variant conversion constructor
// Guaranteed to issue an internal compiler error on:
// 1. Metrowerks CodeWarrior 7.0 (internal compiler error: File:
// 'CTemplateTools.c' Line: 1477
// Variant.h line 244 UnitBase > VisitorBase;)
// 2. Microsoft Visual C++ 7.1 alpha release (Assertion failed:
// ( name - nameBuf ) < LIMIT_ID_LENGTH,
// file f:\vs70builds\2108\vc\Compiler\CxxFE\sl\P1\C\outdname.c,
// line 4583)
// 3. GNU gcc 2.95.3-6 (Internal compiler error 980422)
////////////////////////////////////////////////////////////////////////////////
template <class VariantFrom, class VariantTo>
struct Converter
{
//private: VC7 complains
struct UnitBase : public VariantFrom::ConstStrictVisitor
{
protected:
VariantTo* storageForDestination;
};
template <class Type, class Base>
struct Unit : public Base
{
private:
void DoVisit(const Type& obj, ::Loki::Int2Type<true>)
{
new(this->storageForDestination) VariantTo(obj);
}
void DoVisit(const Type&, ::Loki::Int2Type<false>)
{
throw std::runtime_error("Cannot convert");
}
virtual void Visit(const Type& obj)
{
using namespace Loki;
typedef typename VariantTo::Types TList;
enum { dispatch = TL::IndexOf<TList, Type>::value > -1 };
this->DoVisit(obj, Int2Type<dispatch>());
}
};
private:
typedef ::Loki::GenLinearHierarchy
<
typename VariantFrom::Types,
Unit,
UnitBase
>
VisitorBase;
public:
struct Visitor : public VisitorBase
{
explicit Visitor(VariantTo& dest)
{
// Initialize the pointer to destination
this->storageForDestination = &dest;
}
};
};
////////////////////////////////////////////////////////////////////////////////
// class template ConverterTo
// Supports Variant-to-T conversion
////////////////////////////////////////////////////////////////////////////////
#if 0
template <class VariantFrom, class T>
struct ConverterTo
{
private:
struct DestHolder
: VariantFrom::ConstStrictVisitor
{
protected:
DestHolder() {}
DestHolder(const T& dest) : destination_(dest) {}
T destination_;
};
template <class TList>
struct VisitorBase
: VisitorBase<typename TList::Tail>
{
private:
ASSERT_TYPELIST(TList);
typedef typename TList::Head Type;
typedef typename TList::Tail Tail;
protected:
VisitorBase<TList>() {}
VisitorBase<TList>(const T& dest)
: VisitorBase<Tail>(dest) {}
private:
void DoVisit(const Type& obj, ::Loki::Int2Type<true>)
{ //
// T temp(obj)
// swap(destination_, temp) or destination_ = temp
//
this->destination_ = obj;
}
void DoVisit(const Type&, ::Loki::Int2Type<false>)
{
throw std::runtime_error("Cannot convert");
}
virtual void Visit(const Type& obj)
{
using namespace Loki;
enum { dispatch = Conversion<Type, T>::exists != 0 };
this->DoVisit(obj, Int2Type<dispatch>());
}
};
template <>
struct VisitorBase< ::Loki::NullType >
: DestHolder
{
protected:
VisitorBase< ::Loki::NullType >() {}
VisitorBase< ::Loki::NullType >(const T& dest)
: DestHolder(dest) {}
};
typedef VisitorBase
<
typename VariantFrom::Types
>
VisitorBaseType;
public:
struct Visitor : public VisitorBaseType
{
Visitor() {}
explicit Visitor(const T& dest)
: VisitorBaseType(dest) {}
const T &GetDestination() const
{ return this->destination_; }
};
};
#else
template <class VariantFrom, class T>
struct ConverterTo
{
//private:
struct UnitBase : public VariantFrom::ConstStrictVisitor
{
protected:
T destination_;
};
template <class Type, class Base>
struct Unit : public Base
{
private:
void DoVisit(const Type& obj, ::Loki::Int2Type<true>)
{
this->destination_ = obj;
}
void DoVisit(const Type&, ::Loki::Int2Type<false>)
{
throw std::runtime_error("Cannot convert");
}
virtual void Visit(const Type& obj)
{
using namespace Loki;
enum { dispatch = Conversion<Type, T>::exists != 0 };
this->DoVisit(obj, Int2Type<dispatch>());
}
};
typedef ::Loki::GenLinearHierarchy<
typename VariantFrom::Types,
Unit,
UnitBase > VisitorBase;
public:
struct Visitor : public VisitorBase
{
const T &GetDestination() const
{ return this->destination_; }
};
};
#endif
namespace Private
{
template<typename T>
struct RawDataKeeper
{
private:
typedef char RawBuffer_t[sizeof(T)];
enum ObjectState_e { eNone, ePreConstruct, ePostConstruct };
T &obj_;
ObjectState_e eObjState_;
RawBuffer_t bufferOrg_;
RawBuffer_t bufferNew_;
private:
void SetObj(const RawBuffer_t &buf) throw()
{
memcpy(&reinterpret_cast<char &>(obj_), buf, sizeof(buf));
}
void GetObj(RawBuffer_t &buf) throw()
{
memcpy(buf, &reinterpret_cast<const char &>(obj_), sizeof(buf));
}
public:
explicit RawDataKeeper(T &obj)
: obj_(obj), eObjState_(eNone)
{}
// add const U & version ?
template<typename U>
void ConstructNew(U &src)
{
assert(eObjState_ == eNone);
GetObj(bufferOrg_);
eObjState_ = ePreConstruct;
new (&obj_) T(src);
eObjState_ = ePostConstruct;
GetObj(bufferNew_);
SetObj(bufferOrg_);
}
void SetNew() throw()
{
assert(eObjState_ == ePostConstruct);
obj_.~T();
SetObj(bufferNew_);
eObjState_ = eNone;
}
~RawDataKeeper()
{
switch(eObjState_)
{
case ePostConstruct:
SetObj(bufferNew_);
obj_.~T();
// fall
case ePreConstruct:
SetObj(bufferOrg_);
// fall
case eNone:
break;
}
}
private:
RawDataKeeper(const RawDataKeeper &);
RawDataKeeper& operator=(const RawDataKeeper &);
};
//
// based on Eric Fridman's safe_swap from boost Variant
//
// strong exception-safety guarantee.
//
// !WARNING!
// SafeSwap CANNOT be safely used in the general case if either
// argument's data members may be accessed concurrently.
//
template<typename T>
void SafeSwap(T &lhs, T &rhs)
{
typedef RawDataKeeper<T> RhsDataKeeper;
typedef RawDataKeeper<T> LhsDataKeeper;
RhsDataKeeper rhsKeeper(rhs);
rhsKeeper.ConstructNew(lhs);
LhsDataKeeper lhsKeeper(lhs);
lhsKeeper.ConstructNew(rhs);
rhsKeeper.SetNew();
lhsKeeper.SetNew();
}
//
// based on Eric Fridman's safe_assign from boost Variant
//
// strong exception-safety guarantee.
//
// !WARNING!
// SafeAssign CANNOT be safely used in the general case if either
// argument's data members may be accessed concurrently.
//
template<typename T, typename U>
void SafeAssign(T &lhs, const U &src)
{
typedef RawDataKeeper<T> LhsDataKeeper;
LhsDataKeeper lhsKeeper(lhs);
lhsKeeper.ConstructNew(src);
lhsKeeper.SetNew();
}
template<typename T>
inline void SwapHelper(T &lhs, T &rhs)
{
using namespace std;
swap(lhs, rhs);
}
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template Variant
// Implements a discriminated union in C++
////////////////////////////////////////////////////////////////////////////////
template <class TList, class AlignedPODType = AlignedPOD<TList> >
class Variant
{
// VC7: fatal error C1067: compiler limit :
// debug information module size exceeded
// Therfore define this type here
typedef typename AlignedPODType::Result Align;
public:
typedef TList Types;
// Default constructor
// Initializes the Variant with a default-constructed object of the
// first type in the typelist
Variant()
{
typedef typename TList::Head T;
new(&buffer_[0]) T;
vptr_ = VTableImpl<T>::GetVPTR();
}
// Copy constructor
Variant(const Variant& rhs)
{
(rhs.vptr_->clone_)(rhs, *this);
}
private:
// Converting constructor; accepts any type in the typelist
// @@@ Suggested simple improvement: accept any type convertible to one of
// the types in the typelist. Use Loki::Conversion as a building block
template <class T>
void VariantConstruct(const T& val, double)
{
STATIC_CHECK((::Loki::TL::IndexOf<TList, T>::value >= 0),
Invalid_Type_Used_As_Initializer);
new(&buffer_[0]) T(val);
vptr_ = VTableImpl<T>::GetVPTR();
}
// Inter-Variant conversion constructor
// Current policy is: conversion succeeds iff the actual type of the source
// is one of the types accepted by the target
// @@@ Possible change: accept if the actual type of the source is
// convertible to one of the types accepted by the target. Problem to
// solve: handle ambiguities in a satisfactory manner. Suggestion: when
// in doubt, do closest to what the compiler would do.
template <class TList2, typename Align2>
void VariantConstruct(const Variant<TList2, Align2>& rhs, int)
{
typename Converter<Variant<TList2, Align2>, Variant>::Visitor v(*this);
typename Variant<TList2, Align2>::ConstStrictVisitor& visitor = v;
rhs.Accept(visitor);
}
public:
// VC7 don't support partial ordering
// The constructor initialization section
// is empty which make it to use function instead
// without the int = 0 the explicit seems to confuse
// VC7 when the copy constructor should be selected
// Crazy stuff
template <class T>
explicit Variant(const T& val, int = 0)
{
VariantConstruct(val, int(0));
}
// Canonic assignment operator
Variant& operator=(const Variant& rhs)
{
Private::SafeAssign(*this, rhs);
return *this;
}
private:
// Assignment operator from one of the allowed types
// This is necessary because the constructor is explicit
template <class T>
void VariantAssign(const T& rhs, double)
{
Private::SafeAssign(*this, rhs);
}
// Assignment from another Variant instantiation
template <class TList2, typename Align2>
void VariantAssign(const Variant<TList2, Align2>& rhs, int)
{
Private::SafeAssign(*this, rhs);
}
public:
// VC7 don't support partial ordering
template <class T>
Variant& operator=(const T& rhs)
{
// Both VariantAssign are the same in this implementation
VariantAssign(rhs, int(0));
return *this;
}
// ~
~Variant()
{
(vptr_->destroy_)(*this);
}
// Visitors definitions
// @@@ Possible improvement: add defintions of visitor who return
// something else than void
typedef ::Loki::Visitor<TList, void> StrictVisitor;
typedef ::Loki::Visitor<typename MakeConst<TList>::Result, void>
ConstStrictVisitor;
typedef ::Loki::NonStrictVisitor<TList, void> NonStrictVisitor;
typedef ::Loki::NonStrictVisitor<typename MakeConst<TList>::Result, void>
ConstNonStrictVisitor;
private:
// VTable structure
// The essential component of the fake vtable idiom, VTable contains
// pointers to functions, pointers that will be filled up with addresses
// of functions in VTableImpl
struct VTable
{
const std::type_info& (*typeId_)();
void (*destroy_)(const Variant&);
void (*clone_)(const Variant&, Variant&);
void (*swap_)(void* lhs, void* rhs);
void (*accept_)(Variant&, StrictVisitor&);
void (*acceptConst_)(const Variant&, ConstStrictVisitor&);
};
// VTable concrete implementations
// VTableImpl<T> contains definitions for all of a VTable's pointer to
// functions.
// VC7 thinks that Variant inside VTableImpl is template
typedef Variant VariantType;
template <class T>
struct VTableImpl
{
private:
static const std::type_info& TypeId()
{
return typeid(T);
}
static void Destroy(const VariantType& var)
{
const T& data = *reinterpret_cast<const T*>(&var.buffer_[0]);
(void)data.~T();
}
static void Swap(void* lhs, void* rhs)
{
Private::SwapHelper(*static_cast<T*>(lhs), *static_cast<T*>(rhs));
}
static void Clone(const VariantType& src, VariantType& dest)
{
new(&dest.buffer_[0]) T(
*reinterpret_cast<const T*>(&src.buffer_[0]));
dest.vptr_ = src.vptr_;
}
static void Accept(VariantType& var, StrictVisitor& visitor)
{
typedef typename StrictVisitor::ReturnType RType;
::Loki::Visitor<T,RType> &v = visitor;
v.Visit(*reinterpret_cast<T*>(&var.buffer_[0]));
}
static void AcceptConst(const VariantType& var, ConstStrictVisitor& visitor)
{
typedef typename ConstStrictVisitor::ReturnType RType;
::Loki::Visitor<const T,RType> &v = visitor;
v.Visit(*reinterpret_cast<const T*>(&var.buffer_[0]));
}
public:
static const VTable *GetVPTR()
{
static const VTable vTbl_ =
{
&TypeId,
&Destroy,
&Clone,
&Swap,
&Accept,
&AcceptConst,
};
return &vTbl_;
}
};
template <class T> friend struct VTableImpl;
private: // should be private; some compilers prefer 'public' :o}
enum { neededSize = MaxSize<TList>::result };
VTable const * vptr_;
union
{
Align dummy_;
char buffer_[neededSize];
};
public:
void swap(Variant& rhs)
{
if (this->TypeId() == rhs.TypeId())
{
(vptr_->swap_)(this->buffer_, rhs.buffer_);
}
else
{
Private::SafeSwap(*this, rhs);
}
}
const std::type_info& TypeId() const
{
return (vptr_->typeId_)();
}
template <typename T> T* GetPtr()
{
return TypeId() == typeid(T)
? reinterpret_cast<T*>(&buffer_[0])
: 0;
}
template <typename T> const T* GetPtr() const
{
return TypeId() == typeid(T)
? reinterpret_cast<const T*>(&buffer_[0])
: 0;
}
template <typename T> T& Get()
{
T* p = GetPtr<T>();
if (!p) throw std::runtime_error("Variant::Get() Invalid variant type");
return *p;
}
template <typename T> const T& Get() const
{
const T* p = GetPtr<T>();
if (!p) throw std::runtime_error("Variant::Get() const Invalid variant type");
return *p;
}
// Visitation primitives
// Although there are four visitor types, only two Accept functions are
// necessary, because the non-strict visitors inherit the strict visitors
void Accept(StrictVisitor& visitor)
{
(vptr_->accept_)(*this, visitor);
}
void Accept(ConstStrictVisitor& visitor) const
{
(vptr_->acceptConst_)(*this, visitor);
}
// Extracts the value of a Variant converted to a specific type
template <class To> To ConvertTo() const
{
typename ConverterTo<Variant, To>::Visitor v;
ConstStrictVisitor& visitor = v;
this->Accept(visitor);
return v.GetDestination();
}
// Changes the type of a Variant in-place
template <class To> void ChangeType()
{
Variant(this->ConvertTo<To>()).swap(*this);
}
};
////////////////////////////////////////////////////////////////////////////////
// Change log:
// July 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif

328
include/noncc/MSVC/1300/Visitor.h Executable file
View file

@ -0,0 +1,328 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: May 19, 2002
#ifndef VISITOR_INC_
#define VISITOR_INC_
#include "Typelist.h"
#include "HierarchyGenerators.h"
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitor
// The base class of any Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
class BaseVisitor
{
public:
virtual ~BaseVisitor() {}
};
////////////////////////////////////////////////////////////////////////////////
// class template Visitor
// Forward decleration
////////////////////////////////////////////////////////////////////////////////
template <class T, typename R = void>
class Visitor;
namespace Private
{
// for some reason VC7 needs the base definition altough not in use
template <typename TListTag>
struct VisitorHelper1
{
template <typename T, typename R>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <typename TListTag>
struct VisitorHelper2
{
template <typename T, typename R>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template <>
struct VisitorHelper1<TL::Typelist_tag>
{
template <class TList, typename R>
struct In
{
typedef Visitor<typename TList::Head, R> Result;
};
};
template <>
struct VisitorHelper2<TL::Typelist_tag>
{
template <class TList, typename R>
struct In
{
private:
template<typename Tail>
struct In1
{
typedef Visitor<typename TList::Tail, R> Result;
};
template<>
struct In1<NullType>
{
struct Result {};
};
public:
typedef typename In1<typename TList::Tail>::Result Result;
};
};
template <>
struct VisitorHelper1<TL::NoneList_tag>
{
template <class T, typename R>
struct In
{
struct Result
{
typedef R ReturnType;
virtual ReturnType Visit(T&) = 0;
};
};
};
template <>
struct VisitorHelper2<TL::NoneList_tag>
{
template <class T, typename R>
struct In { struct Result {}; };
};
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template Visitor
// The building block of Acyclic Visitor
////////////////////////////////////////////////////////////////////////////////
template <class T, typename R>
class Visitor
: public Private::VisitorHelper1
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, R>::Result
, public Private::VisitorHelper2
<
typename TL::is_Typelist<T>::type_tag
>
::template In<T, R>::Result
{
public:
typedef R ReturnType;
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitorImpl
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class TList, typename R = void>
class BaseVisitorImpl;
namespace Private
{
// for some reason VC7 needs the base definition altough not in use
template<typename TListTag>
struct BaseVisitorImplHelper
{
template <typename T, typename R>
struct In
{
typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::Typelist_tag>
{
template <typename TList, typename R>
struct In
{
typedef BaseVisitorImpl<TList, R> Result;
};
};
template<>
struct BaseVisitorImplHelper<TL::NullType_tag>
{
template <typename TList, typename R>
struct In
{
struct Result {};
};
};
} // namespace Private
template <class TList, typename R>
class BaseVisitorImpl
: public Visitor<typename TList::Head, R>
, public Private::BaseVisitorImplHelper
<
typename TL::is_Typelist<typename TList::Tail>::type_tag
>
::template In<typename TList::Tail, R>::Result
{
ASSERT_TYPELIST(TList);
public:
// using BaseVisitorImpl<Tail, R>::Visit;
virtual R Visit(typename TList::Head&)
{ return R(); }
};
////////////////////////////////////////////////////////////////////////////////
// class template NonStrictVisitor
// Implements non-strict visitation (you can implement only part of the Visit
// functions)
////////////////////////////////////////////////////////////////////////////////
template <class T, class Base>
struct NonStrictVisitorUnit : public Base
{
typedef typename Base::ReturnType ReturnType;
ReturnType Visit(T&)
{
return ReturnType();
}
};
template <class TList, typename R = void>
class NonStrictVisitor
: public GenLinearHierarchy<
TList,
NonStrictVisitorUnit,
Visitor<TList, R> >
{
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitable
////////////////////////////////////////////////////////////////////////////////
template <typename R, typename Visited>
struct DefaultCatchAll
{
static R OnUnknownVisitor(Visited&, BaseVisitor&)
{ return R(); }
};
////////////////////////////////////////////////////////////////////////////////
// class template BaseVisitable
////////////////////////////////////////////////////////////////////////////////
template
<
typename R = void,
template <typename, class> class CatchAll = DefaultCatchAll
>
class BaseVisitable
{
public:
typedef R ReturnType;
virtual ~BaseVisitable() {}
virtual ReturnType Accept(BaseVisitor&) = 0;
protected: // give access only to the hierarchy
template <class T>
static ReturnType AcceptImpl(T& visited, BaseVisitor& guest)
{
// Apply the Acyclic Visitor
if (Visitor<T,R>* p = dynamic_cast<Visitor<T,R>*>(&guest))
{
return p->Visit(visited);
}
return CatchAll<R, T>::OnUnknownVisitor(visited, guest);
}
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_VISITABLE
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_VISITABLE() \
virtual ReturnType Accept(BaseVisitor& guest) \
{ return AcceptImpl(*this, guest); }
////////////////////////////////////////////////////////////////////////////////
// class template CyclicVisitor
// Put it in every class that you want to make visitable (in addition to
// deriving it from BaseVisitable<R>
////////////////////////////////////////////////////////////////////////////////
template <typename R, class TList>
class CyclicVisitor : public Visitor<TList, R>
{
public:
typedef R ReturnType;
// using Visitor<TList, R>::Visit;
virtual ~CyclicVisitor() {}
template <class Visited>
ReturnType GenericVisit(Visited& host)
{
Visitor<Visited, ReturnType>& subObj = *this;
return subObj.Visit(host);
}
};
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_CYCLIC_VISITABLE
// Put it in every class that you want to make visitable by a cyclic visitor
////////////////////////////////////////////////////////////////////////////////
#define DEFINE_CYCLIC_VISITABLE(SomeVisitor) \
virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \
{ return guest.GenericVisit(*this); }
} // namespace Loki
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20: add default argument DefaultCatchAll to BaseVisitable
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
////////////////////////////////////////////////////////////////////////////////
#endif // VISITOR_INC_

View file

@ -0,0 +1,2 @@
MSVC7
Rani Sharoni

View file

@ -0,0 +1,18 @@
Last update: May 19, 2002
Directions:
To use Loki, simply extract the files from the archive, give your compiler access to their path, and include them appropriately in your code via #include.
If you use the small object allocator directly or indirectly (through the Functor class) you must add SmallObj.cpp to your project/makefile.
If you use Singletons with longevity you must add Singleton.cpp to your project/makefile.
Compatibility:
This is ported version of Loki to VC.NET (VC7 - 9466) it is only targeted for this compiler.
To compile your sources with the original Loki you'll have to place it in a separate directory.
More info:
http://moderncppdesign.com
http://www.geocities.com/rani_sharoni/LokiPort.html

View file

@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////////////////////////
// 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-Welsey Longman make no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
////////////////////////////////////////////////////////////////////////////////
// Last update: June 20, 2001
#ifndef STATIC_CHECK_INC_
#define STATIC_CHECK_INC_
namespace Loki
{
////////////////////////////////////////////////////////////////////////////////
// Helper structure for the STATIC_CHECK macro
////////////////////////////////////////////////////////////////////////////////
template<bool CompileTimeAssertion>
struct CompileTimeError;
template<>
struct CompileTimeError<true>
{
typedef void type;
};
}
////////////////////////////////////////////////////////////////////////////////
// macro STATIC_CHECK
// Invocation: STATIC_CHECK(expr, id)
// where:
// expr is a compile-time integral or pointer expression
// id is a C++ identifier that does not need to be defined
// If expr is zero, id will appear in a compile-time error message.
////////////////////////////////////////////////////////////////////////////////
#define STATIC_CHECK(expr, msg) \
typedef char ERROR_##msg[1][(expr)]
////////////////////////////////////////////////////////////////////////////////
// Change log:
// March 20, 2001: add extra parens to STATIC_CHECK - it looked like a fun
// definition
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
// July 09, 2002: improved for favor of VC diagnostic and usage
////////////////////////////////////////////////////////////////////////////////
#endif // STATIC_CHECK_INC_