From 006feaf276db119ec01071aa72c5c2300d84f0f6 Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Wed, 26 Feb 2025 20:09:40 +0000 Subject: [PATCH] App: Remove old DAG implementation. --- src/App/CMakeLists.txt | 3 - src/App/Document.cpp | 181 ------------------------------------ src/App/DocumentObject.cpp | 78 ---------------- src/App/DocumentObject.h | 4 - src/App/PropertyLinks.cpp | 54 ++++------- src/App/Transactions.cpp | 4 - src/App/private/DocumentP.h | 5 - 7 files changed, 17 insertions(+), 312 deletions(-) diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index cc3c5481a2..312b96fac2 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -20,9 +20,6 @@ IF(DOCDIR) add_definitions(-DDOCDIR="${DOCDIR}") ENDIF(DOCDIR) -#if you want to use the old DAG structure uncomment this line -#add_definitions(-DUSE_OLD_DAG) - # ----------------------------------------------------------------------------- #write relevant cmake variables to a file for later access with python. Exported are all variables diff --git a/src/App/Document.cpp b/src/App/Document.cpp index f0c5d0c0c6..ecf12cc3a7 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -78,13 +78,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees. #include #include -#ifdef USE_OLD_DAG -#include -#include -#include -#include -#endif // USE_OLD_DAG - #include #include #include @@ -2934,15 +2927,7 @@ std::vector Document::getDependentDocuments(std::vector& objs) { -#ifdef USE_OLD_DAG - _buildDependencyList(objs.empty() ? d->objectArray : objs, - false, - 0, - &d->DepList, - &d->VertexObjectList); -#else (void)objs; -#endif } /** @@ -2973,156 +2958,6 @@ void Document::renameObjectIdentifiers( } } -#ifdef USE_OLD_DAG -int Document::recompute(const std::vector& objs, bool force) -{ - if (testStatus(Document::Recomputing)) { - // this is clearly a bug in the calling instance - throw Base::RuntimeError("Nested recomputes of a document are not allowed"); - } - - int objectCount = 0; - - // The 'SkipRecompute' flag can be (tmp.) set to avoid too many - // time expensive recomputes - if (!force && testStatus(Document::SkipRecompute)) { - return 0; - } - - Base::ObjectStatusLocker exe(Document::Recomputing, this); - - // delete recompute log - d->clearRecomputeLog(); - - // updates the dependency graph - _rebuildDependencyList(objs); - - std::list make_order; - DependencyList::out_edge_iterator j, jend; - - try { - // this sort gives the execute - boost::topological_sort(d->DepList, std::front_inserter(make_order)); - } - catch (const std::exception& e) { - std::cerr << "Document::recompute: " << e.what() << std::endl; - return -1; - } - - // caching vertex to DocObject - for (std::map::const_iterator It1 = d->VertexObjectList.begin(); - It1 != d->VertexObjectList.end(); - ++It1) { - d->vertexMap[It1->second] = It1->first; - } - -#ifdef FC_LOGFEATUREUPDATE - std::clog << "make ordering: " << std::endl; -#endif - - std::set recomputeList; - - for (std::list::reverse_iterator i = make_order.rbegin(); i != make_order.rend(); ++i) { - DocumentObject* Cur = d->vertexMap[*i]; - // Because of PropertyXLink, we should account for external objects - // TODO: make sure it is safe to rely on getNameInDocument() to check if - // object is in the document. If it crashes, then we should fix the code - // to properly nullify getNameInDocument(), rather than revert back to - // the inefficient isIn() - // if (!Cur || !isIn(Cur)) continue; - if (!Cur || !Cur->getNameInDocument()) { - continue; - } -#ifdef FC_LOGFEATUREUPDATE - std::clog << Cur->getNameInDocument() << " dep on:"; -#endif - bool NeedUpdate = false; - - // ask the object if it should be recomputed - if (Cur->mustExecute() == 1 || Cur->ExpressionEngine.depsAreTouched()) { -#ifdef FC_LOGFEATUREUPDATE - std::clog << "[touched]"; -#endif - NeedUpdate = true; - } - else { // if (Cur->mustExecute() == -1) - // update if one of the dependencies is touched - for (boost::tie(j, jend) = out_edges(*i, d->DepList); j != jend; ++j) { - DocumentObject* Test = d->vertexMap[target(*j, d->DepList)]; - - if (!Test) { - continue; - } -#ifdef FC_LOGFEATUREUPDATE - std::clog << " " << Test->getNameInDocument(); -#endif - if (Test->isTouched()) { - NeedUpdate = true; -#ifdef FC_LOGFEATUREUPDATE - std::clog << "[touched]"; -#endif - } - } - } - // if one touched recompute - if (NeedUpdate) { - Cur->touch(); -#ifdef FC_LOGFEATUREUPDATE - std::clog << " => Recompute feature"; -#endif - recomputeList.insert(Cur); - } -#ifdef FC_LOGFEATUREUPDATE - std::clog << std::endl; -#endif - } - -#ifdef FC_LOGFEATUREUPDATE - std::clog << "Have to recompute the following document objects" << std::endl; - for (std::set::const_iterator it = recomputeList.begin(); - it != recomputeList.end(); - ++it) { - std::clog << " " << (*it)->getNameInDocument() << std::endl; - } -#endif - - for (std::list::reverse_iterator i = make_order.rbegin(); i != make_order.rend(); ++i) { - DocumentObject* Cur = d->vertexMap[*i]; - if (!Cur || !isIn(Cur)) { - continue; - } - - if (recomputeList.find(Cur) != recomputeList.end() - || Cur->ExpressionEngine.depsAreTouched()) { - if (_recomputeFeature(Cur)) { - // if something happened break execution of recompute - d->vertexMap.clear(); - return -1; - } - signalRecomputedObject(*Cur); - ++objectCount; - } - } - - // reset all touched - for (std::map::iterator it = d->vertexMap.begin(); - it != d->vertexMap.end(); - ++it) { - // TODO: check the TODO comments above for details - // if ((it->second) && isIn(it->second)) - if ((it->second) && it->second->getNameInDocument()) { - it->second->purgeTouched(); - } - } - d->vertexMap.clear(); - - signalRecomputed(*this); - - return objectCount; -} - -#else // ifdef USE_OLD_DAG - int Document::recompute(const std::vector& objs, bool force, bool* hasError, @@ -3315,8 +3150,6 @@ int Document::recompute(const std::vector& objs, return objectCount; } -#endif // USE_OLD_DAG - /*! Does almost the same as topologicalSort() until no object with an input degree of zero can be found. It then searches for objects with an output degree of zero until neither @@ -3912,20 +3745,6 @@ void Document::removeObject(const char* sName) signalTransactionRemove(*pos->second, 0); } -#ifdef USE_OLD_DAG - if (!d->vertexMap.empty()) { - // recompute of document is running - for (std::map::iterator it = d->vertexMap.begin(); - it != d->vertexMap.end(); - ++it) { - if (it->second == pos->second) { - it->second = 0; // just nullify the pointer - break; - } - } - } -#endif // USE_OLD_DAG - // Before deleting we must nullify all dependent objects breakDependency(pos->second, true); diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index ef4fdde3a9..138161db7f 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -468,27 +468,11 @@ std::vector DocumentObject::getOutListOfProperty(App::Prop return ret; } -#ifdef USE_OLD_DAG -std::vector DocumentObject::getInList(void) const -{ - if (_pDoc) { - return _pDoc->getInList(this); - } - else { - return std::vector(); - } -} - -#else // ifndef USE_OLD_DAG - const std::vector& DocumentObject::getInList() const { return _inList; } -#endif // if USE_OLD_DAG - - // The original algorithm is highly inefficient in some special case. // Considering an object is linked by every other objects. After excluding this // object, there is another object linked by every other of the remaining @@ -513,41 +497,6 @@ void DocumentObject::getInListEx(std::set& inSet, bool recursive, std::vector* inList) const { -#ifdef USE_OLD_DAG - std::map> outLists; - - // Old DAG does not have pre-built InList, and must calculate The InList by - // going through all objects' OutLists. So we collect all objects and their - // outLists first here. - for (auto doc : GetApplication().getDocuments()) { - for (auto obj : doc->getObjects()) { - if (!obj || !obj->isAttachedToDocument() || obj == this) { - continue; - } - const auto& outList = obj->getOutList(); - outLists[obj].insert(outList.begin(), outList.end()); - } - } - - std::stack pendings; - pendings.push(const_cast(this)); - while (pendings.size()) { - auto obj = pendings.top(); - pendings.pop(); - for (auto& v : outLists) { - if (v.first == obj) { - continue; - } - auto& outList = v.second; - // Check the outList to see if the object is there, and pend the - // object for recursive check if it's not already in the inList - if (outList.find(obj) != outList.end() && inSet.insert(v.first).second && recursive) { - pendings.push(v.first); - } - } - } -#else // USE_OLD_DAG - if (!recursive) { inSet.insert(_inList.begin(), _inList.end()); if (inList) { @@ -570,8 +519,6 @@ void DocumentObject::getInListEx(std::set& inSet, } } } - -#endif } std::set DocumentObject::getInListEx(bool recursive) const @@ -618,7 +565,6 @@ std::vector DocumentObject::getOutListRecursive() const // helper for isInInListRecursive() bool _isInInListRecursive(const DocumentObject* act, const DocumentObject* checkObj, int depth) { -#ifndef USE_OLD_DAG for (auto obj : act->getInList()) { if (obj == checkObj) { return true; @@ -633,11 +579,6 @@ bool _isInInListRecursive(const DocumentObject* act, const DocumentObject* check return true; } } -#else - (void)act; - (void)checkObj; - (void)depth; -#endif return false; } @@ -649,23 +590,17 @@ bool DocumentObject::isInInListRecursive(DocumentObject* linkTo) const bool DocumentObject::isInInList(DocumentObject* linkTo) const { -#ifndef USE_OLD_DAG if (std::find(_inList.begin(), _inList.end(), linkTo) != _inList.end()) { return true; } else { return false; } -#else - (void)linkTo; - return false; -#endif } // helper for isInOutListRecursive() bool _isInOutListRecursive(const DocumentObject* act, const DocumentObject* checkObj, int depth) { -#ifndef USE_OLD_DAG for (auto obj : act->getOutList()) { if (obj == checkObj) { return true; @@ -680,11 +615,6 @@ bool _isInOutListRecursive(const DocumentObject* act, const DocumentObject* chec return true; } } -#else - (void)act; - (void)checkObj; - (void)depth; -#endif return false; } @@ -1321,29 +1251,21 @@ void DocumentObject::unsetupObject() void App::DocumentObject::_removeBackLink(DocumentObject* rmvObj) { -#ifndef USE_OLD_DAG // do not use erase-remove idom, as this erases ALL entries that match. we only want to remove a // single one. auto it = std::find(_inList.begin(), _inList.end(), rmvObj); if (it != _inList.end()) { _inList.erase(it); } -#else - (void)rmvObj; -#endif } void App::DocumentObject::_addBackLink(DocumentObject* newObj) { -#ifndef USE_OLD_DAG // we need to add all links, even if they are available multiple times. The reason for this is // the removal: If a link loses this object it removes the backlink. If we would have added it // only once this removal would clear the object from the inlist, even though there may be other // link properties from this object that link to us. _inList.push_back(newObj); -#else - (void)newObj; -#endif // USE_OLD_DAG } int DocumentObject::setElementVisible(const char* element, bool visible) diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index c26a085731..860d3af357 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -293,12 +293,8 @@ public: void clearOutListCache() const; /// get all possible paths from this to another object following the OutList std::vector> getPathsByOutList(App::DocumentObject* to) const; -#ifdef USE_OLD_DAG /// get all objects link to this object - std::vector getInList(void) const -#else const std::vector& getInList() const; -#endif /// get all objects link directly or indirectly to this object std::vector getInListRecursive() const; /** Get a set of all objects linking to this object, including possible external parent objects diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 8869e199e6..070ce1c5fc 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -690,7 +690,6 @@ PropertyLink::~PropertyLink() void PropertyLink::resetLink() { // in case this property gets dynamically removed -#ifndef USE_OLD_DAG // maintain the back link in the DocumentObject class if it is from a document object if (_pcScope != LinkScope::Hidden && _pcLink && getContainer() && getContainer()->isDerivedFrom()) { @@ -703,8 +702,6 @@ void PropertyLink::resetLink() } } } -#endif - _pcLink = nullptr; } void PropertyLink::setValue(App::DocumentObject* lValue) @@ -716,7 +713,7 @@ void PropertyLink::setValue(App::DocumentObject* lValue) } aboutToSetValue(); -#ifndef USE_OLD_DAG + // maintain the back link in the DocumentObject class if it is from a document object if (_pcScope != LinkScope::Hidden && parent) { // before accessing internals make sure the object is not about to be destroyed @@ -730,7 +727,7 @@ void PropertyLink::setValue(App::DocumentObject* lValue) } } } -#endif + _pcLink = lValue; hasSetValue(); } @@ -895,7 +892,7 @@ PropertyLinkList::PropertyLinkList() = default; PropertyLinkList::~PropertyLinkList() { // in case this property gety dynamically removed -#ifndef USE_OLD_DAG + // maintain the back link in the DocumentObject class if (_pcScope != LinkScope::Hidden && !_lValueList.empty() && getContainer() && getContainer()->isDerivedFrom()) { @@ -910,7 +907,6 @@ PropertyLinkList::~PropertyLinkList() } } } -#endif } void PropertyLinkList::setSize(int newSize) @@ -921,11 +917,10 @@ void PropertyLinkList::setSize(int newSize) continue; } _nameMap.erase(obj->getNameInDocument()); -#ifndef USE_OLD_DAG + if (_pcScope != LinkScope::Hidden) { obj->_removeBackLink(static_cast(getContainer())); } -#endif } _lValueList.resize(newSize); } @@ -955,7 +950,6 @@ void PropertyLinkList::set1Value(int idx, DocumentObject* const& value) _nameMap.clear(); -#ifndef USE_OLD_DAG if (getContainer() && getContainer()->isDerivedFrom()) { App::DocumentObject* parent = static_cast(getContainer()); // before accessing internals make sure the object is not about to be destroyed @@ -969,7 +963,6 @@ void PropertyLinkList::set1Value(int idx, DocumentObject* const& value) } } } -#endif inherited::set1Value(idx, value); } @@ -993,7 +986,6 @@ void PropertyLinkList::setValues(const std::vector& value) } _nameMap.clear(); -#ifndef USE_OLD_DAG // maintain the back link in the DocumentObject class if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -1011,7 +1003,7 @@ void PropertyLinkList::setValues(const std::vector& value) } } } -#endif + inherited::setValues(value); } @@ -1298,7 +1290,7 @@ PropertyLinkSub::PropertyLinkSub() = default; PropertyLinkSub::~PropertyLinkSub() { // in case this property is dynamically removed -#ifndef USE_OLD_DAG + if (_pcLinkSub && getContainer() && getContainer()->isDerivedFrom()) { App::DocumentObject* parent = static_cast(getContainer()); @@ -1310,7 +1302,6 @@ PropertyLinkSub::~PropertyLinkSub() } } } -#endif } void PropertyLinkSub::setSyncSubObject(bool enable) @@ -1340,7 +1331,7 @@ void PropertyLinkSub::setValue(App::DocumentObject* lValue, } } aboutToSetValue(); -#ifndef USE_OLD_DAG + if (parent) { // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers @@ -1353,7 +1344,7 @@ void PropertyLinkSub::setValue(App::DocumentObject* lValue, } } } -#endif + _pcLinkSub = lValue; _cSubList = std::move(subs); if (shadows.size() == _cSubList.size()) { @@ -2176,7 +2167,7 @@ PropertyLinkSubList::PropertyLinkSubList() = default; PropertyLinkSubList::~PropertyLinkSubList() { // in case this property is dynamically removed -#ifndef USE_OLD_DAG + // maintain backlinks if (!_lValueList.empty() && getContainer() && getContainer()->isDerivedFrom()) { @@ -2191,7 +2182,6 @@ PropertyLinkSubList::~PropertyLinkSubList() } } } -#endif } void PropertyLinkSubList::setSyncSubObject(bool enable) @@ -2228,7 +2218,6 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const char* SubName) auto parent = Base::freecad_dynamic_cast(getContainer()); verifyObject(lValue, parent); -#ifndef USE_OLD_DAG // maintain backlinks if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -2244,7 +2233,6 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const char* SubName) } } } -#endif if (lValue) { aboutToSetValue(); @@ -2276,7 +2264,6 @@ void PropertyLinkSubList::setValues(const std::vector& lValue, "PropertyLinkSubList::setValues: size of subelements list != size of objects list"); } -#ifndef USE_OLD_DAG // maintain backlinks. if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -2299,7 +2286,6 @@ void PropertyLinkSubList::setValues(const std::vector& lValue, } } } -#endif aboutToSetValue(); _lValueList = lValue; @@ -2338,7 +2324,6 @@ void PropertyLinkSubList::setValues(std::vector&& lValue, "PropertyLinkSubList::setValues: size of subelements list != size of objects list"); } -#ifndef USE_OLD_DAG // maintain backlinks. if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -2361,7 +2346,6 @@ void PropertyLinkSubList::setValues(std::vector&& lValue, } } } -#endif aboutToSetValue(); _lValueList = std::move(lValue); @@ -2382,7 +2366,6 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector(getContainer()); verifyObject(lValue, parent); -#ifndef USE_OLD_DAG // maintain backlinks. if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -2403,7 +2386,6 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector(getContainer()); verifyObject(obj, parent); -#ifndef USE_OLD_DAG // maintain backlinks. if (parent) { // before accessing internals make sure the object is not about to be destroyed @@ -2454,7 +2435,6 @@ void PropertyLinkSubList::addValue(App::DocumentObject* obj, } } } -#endif std::vector valueList; std::vector subList; @@ -3850,11 +3830,11 @@ void PropertyXLink::restoreLink(App::DocumentObject* lValue) setFlag(LinkDetached, false); setFlag(LinkRestoring); aboutToSetValue(); -#ifndef USE_OLD_DAG + if (!owner->testStatus(ObjectStatus::Destroy) && _pcScope != LinkScope::Hidden) { lValue->_addBackLink(owner); } -#endif + _pcLink = lValue; updateElementReference(nullptr); hasSetValue(); @@ -3910,7 +3890,7 @@ void PropertyXLink::setValue(App::DocumentObject* lValue, } setFlag(LinkDetached, false); -#ifndef USE_OLD_DAG + if (!owner->testStatus(ObjectStatus::Destroy) && _pcScope != LinkScope::Hidden) { if (_pcLink) { _pcLink->_removeBackLink(owner); @@ -3919,7 +3899,7 @@ void PropertyXLink::setValue(App::DocumentObject* lValue, lValue->_addBackLink(owner); } } -#endif + if (docInfo != info) { unlink(); docInfo = info; @@ -3969,11 +3949,11 @@ void PropertyXLink::setValue(std::string&& filename, } setFlag(LinkDetached, false); aboutToSetValue(); -#ifndef USE_OLD_DAG + if (_pcLink && !owner->testStatus(ObjectStatus::Destroy) && _pcScope != LinkScope::Hidden) { _pcLink->_removeBackLink(owner); } -#endif + _pcLink = nullptr; if (docInfo != info) { unlink(); @@ -5965,7 +5945,7 @@ void PropertyXLinkContainer::clearDeps() if (!owner || !owner->isAttachedToDocument()) { return; } -#ifndef USE_OLD_DAG + if (!owner->testStatus(ObjectStatus::Destroy)) { for (auto& v : _Deps) { auto obj = v.first; @@ -5975,7 +5955,7 @@ void PropertyXLinkContainer::clearDeps() } } } -#endif + _Deps.clear(); _XLinks.clear(); _LinkRestored = false; diff --git a/src/App/Transactions.cpp b/src/App/Transactions.cpp index ebf1c47fe7..988e2d20e7 100644 --- a/src/App/Transactions.cpp +++ b/src/App/Transactions.cpp @@ -464,7 +464,6 @@ void TransactionDocumentObject::applyDel(Document& Doc, TransactionalObject* pcO if (status == Del) { DocumentObject* obj = static_cast(pcObj); -#ifndef USE_OLD_DAG // Make sure the backlinks of all linked objects are updated. As the links of the removed // object are never set to [] they also do not remove the backlink. But as they are // not in the document anymore we need to remove them anyway to ensure a correct graph @@ -472,7 +471,6 @@ void TransactionDocumentObject::applyDel(Document& Doc, TransactionalObject* pcO for (auto link : list) { link->_removeBackLink(obj); } -#endif // simply filling in the saved object Doc._removeObject(obj); @@ -485,13 +483,11 @@ void TransactionDocumentObject::applyNew(Document& Doc, TransactionalObject* pcO DocumentObject* obj = static_cast(pcObj); Doc._addObject(obj, _NameInDocument.c_str()); -#ifndef USE_OLD_DAG // make sure the backlinks of all linked objects are updated auto list = obj->getOutList(); for (auto link : list) { link->_addBackLink(obj); } -#endif } } diff --git a/src/App/private/DocumentP.h b/src/App/private/DocumentP.h index c7e73b6098..98b6457939 100644 --- a/src/App/private/DocumentP.h +++ b/src/App/private/DocumentP.h @@ -92,11 +92,6 @@ struct DocumentP unsigned int UndoMaxStackSize; std::string programVersion; mutable HasherMap hashers; -#ifdef USE_OLD_DAG - DependencyList DepList; - std::map VertexObjectList; - std::map vertexMap; -#endif // USE_OLD_DAG std::multimap> _RecomputeLog;