|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
#include <stack> |
|
|
|
|
#include "deptree.h" |
|
|
|
|
|
|
|
|
|
int DepTree::CreateNodeFromVar(const std::string& var, UsedType& used, CallStack& callstack) |
|
|
|
@ -142,3 +143,198 @@ DepTree* DepTree::FindNodeByVar(const std::string& var) const
|
|
|
|
|
while(curnode->parents.size()!=0) curnode=*(curnode->parents.begin()); |
|
|
|
|
return curnode->FindNodeByVarFromCurrent(var); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DepTree::LeafVector DepTree::FindLeafNodes() const |
|
|
|
|
{ |
|
|
|
|
LeafVector leafs; |
|
|
|
|
std::stack<NodeVector::const_iterator> 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<DepTree*>(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 ("<<G_tosave[leaf->index]->Dump()<<")"<<std::endl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(DepTree::PRINT==leaf->type) |
|
|
|
|
{ |
|
|
|
|
COUT(INFO)<<"print ("<<G_toprint[leaf->index]->Dump()<<")"<<std::endl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(DepTree::VAR==leaf->type) |
|
|
|
|
{ |
|
|
|
|
err=false; |
|
|
|
|
ob=G_vars.at(leaf->name); |
|
|
|
|
// Main working call
|
|
|
|
|
eob=ob->Evaluate(&err); |
|
|
|
|
if(err) |
|
|
|
|
{ |
|
|
|
|
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; |
|
|
|
|
// Begin locked section (errflag set)
|
|
|
|
|
mtx[0].lock(); |
|
|
|
|
*errflag=1; |
|
|
|
|
mtx[0].unlock(); |
|
|
|
|
// End locked section
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// eob is evaluated object
|
|
|
|
|
if(0!=eob) delete ob; |
|
|
|
|
else eob=ob; |
|
|
|
|
G_vars.erase(leaf->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 ("<<G_tosave[leaf->index]->Dump()<<")"<<std::endl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(DepTree::PRINT==leaf->type) |
|
|
|
|
{ |
|
|
|
|
COUT(INFO)<<"print ("<<G_toprint[leaf->index]->Dump()<<")"<<std::endl; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(DepTree::VAR==leaf->type) |
|
|
|
|
{ |
|
|
|
|
err=false; |
|
|
|
|
ob=G_vars.at(leaf->name); |
|
|
|
|
// Main working call
|
|
|
|
|
eob=ob->Evaluate(&err); |
|
|
|
|
if(err) |
|
|
|
|
{ |
|
|
|
|
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; |
|
|
|
|
*errflag=1; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// eob is evaluated object
|
|
|
|
|
if(0!=eob) delete ob; |
|
|
|
|
else eob=ob; |
|
|
|
|
G_vars.erase(leaf->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; |
|
|
|
|
} |
|
|
|
|