App: Remove old DAG implementation.

This commit is contained in:
Joao Matos
2025-02-26 20:09:40 +00:00
committed by Chris Hennes
parent 46b9ff9c50
commit 006feaf276
7 changed files with 17 additions and 312 deletions

View File

@@ -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

View File

@@ -78,13 +78,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include <boost/bimap.hpp>
#include <boost/graph/strong_components.hpp>
#ifdef USE_OLD_DAG
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/visitors.hpp>
#endif // USE_OLD_DAG
#include <boost/regex.hpp>
#include <random>
#include <unordered_map>
@@ -2934,15 +2927,7 @@ std::vector<App::Document*> Document::getDependentDocuments(std::vector<App::Doc
void Document::_rebuildDependencyList(const std::vector<App::DocumentObject*>& 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<App::DocumentObject*>& 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<Document::Status, Document> exe(Document::Recomputing, this);
// delete recompute log
d->clearRecomputeLog();
// updates the dependency graph
_rebuildDependencyList(objs);
std::list<Vertex> 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<DocumentObject*, Vertex>::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<DocumentObject*> recomputeList;
for (std::list<Vertex>::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<DocumentObject*>::const_iterator it = recomputeList.begin();
it != recomputeList.end();
++it) {
std::clog << " " << (*it)->getNameInDocument() << std::endl;
}
#endif
for (std::list<Vertex>::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<Vertex, DocumentObject*>::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<App::DocumentObject*>& objs,
bool force,
bool* hasError,
@@ -3315,8 +3150,6 @@ int Document::recompute(const std::vector<App::DocumentObject*>& 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<Vertex, DocumentObject*>::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);

View File

@@ -468,27 +468,11 @@ std::vector<App::DocumentObject*> DocumentObject::getOutListOfProperty(App::Prop
return ret;
}
#ifdef USE_OLD_DAG
std::vector<App::DocumentObject*> DocumentObject::getInList(void) const
{
if (_pDoc) {
return _pDoc->getInList(this);
}
else {
return std::vector<App::DocumentObject*>();
}
}
#else // ifndef USE_OLD_DAG
const std::vector<App::DocumentObject*>& 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<App::DocumentObject*>& inSet,
bool recursive,
std::vector<App::DocumentObject*>* inList) const
{
#ifdef USE_OLD_DAG
std::map<DocumentObject*, std::set<App::DocumentObject*>> 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<DocumentObject*> pendings;
pendings.push(const_cast<DocumentObject*>(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<App::DocumentObject*>& inSet,
}
}
}
#endif
}
std::set<App::DocumentObject*> DocumentObject::getInListEx(bool recursive) const
@@ -618,7 +565,6 @@ std::vector<App::DocumentObject*> 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)

View File

@@ -293,12 +293,8 @@ public:
void clearOutListCache() const;
/// get all possible paths from this to another object following the OutList
std::vector<std::list<App::DocumentObject*>> getPathsByOutList(App::DocumentObject* to) const;
#ifdef USE_OLD_DAG
/// get all objects link to this object
std::vector<App::DocumentObject*> getInList(void) const
#else
const std::vector<App::DocumentObject*>& getInList() const;
#endif
/// get all objects link directly or indirectly to this object
std::vector<App::DocumentObject*> getInListRecursive() const;
/** Get a set of all objects linking to this object, including possible external parent objects

View File

@@ -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<App::DocumentObject>()) {
@@ -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<App::DocumentObject>()) {
@@ -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<DocumentObject*>(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>()) {
App::DocumentObject* parent = static_cast<DocumentObject*>(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<DocumentObject*>& 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<DocumentObject*>& 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>()) {
App::DocumentObject* parent = static_cast<DocumentObject*>(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<App::DocumentObject>()) {
@@ -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<App::DocumentObject>(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<DocumentObject*>& 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<DocumentObject*>& lValue,
}
}
}
#endif
aboutToSetValue();
_lValueList = lValue;
@@ -2338,7 +2324,6 @@ void PropertyLinkSubList::setValues(std::vector<DocumentObject*>&& 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<DocumentObject*>&& lValue,
}
}
}
#endif
aboutToSetValue();
_lValueList = std::move(lValue);
@@ -2382,7 +2366,6 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vector<std
auto parent = dynamic_cast<App::DocumentObject*>(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<std
}
}
}
#endif
aboutToSetValue();
std::size_t size = SubList.size();
@@ -2431,7 +2413,6 @@ void PropertyLinkSubList::addValue(App::DocumentObject* obj,
auto parent = Base::freecad_dynamic_cast<App::DocumentObject>(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<DocumentObject*> valueList;
std::vector<std::string> 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;

View File

@@ -464,7 +464,6 @@ void TransactionDocumentObject::applyDel(Document& Doc, TransactionalObject* pcO
if (status == Del) {
DocumentObject* obj = static_cast<DocumentObject*>(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<DocumentObject*>(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
}
}

View File

@@ -92,11 +92,6 @@ struct DocumentP
unsigned int UndoMaxStackSize;
std::string programVersion;
mutable HasherMap hashers;
#ifdef USE_OLD_DAG
DependencyList DepList;
std::map<DocumentObject*, Vertex> VertexObjectList;
std::map<Vertex, DocumentObject*> vertexMap;
#endif // USE_OLD_DAG
std::multimap<const App::DocumentObject*, std::unique_ptr<App::DocumentObjectExecReturn>>
_RecomputeLog;