mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
254 lines
7.0 KiB
C++
254 lines
7.0 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of rippled: https://github.com/ripple/rippled
|
|
Copyright (c) 2012-2017 Ripple Labs Inc
|
|
|
|
Permission target use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
|
|
#define RIPPLE_TEST_CSF_DIGRAPH_H_INCLUDED
|
|
|
|
#include <boost/container/flat_map.hpp>
|
|
#include <boost/optional.hpp>
|
|
#include <boost/range/adaptor/transformed.hpp>
|
|
#include <boost/range/iterator_range.hpp>
|
|
#include <fstream>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
|
|
namespace ripple {
|
|
namespace test {
|
|
namespace csf {
|
|
|
|
namespace detail {
|
|
// Dummy class when no edge data needed for graph
|
|
struct NoEdgeData
|
|
{
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
/** Directed graph
|
|
|
|
Basic directed graph that uses an adjacency list to represent out edges.
|
|
|
|
Instances of Vertex uniquely identify vertices in the graph. Instances of
|
|
EdgeData is any data to store in the edge connecting two vertices.
|
|
|
|
Both Vertex and EdgeData should be lightweight and cheap to copy.
|
|
|
|
*/
|
|
template <class Vertex, class EdgeData = detail::NoEdgeData>
|
|
class Digraph
|
|
{
|
|
using Links = boost::container::flat_map<Vertex, EdgeData>;
|
|
using Graph = boost::container::flat_map<Vertex, Links>;
|
|
Graph graph_;
|
|
|
|
// Allows returning empty iterables for unknown vertices
|
|
Links empty;
|
|
|
|
public:
|
|
/** Connect two vertices
|
|
|
|
@param source The source vertex
|
|
@param target The target vertex
|
|
@param e The edge data
|
|
@return true if the edge was created
|
|
|
|
*/
|
|
bool
|
|
connect(Vertex source, Vertex target, EdgeData e)
|
|
{
|
|
return graph_[source].emplace(target, e).second;
|
|
}
|
|
|
|
/** Connect two vertices using default constructed edge data
|
|
|
|
@param source The source vertex
|
|
@param target The target vertex
|
|
@return true if the edge was created
|
|
|
|
*/
|
|
bool
|
|
connect(Vertex source, Vertex target)
|
|
{
|
|
return connect(source, target, EdgeData{});
|
|
}
|
|
|
|
/** Disconnect two vertices
|
|
|
|
@param source The source vertex
|
|
@param target The target vertex
|
|
@return true if an edge was removed
|
|
|
|
If source is not connected to target, this function does nothing.
|
|
*/
|
|
bool
|
|
disconnect(Vertex source, Vertex target)
|
|
{
|
|
auto it = graph_.find(source);
|
|
if (it != graph_.end())
|
|
{
|
|
return it->second.erase(target) > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Return edge data between two vertices
|
|
|
|
@param source The source vertex
|
|
@param target The target vertex
|
|
@return optional<Edge> which is boost::none if no edge exists
|
|
|
|
*/
|
|
boost::optional<EdgeData>
|
|
edge(Vertex source, Vertex target) const
|
|
{
|
|
auto it = graph_.find(source);
|
|
if (it != graph_.end())
|
|
{
|
|
auto edgeIt = it->second.find(target);
|
|
if (edgeIt != it->second.end())
|
|
return edgeIt->second;
|
|
}
|
|
return boost::none;
|
|
}
|
|
|
|
/** Check if two vertices are connected
|
|
|
|
@param source The source vertex
|
|
@param target The target vertex
|
|
@return true if the source has an out edge to target
|
|
*/
|
|
bool
|
|
connected(Vertex source, Vertex target) const
|
|
{
|
|
return edge(source, target) != boost::none;
|
|
}
|
|
|
|
/** Range over vertices in the graph
|
|
|
|
@return A boost transformed range over the vertices with out edges in
|
|
the graph
|
|
*/
|
|
auto
|
|
outVertices() const
|
|
{
|
|
return boost::adaptors::transform(
|
|
graph_,
|
|
[](typename Graph::value_type const& v) { return v.first; });
|
|
}
|
|
|
|
/** Range over target vertices
|
|
|
|
@param source The source vertex
|
|
@return A boost transformed range over the target vertices of source.
|
|
*/
|
|
auto
|
|
outVertices(Vertex source) const
|
|
{
|
|
auto transform = [](typename Links::value_type const& link) {
|
|
return link.first;
|
|
};
|
|
auto it = graph_.find(source);
|
|
if (it != graph_.end())
|
|
return boost::adaptors::transform(it->second, transform);
|
|
|
|
return boost::adaptors::transform(empty, transform);
|
|
}
|
|
|
|
/** Vertices and data associated with an Edge
|
|
*/
|
|
struct Edge
|
|
{
|
|
Vertex source;
|
|
Vertex target;
|
|
EdgeData data;
|
|
};
|
|
|
|
/** Range of out edges
|
|
|
|
@param source The source vertex
|
|
@return A boost transformed range of Edge type for all out edges of
|
|
source.
|
|
*/
|
|
auto
|
|
outEdges(Vertex source) const
|
|
{
|
|
auto transform = [source](typename Links::value_type const& link) {
|
|
return Edge{source, link.first, link.second};
|
|
};
|
|
|
|
auto it = graph_.find(source);
|
|
if (it != graph_.end())
|
|
return boost::adaptors::transform(it->second, transform);
|
|
|
|
return boost::adaptors::transform(empty, transform);
|
|
}
|
|
|
|
/** Vertex out-degree
|
|
|
|
@param source The source vertex
|
|
@return The number of outgoing edges from source
|
|
*/
|
|
std::size_t
|
|
outDegree(Vertex source) const
|
|
{
|
|
auto it = graph_.find(source);
|
|
if (it != graph_.end())
|
|
return it->second.size();
|
|
return 0;
|
|
}
|
|
|
|
/** Save GraphViz dot file
|
|
|
|
Save a GraphViz dot description of the graph
|
|
@param fileName The output file (creates)
|
|
@param vertexName A invokable T vertexName(Vertex const &) that
|
|
returns the name target use for the vertex in the file
|
|
T must be be ostream-able
|
|
*/
|
|
template <class VertexName>
|
|
void
|
|
saveDot(std::ostream& out, VertexName&& vertexName) const
|
|
{
|
|
out << "digraph {\n";
|
|
for (auto const& [vertex, links] : graph_)
|
|
{
|
|
auto const fromName = vertexName(vertex);
|
|
for (auto const& eData : links)
|
|
{
|
|
auto const toName = vertexName(eData.first);
|
|
out << fromName << " -> " << toName << ";\n";
|
|
}
|
|
}
|
|
out << "}\n";
|
|
}
|
|
|
|
template <class VertexName>
|
|
void
|
|
saveDot(std::string const& fileName, VertexName&& vertexName) const
|
|
{
|
|
std::ofstream out(fileName);
|
|
saveDot(out, std::forward<VertexName>(vertexName));
|
|
}
|
|
};
|
|
|
|
} // namespace csf
|
|
} // namespace test
|
|
} // namespace ripple
|
|
#endif
|