#include #include "deptree.h" int DepTree::CreateNodeFromVar(const std::string& var, UsedType& used, CallStack& callstack) { COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<UsedIdents(ids); type=DepTree::VAR; name=var; DepTree* d; int ret; callstack.insert(this); for(auto& i:ids) { d=FindNodeByVar(i); if(d==0) { auto n=*childrens.insert(new DepTree).first; n->parents.insert(this); ret=n->CreateNodeFromVar(i,used,callstack); if(ret!=0) { COUT(ERROR)<<" in definition of variable "<parents.insert(this); } } callstack.erase(this); return 0; } int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, UsedType& used) { if(list!=DepTree::SAVE && list!=DepTree::PRINT) { COUT(ERROR)<<"Internal error, incorrect NodeType in DepTree::CreateNodeFromSP()."<Dump()< ids; CallStack callstack; type=list; index=ind; if(type==DepTree::SAVE) G_tosave[index]->UsedIdents(ids); else if(type==DepTree::PRINT) G_toprint[index]->UsedIdents(ids); DepTree* d; int ret; for(auto& i:ids) { d=FindNodeByVar(i); if(d==0) { auto n=*childrens.insert(new DepTree).first; n->parents.insert(this); ret=n->CreateNodeFromVar(i,used,callstack); if(ret!=0) { COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive "<<((type==DepTree::SAVE)?G_tosave:G_toprint)[index]->Dump()<<"."<parents.insert(this); } } return 0; } int DepTree::CreateGlobalTree(UsedType& used) { if(parents.size()!=0) { COUT(ERROR)<<"Internal error, DepTree::CreateGlobalTree() call for non-root node."<parents.insert(this); auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,used); if(ret!=0) return ret; } for(G_toType::size_type i=0; iparents.insert(this); auto ret=n->CreateNodeFromSP(DepTree::PRINT,i,used); if(ret!=0) return ret; } return 0; } DepTree* DepTree::FindNodeByVarFromCurrent(const std::string& var) const { if(type==DepTree::VAR && name==var) return const_cast(this); DepTree* d; for(auto& i:childrens) { d=i->FindNodeByVarFromCurrent(var); if(d!=0) return d; } return 0; } DepTree* DepTree::FindNodeByVar(const std::string& var) const { const DepTree* curnode=this; while(curnode->parents.size()!=0) curnode=*(curnode->parents.begin()); return curnode->FindNodeByVarFromCurrent(var); } DepTree::LeafVector DepTree::FindLeafNodes() const { LeafVector leafs; std::stack path,ends; NodeVector::const_iterator it,end; // define isvisited as reversion of last visited bool isvisited=!visited; // ascending to root const DepTree* root=this; while(root->parents.size()!=0) root=*(root->parents.begin()); const DepTree* curnode=root; curnode->visited=isvisited; it=curnode->childrens.begin(); end=curnode->childrens.end(); while(true) { if(it!=end) { if((*it)->visited==isvisited) {it++; continue;} path.push(it); ends.push(end); curnode=(*it); curnode->visited=isvisited; it=curnode->childrens.begin(); end=curnode->childrens.end(); if(it==end) leafs.push_back(const_cast(curnode)); } else { if(path.size()==0) break; it=path.top(); path.pop(); end=ends.top(); ends.pop(); it++; } } return leafs; } // Multi-threaded version void TreeEvaluate(std::mutex* mtx, int* errflag, DepTree::LeafVector* leafs, const DepTree* root) { // mtx[0] - mutex for manipulating with LeafVector // mtx[1] - mutex for manipulating with tree DepTree* leaf; ObjectBase *ob,*eob; bool err; while(true) { // Begin locked section (errflag check, leafs manipulations) mtx[0].lock(); // Is was error? if(0!=errflag) {mtx[0].unlock(); return;} // Is work finished? if(0==root->childrens.size()) {mtx[0].unlock(); return;} // Is jobs awaiting? if(0==leafs->size()) {mtx[0].unlock(); std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue;} // Select working node leaf=*(leafs->begin()); // and remove its from list leafs->erase(leafs->begin()); mtx[0].unlock(); // End locked section if(DepTree::SAVE==leaf->type) { COUT(INFO)<<"save ("<index]->Dump()<<")"<type) { COUT(INFO)<<"print ("<index]->Dump()<<")"<type) { err=false; ob=G_vars.at(leaf->name); // Main working call eob=ob->Evaluate(&err); if(err) { COUT(ERROR)<<" in definition of variable "<name<name); // Concurrent access is safe // Begin locked section mtx[1].lock(); for(auto& i:leaf->parents) { // leaf not children of anyone i->childrens.erase(leaf); // Replace variable on eob if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob); if(DepTree::VAR==i->type) { ob=G_vars[i->name]->ReplaceVar(leaf->name,eob); if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;} } // If node have no children, it's a new leaf node if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i); } mtx[1].unlock(); // End locked section leaf->parents.clear(); delete leaf; } } } // Single-threaded version void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) { DepTree* leaf; ObjectBase *ob,*eob; bool err; while(0!=leafs->size()) { // Select working node leaf=*(leafs->begin()); // and remove its from list leafs->erase(leafs->begin()); if(DepTree::SAVE==leaf->type) { COUT(INFO)<<"save ("<index]->Dump()<<")"<type) { COUT(INFO)<<"print ("<index]->Dump()<<")"<type) { err=false; ob=G_vars.at(leaf->name); // Main working call eob=ob->Evaluate(&err); if(err) { COUT(ERROR)<<" in definition of variable "<name<name); // Concurrent access is safe for(auto& i:leaf->parents) { // leaf not children of anyone i->childrens.erase(leaf); // Replace variable on eob if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob); if(DepTree::VAR==i->type) { ob=G_vars[i->name]->ReplaceVar(leaf->name,eob); if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;} } // If node have no children, it's a new leaf node if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i); } leaf->parents.clear(); delete leaf; } } } int DepTree::EvaluateTree() { int errflag=0; LeafVector leafs=FindLeafNodes(); TreeEvaluate(&errflag,&leafs); return errflag; }