Esempio n. 1
0
void CKadHandler::HandleNodeRes(const CVariant& NodeRes, CKadNode* pNode, CComChannel* pChannel)
{
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRT"))
		LogLine(LOG_DEBUG, L"Recived 'Node Response' from %s", pNode->GetID().ToHex().c_str());

	CVariant List = NodeRes["LIST"];
	if(List.Count() > (uint32)GetParent<CKademlia>()->Cfg()->GetInt("NodeReqCount"))
		throw CException(LOG_ERROR, L"Node returned more nodes than requested (spam)");
	
	SKadData* pData = pChannel->GetData<SKadData>();
	// Note: if pData->pLookup is NULL this was just a bootstrap request

	NodeMap Nodes;
	for(uint32 i = 0; i<List.Count(); i++)
	{
		CPointer<CKadNode> pNewNode = new CKadNode(GetParent<CKademlia>()->Root());
		pNewNode->Load(List.At(i));
		if(GetParent<CKademlia>()->Root()->AddNode(pNewNode) && pData->pLookup)
		{
			CUInt128 uDistance = pData->pLookup->GetID() ^ pNewNode->GetID();
			Nodes.insert(NodeMap::value_type(uDistance, pNewNode));
		}
	}

	if(pData->pLookup)
		GetParent<CKademlia>()->Manager()->AddNodes(pData->pLookup, pNode, pChannel, Nodes);
}
Esempio n. 2
0
    static void addInTree(AstNode* nodep, bool linkable) {
#ifndef VL_LEAK_CHECKS
	if (!linkable) return;  // save some time, else the map will get huge!
#endif
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter == s_nodes.end()) {
#ifdef VL_LEAK_CHECKS
	    nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
#endif
	} else {
	    if (!(iter->second & FLAG_ALLOCATED)) {
#ifdef VL_LEAK_CHECKS
		nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
#endif
	    }
	    if (iter->second & FLAG_IN_TREE) {
		nodep->v3fatalSrc("AstNode is already in tree at another location\n");
	    }
	}
	int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
	if (iter == s_nodes.end()) {
	    s_nodes.insert(make_pair(nodep,or_flags));
	} else {
	    iter->second |= or_flags;
	}
    }
Esempio n. 3
0
		void remove(NetNodeIntern* node) {
			NodeMap::iterator f = nodeMap.find(node);
			if(f != nodeMap.end()) {
				updates.erase(f->second);
				nodeMap.erase(f);
			}
		}
void NodeBasedCellPopulation<DIM>::UpdateMapsAfterRemesh(NodeMap& map)
{
    if (!map.IsIdentityMap())
    {
        UpdateParticlesAfterReMesh(map);

        // Update the mappings between cells and location indices
        ///\todo we want to make mCellLocationMap private - we need to find a better way of doing this
        std::map<Cell*, unsigned> old_map = this->mCellLocationMap;

        // Remove any dead pointers from the maps (needed to avoid archiving errors)
        this->mLocationCellMap.clear();
        this->mCellLocationMap.clear();

        for (std::list<CellPtr>::iterator it = this->mCells.begin();
             it != this->mCells.end();
             ++it)
        {
            unsigned old_node_index = old_map[(*it).get()];

            // This shouldn't ever happen, as the cell vector only contains living cells
            assert(!map.IsDeleted(old_node_index));

            unsigned new_node_index = map.GetNewIndex(old_node_index);
            this->SetCellUsingLocationIndex(new_node_index,*it);
        }

        this->Validate();
    }
}
Esempio n. 5
0
Model::Ptr Model::clone(const std::string& newname) const
{
	NodeMap map;

	Model::Ptr result(new Model());
	if (newname.empty()) {
		result->id = id;
	}
	else {
		result->id = newname;
	}

	result->root = root->clone(map); //this populates map with Old Node -> New Node entries

	for (Controller *obj: controllers) {
		result->addController(obj->clone(map));
	}
	for (Renderable *obj: renderables) {
		result->addRenderable(obj->clone(map));
	}
	for (const auto& entry: nodes) {
		result->addNamedNode(entry.first, map.get(entry.second));
	}

	result->shape = shape;
	
	return result;
}
Esempio n. 6
0
    void handleNodeStatus(const ReceivedDataStructure<protocol::NodeStatus>& msg)
    {
        if (!needToQuery(msg.getSrcNodeID()))
        {
            return;
        }

        NodeData* data = node_map_.access(msg.getSrcNodeID());
        if (data == NULL)
        {
            trace(TraceDiscoveryNewNodeFound, msg.getSrcNodeID().get());

            data = node_map_.insert(msg.getSrcNodeID(), NodeData());
            if (data == NULL)
            {
                getNode().registerInternalFailure("NodeDiscoverer OOM");
                return;
            }
        }
        UAVCAN_ASSERT(data != NULL);

        if (msg.uptime_sec < data->last_seen_uptime)
        {
            trace(TraceDiscoveryNodeRestartDetected, msg.getSrcNodeID().get());
            data->num_get_node_info_attempts = 0;
        }
        data->last_seen_uptime = msg.uptime_sec;

        if (!isRunning())
        {
            startPeriodic(MonotonicDuration::fromMSec(TimerPollIntervalMs));
            trace(TraceDiscoveryTimerStart, getPeriod().toUSec());
        }
    }
Esempio n. 7
0
ExpressionPtr IclHostPlugin::PostVisit(const clang::Expr* expr, const insieme::core::ExpressionPtr& irExpr,
                                               insieme::frontend::conversion::Converter& convFact) {
	NodeManager& mgr = irExpr->getNodeManager();
	IRBuilder builder(mgr);
	const core::lang::BasicGenerator& gen = builder.getLangBasic();
		iclRunKernel = irp::callExpr(pattern::any, irp::literal("icl_run_kernel"),
				var("derefKernel", irp::callExpr(pattern::any, pattern::atom(gen.getRefDeref()), pattern::single(var("kernel", pattern::any)))) <<
				*pattern::any << irp::callExpr(pattern::any, pattern::atom(gen.getVarlistPack()),
				pattern::single(irp::tupleExpr(pattern::any << irp::expressions(*var("args", pattern::any))))));

	core::pattern::TreePattern derefOfIclBuffer = irp::callExpr(pattern::atom(builder.refType(
																					builder.arrayType(builder.genericType("_icl_buffer")))),
																					pattern::atom(gen.getRefDeref()), 
																					pattern::single(var("buffer", pattern::any)));


	NodeMap replacements;
	irp::matchAllPairs(iclRunKernel, irExpr, [&](const NodePtr& matchPtr, const NodeMatch& runKernel) {

		// remove deref from buffers
		for(NodePtr arg : runKernel["args"].getFlattened()) {
			MatchOpt match = derefOfIclBuffer.matchPointer(arg);
			if(match) {
				replacements[match.get().getRoot()] = match.get()["buffer"].getValue();
			}
		}
	});
	if(!replacements.empty())
		return transform::replaceAll(mgr, irExpr, replacements).as<ExpressionPtr>();

	return irExpr;
}
Esempio n. 8
0
void CKadHandler::HandleNodeReq(const CVariant& NodeReq, CKadNode* pNode, CComChannel* pChannel)
{
	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRT"))
		LogLine(LOG_DEBUG, L"Recived 'Node Resuest' to %s", pNode->GetID().ToHex().c_str());

	CVariant NodeRes;

	uint32 uDesiredCount = NodeReq["RCT"];
	if(uDesiredCount == 0)
		throw CException(LOG_ERROR, L"node requested 0 nodes");

	int iMaxState = NodeReq.Get("MNC", NODE_2ND_CLASS);

	NodeMap Nodes;
	if(!NodeReq.Has("TID"))
		GetParent<CKademlia>()->Root()->GetBootstrapNodes(GetParent<CKademlia>()->Root()->GetID(), Nodes, uDesiredCount, pChannel->GetAddress().GetProtocol(), iMaxState);
	else
		GetParent<CKademlia>()->Root()->GetClosestNodes(NodeReq["TID"], Nodes, uDesiredCount, pChannel->GetAddress().GetProtocol(), iMaxState);
	
	CVariant List;
	for(NodeMap::iterator I = Nodes.begin(); I != Nodes.end(); I++)
		List.Append(I->second->Store());
	NodeRes["LIST"] = List;

	if(GetParent<CKademlia>()->Cfg()->GetBool("DebugRT"))
		LogLine(LOG_DEBUG, L"Sending 'Node Response' to %s", pNode->GetID().ToHex().c_str());
	pChannel->QueuePacket(KAD_NODE_RESPONSE, NodeRes);
}
Esempio n. 9
0
void UtilOSMVisitor::MakePowerLine()
{
	m_line = m_util_layer->AddNewLine();

	m_line->m_poles.resize(m_refs.size());
	for (uint r = 0; r < m_refs.size(); r++)
	{
		int idx = m_refs[r];

		// Look for that node by id; if we don't find it, then it wasn't a tower;
		// it was probably a start or end point at a non-tower feature.
		NodeMap::iterator it = m_nodes.find(m_id);
		if (it != m_nodes.end())
		{
			// Connect to a known pole.
			m_line->m_poles[r] = m_nodes[idx].pole;
		}
		else
		{
			// We need to make a new pole node.
			OSMNode &node = m_nodes[idx];

			m_pole = m_util_layer->AddNewPole();
			m_pole->m_id = idx;
			m_pole->m_p = node.p;

			node.pole = m_pole;

			// Then we can connect it
			m_line->m_poles[r] = m_pole;
		}
	}
}
Esempio n. 10
0
    static bool okIfBelow(const AstNode* nodep) {
	// Must be linked to and below current node
	if (!okIfLinkedTo(nodep)) return false;
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter == s_nodes.end()) return false;
	if (!(iter->second & FLAG_UNDER_NOW)) return false;
	return true;
    }
Esempio n. 11
0
DOMNode* ScriptInterpreter::getDOMNodeForDocument(Document* document, Node* node)
{
    if (!document)
        return static_cast<DOMNode*>(domObjects().get(node));
    NodeMap* documentDict = domNodesPerDocument().get(document);
    if (documentDict)
        return documentDict->get(node);
    return NULL;
}
Esempio n. 12
0
    static void prepForTree() {
#ifndef VL_LEAK_CHECKS
	s_nodes.clear();
#endif
	for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
	    it->second &= ~FLAG_IN_TREE;
	    it->second &= ~FLAG_LINKABLE;
	}
    }
Esempio n. 13
0
    // METHODS
    static void deleted(const AstNode* nodep) {
	// Called by operator delete on any node - only if VL_LEAK_CHECKS
	if (debug()>=9) cout<<"-nodeDel:  "<<(void*)(nodep)<<endl;
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
	    ((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted\n");
	}
	if (iter!=s_nodes.end()) s_nodes.erase(iter);
    }
Esempio n. 14
0
    static void setUnder(const AstNode* nodep, bool flag) {
	// Called by BrokenCheckVisitor when each node entered/exited
	if (!okIfLinkedTo(nodep)) return;
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter!=s_nodes.end()) {
	    iter->second &= ~FLAG_UNDER_NOW;
	    if (flag) iter->second |=  FLAG_UNDER_NOW;
	}
    }
Status InitializerDependencyGraph::recursiveTopSort(
    const NodeMap& nodeMap,
    const Node& currentNode,
    std::vector<std::string>* inProgressNodeNames,
    stdx::unordered_set<std::string>* visitedNodeNames,
    std::vector<std::string>* sortedNames) {

    /*
     * The top sort is performed by depth-first traversal starting at each node in the
     * dependency graph, short-circuited any time a node is seen that has already been visited
     * in any traversal.  "visitedNodeNames" is the set of nodes that have been successfully
     * visited, while "inProgressNodeNames" are nodes currently in the exploration chain.  This
     * structure is kept explicitly to facilitate cycle detection.
     *
     * This function implements a depth-first traversal, and is called once for each node in the
     * graph by topSort(), above.
     */

    if ((*visitedNodeNames).count(currentNode.first))
        return Status::OK();

    inProgressNodeNames->push_back(currentNode.first);

    auto firstOccurence =
        std::find(inProgressNodeNames->begin(), inProgressNodeNames->end(), currentNode.first);
    if (std::next(firstOccurence) != inProgressNodeNames->end()) {
        sortedNames->clear();
        std::copy(firstOccurence, inProgressNodeNames->end(), std::back_inserter(*sortedNames));
        std::ostringstream os;
        os << "Cycle in dependendcy graph: " << sortedNames->at(0);
        for (size_t i = 1; i < sortedNames->size(); ++i)
            os << " -> " << sortedNames->at(i);
        return Status(ErrorCodes::GraphContainsCycle, os.str());
    }

    for (const auto& prereq : currentNode.second.prerequisites) {
        auto nextNode = nodeMap.find(prereq);
        if (nextNode == nodeMap.end()) {
            std::ostringstream os;
            os << "Initializer " << currentNode.first << " depends on missing initializer "
               << prereq;
            return {ErrorCodes::BadValue, os.str()};
        }

        Status status = recursiveTopSort(
            nodeMap, *nextNode, inProgressNodeNames, visitedNodeNames, sortedNames);
        if (Status::OK() != status)
            return status;
    }
    sortedNames->push_back(currentNode.first);
    if (inProgressNodeNames->back() != currentNode.first)
        return Status(ErrorCodes::InternalError, "inProgressNodeNames stack corrupt");
    inProgressNodeNames->pop_back();
    visitedNodeNames->insert(currentNode.first);
    return Status::OK();
}
Esempio n. 16
0
void CLookupHistory::AddNodes(const NodeMap& Nodes, const CUInt128& ByID)
{
	for(NodeMap::const_iterator I = Nodes.begin(); I != Nodes.end(); I++)
	{
		LookupNodeMap::iterator J = m_Nodes.find(I->second->GetID());
		if(J == m_Nodes.end())
			J = m_Nodes.insert(LookupNodeMap::value_type(I->second->GetID(), SLookupNode())).first;
		J->second.FoundByIDs.push_back(ByID == 0 ? SELF_NODE : ByID);
	}
}
Esempio n. 17
0
		void pushUpdate(const DataPackage& p) {
			NodeMap::iterator f = nodeMap.find(p.node.get());
			if(f != nodeMap.end()) {
				*f->second = p;
			}
			else {
				updates.push_back(p);
				Updates::iterator& last = nodeMap[p.node.get()] = updates.end(); --last;
			}
		}
Esempio n. 18
0
 void PMap(const NodeMap& m)
 {
   // print out map
   NodeMap::const_iterator it;
   pout() << "Node map has " << m.size() << " nodes\n";
   for (it=m.begin(); it!=m.end(); it++)
   {
     pout() << "node "; PIV(it->first); pout() << ": " << it->second << "\n";
   }
 }
Esempio n. 19
0
    static void addNewed(const AstNode* nodep) {
	// Called by operator new on any node - only if VL_LEAK_CHECKS
	if (debug()) cout<<"-nodeNew:  "<<(void*)(nodep)<<endl;
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) {
	    ((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated\n");
	}
	if (iter == s_nodes.end()) {
	    s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
	}
    }
Esempio n. 20
0
CUInt128 CKademlia::MakeCloseTarget(int *pDistance)
{
	if(!m_pKadHandler)
	{
		if(pDistance)
			*pDistance = -1;
		return 0;
	}

	CUInt128 uMyID = m_pRootZone->GetID();
	NodeMap Nodes;
	m_pRootZone->GetClosestNodes(uMyID, Nodes, Cfg()->GetInt("BucketSize"));
	if(Nodes.size() < 2)
	{
		if(pDistance)
			*pDistance = -1;
		return 0;
	}
	
	// Find Median distance difference between nodes closest to us
	vector<CUInt128> Diff;
	for(NodeMap::iterator np = Nodes.begin(), n = np++; np != Nodes.end(); n = np++)
		Diff.push_back(np->first - n->first);
	CUInt128 Sep = Median(Diff);

	// generate ID that is closer to us than the closest node by a few difference
	CUInt128 uDistance = Nodes.begin()->first;
	for(int i=0; i < 3 && uDistance > Sep; i++)
		uDistance = uDistance - Sep;
	CUInt128 uCloser = uMyID ^ uDistance;

	// count the matchign bits
	UINT uLevel=0;
	for(; uLevel < uMyID.GetBitSize(); uLevel++)
	{
		if(uCloser.GetBit(uLevel) != uMyID.GetBit(uLevel))
			break;
	}

	// add a few more matching bytes
	for(UINT i=0; i < 4 && uLevel < uMyID.GetBitSize() - 1; i++)
	{
		uCloser.SetBit(uLevel, uMyID.GetBit(uLevel));
		uLevel++;
	}

	if(pDistance)
		*pDistance = (int)uMyID.GetBitSize() - uLevel;

	// create a random ID that we are closest to
	CUInt128 uRandom(uCloser, uLevel);
	//wstring sTest = (uMyID ^ uRandom).ToBin();
	return uRandom;
}
Esempio n. 21
0
    static bool okIfLinkedTo(const AstNode* nodep) {
	// Someone has a pointer to this node.  Is it kosher?
	NodeMap::iterator iter = s_nodes.find(nodep);
	if (iter == s_nodes.end()) return false;
#ifdef VL_LEAK_CHECKS
	if (!(iter->second & FLAG_ALLOCATED)) return false;
#endif
	if (!(iter->second & FLAG_IN_TREE)) return false;
	if (!(iter->second & FLAG_LINKABLE)) return false;
	return true;
    }
Esempio n. 22
0
void ScriptInterpreter::forgetDOMNodeForDocument(Document* document, Node* node)
{
    REMOVE_WRAPPER(getDOMNodeForDocument(document, node));
    if (!document) {
        domObjects().remove(node);
        return;
    }
    NodeMap* documentDict = domNodesPerDocument().get(document);
    if (documentDict)
        documentDict->remove(node);
}
Esempio n. 23
0
void ScriptInterpreter::putDOMNodeForDocument(Document* document, Node* node, DOMNode* wrapper)
{
    ADD_WRAPPER(wrapper);
    if (!document) {
        domObjects().set(node, wrapper);
        return;
    }
    NodeMap* documentDict = domNodesPerDocument().get(document);
    if (!documentDict) {
        documentDict = new NodeMap;
        domNodesPerDocument().set(document, documentDict);
    }
    documentDict->set(node, wrapper);
}
Esempio n. 24
0
    void handleGetNodeInfoResponse(const ServiceCallResult<protocol::GetNodeInfo>& result)
    {
        if (result.isSuccessful())
        {
            UAVCAN_TRACE("dynamic_node_id_server::NodeDiscoverer", "GetNodeInfo response from %d",
                         int(result.getCallID().server_node_id.get()));
            finalizeNodeDiscovery(&result.getResponse().hardware_version.unique_id, result.getCallID().server_node_id);
        }
        else
        {
            trace(TraceDiscoveryGetNodeInfoFailure, result.getCallID().server_node_id.get());

            NodeData* const data = node_map_.access(result.getCallID().server_node_id);
            if (data == NULL)
            {
                return;         // Probably it is a known node now
            }

            UAVCAN_TRACE("dynamic_node_id_server::NodeDiscoverer",
                         "GetNodeInfo request to %d has timed out, %d attempts",
                         int(result.getCallID().server_node_id.get()), int(data->num_get_node_info_attempts));
            data->num_get_node_info_attempts++;
            if (data->num_get_node_info_attempts >= MaxAttemptsToGetNodeInfo)
            {
                finalizeNodeDiscovery(NULL, result.getCallID().server_node_id);
                // Warning: data pointer is invalidated now
            }
        }
    }
Esempio n. 25
0
void ScriptInterpreter::markDOMNodesForDocument(Document* doc)
{
    NodePerDocMap::iterator dictIt = domNodesPerDocument().find(doc);
    if (dictIt != domNodesPerDocument().end()) {
        NodeMap* nodeDict = dictIt->second;
        NodeMap::iterator nodeEnd = nodeDict->end();
        for (NodeMap::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) {
            DOMNode* node = nodeIt->second;
            // don't mark wrappers for nodes that are no longer in the
            // document - they should not be saved if the node is not
            // otherwise reachable from JS.
            if (node->impl()->inDocument() && !node->marked())
                node->mark();
        }
    }
}
Esempio n. 26
0
  // recursively delete the stmts and subtrees
  ~TreeNode()
  {
    for (StmtMap::iterator sit = stmtMap.begin(); sit != stmtMap.end(); ++sit) {
      delete sit->second;
    }
    stmtMap.clear();

    for (LoopList::iterator lit = loopList.begin(); lit != loopList.end(); ++lit) {
      delete (*lit)->node;
    }
    loopList.clear();

    for (NodeMap::iterator nit = nodeMap.begin(); nit != nodeMap.end(); ++nit) {
      delete nit->second;
    }
    nodeMap.clear();
  }
void MeshBasedCellPopulationWithGhostNodes<DIM>::UpdateGhostNodesAfterReMesh(NodeMap& rMap)
{
    // Copy mIsGhostNode to a temporary vector
    std::vector<bool> ghost_nodes_before_remesh = mIsGhostNode;

    // Reinitialise mIsGhostNode
    mIsGhostNode.clear();
    mIsGhostNode.resize(this->GetNumNodes());

    // Update mIsGhostNode using the node map
    for (unsigned old_index=0; old_index<rMap.GetSize(); old_index++)
    {
        if (!rMap.IsDeleted(old_index))
        {
            unsigned new_index = rMap.GetNewIndex(old_index);
            mIsGhostNode[new_index] = ghost_nodes_before_remesh[old_index];
        }
    }
}
Esempio n. 28
0
    static void doneWithTree() {
	for (int backs=0; backs<2; backs++) {  // Those with backp() are probably under one leaking without
	    for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
		if ((it->second & FLAG_ALLOCATED)
		    && !(it->second & FLAG_IN_TREE)
		    && !(it->second & FLAG_LEAKED)
		    && (it->first->backp() ? backs==1 : backs==0)) {
		    // Use only AstNode::dump instead of the virtual one, as there
		    // may be varp() and other cross links that are bad.
		    if (v3Global.opt.debugCheck()) {
			cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": ");
			((AstNode*)(it->first))->AstNode::dump(cerr);
			cerr<<endl;
			V3Error::incErrors();
		    }
		    it->second |= FLAG_LEAKED;
		}
	    }
	}
    }
Esempio n. 29
0
void prune_unchanged_wrappers(xmlNodePtr node, NodeMap & nmap)
{
	if (node == nullptr)
		return;

	if (node->type != XML_ENTITY_REF_NODE)
	{
		for (xmlNodePtr child = node->children; child != nullptr; child = child->next)
			prune_unchanged_wrappers(child, nmap);
	}

	if (node->_private != nullptr)
	{
		const NodeMap::iterator pos = nmap.find(reinterpret_cast<ePub3::xml::Node*>(node->_private));
		if (pos != nmap.end())
		{
			if (pos->second == node->type)
				nmap.erase(pos);
			else
				node->_private = nullptr;
		}
	}

	switch (node->type)
	{
	case XML_DTD_NODE:
	case XML_ATTRIBUTE_NODE:
	case XML_ELEMENT_DECL:
	case XML_ATTRIBUTE_DECL:
	case XML_ENTITY_DECL:
	case XML_DOCUMENT_NODE:
		return;
	default:
		break;
	}

	for (xmlAttrPtr attr = node->properties; attr != nullptr; attr = attr->next) {
		find_wrappers(reinterpret_cast<xmlNodePtr>(attr), nmap);
	}
}
Esempio n. 30
0
File: MLGDao.cpp Progetto: caomw/mld
HLink MLGDao::mirrorEdge( const HLink& current, Direction dir, const Layer& newLayer, NodeMap& nodeMap )
{
    // Find equivalent in top layer
    Node topSrc;
    auto it = nodeMap.find(current.source());
    if( it != nodeMap.end() ) { // not found
        topSrc = it->second;
    }
    else {
        topSrc = mirrorNode(current.source(), dir, newLayer);
        nodeMap.emplace(current.source(), topSrc);
    }

    Node topTgt;
    it = nodeMap.find(current.target());
    if( it != nodeMap.end() ) { // not found
        topTgt = it->second;
    }
    else {
        topTgt = mirrorNode(current.target(), dir, newLayer);
        // Add to map to retrieve edges
        nodeMap.emplace(current.target(), topTgt);
    }
    // Add new HLink
    return m_link->addHLink(topSrc.id(), topTgt.id(), current.weight());
}