Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6027 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

  • 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                delete (*it);
491                node->subnodes_.erase(it++);
492            }
493            else
494            {
495                // The subnode is necessary: Move on to the next subnode
496                ++it;
497            }
498        }
499    }
500
501    /**
502        @brief Checks if a node for the given subclass exists.
503        @param subclass The Identifier of the subclass
504        @return True = the node exists
505    */
506    bool ClassTreeMask::nodeExists(const Identifier* subclass)
507    {
508        for (ClassTreeMaskIterator it = this->root_; it; ++it)
509            if ((*it)->getClass() == subclass)
510                return true;
511
512        return false;
513    }
514
515    /**
516        @brief Assignment operator: Adds all rules of the other mask.
517        @param other The other mask
518        @return A reference to the mask itself
519    */
520    const ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other)
521    {
522        // Make a copy to avoid troubles with self-assignments (like A = A).
523        ClassTreeMask temp(other);
524
525        // Removes all current rules
526        this->reset();
527
528        // Copy all rules from the other mask
529        for (ClassTreeMaskIterator it = temp.root_; it; ++it)
530            this->add(it->getClass(), it->isIncluded(), false, false);
531
532        // Return a reference to the mask itself
533        return (*this);
534    }
535
536    /**
537        @brief Compares the mask with another mask and returns true if they represent the same logic.
538        @param other The other mask
539        @return True if both masks represent the same logic
540    */
541    bool ClassTreeMask::operator==(const ClassTreeMask& other) const
542    {
543        ClassTreeMask temp1 = other;
544        ClassTreeMask temp2 = (*this);
545
546        temp1.clean();
547        temp2.clean();
548
549        ClassTreeMaskIterator it1 = temp1.root_;
550        ClassTreeMaskIterator it2 = temp2.root_;
551
552        for ( ; it1 && it2; ++it1, ++it2)
553            if (it1->getClass() != it2->getClass())
554                return false;
555
556        return true;
557    }
558
559    /**
560        @brief Compares the mask with another mask and returns true if they represent different logics.
561        @param other The other mask
562        @return True if the masks represent different logics
563    */
564    bool ClassTreeMask::operator!=(const ClassTreeMask& other) const
565    {
566        return (!((*this) == other));
567    }
568
569    /**
570        @brief Prefix operator + does nothing.
571        @return A reference to the mask itself
572    */
573    const ClassTreeMask& ClassTreeMask::operator+() const
574    {
575        return (*this);
576    }
577
578    /**
579        @brief Prefix operator - inverts the mask.
580        @return The inverted mask
581    */
582    ClassTreeMask ClassTreeMask::operator-() const
583    {
584        return (!(*this));
585    }
586
587    /**
588        @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).
589        @param other The mask to unite with
590        @return The union
591    */
592    ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const
593    {
594        // Create a new mask
595        ClassTreeMask newmask;
596
597        // Add all nodes from the first mask, calculate the rule with the or-operation
598        for (ClassTreeMaskIterator it = this->root_; it; ++it)
599        {
600            const Identifier* subclass = it->getClass();
601            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
602        }
603
604        // Add all nodes from the second mask, calculate the rule with the or-operation
605        for (ClassTreeMaskIterator it = other.root_; it; ++it)
606        {
607            const Identifier* subclass = it->getClass();
608            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false);
609        }
610
611        // Drop all redundant rules
612        newmask.clean();
613
614        // Return the new mask
615        return newmask;
616    }
617
618    /**
619        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
620        @param other The mask to intersect with
621        @return The intersection
622    */
623    ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const
624    {
625        // Create a new mask
626        ClassTreeMask newmask;
627
628        // Add all nodes from the first mask, calculate the rule with the and-operation
629        for (ClassTreeMaskIterator it = this->root_; it; ++it)
630        {
631            const Identifier* subclass = it->getClass();
632            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
633        }
634
635        // Add all nodes from the second mask, calculate the rule with the and-operation
636        for (ClassTreeMaskIterator it = other.root_; it; ++it)
637        {
638            const Identifier* subclass = it->getClass();
639            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false);
640        }
641
642        // Drop all redundant rules
643        newmask.clean();
644
645        // Return the new mask
646        return newmask;
647    }
648
649    /**
650        @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).
651        @param other The mask to subtract.
652        @return The difference
653    */
654    ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const
655    {
656        return ((*this) * (!other));
657    }
658
659    /**
660        @brief Inverts the mask (all included classes are now excluded and vice versa).
661        @return The complement
662    */
663    ClassTreeMask ClassTreeMask::operator!() const
664    {
665        // Create a new mask
666        ClassTreeMask newmask;
667
668        // Add all nodes from the other mask, inverting the rules
669        for (ClassTreeMaskIterator it = this->root_; it; ++it)
670        {
671            const Identifier* subclass = it->getClass();
672            newmask.add(subclass, !this->isIncluded(subclass), false, false);
673        }
674
675        // Return the new mask
676        return newmask;
677    }
678
679    /**
680        @brief Unites this mask with another mask.
681        @param other The other mask
682        @return A reference to the mask itself
683    */
684    const ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other)
685    {
686        (*this) = (*this) + other;
687        return (*this);
688    }
689
690    /**
691        @brief Intersects this mask with another mask.
692        @param other The other mask
693        @return A reference to the mask itself
694    */
695    const ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other)
696    {
697        (*this) = (*this) * other;
698        return (*this);
699    }
700
701    /**
702        @brief Subtracts another mask from this mask.
703        @param other The other mask
704        @return A reference to the mask itself
705    */
706    const ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other)
707    {
708        (*this) = (*this) - other;
709        return (*this);
710    }
711
712    /**
713        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
714        @param other The mask to intersect with
715        @return The intersection
716    */
717    ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const
718    {
719        return ((*this) * other);
720    }
721
722    /**
723        @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).
724        @param other The mask to unite with
725        @return The union
726    */
727    ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const
728    {
729        return ((*this) + other);
730    }
731
732    /**
733        @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).
734        @param other The mask to join with
735        @return The result
736    */
737    ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const
738    {
739        // Create a new mask
740        ClassTreeMask newmask;
741
742        // Add all nodes from the first mask, calculate the rule with the xor-operation
743        for (ClassTreeMaskIterator it = this->root_; it; ++it)
744        {
745            const Identifier* subclass = it->getClass();
746            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
747        }
748
749        // Add all nodes from the second mask, calculate the rule with the xor-operation
750        for (ClassTreeMaskIterator it = other.root_; it; ++it)
751        {
752            const Identifier* subclass = it->getClass();
753            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false);
754        }
755
756        // Drop all redundant rules
757        newmask.clean();
758
759        // Return the new mask
760        return newmask;
761    }
762
763    /**
764        @brief Inverts the mask (all included classes are now excluded and vice versa).
765        @return The complement
766    */
767    ClassTreeMask ClassTreeMask::operator~() const
768    {
769        return (!(*this));
770    }
771
772    /**
773        @brief Intersects this mask with another mask (and-operation)
774        @param other The other mask
775        @return A reference to the mask itself
776    */
777    const ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other)
778    {
779        (*this) = (*this) & other;
780        return (*this);
781    }
782
783    /**
784        @brief Unites this mask with another mask (or-operation).
785        @param other The other mask
786        @return A reference to the mask itself
787    */
788    const ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other)
789    {
790        (*this) = (*this) | other;
791        return (*this);
792    }
793
794    /**
795        @brief Joins this mask with another mask with a xor-operation.
796        @param other The other mask
797        @return A reference to the mask itself
798    */
799    const ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other)
800    {
801        (*this) = (*this) ^ other;
802        return (*this);
803    }
804
805    /**
806        @brief Converts the content of a mask into a human readable string and puts it on the ostream.
807        @param out The ostream
808        @param mask The mask
809        @return A reference to the ostream
810    */
811    std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask)
812    {
813        // Iterate through all rules
814        for (ClassTreeMaskIterator it = mask.root_; it; ++it)
815        {
816            // Calculate the prefix: + means included, - means excluded
817            if (it->isIncluded())
818                out << "+";
819            else
820                out << "-";
821
822            // Put the name of the corresponding class on the stream
823            out << it->getClass()->getName() << " ";
824        }
825
826        return out;
827    }
828
829
830    // ###################################
831    // ### ClassTreeMaskObjectIterator ###
832    // ###################################
833    /**
834        @brief Initializes the iterator from a given ClassTreeMask.
835        @param mask The mask
836    */
837    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator=(const ClassTreeMask& mask)
838    {
839        // Clear everything, use a cleaned copy of the mask
840        this->subclasses_.clear();
841        ClassTreeMask temp = mask;
842        temp.clean();
843
844        // Create the subclass-list by going through the mask-tree, starting with the root-node
845        this->create(temp.root_);
846
847        // Move the subclass-iterator to the beginning of the subclass-list
848        this->subclassIterator_ = this->subclasses_.begin();
849
850        // If there is a first subclass, move the object-iterator to the first object of this class. Else go to the end
851        if (this->subclassIterator_ != this->subclasses_.end())
852            this->objectIterator_ = (*this->subclassIterator_).first->getObjects()->begin();
853        else
854            this->objectIterator_ = ObjectList<BaseObject>::end();
855
856        // Check if the iterator points on a valid object. If not, go to the next object by calling ++
857        if (!this->objectIterator_ || ((*this->subclassIterator_).second && !this->objectIterator_->isExactlyA((*this->subclassIterator_).first)))
858            this->operator++();
859
860        return (*this);
861    }
862
863    /**
864        @brief Iterate to the next object (if any).
865        @return The iterator itself
866    */
867    const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator++()
868    {
869        if (this->objectIterator_)
870        {
871            // The iterator points on a valid object, therefore we also have a valid subclass-iterator at the moment
872            do
873            {
874                // Go to the next object
875                ++this->objectIterator_;
876
877                while (!this->objectIterator_)
878                {
879                    // We reached the end of the current objectlist - go to the next class
880                    ++this->subclassIterator_;
881
882                    // Check if there really is a next class. If yes, move the object-iterator to the first object
883                    if (this->subclassIterator_ != this->subclasses_.end())
884                        this->objectIterator_ = (*this->subclassIterator_).first->getObjects()->begin();
885                    else
886                        return (*this);
887                }
888
889            // Repeat this until we reach a valid object or the end
890            } while ((*this->subclassIterator_).second && !this->objectIterator_->isExactlyA((*this->subclassIterator_).first));
891        }
892        return (*this);
893    }
894
895    /**
896        @brief Recursive function to create the Iterators subclass-list by going through the node-tree of the mask.
897        @param node The current node
898    */
899    void ClassTreeMaskObjectIterator::create(ClassTreeMaskNode* node)
900    {
901        // Add the class of this node to the list, if the class is included
902        if (node->isIncluded())
903        {
904            // If there are some subnodes, the bool is "true", meaning we have to check for the exact clss when iterating
905            if (node->hasSubnodes())
906                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), true));
907            else
908                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(node->getClass(), false));
909        }
910
911        // Now check if the node has subnodes
912        if (node->hasSubnodes())
913        {
914            // Get all _direct_ children of the nodes class
915            std::set<const Identifier*> directChildren = node->getClass()->getDirectChildren();
916
917            // Iterate through all subnodes
918            for (std::list<ClassTreeMaskNode*>::iterator it1 = node->subnodes_.begin(); it1 != node->subnodes_.end(); ++it1)
919            {
920                // Recursive call to this function with the subnode
921                this->create(*it1);
922
923                // Only execute the following code if the current node is included, meaning some of the subnodes might be included too
924                if (node->isIncluded())
925                {
926                    scanChildren: // This is a label for goto
927
928                    // Iterate through all direct children
929                    for (std::set<const Identifier*>::iterator it2 = directChildren.begin(); it2 != directChildren.end(); ++it2)
930                    {
931                        // Check if the subnode (it1) is a child of the directChild (it2)
932                        if ((*it1)->getClass()->isA(*it2))
933                        {
934                            // Yes it is - remove the directChild (it2) from the list, because it will already be handled by a recursive call to the create() function
935                            directChildren.erase(it2);
936
937                            // Check if the removed directChild was exactly the subnode
938                            if (!(*it1)->getClass()->isExactlyA(*it2))
939                            {
940                                // No, it wasn't exactly the subnode - therefore there are some classes between
941
942                                // Add the previously removed directChild (it2) to the subclass-list
943                                this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it2, true));
944
945                                // Insert all directChildren of the directChild
946                                directChildren.insert((*it2)->getDirectChildrenBegin(), (*it2)->getDirectChildrenEnd());
947
948                                // Restart the scan with the expanded set of directChildren
949                                goto scanChildren;
950                            }
951                            break;
952                        }
953                    }
954                }
955            }
956
957            // Now add all directChildren which don't have subnodes on their own to the subclass-list
958            // The bool is "false", meaning they have no subnodes and therefore need no further checks
959            if (node->isIncluded())
960                for (std::set<const Identifier*>::iterator it = directChildren.begin(); it != directChildren.end(); ++it)
961                    this->subclasses_.insert(this->subclasses_.end(), std::pair<const Identifier*, bool>(*it, false));
962        }
963    }
964}
Note: See TracBrowser for help on using the repository browser.