#ifndef LLVM_XRAY_GRAPH_H
#define LLVM_XRAY_GRAPH_H
#include <initializer_list>
#include <stdint.h>
#include <type_traits>
#include <utility>
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/iterator.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace xray {
template <typename VertexAttribute, typename EdgeAttribute,
typename VI = int32_t>
class Graph {
public:
typedef VI VertexIdentifier;
typedef std::pair<VI, VI> EdgeIdentifier;
using VertexValueType =
detail::DenseMapPair<VertexIdentifier, VertexAttribute>;
using EdgeValueType = detail::DenseMapPair<EdgeIdentifier, EdgeAttribute>;
using size_type = std::size_t;
private:
using EdgeMapT = DenseMap<EdgeIdentifier, EdgeAttribute>;
using VertexMapT = DenseMap<VertexIdentifier, VertexAttribute>;
using NeighborSetT = DenseSet<VertexIdentifier>;
using NeighborLookupT = DenseMap<VertexIdentifier, NeighborSetT>;
private:
EdgeMapT Edges;
VertexMapT Vertices;
NeighborLookupT InNeighbors;
NeighborLookupT OutNeighbors;
template <bool IsConst, bool IsOut,
typename BaseIt = typename NeighborSetT::const_iterator,
typename T =
std::conditional_t<IsConst, const EdgeValueType, EdgeValueType>>
class NeighborEdgeIteratorT
: public iterator_adaptor_base<
NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
typename std::iterator_traits<BaseIt>::iterator_category, T> {
using InternalEdgeMapT =
std::conditional_t<IsConst, const EdgeMapT, EdgeMapT>;
friend class NeighborEdgeIteratorT<false, IsOut, BaseIt, EdgeValueType>;
friend class NeighborEdgeIteratorT<true, IsOut, BaseIt,
const EdgeValueType>;
InternalEdgeMapT *MP;
VertexIdentifier SI;
public:
template <bool IsConstDest,
typename = std::enable_if<IsConstDest && !IsConst>>
operator NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
const EdgeValueType>() const {
return NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
const EdgeValueType>(this->I, MP, SI);
}
NeighborEdgeIteratorT() = default;
NeighborEdgeIteratorT(BaseIt _I, InternalEdgeMapT *_MP,
VertexIdentifier _SI)
: iterator_adaptor_base<
NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
typename std::iterator_traits<BaseIt>::iterator_category, T>(_I),
MP(_MP), SI(_SI) {}
T &operator*() const {
if (!IsOut)
return *(MP->find({*(this->I), SI}));
else
return *(MP->find({SI, *(this->I)}));
}
};
public:
using ConstInEdgeIterator = NeighborEdgeIteratorT<true, false>;
using InEdgeIterator = NeighborEdgeIteratorT<false, false>;
using ConstOutEdgeIterator = NeighborEdgeIteratorT<true, true>;
using OutEdgeIterator = NeighborEdgeIteratorT<false, true>;
template <bool isConst, bool isOut> class InOutEdgeView {
public:
using iterator = NeighborEdgeIteratorT<isConst, isOut>;
using const_iterator = NeighborEdgeIteratorT<true, isOut>;
using GraphT = std::conditional_t<isConst, const Graph, Graph>;
using InternalEdgeMapT =
std::conditional_t<isConst, const EdgeMapT, EdgeMapT>;
private:
InternalEdgeMapT &M;
const VertexIdentifier A;
const NeighborLookupT &NL;
public:
iterator begin() {
auto It = NL.find(A);
if (It == NL.end())
return iterator();
return iterator(It->second.begin(), &M, A);
}
const_iterator cbegin() const {
auto It = NL.find(A);
if (It == NL.end())
return const_iterator();
return const_iterator(It->second.begin(), &M, A);
}
const_iterator begin() const { return cbegin(); }
iterator end() {
auto It = NL.find(A);
if (It == NL.end())
return iterator();
return iterator(It->second.end(), &M, A);
}
const_iterator cend() const {
auto It = NL.find(A);
if (It == NL.end())
return const_iterator();
return const_iterator(It->second.end(), &M, A);
}
const_iterator end() const { return cend(); }
size_type size() const {
auto I = NL.find(A);
if (I == NL.end())
return 0;
else
return I->second.size();
}
bool empty() const { return NL.count(A) == 0; };
InOutEdgeView(GraphT &G, VertexIdentifier A)
: M(G.Edges), A(A), NL(isOut ? G.OutNeighbors : G.InNeighbors) {}
};
using ConstVertexIterator = typename VertexMapT::const_iterator;
using VertexIterator = typename VertexMapT::iterator;
template <bool isConst> class VertexView {
public:
using iterator =
std::conditional_t<isConst, ConstVertexIterator, VertexIterator>;
using const_iterator = ConstVertexIterator;
using GraphT = std::conditional_t<isConst, const Graph, Graph>;
private:
GraphT &G;
public:
iterator begin() { return G.Vertices.begin(); }
iterator end() { return G.Vertices.end(); }
const_iterator cbegin() const { return G.Vertices.cbegin(); }
const_iterator cend() const { return G.Vertices.cend(); }
const_iterator begin() const { return G.Vertices.begin(); }
const_iterator end() const { return G.Vertices.end(); }
size_type size() const { return G.Vertices.size(); }
bool empty() const { return G.Vertices.empty(); }
VertexView(GraphT &_G) : G(_G) {}
};
using ConstEdgeIterator = typename EdgeMapT::const_iterator;
using EdgeIterator = typename EdgeMapT::iterator;
template <bool isConst> class EdgeView {
public:
using iterator =
std::conditional_t<isConst, ConstEdgeIterator, EdgeIterator>;
using const_iterator = ConstEdgeIterator;
using GraphT = std::conditional_t<isConst, const Graph, Graph>;
private:
GraphT &G;
public:
iterator begin() { return G.Edges.begin(); }
iterator end() { return G.Edges.end(); }
const_iterator cbegin() const { return G.Edges.cbegin(); }
const_iterator cend() const { return G.Edges.cend(); }
const_iterator begin() const { return G.Edges.begin(); }
const_iterator end() const { return G.Edges.end(); }
size_type size() const { return G.Edges.size(); }
bool empty() const { return G.Edges.empty(); }
EdgeView(GraphT &_G) : G(_G) {}
};
public:
void clear() {
Edges.clear();
Vertices.clear();
InNeighbors.clear();
OutNeighbors.clear();
}
VertexView<false> vertices() { return VertexView<false>(*this); }
VertexView<true> vertices() const { return VertexView<true>(*this); }
EdgeView<false> edges() { return EdgeView<false>(*this); }
EdgeView<true> edges() const { return EdgeView<true>(*this); }
InOutEdgeView<false, true> outEdges(const VertexIdentifier I) {
return InOutEdgeView<false, true>(*this, I);
}
InOutEdgeView<true, true> outEdges(const VertexIdentifier I) const {
return InOutEdgeView<true, true>(*this, I);
}
InOutEdgeView<false, false> inEdges(const VertexIdentifier I) {
return InOutEdgeView<false, false>(*this, I);
}
InOutEdgeView<true, false> inEdges(const VertexIdentifier I) const {
return InOutEdgeView<true, false>(*this, I);
}
VertexAttribute &operator[](const VertexIdentifier &I) {
return Vertices.FindAndConstruct(I).second;
}
EdgeAttribute &operator[](const EdgeIdentifier &I) {
auto &P = Edges.FindAndConstruct(I);
Vertices.FindAndConstruct(I.first);
Vertices.FindAndConstruct(I.second);
InNeighbors[I.second].insert(I.first);
OutNeighbors[I.first].insert(I.second);
return P.second;
}
Expected<VertexAttribute &> at(const VertexIdentifier &I) {
auto It = Vertices.find(I);
if (It == Vertices.end())
return make_error<StringError>(
"Vertex Identifier Does Not Exist",
std::make_error_code(std::errc::invalid_argument));
return It->second;
}
Expected<const VertexAttribute &> at(const VertexIdentifier &I) const {
auto It = Vertices.find(I);
if (It == Vertices.end())
return make_error<StringError>(
"Vertex Identifier Does Not Exist",
std::make_error_code(std::errc::invalid_argument));
return It->second;
}
Expected<EdgeAttribute &> at(const EdgeIdentifier &I) {
auto It = Edges.find(I);
if (It == Edges.end())
return make_error<StringError>(
"Edge Identifier Does Not Exist",
std::make_error_code(std::errc::invalid_argument));
return It->second;
}
Expected<const EdgeAttribute &> at(const EdgeIdentifier &I) const {
auto It = Edges.find(I);
if (It == Edges.end())
return make_error<StringError>(
"Edge Identifier Does Not Exist",
std::make_error_code(std::errc::invalid_argument));
return It->second;
}
size_type count(const VertexIdentifier &I) const {
return Vertices.count(I);
}
size_type count(const EdgeIdentifier &I) const { return Edges.count(I); }
std::pair<VertexIterator, bool>
insert(const std::pair<VertexIdentifier, VertexAttribute> &Val) {
return Vertices.insert(Val);
}
std::pair<VertexIterator, bool>
insert(std::pair<VertexIdentifier, VertexAttribute> &&Val) {
return Vertices.insert(std::move(Val));
}
std::pair<EdgeIterator, bool>
insert(const std::pair<EdgeIdentifier, EdgeAttribute> &Val) {
const auto &p = Edges.insert(Val);
if (p.second) {
const auto &EI = Val.first;
Vertices.FindAndConstruct(EI.first);
Vertices.FindAndConstruct(EI.second);
InNeighbors[EI.second].insert(EI.first);
OutNeighbors[EI.first].insert(EI.second);
};
return p;
}
std::pair<EdgeIterator, bool>
insert(std::pair<EdgeIdentifier, EdgeAttribute> &&Val) {
auto EI = Val.first;
const auto &p = Edges.insert(std::move(Val));
if (p.second) {
Vertices.FindAndConstruct(EI.first);
Vertices.FindAndConstruct(EI.second);
InNeighbors[EI.second].insert(EI.first);
OutNeighbors[EI.first].insert(EI.second);
};
return p;
}
};
}
}
#endif