//////////////////////////////////////////////////////////////////
//
// Object factory for GNU Gatekeeper
//
// Copyright (c) Citron Network Inc. 2003
//
// This work is published under the GNU Public License (GPL)
// see file COPYING for details.
// We also explicitely grant the right to link this code
// with the OpenH323 library.
//
// initial author: Chih-Wei Huang <cwhuang@linux.org.tw>
// initial version: 06/05/2003
//
//////////////////////////////////////////////////////////////////
#ifndef FACTORY_H
#define FACTORY_H "@(#) $Id: factory.h,v 1.7 2006/04/14 13:56:19 willamowius Exp $"
/*****************************************************************
//
// An example how to use the factory template
//
// a base class for polymorphic objects
class SampleBase {
public:
SampleBase() {}
SampleBase(const char *n) { cerr << "This is a " << n << "\n"; }
virtual ~SampleBase() {}
template<class Derived>
struct Init : public Factory<SampleBase>::Creator0 {
Init(const char *n) : Factory<SampleBase>::Creator0(n), n_(n) {}
virtual SampleBase *operator()() const { return new Derived(n_); }
const char *n_;
};
};
class SampleA : public SampleBase {
public:
SampleA(const char *n) : SampleBase(n) {}
};
class SampleB : public SampleBase {
public:
SampleB(const char *n) : SampleBase(n) {}
};
class SampleC : public SampleBase {
public:
SampleC(const char *n) : SampleBase(n) {}
SampleC(int i) { cerr << "This is a SampleC " << i << "\n"; }
// how to create object for a class with different constructors
struct InitC : public SampleBase::Init<SampleC>, public Factory<SampleBase>::Creator1<int> {
InitC(const char *n) : SampleBase::Init<SampleC>(n), Factory<SampleBase>::Creator1<int>(n) {}
virtual SampleBase *operator()(int i) const { return new SampleC(i); }
};
};
// register the derived classes with the factory
SampleA::Init<SampleA> SampleAInit("SampleA");
SampleB::Init<SampleB> SampleBInit("SampleB");
SampleC::InitC SampleCInit("SampleC");
void CreateSamples()
{
SampleBase *pa, *pb, *pc1, *pc2, *pc3;
pa = Factory<SampleBase>::Create("SampleA");
pb = Factory<SampleBase>::Create("SampleB");
pc1 = Factory<SampleBase>::Create("SampleC");
pc2 = Factory<SampleBase>::Create("SampleC", 2);
pc3 = Factory<SampleBase>::Create("SampleC", 1, 2, 3); // runtime error
}
The output
This is a SampleA
This is a SampleB
This is a SampleC
This is a SampleC 2
and an error message in trace
factory.h(135) Init Can't create SampleC with 3 parameter(s)
*****************************************************************/
#if defined(_WIN32) && (_MSC_VER >= 1200)
#pragma warning( disable : 4355 ) // warning about using 'this' in initializer
#endif
#include <map>
#include <cstring>
namespace std {
// gcc 3.x said specialization can't be put in different namespace
template<> struct less<const char *> : public binary_function<const char *, const char *, bool> {
bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; }
};
}
// a function object template with returned value R
template<typename R>
struct Functor {
typedef R result_type;
virtual ~Functor() {}
};
// function objects with different parameters
// currently at most 3 parameters are supported
// since VC6 didn't support partial specialization,
// we have to define Functor with different parameters to
// different names
template<typename R>
struct Functor0 : public Functor<R> {
virtual R operator()() const = 0;
};
template<typename R, typename T1>
struct Functor1 : public Functor<R> {
typedef T1 argument_type;
virtual R operator()(T1) const = 0;
};
template<typename R, typename T1, typename T2>
struct Functor2 : public Functor<R> {
typedef T1 first_argument_type;
typedef T2 second_argument_type;
virtual R operator()(T1, T2) const = 0;
};
template<typename R, typename T1, typename T2, typename T3>
struct Functor3 : public Functor<R> {
typedef T1 first_argument_type;
typedef T2 second_argument_type;
typedef T3 third_argument_type;
virtual R operator()(T1, T2, T3) const = 0;
};
// object factory template
template<class Product, typename Identifier = const char *>
class Factory {
public:
typedef Factory<Product, Identifier> Self;
typedef Functor<Product *> *Creator;
typedef std::map<Identifier, Creator> Associations;
static Creator Register(Identifier n, Creator c);
static void SetDefaultCreator(Creator c) { m_default = c; }
// registrars
class Registrar {
protected:
Identifier m_id;
Creator m_old;
#if defined(_WIN32) && (_MSC_VER <= 1300)
Registrar(Identifier n, Creator c) : m_id(n) { m_old = Self::Register(n, c); }
~Registrar() { if (m_old) Self::Register(m_id, m_old); }
#else
Registrar(Identifier n, Creator c);
~Registrar();
#endif
};
struct Creator0 : public Functor0<Product *>, Registrar {
Creator0(Identifier n) : Registrar(n, this) {}
};
template<typename P1>
struct Creator1 : public Functor1<Product *, P1>, Registrar {
Creator1(Identifier n) : Registrar(n, this) {}
};
template<typename P1, typename P2>
struct Creator2 : public Functor2<Product *, P1, P2>, Registrar {
Creator2(Identifier n) : Registrar(n, this) {}
};
template<typename P1, typename P2, typename P3>
struct Creator3 : public Functor3<Product *, P1, P2, P3>, Registrar {
Creator3(Identifier n) : Registrar(n, this) {}
};
static Product *Create(Identifier n)
{
Functor0<Product *> *f0;
return FindCreator(n, 0, f0) ? (*f0)() : 0;
}
template<typename P1>
static Product *Create(Identifier n, P1 p1)
{
Functor1<Product *, P1> *f1;
return FindCreator(n, 1, f1) ? (*f1)(p1) : 0;
}
template<typename P1, typename P2>
static Product *Create(Identifier n, P1 p1, P2 p2)
{
Functor2<Product *, P1, P2> *f2;
return FindCreator(n, 2, f2) ? (*f2)(p1, p2) : 0;
}
template<typename P1, typename P2, typename P3>
static Product *Create(Identifier n, P1 p1, P2 p2, P3 p3)
{
Functor3<Product *, P1, P2, P3> *f3;
return FindCreator(n, 3, f3) ? (*f3)(p1, p2, p3) : 0;
}
private:
static Creator FindCreator(Identifier);
static bool ParmMismatch(Identifier, int);
template<typename P>
static bool FindCreator(Identifier n, int i, P & p)
{
Creator creator = FindCreator(n);
p = dynamic_cast<P>(creator);
return creator && (p || ParmMismatch(n, i));
}
static Associations *m_associations;
static Creator m_default;
};
#if !defined(_WIN32) || (_MSC_VER > 1300)
// stupid VC can't instantiate these
template<class Product, typename Identifier>
Factory<Product, Identifier>::Registrar::Registrar(Identifier n, Creator c) : m_id(n)
{
// VS.NET fix
#if defined(_WIN32) && (_MSC_VER > 1300)
m_old = Register(n, c);
#else
m_old = Self::Register(n, c);
#endif
}
template<class Product, typename Identifier>
Factory<Product, Identifier>::Registrar::~Registrar()
{
if (m_old)
// VS.NET fix
#if defined(_WIN32) && (_MSC_VER > 1300)
Register(m_id, m_old);
#else
Self::Register(m_id, m_old);
#endif
}
#endif
template<class Product, typename Identifier>
Functor<Product *> *Factory<Product, Identifier>::Register(Identifier n, Creator c)
{
static Associations associations;
m_associations = &associations;
Creator & d = associations[n];
Creator old = d;
d = c;
return old;
}
template<class Product, typename Identifier>
Functor<Product *> *Factory<Product, Identifier>::FindCreator(Identifier n)
{
typename Associations::iterator i = m_associations->find(n);
if (i != m_associations->end())
return i->second;
else if (m_default)
return m_default;
PTRACE(1, "Init\tCan't create unknown class " << n);
return 0;
}
template<class Product, typename Identifier>
bool Factory<Product, Identifier>::ParmMismatch(Identifier n, int i)
{
PTRACE(1, "Init\tCan't create " << n << " with " << i << " parameter(s)");
return false;
}
template<class Product, typename Identifier>
std::map<Identifier, Functor<Product *> *> *Factory<Product, Identifier>::m_associations;
template<class Product, typename Identifier>
Functor<Product *> *Factory<Product, Identifier>::m_default = 0;
// a simple creator for classes having default constructor
// the ConcreteProduct must define its base class as a subtype Base
template<class ConcreteProduct, typename Identifier = const char *>
struct SimpleCreator : public Factory<typename ConcreteProduct::Base, Identifier>::Creator0 {
typedef typename ConcreteProduct::Base AbstractProduct;
SimpleCreator(Identifier n) : Factory<AbstractProduct, Identifier>::Creator0(n) {}
virtual AbstractProduct *operator()() const { return new ConcreteProduct; }
};
#endif // FACTORY_H
syntax highlighted by Code2HTML, v. 0.9.1