// macros.h see license.txt for copyright and terms of use // grab-bag of useful macros, stashed here to avoid mucking up // other modules with more focus; there's no clear rhyme or // reason for why some stuff is here and some in typ.h // (no configuration stuff here!) #ifndef __MACROS_H #define __MACROS_H #include "typ.h" // bool // complement of == #define NOTEQUAL_OPERATOR(T) \ bool operator != (T const &obj) const \ { return !operator==(obj); } // toss this into a class that already has == and < defined, to // round out the set of relational operators (assumes a total // order, i.e. a < b <=> b < a) #define RELATIONAL_OPERATORS(T) \ NOTEQUAL_OPERATOR(T) \ bool operator <= (T const &obj) const \ { return !obj.operator<(*this); } \ bool operator > (T const &obj) const \ { return obj.operator<(*this); } \ bool operator >= (T const &obj) const \ { return !operator<(obj); } // member copy in constructor initializer list #define DMEMB(var) var(obj.var) // member copy in operator = #define CMEMB(var) var = obj.var // member comparison in operator == #define EMEMB(var) var == obj.var // standard insert operator // (note that you can put 'virtual' in front of the macro call if desired) #define INSERT_OSTREAM(T) \ void insertOstream(ostream &os) const; \ friend ostream& operator<< (ostream &os, T const &obj) \ { obj.insertOstream(os); return os; } // usual declarations for a data object (as opposed to control object) #define DATA_OBJ_DECL(T) \ T(); \ T(T const &obj); \ ~T(); \ T& operator= (T const &obj); \ bool operator== (T const &obj) const; \ NOTEQUAL_OPERATOR(T) \ INSERTOSTREAM(T) // copy this to the .cc file for implementation of DATA_OBJ_DECL #if 0 T::T() {} T::T(T const &obj) : DMEMB(), DMEMB(), DMEMB() {} T::~T() {} T& T::operator= (T const &obj) { if (this != &obj) { CMEMB(); } return *this; } bool T::operator== (T const &obj) const { return EMEMB() && EMEMB(); } void T::insertOstream(ostream &os) const {} #endif // 0 // assert something at compile time (must use this inside a function); // works because compilers won't let us declare negative-length arrays // (the expression below works with egcs-1.1.2, gcc-2.x, gcc-3.x) #define STATIC_ASSERT(cond) \ { (void)((int (*)(char failed_static_assertion[(cond)?1:-1]))0); } // assert that a table is an expected size; the idea is to make sure // that static data in some table gets updated when a corresponding // symbolic constant is changed #define ASSERT_TABLESIZE(table, size) \ STATIC_ASSERT(TABLESIZE(table) == (size)) // for silencing variable-not-used warnings template inline void pretendUsedFn(T const &) {} #define PRETEND_USED(arg) pretendUsedFn(arg) /* user ; */ // appended to function declarations to indicate they do not // return control to their caller; e.g.: // void exit(int code) NORETURN; #ifdef __GNUC__ #define NORETURN __attribute__((noreturn)) #else // just let the warnings roll if we can't suppress them #define NORETURN #endif // these two are a common idiom in my code for typesafe casts; // they are essentially a roll-your-own RTTI #define CAST_MEMBER_FN(destType) \ destType const &as##destType##C() const; \ destType &as##destType() { return const_cast(as##destType##C()); } #define CAST_MEMBER_IMPL(inClass, destType) \ destType const &inClass::as##destType##C() const \ { \ xassert(is##destType()); \ return (destType const&)(*this); \ } // same as the above, but returning pointers; I think returning // references was a mistake #define DOWNCAST_FN(destType) \ destType const *as##destType##C() const; \ destType *as##destType() { return const_cast(as##destType##C()); } #define DOWNCAST_IMPL(inClass, destType) \ destType const *inClass::as##destType##C() const \ { \ xassert(is##destType()); \ return static_cast(this); \ } // keep track of a count and a high water mark #define INC_HIGH_WATER(count, highWater) \ count++; \ if (count > highWater) { \ highWater = count; \ } // egcs has the annoying "feature" that it warns // about switches on enums where not all cases are // covered .... what is this, f-ing ML?? #define INCL_SWITCH \ default: break; /*silence warning*/ // for a class that maintains allocated-node stats #define ALLOC_STATS_DECLARE \ static int numAllocd; \ static int maxAllocd; \ static void printAllocStats(bool anyway); // these would go in a .cc file, whereas above goes in .h file #define ALLOC_STATS_DEFINE(classname) \ int classname::numAllocd = 0; \ int classname::maxAllocd = 0; \ STATICDEF void classname::printAllocStats(bool anyway) \ { \ if (anyway || numAllocd != 0) { \ cout << #classname << " nodes: " << numAllocd \ << ", max nodes: " << maxAllocd \ << endl; \ } \ } #define ALLOC_STATS_IN_CTOR \ INC_HIGH_WATER(numAllocd, maxAllocd); #define ALLOC_STATS_IN_DTOR \ numAllocd--; // ----------- automatic data value restorer ------------- // used when a value is to be set to one thing now, but restored // to its original value on return (even when the return is by // an exception being thrown) template class Restorer { T &variable; T prevValue; public: Restorer(T &var, T newValue) : variable(var), prevValue(var) { variable = newValue; } // this one does not set it to a new value, just remembers the current Restorer(T &var) : variable(var), prevValue(var) {} ~Restorer() { variable = prevValue; } }; // declare a bunch of a set-like operators for enum types #define ENUM_BITWISE_AND(Type) \ inline Type operator& (Type f1, Type f2) \ { return (Type)((int)f1 & (int)f2); } \ inline Type& operator&= (Type &f1, Type f2) \ { return f1 = f1 & f2; } #define ENUM_BITWISE_OR(Type) \ inline Type operator| (Type f1, Type f2) \ { return (Type)((int)f1 | (int)f2); } \ inline Type& operator|= (Type &f1, Type f2) \ { return f1 = f1 | f2; } #define ENUM_BITWISE_XOR(Type) \ inline Type operator^ (Type f1, Type f2) \ { return (Type)((int)f1 ^ (int)f2); } \ inline Type& operator^= (Type &f1, Type f2) \ { return f1 = f1 ^ f2; } #define ENUM_BITWISE_NOT(Type, ALL) \ inline Type operator~ (Type f) \ { return (Type)((~(int)f) & ALL); } #define ENUM_BITWISE_OPS(Type, ALL) \ ENUM_BITWISE_AND(Type) \ ENUM_BITWISE_OR(Type) \ ENUM_BITWISE_XOR(Type) \ ENUM_BITWISE_NOT(Type, ALL) // macro to conditionalize something on NDEBUG; I typically use this // to hide the declaration of a variable whose value is only used by // debugging trace statements (and thus provokes warnings about unused // variables if NDEBUG is set) #ifdef NDEBUG #define IFDEBUG(stuff) #else #define IFDEBUG(stuff) stuff #endif // put at the top of a class for which the default copy ctor // and operator= are not desired; then don't define these functions #define NO_OBJECT_COPIES(name) \ private: \ name(name&); \ void operator=(name&) /*user ;*/ #endif // __MACROS_H