Make Group searching robust for cyclic dependencies. fixes #0002567

This commit is contained in:
Stefan Tröger
2017-08-04 07:06:58 +02:00
committed by wmayer
parent f34c77211a
commit 96f8d944f8
3 changed files with 66 additions and 19 deletions

View File

@@ -167,15 +167,28 @@ DocumentObject *GroupExtension::getObject(const char *Name) const
bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
{
if(obj == getExtendedObject())
return false;
const std::vector<DocumentObject*>& grp = Group.getValues();
for (std::vector<DocumentObject*>::const_iterator it = grp.begin(); it != grp.end(); ++it) {
if (*it == obj) {
for (auto child : grp) {
if(!child)
continue;
if (child == obj) {
return true;
} else if ( recursive && (*it)->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
} else if (child == getExtendedObject()) {
Base::Exception("Cyclic dependencies detected: Search cannot be performed");
} else if ( recursive && child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
App::GroupExtension *subGroup = static_cast<App::GroupExtension *> (
(*it)->getExtension(GroupExtension::getExtensionClassTypeId()));
child->getExtension(GroupExtension::getExtensionClassTypeId()));
std::vector<const GroupExtension*> history;
history.push_back(this);
if (subGroup->hasObject (obj, recursive)) {
if (subGroup->recursiveHasObject (obj, subGroup, history)) {
return true;
}
}
@@ -184,22 +197,45 @@ bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
return false;
}
bool GroupExtension::isChildOf(const GroupExtension* group) const
{
const std::vector<DocumentObject*>& grp = group->Group.getValues();
for (std::vector<DocumentObject*>::const_iterator it = grp.begin(); it != grp.end(); ++it) {
if (*it == getExtendedObject())
return true;
if ((*it)->hasExtension(GroupExtension::getExtensionClassTypeId())) {
if (this->isChildOf(static_cast<GroupExtension*>((*it)->getExtension(GroupExtension::getExtensionClassTypeId()))))
bool GroupExtension::recursiveHasObject(const DocumentObject* obj, const GroupExtension* group,
std::vector< const GroupExtension* > history) const {
//the purpose is to prevent infinite recursion when groups form a cyclic graph. To do this
//we store every group we processed on the current leave of the tree, and if we reach an
//already processed group we know that it not really is a tree but a cycle.
history.push_back(this);
for (auto child : group->Group.getValues()) {
if(!child)
continue;
if (child == obj) {
return true;
} else if ( child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
auto ext = child->getExtensionByType<GroupExtension>();
if(std::find(history.begin(), history.end(), ext) != history.end())
Base::Exception("Cyclic dependencies detected: Search cannot be performed");
if (recursiveHasObject(obj, ext, history)) {
return true;
}
}
}
return false;
}
bool GroupExtension::isChildOf(const GroupExtension* group, bool recursive) const
{
return group->hasObject(getExtendedObject(), recursive);
}
std::vector<DocumentObject*> GroupExtension::getObjects() const
{
return Group.getValues();