20 #ifndef RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
21 #define RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
23 #include <boost/container/flat_map.hpp>
24 #include <boost/optional.hpp>
25 #include <boost/range/adaptor/transformed.hpp>
26 #include <boost/range/iterator_range.hpp>
53 template <
class Vertex,
class EdgeData = detail::NoEdgeData>
56 using Links = boost::container::flat_map<Vertex, EdgeData>;
57 using Graph = boost::container::flat_map<Vertex, Links>;
73 connect(Vertex source, Vertex target, EdgeData e)
75 return graph_[source].emplace(target, e).second;
88 return connect(source, target, EdgeData{});
102 auto it =
graph_.find(source);
105 return it->second.erase(target) > 0;
117 boost::optional<EdgeData>
118 edge(Vertex source, Vertex target)
const
120 auto it =
graph_.find(source);
123 auto edgeIt = it->second.find(target);
124 if (edgeIt != it->second.end())
125 return edgeIt->second;
139 return edge(source, target) != boost::none;
150 return boost::adaptors::transform(
152 [](
typename Graph::value_type
const& v) {
return v.first; });
163 auto transform = [](
typename Links::value_type
const& link) {
166 auto it =
graph_.find(source);
168 return boost::adaptors::transform(it->second, transform);
170 return boost::adaptors::transform(
empty, transform);
191 auto transform = [source](
typename Links::value_type
const& link) {
192 return Edge{source, link.first, link.second};
195 auto it =
graph_.find(source);
197 return boost::adaptors::transform(it->second, transform);
199 return boost::adaptors::transform(
empty, transform);
210 auto it =
graph_.find(source);
212 return it->second.size();
224 template <
class VertexName>
228 out <<
"digraph {\n";
229 for (
auto const& [vertex, links] :
graph_)
231 auto const fromName = vertexName(vertex);
232 for (
auto const& eData : links)
234 auto const toName = vertexName(eData.first);
235 out << fromName <<
" -> " << toName <<
";\n";
241 template <
class VertexName>
246 saveDot(
out, std::forward<VertexName>(vertexName));