/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Fabian 'x3n' Landau * Co-authors: * ... * */ /** @file @brief Implementation of the ClassTreeMask, ClassTreeMaskNode, and ClassTreeMaskIterator classes. */ #include "ClassTreeMask.h" #include "class/Identifier.h" namespace orxonox { // ############################### // ### ClassTreeMaskNode ### // ############################### /** @brief Constructor: Creates the node, sets the subclass and the rule. @param subclass The subclass the rule refers to @param bIncluded The rule: included (true) or excluded (false) */ ClassTreeMaskNode::ClassTreeMaskNode(const Identifier* subclass, bool bIncluded) { this->subclass_ = subclass; this->bIncluded_ = bIncluded; } /** @brief Destructor: Deletes all subnodes. */ ClassTreeMaskNode::~ClassTreeMaskNode() { // Go through the list of all subnodes and delete them this->deleteAllSubnodes(); } /** @brief Sets the rule for the node to "included". @param overwrite True = overwrite previously added rules for inheriting classes */ void ClassTreeMaskNode::include(bool overwrite) { this->setIncluded(true, overwrite); } /** @brief Sets the rule for the node to "excluded". @param overwrite True = overwrite previously added rules for inheriting classes */ void ClassTreeMaskNode::exclude(bool overwrite) { this->setIncluded(false, overwrite); } /** @brief Sets the rule for the node to a given value and erases all following rules. @param bIncluded The rule: included (true) or excluded (false) @param overwrite True = overwrite previously added rules for inheriting classes */ void ClassTreeMaskNode::setIncluded(bool bIncluded, bool overwrite) { if (overwrite) this->deleteAllSubnodes(); this->bIncluded_ = bIncluded; } /** @brief Adds a new subnode to the list of subnodes. */ void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode) { this->subnodes_.insert(this->subnodes_.end(), subnode); } /** @brief Deletes all subnodes of this node. */ void ClassTreeMaskNode::deleteAllSubnodes() { // Go through the list of all subnodes and delete them for (std::list::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); ) delete (*(it++)); // Clear the list this->subnodes_.clear(); } // ############################### // ### ClassTreeMaskIterator ### // ############################### /** @brief Constructor: Initializes the iterator by creating a helper-list with the root-node and putting it to the stack. @param node The root-node */ ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node) { // Create a list and put the root-note into it std::list::iterator it = this->rootlist_.insert(this->rootlist_.end(), node); // Put the iterator to the only element of the list and the corresponding end()-iterator on the stack this->nodes_.push(std::pair::iterator, std::list::iterator>(it, this->rootlist_.end())); } /** @brief Destructor: Does nothing. */ ClassTreeMaskIterator::~ClassTreeMaskIterator() { } /** @brief Iterates through the rule-tree. @return A reference to the iterator itself */ const ClassTreeMaskIterator& ClassTreeMaskIterator::operator++() { // Check if the actual node has subnodes if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end()) { // Yes it has: Push an iterator, pointing at the first subnode, on the stack this->nodes_.push(std::pair::iterator, std::list::iterator>((*this->nodes_.top().first)->subnodes_.begin(), (*this->nodes_.top().first)->subnodes_.end())); } else { // No subnodes, meaning we reached a leaf: Go to the next node do { // Iterate one step in the current list ++this->nodes_.top().first; // Check if we reached the end of the list (the second item in the stored pair always represents the end) if (this->nodes_.top().first == this->nodes_.top().second) { // Yes we've reached the end: Pop the list-iterator from the stack this->nodes_.pop(); // Continue with the loop, meaning: Try to iterate through the previous list continue; } // If we reached this point, we aren't yet at the end of the list: Leave the loop break; } while (!this->nodes_.empty()); // Stop looping if the stack is empty, meaning: We've iterated to the end } // Finally return a reference to the iterator itself return *this; } /** @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points. */ ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const { return (*this->nodes_.top().first); } /** @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points. */ ClassTreeMaskNode* ClassTreeMaskIterator::operator->() const { return (*this->nodes_.top().first); } /** @brief Returns true if the stack is empty, meaning we've reached the end of the tree. */ ClassTreeMaskIterator::operator bool() const { return (!this->nodes_.empty()); } /** @brief Compares the current node with the given one and returns true if they match. */ bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare) const { if (!this->nodes_.empty()) return ((*this->nodes_.top().first) == compare); else return (compare == 0); } /** @brief Compares the current node with the given one and returns true if they don't match. */ bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare) const { if (!this->nodes_.empty()) return ((*this->nodes_.top().first) != compare); else return (compare != 0); } // ############################### // ### ClassTreeMask ### // ############################### /** @brief Constructor: Adds the root-node of the tree with the first rule ("include everything"). */ ClassTreeMask::ClassTreeMask() { this->root_ = new ClassTreeMaskNode(ClassIdentifier::getIdentifier(), true); } /** @brief Copy-constructor: Adds the root-node of the tree with the first rule ("include everything") and adds all rules from the other mask. */ ClassTreeMask::ClassTreeMask(const ClassTreeMask& other) { this->root_ = new ClassTreeMaskNode(ClassIdentifier::getIdentifier(), true); for (ClassTreeMaskIterator it = other.root_; it; ++it) this->add(it->getClass(), it->isIncluded(), false); } /** @brief Destructor: Deletes the root node (which will delete all subnodes too). */ ClassTreeMask::~ClassTreeMask() { delete this->root_; } /** @brief Adds a new "include" rule for a given subclass to the mask. @param subclass The subclass @param overwrite True = overwrite previously added rules for inheriting classes @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::include(const Identifier* subclass, bool overwrite, bool clean) { this->add(subclass, true, overwrite, clean); } /** @brief Adds a new "exclude" rule for a given subclass to the mask. @param subclass The subclass @param overwrite True = overwrite previously added rules for inheriting classes @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::exclude(const Identifier* subclass, bool overwrite, bool clean) { this->add(subclass, false, overwrite, clean); } /** @brief Adds a new rule for a given subclass to the mask. @param subclass The subclass @param bInclude The rule: include (true) or exclude (false) @param overwrite True = overwrite previously added rules for inheriting classes @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::add(const Identifier* subclass, bool bInclude, bool overwrite, bool clean) { if (!subclass) return; // Check if the given subclass is a child of our root-class if (subclass->isA(this->root_->getClass())) { // Yes it is: Just add the rule to the three this->add(this->root_, subclass, bInclude, overwrite); } else { // No it's not: Search for classes inheriting from the given class and add the rules for them for (std::set::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it) if ((*it)->isA(this->root_->getClass())) if (overwrite || (!this->nodeExists(*it))) // If we don't want to overwrite, only add nodes that don't already exist this->add(this->root_, *it, bInclude, overwrite); } // Clean the rule-tree if (clean) this->clean(); } /** @brief Adds a new rule for a given subclass to a node of the internal rule-tree (recursive function). @param node The node @param subclass The subclass @param bInclude The rule: include (true) or exclude (false) @param overwrite True = overwrite previously added rules for inheriting classes */ void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude, bool overwrite) { if (!subclass) return; // Check if the current node contains exactly the subclass we want to add if (subclass == node->getClass()) { // We're at the right place, just change the mask and return node->setIncluded(bInclude, overwrite); return; } else if (subclass->isA(node->getClass())) { // Search for an already existing node, containing the subclass we want to add for (std::list::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it) { if (subclass->isA((*it)->getClass())) { // We've found an existing node -> delegate the work with a recursive function-call and return this->add(*it, subclass, bInclude, overwrite); return; } } // There is no existing node satisfying our needs -> we create a new node ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude); // Search for nodes that should actually be subnodes of our new node and erase them for (std::list::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ) { if ((*it)->getClass()->isChildOf(subclass)) { // We've found a subnode: add it to the new node and erase it from the current node if (!overwrite) newnode->addSubnode(*it); else delete (*it); node->subnodes_.erase(it++); } else { ++it; } } // Finally add the new node as a subnode to the current node node->addSubnode(newnode); } } /** @brief Adds a new "include" rule for a single subclass. The new rule doesn't change the mask for inheriting classes. @param subclass The subclass @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::includeSingle(const Identifier* subclass, bool clean) { this->addSingle(subclass, true, clean); } /** @brief Adds a new "exclude" rule for a single subclass. The new rule doesn't change the mask for inheriting classes. @param subclass The subclass @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::excludeSingle(const Identifier* subclass, bool clean) { this->addSingle(subclass, false, clean); } /** @brief Adds a new rule for a single subclass. The new rule doesn't change the mask for inheriting classes. @param bInclude The rule: include (true) or exclude (false) @param subclass The subclass @param clean True = clean the tree after adding the new rule */ void ClassTreeMask::addSingle(const Identifier* subclass, bool bInclude, bool clean) { if (!subclass) return; for (std::set::const_iterator it = subclass->getDirectChildrenBegin(); it != subclass->getDirectChildrenEnd(); ++it) this->add(*it, this->isIncluded(*it), false, false); this->add(subclass, bInclude, false, clean); } /** @brief Resets the mask to "include everything". */ void ClassTreeMask::reset() { delete this->root_; this->root_ = new ClassTreeMaskNode(ClassIdentifier::getIdentifier(), true); } /** @brief Tells if a given subclass is included or not. @param subclass The subclass @return Included (true) or excluded (false) */ bool ClassTreeMask::isIncluded(const Identifier* subclass) const { return this->isIncluded(this->root_, subclass); } /** @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function). @param node The node @param subclass The subclass @return Included (true) or excluded (false) */ bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const { if (!subclass) return false; // Check if the searched subclass is of the same type as the class in the current node or a derivative if (subclass->isA(node->getClass())) { // Check for the special case if (subclass == node->getClass()) return node->isIncluded(); // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call. for (std::list::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it) if (subclass->isA((*it)->getClass())) return isIncluded(*it, subclass); // There is no subnode containing our class -> the rule of the current node takes in effect return node->isIncluded(); } else { // The class is not included in the mask: return false return false; } } /** @brief Tells if a given subclass is excluded or not. @param subclass The subclass @return The inverted rule: Excluded (true) or included (false) */ bool ClassTreeMask::isExcluded(const Identifier* subclass) const { return (!this->isIncluded(subclass)); } /** @brief Removes all unneeded rules that don't change the information of the mask. */ void ClassTreeMask::clean() { this->clean(this->root_); } /** @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function). @param node The node */ void ClassTreeMask::clean(ClassTreeMaskNode* node) { // Iterate through all subnodes of the given node for (std::list::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ) { // Recursive function-call: Clean the subnode this->clean(*it); // Now check if the subnode contains the same rule as the current node if ((*it)->isIncluded() == node->isIncluded()) { // It does: Move all subnodes of the redundant subnode to the current node node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end()); (*it)->subnodes_.clear(); // Remove the redundant subnode from the current node delete (*it); node->subnodes_.erase(it++); } else { // The subnode is necessary: Move on to the next subnode ++it; } } } /** @brief Checks if a node for the given subclass exists. @param subclass The Identifier of the subclass @return True = the node exists */ bool ClassTreeMask::nodeExists(const Identifier* subclass) { for (ClassTreeMaskIterator it = this->root_; it; ++it) if ((*it)->getClass() == subclass) return true; return false; } /** @brief Assignment operator: Adds all rules of the other mask. @param other The other mask @return A reference to the mask itself */ ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other) { // Make a copy to avoid troubles with self-assignments (like A = A). ClassTreeMask temp(other); // Removes all current rules this->reset(); // Copy all rules from the other mask for (ClassTreeMaskIterator it = temp.root_; it; ++it) this->add(it->getClass(), it->isIncluded(), false, false); // Return a reference to the mask itself return (*this); } /** @brief Compares the mask with another mask and returns true if they represent the same logic. @param other The other mask @return True if both masks represent the same logic */ bool ClassTreeMask::operator==(const ClassTreeMask& other) const { ClassTreeMask temp1 = other; ClassTreeMask temp2 = (*this); temp1.clean(); temp2.clean(); ClassTreeMaskIterator it1 = temp1.root_; ClassTreeMaskIterator it2 = temp2.root_; for ( ; it1 && it2; ++it1, ++it2) if (it1->getClass() != it2->getClass()) return false; return true; } /** @brief Compares the mask with another mask and returns true if they represent different logics. @param other The other mask @return True if the masks represent different logics */ bool ClassTreeMask::operator!=(const ClassTreeMask& other) const { return (!((*this) == other)); } /** @brief Prefix operator + does nothing. @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator+() const { return (*this); } /** @brief Prefix operator - inverts the mask. @return The inverted mask */ ClassTreeMask ClassTreeMask::operator-() const { return (!(*this)); } /** @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). @param other The mask to unite with @return The union */ ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const { // Create a new mask ClassTreeMask newmask; // Add all nodes from the first mask, calculate the rule with the or-operation for (ClassTreeMaskIterator it = this->root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false); } // Add all nodes from the second mask, calculate the rule with the or-operation for (ClassTreeMaskIterator it = other.root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass), false, false); } // Drop all redundant rules newmask.clean(); // Return the new mask return newmask; } /** @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too). @param other The mask to intersect with @return The intersection */ ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const { // Create a new mask ClassTreeMask newmask; // Add all nodes from the first mask, calculate the rule with the and-operation for (ClassTreeMaskIterator it = this->root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false); } // Add all nodes from the second mask, calculate the rule with the and-operation for (ClassTreeMaskIterator it = other.root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass), false, false); } // Drop all redundant rules newmask.clean(); // Return the new mask return newmask; } /** @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). @param other The mask to subtract. @return The difference */ ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const { return ((*this) * (!other)); } /** @brief Inverts the mask (all included classes are now excluded and vice versa). @return The complement */ ClassTreeMask ClassTreeMask::operator!() const { // Create a new mask ClassTreeMask newmask; // Add all nodes from the other mask, inverting the rules for (ClassTreeMaskIterator it = this->root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, !this->isIncluded(subclass), false, false); } // Return the new mask return newmask; } /** @brief Unites this mask with another mask. @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other) { (*this) = (*this) + other; return (*this); } /** @brief Intersects this mask with another mask. @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other) { (*this) = (*this) * other; return (*this); } /** @brief Subtracts another mask from this mask. @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other) { (*this) = (*this) - other; return (*this); } /** @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too). @param other The mask to intersect with @return The intersection */ ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const { return ((*this) * other); } /** @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). @param other The mask to unite with @return The union */ ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const { return ((*this) + other); } /** @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). @param other The mask to join with @return The result */ ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const { // Create a new mask ClassTreeMask newmask; // Add all nodes from the first mask, calculate the rule with the xor-operation for (ClassTreeMaskIterator it = this->root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false); } // Add all nodes from the second mask, calculate the rule with the xor-operation for (ClassTreeMaskIterator it = other.root_; it; ++it) { const Identifier* subclass = it->getClass(); newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass), false, false); } // Drop all redundant rules newmask.clean(); // Return the new mask return newmask; } /** @brief Inverts the mask (all included classes are now excluded and vice versa). @return The complement */ ClassTreeMask ClassTreeMask::operator~() const { return (!(*this)); } /** @brief Intersects this mask with another mask (and-operation) @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other) { (*this) = (*this) & other; return (*this); } /** @brief Unites this mask with another mask (or-operation). @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other) { (*this) = (*this) | other; return (*this); } /** @brief Joins this mask with another mask with a xor-operation. @param other The other mask @return A reference to the mask itself */ const ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other) { (*this) = (*this) ^ other; return (*this); } /** @brief Converts the content of a mask into a human readable string and puts it on the ostream. @param out The ostream @param mask The mask @return A reference to the ostream */ std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask) { // Iterate through all rules for (ClassTreeMaskIterator it = mask.root_; it; ++it) { // Calculate the prefix: + means included, - means excluded if (it->isIncluded()) out << '+'; else out << '-'; // Put the name of the corresponding class on the stream out << it->getClass()->getName() << ' '; } return out; } // ################################### // ### ClassTreeMaskObjectIterator ### // ################################### /** @brief Initializes the iterator from a given ClassTreeMask. @param mask The mask */ ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator=(const ClassTreeMask& mask) { // Clear everything, use a cleaned copy of the mask this->subclasses_.clear(); ClassTreeMask temp = mask; temp.clean(); // Create the subclass-list by going through the mask-tree, starting with the root-node this->create(temp.root_); // Move the subclass-iterator to the beginning of the subclass-list this->subclassIterator_ = this->subclasses_.begin(); // If there is a first subclass, move the object-iterator to the first object of this class. Else go to the end if (this->subclassIterator_ != this->subclasses_.end()) this->objectIterator_ = Context::getRootContext()->getObjectList(this->subclassIterator_->first)->begin(); else this->objectIterator_ = ObjectList::end(); // Check if the iterator points on a valid object. If not, go to the next object by calling ++ if (!this->objectIterator_ || (this->subclassIterator_->second && !this->objectIterator_->isExactlyA(this->subclassIterator_->first))) this->operator++(); return (*this); } /** @brief Iterate to the next object (if any). @return The iterator itself */ const ClassTreeMaskObjectIterator& ClassTreeMaskObjectIterator::operator++() { if (this->objectIterator_) { // The iterator points on a valid object, therefore we also have a valid subclass-iterator at the moment do { // Go to the next object ++this->objectIterator_; while (!this->objectIterator_) { // We reached the end of the current objectlist - go to the next class ++this->subclassIterator_; // Check if there really is a next class. If yes, move the object-iterator to the first object if (this->subclassIterator_ != this->subclasses_.end()) this->objectIterator_ = Context::getRootContext()->getObjectList(this->subclassIterator_->first)->begin(); else return (*this); } // Repeat this until we reach a valid object or the end } while (this->subclassIterator_->second && !this->objectIterator_->isExactlyA(this->subclassIterator_->first)); } return (*this); } /** @brief Recursive function to create the Iterators subclass-list by going through the node-tree of the mask. @param node The current node */ void ClassTreeMaskObjectIterator::create(ClassTreeMaskNode* node) { // Add the class of this node to the list, if the class is included if (node->isIncluded()) { // If there are some subnodes, the bool is "true", meaning we have to check for the exact clss when iterating if (node->hasSubnodes()) this->subclasses_.insert(this->subclasses_.end(), std::pair(node->getClass(), true)); else this->subclasses_.insert(this->subclasses_.end(), std::pair(node->getClass(), false)); } // Now check if the node has subnodes if (node->hasSubnodes()) { // Get all _direct_ children of the nodes class std::set directChildren = node->getClass()->getDirectChildren(); // Iterate through all subnodes for (std::list::iterator it1 = node->subnodes_.begin(); it1 != node->subnodes_.end(); ++it1) { // Recursive call to this function with the subnode this->create(*it1); // Only execute the following code if the current node is included, meaning some of the subnodes might be included too if (node->isIncluded()) { scanChildren: // This is a label for goto // Iterate through all direct children for (std::set::iterator it2 = directChildren.begin(); it2 != directChildren.end(); ++it2) { // Check if the subnode (it1) is a child of the directChild (it2) if ((*it1)->getClass()->isA(*it2)) { // Yes it is - remove the directChild (it2) from the list, because it will already be handled by a recursive call to the create() function directChildren.erase(it2); // Check if the removed directChild was exactly the subnode if (!(*it1)->getClass()->isExactlyA(*it2)) { // No, it wasn't exactly the subnode - therefore there are some classes between // Add the previously removed directChild (it2) to the subclass-list this->subclasses_.insert(this->subclasses_.end(), std::pair(*it2, true)); // Insert all directChildren of the directChild directChildren.insert((*it2)->getDirectChildrenBegin(), (*it2)->getDirectChildrenEnd()); // Restart the scan with the expanded set of directChildren goto scanChildren; } break; } } } } // Now add all directChildren which don't have subnodes on their own to the subclass-list // The bool is "false", meaning they have no subnodes and therefore need no further checks if (node->isIncluded()) for (std::set::iterator it = directChildren.begin(); it != directChildren.end(); ++it) this->subclasses_.insert(this->subclasses_.end(), std::pair(*it, false)); } } }