-
-
Notifications
You must be signed in to change notification settings - Fork 563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory allocation error using co/stl containers (co::vector, co::hash_map) #349
Comments
Just to make sure, I rewrote the graph class using file: graph.h#ifndef GRAPH_H
#define GRAPH_H
#include "co/cout.h"
//#include "co/stl.h"
#include <vector>
#include <unordered_map>
#include "co/log.h"
#include "co/json.h"
#include "co/fastring.h"
using namespace std;
template <typename VertexType, typename IDType>
class Graph {
public:
/// @brief default constructor
Graph() = default;
/// @brief add a vertex to the graph
/// @param IdType the vertex id to be added
/// @param VertexType the vertex to be added
void addVertex(const IDType& id, const VertexType& vertex) {
if (vertexMap.find(id) != vertexMap.end()) {
ELOG << "vertex " << id << " already exists";
return;
}
vertices.push_back(vertex);
vertexMap[id] = vertices.size() - 1;
adjacencyLists.push_back(vector<IDType>());
}
/// @brief add an edge to the graph
/// @param IDType the source vertex id
/// @param IDType the target vertex id
void addEdge(const IDType& source, const IDType& target) {
if (vertexMap.find(source) == vertexMap.end()) {
ELOG << "vertex " << source << " does not exist";
return;
}
if (vertexMap.find(target) == vertexMap.end()) {
ELOG << "vertex " << target << " does not exist";
return;
}
adjacencyLists[vertexMap[source]].push_back(target);
}
/// @brief get a node by id
/// @param IDType the vertex id
/// @return VertexType the vertex
VertexType findNode(const IDType& id) const {
if (vertexMap.find(id) == vertexMap.end()) {
ELOG << "vertex " << id << " does not exist";
return VertexType();
}
return vertices[vertexMap.at(id)];
}
/// @brief remove a node by id
/// @param IDType the vertex id
void removeNode(const IDType& id) {
if (vertexMap.find(id) == vertexMap.end()) {
ELOG << "vertex " << id << " does not exist";
return;
}
size_t index = vertexMap.at(id);
vertices.erase(vertices.begin() + index);
vertexMap.erase(id);
adjacencyLists.erase(adjacencyLists.begin() + index);
for (auto& list : adjacencyLists) {
for (auto& node : list) {
if (node == id) {
node = adjacencyLists.size();
}
if (node > index) {
node--;
}
}
}
}
/// @brief remove an edge by id
/// @param IDType the source vertex id
/// @param IDType the target vertex id
void removeEdge(const IDType& source, const IDType& target) {
if (vertexMap.find(source) == vertexMap.end()) {
ELOG << "vertex " << source << " does not exist";
return;
}
if (vertexMap.find(target) == vertexMap.end()) {
ELOG << "vertex " << target << " does not exist";
return;
}
size_t sourceIndex = vertexMap.at(source);
size_t targetIndex = vertexMap.at(target);
for (auto& node : adjacencyLists[sourceIndex]) {
if (node == target) {
node = adjacencyLists.size();
}
if (node > targetIndex) {
node--;
}
}
// remove the edge from the adjacency list
adjacencyLists[sourceIndex].erase(
std::remove(adjacencyLists[sourceIndex].begin(), adjacencyLists[sourceIndex].end(), adjacencyLists.size()),
adjacencyLists[sourceIndex].end());
}
/// @brief VertexMap getter
/// @return co::map<IDType, size_t> the vertex map
unordered_map<IDType, size_t> VertexMap() const {
return vertexMap;
}
/// @brief Vertices getter
/// @return vector<VertexType> the vertices
vector<VertexType> Vertices() const {
return vertices;
}
/// @brief Edges getter
/// @return vector<vector<IDType>> the adjacency lists
vector<vector<IDType>> Edges() const {
return adjacencyLists;
}
/// @brief function to check if an edge exists between two vertices
/// @param IDType the source vertex id
/// @param IDType the target vertex id
/// @return bool true if the edge exists, false otherwise
bool hasEdge(const IDType& source, const IDType& target) const {
if (vertexMap.find(source) == vertexMap.end()) {
ELOG << "vertex " << source << " does not exist";
return false;
}
if (vertexMap.find(target) == vertexMap.end()) {
ELOG << "vertex " << target << " does not exist";
return false;
}
size_t sourceIndex = vertexMap.at(source);
for (auto& node : adjacencyLists[sourceIndex]) {
if (node == target) {
return true;
}
}
return false;
}
private:
/// @brief vertex list
vector<VertexType> vertices;
/// @brief vertex map
unordered_map<IDType, size_t> vertexMap;
/// @brief adjacency lists representing the graph
vector<vector<IDType>> adjacencyLists;
};
#endif // GRAPH_H maybe I should use something different that |
Reproduced it. Let me see.. |
sorry, a little busy at work these days.It is a bug in |
@idealvin awesome! That worked right away. Thank you so much for replying so quickly. In case some needs it, here's the tests with the file: graph.cc#include "co/flag.h"
#include "co/cout.h"
#include "co/log.h"
#include "co/unitest.h"
#include "co/fastring.h"
#include "co/mem.h"
#include "co/graph.h"
#include <chrono>
namespace test {
DEF_test(graph) {
Graph<fastring, uint32_t> myGraph = Graph<fastring, uint32_t>();
myGraph.addVertex(1, "a");
myGraph.addVertex(2, "b");
myGraph.addVertex(3, "c");
myGraph.addVertex(4, "d");
myGraph.addEdge(1, 2);
myGraph.addEdge(2, 3);
myGraph.addEdge(3, 4);
myGraph.addEdge(4, 1);
myGraph.addEdge(2, 4);
myGraph.addEdge(4, 2);
DEF_case(check_vertices) {
EXPECT_EQ(myGraph.Vertices()[myGraph.VertexMap()[1]],"a");
EXPECT_EQ(myGraph.Vertices()[myGraph.VertexMap()[2]],"b");
EXPECT_EQ(myGraph.Vertices()[myGraph.VertexMap()[3]],"c");
EXPECT_EQ(myGraph.Vertices()[myGraph.VertexMap()[4]],"d");
}
DEF_case(find_node) {
auto result = myGraph.findNode(3);
EXPECT_EQ(result , "c");
}
DEF_case(find_node_not_found) {
auto result = myGraph.findNode(5);
EXPECT_EQ(result, "");
}
DEF_case(huge_graph) {
const int NUMBER_OF_VERTICES = 2000;
Graph<fastring, uint32_t> bigGraph;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < NUMBER_OF_VERTICES; i++) {
bigGraph.addVertex(i, "Vertex_" + std::to_string(i));
}
for (int sourceID = 1; sourceID <= NUMBER_OF_VERTICES; ++sourceID) {
for (int targetID = 1; targetID <= NUMBER_OF_VERTICES; ++targetID) {
// add 4 edges per vertex
if (targetID == (sourceID -1) || targetID == (sourceID +1) || targetID == (sourceID -2) || targetID == (sourceID +2))
bigGraph.addEdge(sourceID, targetID);
}
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
cout << "Time taken to create the big graph: " << duration.count() << " microseconds" << std::endl;
//EXPECT_EQ(bigGraph.Vertices().size(), NUMBER_OF_VERTICES);
fastring halfwayVertex = "Vertex_" + std::to_string(NUMBER_OF_VERTICES/2);
start = std::chrono::high_resolution_clock::now();
auto result = bigGraph.findNode(NUMBER_OF_VERTICES/2);
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
cout << "Time taken to find node: " << duration.count() << " microseconds" << std::endl;
EXPECT_EQ(result, halfwayVertex);
}
}
} // namespace test
|
@piperoc |
@idealvin that works. Thanks! |
I wrote a simple graph class using the
co::vector
and theco::hash_map
to use a common adjacency list technique.I then created a unit test like the the other files in your
unitest
source folder.All tests pass but at the very end I get what looks like a memory allocation error (it's probably my mistake in using those structures).
I tried to profile it but cannot figure it out.
Here's my class:
file: graph.h
and here's the file implementing the tests:
file: graph.h
When I run the unit tests I get the following
if I debug it aborts when calling
void _destruct_range
from theco::vector
class (fileinclude/co/vector.h
line 322) as the for loop range that I'm indirectly passing (with the destructor) is probably wrong.call stack
Sorry for the lengthy description. Thanks for any advice
The text was updated successfully, but these errors were encountered: