From 68c6ede2446fc36861160f28d94633b40f597910 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Sat, 26 Jul 2014 14:58:06 +0200 Subject: [PATCH] data: saving graph nodes with short name only This change saves only the short names in the node, getName() no only gives the short version. The fullName is assembled from the parent nodes on demand using the getFullName() method. --- src/lib/data/Storage.cpp | 11 ++- src/lib/data/Storage.h | 2 +- src/lib/data/graph/Graph.cpp | 115 +++++++++++++++++++++--------- src/lib/data/graph/Graph.h | 8 ++- src/lib/data/graph/Node.cpp | 48 ++++++++++++- src/lib/data/graph/Node.h | 4 ++ src/lib/utility/utilityString.cpp | 22 ------ src/lib/utility/utilityString.h | 31 +++++++- src/test/GraphTestSuite.h | 102 ++++++++++++++++++++++++-- 9 files changed, 268 insertions(+), 75 deletions(-) diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 808f31ab..391b548a 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -238,26 +238,23 @@ void Storage::onGlobalVariableUsageParsed( addTokenLocation(edge, location); } -Id Storage::getIdForNodeWithName(const std::string& name) const +Id Storage::getIdForNodeWithName(const std::string& fullName) const { - Node* node = m_graph.findNode([&](Node* node){ - return node->getName() == name; - }); - + Node* node = m_graph.getNode(fullName); return (node ? node->getId() : 0); } std::string Storage::getNameForNodeWithId(Id id) const { Node* node = m_graph.getNodeById(id); - return (node ? node->getName() : ""); + return (node ? node->getFullName() : ""); } std::vector Storage::getNamesForNodesWithNamePrefix(const std::string& prefix) const { std::vector names; m_graph.forEachNode([&](Node* node){ - const std::string& nodeName = node->getName(); + const std::string& nodeName = node->getFullName(); if (utility::isPrefix(prefix, nodeName)) { names.push_back(nodeName); diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 4e45deac..681ee4ea 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -64,7 +64,7 @@ public: const ParseLocation& location, const std::string& userName, const std::string& usedName); // GraphAccess implementation - virtual Id getIdForNodeWithName(const std::string& name) const; + virtual Id getIdForNodeWithName(const std::string& fullName) const; virtual std::string getNameForNodeWithId(Id id) const; virtual std::vector getNamesForNodesWithNamePrefix(const std::string& prefix) const; virtual std::vector getIdsOfNeighbours(const Id id) const; diff --git a/src/lib/data/graph/Graph.cpp b/src/lib/data/graph/Graph.cpp index 0a679360..e9a83904 100644 --- a/src/lib/data/graph/Graph.cpp +++ b/src/lib/data/graph/Graph.cpp @@ -16,12 +16,15 @@ Graph::~Graph() Node* Graph::getNode(const std::string& fullName) const { - return findNode( - [fullName](Node* n) - { - return n->getName() == fullName; - } - ); + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + + if (node && !names.size()) + { + return node; + } + + return nullptr; } Edge* Graph::getEdge(Edge::EdgeType type, Node* from, Node* to) const @@ -71,8 +74,9 @@ Node* Graph::createNodeHierarchy(const std::string& fullName) Node* Graph::createNodeHierarchy(Node::NodeType type, const std::string& fullName) { - Node* node = getNode(fullName); - if (node) + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + if (node && !names.size()) { if (type != Node::NODE_UNDEFINED) { @@ -81,7 +85,7 @@ Node* Graph::createNodeHierarchy(Node::NodeType type, const std::string& fullNam return node; } - return insertNodeHierarchy(type, fullName); + return insertNodeHierarchy(type, names, node); } Node* Graph::createNodeHierarchyWithDistinctSignature(const std::string& fullName, const std::string& signature) @@ -92,10 +96,12 @@ Node* Graph::createNodeHierarchyWithDistinctSignature(const std::string& fullNam Node* Graph::createNodeHierarchyWithDistinctSignature( Node::NodeType type, const std::string& fullName, const std::string& signature ){ - Node* node = getNode(fullName); - if (node) + std::deque names = utility::split>(fullName, DELIMITER); + Node* node = getLastValidNode(&names); + if (node && !names.size()) { - if (node->getComponent()->getSignature() == signature) + TokenComponentSignature* sigComponent = node->getComponent(); + if (sigComponent && sigComponent->getSignature() == signature) { if (type != Node::NODE_UNDEFINED) { @@ -104,11 +110,35 @@ Node* Graph::createNodeHierarchyWithDistinctSignature( return node; } - node = insertNode(type, fullName, node->getParentNode()); + Node* parentNode = node->getParentNode(); + const std::string& name = node->getName(); + + std::function findSignature = + [&name, &signature](Node* n) + { + TokenComponentSignature* c = n->getComponent(); + return n->getName() == name && c && c->getSignature() == signature; + }; + + if (parentNode) + { + node = parentNode->findChildNode(findSignature); + } + else + { + node = findNode(findSignature); + } + + if (node) + { + return node; + } + + node = insertNode(type, name, parentNode); } else { - node = insertNodeHierarchy(type, fullName); + node = insertNodeHierarchy(type, names, node); } node->addComponentSignature(std::make_shared(signature)); @@ -311,43 +341,60 @@ Edge* Graph::addEdgeAsPlainCopy(Edge* edge) const std::string Graph::DELIMITER = "::"; -Node* Graph::insertNodeHierarchy(Node::NodeType type, const std::string& fullName) +Node* Graph::getLastValidNode(std::deque* names) const { - Node* node = nullptr; - std::vector names = utility::split(fullName, DELIMITER); - std::string name; + const std::string& name = names->front(); - for (size_t i = 0; i < names.size(); i++) - { - if (i > 0) + Node* node = findNode( + [&name](Node* n) { - name += DELIMITER; + return n->getName() == name && n->getParentNode() == nullptr; } - name += names[i]; + ); - Node* childNode = getNode(name); + if (!node) + { + return nullptr; + } + + names->pop_front(); + + while (names->size()) + { + const std::string& name = names->front(); + Node* childNode = node->findChildNode( + [&name](Node* n) + { + return n->getName() == name; + } + ); if (!childNode) { - if (i == names.size() - 1) - { - childNode = insertNode(type, name, node); - } - else - { - childNode = insertNode(Node::NODE_UNDEFINED, name, node); - } + break; } node = childNode; + names->pop_front(); } return node; } -Node* Graph::insertNode(Node::NodeType type, const std::string& fullName, Node* parentNode) +Node* Graph::insertNodeHierarchy(Node::NodeType type, std::deque names, Node* parentNode) { - std::shared_ptr nodePtr = std::make_shared(type, fullName); + while (names.size()) + { + parentNode = insertNode(names.size() == 1 ? type : Node::NODE_UNDEFINED, names.front(), parentNode); + names.pop_front(); + } + + return parentNode; +} + +Node* Graph::insertNode(Node::NodeType type, const std::string& name, Node* parentNode) +{ + std::shared_ptr nodePtr = std::make_shared(type, name); m_nodes.push_back(nodePtr); Node* node = nodePtr.get(); diff --git a/src/lib/data/graph/Graph.h b/src/lib/data/graph/Graph.h index fb264e6a..a72f4d88 100644 --- a/src/lib/data/graph/Graph.h +++ b/src/lib/data/graph/Graph.h @@ -2,8 +2,9 @@ #define GRAPH_H #include -#include #include +#include +#include #include "data/graph/Edge.h" #include "data/graph/Node.h" @@ -54,8 +55,9 @@ protected: private: static const std::string DELIMITER; - Node* insertNodeHierarchy(Node::NodeType type, const std::string& fullName); - Node* insertNode(Node::NodeType type, const std::string& fullName, Node* parentNode); + Node* getLastValidNode(std::deque* names) const; + Node* insertNodeHierarchy(Node::NodeType type, std::deque names, Node* parentNode); + Node* insertNode(Node::NodeType type, const std::string& name, Node* parentNode); Edge* insertEdge(Edge::EdgeType type, Node* from, Node* to); void removeEdgeInternal(Edge* edge); diff --git a/src/lib/data/graph/Node.cpp b/src/lib/data/graph/Node.cpp index ce91d567..f81443cf 100644 --- a/src/lib/data/graph/Node.cpp +++ b/src/lib/data/graph/Node.cpp @@ -46,6 +46,19 @@ const std::string& Node::getName() const return m_name; } +std::string Node::getFullName() const +{ + Node* parent = getParentNode(); + if (parent) + { + return parent->getFullName() + "::" + m_name; + } + else + { + return m_name; + } +} + const std::vector& Node::getEdges() const { return m_edges; @@ -90,7 +103,7 @@ Edge* Node::findEdge(std::function func) const return *it; } - return NULL; + return nullptr; } Edge* Node::findEdgeOfType(Edge::EdgeType type) const @@ -116,7 +129,28 @@ Edge* Node::findEdgeOfType(Edge::EdgeType type, std::function func) return *it; } - return NULL; + return nullptr; +} + +Node* Node::findChildNode(std::function func) const +{ + std::vector::const_iterator it = find_if(m_edges.begin(), m_edges.end(), + [&func](Edge* e) + { + if (e->getType() == Edge::EDGE_MEMBER) + { + return func(e->getTo()); + } + return false; + } + ); + + if (it != m_edges.end()) + { + return (*it)->getTo(); + } + + return nullptr; } void Node::forEachEdge(std::function func) const @@ -137,6 +171,16 @@ void Node::forEachEdgeOfType(Edge::EdgeType type, std::function fun ); } +void Node::forEachChildNode(std::function func) const +{ + forEachEdgeOfType(Edge::EDGE_MEMBER, + [func](Edge* e) + { + func(e->getTo()); + } + ); +} + bool Node::isNode() const { return true; diff --git a/src/lib/data/graph/Node.h b/src/lib/data/graph/Node.h index dcfc9d5c..19af8ecd 100644 --- a/src/lib/data/graph/Node.h +++ b/src/lib/data/graph/Node.h @@ -38,6 +38,8 @@ public: void setType(NodeType type); const std::string& getName() const; + std::string getFullName() const; + const std::vector& getEdges() const; void addEdge(Edge* edge); @@ -49,9 +51,11 @@ public: Edge* findEdge(std::function func) const; Edge* findEdgeOfType(Edge::EdgeType type) const; Edge* findEdgeOfType(Edge::EdgeType type, std::function func) const; + Node* findChildNode(std::function func) const; void forEachEdge(std::function func) const; void forEachEdgeOfType(Edge::EdgeType type, std::function func) const; + void forEachChildNode(std::function func) const; // Token implementation. virtual bool isNode() const; diff --git a/src/lib/utility/utilityString.cpp b/src/lib/utility/utilityString.cpp index ec1a9119..84d17e79 100644 --- a/src/lib/utility/utilityString.cpp +++ b/src/lib/utility/utilityString.cpp @@ -2,28 +2,6 @@ namespace utility { - std::vector split(const std::string& str, char delimiter) - { - return split(str, std::string(1, delimiter)); - } - - std::vector split(const std::string& str, const std::string& delimiter) - { - size_t pos = 0; - size_t oldPos = 0; - std::vector vec; - - do - { - pos = str.find(delimiter, oldPos); - vec.push_back(str.substr(oldPos, pos - oldPos)); - oldPos = pos + delimiter.size(); - } - while (pos != std::string::npos); - - return vec; - } - bool isPrefix(const std::string& prefix, const std::string& text) { typedef std::pair ResType; diff --git a/src/lib/utility/utilityString.h b/src/lib/utility/utilityString.h index 884ef726..185e5c1b 100644 --- a/src/lib/utility/utilityString.h +++ b/src/lib/utility/utilityString.h @@ -6,10 +6,37 @@ namespace utility { - std::vector split(const std::string& str, char delimiter); - std::vector split(const std::string& str, const std::string& delimiter); + template> + ContainerType split(const std::string& str, char delimiter); + + template> + ContainerType split(const std::string& str, const std::string& delimiter); bool isPrefix(const std::string& prefix, const std::string& text); } +template +ContainerType utility::split(const std::string& str, char delimiter) +{ + return split(str, std::string(1, delimiter)); +} + +template +ContainerType utility::split(const std::string& str, const std::string& delimiter) +{ + size_t pos = 0; + size_t oldPos = 0; + ContainerType c; + + do + { + pos = str.find(delimiter, oldPos); + c.push_back(str.substr(oldPos, pos - oldPos)); + oldPos = pos + delimiter.size(); + } + while (pos != std::string::npos); + + return c; +} + #endif // UTILITY_STRING_H diff --git a/src/test/GraphTestSuite.h b/src/test/GraphTestSuite.h index 1b9239af..a8b764cd 100644 --- a/src/test/GraphTestSuite.h +++ b/src/test/GraphTestSuite.h @@ -169,6 +169,64 @@ public: TS_ASSERT_EQUALS(e.getType(), e2.getType()); } + void test_node_finds_child_node() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + Node* x = a.findChildNode( + [](Node* n) + { + return n->getName() == "C"; + } + ); + + TS_ASSERT_EQUALS(x, &c); + TS_ASSERT_DIFFERS(x, &b); + } + + void test_node_can_not_find_child_node() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + Node* x = a.findChildNode( + [](Node* n) + { + return n->getName() == "D"; + } + ); + + TS_ASSERT(!x); + } + + void test_node_visits_child_nodes() + { + Node a(Node::NODE_UNDEFINED, "A"); + Node b(Node::NODE_UNDEFINED, "B"); + Node c(Node::NODE_UNDEFINED, "C"); + Edge e(Edge::EDGE_MEMBER, &a, &b); + Edge e2(Edge::EDGE_MEMBER, &a, &c); + + std::vector children; + a.forEachChildNode( + [&children](Node* n) + { + return children.push_back(n); + } + ); + + TS_ASSERT_EQUALS(children.size(), 2); + TS_ASSERT_EQUALS(children[0], &b); + TS_ASSERT_EQUALS(children[1], &c); + } + void test_graph_saves_nodes() { TestGraph graph; @@ -284,6 +342,42 @@ public: TS_ASSERT(graph.getNode("A::C")); } + void test_node_in_graph_finds_child_node() + { + TestGraph graph; + Node* a = graph.createNodeHierarchy("A"); + Node* b = graph.createNodeHierarchy("A::B"); + Node* c = graph.createNodeHierarchy("A::C"); + + Node* x = a->findChildNode( + [](Node* n) + { + return n->getName() == "C"; + } + ); + + TS_ASSERT_EQUALS(x, c); + TS_ASSERT_DIFFERS(x, b); + } + + void test_graph_saves_nodes_with_distinct_signatures() + { + TestGraph graph; + Node* a1 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A1"); + Node* a2 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A2"); + Node* a3 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, "A", "A2"); + + TS_ASSERT_DIFFERS(a1, a2); + TS_ASSERT_EQUALS(a2, a3); + + Node* c1 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C1"); + Node* c2 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C2"); + Node* c3 = graph.createNodeHierarchyWithDistinctSignature(Node::NODE_METHOD, "B::C", "C2"); + + TS_ASSERT_DIFFERS(c1, c2); + TS_ASSERT_EQUALS(c2, c3); + } + void test_graph_creates_multiple_nodes_as_undefined_nodes() { TestGraph graph; @@ -295,11 +389,11 @@ public: TS_ASSERT_EQUALS("A", graph.getNode("A")->getName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A")->getType()); - TS_ASSERT_EQUALS("A::B", graph.getNode("A::B")->getName()); + TS_ASSERT_EQUALS("A::B", graph.getNode("A::B")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B")->getType()); TS_ASSERT_EQUALS(abc, graph.getNode("A::B::C")); - TS_ASSERT_EQUALS("A::B::C", graph.getNode("A::B::C")->getName()); + TS_ASSERT_EQUALS("A::B::C", graph.getNode("A::B::C")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C")->getType()); Node* abcde = graph.createNodeHierarchy("A::B::C::D::E"); @@ -307,11 +401,11 @@ public: TS_ASSERT_EQUALS(5, graph.getNodeCount()); TS_ASSERT_EQUALS(4, graph.getEdgeCount()); - TS_ASSERT_EQUALS("A::B::C::D", graph.getNode("A::B::C::D")->getName()); + TS_ASSERT_EQUALS("A::B::C::D", graph.getNode("A::B::C::D")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C::D")->getType()); TS_ASSERT_EQUALS(abcde, graph.getNode("A::B::C::D::E")); - TS_ASSERT_EQUALS("A::B::C::D::E", graph.getNode("A::B::C::D::E")->getName()); + TS_ASSERT_EQUALS("A::B::C::D::E", graph.getNode("A::B::C::D::E")->getFullName()); TS_ASSERT_EQUALS(Node::NODE_UNDEFINED, graph.getNode("A::B::C::D::E")->getType()); }