forked from willamowius/gnugk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
factory.h
303 lines (247 loc) · 8.15 KB
/
factory.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
//////////////////////////////////////////////////////////////////
//
// Object factory for GNU Gatekeeper
//
// Copyright (c) Citron Network Inc. 2003
// Copyright (c) 2006-2018, Jan Willamowius
//
// This work is published under the GNU Public License version 2 (GPLv2)
// see file COPYING for details.
// We also explicitly grant the right to link this code
// with the OpenH323/H323Plus and OpenSSL library.
//
//////////////////////////////////////////////////////////////////
#ifndef FACTORY_H
#define FACTORY_H "@(#) $Id$"
/*****************************************************************
//
// 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;
Registrar(Identifier n, Creator c);
~Registrar();
};
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)() : NULL;
}
template<typename P1>
static Product *Create(Identifier n, P1 p1)
{
Functor1<Product *, P1> *f1;
return FindCreator(n, 1, f1) ? (*f1)(p1) : NULL;
}
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) : NULL;
}
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) : NULL;
}
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\tError: Can't create unknown class " << n);
return NULL;
}
template<class Product, typename Identifier>
bool Factory<Product, Identifier>::ParmMismatch(Identifier n, int i)
{
PTRACE(1, "Init\tError: Can'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 = NULL;
// 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