Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

removed some debug and test code

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