Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/class/Identifier.cc @ 10395

Last change on this file since 10395 was 10395, checked in by landauf, 10 years ago

create and initialize Identifiers explicitly via registerClass(). registerClass() must be called before using an Identifier of this type.
(some tests will currently fail)

  • Property svn:eol-style set to native
File size: 18.9 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
31    @brief Implementation of the Identifier class.
32*/
33
34#include "Identifier.h"
35
36#include <ostream>
37
38#include "util/StringUtils.h"
39#include "core/CoreIncludes.h"
40#include "core/config/ConfigValueContainer.h"
41#include "core/XMLPort.h"
42#include "core/object/ClassFactory.h"
43
44namespace orxonox
45{
46    // ###############################
47    // ###       Identifier        ###
48    // ###############################
49    /**
50        @brief Constructor: No factory, no object created, new ObjectList and a unique networkID.
51    */
52    Identifier::Identifier(const std::string& name, Factory* factory, bool bLoadable)
53        : classID_(IdentifierManager::getInstance().getUniqueClassId())
54    {
55        this->name_ = name;
56        this->factory_ = factory;
57        this->bLoadable_ = bLoadable;
58        this->bInitialized_ = false;
59        this->bIsVirtualBase_ = false;
60
61        this->bHasConfigValues_ = false;
62
63        // Default network ID is the class ID
64        this->networkID_ = this->classID_;
65    }
66
67    /**
68        @brief Destructor: Deletes the list containing the children.
69    */
70    Identifier::~Identifier()
71    {
72        if (this->factory_)
73            delete this->factory_;
74
75        for (std::map<std::string, ConfigValueContainer*>::iterator it = this->configValues_.begin(); it != this->configValues_.end(); ++it)
76            delete (it->second);
77        for (std::map<std::string, XMLPortParamContainer*>::iterator it = this->xmlportParamContainers_.begin(); it != this->xmlportParamContainers_.end(); ++it)
78            delete (it->second);
79        for (std::map<std::string, XMLPortObjectContainer*>::iterator it = this->xmlportObjectContainers_.begin(); it != this->xmlportObjectContainers_.end(); ++it)
80            delete (it->second);
81    }
82
83
84    /**
85        @brief Creates an object of the type the Identifier belongs to.
86        @return The new object
87    */
88    Identifiable* Identifier::fabricate(Context* context)
89    {
90        if (this->factory_)
91        {
92            return this->factory_->fabricate(context);
93        }
94        else
95        {
96            orxout(user_error) << "An error occurred in Identifier.cc:" << endl;
97            orxout(user_error) << "Cannot fabricate an object of type '" << this->name_ << "'. Class has no factory." << endl;
98            orxout(user_error) << "Aborting..." << endl;
99            abort();
100            return 0;
101        }
102    }
103
104    /**
105        @brief Sets the network ID to a new value and changes the entry in the ID-Identifier-map.
106    */
107    void Identifier::setNetworkID(uint32_t id)
108    {
109        this->networkID_ = id;
110        IdentifierManager::getInstance().addIdentifier(this);
111    }
112
113    /**
114     * @brief Used to define the direct parents of an Identifier of an abstract class.
115     */
116    Identifier& Identifier::inheritsFrom(Identifier* directParent)
117    {
118        if (this->parents_.empty())
119            this->directParents_.push_back(directParent);
120        else
121            orxout(internal_error) << "Trying to add " << directParent->getName() << " as a direct parent of " << this->getName() << " after the latter was already initialized" << endl;
122
123        return *this;
124    }
125
126    /**
127     * @brief Initializes the parents of this Identifier while creating the class hierarchy.
128     * @param initializationTrace All identifiers that were recorded while creating an instance of this class (including nested classes and this identifier itself)
129     */
130    void Identifier::initializeParents(const std::list<const Identifier*>& initializationTrace)
131    {
132        if (!IdentifierManager::getInstance().isCreatingHierarchy())
133        {
134            orxout(internal_warning) << "Identifier::initializeParents() created outside of class hierarchy creation" << endl;
135            return;
136        }
137
138        if (this->directParents_.empty())
139        {
140            for (std::list<const Identifier*>::const_iterator it = initializationTrace.begin(); it != initializationTrace.end(); ++it)
141                if (*it != this)
142                    this->parents_.push_back(*it);
143        }
144        else
145            orxout(internal_error) << "Trying to add parents to " << this->getName() << " after it was already initialized with manual calls to inheritsFrom<Class>()." << endl;
146    }
147
148    /**
149     * @brief Finishes the initialization of this Identifier after creating the class hierarchy by wiring the (direct) parent/child references correctly.
150     */
151    void Identifier::finishInitialization()
152    {
153        if (!IdentifierManager::getInstance().isCreatingHierarchy())
154        {
155            orxout(internal_warning) << "Identifier::finishInitialization() created outside of class hierarchy creation" << endl;
156            return;
157        }
158
159        if (this->isInitialized())
160            return;
161
162        if (!this->parents_.empty())
163        {
164            // parents defined -> this class was initialized by creating a sample instance and recording the trace of identifiers
165
166            // initialize all parents
167            for (std::list<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
168                const_cast<Identifier*>(*it)->finishInitialization(); // initialize parent
169
170            // parents of parents are no direct parents of this identifier
171            this->directParents_ = this->parents_;
172            for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
173                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
174                    this->directParents_.remove(*it_parent_parent);
175
176            this->verifyIdentifierTrace();
177        }
178        else if (!this->directParents_.empty())
179        {
180            // no parents defined -> this class was manually initialized by calling inheritsFrom<Class>()
181
182            // initialize all direct parents
183            for (std::list<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
184                const_cast<Identifier*>(*it)->finishInitialization(); // initialize parent
185
186            // direct parents and their parents are also parents of this identifier (but only add them once)
187            for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
188            {
189                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
190                    this->addIfNotExists(this->parents_, *it_parent_parent);
191                this->addIfNotExists(this->parents_, *it_parent);
192            }
193        }
194        else if (!this->isExactlyA(Class(Identifiable)))
195        {
196            // only Identifiable is allowed to have no parents (even tough it's currently not abstract)
197            orxout(internal_error) << "Identifier " << this->getName() << " / " << this->getTypeidName() << " is marked as abstract but has no direct parents defined" << endl;
198            orxout(internal_error) << "  If this class is not abstract, use RegisterClass(ThisClass);" << endl;
199            orxout(internal_error) << "  If this class is abstract, use RegisterAbstractClass(ThisClass).inheritsFrom(Class(BaseClass));" << endl;
200        }
201
202        // tell all parents that this identifier is a child
203        for (std::list<const Identifier*>::const_iterator it = this->parents_.begin(); it != this->parents_.end(); ++it)
204            const_cast<Identifier*>(*it)->children_.insert(this);
205
206        // tell all direct parents that this identifier is a direct child
207        for (std::list<const Identifier*>::const_iterator it = this->directParents_.begin(); it != this->directParents_.end(); ++it)
208        {
209            const_cast<Identifier*>(*it)->directChildren_.insert(this);
210
211            // Create the super-function dependencies
212            (*it)->createSuperFunctionCaller();
213        }
214
215        this->bInitialized_ = true;
216    }
217
218    /**
219     * Verifies if the recorded trace of parent identifiers matches the expected trace according to the class hierarchy. If it doesn't match, the class
220     * hierarchy is likely wrong, e.g. due to wrong inheritsFrom<>() definitions in abstract classes.
221     */
222    void Identifier::verifyIdentifierTrace() const
223    {
224
225        std::list<const Identifier*> expectedIdentifierTrace;
226
227        // if any parent class is virtual, it will be instantiated first, so we need to add them first.
228        for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
229        {
230            if ((*it_parent)->isVirtualBase())
231            {
232                for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
233                    this->addIfNotExists(expectedIdentifierTrace, *it_parent_parent);
234                this->addIfNotExists(expectedIdentifierTrace, *it_parent);
235            }
236        }
237
238        // now all direct parents get created recursively. already added identifiers (e.g. virtual base classes) are not added again.
239        for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
240        {
241            for (std::list<const Identifier*>::const_iterator it_parent_parent = const_cast<Identifier*>(*it_parent)->parents_.begin(); it_parent_parent != const_cast<Identifier*>(*it_parent)->parents_.end(); ++it_parent_parent)
242                this->addIfNotExists(expectedIdentifierTrace, *it_parent_parent);
243            this->addIfNotExists(expectedIdentifierTrace, *it_parent);
244        }
245
246        // check if the expected trace matches the actual trace (which was defined by creating a sample instance)
247        if (expectedIdentifierTrace != this->parents_)
248        {
249            orxout(internal_warning) << this->getName() << " has an unexpected initialization trace:" << endl;
250
251            orxout(internal_warning) << "  Actual trace (after creating a sample instance):" << endl << "    ";
252            for (std::list<const Identifier*>::const_iterator it_parent = this->parents_.begin(); it_parent != this->parents_.end(); ++it_parent)
253                orxout(internal_warning) << " " << (*it_parent)->getName();
254            orxout(internal_warning) << endl;
255
256            orxout(internal_warning) << "  Expected trace (according to class hierarchy definitions):" << endl << "    ";
257            for (std::list<const Identifier*>::const_iterator it_parent = expectedIdentifierTrace.begin(); it_parent != expectedIdentifierTrace.end(); ++it_parent)
258                orxout(internal_warning) << " " << (*it_parent)->getName();
259            orxout(internal_warning) << endl;
260
261            orxout(internal_warning) << "  Direct parents (according to class hierarchy definitions):" << endl << "    ";
262            for (std::list<const Identifier*>::const_iterator it_parent = this->directParents_.begin(); it_parent != this->directParents_.end(); ++it_parent)
263                orxout(internal_warning) << " " << (*it_parent)->getName();
264            orxout(internal_warning) << endl;
265        }
266    }
267
268    /**
269     * Adds @param identifierToAdd to @param list if this identifier is not already contained in the list.
270     */
271    void Identifier::addIfNotExists(std::list<const Identifier*>& list, const Identifier* identifierToAdd) const
272    {
273        if (std::find(list.begin(), list.end(), identifierToAdd) == list.end())
274            list.push_back(identifierToAdd);
275    }
276
277    /**
278        @brief Returns true, if the Identifier is at least of the given type.
279        @param identifier The identifier to compare with
280    */
281    bool Identifier::isA(const Identifier* identifier) const
282    {
283        return (identifier == this || (this->isChildOf(identifier)));
284    }
285
286    /**
287        @brief Returns true, if the Identifier is exactly of the given type.
288        @param identifier The identifier to compare with
289    */
290    bool Identifier::isExactlyA(const Identifier* identifier) const
291    {
292        return (identifier == this);
293    }
294
295    /**
296        @brief Returns true, if the assigned identifier is a child of the given identifier.
297        @param identifier The identifier to compare with
298    */
299    bool Identifier::isChildOf(const Identifier* identifier) const
300    {
301        return (std::find(this->parents_.begin(), this->parents_.end(),  identifier) != this->parents_.end());
302    }
303
304    /**
305        @brief Returns true, if the assigned identifier is a direct child of the given identifier.
306        @param identifier The identifier to compare with
307    */
308    bool Identifier::isDirectChildOf(const Identifier* identifier) const
309    {
310        return (std::find(this->directParents_.begin(), this->directParents_.end(), identifier) != this->directParents_.end());
311    }
312
313    /**
314        @brief Returns true, if the assigned identifier is a parent of the given identifier.
315        @param identifier The identifier to compare with
316    */
317    bool Identifier::isParentOf(const Identifier* identifier) const
318    {
319        return (this->children_.find(identifier) != this->children_.end());
320    }
321
322    /**
323        @brief Returns true, if the assigned identifier is a direct parent of the given identifier.
324        @param identifier The identifier to compare with
325    */
326    bool Identifier::isDirectParentOf(const Identifier* identifier) const
327    {
328        return (this->directChildren_.find(identifier) != this->directChildren_.end());
329    }
330
331    /**
332        @brief Adds the ConfigValueContainer of a variable, given by the string of its name.
333        @param varname The name of the variablee
334        @param container The container
335    */
336    void Identifier::addConfigValueContainer(const std::string& varname, ConfigValueContainer* container)
337    {
338        std::map<std::string, ConfigValueContainer*>::const_iterator it = this->configValues_.find(varname);
339        if (it != this->configValues_.end())
340        {
341            orxout(internal_warning) << "Overwriting config-value with name " << varname << " in class " << this->getName() << '.' << endl;
342            delete (it->second);
343        }
344
345        this->bHasConfigValues_ = true;
346        this->configValues_[varname] = container;
347    }
348
349    /**
350        @brief Returns the ConfigValueContainer of a variable, given by the string of its name.
351        @param varname The name of the variable
352        @return The ConfigValueContainer
353    */
354    ConfigValueContainer* Identifier::getConfigValueContainer(const std::string& varname)
355    {
356        std::map<std::string, ConfigValueContainer*>::const_iterator it = configValues_.find(varname);
357        if (it != configValues_.end())
358            return it->second;
359        else
360            return 0;
361    }
362
363    /**
364        @brief Returns a XMLPortParamContainer that loads a parameter of this class.
365        @param paramname The name of the parameter
366        @return The container
367    */
368    XMLPortParamContainer* Identifier::getXMLPortParamContainer(const std::string& paramname)
369    {
370        std::map<std::string, XMLPortParamContainer*>::const_iterator it = this->xmlportParamContainers_.find(paramname);
371        if (it != this->xmlportParamContainers_.end())
372            return it->second;
373        else
374            return 0;
375    }
376
377    /**
378        @brief Adds a new XMLPortParamContainer that loads a parameter of this class.
379        @param paramname The name of the parameter
380        @param container The container
381    */
382    void Identifier::addXMLPortParamContainer(const std::string& paramname, XMLPortParamContainer* container)
383    {
384        std::map<std::string, XMLPortParamContainer*>::const_iterator it = this->xmlportParamContainers_.find(paramname);
385        if (it != this->xmlportParamContainers_.end())
386        {
387            orxout(internal_warning) << "Overwriting XMLPortParamContainer in class " << this->getName() << '.' << endl;
388            delete (it->second);
389        }
390
391        this->xmlportParamContainers_[paramname] = container;
392    }
393
394    /**
395        @brief Returns a XMLPortObjectContainer that attaches an object to this class.
396        @param sectionname The name of the section that contains the attachable objects
397        @return The container
398    */
399    XMLPortObjectContainer* Identifier::getXMLPortObjectContainer(const std::string& sectionname)
400    {
401        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportObjectContainers_.find(sectionname);
402        if (it != this->xmlportObjectContainers_.end())
403            return it->second;
404        else
405            return 0;
406    }
407
408    /**
409        @brief Adds a new XMLPortObjectContainer that attaches an object to this class.
410        @param sectionname The name of the section that contains the attachable objects
411        @param container The container
412    */
413    void Identifier::addXMLPortObjectContainer(const std::string& sectionname, XMLPortObjectContainer* container)
414    {
415        std::map<std::string, XMLPortObjectContainer*>::const_iterator it = this->xmlportObjectContainers_.find(sectionname);
416        if (it != this->xmlportObjectContainers_.end())
417        {
418            orxout(internal_warning) << "Overwriting XMLPortObjectContainer in class " << this->getName() << '.' << endl;
419            delete (it->second);
420        }
421
422        this->xmlportObjectContainers_[sectionname] = container;
423    }
424
425    /**
426        @brief Lists the names of all Identifiers in a std::set<const Identifier*>.
427        @param out The outstream
428        @param list The list (or set) of Identifiers
429        @return The outstream
430    */
431    std::ostream& operator<<(std::ostream& out, const std::set<const Identifier*>& list)
432    {
433        for (std::set<const Identifier*>::const_iterator it = list.begin(); it != list.end(); ++it)
434        {
435            if (it != list.begin())
436                out << ' ';
437            out << (*it)->getName();
438        }
439
440        return out;
441    }
442}
Note: See TracBrowser for help on using the repository browser.