↰ Return to documentation for file (include/networkit/graph/EdgeIterators.hpp)
/*
* EdgeIterators.hpp
*
* Created on: 16.09.2024
*/
#ifndef NETWORKIT_GRAPH_EDGE_ITERATORS_HPP_
#define NETWORKIT_GRAPH_EDGE_ITERATORS_HPP_
#include <type_traits>
#include <networkit/Globals.hpp>
#include <networkit/graph/EdgeUtils.hpp>
#include <networkit/graph/GraphConcepts.hpp>
#include <networkit/graph/NodeIterators.hpp>
namespace NetworKit {
template <class GraphType, GraphNode NodeT, GraphEdgeWeight EdgeWeightT>
class EdgeIteratorBase {
protected:
const GraphType *G;
NodeIteratorBase<GraphType, NodeT, EdgeWeightT> nodeIter;
index i{none};
public:
EdgeIteratorBase(const GraphType *G, NodeIteratorBase<GraphType, NodeT, EdgeWeightT> nodeIter)
: G(G), nodeIter(nodeIter), i(index{0}) {
if (nodeIter != G->nodeRange().end() && !G->degree(*nodeIter)) {
nextEdge();
}
}
EdgeIteratorBase() : G(nullptr) {}
virtual ~EdgeIteratorBase() = default;
// A valid edge might be defined differently for different graph types
bool validEdge() const noexcept {
return G->isDirected() || (*nodeIter <= G->getIthNeighbor(Unsafe{}, *nodeIter, i));
}
void nextEdge() {
do {
if (++i >= G->degree(*nodeIter)) {
i = 0;
do {
assert(nodeIter != G->nodeRange().end());
++nodeIter;
if (nodeIter == G->nodeRange().end()) {
return;
}
} while (!G->degree(*nodeIter));
}
} while (!validEdge());
}
void prevEdge() {
do {
if (!i) {
do {
assert(nodeIter != G->nodeRange().begin());
--nodeIter;
} while (!G->degree(*nodeIter));
i = G->degree(*nodeIter);
}
--i;
} while (!validEdge());
}
bool operator==(const EdgeIteratorBase &rhs) const noexcept {
return nodeIter == rhs.nodeIter && i == rhs.i;
}
bool operator!=(const EdgeIteratorBase &rhs) const noexcept { return !(*this == rhs); }
};
template <class T>
struct is_weighted_edge_specialization : std::false_type {};
template <GraphNode NodeT, GraphEdgeWeight EdgeWeightT>
struct is_weighted_edge_specialization<WeightedEdgeT<NodeT, EdgeWeightT>> : std::true_type {};
template <class GraphType, GraphNode NodeT, GraphEdgeWeight EdgeWeightT, class IterEdgeWeightT>
class EdgeWeightTIterator : public EdgeIteratorBase<GraphType, NodeT, EdgeWeightT> {
using EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::nodeIter;
using EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::G;
using EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::i;
EdgeT<NodeT> starOperator(std::false_type) const {
return EdgeT<NodeT>(*nodeIter, G->getIthNeighbor(Unsafe{}, *nodeIter, i));
}
WeightedEdgeT<NodeT, EdgeWeightT> starOperator(std::true_type) const {
return WeightedEdgeT<NodeT, EdgeWeightT>(*nodeIter,
G->getIthNeighbor(Unsafe{}, *nodeIter, i),
G->getIthNeighborWeight(Unsafe{}, *nodeIter, i));
}
public:
// The value type of the edges (i.e. a pair). Returned by operator*().
using value_type = IterEdgeWeightT;
// Reference to the value_type, required by STL.
using reference = value_type &;
// Pointer to the value_type, required by STL.
using pointer = value_type *;
// STL iterator category.
using iterator_category = std::forward_iterator_tag;
// Signed integer type of the result of subtracting two pointers,
// required by STL.
using difference_type = ptrdiff_t;
// Own type.
using self = EdgeWeightTIterator;
EdgeWeightTIterator(const GraphType *G,
NodeIteratorBase<GraphType, NodeT, EdgeWeightT> nodeIter)
: EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>(G, nodeIter) {}
EdgeWeightTIterator() : EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>() {}
bool operator==(const EdgeWeightTIterator &rhs) const noexcept {
return this->EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::operator==(
static_cast<EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>>(rhs));
}
bool operator!=(const EdgeWeightTIterator &rhs) const noexcept { return !(*this == rhs); }
// The returned edge depends on both the type of edge and graph
IterEdgeWeightT operator*() const noexcept {
return this->starOperator(is_weighted_edge_specialization<IterEdgeWeightT>{});
}
EdgeWeightTIterator &operator++() {
EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::nextEdge();
return *this;
}
EdgeWeightTIterator operator++(int) {
const auto tmp = *this;
++(*this);
return tmp;
}
EdgeWeightTIterator operator--() {
EdgeIteratorBase<GraphType, NodeT, EdgeWeightT>::prevEdge();
return *this;
}
EdgeWeightTIterator operator--(int) {
const auto tmp = *this;
--(*this);
return tmp;
}
};
template <class GraphType, GraphNode NodeT, GraphEdgeWeight EdgeWeightT, class IterEdgeWeightT>
class EdgeWeightTRange {
const GraphType *G;
public:
EdgeWeightTRange(const GraphType &G) : G(&G) {}
EdgeWeightTRange() : G(nullptr) {};
~EdgeWeightTRange() = default;
EdgeWeightTIterator<GraphType, NodeT, EdgeWeightT, IterEdgeWeightT> begin() const {
assert(G);
return EdgeWeightTIterator<GraphType, NodeT, EdgeWeightT, IterEdgeWeightT>(
G, G->nodeRange().begin());
}
EdgeWeightTIterator<GraphType, NodeT, EdgeWeightT, IterEdgeWeightT> end() const {
assert(G);
return EdgeWeightTIterator<GraphType, NodeT, EdgeWeightT, IterEdgeWeightT>(
G, G->nodeRange().end());
}
};
} // namespace NetworKit
#endif // NETWORKIT_GRAPH_EDGE_ITERATORS_HPP_