Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/ClassTreeMask.cc @ 6763

Last change on this file since 6763 was 6417, checked in by rgrieder, 15 years ago

Merged presentation2 branch back to trunk.
Major new features:

  • Actual GUI with settings, etc.
  • Improved space ship steering (human interaction)
  • Rocket fire and more particle effects
  • Advanced sound framework
  • Property svn:eol-style set to native
File size: 35.0 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 ClassTreeMask, ClassTreeMaskNode and ClassTreeMaskIterator classes.
32*/
33
34#include "ClassTreeMask.h"
35#include "Identifier.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        this->deleteAllSubnodes();
60    }
61
62    /**
63        @brief Sets the rule for the node to "included".
64        @param overwrite True = overwrite previously added rules for inheriting classes
65    */
66    void ClassTreeMaskNode::include(bool overwrite)
67    {
68        this->setIncluded(true, overwrite);
69    }
70
71    /**
72        @brief Sets the rule for the node to "excluded".
73        @param overwrite True = overwrite previously added rules for inheriting classes
74    */
75    void ClassTreeMaskNode::exclude(bool overwrite)
76    {
77        this->setIncluded(false, overwrite);
78    }
79
80    /**
81        @brief Sets the rule for the node to a given value and erases all following rules.
82        @param bIncluded The rule: included (true) or excluded (false)
83        @param overwrite True = overwrite previously added rules for inheriting classes
84    */
85    void ClassTreeMaskNode::setIncluded(bool bIncluded, bool overwrite)
86    {
87        if (overwrite)
88            this->deleteAllSubnodes();
89
90        this->bIncluded_ = bIncluded;
91    }
92
93    /**
94        @brief Adds a new subnode to the list of subnodes.
95        @param subnode The new subnode
96    */
97    void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode)
98    {
99        this->subnodes_.insert(this->subnodes_.end(), subnode);
100    }
101
102    /**
103        @brief Deletes all subnodes of this node.
104    */
105    void ClassTreeMaskNode::deleteAllSubnodes()
106    {
107        // Go through the list of all subnodes and delete them
108        for (std::list<ClassTreeMaskNode*>::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); )
109            delete (*(it++));
110
111        // Clear the list
112        this->subnodes_.clear();
113    }
114
115
116    // ###############################
117    // ###  ClassTreeMaskIterator  ###
118    // ###############################
119    /**
120        @brief Constructor: Initializes the iterator by creating a helper-list with the root-node and putting it to the stack.
121        @param node The root-node
122    */
123    ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node)
124    {
125        // Create a list and put the root-note into it
126        std::list<ClassTreeMaskNode*>::iterator it = this->rootlist_.insert(this->rootlist_.end(), node);
127
128        // Put the iterator to the only element of the list and the corresponding end()-iterator on the stack
129        this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>(it, this->rootlist_.end()));
130    }
131
132    /**
133        @brief Destructor: Does nothing.
134    */
135    ClassTreeMaskIterator::~ClassTreeMaskIterator()
136    {
137    }
138
139    /**
140        @brief Iterates through the rule-tree.
141        @return A reference to the iterator itself
142    */
143    const ClassTreeMaskIterator& ClassTreeMaskIterator::operator++()
144    {
145        // Check if the actual node has subnodes
146        if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end())
147        {
148            // Yes it has: Push an iterator, pointing at the first subnode, on the stack
149            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()));
150        }
151        else
152        {
153            // No subnodes, meaning we reached a leaf: Go to the next node
154            do
155            {
156                // Iterate one step in the current list
157                ++this->nodes_.top().first;
158
159                // Check if we reached the end of the list (the second item in the stored pair always represents the end)
160                if (this->nodes_.top().first == this->nodes_.top().second)
161                {
162                    // Yes we've reached the end: Pop the list-iterator from the stack
163                    this->nodes_.pop();
164
165                    // Continue with the loop, meaning: Try to iterate through the previous list
166                    continue;
167                }
168
169                // If we reached this point, we aren't yet at the end of the list: Leave the loop
170                break;
171            } while (!this->nodes_.empty()); // Stop looping if the stack is empty, meaning: We've iterated to the end
172        }
173
174        // Finally return a reference to the iterator itself
175        return *this;
176    }
177
178    /**
179        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
180        @return The pointer to the node
181    */
182    ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const
183    {
184        return (*this->nodes_.top().first);
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 true if the stack is empty, meaning we've reached the end of the tree.
198        @return True if we've reached the end of the tree
199    */
200    ClassTreeMaskIterator::operator bool() const
201    {
202        return (!this->nodes_.empty());
203    }
204
205    /**
206        @brief Compares the current node with the given one and returns true if they match.
207        @param compare The node to compare with
208        @return The result of the comparison (true if they match)
209    */
210    bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare) const
211    {
212        if (!this->nodes_.empty())
213            return ((*this->nodes_.top().first) == compare);
214        else
215            return (compare == 0);
216    }
217
218    /**
219        @brief Compares the current node with the given one and returns true if they don't match.
220        @param compare The node to compare with
221        @return The result of the comparison (true if they don't match)
222    */
223    bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare) const
224    {
225        if (!this->nodes_.empty())
226            return ((*this->nodes_.top().first) != compare);
227        else
228            return (compare != 0);
229    }
230
231
232    // ###############################
233    // ###      ClassTreeMask      ###
234    // ###############################
235    /**
236        @brief Constructor: Adds the root-node of the tree with the first rule ("include everything").
237    */
238    ClassTreeMask::ClassTreeMask()
239    {
240        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
241    }
242
243    /**
244        @brief Copyconstructor: Adds the root-node of the tree with the first rule ("include everything") and adds all rules from the other mask.
245        @param other The other mask
246    */
247    ClassTreeMask::ClassTreeMask(const ClassTreeMask& other)
248    {
249        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
250        for (ClassTreeMaskIterator it = other.root_; it; ++it)
251            this->add(it->getClass(), it->isIncluded(), false);
252    }
253
254    /**
255        @brief Destructor: Deletes the root node (which will delete all subnodes too).
256    */
257    ClassTreeMask::~ClassTreeMask()
258    {
259        delete this->root_;
260    }
261
262    /**
263        @brief Adds a new "include" rule for a given subclass to the mask.
264        @param subclass The subclass
265        @param overwrite True = overwrite previously added rules for inheriting classes
266        @param clean True = clean the tree after adding the new rule
267    */
268    void ClassTreeMask::include(const Identifier* subclass, bool overwrite, bool clean)
269    {
270        this->add(subclass, true, overwrite, clean);
271    }
272
273    /**
274        @brief Adds a new "exclude" rule for a given subclass to the mask.
275        @param subclass The subclass
276        @param overwrite True = overwrite previously added rules for inheriting classes
277        @param clean True = clean the tree after adding the new rule
278    */
279    void ClassTreeMask::exclude(const Identifier* subclass, bool overwrite, bool clean)
280    {
281        this->add(subclass, false, overwrite, clean);
282    }
283
284    /**
285        @brief Adds a new rule for a given subclass to the mask.
286        @param subclass The subclass
287        @param bInclude The rule: include (true) or exclude (false)
288        @param overwrite True = overwrite previously added rules for inheriting classes
289        @param clean True = clean the tree after adding the new rule
290    */
291    void ClassTreeMask::add(const Identifier* subclass, bool bInclude, bool overwrite, bool clean)
292    {
293        if (!subclass)
294            return;
295        // Check if the given subclass is a child of our root-class
296        if (subclass->isA(this->root_->getClass()))
297        {
298            // Yes it is: Just add the rule to the three
299            this->add(this->root_, subclass, bInclude, overwrite);
300        }
301        else
302        {
303            // No it's not: Search for classes inheriting from the given class and add the rules for them
304            for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
305                if ((*it)->isA(this->root_->getClass()))
306                    if (overwrite || (!this->nodeExists(*it))) // If we don't want to overwrite, only add nodes that don't already exist
307                        this->add(this->root_, *it, bInclude, overwrite);
308        }
309
310        // Clean the rule-tree
311        if (clean)
312            this->clean();
313    }
314
315    /**
316        @brief Adds a new rule for a given subclass to a node of the internal rule-tree (recursive function).
317        @param node The node
318        @param subclass The subclass
319        @param bInclude The rule: include (true) or exclude (false)
320        @param overwrite True = overwrite previously added rules for inheriting classes
321    */
322    void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude, bool overwrite)
323    {
324        if (!subclass)
325            return;
326        // Check if the current node contains exactly the subclass we want to add
327        if (subclass == node->getClass())
328        {
329            // We're at the right place, just change the mask and return
330            node->setIncluded(bInclude, overwrite);
331            return;
332        }
333        else if (subclass->isA(node->getClass()))
334        {
335            // Search for an already existing node, containing the subclass we want to add
336            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
337            {
338                if (subclass->isA((*it)->getClass()))
339                {
340                    // We've found an existing node -> delegate the work with a recursive function-call and return
341                    this->add(*it, subclass, bInclude, overwrite);
342                    return;
343                }
344            }
345
346            // There is no existing node satisfying our needs -> we create a new node
347            ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude);
348
349            // Search for nodes that should actually be subnodes of our new node and erase them
350            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
351            {
352                if ((*it)->getClass()->isChildOf(subclass))
353                {
354                    // We've found a subnode: add it to the new node and erase it from the current node
355                    if (!overwrite)
356                        newnode->addSubnode(*it);
357                    else
358                        delete (*it);
359
360                    node->subnodes_.erase(it++);
361                }
362                else
363                {
364                    ++it;
365                }
366            }
367
368            // Finally add the new node as a subnode to the current node
369            node->addSubnode(newnode);
370        }
371    }
372
373    /**
374        @brief Adds a new "include" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
375        @param subclass The subclass
376        @param clean True = clean the tree after adding the new rule
377    */
378    void ClassTreeMask::includeSingle(const Identifier* subclass, bool clean)
379    {
380        this->addSingle(subclass, true, clean);
381    }
382
383    /**
384        @brief Adds a new "exclude" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
385        @param subclass The subclass
386        @param clean True = clean the tree after adding the new rule
387    */
388    void ClassTreeMask::excludeSingle(const Identifier* subclass, bool clean)
389    {
390        this->addSingle(subclass, false, clean);
391    }
392
393    /**
394        @brief Adds a new rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
395        @param bInclude The rule: include (true) or exclude (false)
396        @param subclass The subclass
397        @param clean True = clean the tree after adding the new rule
398    */
399    void ClassTreeMask::addSingle(const Identifier* subclass, bool bInclude, bool clean)
400    {
401        if (!subclass)
402            return;
403        for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
404            this->add(*it, this->isIncluded(*it), false, false);
405
406        this->add(subclass, bInclude, false, clean);
407    }
408
409    /**
410        @brief Resets the mask to "include everything".
411    */
412    void ClassTreeMask::reset()
413    {
414        delete this->root_;
415        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
416    }
417
418    /**
419        @brief Tells if a given subclass is included or not.
420        @param subclass The subclass
421        @return Included (true) or excluded (false)
422    */
423    bool ClassTreeMask::isIncluded(const Identifier* subclass) const
424    {
425        return this->isIncluded(this->root_, subclass);
426    }
427
428    /**
429        @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function).
430        @param node The node
431        @param subclass The subclass
432        @return Included (true) or excluded (false)
433    */
434    bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const
435    {
436        if (!subclass)
437            return false;
438        // Check if the searched subclass is of the same type as the class in the current node or a derivative
439        if (subclass->isA(node->getClass()))
440        {
441            // Check for the special case
442            if (subclass == node->getClass())
443                return node->isIncluded();
444
445            // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call.
446            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
447                if (subclass->isA((*it)->getClass()))
448                    return isIncluded(*it, subclass);
449
450            // There is no subnode containing our class -> the rule of the current node takes in effect
451            return node->isIncluded();
452        }
453        else
454        {
455            // The class is not included in the mask: return false
456            return false;
457        }
458    }
459
460    /**
461        @brief Tells if a given subclass is excluded or not.
462        @param subclass The subclass
463        @return The inverted rule: Excluded (true) or included (false)
464    */
465    bool ClassTreeMask::isExcluded(const Identifier* subclass) const
466    {
467        return (!this->isIncluded(subclass));
468    }
469
470    /**
471        @brief Removes all unneeded rules that don't change the information of the mask.
472    */
473    void ClassTreeMask::clean()
474    {
475        this->clean(this->root_);
476    }
477
478    /**
479        @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function).
480        @param node The node
481    */
482    void ClassTreeMask::clean(ClassTreeMaskNode* node)
483    {
484        // Iterate through all subnodes of the given node
485        for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
486        {
487            // Recursive function-call: Clean the subnode
488            this->clean(*it);
489
490            // Now check if the subnode contains the same rule as the current node
491            if ((*it)->isIncluded() == node->isIncluded())
492            {
493                // It does: Move all subnodes of the redundant subnode to the current node
494                node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end());
495                (*it)->subnodes_.clear();
496
497                // Remove the redundant subnode from the current node
498                delete (*it);
499                node->subnodes_.erase(it++);
500            }
501            else
502            {
503                // The subnode is necessary: Move on to the next subnode
504                ++it;
505            }
506        }
507    }
508
509    /**
510        @brief Checks if a node for the given subclass exists.
511        @param subclass The Identifier of the subclass
512        @return True = the node exists
513    */
514    bool ClassTreeMask::nodeExists(const Identifier* subclass)
515    {
516        for (ClassTreeMaskIterator it = this->root_; it; ++it)
517            if ((*it)->getClass() == subclass)
518                return true;
519
520        return false;
521    }
522
523    /**
524        @brief Assignment operator: Adds all rules of the other mask.
525        @param other The other mask
526        @return A reference to the mask itself
527    */
528    const ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other)
529    {
530        // Make a copy to avoid troubles with self-assignments (like A = A).
531        ClassTreeMask temp(other);
532
533        // Removes all current rules
534        this->reset();
535
536        // Copy all rules from the other mask
537        for (ClassTreeMaskIterator it = temp.root_; it; ++it)
538            this->add(it->getClass(), it->isIncluded(), false, false);
539
540        // Return a reference to the mask itself
541        return (*this);
542    }
543
544    /**
545        @brief Compares the mask with another mask and returns true if they represent the same logic.
546        @param other The other mask
547        @return True if both masks represent the same logic
548    */
549    bool ClassTreeMask::operator==(const ClassTreeMask& other) const
550    {
551        ClassTreeMask temp1 = other;
552        ClassTreeMask temp2 = (*this);
553
554        temp1.clean();
555        temp2.clean();
556
557        ClassTreeMaskIterator it1 = temp1.root_;
558        ClassTreeMaskIterator it2 = temp2.root_;
559
560        for ( ; it1 && it2; ++it1, ++it2)
561            if (it1->getClass() != it2->getClass())
562                return false;
563
564        return true;
565    }
566
567    /**
568        @brief Compares the mask with another mask and returns true if they represent different logics.
569        @param other The other mask
570        @return True if the masks represent different logics
571    */
572    bool ClassTreeMask::operator!=(const ClassTreeMask& other) const
573    {
574        return (!((*this) == other));
575    }
576
577    /**
578        @brief Prefix operator + does nothing.
579        @return A reference to the mask itself
580    */
581    const ClassTreeMask& ClassTreeMask::operator+() const
582    {
583        return (*this);
584    }
585
586    /**
587        @brief Prefix operator - inverts the mask.
588        @return The inverted mask
589    */
590    ClassTreeMask ClassTreeMask::operator-() const
591    {
592        return (!(*this));
593    }
594
595    /**
596        @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).
597        @param other The mask to unite with
598        @return The union
599    */
600    ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const
601    {
602        // Create a new mask
603        ClassTreeMask newmask;
604
605        // Add all nodes from the first mask, calculate the rule with the or-operation
606        for (ClassTreeMaskIterator it = this->root_; it; ++it)
607        {
608            const Identifier* subclass = it->getClass();
609            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
610        }
611
612        // Add all nodes from the second mask, calculate the rule with the or-operation
613        for (ClassTreeMaskIterator it = other.root_; it; ++it)
614        {
615            const Identifier* subclass = it->getClass();
616            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
617        }
618
619        // Drop all redundant rules
620        newmask.clean();
621
622        // Return the new mask
623        return newmask;
624    }
625
626    /**
627        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
628        @param other The mask to intersect with
629        @return The intersection
630    */
631    ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const
632    {
633        // Create a new mask
634        ClassTreeMask newmask;
635
636        // Add all nodes from the first mask, calculate the rule with the and-operation
637        for (ClassTreeMaskIterator it = this->root_; it; ++it)
638        {
639            const Identifier* subclass = it->getClass();
640            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
641        }
642
643        // Add all nodes from the second mask, calculate the rule with the and-operation
644        for (ClassTreeMaskIterator it = other.root_; it; ++it)
645        {
646            const Identifier* subclass = it->getClass();
647            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
648        }
649
650        // Drop all redundant rules
651        newmask.clean();
652
653        // Return the new mask
654        return newmask;
655    }
656
657    /**
658        @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).
659        @param other The mask to subtract.
660        @return The difference
661    */
662    ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const
663    {
664        return ((*this) * (!other));
665    }
666
667    /**
668        @brief Inverts the mask (all included classes are now excluded and vice versa).
669        @return The complement
670    */
671    ClassTreeMask ClassTreeMask::operator!() const
672    {
673        // Create a new mask
674        ClassTreeMask newmask;
675
676        // Add all nodes from the other mask, inverting the rules
677        for (ClassTreeMaskIterator it = this->root_; it; ++it)
678        {
679            const Identifier* subclass = it->getClass();
680            newmask.add(subclass, !this->isIncluded(subclass), false, false);
681        }
682
683        // Return the new mask
684        return newmask;
685    }
686
687    /**
688        @brief Unites this mask with another mask.
689        @param other The other mask
690        @return A reference to the mask itself
691    */
692    const ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other)
693    {
694        (*this) = (*this) + other;
695        return (*this);
696    }
697
698    /**
699        @brief Intersects this mask with another mask.
700        @param other The other mask
701        @return A reference to the mask itself
702    */
703    const ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other)
704    {
705        (*this) = (*this) * other;
706        return (*this);
707    }
708
709    /**
710        @brief Subtracts another mask from this mask.
711        @param other The other mask
712        @return A reference to the mask itself
713    */
714    const ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other)
715    {
716        (*this) = (*this) - other;
717        return (*this);
718    }
719
720    /**
721        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
722        @param other The mask to intersect with
723        @return The intersection
724    */
725    ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const
726    {
727        return ((*this) * other);
728    }
729
730    /**
731        @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).
732        @param other The mask to unite with
733        @return The union
734    */
735    ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const
736    {
737        return ((*this) + other);
738    }
739
740    /**
741        @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).
742        @param other The mask to join with
743        @return The result
744    */
745    ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const
746    {
747        // Create a new mask
748        ClassTreeMask newmask;
749
750        // Add all nodes from the first mask, calculate the rule with the xor-operation
751        for (ClassTreeMaskIterator it = this->root_; it; ++it)
752        {
753            const Identifier* subclass = it->getClass();
754            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
755        }
756
757        // Add all nodes from the second mask, calculate the rule with the xor-operation
758        for (ClassTreeMaskIterator it = other.root_; it; ++it)
759        {
760            const Identifier* subclass = it->getClass();
761            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
762        }
763
764        // Drop all redundant rules
765        newmask.clean();
766
767        // Return the new mask
768        return newmask;
769    }
770
771    /**
772        @brief Inverts the mask (all included classes are now excluded and vice versa).
773        @return The complement
774    */
775    ClassTreeMask ClassTreeMask::operator~() const
776    {
777        return (!(*this));
778    }
779
780    /**
781        @brief Intersects this mask with another mask (and-operation)
782        @param other The other mask
783        @return A reference to the mask itself
784    */
785    const ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other)
786    {
787        (*this) = (*this) & other;
788        return (*this);
789    }
790
791    /**
792        @brief Unites this mask with another mask (or-operation).
793        @param other The other mask
794        @return A reference to the mask itself
795    */
796    const ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other)
797    {
798        (*this) = (*this) | other;
799        return (*this);
800    }
801
802    /**
803        @brief Joins this mask with another mask with a xor-operation.
804        @param other The other mask
805        @return A reference to the mask itself
806    */
807    const ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other)
808    {
809        (*this) = (*this) ^ other;
810        return (*this);
811    }
812
813    /**
814        @brief Converts the content of a mask into a human readable string and puts it on the ostream.
815        @param out The ostream
816        @param mask The mask
817        @return A reference to the ostream
818    */
819    std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask)
820    {
821        // Iterate through all rules
822        for (ClassTreeMaskIterator it = mask.root_; it; ++it)
823        {
824            // Calculate the prefix: + means included, - means excluded
825            if (it->isIncluded())
826                out << '+';
827            else
828                out << '-';
829
830            // Put the name of the corresponding class on the stream
831            out << it->getClass()->getName() << ' ';
832        }
833
834        return out;
835    }
836
837
838    // ###################################
839    // ### ClassTreeMaskObjectIterator ###
840    // ###################################
841    /**
842        @brief Initializes the iterator from a given ClassTreeMask.
843        @param mask The mask
844    */
845    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator=(const ClassTreeMask& mask)
846    {
847        // Clear everything, use a cleaned copy of the mask
848        this->subclasses_.clear();
849        ClassTreeMask temp = mask;
850        temp.clean();
851
852        // Create the subclass-list by going through the mask-tree, starting with the root-node
853        this->create(temp.root_);
854
855        // Move the subclass-iterator to the beginning of the subclass-list
856        this->subclassIterator_ = this->subclasses_.begin();
857
858        // If there is a first subclass, move the object-iterator to the first object of this class. Else go to the end
859        if (this->subclassIterator_ != this->subclasses_.end())
860            this->objectIterator_ = this->subclassIterator_->first->getObjects()->begin();
861        else
862            this->objectIterator_ = ObjectList<BaseObject>::end();
863
864        // Check if the iterator points on a valid object. If not, go to the next object by calling ++
865        if (!this->objectIterator_ || (this->subclassIterator_->second && !this->objectIterator_->isExactlyA(this->subclassIterator_->first)))
866            this->operator++();
867
868        return (*this);
869    }
870
871    /**
872        @brief Iterate to the next object (if any).
873        @return The iterator itself
874    */
875    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator++()
876    {
877        if (this->objectIterator_)
878        {
879            // The iterator points on a valid object, therefore we also have a valid subclass-iterator at the moment
880            do
881            {
882                // Go to the next object
883                ++this->objectIterator_;
884
885                while (!this->objectIterator_)
886                {
887                    // We reached the end of the current objectlist - go to the next class
888                    ++this->subclassIterator_;
889
890                    // Check if there really is a next class. If yes, move the object-iterator to the first object
891                    if (this->subclassIterator_ != this->subclasses_.end())
892                        this->objectIterator_ = this->subclassIterator_->first->getObjects()->begin();
893                    else
894                        return (*this);
895                }
896
897            // Repeat this until we reach a valid object or the end
898            } while (this->subclassIterator_->second && !this->objectIterator_->isExactlyA(this->subclassIterator_->first));
899        }
900        return (*this);
901    }
902
903    /**
904        @brief Recursive function to create the Iterators subclass-list by going through the node-tree of the mask.
905        @param node The current node
906    */
907    void ClassTreeMaskObjectIterator::create(ClassTreeMaskNode* node)
908    {
909        // Add the class of this node to the list, if the class is included
910        if (node->isIncluded())
911        {
912            // If there are some subnodes, the bool is "true", meaning we have to check for the exact clss when iterating
913            if (node->hasSubnodes())
914                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), true));
915            else
916                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), false));
917        }
918
919        // Now check if the node has subnodes
920        if (node->hasSubnodes())
921        {
922            // Get all _direct_ children of the nodes class
923            std::set<const Identifier*> directChildren = node->getClass()->getDirectChildren();
924
925            // Iterate through all subnodes
926            for (std::list<ClassTreeMaskNode*>::iterator it1 = node->subnodes_.begin(); it1 != node->subnodes_.end(); ++it1)
927            {
928                // Recursive call to this function with the subnode
929                this->create(*it1);
930
931                // Only execute the following code if the current node is included, meaning some of the subnodes might be included too
932                if (node->isIncluded())
933                {
934                    scanChildren: // This is a label for goto
935
936                    // Iterate through all direct children
937                    for (std::set<const Identifier*>::iterator it2 = directChildren.begin(); it2 != directChildren.end(); ++it2)
938                    {
939                        // Check if the subnode (it1) is a child of the directChild (it2)
940                        if ((*it1)->getClass()->isA(*it2))
941                        {
942                            // Yes it is - remove the directChild (it2) from the list, because it will already be handled by a recursive call to the create() function
943                            directChildren.erase(it2);
944
945                            // Check if the removed directChild was exactly the subnode
946                            if (!(*it1)->getClass()->isExactlyA(*it2))
947                            {
948                                // No, it wasn't exactly the subnode - therefore there are some classes between
949
950                                // Add the previously removed directChild (it2) to the subclass-list
951                                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it2, true));
952
953                                // Insert all directChildren of the directChild
954                                directChildren.insert((*it2)->getDirectChildrenBegin(), (*it2)->getDirectChildrenEnd());
955
956                                // Restart the scan with the expanded set of directChildren
957                                goto scanChildren;
958                            }
959                            break;
960                        }
961                    }
962                }
963            }
964
965            // Now add all directChildren which don't have subnodes on their own to the subclass-list
966            // The bool is "false", meaning they have no subnodes and therefore need no further checks
967            if (node->isIncluded())
968                for (std::set<const Identifier*>::iterator it = directChildren.begin(); it != directChildren.end(); ++it)
969                    this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it, false));
970        }
971    }
972}
Note: See TracBrowser for help on using the repository browser.