Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

use lists instead of sets to store parent identifiers. this allows to store the exact order of initialization of parent classes.

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