From 07e865fdfa663e905b69f668a97102d04d3f048b Mon Sep 17 00:00:00 2001 From: varunsha30 Date: Thu, 15 Oct 2026 20:06:59 +0530 Subject: [PATCH 1/5] Add `adjacency_matrix` serialization support. --- include/boost/graph/adj_matrix_serialize.hpp | 131 +++++++++++++++++++ test/Jamfile.v2 | 4 + test/adj_matrix_serialize.cpp | 103 +++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 include/boost/graph/adj_matrix_serialize.hpp create mode 100644 test/adj_matrix_serialize.cpp diff --git a/include/boost/graph/adj_matrix_serialize.hpp b/include/boost/graph/adj_matrix_serialize.hpp new file mode 100644 index 000000000..273795bef --- /dev/null +++ b/include/boost/graph/adj_matrix_serialize.hpp @@ -0,0 +1,131 @@ +//======================================================================= +// Copyright 2026 Varun Sharma +// Authors: Varun Sharma +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +#ifndef BOOST_GRAPH_ADJ_MATRIX_SERIALIZE_HPP +#define BOOST_GRAPH_ADJ_MATRIX_SERIALIZE_HPP + +#include + +#include +#include +#include +#include + +namespace boost +{ + +namespace serialization +{ + + // Disable tracking for adjacency_matrix, which is not polymorphic. This + // serializer writes graph structure and properties by value and rebuilds + // edges on load; it does not preserve graph-object identity. Use this only + // when pointer identity for graph objects need not be preserved. + template < class T > + struct tracking_level_impl; + + template < class Directed, class VP, class EP, class GP, class Allocator > + struct tracking_level_impl< + const boost::adjacency_matrix< Directed, VP, EP, GP, Allocator > > + : boost::integral_constant< int, 0 > + { + }; + + template < class Archive, class Directed, class VP, class EP, class GP, class Allocator > + inline void save(Archive& ar, + const boost::adjacency_matrix< Directed, VP, EP, GP, Allocator >& graph, + const unsigned int /* version */) + { + const auto V = boost::num_vertices(graph); + const auto E = boost::num_edges(graph); + + ar << BOOST_NVP(V); + ar << BOOST_NVP(E); + + auto vertex_range = boost::vertices(graph); + for (auto it = vertex_range.first; it != vertex_range.second; ++it) + { + auto&& vertex_property = + boost::get(boost::vertex_all_t(), graph, *it); + ar << BOOST_NVP(vertex_property); + } + + auto edge_range = boost::edges(graph); + for (auto it = edge_range.first; it != edge_range.second; ++it) + { + const auto u = boost::source(*it, graph); + const auto v = boost::target(*it, graph); + auto&& edge_property = + boost::get(boost::edge_all_t(), graph, *it); + + ar << BOOST_NVP(u); + ar << BOOST_NVP(v); + ar << BOOST_NVP(edge_property); + } + + ar << boost::make_nvp( + "graph_property", boost::get_property(graph, boost::graph_all_t())); + } + + template < class Archive, class Directed, class VP, class EP, class GP, class Allocator > + inline void load(Archive& ar, + boost::adjacency_matrix< Directed, VP, EP, GP, Allocator >& graph, + const unsigned int /* version */) + { + using Graph = boost::adjacency_matrix< Directed, VP, EP, GP, Allocator >; + using VertexSize = typename Graph::vertices_size_type; + using EdgeSize = typename Graph::edges_size_type; + using Vertex = typename Graph::vertex_descriptor; + + VertexSize V = 0; + EdgeSize E = 0; + + ar >> BOOST_NVP(V); + ar >> BOOST_NVP(E); + + Graph loaded(V); + + auto vertex_range = boost::vertices(loaded); + for (auto it = vertex_range.first; it != vertex_range.second; ++it) + { + auto&& vertex_property = + boost::get(boost::vertex_all_t(), loaded, *it); + ar >> BOOST_NVP(vertex_property); + } + + for (EdgeSize i = 0; i < E; ++i) + { + Vertex u = 0; + Vertex v = 0; + + ar >> BOOST_NVP(u); + ar >> BOOST_NVP(v); + + const auto e = boost::add_edge(u, v, loaded).first; + auto&& edge_property = boost::get(boost::edge_all_t(), loaded, e); + ar >> BOOST_NVP(edge_property); + } + + ar >> boost::make_nvp("graph_property", + boost::get_property(loaded, boost::graph_all_t())); + + graph = std::move(loaded); + } + + template < class Archive, class Directed, class VP, class EP, class GP, class Allocator > + inline void serialize(Archive& ar, + boost::adjacency_matrix< Directed, VP, EP, GP, Allocator >& graph, + const unsigned int version) + { + boost::core::split_free(ar, graph, version); + } + +} // namespace serialization +} // namespace boost + +#endif // BOOST_GRAPH_ADJ_MATRIX_SERIALIZE_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7287f460f..eba4c5096 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -89,6 +89,10 @@ alias graph_test_regular : /boost/serialization//boost_serialization : : : ] + [ run adj_matrix_serialize.cpp + /boost/serialization//boost_serialization + : : : ] + [ compile reverse_graph_cc.cpp ] [ run sequential_vertex_coloring.cpp ] diff --git a/test/adj_matrix_serialize.cpp b/test/adj_matrix_serialize.cpp new file mode 100644 index 000000000..afd25f4cc --- /dev/null +++ b/test/adj_matrix_serialize.cpp @@ -0,0 +1,103 @@ +// Copyright 2026 Varun Sharma +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#include +#include + +struct vertex_properties +{ + std::string name; + + template < class Archive > + void serialize(Archive& ar, const unsigned int /* version */) + { + ar& boost::make_nvp("name", name); + } +}; + +struct edge_properties +{ + int weight; + + template < class Archive > + void serialize(Archive& ar, const unsigned int /* version */) + { + ar& boost::make_nvp("weight", weight); + } +}; + +typedef boost::adjacency_matrix< boost::directedS > DirectedGraph; +typedef boost::adjacency_matrix< boost::undirectedS, vertex_properties, + edge_properties > + UndirectedGraph; + +static_assert(boost::serialization::tracking_level< DirectedGraph >::value + == boost::serialization::track_never, + "adjacency_matrix tracking_level must be track_never"); +static_assert(boost::serialization::tracking_level< UndirectedGraph >::value + == boost::serialization::track_never, + "adjacency_matrix tracking_level must be track_never"); + +int main() +{ + DirectedGraph directed(3); + boost::add_edge(0, 1, directed); + boost::add_edge(1, 2, directed); + + UndirectedGraph undirected(3); + undirected[0].name = "A"; + undirected[1].name = "B"; + undirected[2].name = "C"; + + edge_properties first_edge = { 7 }; + edge_properties second_edge = { 11 }; + boost::add_edge(0, 1, first_edge, undirected); + boost::add_edge(1, 2, second_edge, undirected); + + std::stringstream buffer; + { + boost::archive::xml_oarchive archive(buffer); + archive << boost::make_nvp("directed_graph", directed); + archive << boost::make_nvp("undirected_graph", undirected); + } + + DirectedGraph restored_directed(0); + UndirectedGraph restored_undirected(0); + { + boost::archive::xml_iarchive archive(buffer); + archive >> boost::make_nvp("directed_graph", restored_directed); + archive >> boost::make_nvp("undirected_graph", restored_undirected); + } + + if (boost::num_vertices(restored_directed) != 3 || + boost::num_edges(restored_directed) != 2 || + !boost::edge(0, 1, restored_directed).second || + !boost::edge(1, 2, restored_directed).second || + boost::edge(1, 0, restored_directed).second) + return 1; + + if (boost::num_vertices(restored_undirected) != 3 || + boost::num_edges(restored_undirected) != 2 || + restored_undirected[0].name != "A" || + restored_undirected[1].name != "B" || + restored_undirected[2].name != "C") + return 1; + + const auto first = boost::edge(0, 1, restored_undirected); + const auto second = boost::edge(1, 2, restored_undirected); + if (!first.second || !second.second || + restored_undirected[first.first].weight != 7 || + restored_undirected[second.first].weight != 11) + return 1; + + return 0; +} From 46cbf28f2b712a1b3a318865060b849303a9ac3b Mon Sep 17 00:00:00 2001 From: varunsha30 Date: Mon, 19 Oct 2026 14:20:26 +0530 Subject: [PATCH 2/5] Add serialization support for `compressed_sparse_row_graph` --- include/boost/graph/csr_graph_serialize.hpp | 162 ++++++++++++++++++++ test/Jamfile.v2 | 4 + test/csr_graph_serialize.cpp | 121 +++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 include/boost/graph/csr_graph_serialize.hpp create mode 100644 test/csr_graph_serialize.cpp diff --git a/include/boost/graph/csr_graph_serialize.hpp b/include/boost/graph/csr_graph_serialize.hpp new file mode 100644 index 000000000..552bcc53a --- /dev/null +++ b/include/boost/graph/csr_graph_serialize.hpp @@ -0,0 +1,162 @@ +//======================================================================= +// Copyright 2026 Varun Sharma +// Authors: Varun Sharma +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +#ifndef BOOST_GRAPH_CSR_GRAPH_SERIALIZE_HPP +#define BOOST_GRAPH_CSR_GRAPH_SERIALIZE_HPP + +#include +#include +#include + +#include +#include +#include +#include + +namespace boost +{ + +namespace serialization +{ + + // This serializer writes graph structure and properties by value and + // rebuilds edges on load; it does not preserve graph-object identity. + template < class T > + struct tracking_level_impl; + + template < class Directed, class VP, class EP, class GP, class Vertex, + class EdgeIndex > + struct tracking_level_impl< const boost::compressed_sparse_row_graph< + Directed, VP, EP, GP, Vertex, EdgeIndex > > + : boost::integral_constant< int, 0 > + { + }; + + template < class Archive, class Directed, class VP, class EP, class GP, + class Vertex, class EdgeIndex > + inline void save(Archive& ar, + const boost::compressed_sparse_row_graph< Directed, VP, EP, GP, Vertex, + EdgeIndex >& graph, + const unsigned int /* version */) + { + const auto V = boost::num_vertices(graph); + const auto E = boost::num_edges(graph); + + ar << BOOST_NVP(V); + ar << BOOST_NVP(E); + + auto vertex_range = boost::vertices(graph); + for (auto it = vertex_range.first; it != vertex_range.second; ++it) + { + auto&& vertex_property + = boost::get(boost::vertex_all_t(), graph, *it); + ar << BOOST_NVP(vertex_property); + } + + auto edge_range = boost::edges(graph); + for (auto it = edge_range.first; it != edge_range.second; ++it) + { + const auto u = boost::source(*it, graph); + const auto v = boost::target(*it, graph); + const auto edge_property + = boost::get(boost::edge_all_t(), graph, *it); + + ar << BOOST_NVP(u); + ar << BOOST_NVP(v); + ar << BOOST_NVP(edge_property); + } + + ar << boost::make_nvp( + "graph_property", boost::get_property(graph, boost::graph_all_t())); + } + + template < class Archive, class Directed, class VP, class EP, class GP, + class Vertex, class EdgeIndex > + inline void load(Archive& ar, + boost::compressed_sparse_row_graph< Directed, VP, EP, GP, Vertex, + EdgeIndex >& graph, + const unsigned int /* version */) + { + using Graph = boost::compressed_sparse_row_graph< Directed, VP, EP, GP, + Vertex, EdgeIndex >; + using VertexSize = typename Graph::vertices_size_type; + using EdgeSize = typename Graph::edges_size_type; + using VertexDescriptor = typename Graph::vertex_descriptor; + using EdgeProperty = typename Graph::edge_bundled; + + VertexSize V = 0; + EdgeSize E = 0; + + ar >> BOOST_NVP(V); + ar >> BOOST_NVP(E); + + Graph loaded(V); + + auto vertex_range = boost::vertices(loaded); + for (auto it = vertex_range.first; it != vertex_range.second; ++it) + { + auto&& vertex_property + = boost::get(boost::vertex_all_t(), loaded, *it); + ar >> BOOST_NVP(vertex_property); + } + + std::vector< std::pair< VertexDescriptor, VertexDescriptor > > + endpoints; + std::vector< EdgeProperty > edge_properties; + endpoints.reserve(static_cast< std::size_t >(E)); + edge_properties.reserve(static_cast< std::size_t >(E)); + + for (EdgeSize i = 0; i < E; ++i) + { + VertexDescriptor u = 0; + VertexDescriptor v = 0; + EdgeProperty edge_property { }; + + ar >> BOOST_NVP(u); + ar >> BOOST_NVP(v); + ar >> BOOST_NVP(edge_property); + + endpoints.emplace_back(u, v); + edge_properties.push_back(std::move(edge_property)); + } + + Graph rebuilt(boost::edges_are_sorted, endpoints.begin(), + endpoints.end(), edge_properties.begin(), V, E); + + auto loaded_vertices = boost::vertices(loaded); + auto rebuilt_vertices = boost::vertices(rebuilt); + for (auto loaded_it = loaded_vertices.first, + rebuilt_it = rebuilt_vertices.first; + loaded_it != loaded_vertices.second + && rebuilt_it != rebuilt_vertices.second; + ++loaded_it, ++rebuilt_it) + { + boost::get(boost::vertex_all_t(), rebuilt, *rebuilt_it) = std::move( + boost::get(boost::vertex_all_t(), loaded, *loaded_it)); + } + + ar >> boost::make_nvp("graph_property", + boost::get_property(rebuilt, boost::graph_all_t())); + + graph = std::move(rebuilt); + } + + template < class Archive, class Directed, class VP, class EP, class GP, + class Vertex, class EdgeIndex > + inline void serialize(Archive& ar, + boost::compressed_sparse_row_graph< Directed, VP, EP, GP, Vertex, + EdgeIndex >& graph, + const unsigned int version) + { + boost::core::split_free(ar, graph, version); + } + +} // namespace serialization +} // namespace boost + +#endif // BOOST_GRAPH_CSR_GRAPH_SERIALIZE_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index eba4c5096..4fe9fd0a8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -93,6 +93,10 @@ alias graph_test_regular : /boost/serialization//boost_serialization : : : ] + [ run csr_graph_serialize.cpp + /boost/serialization//boost_serialization + : : : ] + [ compile reverse_graph_cc.cpp ] [ run sequential_vertex_coloring.cpp ] diff --git a/test/csr_graph_serialize.cpp b/test/csr_graph_serialize.cpp new file mode 100644 index 000000000..93da5c1be --- /dev/null +++ b/test/csr_graph_serialize.cpp @@ -0,0 +1,121 @@ +// Copyright 2026 Varun Sharma +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct vertex_properties +{ + std::string name; + + template < class Archive > + void serialize(Archive& ar, const unsigned int /* version */) + { + ar& boost::make_nvp("name", name); + } +}; + +struct edge_properties +{ + edge_properties() : weight(0) { } + explicit edge_properties(int value) : weight(value) { } + + int weight = 0; + + template < class Archive > + void serialize(Archive& ar, const unsigned int /* version */) + { + ar& boost::make_nvp("weight", weight); + } +}; + +struct graph_properties +{ + std::string name; + + template < class Archive > + void serialize(Archive& ar, const unsigned int /* version */) + { + ar& boost::make_nvp("name", name); + } +}; + +typedef boost::compressed_sparse_row_graph< boost::directedS, vertex_properties, + edge_properties, graph_properties > + CSRGraph; +typedef boost::compressed_sparse_row_graph< boost::directedS > PlainCSRGraph; + +static_assert(boost::serialization::tracking_level< CSRGraph >::value + == boost::serialization::track_never, + "compressed_sparse_row_graph tracking_level must be track_never"); +static_assert(boost::serialization::tracking_level< PlainCSRGraph >::value + == boost::serialization::track_never, + "compressed_sparse_row_graph tracking_level must be track_never"); + +int main() +{ + typedef CSRGraph::vertex_descriptor Vertex; + typedef std::pair< Vertex, Vertex > Edge; + + std::vector< Edge > endpoints { Edge(0, 1), Edge(0, 2), Edge(2, 1) }; + std::vector< edge_properties > edge_data { edge_properties { 7 }, + edge_properties { 11 }, edge_properties { 13 } }; + std::vector< Edge > plain_endpoints { Edge(0, 1), Edge(1, 2) }; + + CSRGraph graph(boost::edges_are_sorted, endpoints.begin(), endpoints.end(), + edge_data.begin(), 3, endpoints.size()); + PlainCSRGraph plain_graph(boost::edges_are_sorted, plain_endpoints.begin(), + plain_endpoints.end(), 3); + graph[0].name = "A"; + graph[1].name = "B"; + graph[2].name = "C"; + boost::get_property(graph, boost::graph_all_t()).name = "sample"; + + std::stringstream buffer; + { + boost::archive::xml_oarchive archive(buffer); + archive << boost::make_nvp("graph", graph); + archive << boost::make_nvp("plain_graph", plain_graph); + } + + CSRGraph restored; + PlainCSRGraph restored_plain_graph; + { + boost::archive::xml_iarchive archive(buffer); + archive >> boost::make_nvp("graph", restored); + archive >> boost::make_nvp("plain_graph", restored_plain_graph); + } + + if (boost::num_vertices(restored) != 3 || boost::num_edges(restored) != 3 + || restored[0].name != "A" || restored[1].name != "B" + || restored[2].name != "C" + || boost::get_property(restored, boost::graph_all_t()).name != "sample") + return 1; + + const auto e01 = boost::edge(Vertex(0), Vertex(1), restored); + const auto e02 = boost::edge(Vertex(0), Vertex(2), restored); + const auto e21 = boost::edge(Vertex(2), Vertex(1), restored); + if (!e01.second || !e02.second || !e21.second + || restored[e01.first].weight != 7 || restored[e02.first].weight != 11 + || restored[e21.first].weight != 13) + return 1; + + if (boost::num_vertices(restored_plain_graph) != 3 + || boost::num_edges(restored_plain_graph) != 2 + || !boost::edge(Vertex(0), Vertex(1), restored_plain_graph).second + || !boost::edge(Vertex(1), Vertex(2), restored_plain_graph).second) + return 1; + + return 0; +} From 652e5b2835597faef4c41c000844fbdd940e3dc4 Mon Sep 17 00:00:00 2001 From: varunsha30 Date: Mon, 19 Oct 2026 14:37:57 +0530 Subject: [PATCH 3/5] chore: re-trigger CI From 1dac7c282c787bdc40ce7de05eee60f73299beb3 Mon Sep 17 00:00:00 2001 From: varunsha30 Date: Mon, 19 Oct 2026 19:45:46 +0530 Subject: [PATCH 4/5] Add bidirectional support for the CSR serializer. --- include/boost/graph/csr_graph_serialize.hpp | 4 +- test/csr_graph_serialize.cpp | 46 +++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/boost/graph/csr_graph_serialize.hpp b/include/boost/graph/csr_graph_serialize.hpp index 552bcc53a..e443a53a0 100644 --- a/include/boost/graph/csr_graph_serialize.hpp +++ b/include/boost/graph/csr_graph_serialize.hpp @@ -125,8 +125,8 @@ namespace serialization edge_properties.push_back(std::move(edge_property)); } - Graph rebuilt(boost::edges_are_sorted, endpoints.begin(), - endpoints.end(), edge_properties.begin(), V, E); + Graph rebuilt(boost::edges_are_unsorted_multi_pass, endpoints.begin(), + endpoints.end(), edge_properties.begin(), V); auto loaded_vertices = boost::vertices(loaded); auto rebuilt_vertices = boost::vertices(rebuilt); diff --git a/test/csr_graph_serialize.cpp b/test/csr_graph_serialize.cpp index 93da5c1be..60f9baedd 100644 --- a/test/csr_graph_serialize.cpp +++ b/test/csr_graph_serialize.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -55,6 +56,9 @@ typedef boost::compressed_sparse_row_graph< boost::directedS, vertex_properties, edge_properties, graph_properties > CSRGraph; typedef boost::compressed_sparse_row_graph< boost::directedS > PlainCSRGraph; +typedef boost::compressed_sparse_row_graph< boost::bidirectionalS, + vertex_properties, edge_properties, graph_properties > + BidirCSRGraph; static_assert(boost::serialization::tracking_level< CSRGraph >::value == boost::serialization::track_never, @@ -75,25 +79,37 @@ int main() CSRGraph graph(boost::edges_are_sorted, endpoints.begin(), endpoints.end(), edge_data.begin(), 3, endpoints.size()); + BidirCSRGraph bidirectional_graph(boost::edges_are_sorted, + endpoints.begin(), endpoints.end(), edge_data.begin(), 3, + endpoints.size()); PlainCSRGraph plain_graph(boost::edges_are_sorted, plain_endpoints.begin(), plain_endpoints.end(), 3); graph[0].name = "A"; graph[1].name = "B"; graph[2].name = "C"; boost::get_property(graph, boost::graph_all_t()).name = "sample"; + bidirectional_graph[0].name = "A"; + bidirectional_graph[1].name = "B"; + bidirectional_graph[2].name = "C"; + boost::get_property(bidirectional_graph, boost::graph_all_t()).name + = "sample"; std::stringstream buffer; { boost::archive::xml_oarchive archive(buffer); archive << boost::make_nvp("graph", graph); + archive << boost::make_nvp("bidirectional_graph", bidirectional_graph); archive << boost::make_nvp("plain_graph", plain_graph); } CSRGraph restored; + BidirCSRGraph restored_bidirectional; PlainCSRGraph restored_plain_graph; { boost::archive::xml_iarchive archive(buffer); archive >> boost::make_nvp("graph", restored); + archive >> boost::make_nvp( + "bidirectional_graph", restored_bidirectional); archive >> boost::make_nvp("plain_graph", restored_plain_graph); } @@ -103,6 +119,36 @@ int main() || boost::get_property(restored, boost::graph_all_t()).name != "sample") return 1; + if (boost::num_vertices(restored_bidirectional) != 3 + || boost::num_edges(restored_bidirectional) != 3 + || restored_bidirectional[0].name != "A" + || restored_bidirectional[1].name != "B" + || restored_bidirectional[2].name != "C" + || boost::get_property( + restored_bidirectional, boost::graph_all_t()).name + != "sample") + return 1; + + const auto incoming = boost::in_edges(Vertex(1), restored_bidirectional); + if (boost::in_degree(Vertex(1), restored_bidirectional) != 2 + || std::distance(incoming.first, incoming.second) != 2) + return 1; + + bool found_0_to_1 = false; + bool found_2_to_1 = false; + for (auto it = incoming.first; it != incoming.second; ++it) + { + const Vertex source = boost::source(*it, restored_bidirectional); + const Vertex target = boost::target(*it, restored_bidirectional); + const int weight = restored_bidirectional[*it].weight; + if (source == Vertex(0) && target == Vertex(1) && weight == 7) + found_0_to_1 = true; + else if (source == Vertex(2) && target == Vertex(1) && weight == 13) + found_2_to_1 = true; + } + if (!found_0_to_1 || !found_2_to_1) + return 1; + const auto e01 = boost::edge(Vertex(0), Vertex(1), restored); const auto e02 = boost::edge(Vertex(0), Vertex(2), restored); const auto e21 = boost::edge(Vertex(2), Vertex(1), restored); From ebb1b9361852b921070d5239c1c82168c5672b30 Mon Sep 17 00:00:00 2001 From: varunsha30 Date: Mon, 19 Oct 2026 22:37:18 +0530 Subject: [PATCH 5/5] Added changes based on the comments. --- include/boost/graph/adj_matrix_serialize.hpp | 17 ++-- include/boost/graph/csr_graph_serialize.hpp | 31 +++---- test/adj_matrix_serialize.cpp | 44 +++++----- test/csr_graph_serialize.cpp | 87 +++++++++++--------- 4 files changed, 87 insertions(+), 92 deletions(-) diff --git a/include/boost/graph/adj_matrix_serialize.hpp b/include/boost/graph/adj_matrix_serialize.hpp index 273795bef..74a70e02d 100644 --- a/include/boost/graph/adj_matrix_serialize.hpp +++ b/include/boost/graph/adj_matrix_serialize.hpp @@ -30,8 +30,7 @@ namespace serialization struct tracking_level_impl; template < class Directed, class VP, class EP, class GP, class Allocator > - struct tracking_level_impl< - const boost::adjacency_matrix< Directed, VP, EP, GP, Allocator > > + struct tracking_level_impl< const boost::adjacency_matrix< Directed, VP, EP, GP, Allocator > > : boost::integral_constant< int, 0 > { }; @@ -50,8 +49,8 @@ namespace serialization auto vertex_range = boost::vertices(graph); for (auto it = vertex_range.first; it != vertex_range.second; ++it) { - auto&& vertex_property = - boost::get(boost::vertex_all_t(), graph, *it); + const auto& vertex_property + = boost::get(boost::vertex_all_t(), graph, *it); ar << BOOST_NVP(vertex_property); } @@ -60,8 +59,8 @@ namespace serialization { const auto u = boost::source(*it, graph); const auto v = boost::target(*it, graph); - auto&& edge_property = - boost::get(boost::edge_all_t(), graph, *it); + const auto& edge_property + = boost::get(boost::edge_all_t(), graph, *it); ar << BOOST_NVP(u); ar << BOOST_NVP(v); @@ -93,8 +92,8 @@ namespace serialization auto vertex_range = boost::vertices(loaded); for (auto it = vertex_range.first; it != vertex_range.second; ++it) { - auto&& vertex_property = - boost::get(boost::vertex_all_t(), loaded, *it); + auto& vertex_property + = boost::get(boost::vertex_all_t(), loaded, *it); ar >> BOOST_NVP(vertex_property); } @@ -107,7 +106,7 @@ namespace serialization ar >> BOOST_NVP(v); const auto e = boost::add_edge(u, v, loaded).first; - auto&& edge_property = boost::get(boost::edge_all_t(), loaded, e); + auto& edge_property = boost::get(boost::edge_all_t(), loaded, e); ar >> BOOST_NVP(edge_property); } diff --git a/include/boost/graph/csr_graph_serialize.hpp b/include/boost/graph/csr_graph_serialize.hpp index e443a53a0..44ae0a9eb 100644 --- a/include/boost/graph/csr_graph_serialize.hpp +++ b/include/boost/graph/csr_graph_serialize.hpp @@ -53,7 +53,7 @@ namespace serialization auto vertex_range = boost::vertices(graph); for (auto it = vertex_range.first; it != vertex_range.second; ++it) { - auto&& vertex_property + const auto& vertex_property = boost::get(boost::vertex_all_t(), graph, *it); ar << BOOST_NVP(vertex_property); } @@ -63,7 +63,7 @@ namespace serialization { const auto u = boost::source(*it, graph); const auto v = boost::target(*it, graph); - const auto edge_property + const auto& edge_property = boost::get(boost::edge_all_t(), graph, *it); ar << BOOST_NVP(u); @@ -87,6 +87,7 @@ namespace serialization using VertexSize = typename Graph::vertices_size_type; using EdgeSize = typename Graph::edges_size_type; using VertexDescriptor = typename Graph::vertex_descriptor; + using VertexProperty = typename Graph::vertex_bundled; using EdgeProperty = typename Graph::edge_bundled; VertexSize V = 0; @@ -95,13 +96,10 @@ namespace serialization ar >> BOOST_NVP(V); ar >> BOOST_NVP(E); - Graph loaded(V); - - auto vertex_range = boost::vertices(loaded); - for (auto it = vertex_range.first; it != vertex_range.second; ++it) + std::vector< VertexProperty > vertex_properties( + static_cast< std::size_t >(V)); + for (auto& vertex_property : vertex_properties) { - auto&& vertex_property - = boost::get(boost::vertex_all_t(), loaded, *it); ar >> BOOST_NVP(vertex_property); } @@ -125,19 +123,12 @@ namespace serialization edge_properties.push_back(std::move(edge_property)); } - Graph rebuilt(boost::edges_are_unsorted_multi_pass, endpoints.begin(), - endpoints.end(), edge_properties.begin(), V); - - auto loaded_vertices = boost::vertices(loaded); - auto rebuilt_vertices = boost::vertices(rebuilt); - for (auto loaded_it = loaded_vertices.first, - rebuilt_it = rebuilt_vertices.first; - loaded_it != loaded_vertices.second - && rebuilt_it != rebuilt_vertices.second; - ++loaded_it, ++rebuilt_it) + Graph rebuilt(boost::edges_are_sorted, endpoints.begin(), + endpoints.end(), edge_properties.begin(), V, E); + for (VertexDescriptor vertex = 0; vertex < V; ++vertex) { - boost::get(boost::vertex_all_t(), rebuilt, *rebuilt_it) = std::move( - boost::get(boost::vertex_all_t(), loaded, *loaded_it)); + boost::get(boost::vertex_all_t(), rebuilt, vertex) = std::move( + vertex_properties[static_cast< std::size_t >(vertex)]); } ar >> boost::make_nvp("graph_property", diff --git a/test/adj_matrix_serialize.cpp b/test/adj_matrix_serialize.cpp index afd25f4cc..b68acee0a 100644 --- a/test/adj_matrix_serialize.cpp +++ b/test/adj_matrix_serialize.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -35,10 +36,9 @@ struct edge_properties } }; -typedef boost::adjacency_matrix< boost::directedS > DirectedGraph; -typedef boost::adjacency_matrix< boost::undirectedS, vertex_properties, - edge_properties > - UndirectedGraph; +using DirectedGraph = boost::adjacency_matrix< boost::directedS >; +using UndirectedGraph = boost::adjacency_matrix< boost::undirectedS, + vertex_properties, edge_properties >; static_assert(boost::serialization::tracking_level< DirectedGraph >::value == boost::serialization::track_never, @@ -78,26 +78,26 @@ int main() archive >> boost::make_nvp("undirected_graph", restored_undirected); } - if (boost::num_vertices(restored_directed) != 3 || - boost::num_edges(restored_directed) != 2 || - !boost::edge(0, 1, restored_directed).second || - !boost::edge(1, 2, restored_directed).second || - boost::edge(1, 0, restored_directed).second) - return 1; + BOOST_TEST(boost::num_vertices(restored_directed) == 3); + BOOST_TEST(boost::num_edges(restored_directed) == 2); + BOOST_TEST(boost::edge(0, 1, restored_directed).second); + BOOST_TEST(boost::edge(1, 2, restored_directed).second); + BOOST_TEST(!boost::edge(1, 0, restored_directed).second); - if (boost::num_vertices(restored_undirected) != 3 || - boost::num_edges(restored_undirected) != 2 || - restored_undirected[0].name != "A" || - restored_undirected[1].name != "B" || - restored_undirected[2].name != "C") - return 1; + BOOST_TEST(boost::num_vertices(restored_undirected) == 3); + BOOST_TEST(boost::num_edges(restored_undirected) == 2); + BOOST_TEST(restored_undirected[0].name == "A"); + BOOST_TEST(restored_undirected[1].name == "B"); + BOOST_TEST(restored_undirected[2].name == "C"); const auto first = boost::edge(0, 1, restored_undirected); const auto second = boost::edge(1, 2, restored_undirected); - if (!first.second || !second.second || - restored_undirected[first.first].weight != 7 || - restored_undirected[second.first].weight != 11) - return 1; - - return 0; + BOOST_TEST(first.second); + BOOST_TEST(second.second); + if (first.second) + BOOST_TEST(restored_undirected[first.first].weight == 7); + if (second.second) + BOOST_TEST(restored_undirected[second.first].weight == 11); + + return boost::report_errors(); } diff --git a/test/csr_graph_serialize.cpp b/test/csr_graph_serialize.cpp index 60f9baedd..ad4b925ee 100644 --- a/test/csr_graph_serialize.cpp +++ b/test/csr_graph_serialize.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -52,13 +53,11 @@ struct graph_properties } }; -typedef boost::compressed_sparse_row_graph< boost::directedS, vertex_properties, - edge_properties, graph_properties > - CSRGraph; -typedef boost::compressed_sparse_row_graph< boost::directedS > PlainCSRGraph; -typedef boost::compressed_sparse_row_graph< boost::bidirectionalS, - vertex_properties, edge_properties, graph_properties > - BidirCSRGraph; +using CSRGraph = boost::compressed_sparse_row_graph< boost::directedS, + vertex_properties, edge_properties, graph_properties >; +using PlainCSRGraph = boost::compressed_sparse_row_graph< boost::directedS >; +using BidirCSRGraph = boost::compressed_sparse_row_graph< boost::bidirectionalS, + vertex_properties, edge_properties, graph_properties >; static_assert(boost::serialization::tracking_level< CSRGraph >::value == boost::serialization::track_never, @@ -69,8 +68,8 @@ static_assert(boost::serialization::tracking_level< PlainCSRGraph >::value int main() { - typedef CSRGraph::vertex_descriptor Vertex; - typedef std::pair< Vertex, Vertex > Edge; + using Vertex = CSRGraph::vertex_descriptor; + using Edge = std::pair< Vertex, Vertex >; std::vector< Edge > endpoints { Edge(0, 1), Edge(0, 2), Edge(2, 1) }; std::vector< edge_properties > edge_data { edge_properties { 7 }, @@ -113,26 +112,26 @@ int main() archive >> boost::make_nvp("plain_graph", restored_plain_graph); } - if (boost::num_vertices(restored) != 3 || boost::num_edges(restored) != 3 - || restored[0].name != "A" || restored[1].name != "B" - || restored[2].name != "C" - || boost::get_property(restored, boost::graph_all_t()).name != "sample") - return 1; - - if (boost::num_vertices(restored_bidirectional) != 3 - || boost::num_edges(restored_bidirectional) != 3 - || restored_bidirectional[0].name != "A" - || restored_bidirectional[1].name != "B" - || restored_bidirectional[2].name != "C" - || boost::get_property( - restored_bidirectional, boost::graph_all_t()).name - != "sample") - return 1; + BOOST_TEST(boost::num_vertices(restored) == 3); + BOOST_TEST(boost::num_edges(restored) == 3); + BOOST_TEST(restored[0].name == "A"); + BOOST_TEST(restored[1].name == "B"); + BOOST_TEST(restored[2].name == "C"); + BOOST_TEST( + boost::get_property(restored, boost::graph_all_t()).name == "sample"); + + BOOST_TEST(boost::num_vertices(restored_bidirectional) == 3); + BOOST_TEST(boost::num_edges(restored_bidirectional) == 3); + BOOST_TEST(restored_bidirectional[0].name == "A"); + BOOST_TEST(restored_bidirectional[1].name == "B"); + BOOST_TEST(restored_bidirectional[2].name == "C"); + BOOST_TEST(boost::get_property( + restored_bidirectional, boost::graph_all_t()).name + == "sample"); const auto incoming = boost::in_edges(Vertex(1), restored_bidirectional); - if (boost::in_degree(Vertex(1), restored_bidirectional) != 2 - || std::distance(incoming.first, incoming.second) != 2) - return 1; + BOOST_TEST(boost::in_degree(Vertex(1), restored_bidirectional) == 2); + BOOST_TEST(std::distance(incoming.first, incoming.second) == 2); bool found_0_to_1 = false; bool found_2_to_1 = false; @@ -146,22 +145,28 @@ int main() else if (source == Vertex(2) && target == Vertex(1) && weight == 13) found_2_to_1 = true; } - if (!found_0_to_1 || !found_2_to_1) - return 1; + BOOST_TEST(found_0_to_1); + BOOST_TEST(found_2_to_1); const auto e01 = boost::edge(Vertex(0), Vertex(1), restored); const auto e02 = boost::edge(Vertex(0), Vertex(2), restored); const auto e21 = boost::edge(Vertex(2), Vertex(1), restored); - if (!e01.second || !e02.second || !e21.second - || restored[e01.first].weight != 7 || restored[e02.first].weight != 11 - || restored[e21.first].weight != 13) - return 1; - - if (boost::num_vertices(restored_plain_graph) != 3 - || boost::num_edges(restored_plain_graph) != 2 - || !boost::edge(Vertex(0), Vertex(1), restored_plain_graph).second - || !boost::edge(Vertex(1), Vertex(2), restored_plain_graph).second) - return 1; - - return 0; + BOOST_TEST(e01.second); + BOOST_TEST(e02.second); + BOOST_TEST(e21.second); + if (e01.second) + BOOST_TEST(restored[e01.first].weight == 7); + if (e02.second) + BOOST_TEST(restored[e02.first].weight == 11); + if (e21.second) + BOOST_TEST(restored[e21.first].weight == 13); + + BOOST_TEST(boost::num_vertices(restored_plain_graph) == 3); + BOOST_TEST(boost::num_edges(restored_plain_graph) == 2); + BOOST_TEST( + boost::edge(Vertex(0), Vertex(1), restored_plain_graph).second); + BOOST_TEST( + boost::edge(Vertex(1), Vertex(2), restored_plain_graph).second); + + return boost::report_errors(); }