Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/core/Super.h @ 1687

Last change on this file since 1687 was 1687, checked in by landauf, 16 years ago

simplified the declaration of a new super-function by replacing 2 intrusive macros with some templates

  • Property svn:eol-style set to native
File size: 21.1 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file Super.h
31    @brief Definition of all super-function related macros.
32
33    This file defines all macros needed to add a new "super-function".
34    If you add a super-function, you can call SUPER(myclass, functionname) inside your
35    code and the function of the parentclass gets called. This is comparable with
36    super.functionname() in Java or other languages.
37
38    This works only with virtual functions that return nothing (void) and belong to
39    classes that have an Identifier. Arguments however are supported.
40
41    To add a new super-function, you have process 4 steps:
42
43    1) Add a new SUPER macro
44       This allows you to call the super-function in your code.
45       Location: This file (Super.h), marked with --> HERE <-- comments (1/3)
46
47    2) Call the SUPER_FUNCTION_GLOBAL_DECLARATION_PART1/2 macros.
48       This defines some global classes and templates, needed to create and call the super-functions.
49       Location: This file (Super.h), marked with --> HERE <-- comments (2/3)
50
51    3) Call the SUPER_INTRUSIVE_DECLARATION macro.
52       This will be included into the declaration of ClassIdentifier<T>.
53       Location: This file (Super.h), marked with --> HERE <-- comments (3/3)
54
55    4) Call the SUPER_FUNCTION macro.
56       This defines a partially specialized template that will decide if a class is "super" to another class.
57       If the check returns true, a SuperFunctionCaller gets created, which will be used by the SUPER macro.
58       You have to add this into the header-file of the baseclass of the super-function (the class that first
59       implements the function), below the class declaration. You can't call it directly in this file, because
60       otherwise you had to include the headerfile right here, which would cause some ugly backdependencies,
61       include loops and slower compilation.
62       Dont forget to include Super.h in the header-file.
63       Location: The header-file of the baseclass (Baseclass.h), below the class declaration
64*/
65
66#ifndef _Super_H__
67#define _Super_H__
68
69#include <iostream>
70
71#include "CorePrereqs.h"
72
73#include "util/Debug.h"
74#include "util/XMLIncludes.h"
75
76///////////////////////
77// Macro definitions //
78///////////////////////
79
80//// Common macros ////
81
82    /**
83        @brief Declares a new super-function by creating a specialized template. Add this below the class declaration of the baseclass.
84        @param functionnumber Each super-function needs a unique number, starting with zero, increasing by one
85        @param baseclass The baseclass of the super-function (~the root)
86        @param functionname The name of the super-function
87        @param purevirtualbase "true" if the function is pure virtual in the baseclass, "false" if the function is implemented (without "")
88    */
89    #define SUPER_FUNCTION(functionnumber, baseclass, functionname, purevirtualbase) \
90        template <class T, int templatehack2> \
91        struct SuperFunctionCondition<functionnumber, T, 0, templatehack2> \
92        { \
93            static void check() \
94            { \
95                SuperFunctionCondition<functionnumber, T, 0, templatehack2>::apply((T*)0); \
96                SuperFunctionCondition<functionnumber + 1, T, 0, templatehack2>::check(); \
97            } \
98            \
99            static void apply(void* temp) {} \
100            static void apply(baseclass* temp) \
101            { \
102                ClassIdentifier<T>* identifier = ClassIdentifier<T>::getIdentifier(); \
103                for (std::set<const Identifier*>::iterator it = identifier->getDirectChildrenIntern().begin(); it != identifier->getDirectChildrenIntern().end(); ++it) \
104                { \
105                    if (!((ClassIdentifier<T>*)(*it))->superFunctionCaller_##functionname##_) \
106                    { \
107                        COUT(0) << "Added SuperFunctionCaller for " << #functionname << ": " << ClassIdentifier<T>::getIdentifier()->getName() << " <- " << ((ClassIdentifier<T>*)(*it))->getName() << std::endl; \
108                        ((ClassIdentifier<T>*)(*it))->superFunctionCaller_##functionname##_ = new SuperFunctionClassCaller_##functionname <T>; \
109                    } \
110                } \
111            } \
112        }; \
113        \
114        SUPER_FUNCTION_PUREVIRTUAL_WORKAROUND##purevirtualbase(functionnumber, baseclass)
115
116    #define SUPER_FUNCTION_PUREVIRTUAL_WORKAROUND0(functionnumber, baseclass) SUPER_FUNCTION_PUREVIRTUAL_WORKAROUNDfalse(functionnumber, baseclass)
117    #define SUPER_FUNCTION_PUREVIRTUAL_WORKAROUND1(functionnumber, baseclass) SUPER_FUNCTION_PUREVIRTUAL_WORKAROUNDtrue(functionnumber, baseclass)
118    #define SUPER_FUNCTION_PUREVIRTUAL_WORKAROUNDfalse(functionnumber, baseclass)
119    #define SUPER_FUNCTION_PUREVIRTUAL_WORKAROUNDtrue(functionnumber, baseclass) \
120        template <int templatehack2> \
121        struct SuperFunctionCondition<functionnumber, baseclass, 0, templatehack2> \
122        { \
123            static void check() \
124            { \
125                SuperFunctionCondition<functionnumber + 1, baseclass, 0, templatehack2>::check(); \
126            } \
127        };
128
129
130    /*
131    //// Comments about the macro ////
132
133        // Partially specialized template (templatehack is now specialized too).
134        //
135        // This ensures the compiler takes THIS template if the header-file of the super-function
136        // is included. In any other case, the compiler just uses the fallback template which is
137        // defined in this file.
138        template <class T, templatehack2>
139        struct SuperFunctionCondition<functionnumber, T, 0, templatehack2>
140        {
141            static void check()
142            {
143                // This call to the apply-function is the whole check. By calling the function with
144                // a T* pointer, the right function get's called.
145                SuperFunctionCondition<functionnumber, T, 0, templatehack2>::apply((T*)0);
146
147                // Go go the check for of next super-function (functionnumber + 1)
148                SuperFunctionCondition<functionnumber + 1, T, 0, templatehack2>::check();
149            }
150
151            // This function gets called if T is not a child of the baseclass.
152            // The function does nothing.
153            static void apply(void* temp) {}
154
155            // This function gets called if T is a child of the baseclass and can therefore be converted.
156            // The function adds a SuperFunctionCaller to the Identifier of all subclasses of T.
157            static void apply(baseclass* temp)
158            {
159                ClassIdentifier<T>* identifier = ClassIdentifier<T>::getIdentifier();
160
161                // Iterate through all children
162                for (std::set<const Identifier*>::iterator it = identifier->getDirectChildrenIntern().begin(); it != identifier->getDirectChildrenIntern().end(); ++it)
163                {
164                    // Check if there's not already a caller
165                    if (!((ClassIdentifier<T>*)(*it))->superFunctionCaller_##functionname##_)
166                    {
167                        // Add the SuperFunctionCaller
168                        COUT(5) << "adding functionpointer to " << ((ClassIdentifier<T>*)(*it))->getName() << std::endl;
169                        ((ClassIdentifier<T>*)(*it))->superFunctionCaller_##functionname##_ = new SuperFunctionClassCaller_##functionname <T>;
170                    }
171                }
172            }
173        };
174        SUPER_FUNCTION_PUREVIRTUAL_WORKAROUND##purevirtualbase
175
176
177        // The following piece of code is only added if purevirtualbase = true
178
179        // Explicit specialization of the Condition template for the baseclass to avoid
180        // errors if the function is pure virtual in the baseclass.
181        template <int templatehack2> \
182        struct SuperFunctionCondition<functionnumber, baseclass, 0, templatehack2> \
183        { \
184            // The check function just behaves like the fallback - it advances to the check for the next super-function (functionnumber + 1)
185            static void check() \
186            { \
187                SuperFunctionCondition<functionnumber + 1, baseclass, 0, templatehack2>::check(); \
188            } \
189        };
190    */
191
192    // SUPER-macro: Calls Parent::functionname() where Parent is the direct parent of classname
193    #define SUPER(classname, functionname, ...) \
194        SUPER_##functionname(classname, functionname, __VA_ARGS__)
195
196    // helper macro: for functions without arguments
197    #define SUPER_NOARGS(classname, functionname) \
198        (*ClassIdentifier<classname>::getIdentifier()->superFunctionCaller_##functionname##_)(this)
199
200    // helper macro: for functions with arguments
201    #define SUPER_ARGS(classname, functionname, ...) \
202        (*ClassIdentifier<classname>::getIdentifier()->superFunctionCaller_##functionname##_)(this, __VA_ARGS__)
203
204
205//// Function-specific macros ////
206
207    /*
208        Add a macro for each super-function
209
210        Example (no arguments):
211        #define SUPER_myfunction(classname, functionname, ...) \
212            SUPER_NOARGS(classname, functionname)
213
214        Example (with arguments):
215        #define SUPER_myfunction(classname, functionname, ...) \
216            SUPER_ARGS(classname, functionname, __VA_ARGS__)
217    */
218
219    // (1/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
220    #define SUPER_testfunction(classname, functionname, ...) \
221        SUPER_NOARGS(classname, functionname)
222
223    #define SUPER_XMLPort(classname, functionname, ...) \
224        SUPER_ARGS(classname, functionname, __VA_ARGS__)
225
226    #define SUPER_tick(classname, functionname, ...) \
227        SUPER_ARGS(classname, functionname, __VA_ARGS__)
228
229    #define SUPER_changedActivity(classname, functionname, ...) \
230        SUPER_NOARGS(classname, functionname)
231
232    #define SUPER_changedVisibility(classname, functionname, ...) \
233        SUPER_NOARGS(classname, functionname)
234    // (1/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
235
236
237namespace orxonox
238{
239    /////////////////////////////////////////////////////////////////////////////////////////////////////
240    // This code gets included by Identifier.h and every other header file that needs a super-function //
241    /////////////////////////////////////////////////////////////////////////////////////////////////////
242
243    //// Common code ////
244
245        // Base templates
246        /**
247            @brief Creates the SuperFunctionCaller if T is a child of the super-functions baseclass.
248        */
249        template <int functionnumber, class T, int templatehack1, int templatehack2>
250        struct SuperFunctionCondition
251        {
252            static void check() {}
253        };
254
255        /**
256            @brief Initializes the SuperFunctionCaller-pointer with zero.
257        */
258        template <int functionnumber, class T>
259        struct SuperFunctionInitialization
260        {
261            static void initialize(ClassIdentifier<T>* identifier) {}
262        };
263
264        /**
265            @brief Deletes the SuperFunctionCaller.
266        */
267        template <int functionnumber, class T>
268        struct SuperFunctionDestruction
269        {
270            static void destroy(ClassIdentifier<T>* identifier) {}
271        };
272
273
274    //// Function-specific code ////
275
276        /**
277            @brief Creates the needed objects and templates to call a super-function.
278            @param functionnumber Each super-function needs a unique number, starting with zero, increasing by one
279            @param functionname The name of the super-function
280            @param hasarguments "false" if the function doesn't take any arguments, "true" if it does (without "")
281            @param ... Variadic: If the function takes arguments, add them here with type and name. Example: int myvalue, float myothervalue
282        */
283        #define SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(functionnumber, functionname, hasarguments, ...) \
284            template <class T, int templatehack1, int templatehack2> \
285            struct SuperFunctionCondition<functionnumber, T, templatehack1, templatehack2> \
286            { \
287                static void check() \
288                { \
289                    SuperFunctionCondition<functionnumber + 1, T, templatehack1, templatehack2>::check(); \
290                } \
291            }; \
292            \
293            template <class T> \
294            struct SuperFunctionInitialization<functionnumber, T> \
295            { \
296                static void initialize(ClassIdentifier<T>* identifier) \
297                { \
298                    identifier->superFunctionCaller_##functionname##_ = 0; \
299                    SuperFunctionInitialization<functionnumber + 1, T>::initialize(identifier); \
300                } \
301            }; \
302            \
303            template <class T> \
304            struct SuperFunctionDestruction<functionnumber, T> \
305            { \
306                static void destroy(ClassIdentifier<T>* identifier) \
307                { \
308                    if (identifier->superFunctionCaller_##functionname##_) \
309                        delete identifier->superFunctionCaller_##functionname##_; \
310                    SuperFunctionDestruction<functionnumber + 1, T>::destroy(identifier); \
311                } \
312            }; \
313            \
314            class _CoreExport SuperFunctionCaller_##functionname \
315            { \
316                public: \
317                    virtual void operator()( SUPER_CALL_ARGUMENTS##hasarguments(__VA_ARGS__) ) = 0; \
318                    virtual ~SuperFunctionCaller_##functionname () {} \
319            }; \
320            \
321            template <class T> \
322            class SuperFunctionClassCaller_##functionname : public SuperFunctionCaller_##functionname \
323            { \
324                public: \
325                    inline void operator()( SUPER_CALL_ARGUMENTS##hasarguments(__VA_ARGS__) ) \
326                    { \
327                        (dynamic_cast<T*>(object))->T:: functionname
328
329        /*
330            JUST ADD THE FUNCTION ARGUMENTS BETWEEN BOTH MACROS, ENCLOSED BY BRACKETS
331            EXAMPLE:
332
333              SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(0, myfunction, true, int myvalue, float myothervalue) <-- !!! DONT ADD A SEMICOLON HERE !!!
334                (myvalue, myothervalue)
335              SUPER_FUNCTION_GLOBAL_DECLARATION_PART2
336        */
337
338        #define SUPER_FUNCTION_GLOBAL_DECLARATION_PART2 \
339                                                        ; \
340                    } \
341            };
342
343        #define SUPER_CALL_ARGUMENTSfalse(...) OrxonoxClass* object
344        #define SUPER_CALL_ARGUMENTS0(...)     OrxonoxClass* object
345        #define SUPER_CALL_ARGUMENTStrue(...) OrxonoxClass* object, __VA_ARGS__
346        #define SUPER_CALL_ARGUMENTS1(...)    OrxonoxClass* object, __VA_ARGS__
347
348
349    /*
350    //// COMMENTS ABOUT THE MACRO ////
351
352        // Partially specialized template (templatehack not yet specialized, this
353        // will be done by the real condition in the header-file of the super-function)
354        // Only used as fallback
355        template <class T, int templatehack1, int templatehack2>
356        struct SuperFunctionCondition<functionnumber, T, templatehack1, templatehack2>
357        {
358            // If this function gets called, the header-file of the super function is not
359            // included, so this fallback template (templatehack not specialized) is used
360            static void check()
361            {
362                // Calls the condition-check of the next super-function (functionnumber + 1)
363                SuperFunctionCondition<functionnumber + 1, T, templatehack1, templatehack2>::check();
364            }
365        };
366
367        // Initializes the SuperFunctionCaller-pointer with zero.
368        template <class T>
369        struct SuperFunctionInitialization<functionnumber, T>
370        {
371            static void initialize(ClassIdentifier<T>* identifier)
372            {
373                identifier->superFunctionCaller_##functionname##_ = 0;
374
375                // Calls the initialization of the next super-function (functionnumber + 1)
376                SuperFunctionInitialization<functionnumber + 1, T>::initialize(identifier);
377            }
378        };
379
380        // Deletes the SuperFunctionCaller.
381        template <class T>
382        struct SuperFunctionDestruction<functionnumber, T>
383        {
384            static void destroy(ClassIdentifier<T>* identifier)
385            {
386                if (identifier->superFunctionCaller_##functionname##_)
387                    delete identifier->superFunctionCaller_##functionname##_;
388
389                // Calls the destruction of the next super-function (functionnumber + 1)
390                SuperFunctionDestruction<functionnumber + 1, T>::destroy(identifier);
391            }
392        };
393
394        // Baseclass of the super-function caller. The real call will be done by a
395        // templatized subclass through the virtual () operator.
396        class _CoreExport SuperFunctionCaller_##functionname
397        {
398            public:
399                virtual void operator()( SUPER_CALL_ARGUMENTS##hasarguments(__VA_ARGS__) ) = 0;
400                virtual ~SuperFunctionCaller_##functionname () {}
401        };
402
403        // The real super-function caller: Calls T::functionname()
404        // T should be the parent, but this will be done by the spezialized condition template
405        template <class T>
406        class SuperFunctionClassCaller_##functionname : public SuperFunctionCaller_##functionname
407        {
408            public:
409                // @brief Calls the function.
410                // @param object The object to call the function on
411                // @param ... The arguments of the function
412                inline void operator()( SUPER_CALL_ARGUMENTS##hasarguments(__VA_ARGS__) )
413                {
414                    (dynamic_cast<T*>(object))->T:: functionname ( Call the function with it's arguments );
415                }
416        }
417    */
418
419
420    //// Execute the code for each super-function ////
421
422        // (2/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
423        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(0, testfunction, false)
424            ()
425        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
426
427        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(1, XMLPort, true, Element& xmlelement, XMLPort::Mode mode)
428            (xmlelement, mode)
429        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
430
431        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(2, tick, true, float dt)
432            (dt)
433        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
434
435        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(3, changedActivity, false)
436            ()
437        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
438
439        SUPER_FUNCTION_GLOBAL_DECLARATION_PART1(4, changedVisibility, false)
440            ()
441        SUPER_FUNCTION_GLOBAL_DECLARATION_PART2;
442        // (2/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
443
444}
445
446#else /* _Super_H__ */
447  #ifdef SUPER_INTRUSIVE_DECLARATION_INCLUDE
448
449//////////////////////////////////////////////////////////////////////////
450// This code gets included within the declaration of ClassIdentifier<T> //
451//////////////////////////////////////////////////////////////////////////
452
453//// Common code ////
454
455    private:
456
457        template <int functionnumber, class TT, int templatehack1, int templatehack2>
458        friend struct SuperFunctionCondition;
459
460        // Creates the super-function-callers by calling the first SuperFunctionCondition check
461        // This get's called within the initialization of an Identifier
462        virtual void createSuperFunctionCaller() const
463        {
464            SuperFunctionCondition<0, T, 0, 0>::check();
465        }
466
467
468//// Function-specific code ////
469
470    public:
471        /**
472            @brief Adds a pointer to the SuperFunctionCaller as a member of ClassIdentifier.
473            @param functionname The name of the super-function
474        */
475        #ifndef SUPER_INTRUSIVE_DECLARATION
476          #define SUPER_INTRUSIVE_DECLARATION(functionname) \
477            SuperFunctionCaller_##functionname * superFunctionCaller_##functionname##_
478        #endif
479
480
481//// Execute the code for each super-function ////
482
483    // (3/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
484    SUPER_INTRUSIVE_DECLARATION(testfunction);
485    SUPER_INTRUSIVE_DECLARATION(XMLPort);
486    SUPER_INTRUSIVE_DECLARATION(tick);
487    SUPER_INTRUSIVE_DECLARATION(changedActivity);
488    SUPER_INTRUSIVE_DECLARATION(changedVisibility);
489    // (3/3) --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <-- --> HERE <--
490
491
492    #undef SUPER_INTRUSIVE_DECLARATION_INCLUDE
493  #endif /* SUPER_INTRUSIVE_DECLARATION_INCLUDE */
494#endif /* _Super_H__ */
Note: See TracBrowser for help on using the repository browser.