// /*-------------------------------------------------------------------*\ // | Macros // \*-------------------------------------------------------------------*/ #ifndef MACROS_H #define MACROS_H 1 ///------------------------------------------------------------------------ /// "standard_abstract_operations (T)" ///------------------------------------------------------------------------ // The following macro is for readability only, so in an abstract // "XXX_Kernel" component you can (should) declare that the type has the // standard operations: constructor, destructor, operator &= (swap), // and Clear. Since it is followed by a semicolon when used, and // some compilers don't like bare semicolons, it expands to the // harmless declaration of the constructor, which will be overridden // anyway in any concrete class that implements this abstract class. #define standard_abstract_operations(T) T(){} ///------------------------------------------------------------------------ /// "standard_concrete_operations (K)" ///------------------------------------------------------------------------ // This macro is used to define the boilerplate in kernel concrete // classes. It does three things for the kernel concrete component // whose name is K: // // (1) Prohibits the assignment operator and copy constructor. // (2) Declares the constructor and destructor (operator &= and the Clear // operation, which are also assumed standard for all classes, are // introduced through the "encapsulates" relation rather than being // declared directly; they are inherited directly from an instance of // the template Representation). // (3) By not making the destructor virtual, prevents overriding of the // (constructor and) destructor, because this is supposed to be THE // only way to implement these operations! // // The constructor body is always empty, as shown below, because of // the "smart constructor" (Initialize) which is used by // Representation to do lazy initialization. The destructor body is // always what is shown below because this is the "smart destructor" // to match Initialize. // // See Representation for details of how lazy initialization works. // Notice in particular that Finalize, like Initialize, has a default // implementation in Representation which does nothing, and which // might be overridden in derived classes, i.e., in kernel components. // Initialize_Has_Been_Called, on the other hand, is an operation of // Representation that is never overridden. // // Note: This macro leaves the default visibility of any // declarations following it as "public". #define standard_concrete_operations(K) \ private: \ K & operator = (const K & /*rhs*/); \ K (const K & /*x*/); \ public: \ K () {} \ ~K () \ { \ if (this->Initialize_Has_Been_Called ()) \ { \ this->Finalize (); \ } \ } ///------------------------------------------------------------------------ /// "field_name (record_type, field_index, field_type, logical_name)" ///------------------------------------------------------------------------ // When using the "Record" component, you must use this macro to // declare logical field names and associate them with specific // field positions within the record structure. The four // parameters are: // // (1) The name of the Record instance. // (2) The field number (where 0 is the first field). // (3) The type for the field you wish to declare. // (4) The logical name for the field you wish to declare. // // Note: The first and third fields are ignored -- they are for // readability purposes (and for uniformity with rep_field_name) only. #define field_name(record_type, field_index, field_type, logical_name) \ Record_Accessor logical_name ///------------------------------------------------------------------------ /// "rep_field_name (rep_type, field_index, field_type, logical_name)" ///------------------------------------------------------------------------ // When using the "Representation" component, you must use this macro // to declare logical field names and associate them with specific // field positions within the structure, AND to give the same effect // as "using rep_type::operator [];" is supposed to have (which some // compilers don't seem to do, as we understand how C++ is supposed to // work). The four parameters are: // // (1) The name of the Representation instance. // (2) The field number (where 0 is the first field). // (3) The type for the field you wish to declare. // (4) The logical name for the field you wish to declare. #define rep_field_name(rep_type, field_index, field_type, logical_name) \ function field_type& operator [] ( \ Representation_Accessor& accessor \ ) \ { \ return rep_type::operator[] (accessor); \ } \ Representation_Accessor logical_name ///------------------------------------------------------------------------ /// "standard_assignment_operator (T)" ///------------------------------------------------------------------------ // This macro helps with the fact that in C++, operator = is not // inherited. It assumes that Copy_To (which *is* inherited) is // defined for the current class. When called, this macro generates a // standard inline implementation for operator = layered on top of // Copy_To. You can use it in instances of classes that define // Copy_To so that you can use "x = y;" as a shorthand notation. If // used faithfully in all derived classes and instances that declare or // inherit Copy_To, it provides a satisfactory illusion that operator = // is being inherited. #define standard_assignment_operator(T) \ public: \ function T& operator = (T& rhs) \ { \ rhs.Copy_To (self); \ return (self); \ } ///------------------------------------------------------------------------ /// "standard_equality_operators (T)" ///------------------------------------------------------------------------ // This macro assumes that operation Is_Equal_To is defined for this // class, taking an object of type "T" as the argument. It generates // a standard inline implementation for == and != layered on top of // "==". It can be used anywhere that you can't (or don't want to) // write a faster, optimized version of != for your class. #define standard_equality_operators(T) \ custom_equality_operators(T&) #define custom_equality_operators(T) \ public: \ function Boolean operator == (T rhs) \ { \ return self.Is_Equal_To (rhs); \ } \ function Boolean operator != (T rhs) \ { \ return (not self.Is_Equal_To (rhs)); \ } ///------------------------------------------------------------------------ /// "standard_comparison_operators (T)" ///------------------------------------------------------------------------ // This macro assumes that "Compare (x)" (returning an Integer) is // defined for comparing self, of type T, to another object of type T. // It generates standard inline implementations of the six standard // comparison operators layered on top of "Compare". Use it wherever // you want to provide all comparison operations without writing // optimized versions of each one for your class. // Note that only one of the two macros "standard_equality_operators" // or "standard_comparison_operators" can be used in the same // interface, since they both define operators == and !=. Of course, // it is always OK to provide a manual implementation of all of the // comparison and equality operators, but the sets provided should be // consistent with those provided by these two macros. // //---------------------------------------------------------------------- // T's interface includes operation | //-----------------------------------+ Use the following macro // Is_Equal_To | Compare | //------------------+----------------+---------------------------------- // | | Can't use either // * | | standard_equality_operators // | * | standard_comparison_operators // * | * | standard_comparison_operators //---------------------------------------------------------------------- #define standard_comparison_operators(T) \ custom_comparison_operators(T&) #define custom_comparison_operators(T) \ public: \ function Boolean operator == (T rhs) \ { \ return self.Compare (rhs) == 0; \ } \ function Boolean operator != (T rhs) \ { \ return self.Compare (rhs) != 0; \ } \ function Boolean operator < (T rhs) \ { \ return self.Compare (rhs) < 0; \ } \ function Boolean operator > (T rhs) \ { \ return self.Compare (rhs) > 0; \ } \ function Boolean operator >= (T rhs) \ { \ return self.Compare (rhs) >= 0; \ } \ function Boolean operator <= (T rhs) \ { \ return self.Compare (rhs) <= 0; \ } // The following macros provide various statements to the C++ // language. Needless to say, this section should not be expanded // gratuitiously. There is only one (so far :-): case_select. #define case_select(arg) \ switch (To_int (arg)) #endif // MACROS_H