Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core/src/orxonox/core/ClassTreeMask.cc @ 813

Last change on this file since 813 was 813, checked in by landauf, 16 years ago
  • removed IdentifierList and replaced it by a std::list
  • changed several doxygen tags
File size: 24.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
6 *
7 *   This program is free software; you can redistribute it and/or
8 *   modify it under the terms of the GNU General Public License
9 *   as published by the Free Software Foundation; either version 2
10 *   of the License, or (at your option) any later version.
11 *
12 *   This program is distributed in the hope that it will be useful,
13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *   GNU General Public License for more details.
16 *
17 *   You should have received a copy of the GNU General Public License
18 *   along with this program; if not, write to the Free Software
19 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 *
21 *   Author:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
28/**
29    @file ClassTreeMask.cc
30    @brief Implementation of the ClassTreeMask, ClassTreeMaskNode and ClassTreeMaskIterator classes.
31*/
32
33#include "ClassTreeMask.h"
34#include "Identifier.h"
35#include "BaseObject.h"
36
37namespace orxonox
38{
39    // ###############################
40    // ###    ClassTreeMaskNode    ###
41    // ###############################
42    /**
43        @brief Constructor: Creates the node, sets the subclass and the rule.
44        @param subclass The subclass the rule refers to
45        @param bIncluded The rule: included (true) or excluded (false)
46    */
47    ClassTreeMaskNode::ClassTreeMaskNode(const Identifier* subclass, bool bIncluded)
48    {
49        this->subclass_ = subclass;
50        this->bIncluded_ = bIncluded;
51    }
52
53    /**
54        @brief Destructor: Deletes all subnodes.
55    */
56    ClassTreeMaskNode::~ClassTreeMaskNode()
57    {
58        // Go through the list of all subnodes and delete them
59        for (std::list<ClassTreeMaskNode*>::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); )
60            delete (*(it++));
61    }
62
63    /**
64        @brief Sets the rule for the node to "included".
65    */
66    void ClassTreeMaskNode::include()
67    {
68        this->bIncluded_ = true;
69    }
70
71    /**
72        @brief Sets the rule for the node to "excluded".
73    */
74    void ClassTreeMaskNode::exclude()
75    {
76        this->bIncluded_ = false;
77    }
78
79    /**
80        @brief Sets the rule for the node to a given value.
81        @param bIncluded The rule: included (true) or excluded (false)
82    */
83    void ClassTreeMaskNode::setIncluded(bool bIncluded)
84    {
85        this->bIncluded_ = bIncluded;
86    }
87
88    /**
89        @brief Adds a new subnode to the list of subnodes.
90        @param subnode The new subnode
91    */
92    void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode)
93    {
94        this->subnodes_.insert(this->subnodes_.end(), subnode);
95    }
96
97    /**
98        @brief Tells if the rule is "included" or not.
99        @return The rule: true = included, false = excluded
100    */
101    bool ClassTreeMaskNode::isIncluded() const
102    {
103        return this->bIncluded_;
104    }
105
106    /**
107        @brief Tells if the rule is "excluded" or not.
108        @return The inverted rule: true = excluded, false = included
109    */
110    bool ClassTreeMaskNode::isExcluded() const
111    {
112        return (!this->bIncluded_);
113    }
114
115    /**
116        @brief Returns the Identifier of the class the rule refers to.
117        @return The Identifier representing the class
118    */
119    const Identifier* ClassTreeMaskNode::getClass() const
120    {
121        return this->subclass_;
122    }
123
124
125    // ###############################
126    // ###  ClassTreeMaskIterator  ###
127    // ###############################
128    /**
129        @brief Constructor: Initializes the iterator by creating a helper-list with the root-node and putting it to the stack.
130        @param node The root-node
131    */
132    ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node)
133    {
134        // Create a list and put the root-note into it
135        std::list<ClassTreeMaskNode*>::iterator it = this->rootlist_.insert(this->rootlist_.end(), node);
136
137        // Put the iterator to the only element of the list and the corresponding end()-iterator on the stack
138        this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>(it, this->rootlist_.end()));
139    }
140
141    /**
142        @brief Destructor: Does nothing.
143    */
144    ClassTreeMaskIterator::~ClassTreeMaskIterator()
145    {
146    }
147
148    /**
149        @brief Iterates through the rule-tree.
150        @return A reference to the iterator itself
151    */
152    ClassTreeMaskIterator& ClassTreeMaskIterator::operator++()
153    {
154        // Check if the actual node has subnodes
155        if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end())
156        {
157            // Yes it has: Push an iterator, pointing at the first subnode, on the stack
158            this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>((*this->nodes_.top().first)->subnodes_.begin(), (*this->nodes_.top().first)->subnodes_.end()));
159        }
160        else
161        {
162            // No subnodes, meaning we reached a leaf: Go to the next node
163            do
164            {
165                // Iterate one step in the current list
166                ++this->nodes_.top().first;
167
168                // Check if we reached the end of the list (the second item in the stored pair always represents the end)
169                if (this->nodes_.top().first == this->nodes_.top().second)
170                {
171                    // Yes we've reached the end: Pop the list-iterator from the stack
172                    this->nodes_.pop();
173
174                    // Continue with the loop, meaning: Try to iterate through the previous list
175                    continue;
176                }
177
178                // If we reached this point, we aren't yet at the end of the list: Leave the loop
179                break;
180            } while (!this->nodes_.empty()); // Stop looping if the stack is empty, meaning: We've iterated to the end
181        }
182
183        // Finally return a reference to the iterator itself
184        return *this;
185    }
186
187    /**
188        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
189        @return The pointer to the node
190    */
191    ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const
192    {
193        return (*this->nodes_.top().first);
194    }
195
196    /**
197        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
198        @return The pointer to the node
199    */
200    ClassTreeMaskNode* ClassTreeMaskIterator::operator->() const
201    {
202        return (*this->nodes_.top().first);
203    }
204
205    /**
206        @brief Returns true if the stack is empty, meaning we've reached the end of the tree.
207        @return True if we've reached the end of the tree
208    */
209    ClassTreeMaskIterator::operator bool()
210    {
211        return (!this->nodes_.empty());
212    }
213
214    /**
215        @brief Compares the current node with the given one and returns true if they match.
216        @param compare The node to compare with
217        @return The result of the comparison (true if they match)
218    */
219    bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare)
220    {
221        if (!this->nodes_.empty())
222            return ((*this->nodes_.top().first) == compare);
223        else
224            return (compare == 0);
225    }
226
227    /**
228        @brief Compares the current node with the given one and returns true if they don't match.
229        @param compare The node to compare with
230        @return The result of the comparison (true if they don't match)
231    */
232    bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare)
233    {
234        if (!this->nodes_.empty())
235            return ((*this->nodes_.top().first) != compare);
236        else
237            return (compare != 0);
238    }
239
240
241    // ###############################
242    // ###      ClassTreeMask      ###
243    // ###############################
244    /**
245        @brief Constructor: Adds the root-node of the tree with the first rule ("include everything").
246    */
247    ClassTreeMask::ClassTreeMask()
248    {
249        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
250    }
251
252    /**
253        @brief Copyconstructor: Adds the root-node of the tree with the first rule ("include everything") and adds all rules from the other mask.
254        @param other The other mask
255    */
256    ClassTreeMask::ClassTreeMask(const ClassTreeMask& other)
257    {
258        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
259        for (ClassTreeMaskIterator it = other.root_; it; ++it)
260            this->add(it->getClass(), it->isIncluded());
261    }
262
263    /**
264        @brief Destructor: Deletes the root node (which will delete all subnodes too).
265    */
266    ClassTreeMask::~ClassTreeMask()
267    {
268        delete this->root_;
269    }
270
271    /**
272        @brief Adds a new "include" rule for a given subclass to the mask.
273        @param subclass The subclass
274    */
275    void ClassTreeMask::include(const Identifier* subclass)
276    {
277        this->add(subclass, true);
278    }
279
280    /**
281        @brief Adds a new "exclude" rule for a given subclass to the mask.
282        @param subclass The subclass
283    */
284    void ClassTreeMask::exclude(const Identifier* subclass)
285    {
286        this->add(subclass, false);
287    }
288
289    /**
290        @brief Adds a new rule for a given subclass to the mask.
291        @param subclass The subclass
292        @param bInclude The rule: include (true) or exclude (false)
293    */
294    void ClassTreeMask::add(const Identifier* subclass, bool bInclude)
295    {
296        if (subclass->isA(this->root_->getClass()))
297            this->add(this->root_, subclass, bInclude);
298        else
299        {
300
301        }
302
303        this->clean();
304    }
305
306    /**
307        @brief Adds a new rule for a given subclass to a node of the internal rule-tree (recursive function).
308        @param node The node
309        @param subclass The subclass
310        @param bInclude The rule: include (true) or exclude (false)
311    */
312    void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude)
313    {
314        // Check if the current node contains exactly the subclass we want to add
315        if (subclass == node->getClass())
316        {
317            // We're at the right place, just change the mask and return
318            node->setIncluded(bInclude);
319            return;
320        }
321        else
322        {
323            // Search for an already existing node, containing the subclass we want to add
324            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
325            {
326                if (subclass->isA((*it)->getClass()))
327                {
328                    // We've found an existing node -> delegate the work with a recursive function-call and return
329                    this->add(*it, subclass, bInclude);
330                    return;
331                }
332            }
333
334            // There is no existing node satisfying our needs -> we create a new node
335            ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude);
336
337            // Search for nodes that should actually be subnodes of our new node
338            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
339            {
340                if ((*it)->getClass()->isChildOf(subclass))
341                {
342                    // We've found a subnode: add it to the new node an erase it from the current node
343                    newnode->addSubnode(*it);
344                    node->subnodes_.erase(it++);
345                }
346                else
347                {
348                    ++it;
349                }
350            }
351
352            // Finally add the new node as a subnode to the current node
353            node->addSubnode(newnode);
354        }
355    }
356
357    /**
358        @brief Resets the mask to "include everything".
359    */
360    void ClassTreeMask::reset()
361    {
362        delete this->root_;
363        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
364    }
365
366    /**
367        @brief Tells if a given subclass is included or not.
368        @param subclass The subclass
369        @return Included (true) or excluded (false)
370    */
371    bool ClassTreeMask::isIncluded(const Identifier* subclass) const
372    {
373        return this->isIncluded(this->root_, subclass);
374    }
375
376    /**
377        @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function).
378        @param node The node
379        @param subclass The subclass
380        @return Included (true) or excluded (false)
381    */
382    bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const
383    {
384        // Check if the searched subclass is of the same type as the class in the current node or a derivative
385        if (subclass->isA(node->getClass()))
386        {
387            // Check for the special case
388            if (subclass == node->getClass())
389                return node->isIncluded();
390
391            // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call.
392            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
393                if (subclass->isA((*it)->getClass()))
394                    return isIncluded(*it, subclass);
395
396            // There is no subnode containing our class -> the rule of the current node takes in effect
397            return node->isIncluded();
398        }
399        else
400        {
401            // The class is not included in the mask: return false
402            return false;
403        }
404    }
405
406    /**
407        @brief Tells if a given subclass is excluded or not.
408        @param subclass The subclass
409        @return The inverted rule: Excluded (true) or included (false)
410    */
411    bool ClassTreeMask::isExcluded(const Identifier* subclass) const
412    {
413        return (!this->isIncluded(subclass));
414    }
415
416    /**
417        @brief Removes all unneeded rules that don't change the information of the mask.
418    */
419    void ClassTreeMask::clean()
420    {
421        this->clean(this->root_);
422    }
423
424    /**
425        @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function).
426        @param node The node
427    */
428    void ClassTreeMask::clean(ClassTreeMaskNode* node)
429    {
430        // Iterate through all subnodes of the given node
431        for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
432        {
433            // Recursive function-call: Clean the subnode
434            this->clean(*it);
435
436            // Now check if the subnode contains the same rule as the current node
437            if ((*it)->isIncluded() == node->isIncluded())
438            {
439                // It does: Move all subnodes of the redundant subnode to the current node
440                node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end());
441                (*it)->subnodes_.clear();
442
443                // Remove the redundant subnode from the current node
444                node->subnodes_.erase(it++);
445            }
446            else
447            {
448                // The subnode is necessary: Move on to the next subnode
449                ++it;
450            }
451        }
452    }
453
454    /**
455        @brief Assignment operator: Adds all rules of the other mask.
456        @param other The other mask
457        @return A reference to the mask itself
458    */
459    ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other)
460    {
461        // Make a copy to avoid troubles with self-assignments (like A = A).
462        ClassTreeMask temp(other);
463
464        // Removes all current rules
465        this->reset();
466
467        // Copy all rules from the other mask
468        for (ClassTreeMaskIterator it = temp.root_; it; ++it)
469            this->add(it->getClass(), it->isIncluded());
470
471        // Return a reference to the mask itself
472        return (*this);
473    }
474
475    /**
476        @brief Prefix operator + does nothing.
477        @return A reference to the mask itself
478    */
479    ClassTreeMask& ClassTreeMask::operator+()
480    {
481        return (*this);
482    }
483
484    /**
485        @brief Prefix operator - inverts the mask.
486        @return The inverted mask
487    */
488    ClassTreeMask ClassTreeMask::operator-() const
489    {
490        return (!(*this));
491    }
492
493    /**
494        @brief Adds two masks in the sense of a union (all classes that are included in at least one of the masks will be included in the resulting mask too).
495        @param other The mask to unite with
496        @return The union
497    */
498    ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const
499    {
500        // Create a new mask
501        ClassTreeMask newmask;
502
503        // Add all nodes from the first mask, calculate the rule with the or-operation
504        for (ClassTreeMaskIterator it = this->root_; it; ++it)
505        {
506            const Identifier* subclass = it->getClass();
507            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass));
508        }
509
510        // Add all nodes from the second mask, calculate the rule with the or-operation
511        for (ClassTreeMaskIterator it = other.root_; it; ++it)
512        {
513            const Identifier* subclass = it->getClass();
514            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass));
515        }
516
517        // Drop all redundant rules
518        newmask.clean();
519
520        // Return the new mask
521        return newmask;
522    }
523
524    /**
525        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
526        @param other The mask to intersect with
527        @return The intersection
528    */
529    ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const
530    {
531        // Create a new mask
532        ClassTreeMask newmask;
533
534        // Add all nodes from the first mask, calculate the rule with the and-operation
535        for (ClassTreeMaskIterator it = this->root_; it; ++it)
536        {
537            const Identifier* subclass = it->getClass();
538            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass));
539        }
540
541        // Add all nodes from the second mask, calculate the rule with the and-operation
542        for (ClassTreeMaskIterator it = other.root_; it; ++it)
543        {
544            const Identifier* subclass = it->getClass();
545            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass));
546        }
547
548        // Drop all redundant rules
549        newmask.clean();
550
551        // Return the new mask
552        return newmask;
553    }
554
555    /**
556        @brief Removes all elements of the second mask from the first mask (all classes that are included in the first mask stay included, except those that are included in the second mask too).
557        @param other The mask to subtract.
558        @return The difference
559    */
560    ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const
561    {
562        return ((*this) * (!other));
563    }
564
565    /**
566        @brief Inverts the mask (all included classes are now excluded and vice versa).
567        @return The complement
568    */
569    ClassTreeMask ClassTreeMask::operator!() const
570    {
571        // Create a new mask
572        ClassTreeMask newmask;
573
574        // Add all nodes from the other mask, inverting the rules
575        for (ClassTreeMaskIterator it = this->root_; it; ++it)
576        {
577            const Identifier* subclass = it->getClass();
578            newmask.add(subclass, !this->isIncluded(subclass));
579        }
580
581        // Return the new mask
582        return newmask;
583    }
584
585    /**
586        @brief Unites this mask with another mask.
587        @param other The other mask
588        @return A reference to the mask itself
589    */
590    ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other)
591    {
592        (*this) = (*this) + other;
593        return (*this);
594    }
595
596    /**
597        @brief Intersects this mask with another mask.
598        @param other The other mask
599        @return A reference to the mask itself
600    */
601    ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other)
602    {
603        (*this) = (*this) * other;
604        return (*this);
605    }
606
607    /**
608        @brief Subtracts another mask from this mask.
609        @param other The other mask
610        @return A reference to the mask itself
611    */
612    ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other)
613    {
614        (*this) = (*this) - other;
615        return (*this);
616    }
617
618    /**
619        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
620        @param other The mask to intersect with
621        @return The intersection
622    */
623    ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const
624    {
625        return ((*this) * other);
626    }
627
628    /**
629        @brief Adds two masks in the sense of a union (all classes that are included in at least one of the masks will be included in the resulting mask too).
630        @param other The mask to unite with
631        @return The union
632    */
633    ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const
634    {
635        return ((*this) + other);
636    }
637
638    /**
639        @brief Joins two masks in the sense of a xor (exclusivity) operation (all classes that are included in exactly one of the masks, but not in both, will be included in the resulting mask too).
640        @param other The mask to join with
641        @return The result
642    */
643    ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const
644    {
645        // Create a new mask
646        ClassTreeMask newmask;
647
648        // Add all nodes from the first mask, calculate the rule with the xor-operation
649        for (ClassTreeMaskIterator it = this->root_; it; ++it)
650        {
651            const Identifier* subclass = it->getClass();
652            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass));
653        }
654
655        // Add all nodes from the second mask, calculate the rule with the xor-operation
656        for (ClassTreeMaskIterator it = other.root_; it; ++it)
657        {
658            const Identifier* subclass = it->getClass();
659            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass));
660        }
661
662        // Drop all redundant rules
663        newmask.clean();
664
665        // Return the new mask
666        return newmask;
667    }
668
669    /**
670        @brief Inverts the mask (all included classes are now excluded and vice versa).
671        @return The complement
672    */
673    ClassTreeMask ClassTreeMask::operator~() const
674    {
675        return (!(*this));
676    }
677
678    /**
679        @brief Intersects this mask with another mask (and-operation)
680        @param other The other mask
681        @return A reference to the mask itself
682    */
683    ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other)
684    {
685        (*this) = (*this) & other;
686        return (*this);
687    }
688
689    /**
690        @brief Unites this mask with another mask (or-operation).
691        @param other The other mask
692        @return A reference to the mask itself
693    */
694    ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other)
695    {
696        (*this) = (*this) | other;
697        return (*this);
698    }
699
700    /**
701        @brief Joins this mask with another mask with a xor-operation.
702        @param other The other mask
703        @return A reference to the mask itself
704    */
705    ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other)
706    {
707        (*this) = (*this) ^ other;
708        return (*this);
709    }
710
711    /**
712        @brief Converts the content of a mask into a human readable string and puts it on the ostream.
713        @param out The ostream
714        @param mask The mask
715        @return A reference to the ostream
716    */
717    std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask)
718    {
719        // Iterate through all rules
720        for (ClassTreeMaskIterator it = mask.root_; it; ++it)
721        {
722            // Calculate the prefix: + means included, - means excluded
723            if (it->isIncluded())
724                out << "+";
725            else
726                out << "-";
727
728            // Put the name of the corresponding class on the stream
729            out << it->getClass()->getName() << " ";
730        }
731
732        return out;
733    }
734}
Note: See TracBrowser for help on using the repository browser.