rippled
Digraph.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 Ripple Labs Inc
5 
6  Permission target use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
21 #define RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
22 
23 #include <boost/container/flat_map.hpp>
24 #include <boost/range/adaptor/transformed.hpp>
25 #include <boost/range/iterator_range.hpp>
26 
27 #include <fstream>
28 #include <optional>
29 #include <type_traits>
30 #include <unordered_map>
31 
32 namespace ripple {
33 namespace test {
34 namespace csf {
35 
36 namespace detail {
37 // Dummy class when no edge data needed for graph
38 struct NoEdgeData
39 {
40 };
41 
42 } // namespace detail
43 
54 template <class Vertex, class EdgeData = detail::NoEdgeData>
55 class Digraph
56 {
57  using Links = boost::container::flat_map<Vertex, EdgeData>;
58  using Graph = boost::container::flat_map<Vertex, Links>;
60 
61  // Allows returning empty iterables for unknown vertices
63 
64 public:
73  bool
74  connect(Vertex source, Vertex target, EdgeData e)
75  {
76  return graph_[source].emplace(target, e).second;
77  }
78 
86  bool
87  connect(Vertex source, Vertex target)
88  {
89  return connect(source, target, EdgeData{});
90  }
91 
100  bool
101  disconnect(Vertex source, Vertex target)
102  {
103  auto it = graph_.find(source);
104  if (it != graph_.end())
105  {
106  return it->second.erase(target) > 0;
107  }
108  return false;
109  }
110 
119  edge(Vertex source, Vertex target) const
120  {
121  auto it = graph_.find(source);
122  if (it != graph_.end())
123  {
124  auto edgeIt = it->second.find(target);
125  if (edgeIt != it->second.end())
126  return edgeIt->second;
127  }
128  return std::nullopt;
129  }
130 
137  bool
138  connected(Vertex source, Vertex target) const
139  {
140  return edge(source, target) != std::nullopt;
141  }
142 
148  auto
149  outVertices() const
150  {
151  return boost::adaptors::transform(
152  graph_,
153  [](typename Graph::value_type const& v) { return v.first; });
154  }
155 
161  auto
162  outVertices(Vertex source) const
163  {
164  auto transform = [](typename Links::value_type const& link) {
165  return link.first;
166  };
167  auto it = graph_.find(source);
168  if (it != graph_.end())
169  return boost::adaptors::transform(it->second, transform);
170 
171  return boost::adaptors::transform(empty, transform);
172  }
173 
176  struct Edge
177  {
178  Vertex source;
179  Vertex target;
180  EdgeData data;
181  };
182 
189  auto
190  outEdges(Vertex source) const
191  {
192  auto transform = [source](typename Links::value_type const& link) {
193  return Edge{source, link.first, link.second};
194  };
195 
196  auto it = graph_.find(source);
197  if (it != graph_.end())
198  return boost::adaptors::transform(it->second, transform);
199 
200  return boost::adaptors::transform(empty, transform);
201  }
202 
209  outDegree(Vertex source) const
210  {
211  auto it = graph_.find(source);
212  if (it != graph_.end())
213  return it->second.size();
214  return 0;
215  }
216 
225  template <class VertexName>
226  void
227  saveDot(std::ostream& out, VertexName&& vertexName) const
228  {
229  out << "digraph {\n";
230  for (auto const& [vertex, links] : graph_)
231  {
232  auto const fromName = vertexName(vertex);
233  for (auto const& eData : links)
234  {
235  auto const toName = vertexName(eData.first);
236  out << fromName << " -> " << toName << ";\n";
237  }
238  }
239  out << "}\n";
240  }
241 
242  template <class VertexName>
243  void
244  saveDot(std::string const& fileName, VertexName&& vertexName) const
245  {
246  std::ofstream out(fileName);
247  saveDot(out, std::forward<VertexName>(vertexName));
248  }
249 };
250 
251 } // namespace csf
252 } // namespace test
253 } // namespace ripple
254 #endif
ripple::test::csf::Digraph< ripple::test::csf::ripple::test::csf::Peer *, ripple::test::csf::BasicNetwork::link_type >::Links
boost::container::flat_map< ripple::test::csf::ripple::test::csf::Peer *, ripple::test::csf::BasicNetwork::link_type > Links
Definition: Digraph.h:57
ripple::test::csf::Digraph::Edge::target
Vertex target
Definition: Digraph.h:179
fstream
std::string
STL class.
ripple::test::csf::Digraph::outVertices
auto outVertices() const
Range over vertices in the graph.
Definition: Digraph.h:149
ripple::test::csf::Digraph::connect
bool connect(Vertex source, Vertex target)
Connect two vertices using default constructed edge data.
Definition: Digraph.h:87
ripple::test::csf::Digraph::saveDot
void saveDot(std::ostream &out, VertexName &&vertexName) const
Save GraphViz dot file.
Definition: Digraph.h:227
ripple::test::csf::Digraph::empty
Links empty
Definition: Digraph.h:62
ripple::test::csf::Digraph
Directed graph.
Definition: Digraph.h:55
ripple::test::csf::Digraph::outVertices
auto outVertices(Vertex source) const
Range over target vertices.
Definition: Digraph.h:162
ripple::test::csf::Digraph::graph_
Graph graph_
Definition: Digraph.h:59
ripple::test::csf::Digraph::Edge::source
Vertex source
Definition: Digraph.h:178
ripple::QualityDirection::out
@ out
ripple::test::csf::Digraph::disconnect
bool disconnect(Vertex source, Vertex target)
Disconnect two vertices.
Definition: Digraph.h:101
std::ostream
STL class.
std::ofstream
STL class.
ripple::test::csf::Digraph::outDegree
std::size_t outDegree(Vertex source) const
Vertex out-degree.
Definition: Digraph.h:209
ripple::test::csf::Digraph::edge
std::optional< EdgeData > edge(Vertex source, Vertex target) const
Return edge data between two vertices.
Definition: Digraph.h:119
ripple::test::csf::Digraph::Edge::data
EdgeData data
Definition: Digraph.h:180
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::csf::detail::NoEdgeData
Definition: Digraph.h:38
optional
std::size_t
ripple::test::csf::Digraph::connect
bool connect(Vertex source, Vertex target, EdgeData e)
Connect two vertices.
Definition: Digraph.h:74
ripple::test::csf::Digraph::connected
bool connected(Vertex source, Vertex target) const
Check if two vertices are connected.
Definition: Digraph.h:138
ripple::test::csf::Digraph::outEdges
auto outEdges(Vertex source) const
Range of out edges.
Definition: Digraph.h:190
unordered_map
ripple::test::csf::Digraph< ripple::test::csf::ripple::test::csf::Peer *, ripple::test::csf::BasicNetwork::link_type >::Graph
boost::container::flat_map< ripple::test::csf::ripple::test::csf::Peer *, Links > Graph
Definition: Digraph.h:58
type_traits
ripple::test::csf::Digraph::saveDot
void saveDot(std::string const &fileName, VertexName &&vertexName) const
Definition: Digraph.h:244
ripple::test::csf::Digraph::Edge
Vertices and data associated with an Edge.
Definition: Digraph.h:176