diff --git a/include/Graph/Graph.hpp b/include/Graph/Graph.hpp index f6496d0eb..f11bd8c70 100644 --- a/include/Graph/Graph.hpp +++ b/include/Graph/Graph.hpp @@ -87,6 +87,10 @@ template class Graph { private: T_EdgeSet edgeSet = {}; + + // Private non-const getter for the set of nodes + std::set *> nodeSet(); + std::optional> getExtenstionAndSeparator( InputOutputFormat format) const; void writeGraphToStream(std::ostream &oGraph, std::ostream &oNodeFeat, @@ -161,6 +165,23 @@ class Graph { * */ virtual const std::set *> getNodeSet() const; + /** + * \brief + * Function that sets the data contained in a node + * + * @param nodeUserId The userId string of the node whose data is to be changes + * @param data The new value for the node data + * + */ + virtual void setNodeData(const std::string &nodeUserId, T data); + /** + * \brief + * Function that sets the data contained in every node of the graph + * + * @param dataMap Map of the userId of every node with its new data value + * + */ + virtual void setNodeData(std::map &dataMap); /** * \brief * Function that return an Edge with specific ID if Exist in the Graph @@ -641,6 +662,24 @@ const std::set *> Graph::getNodeSet() const { return nodeSet; } +template +void Graph::setNodeData(const std::string &nodeUserId, T data) { + for(auto &nodeSetIt : this->nodeSet()) { + if (nodeSetIt->getUserId() == nodeUserId) { + nodeSetIt->setData(std::move(data)); + break; + } + } +} + +template +void Graph::setNodeData(std::map &dataMap) { + // Construct the set of all the nodes in the graph + for(auto &nodeSetIt : this->nodeSet()) { + nodeSetIt->setData(std::move(dataMap[nodeSetIt->getUserId()])); + } +} + template const std::optional *> Graph::getEdge( const unsigned long long edgeId) const { @@ -653,6 +692,17 @@ const std::optional *> Graph::getEdge( return std::nullopt; } +template +std::set *> Graph::nodeSet() { + std::set *> nodeSet; + for (auto &edgeSetIt : edgeSet) { + nodeSet.insert(const_cast *>(edgeSetIt->getNodePair().first)); + nodeSet.insert(const_cast *>(edgeSetIt->getNodePair().second)); + } + + return nodeSet; +} + template std::optional> Graph::getExtenstionAndSeparator( InputOutputFormat format) const { @@ -909,7 +959,7 @@ void Graph::recreateGraph( // Create new Node T feat; if (nodeFeatMap.find(edgeIt.second.first) != nodeFeatMap.end()) { - feat = nodeFeatMap.at(edgeIt.second.first); + feat = std::move(nodeFeatMap.at(edgeIt.second.first)); } node1 = new Node(edgeIt.second.first, feat); nodeMap[edgeIt.second.first] = node1; @@ -920,7 +970,7 @@ void Graph::recreateGraph( // Create new Node T feat; if (nodeFeatMap.find(edgeIt.second.second) != nodeFeatMap.end()) { - feat = nodeFeatMap.at(edgeIt.second.second); + feat = std::move(nodeFeatMap.at(edgeIt.second.second)); } node2 = new Node(edgeIt.second.second, feat); nodeMap[edgeIt.second.second] = node2; diff --git a/include/Node/Node.hpp b/include/Node/Node.hpp index 29fe4b7b2..e606e1142 100755 --- a/include/Node/Node.hpp +++ b/include/Node/Node.hpp @@ -39,11 +39,14 @@ class Node { void setId(const std::string &); public: - Node(const std::string &, const T &data); + Node(const std::string &, const T& data); + // Move constructor + Node(const std::string &, T&& data) noexcept; ~Node() = default; const std::size_t &getId() const; const std::string &getUserId() const; const T &getData() const; + void setData(T&& new_data); // operator bool operator==(const Node &b) const; bool operator<(const Node &b) const; @@ -51,13 +54,21 @@ class Node { }; template -Node::Node(const std::string &id, const T &data) { +Node::Node(const std::string& id, const T& data) { this->userId = id; // the userid is set as sha512 hash of the user provided id setId(id); this->data = data; } +template +Node::Node(const std::string& id, T&& data) noexcept { + this->userId = id; + // the userid is set as sha512 hash of the user provided id + setId(id); + std::swap(this->data, data); +} + template void Node::setId(const std::string &inpId) { // const unsigned char* userId = reinterpret_cast::getData() const { return data; } +template +void Node::setData(T&& new_data) { + this->data = std::move(new_data); +} + +// The data type T must have an overload of the equality operator template bool Node::operator==(const Node &b) const { return (this->id == b.id && this->data == b.data); @@ -110,6 +127,7 @@ bool Node::operator<(const Node &b) const { } // ostream overload +// The data type T must have an overload of the ostream operator template std::ostream &operator<<(std::ostream &os, const Node &node) { os << "Node: {\n" @@ -118,4 +136,4 @@ std::ostream &operator<<(std::ostream &os, const Node &node) { } } // namespace CXXGraph -#endif // __CXXGRAPH_NODE_H__ \ No newline at end of file +#endif // __CXXGRAPH_NODE_H__ diff --git a/test/DirectedEdgeTest.cpp b/test/DirectedEdgeTest.cpp index 8ae35ec6e..17e8855d2 100644 --- a/test/DirectedEdgeTest.cpp +++ b/test/DirectedEdgeTest.cpp @@ -52,6 +52,52 @@ TEST(DirectedEdgeTest, Constructor_5) { ASSERT_FALSE(edge.isWeighted().value()); } +TEST(DirectedEdgeTest, Bool_data) { + // First constructor + CXXGraph::Node node1("1", true); + CXXGraph::Node node2("2", false); + CXXGraph::DirectedEdge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_TRUE(edge1.isDirected().value()); + ASSERT_FALSE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", true); + CXXGraph::Node node4("4", false); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::DirectedEdge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_TRUE(edge2.isDirected().value()); + ASSERT_FALSE(edge2.isWeighted().value()); +} + +TEST(DirectedEdgeTest, String_data) { + // First constructor + CXXGraph::Node node1("1", "On"); + CXXGraph::Node node2("2", "Off"); + CXXGraph::DirectedEdge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_TRUE(edge1.isDirected().value()); + ASSERT_FALSE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", "On"); + CXXGraph::Node node4("4", "Off"); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::DirectedEdge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_TRUE(edge2.isDirected().value()); + ASSERT_FALSE(edge2.isWeighted().value()); +} + TEST(DirectedEdgeTest, Cast_1) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); diff --git a/test/DirectedWeightedEdgeTest.cpp b/test/DirectedWeightedEdgeTest.cpp index dff2ddd04..8eed0f700 100644 --- a/test/DirectedWeightedEdgeTest.cpp +++ b/test/DirectedWeightedEdgeTest.cpp @@ -85,6 +85,52 @@ TEST(DirectedWeightedEdgeTest, Constructor_7) { ASSERT_EQ(edge.getWeight(), 0.0); } +TEST(DirectedWeightedEdgeTest, Bool_data) { + // First constructor + CXXGraph::Node node1("1", true); + CXXGraph::Node node2("2", false); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 8); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_TRUE(edge1.isDirected().value()); + ASSERT_TRUE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", true); + CXXGraph::Node node4("4", false); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::DirectedWeightedEdge edge2(2, pairNode, 2); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_TRUE(edge2.isDirected().value()); + ASSERT_TRUE(edge2.isWeighted().value()); +} + +TEST(DirectedWeightedEdgeTest, String_data) { + // First constructor + CXXGraph::Node node1("1", "On"); + CXXGraph::Node node2("2", "Off"); + CXXGraph::DirectedWeightedEdge edge1(1, node1, node2, 4); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_TRUE(edge1.isDirected().value()); + ASSERT_TRUE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", "On"); + CXXGraph::Node node4("4", "Off"); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::DirectedWeightedEdge edge2(2, pairNode, 6); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_TRUE(edge2.isDirected().value()); + ASSERT_TRUE(edge2.isWeighted().value()); +} + TEST(DirectedWeightedEdgeTest, Cast_1) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); diff --git a/test/EdgeTest.cpp b/test/EdgeTest.cpp index 329491c64..fd4a6e823 100644 --- a/test/EdgeTest.cpp +++ b/test/EdgeTest.cpp @@ -28,6 +28,44 @@ TEST(EdgeTest, print_1) { std::cout << edge << std::endl; } +TEST(EdgeTest, Bool_data) { + // First constructor + CXXGraph::Node node1("1", true); + CXXGraph::Node node2("2", false); + CXXGraph::Edge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + + // Second constructor + CXXGraph::Node node3("3", true); + CXXGraph::Node node4("4", false); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::Edge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); +} + +TEST(EdgeTest, String_data) { + // First constructor + CXXGraph::Node node1("1", "On"); + CXXGraph::Node node2("2", "Off"); + CXXGraph::Edge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + + // Second constructor + CXXGraph::Node node3("3", "On"); + CXXGraph::Node node4("4", "Off"); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::Edge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); +} + TEST(EdgeTest, test) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); @@ -54,4 +92,4 @@ TEST(EdgeTest, test) { adj = graph.getAdjMatrix(); ASSERT_EQ(adj->size(), 1); std::cout << *adj << std::endl; -} \ No newline at end of file +} diff --git a/test/GraphTest.cpp b/test/GraphTest.cpp index 5b9bf2e39..e28f8659c 100644 --- a/test/GraphTest.cpp +++ b/test/GraphTest.cpp @@ -179,4 +179,50 @@ TEST(GraphTest, adj_print_6) { CXXGraph::Graph graph(edgeSet); std::cout << "Test Print Adjacency Matrix" << std::endl; std::cout << *graph.getAdjMatrix() << std::endl; -} \ No newline at end of file +} + +TEST(GraphTest, set_data) { + // Create the graph + CXXGraph::Node node1("1", 1); + CXXGraph::Node node2("2", 2); + CXXGraph::Node node3("3", 3); + std::pair *, const CXXGraph::Node *> pairNode( + &node1, &node2); + CXXGraph::DirectedEdge edge1(1, pairNode); + CXXGraph::DirectedEdge edge2(2, node2, node3); + CXXGraph::UndirectedEdge edge3(3, node1, node3); + CXXGraph::T_EdgeSet edgeSet; + edgeSet.insert(&edge1); + edgeSet.insert(&edge2); + edgeSet.insert(&edge3); + CXXGraph::Graph graph(edgeSet); + + + std::map initial_values; + // Construct map with the initial values of the nodes data + for (const auto& nodeIt : graph.getNodeSet()) { + initial_values[nodeIt->getUserId()] = nodeIt->getData(); + } + // Change the data contained in the nodes singularly + std::map new_values; + for (const auto& nodeIt : graph.getNodeSet()) { + int r = std::rand(); + graph.setNodeData(nodeIt->getUserId(), r); + new_values[nodeIt->getUserId()] = r; + } + // Check the final values of the node data + for (const auto& nodeIt : graph.getNodeSet()) { + ASSERT_EQ(nodeIt->getData(), new_values[nodeIt->getUserId()]); + } + + // Now set the data of all the nodes at once + std::map data_values; + for (const auto& nodeIt : graph.getNodeSet()) { + int r = std::rand(); + data_values[nodeIt->getUserId()] = r; + } + graph.setNodeData(data_values); + for (const auto& nodeIt : graph.getNodeSet()) { + ASSERT_EQ(nodeIt->getData(), data_values[nodeIt->getUserId()]); + } +} diff --git a/test/UndirectedEdgeTest.cpp b/test/UndirectedEdgeTest.cpp index 05e270972..6b73fcea0 100644 --- a/test/UndirectedEdgeTest.cpp +++ b/test/UndirectedEdgeTest.cpp @@ -52,6 +52,52 @@ TEST(UndirectedEdgeTest, Constructor_5) { ASSERT_FALSE(edge.isWeighted().value()); } +TEST(UndirectedEdgeTest, Bool_data) { + // First constructor + CXXGraph::Node node1("1", true); + CXXGraph::Node node2("2", false); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_FALSE(edge1.isDirected().value()); + ASSERT_FALSE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", true); + CXXGraph::Node node4("4", false); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::UndirectedEdge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_FALSE(edge2.isDirected().value()); + ASSERT_FALSE(edge2.isWeighted().value()); +} + +TEST(UndirectedEdgeTest, String_data) { + // First constructor + CXXGraph::Node node1("1", "On"); + CXXGraph::Node node2("2", "Off"); + CXXGraph::UndirectedEdge edge1(1, node1, node2); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_FALSE(edge1.isDirected().value()); + ASSERT_FALSE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", "On"); + CXXGraph::Node node4("4", "Off"); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::UndirectedEdge edge2(2, pairNode); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_FALSE(edge2.isDirected().value()); + ASSERT_FALSE(edge2.isWeighted().value()); +} + TEST(UndirectedEdgeTest, Cast_1) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2); @@ -87,4 +133,4 @@ TEST(UndirectedEdgeTest, print_1) { CXXGraph::UndirectedEdge edge(1, node1, node2); std::cout << "Test Print UndirectedEdge" << std::endl; std::cout << edge << std::endl; -} \ No newline at end of file +} diff --git a/test/UndirectedWeightedEdgeTest.cpp b/test/UndirectedWeightedEdgeTest.cpp index 95ce7ae82..2fd84e627 100644 --- a/test/UndirectedWeightedEdgeTest.cpp +++ b/test/UndirectedWeightedEdgeTest.cpp @@ -85,6 +85,52 @@ TEST(UndirectedWeightedEdgeTest, Constructor_7) { ASSERT_EQ(edge.getWeight(), 0.0); } +TEST(UndirectedWeightedEdgeTest, Bool_data) { + // First constructor + CXXGraph::Node node1("1", true); + CXXGraph::Node node2("2", false); + CXXGraph::UndirectedWeightedEdge edge1(1, node1, node2, 4); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_FALSE(edge1.isDirected().value()); + ASSERT_TRUE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", true); + CXXGraph::Node node4("4", false); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::UndirectedWeightedEdge edge2(2, pairNode, 7); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_FALSE(edge2.isDirected().value()); + ASSERT_TRUE(edge2.isWeighted().value()); +} + +TEST(UndirectedWeightedEdgeTest, String_data) { + // First constructor + CXXGraph::Node node1("1", "On"); + CXXGraph::Node node2("2", "Off"); + CXXGraph::UndirectedWeightedEdge edge1(1, node1, node2, 3); + ASSERT_EQ(*(edge1.getNodePair().first), node1); + ASSERT_EQ(*(edge1.getNodePair().second), node2); + ASSERT_FALSE(edge1.isDirected().value()); + ASSERT_TRUE(edge1.isWeighted().value()); + + // Second constructor + CXXGraph::Node node3("3", "On"); + CXXGraph::Node node4("4", "Off"); + std::pair *, const CXXGraph::Node *> pairNode( + &node3, &node4); + CXXGraph::UndirectedWeightedEdge edge2(2, pairNode, 5); + ASSERT_EQ(edge2.getNodePair(), pairNode); + ASSERT_EQ(*(edge2.getNodePair().first), node3); + ASSERT_EQ(*(edge2.getNodePair().second), node4); + ASSERT_FALSE(edge2.isDirected().value()); + ASSERT_TRUE(edge2.isWeighted().value()); +} + TEST(UndirectedWeightedEdgeTest, Cast_1) { CXXGraph::Node node1("1", 1); CXXGraph::Node node2("2", 2);