From 6505b5c1c3966292a1685f1bb56b0339df4a5383 Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Wed, 2 Aug 2000 18:28:51 +0000 Subject: Initial checkin. --- doc/.cvsignore | 2 + doc/api/.cvsignore | 3 + lib/Enum.cc | 57 +++++++++++ lib/Enum.h | 289 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 351 insertions(+) create mode 100644 doc/.cvsignore create mode 100644 doc/api/.cvsignore create mode 100644 lib/Enum.cc create mode 100644 lib/Enum.h diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..3dda729 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,2 @@ +Makefile.in +Makefile diff --git a/doc/api/.cvsignore b/doc/api/.cvsignore new file mode 100644 index 0000000..3eed221 --- /dev/null +++ b/doc/api/.cvsignore @@ -0,0 +1,3 @@ +Makefile.in +Makefile +*.html diff --git a/lib/Enum.cc b/lib/Enum.cc new file mode 100644 index 0000000..8abce8b --- /dev/null +++ b/lib/Enum.cc @@ -0,0 +1,57 @@ +/*--*-c++-*------------------------------------------------------------- + * $Id$ + *---------------------------------------------------------------------*/ + +#include "Enum.h" + +void EnumBase::i2sMapper::add(long i, const char* s) { + stringMap.insert(pair(i, s)); +} + +string EnumBase::i2sMapper::lookup (long i) const { + i2s_map_t::const_iterator searchPtr = stringMap.find(i); + + if (searchPtr == stringMap.end()) + return "[OUT-OF-RANGE]"; + /* + * now combine the probably the multiple strings belonging to this + * integer + */ + string result; + for (i = stringMap.count(i); i > 0 ; --i, ++searchPtr) { + // this should be the case: + assert(searchPtr != stringMap.end()); + if (result.length() != 0) + result += string(","); + result += string(searchPtr->second); + } + return result; +} + + +long EnumBase::i2sMapper::lookup (const char *s) const { + /* + * lookup a specific string. + * Since speed does not matter, we just do an exhaustive + * search. + * Otherwise we would have to maintain another map + * mapping strings to ints .. but its not worth the memory + */ + i2s_map_t::const_iterator run = stringMap.begin(); + while (run != stringMap.end() && strcmp(s, run->second)) { + ++run; + } + if (run == stringMap.end()) + return -1; // FIXME .. maybe throw an exception ? + return run->first; +} + +bool EnumBase::i2sMapper::inRange (long i) const { + return (stringMap.find(i) != stringMap.end()); +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/lib/Enum.h b/lib/Enum.h new file mode 100644 index 0000000..9cb41ff --- /dev/null +++ b/lib/Enum.h @@ -0,0 +1,289 @@ +/*--*-c++-*------------------------------------------------------------- + * $Id$ + *---------------------------------------------------------------------*/ + +#ifndef _ENUM_H_ +#define _ENUM_H_ + +#include +#include + +/** + * 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 multimap 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 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. + */ + 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)). + * + * 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, not 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. + * + * @see #ENUM_DEFINITION + * @author Henner Zeller + */ +template +class Enum : private EnumBase { +private: + 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; + 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::sdata::sdata() ? + assert(inRange(init)); + } + + /** + * initialize with the string representation + * XXX: throw Exception if not found ? + */ + Enum(const 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 init) { + value = init; + assert(inRange(init)); + 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. + */ + string toString() const { return getStringFor(value); } + + /** + * 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::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 string getEnumName() { return staticData.name; } + + /** + * gives the String represenatation of a specific + * value of this Enumeration. + */ + static string getStringFor(E e) { + return staticData.stringRep.lookup((long) e); + } + + /** + * returns the Value for a specific String. + * XXX: throw OutOfRangeException ? + */ + static E getValueFor(const string &s) { + return (E) staticData.stringRep.lookup(s.getCStr()); + } +}; + +/** + * Helper macro to construct an enumeration wrapper Enum 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: + *
+ * // 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 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");
+ * }
+ * 
+ * + * @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 + */ +#define ENUM_DEFINITION(EnumName, initWith) \ + /** \ + * The definition of the static variable holding the static \ + * data for this Enumeration wrapper. \ + */ \ + Enum::sdata Enum::staticData; \ + /** \ + * actual definition of the constructor for the static data. \ + * This is called implicitly by the definition above. \ + */ \ + Enum::sdata::sdata() : \ + name(#EnumName),defaultValue(initWith) + +/** + * Writes enumeration's string representation. + */ +template +inline ostream& operator << (ostream& out, const Enum &e) { + return out << e.toString(); +} + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + +#endif /* _ENUM_H_ */ -- cgit v1.2.3