Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9667 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

  • Property svn:eol-style set to native
File size: 34.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of the ClassTreeMask, ClassTreeMaskNode, and ClassTreeMaskIterator classes.
32*/
33
34#include "ClassTreeMask.h"
35#include "class/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    */
96    void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode)
97    {
98        this->subnodes_.insert(this->subnodes_.end(), subnode);
99    }
100
101    /**
102        @brief Deletes all subnodes of this node.
103    */
104    void ClassTreeMaskNode::deleteAllSubnodes()
105    {
106        // Go through the list of all subnodes and delete them
107        for (std::list<ClassTreeMaskNode*>::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); )
108            delete (*(it++));
109
110        // Clear the list
111        this->subnodes_.clear();
112    }
113
114
115    // ###############################
116    // ###  ClassTreeMaskIterator  ###
117    // ###############################
118    /**
119        @brief Constructor: Initializes the iterator by creating a helper-list with the root-node and putting it to the stack.
120        @param node The root-node
121    */
122    ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node)
123    {
124        // Create a list and put the root-note into it
125        std::list<ClassTreeMaskNode*>::iterator it = this->rootlist_.insert(this->rootlist_.end(), node);
126
127        // Put the iterator to the only element of the list and the corresponding end()-iterator on the stack
128        this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>(it, this->rootlist_.end()));
129    }
130
131    /**
132        @brief Destructor: Does nothing.
133    */
134    ClassTreeMaskIterator::~ClassTreeMaskIterator()
135    {
136    }
137
138    /**
139        @brief Iterates through the rule-tree.
140        @return A reference to the iterator itself
141    */
142    const ClassTreeMaskIterator& ClassTreeMaskIterator::operator++()
143    {
144        // Check if the actual node has subnodes
145        if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end())
146        {
147            // Yes it has: Push an iterator, pointing at the first subnode, on the stack
148            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()));
149        }
150        else
151        {
152            // No subnodes, meaning we reached a leaf: Go to the next node
153            do
154            {
155                // Iterate one step in the current list
156                ++this->nodes_.top().first;
157
158                // Check if we reached the end of the list (the second item in the stored pair always represents the end)
159                if (this->nodes_.top().first == this->nodes_.top().second)
160                {
161                    // Yes we've reached the end: Pop the list-iterator from the stack
162                    this->nodes_.pop();
163
164                    // Continue with the loop, meaning: Try to iterate through the previous list
165                    continue;
166                }
167
168                // If we reached this point, we aren't yet at the end of the list: Leave the loop
169                break;
170            } while (!this->nodes_.empty()); // Stop looping if the stack is empty, meaning: We've iterated to the end
171        }
172
173        // Finally return a reference to the iterator itself
174        return *this;
175    }
176
177    /**
178        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
179    */
180    ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const
181    {
182        return (*this->nodes_.top().first);
183    }
184
185    /**
186        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
187    */
188    ClassTreeMaskNode* ClassTreeMaskIterator::operator->() const
189    {
190        return (*this->nodes_.top().first);
191    }
192
193    /**
194        @brief Returns true if the stack is empty, meaning we've reached the end of the tree.
195    */
196    ClassTreeMaskIterator::operator bool() const
197    {
198        return (!this->nodes_.empty());
199    }
200
201    /**
202        @brief Compares the current node with the given one and returns true if they match.
203    */
204    bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare) const
205    {
206        if (!this->nodes_.empty())
207            return ((*this->nodes_.top().first) == compare);
208        else
209            return (compare == 0);
210    }
211
212    /**
213        @brief Compares the current node with the given one and returns true if they don't match.
214    */
215    bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare) const
216    {
217        if (!this->nodes_.empty())
218            return ((*this->nodes_.top().first) != compare);
219        else
220            return (compare != 0);
221    }
222
223
224    // ###############################
225    // ###      ClassTreeMask      ###
226    // ###############################
227    /**
228        @brief Constructor: Adds the root-node of the tree with the first rule ("include everything").
229    */
230    ClassTreeMask::ClassTreeMask()
231    {
232        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
233    }
234
235    /**
236        @brief Copy-constructor: Adds the root-node of the tree with the first rule ("include everything") and adds all rules from the other mask.
237    */
238    ClassTreeMask::ClassTreeMask(const ClassTreeMask& other)
239    {
240        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
241        for (ClassTreeMaskIterator it = other.root_; it; ++it)
242            this->add(it->getClass(), it->isIncluded(), false);
243    }
244
245    /**
246        @brief Destructor: Deletes the root node (which will delete all subnodes too).
247    */
248    ClassTreeMask::~ClassTreeMask()
249    {
250        delete this->root_;
251    }
252
253    /**
254        @brief Adds a new "include" rule for a given subclass to the mask.
255        @param subclass The subclass
256        @param overwrite True = overwrite previously added rules for inheriting classes
257        @param clean True = clean the tree after adding the new rule
258    */
259    void ClassTreeMask::include(const Identifier* subclass, bool overwrite, bool clean)
260    {
261        this->add(subclass, true, overwrite, clean);
262    }
263
264    /**
265        @brief Adds a new "exclude" rule for a given subclass to the mask.
266        @param subclass The subclass
267        @param overwrite True = overwrite previously added rules for inheriting classes
268        @param clean True = clean the tree after adding the new rule
269    */
270    void ClassTreeMask::exclude(const Identifier* subclass, bool overwrite, bool clean)
271    {
272        this->add(subclass, false, overwrite, clean);
273    }
274
275    /**
276        @brief Adds a new rule for a given subclass to the mask.
277        @param subclass The subclass
278        @param bInclude The rule: include (true) or exclude (false)
279        @param overwrite True = overwrite previously added rules for inheriting classes
280        @param clean True = clean the tree after adding the new rule
281    */
282    void ClassTreeMask::add(const Identifier* subclass, bool bInclude, bool overwrite, bool clean)
283    {
284        if (!subclass)
285            return;
286        // Check if the given subclass is a child of our root-class
287        if (subclass->isA(this->root_->getClass()))
288        {
289            // Yes it is: Just add the rule to the three
290            this->add(this->root_, subclass, bInclude, overwrite);
291        }
292        else
293        {
294            // No it's not: Search for classes inheriting from the given class and add the rules for them
295            for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
296                if ((*it)->isA(this->root_->getClass()))
297                    if (overwrite || (!this->nodeExists(*it))) // If we don't want to overwrite, only add nodes that don't already exist
298                        this->add(this->root_, *it, bInclude, overwrite);
299        }
300
301        // Clean the rule-tree
302        if (clean)
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        @param overwrite True = overwrite previously added rules for inheriting classes
312    */
313    void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude, bool overwrite)
314    {
315        if (!subclass)
316            return;
317        // Check if the current node contains exactly the subclass we want to add
318        if (subclass == node->getClass())
319        {
320            // We're at the right place, just change the mask and return
321            node->setIncluded(bInclude, overwrite);
322            return;
323        }
324        else if (subclass->isA(node->getClass()))
325        {
326            // Search for an already existing node, containing the subclass we want to add
327            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
328            {
329                if (subclass->isA((*it)->getClass()))
330                {
331                    // We've found an existing node -> delegate the work with a recursive function-call and return
332                    this->add(*it, subclass, bInclude, overwrite);
333                    return;
334                }
335            }
336
337            // There is no existing node satisfying our needs -> we create a new node
338            ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude);
339
340            // Search for nodes that should actually be subnodes of our new node and erase them
341            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
342            {
343                if ((*it)->getClass()->isChildOf(subclass))
344                {
345                    // We've found a subnode: add it to the new node and erase it from the current node
346                    if (!overwrite)
347                        newnode->addSubnode(*it);
348                    else
349                        delete (*it);
350
351                    node->subnodes_.erase(it++);
352                }
353                else
354                {
355                    ++it;
356                }
357            }
358
359            // Finally add the new node as a subnode to the current node
360            node->addSubnode(newnode);
361        }
362    }
363
364    /**
365        @brief Adds a new "include" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
366        @param subclass The subclass
367        @param clean True = clean the tree after adding the new rule
368    */
369    void ClassTreeMask::includeSingle(const Identifier* subclass, bool clean)
370    {
371        this->addSingle(subclass, true, clean);
372    }
373
374    /**
375        @brief Adds a new "exclude" rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
376        @param subclass The subclass
377        @param clean True = clean the tree after adding the new rule
378    */
379    void ClassTreeMask::excludeSingle(const Identifier* subclass, bool clean)
380    {
381        this->addSingle(subclass, false, clean);
382    }
383
384    /**
385        @brief Adds a new rule for a single subclass. The new rule doesn't change the mask for inheriting classes.
386        @param bInclude The rule: include (true) or exclude (false)
387        @param subclass The subclass
388        @param clean True = clean the tree after adding the new rule
389    */
390    void ClassTreeMask::addSingle(const Identifier* subclass, bool bInclude, bool clean)
391    {
392        if (!subclass)
393            return;
394        for (std::set<const Identifier*>::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it)
395            this->add(*it, this->isIncluded(*it), false, false);
396
397        this->add(subclass, bInclude, false, clean);
398    }
399
400    /**
401        @brief Resets the mask to "include everything".
402    */
403    void ClassTreeMask::reset()
404    {
405        delete this->root_;
406        this->root_ = new ClassTreeMaskNode(ClassIdentifier<BaseObject>::getIdentifier(), true);
407    }
408
409    /**
410        @brief Tells if a given subclass is included or not.
411        @param subclass The subclass
412        @return Included (true) or excluded (false)
413    */
414    bool ClassTreeMask::isIncluded(const Identifier* subclass) const
415    {
416        return this->isIncluded(this->root_, subclass);
417    }
418
419    /**
420        @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function).
421        @param node The node
422        @param subclass The subclass
423        @return Included (true) or excluded (false)
424    */
425    bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const
426    {
427        if (!subclass)
428            return false;
429        // Check if the searched subclass is of the same type as the class in the current node or a derivative
430        if (subclass->isA(node->getClass()))
431        {
432            // Check for the special case
433            if (subclass == node->getClass())
434                return node->isIncluded();
435
436            // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call.
437            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
438                if (subclass->isA((*it)->getClass()))
439                    return isIncluded(*it, subclass);
440
441            // There is no subnode containing our class -> the rule of the current node takes in effect
442            return node->isIncluded();
443        }
444        else
445        {
446            // The class is not included in the mask: return false
447            return false;
448        }
449    }
450
451    /**
452        @brief Tells if a given subclass is excluded or not.
453        @param subclass The subclass
454        @return The inverted rule: Excluded (true) or included (false)
455    */
456    bool ClassTreeMask::isExcluded(const Identifier* subclass) const
457    {
458        return (!this->isIncluded(subclass));
459    }
460
461    /**
462        @brief Removes all unneeded rules that don't change the information of the mask.
463    */
464    void ClassTreeMask::clean()
465    {
466        this->clean(this->root_);
467    }
468
469    /**
470        @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function).
471        @param node The node
472    */
473    void ClassTreeMask::clean(ClassTreeMaskNode* node)
474    {
475        // Iterate through all subnodes of the given node
476        for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
477        {
478            // Recursive function-call: Clean the subnode
479            this->clean(*it);
480
481            // Now check if the subnode contains the same rule as the current node
482            if ((*it)->isIncluded() == node->isIncluded())
483            {
484                // It does: Move all subnodes of the redundant subnode to the current node
485                node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end());
486                (*it)->subnodes_.clear();
487
488                // Remove the redundant subnode from the current node
489                delete (*it);
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    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    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_ = Context::getRootContext()->getObjectList(this->subclassIterator_->first)->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_ = Context::getRootContext()->getObjectList(this->subclassIterator_->first)->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.