Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/ClassTreeMask.cc @ 3731

Last change on this file since 3731 was 3196, checked in by rgrieder, 15 years ago

Merged pch branch back to trunk.

  • Property svn:eol-style set to native
File size: 34.8 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        // Check if the given subclass is a child of our root-class
294        if (subclass->isA(this->root_->getClass()))
295        {
296            // Yes it is: Just add the rule to the three
297            this->add(this->root_, subclass, bInclude, overwrite);
298        }
299        else
300        {
301            // No it's not: Search for classes inheriting from the given class and add the rules for them
302            for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
303                if ((*it)->isA(this->root_->getClass()))
304                    if (overwrite || (!this->nodeExists(*it))) // If we don't want to overwrite, only add nodes that don't already exist
305                        this->add(this->root_, *it, bInclude, overwrite);
306        }
307
308        // Clean the rule-tree
309        if (clean)
310            this->clean();
311    }
312
313    /**
314        @brief Adds a new rule for a given subclass to a node of the internal rule-tree (recursive function).
315        @param node The node
316        @param subclass The subclass
317        @param bInclude The rule: include (true) or exclude (false)
318        @param overwrite True = overwrite previously added rules for inheriting classes
319    */
320    void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude, bool overwrite)
321    {
322        // Check if the current node contains exactly the subclass we want to add
323        if (subclass == node->getClass())
324        {
325            // We're at the right place, just change the mask and return
326            node->setIncluded(bInclude, overwrite);
327            return;
328        }
329        else if (subclass->isA(node->getClass()))
330        {
331            // Search for an already existing node, containing the subclass we want to add
332            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
333            {
334                if (subclass->isA((*it)->getClass()))
335                {
336                    // We've found an existing node -> delegate the work with a recursive function-call and return
337                    this->add(*it, subclass, bInclude, overwrite);
338                    return;
339                }
340            }
341
342            // There is no existing node satisfying our needs -> we create a new node
343            ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude);
344
345            // Search for nodes that should actually be subnodes of our new node and erase them
346            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
347            {
348                if ((*it)->getClass()->isChildOf(subclass))
349                {
350                    // We've found a subnode: add it to the new node and erase it from the current node
351                    if (!overwrite)
352                        newnode->addSubnode(*it);
353                    else
354                        delete (*it);
355
356                    node->subnodes_.erase(it++);
357                }
358                else
359                {
360                    ++it;
361                }
362            }
363
364            // Finally add the new node as a subnode to the current node
365            node->addSubnode(newnode);
366        }
367    }
368
369    /**
370        @brief Adds a new "include" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
371        @param subclass The subclass
372        @param clean True = clean the tree after adding the new rule
373    */
374    void ClassTreeMask::includeSingle(const Identifier* subclass, bool clean)
375    {
376        this->addSingle(subclass, true, clean);
377    }
378
379    /**
380        @brief Adds a new "exclude" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
381        @param subclass The subclass
382        @param clean True = clean the tree after adding the new rule
383    */
384    void ClassTreeMask::excludeSingle(const Identifier* subclass, bool clean)
385    {
386        this->addSingle(subclass, false, clean);
387    }
388
389    /**
390        @brief Adds a new rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
391        @param bInclude The rule: include (true) or exclude (false)
392        @param subclass The subclass
393        @param clean True = clean the tree after adding the new rule
394    */
395    void ClassTreeMask::addSingle(const Identifier* subclass, bool bInclude, bool clean)
396    {
397        for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
398            this->add(*it, this->isIncluded(*it), false, false);
399
400        this->add(subclass, bInclude, false, clean);
401    }
402
403    /**
404        @brief Resets the mask to "include everything".
405    */
406    void ClassTreeMask::reset()
407    {
408        delete this->root_;
409        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
410    }
411
412    /**
413        @brief Tells if a given subclass is included or not.
414        @param subclass The subclass
415        @return Included (true) or excluded (false)
416    */
417    bool ClassTreeMask::isIncluded(const Identifier* subclass) const
418    {
419        return this->isIncluded(this->root_, subclass);
420    }
421
422    /**
423        @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function).
424        @param node The node
425        @param subclass The subclass
426        @return Included (true) or excluded (false)
427    */
428    bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const
429    {
430        // Check if the searched subclass is of the same type as the class in the current node or a derivative
431        if (subclass->isA(node->getClass()))
432        {
433            // Check for the special case
434            if (subclass == node->getClass())
435                return node->isIncluded();
436
437            // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call.
438            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
439                if (subclass->isA((*it)->getClass()))
440                    return isIncluded(*it, subclass);
441
442            // There is no subnode containing our class -> the rule of the current node takes in effect
443            return node->isIncluded();
444        }
445        else
446        {
447            // The class is not included in the mask: return false
448            return false;
449        }
450    }
451
452    /**
453        @brief Tells if a given subclass is excluded or not.
454        @param subclass The subclass
455        @return The inverted rule: Excluded (true) or included (false)
456    */
457    bool ClassTreeMask::isExcluded(const Identifier* subclass) const
458    {
459        return (!this->isIncluded(subclass));
460    }
461
462    /**
463        @brief Removes all unneeded rules that don't change the information of the mask.
464    */
465    void ClassTreeMask::clean()
466    {
467        this->clean(this->root_);
468    }
469
470    /**
471        @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function).
472        @param node The node
473    */
474    void ClassTreeMask::clean(ClassTreeMaskNode* node)
475    {
476        // Iterate through all subnodes of the given node
477        for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
478        {
479            // Recursive function-call: Clean the subnode
480            this->clean(*it);
481
482            // Now check if the subnode contains the same rule as the current node
483            if ((*it)->isIncluded() == node->isIncluded())
484            {
485                // It does: Move all subnodes of the redundant subnode to the current node
486                node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end());
487                (*it)->subnodes_.clear();
488
489                // Remove the redundant subnode from the current node
490                node->subnodes_.erase(it++);
491            }
492            else
493            {
494                // The subnode is necessary: Move on to the next subnode
495                ++it;
496            }
497        }
498    }
499
500    /**
501        @brief Checks if a node for the given subclass exists.
502        @param subclass The Identifier of the subclass
503        @return True = the node exists
504    */
505    bool ClassTreeMask::nodeExists(const Identifier* subclass)
506    {
507        for (ClassTreeMaskIterator it = this->root_; it; ++it)
508            if ((*it)->getClass() == subclass)
509                return true;
510
511        return false;
512    }
513
514    /**
515        @brief Assignment operator: Adds all rules of the other mask.
516        @param other The other mask
517        @return A reference to the mask itself
518    */
519    const ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other)
520    {
521        // Make a copy to avoid troubles with self-assignments (like A = A).
522        ClassTreeMask temp(other);
523
524        // Removes all current rules
525        this->reset();
526
527        // Copy all rules from the other mask
528        for (ClassTreeMaskIterator it = temp.root_; it; ++it)
529            this->add(it->getClass(), it->isIncluded(), false, false);
530
531        // Return a reference to the mask itself
532        return (*this);
533    }
534
535    /**
536        @brief Compares the mask with another mask and returns true if they represent the same logic.
537        @param other The other mask
538        @return True if both masks represent the same logic
539    */
540    bool ClassTreeMask::operator==(const ClassTreeMask& other) const
541    {
542        ClassTreeMask temp1 = other;
543        ClassTreeMask temp2 = (*this);
544
545        temp1.clean();
546        temp2.clean();
547
548        ClassTreeMaskIterator it1 = temp1.root_;
549        ClassTreeMaskIterator it2 = temp2.root_;
550
551        for ( ; it1 && it2; ++it1, ++it2)
552            if (it1->getClass() != it2->getClass())
553                return false;
554
555        return true;
556    }
557
558    /**
559        @brief Compares the mask with another mask and returns true if they represent different logics.
560        @param other The other mask
561        @return True if the masks represent different logics
562    */
563    bool ClassTreeMask::operator!=(const ClassTreeMask& other) const
564    {
565        return (!((*this) == other));
566    }
567
568    /**
569        @brief Prefix operator + does nothing.
570        @return A reference to the mask itself
571    */
572    const ClassTreeMask& ClassTreeMask::operator+() const
573    {
574        return (*this);
575    }
576
577    /**
578        @brief Prefix operator - inverts the mask.
579        @return The inverted mask
580    */
581    ClassTreeMask ClassTreeMask::operator-() const
582    {
583        return (!(*this));
584    }
585
586    /**
587        @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).
588        @param other The mask to unite with
589        @return The union
590    */
591    ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const
592    {
593        // Create a new mask
594        ClassTreeMask newmask;
595
596        // Add all nodes from the first mask, calculate the rule with the or-operation
597        for (ClassTreeMaskIterator it = this->root_; it; ++it)
598        {
599            const Identifier* subclass = it->getClass();
600            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
601        }
602
603        // Add all nodes from the second mask, calculate the rule with the or-operation
604        for (ClassTreeMaskIterator it = other.root_; it; ++it)
605        {
606            const Identifier* subclass = it->getClass();
607            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
608        }
609
610        // Drop all redundant rules
611        newmask.clean();
612
613        // Return the new mask
614        return newmask;
615    }
616
617    /**
618        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
619        @param other The mask to intersect with
620        @return The intersection
621    */
622    ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const
623    {
624        // Create a new mask
625        ClassTreeMask newmask;
626
627        // Add all nodes from the first mask, calculate the rule with the and-operation
628        for (ClassTreeMaskIterator it = this->root_; it; ++it)
629        {
630            const Identifier* subclass = it->getClass();
631            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
632        }
633
634        // Add all nodes from the second mask, calculate the rule with the and-operation
635        for (ClassTreeMaskIterator it = other.root_; it; ++it)
636        {
637            const Identifier* subclass = it->getClass();
638            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
639        }
640
641        // Drop all redundant rules
642        newmask.clean();
643
644        // Return the new mask
645        return newmask;
646    }
647
648    /**
649        @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).
650        @param other The mask to subtract.
651        @return The difference
652    */
653    ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const
654    {
655        return ((*this) * (!other));
656    }
657
658    /**
659        @brief Inverts the mask (all included classes are now excluded and vice versa).
660        @return The complement
661    */
662    ClassTreeMask ClassTreeMask::operator!() const
663    {
664        // Create a new mask
665        ClassTreeMask newmask;
666
667        // Add all nodes from the other mask, inverting the rules
668        for (ClassTreeMaskIterator it = this->root_; it; ++it)
669        {
670            const Identifier* subclass = it->getClass();
671            newmask.add(subclass, !this->isIncluded(subclass), false, false);
672        }
673
674        // Return the new mask
675        return newmask;
676    }
677
678    /**
679        @brief Unites this mask with another mask.
680        @param other The other mask
681        @return A reference to the mask itself
682    */
683    const ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other)
684    {
685        (*this) = (*this) + other;
686        return (*this);
687    }
688
689    /**
690        @brief Intersects this mask with another mask.
691        @param other The other mask
692        @return A reference to the mask itself
693    */
694    const ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other)
695    {
696        (*this) = (*this) * other;
697        return (*this);
698    }
699
700    /**
701        @brief Subtracts another mask from this mask.
702        @param other The other mask
703        @return A reference to the mask itself
704    */
705    const ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other)
706    {
707        (*this) = (*this) - other;
708        return (*this);
709    }
710
711    /**
712        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
713        @param other The mask to intersect with
714        @return The intersection
715    */
716    ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const
717    {
718        return ((*this) * other);
719    }
720
721    /**
722        @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).
723        @param other The mask to unite with
724        @return The union
725    */
726    ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const
727    {
728        return ((*this) + other);
729    }
730
731    /**
732        @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).
733        @param other The mask to join with
734        @return The result
735    */
736    ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const
737    {
738        // Create a new mask
739        ClassTreeMask newmask;
740
741        // Add all nodes from the first mask, calculate the rule with the xor-operation
742        for (ClassTreeMaskIterator it = this->root_; it; ++it)
743        {
744            const Identifier* subclass = it->getClass();
745            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
746        }
747
748        // Add all nodes from the second mask, calculate the rule with the xor-operation
749        for (ClassTreeMaskIterator it = other.root_; it; ++it)
750        {
751            const Identifier* subclass = it->getClass();
752            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
753        }
754
755        // Drop all redundant rules
756        newmask.clean();
757
758        // Return the new mask
759        return newmask;
760    }
761
762    /**
763        @brief Inverts the mask (all included classes are now excluded and vice versa).
764        @return The complement
765    */
766    ClassTreeMask ClassTreeMask::operator~() const
767    {
768        return (!(*this));
769    }
770
771    /**
772        @brief Intersects this mask with another mask (and-operation)
773        @param other The other mask
774        @return A reference to the mask itself
775    */
776    const ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other)
777    {
778        (*this) = (*this) & other;
779        return (*this);
780    }
781
782    /**
783        @brief Unites this mask with another mask (or-operation).
784        @param other The other mask
785        @return A reference to the mask itself
786    */
787    const ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other)
788    {
789        (*this) = (*this) | other;
790        return (*this);
791    }
792
793    /**
794        @brief Joins this mask with another mask with a xor-operation.
795        @param other The other mask
796        @return A reference to the mask itself
797    */
798    const ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other)
799    {
800        (*this) = (*this) ^ other;
801        return (*this);
802    }
803
804    /**
805        @brief Converts the content of a mask into a human readable string and puts it on the ostream.
806        @param out The ostream
807        @param mask The mask
808        @return A reference to the ostream
809    */
810    std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask)
811    {
812        // Iterate through all rules
813        for (ClassTreeMaskIterator it = mask.root_; it; ++it)
814        {
815            // Calculate the prefix: + means included, - means excluded
816            if (it->isIncluded())
817                out << "+";
818            else
819                out << "-";
820
821            // Put the name of the corresponding class on the stream
822            out << it->getClass()->getName() << " ";
823        }
824
825        return out;
826    }
827
828
829    // ###################################
830    // ### ClassTreeMaskObjectIterator ###
831    // ###################################
832    /**
833        @brief Initializes the iterator from a given ClassTreeMask.
834        @param mask The mask
835    */
836    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator=(const ClassTreeMask& mask)
837    {
838        // Clear everything, use a cleaned copy of the mask
839        this->subclasses_.clear();
840        ClassTreeMask temp = mask;
841        temp.clean();
842
843        // Create the subclass-list by going through the mask-tree, starting with the root-node
844        this->create(temp.root_);
845
846        // Move the subclass-iterator to the beginning of the subclass-list
847        this->subclassIterator_ = this->subclasses_.begin();
848
849        // If there is a first subclass, move the object-iterator to the first object of this class. Else go to the end
850        if (this->subclassIterator_ != this->subclasses_.end())
851            this->objectIterator_ = (*this->subclassIterator_).first->getObjects()->begin();
852        else
853            this->objectIterator_ = ObjectList<BaseObject>::end();
854
855        // Check if the iterator points on a valid object. If not, go to the next object by calling ++
856        if (!this->objectIterator_ || ((*this->subclassIterator_).second && !this->objectIterator_->isExactlyA((*this->subclassIterator_).first)))
857            this->operator++();
858
859        return (*this);
860    }
861
862    /**
863        @brief Iterate to the next object (if any).
864        @return The iterator itself
865    */
866    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator++()
867    {
868        if (this->objectIterator_)
869        {
870            // The iterator points on a valid object, therefore we also have a valid subclass-iterator at the moment
871            do
872            {
873                // Go to the next object
874                ++this->objectIterator_;
875
876                while (!this->objectIterator_)
877                {
878                    // We reached the end of the current objectlist - go to the next class
879                    ++this->subclassIterator_;
880
881                    // Check if there really is a next class. If yes, move the object-iterator to the first object
882                    if (this->subclassIterator_ != this->subclasses_.end())
883                        this->objectIterator_ = (*this->subclassIterator_).first->getObjects()->begin();
884                    else
885                        return (*this);
886                }
887
888            // Repeat this until we reach a valid object or the end
889            } while ((*this->subclassIterator_).second && !this->objectIterator_->isExactlyA((*this->subclassIterator_).first));
890        }
891        return (*this);
892    }
893
894    /**
895        @brief Recursive function to create the Iterators subclass-list by going through the node-tree of the mask.
896        @param node The current node
897    */
898    void ClassTreeMaskObjectIterator::create(ClassTreeMaskNode* node)
899    {
900        // Add the class of this node to the list, if the class is included
901        if (node->isIncluded())
902        {
903            // If there are some subnodes, the bool is "true", meaning we have to check for the exact clss when iterating
904            if (node->hasSubnodes())
905                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), true));
906            else
907                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), false));
908        }
909
910        // Now check if the node has subnodes
911        if (node->hasSubnodes())
912        {
913            // Get all _direct_ children of the nodes class
914            std::set<const Identifier*> directChildren = node->getClass()->getDirectChildren();
915
916            // Iterate through all subnodes
917            for (std::list<ClassTreeMaskNode*>::iterator it1 = node->subnodes_.begin(); it1 != node->subnodes_.end(); ++it1)
918            {
919                // Recursive call to this function with the subnode
920                this->create(*it1);
921
922                // Only execute the following code if the current node is included, meaning some of the subnodes might be included too
923                if (node->isIncluded())
924                {
925                    scanChildren: // This is a label for goto
926
927                    // Iterate through all direct children
928                    for (std::set<const Identifier*>::iterator it2 = directChildren.begin(); it2 != directChildren.end(); ++it2)
929                    {
930                        // Check if the subnode (it1) is a child of the directChild (it2)
931                        if ((*it1)->getClass()->isA(*it2))
932                        {
933                            // Yes it is - remove the directChild (it2) from the list, because it will already be handled by a recursive call to the create() function
934                            directChildren.erase(it2);
935
936                            // Check if the removed directChild was exactly the subnode
937                            if (!(*it1)->getClass()->isExactlyA(*it2))
938                            {
939                                // No, it wasn't exactly the subnode - therefore there are some classes between
940
941                                // Add the previously removed directChild (it2) to the subclass-list
942                                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it2, true));
943
944                                // Insert all directChildren of the directChild
945                                directChildren.insert((*it2)->getDirectChildrenBegin(), (*it2)->getDirectChildrenEnd());
946
947                                // Restart the scan with the expanded set of directChildren
948                                goto scanChildren;
949                            }
950                            break;
951                        }
952                    }
953                }
954            }
955
956            // Now add all directChildren which don't have subnodes on their own to the subclass-list
957            // The bool is "false", meaning they have no subnodes and therefore need no further checks
958            if (node->isIncluded())
959                for (std::set<const Identifier*>::iterator it = directChildren.begin(); it != directChildren.end(); ++it)
960                    this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it, false));
961        }
962    }
963}
Note: See TracBrowser for help on using the repository browser.