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/optional.hpp>
25 #include <boost/range/adaptor/transformed.hpp>
26 #include <boost/range/iterator_range.hpp>
27 #include <fstream>
28 #include <unordered_map>
29 #include <type_traits>
30 
31 namespace ripple {
32 namespace test {
33 namespace csf {
34 
35 namespace detail {
36 // Dummy class when no edge data needed for graph
37 struct NoEdgeData
38 {
39 };
40 
41 } // namespace detail
42 
53 template <class Vertex, class EdgeData = detail::NoEdgeData>
54 class Digraph
55 {
56  using Links = boost::container::flat_map<Vertex, EdgeData>;
57  using Graph = boost::container::flat_map<Vertex, Links>;
59 
60  // Allows returning empty iterables for unknown vertices
62 
63 public:
72  bool
73  connect(Vertex source, Vertex target, EdgeData e)
74  {
75  return graph_[source].emplace(target, e).second;
76  }
77 
85  bool
86  connect(Vertex source, Vertex target)
87  {
88  return connect(source, target, EdgeData{});
89  }
90 
99  bool
100  disconnect(Vertex source, Vertex target)
101  {
102  auto it = graph_.find(source);
103  if (it != graph_.end())
104  {
105  return it->second.erase(target) > 0;
106  }
107  return false;
108  }
109 
117  boost::optional<EdgeData>
118  edge(Vertex source, Vertex target) const
119  {
120  auto it = graph_.find(source);
121  if (it != graph_.end())
122  {
123  auto edgeIt = it->second.find(target);
124  if (edgeIt != it->second.end())
125  return edgeIt->second;
126  }
127  return boost::none;
128  }
129 
136  bool
137  connected(Vertex source, Vertex target) const
138  {
139  return edge(source, target) != boost::none;
140  }
141 
147  auto
148  outVertices() const
149  {
150  return boost::adaptors::transform(
151  graph_,
152  [](typename Graph::value_type const& v) { return v.first; });
153  }
154 
160  auto
161  outVertices(Vertex source) const
162  {
163  auto transform = [](typename Links::value_type const& link) {
164  return link.first;
165  };
166  auto it = graph_.find(source);
167  if (it != graph_.end())
168  return boost::adaptors::transform(it->second, transform);
169 
170  return boost::adaptors::transform(empty, transform);
171  }
172 
175  struct Edge
176  {
177  Vertex source;
178  Vertex target;
179  EdgeData data;
180  };
181 
188  auto
189  outEdges(Vertex source) const
190  {
191  auto transform = [source](typename Links::value_type const& link) {
192  return Edge{source, link.first, link.second};
193  };
194 
195  auto it = graph_.find(source);
196  if (it != graph_.end())
197  return boost::adaptors::transform(it->second, transform);
198 
199  return boost::adaptors::transform(empty, transform);
200  }
201 
208  outDegree(Vertex source) const
209  {
210  auto it = graph_.find(source);
211  if (it != graph_.end())
212  return it->second.size();
213  return 0;
214  }
215 
224  template <class VertexName>
225  void
226  saveDot(std::ostream & out, VertexName&& vertexName) const
227  {
228  out << "digraph {\n";
229  for (auto const& [vertex, links] : graph_)
230  {
231  auto const fromName = vertexName(vertex);
232  for (auto const& eData : links)
233  {
234  auto const toName = vertexName(eData.first);
235  out << fromName << " -> " << toName << ";\n";
236  }
237  }
238  out << "}\n";
239  }
240 
241  template <class VertexName>
242  void
243  saveDot(std::string const& fileName, VertexName&& vertexName) const
244  {
245  std::ofstream out(fileName);
246  saveDot(out, std::forward<VertexName>(vertexName));
247  }
248 };
249 
250 } // namespace csf
251 } // namespace test
252 } // namespace ripple
253 #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:56
ripple::test::csf::Digraph::Edge::target
Vertex target
Definition: Digraph.h:178
fstream
std::string
STL class.
ripple::test::csf::Digraph::outVertices
auto outVertices() const
Range over vertices in the graph.
Definition: Digraph.h:148
ripple::test::csf::Digraph::connect
bool connect(Vertex source, Vertex target)
Connect two vertices using default constructed edge data.
Definition: Digraph.h:86
ripple::test::csf::Digraph::saveDot
void saveDot(std::ostream &out, VertexName &&vertexName) const
Save GraphViz dot file.
Definition: Digraph.h:226
ripple::test::csf::Digraph::empty
Links empty
Definition: Digraph.h:61
ripple::test::csf::Digraph
Directed graph.
Definition: Digraph.h:54
ripple::test::csf::Digraph::outVertices
auto outVertices(Vertex source) const
Range over target vertices.
Definition: Digraph.h:161
ripple::test::csf::Digraph::graph_
Graph graph_
Definition: Digraph.h:58
ripple::test::csf::Digraph::Edge::source
Vertex source
Definition: Digraph.h:177
ripple::QualityDirection::out
@ out
ripple::test::csf::Digraph::disconnect
bool disconnect(Vertex source, Vertex target)
Disconnect two vertices.
Definition: Digraph.h:100
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:208
ripple::test::csf::Digraph::edge
boost::optional< EdgeData > edge(Vertex source, Vertex target) const
Return edge data between two vertices.
Definition: Digraph.h:118
ripple::test::csf::Digraph::Edge::data
EdgeData data
Definition: Digraph.h:179
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:37
std::size_t
ripple::test::csf::Digraph::connect
bool connect(Vertex source, Vertex target, EdgeData e)
Connect two vertices.
Definition: Digraph.h:73
ripple::test::csf::Digraph::connected
bool connected(Vertex source, Vertex target) const
Check if two vertices are connected.
Definition: Digraph.h:137
ripple::test::csf::Digraph::outEdges
auto outEdges(Vertex source) const
Range of out edges.
Definition: Digraph.h:189
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:57
type_traits
ripple::test::csf::Digraph::saveDot
void saveDot(std::string const &fileName, VertexName &&vertexName) const
Definition: Digraph.h:243
ripple::test::csf::Digraph::Edge
Vertices and data associated with an Edge.
Definition: Digraph.h:175