aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Enum.h
blob: a175328cf41c9f2383bdd1a663c04c53128519a1 (plain)
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/*-*-c++-*-
 * $Id$
 *
 * This file is part of plptools.
 *
 *  Copyright (C) 2000 Henner Zeller <hzeller@to.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
#ifndef _ENUM_H_
#define _ENUM_H_

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <assert.h>
#include <map>
#include <string>

#include <plpintl.h>
#include <assert.h>

/**
 * the Base for the Enum template.
 * currently, only purpose is to provide a class type for mapping
 * integer enum values to strings in the Enumeration class.
 * The mapping is done basically with a STL-multimap.
 *
 * @author Henner Zeller
 */
class EnumBase {
protected:
    /**
    * maps integers (typically: enumeration values) to
    * Strings. Takes care of the fact, that an Integer may map
    * to multiple strings (sometimes multiple enumeration values
    * represent the same integer).
    *
    * Provides a means to get the string representation of an
    * integer and vice versa.
    *
    * @author Henner Zeller
    */
    class i2sMapper {
    private:
	/**
	* there can be one value, mapping to multiple
	* strings. Therefore, we need a multimap.
	*/
	typedef std::multimap<long, const char*> i2s_map_t;

	/**
	* just for the record. Mapping back a string to the
	* Integer value in question. Since Symbols must be unique,
	* there is only a 1:1 relation as opposed to i2s_map_t. So
	* we can use a normal map here.
	*
	* Since in the usual application, mapping a string back
	* to its value is not important performance wise (typically
	* in a frontend), so it is implemented as exhaustive search,
	* not as extra map. Saves some bits of memrory ..
	*/
	//typedef map<const char*, long> s2i_map_t;

	i2s_map_t stringMap;
    public:
	/**
	* adds a new int -> string mapping
	* Does NOT take over responsibility for the
	* pointer (i.e. it is not freed), so it is save
	* to add constant strings provided in the program code.
	*/
	void add(long, const char*);

	/**
	* returns the string representation for this integer.
	* If there are multiple strings for this integer,
	* return a comma delimited list.
	*/
	std::string lookup(long) const;

	/**
	* returns the integer associated with the
	* given string or -1 if the value
	* is not found (XXX: this should throw
	* an exception).
	*/
	long lookup (const char *) const;

	/**
	* returns true, if we have an representation for
	* the given integer.
	*/
	bool inRange(long) const;
    };
};

/**
 * Wrapper class featuring range-checking and string
 * representation of enumerated values.
 *
 * The string representation capability is needed to provide a
 * generic input frontend for any Enumeration because text labels
 * are needed in GUIs, and, of course, aids debugging, because you
 * can provide a readable presentation of an entry if something
 * goes wrong.
 *
 * NOTE, that wrapping an enumeration with this class
 * does not mean any performance overhead at all since the
 * compiler optimizes the member calls away. Nor does an instance of
 * this class use more memory than the use of an usual Enumeration.
 * (i.e. sizeof(E) == sizeof(Enum<E>)).
 *
 * Besides that, it provides a great opportunity to check the
 * code and make it bug free, esp. if you've to read the
 * Enumeration from some dubious integer source
 * (.. to make the dubious integer source bug free ;-)
 *
 * So there is no reason, <b>not</b> to use this class.
 * Alas, you've to provide a StringRepresentation for it, which may
 * be tedious for large enumerations. To make the Definition easier
 * and more readable, an ENUM_DEFINITION() macro is provided.
 *
 * FIXME: At the moment enumeration strings don't get translated by gettext
 * 
 * @see #ENUM_DEFINITION
 * @author Henner Zeller
 */
template<typename E>
class Enum : private EnumBase {
public:
    struct sdata {
	/**
	 * The constructor of the static data part.
	 * You've to provide a constructor for each Enumeration
	 * you want to wrap with this class. Initializes
	 * the string Representation map, the readable name
	 * of this Enumeration and a default value.
	 *
	 * The constructor is called automatically on definition,
	 * so this makes sure, that the static part is initialized
	 * properly before the program starts.
	 */
	sdata();
	i2sMapper    stringRep;
	std::string name;
	E           defaultValue;
    };
    static sdata staticData;

    /**
    * The actual value hold by this instance
    */
    E value;

public:
    /**
    * default constructor.
    * Initialize with default value.
    */
    Enum() : value(staticData.defaultValue) {}

    /**
    * initialize with Enumeration given.
    */
    Enum(E init) : value(init){
	// if this hits you and you're sure, that the
	// value is right .. is this Enum proper
	// initialized in the Enum<E>::sdata::sdata() ?
	assert(inRange(init));
    }

    /**
    * initialize with the string representation
    * XXX: throw Exception if not found ?
    */
    Enum(const std::string& s) : value(getValueFor(s)) {
	assert(inRange(value));
    }

    /**
    * assign an Enumeration of this type. In debug
    * version, assert, that it is really in the Range of
    * this Enumeration.
    */
    inline Enum& operator = (E setval) {
	value = setval;
	assert(inRange(setval));
	return *this;
    }

    inline Enum& operator = (const Enum& rhs) {
        if (&rhs != this)
            value = rhs.value;
	return *this;
    }

    /**
    * returns the enumeration value hold with this
    * enum.
    */
    inline operator E () const { return value; }

    /**
    * returns the String representation for the value
    * represented by this instance.
    */
    std::string toString() const { return getStringFor(value); }

    /**
    * returns the C string representation for the value
    * represented by this instance.
    */
    operator const char *() const { return toString().c_str(); }

    /**
    * This static member returns true, if the integer value
    * given fits int the range of this Enumeration. Use this
    * to verify input/output.
    * Fitting in the range of Enumeration here means, that
    * there actually exists a String representation for it,
    * so this Enumeration is needed to be initialized properly
    * in its Enum<E>::sdata::sdata() constructor, you've to
    * provide. For convenience, use the ENUM_DEFINITION() macro
    * for this.
    */
    static bool inRange(long i) {
	return (staticData.stringRep.inRange(i));
    }

    /**
    * returns the Name for this enumeration. Useful for
    * error reporting.
    */
    static std::string getEnumName() { return staticData.name; }

    /**
    * gives the String represenatation of a specific
    * value of this Enumeration.
    */
    static std::string getStringFor(E e) {
	return staticData.stringRep.lookup((long) e);
    }

    /**
    * returns the Value for a specific String.
    * XXX: throw OutOfRangeException ?
    */
    static E getValueFor(const std::string &s) {
	return (E) staticData.stringRep.lookup(s.c_str());
    }
};

template<typename E> typename Enum<E>::sdata Enum<E>::staticData;

/**
 * Helper macro to construct an enumeration wrapper Enum<E> for
 * a specific enum type.
 *
 * It defines the static variable holding the static
 * information and provides the head of its Constructor.
 * You only have to provide the string-mapping additions in the
 * constructor body. This macro behaves much like a function declaration,
 * i.e. you have to start the constructor with { ..
 *
 * usage example:
 * <pre>
 * // declaration of enumeration; somewhere
 * class rfsv {
 * [...]
 *	enum PSI_ERROR_CODES { E_PSI_GEN_NONE, E_PSI_GEN_FAIL, E_PSI_GEN_ARG };
 * [...]
 * };
 *
 * // definition of the Enum<E> with the appropriate string representations
 * ENUM_DEFINITION(rfsv::PSI_ERROR_CODES,
 *		   rfsv::E_PSI_GEN_NONE) {
 *	stringRep.add(rfsv::E_PSI_GEN_NONE,	"no error");
 *	stringRep.add(rfsv::E_PSI_GEN_FAIL,	"general");
 *	stringRep.add(rfsv::E_PSI_GEN_ARG,	"bad argument");
 * }
 * </pre>
 *
 * @param EnumName  The fully qualified Name of the enum type to be wrapped
 * @param init      The fully qualified Name of the initialization
 *                  value.
 *
 * @author Henner Zeller
 */
/**								
  * The definition of the static variable holding the static	
  * data for this Enumeration wrapper.				
  */								
#define ENUM_DEFINITION_BEGIN(EnumName, initWith)			\
/**								\
  * actual definition of the constructor for the static data.	\
  * This is called implicitly by the definition above.		\
  */								\
template <> Enum<EnumName>::sdata::sdata() :				\
    name(#EnumName),defaultValue(initWith) {

#define ENUM_DEFINITION_END(EnumName) \
} template Enum< EnumName >::sdata Enum< EnumName >::staticData;

/**
 * Writes enumeration's string representation.
 */
template <typename E>
inline std::ostream& operator << (std::ostream& out, const Enum<E> &e) {
    return out << e.toString().c_str();
}

#endif /* _ENUM_H_ */

/*
 * Local variables:
 * c-basic-offset: 4
 * End:
 */