graph: export from google3

This commit is contained in:
Corentin Le Molgat
2025-03-10 17:21:31 +01:00
parent 8b097bbfc0
commit 3434515e7d
2 changed files with 222 additions and 345 deletions

View File

@@ -290,6 +290,60 @@ class BaseGraph {
bool const_capacities_;
};
// An iterator that wraps an arc iterator and retrieves a property of the arc.
// The property to retrieve is specified by a `Graph` member function taking an
// `ArcIndex` parameter. For example, `ArcHeadIterator` retrieves the head of an
// arc with `&Graph::Head`.
template <typename Graph, typename ArcIterator, typename PropertyT,
PropertyT (Graph::*property)(typename Graph::ArcIndex) const>
class ArcPropertyIterator
#if __cplusplus < 202002L
: public std::iterator<std::input_iterator_tag, PropertyT>
#endif
{
public:
using value_type = PropertyT;
// TODO(b/385094969): This should be `NodeIndex` for integers,
// `NodeIndex::value_type` for strong signed integer types.
using difference_type = std::ptrdiff_t;
ArcPropertyIterator() = default;
ArcPropertyIterator(const Graph& graph, ArcIterator arc_it)
: arc_it_(std::move(arc_it)), graph_(&graph) {}
value_type operator*() const { return (graph_->*property)(*arc_it_); }
ArcPropertyIterator& operator++() {
++arc_it_;
return *this;
}
ArcPropertyIterator operator++(int) {
auto tmp = *this;
++arc_it_;
return tmp;
}
friend bool operator==(const ArcPropertyIterator& l,
const ArcPropertyIterator& r) {
return l.arc_it_ == r.arc_it_;
}
friend bool operator!=(const ArcPropertyIterator& l,
const ArcPropertyIterator& r) {
return !(l == r);
}
private:
ArcIterator arc_it_;
const Graph* graph_;
};
// An iterator that iterates on the heads of the arcs of another iterator.
template <typename Graph, typename ArcIterator>
using ArcHeadIterator =
ArcPropertyIterator<Graph, ArcIterator, typename Graph::NodeIndex,
&Graph::Head>;
// Basic graph implementation without reverse arc. This class also serves as a
// documentation for the generic graph interface (minus the part related to
// reverse arcs).
@@ -352,9 +406,15 @@ class ListGraph : public BaseGraph<NodeIndexType, ArcIndexType, false> {
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
// Returns the tail/head of a valid arc.
NodeIndexType Tail(ArcIndexType arc) const;
NodeIndexType Head(ArcIndexType arc) const;
// Do not use directly.
class OutgoingArcIterator;
class OutgoingHeadIterator;
struct OutgoingArcIteratorTag {};
using OutgoingArcIterator =
ChasingIterator<ArcIndexType, Base::kNilArc, OutgoingArcIteratorTag>;
using OutgoingHeadIterator = ArcHeadIterator<ListGraph, OutgoingArcIterator>;
// Graph jargon: the "degree" of a node is its number of arcs. The out-degree
// is the number of outgoing arcs. The in-degree is the number of incoming
@@ -366,22 +426,30 @@ class ListGraph : public BaseGraph<NodeIndexType, ArcIndexType, false> {
// Allows to iterate over the forward arcs that verify Tail(arc) == node.
// This is meant to be used as:
// for (const ArcIndex arc : graph.OutgoingArcs(node)) { ... }
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const {
DCHECK(Base::IsNodeValid(node));
return {OutgoingArcIterator(start_[node], next_.data()),
OutgoingArcIterator()};
}
// Advanced usage. Same as OutgoingArcs(), but allows to restart the iteration
// from an already known outgoing arc of the given node. If `from` is
// `kNilArc`, an empty range is returned.
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
NodeIndexType node, ArcIndexType from) const {
DCHECK(Base::IsNodeValid(node));
if (from == Base::kNilArc) return {};
DCHECK_EQ(Tail(from), node);
return {OutgoingArcIterator(from, next_.data()), OutgoingArcIterator()};
}
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
BeginEndWrapper<OutgoingHeadIterator> operator[](NodeIndexType node) const;
// Returns the tail/head of a valid arc.
NodeIndexType Tail(ArcIndexType arc) const;
NodeIndexType Head(ArcIndexType arc) const;
BeginEndWrapper<OutgoingHeadIterator> operator[](NodeIndexType node) const {
return {OutgoingHeadIterator(*this, OutgoingArcs(node).begin()),
OutgoingHeadIterator()};
}
void ReserveNodes(NodeIndexType bound) override;
void ReserveArcs(ArcIndexType bound) override;
@@ -508,16 +576,27 @@ class ReverseArcListGraph
}
}
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
// Returns the opposite arc of a given arc. That is the reverse arc of the
// given forward arc or the forward arc of a given reverse arc.
ArcIndexType OppositeArc(ArcIndexType arc) const;
// Do not use directly. See instead the arc iteration functions below.
struct OutgoingArcIteratorTag {};
using OutgoingArcIterator =
ChasingIterator<ArcIndexType, Base::kNilArc, OutgoingArcIteratorTag>;
struct OppositeIncomingArcIteratorTag {};
using OppositeIncomingArcIterator =
ChasingIterator<ArcIndexType, Base::kNilArc,
OppositeIncomingArcIteratorTag>;
class OutgoingOrOppositeIncomingArcIterator;
class OppositeIncomingArcIterator;
class IncomingArcIterator;
class OutgoingArcIterator;
class OutgoingHeadIterator;
using OutgoingHeadIterator =
ArcHeadIterator<ReverseArcListGraph, OutgoingArcIterator>;
using IncomingArcIterator =
ArcPropertyIterator<ReverseArcListGraph, OppositeIncomingArcIterator,
ArcIndexType, &ReverseArcListGraph::OppositeArc>;
// ReverseArcListGraph<>::OutDegree() and ::InDegree() work in O(degree).
ArcIndexType OutDegree(NodeIndexType node) const;
@@ -530,30 +609,62 @@ class ReverseArcListGraph
// The StartingFrom() version are similar, but restart the iteration from a
// given arc position (which must be valid in the iteration context), or
// `kNilArc`, in which case an empty range is returned.
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const {
DCHECK(Base::IsNodeValid(node));
return {OutgoingArcIterator(start_[node], next_.data()),
OutgoingArcIterator()};
}
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const {
DCHECK(Base::IsNodeValid(node));
if (from == Base::kNilArc) return {};
DCHECK_GE(from, 0);
DCHECK_EQ(Tail(from), node);
return {OutgoingArcIterator(from, next_.data()), OutgoingArcIterator()};
}
BeginEndWrapper<IncomingArcIterator> IncomingArcs(NodeIndexType node) const {
return {IncomingArcIterator(*this, OppositeIncomingArcs(node).begin()),
IncomingArcIterator()};
}
BeginEndWrapper<IncomingArcIterator> IncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const {
DCHECK(Base::IsNodeValid(node));
if (from == Base::kNilArc) return {};
return {
IncomingArcIterator(
*this,
OppositeIncomingArcsStartingFrom(node, OppositeArc(from)).begin()),
IncomingArcIterator()};
}
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcs(
NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
NodeIndexType node) const {
DCHECK(Base::IsNodeValid(node));
return {OppositeIncomingArcIterator(reverse_start_[node], next_.data()),
OppositeIncomingArcIterator()};
}
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const {
DCHECK(Base::IsNodeValid(node));
if (from == Base::kNilArc) return {};
DCHECK_LT(from, 0);
DCHECK_EQ(Tail(from), node);
return {OppositeIncomingArcIterator(from, next_.data()),
OppositeIncomingArcIterator()};
}
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node,
ArcIndexType from) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
BeginEndWrapper<OutgoingHeadIterator> operator[](NodeIndexType node) const;
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
void ReserveNodes(NodeIndexType bound) override;
void ReserveArcs(ArcIndexType bound) override;
void AddNode(NodeIndexType node);
@@ -604,9 +715,9 @@ class ReverseArcStaticGraph
// Deprecated.
class OutgoingOrOppositeIncomingArcIterator;
class OppositeIncomingArcIterator;
using OppositeIncomingArcIterator = IntegerRangeIterator<ArcIndexType>;
class IncomingArcIterator;
class OutgoingArcIterator;
using OutgoingArcIterator = IntegerRangeIterator<ArcIndexType>;
// ReverseArcStaticGraph<>::OutDegree() and ::InDegree() work in O(1).
ArcIndexType OutDegree(NodeIndexType node) const;
@@ -989,7 +1100,7 @@ void BaseGraph<NodeIndexType, ArcIndexType, HasNegativeReverseArcs>::
(*v)[i] = sum;
sum += temp;
}
DCHECK(sum == num_arcs_);
DCHECK_EQ(sum, num_arcs_);
(*v)[num_nodes_] = sum; // Sentinel.
}
@@ -1109,17 +1220,6 @@ void BaseGraph<NodeIndexType, ArcIndexType, HasNegativeReverseArcs>::
// ListGraph implementation ----------------------------------------------------
DEFINE_RANGE_BASED_ARC_ITERATION(ListGraph, Outgoing);
template <typename NodeIndexType, typename ArcIndexType>
BeginEndWrapper<
typename ListGraph<NodeIndexType, ArcIndexType>::OutgoingHeadIterator>
ListGraph<NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const {
return BeginEndWrapper<OutgoingHeadIterator>(
OutgoingHeadIterator(*this, node),
OutgoingHeadIterator(*this, node, Base::kNilArc));
}
template <typename NodeIndexType, typename ArcIndexType>
NodeIndexType ListGraph<NodeIndexType, ArcIndexType>::Tail(
ArcIndexType arc) const {
@@ -1130,7 +1230,7 @@ NodeIndexType ListGraph<NodeIndexType, ArcIndexType>::Tail(
template <typename NodeIndexType, typename ArcIndexType>
NodeIndexType ListGraph<NodeIndexType, ArcIndexType>::Head(
ArcIndexType arc) const {
DCHECK(IsArcValid(arc));
DCHECK(IsArcValid(arc)) << arc;
return head_[arc];
}
@@ -1188,80 +1288,6 @@ void ListGraph<NodeIndexType, ArcIndexType>::Build(
}
}
template <typename NodeIndexType, typename ArcIndexType>
class ListGraph<NodeIndexType, ArcIndexType>::OutgoingArcIterator {
public:
OutgoingArcIterator(const ListGraph& graph, NodeIndexType node)
: graph_(&graph), index_(graph.start_[node]) {
DCHECK(graph.IsNodeValid(node));
}
OutgoingArcIterator(const ListGraph& graph, NodeIndexType node,
ArcIndexType arc)
: graph_(&graph), index_(arc) {
DCHECK(graph.IsNodeValid(node));
DCHECK(arc == Base::kNilArc || graph.Tail(arc) == node);
}
bool Ok() const { return index_ != Base::kNilArc; }
ArcIndexType Index() const { return index_; }
void Next() {
DCHECK(Ok());
index_ = graph_->next_[index_];
}
DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator);
private:
const ListGraph* graph_;
ArcIndexType index_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ListGraph<NodeIndexType, ArcIndexType>::OutgoingHeadIterator {
public:
using iterator_category = std::input_iterator_tag;
using difference_type = ptrdiff_t;
using pointer = const NodeIndexType*;
using reference = const NodeIndexType&;
using value_type = NodeIndexType;
OutgoingHeadIterator(const ListGraph& graph, NodeIndexType node)
: graph_(&graph), index_(graph.start_[node]) {
DCHECK(graph.IsNodeValid(node));
}
OutgoingHeadIterator(const ListGraph& graph, NodeIndexType node,
ArcIndexType arc)
: graph_(&graph), index_(arc) {
DCHECK(graph.IsNodeValid(node));
DCHECK(arc == Base::kNilArc || graph.Tail(arc) == node);
}
bool Ok() const { return index_ != Base::kNilArc; }
NodeIndexType Index() const { return graph_->Head(index_); }
void Next() {
DCHECK(Ok());
index_ = graph_->next_[index_];
}
bool operator!=(
const typename ListGraph<
NodeIndexType, ArcIndexType>::OutgoingHeadIterator& other) const {
return index_ != other.index_;
}
NodeIndexType operator*() const { return Index(); }
OutgoingHeadIterator& operator++() {
Next();
return *this;
}
OutgoingHeadIterator operator++(int) {
auto tmp = *this;
Next();
return *this;
}
private:
const ListGraph* graph_;
ArcIndexType index_;
};
// StaticGraph implementation --------------------------------------------------
template <typename NodeIndexType, typename ArcIndexType>
@@ -1422,49 +1448,21 @@ void StaticGraph<NodeIndexType, ArcIndexType>::Build(
}
}
// TODO(b/385094969): Remove this class.
template <typename NodeIndexType, typename ArcIndexType>
class StaticGraph<NodeIndexType, ArcIndexType>::OutgoingArcIterator {
public:
OutgoingArcIterator(const OutgoingArcIterator&) = default;
OutgoingArcIterator& operator=(const OutgoingArcIterator&) = default;
OutgoingArcIterator(const StaticGraph& graph, NodeIndexType node)
: index_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) {}
OutgoingArcIterator(const StaticGraph& graph, NodeIndexType node,
ArcIndexType arc)
: limit_(graph.DirectArcLimit(node)) {
index_ = arc == Base::kNilArc ? limit_ : arc;
DCHECK_GE(arc, graph.start_[node]);
}
bool Ok() const { return index_ != limit_; }
ArcIndexType Index() const { return index_; }
void Next() {
DCHECK(Ok());
index_++;
}
private:
ArcIndexType index_;
ArcIndexType limit_;
};
// ReverseArcListGraph implementation ------------------------------------------
DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcListGraph, Outgoing);
DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcListGraph, Incoming);
DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcListGraph,
OutgoingOrOppositeIncoming);
DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcListGraph, OppositeIncoming);
template <typename NodeIndexType, typename ArcIndexType>
BeginEndWrapper<typename ReverseArcListGraph<
NodeIndexType, ArcIndexType>::OutgoingHeadIterator>
ReverseArcListGraph<NodeIndexType, ArcIndexType>::operator[](
NodeIndexType node) const {
const auto outgoing_arcs = OutgoingArcs(node);
// Note: `BeginEndWrapper` is a borrowed range (`std::ranges::borrowed_range`)
// so copying begin/end is safe.
return BeginEndWrapper<OutgoingHeadIterator>(
OutgoingHeadIterator(*this, node),
OutgoingHeadIterator(*this, node, Base::kNilArc));
OutgoingHeadIterator(*this, outgoing_arcs.begin()),
OutgoingHeadIterator(*this, outgoing_arcs.end()));
}
template <typename NodeIndexType, typename ArcIndexType>
@@ -1553,90 +1551,6 @@ void ReverseArcListGraph<NodeIndexType, ArcIndexType>::Build(
}
}
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcListGraph<NodeIndexType, ArcIndexType>::OutgoingArcIterator {
public:
OutgoingArcIterator(const ReverseArcListGraph& graph, NodeIndexType node)
: graph_(&graph), index_(graph.start_[node]) {
DCHECK(graph.IsNodeValid(node));
}
OutgoingArcIterator(const ReverseArcListGraph& graph, NodeIndexType node,
ArcIndexType arc)
: graph_(&graph), index_(arc) {
DCHECK(graph.IsNodeValid(node));
DCHECK(arc == Base::kNilArc || arc >= 0);
DCHECK(arc == Base::kNilArc || graph.Tail(arc) == node);
}
bool Ok() const { return index_ != Base::kNilArc; }
ArcIndexType Index() const { return index_; }
void Next() {
DCHECK(Ok());
index_ = graph_->next_[index_];
}
DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingArcIterator);
private:
const ReverseArcListGraph* graph_;
ArcIndexType index_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcListGraph<NodeIndexType,
ArcIndexType>::OppositeIncomingArcIterator {
public:
OppositeIncomingArcIterator(const ReverseArcListGraph& graph,
NodeIndexType node)
: next_(graph.next_.data()), index_(graph.reverse_start_[node]) {
DCHECK(graph.IsNodeValid(node));
}
OppositeIncomingArcIterator(const ReverseArcListGraph& graph,
NodeIndexType node, ArcIndexType arc)
: next_(graph.next_.data()), index_(arc) {
DCHECK(graph.IsNodeValid(node));
DCHECK(arc == Base::kNilArc || arc < 0);
DCHECK(arc == Base::kNilArc || graph.Tail(arc) == node);
}
bool Ok() const { return index_ != Base::kNilArc; }
ArcIndexType Index() const { return index_; }
void Next() {
DCHECK(Ok());
index_ = next_[index_];
}
DEFINE_STL_ITERATOR_FUNCTIONS(OppositeIncomingArcIterator);
protected:
const ArcIndexType* next_;
ArcIndexType index_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcListGraph<NodeIndexType, ArcIndexType>::IncomingArcIterator
: public OppositeIncomingArcIterator {
public:
IncomingArcIterator(const ReverseArcListGraph& graph, NodeIndexType node)
: OppositeIncomingArcIterator(graph, node), graph_(&graph) {}
IncomingArcIterator(const ReverseArcListGraph& graph, NodeIndexType node,
ArcIndexType arc)
: OppositeIncomingArcIterator(
graph, node,
arc == Base::kNilArc ? Base::kNilArc : graph.OppositeArc(arc)),
graph_(&graph) {}
// We overwrite OppositeIncomingArcIterator::Index() here.
ArcIndexType Index() const {
return this->index_ == Base::kNilArc ? Base::kNilArc
: graph_->OppositeArc(this->index_);
}
DEFINE_STL_ITERATOR_FUNCTIONS(IncomingArcIterator);
private:
const ReverseArcListGraph* graph_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcListGraph<NodeIndexType,
ArcIndexType>::OutgoingOrOppositeIncomingArcIterator {
@@ -1676,34 +1590,6 @@ class ReverseArcListGraph<NodeIndexType,
NodeIndexType node_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcListGraph<NodeIndexType, ArcIndexType>::OutgoingHeadIterator {
public:
OutgoingHeadIterator(const ReverseArcListGraph& graph, NodeIndexType node)
: graph_(&graph), index_(graph.start_[node]) {
DCHECK(graph.IsNodeValid(node));
}
OutgoingHeadIterator(const ReverseArcListGraph& graph, NodeIndexType node,
ArcIndexType arc)
: graph_(&graph), index_(arc) {
DCHECK(graph.IsNodeValid(node));
DCHECK(arc == Base::kNilArc || arc >= 0);
DCHECK(arc == Base::kNilArc || graph.Tail(arc) == node);
}
bool Ok() const { return index_ != Base::kNilArc; }
ArcIndexType Index() const { return graph_->Head(index_); }
void Next() {
DCHECK(Ok());
index_ = graph_->next_[index_];
}
DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingHeadIterator);
private:
const ReverseArcListGraph* graph_;
ArcIndexType index_;
};
// ReverseArcStaticGraph implementation ----------------------------------------
DEFINE_RANGE_BASED_ARC_ITERATION(ReverseArcStaticGraph, Incoming);
@@ -1833,90 +1719,45 @@ void ReverseArcStaticGraph<NodeIndexType, ArcIndexType>::Build(
}
}
// TODO(b/385094969): Remove this class.
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcStaticGraph<NodeIndexType, ArcIndexType>::OutgoingArcIterator {
class ReverseArcStaticGraph<NodeIndexType, ArcIndexType>::IncomingArcIterator
: public OppositeIncomingArcIterator {
public:
OutgoingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node)
: index_(graph.start_[node]), limit_(graph.DirectArcLimit(node)) {}
OutgoingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node,
ArcIndexType arc)
: limit_(graph.DirectArcLimit(node)) {
index_ = arc == Base::kNilArc ? limit_ : arc;
DCHECK_GE(arc, graph.start_[node]);
}
bool Ok() const { return index_ != limit_; }
ArcIndexType Index() const { return index_; }
void Next() {
DCHECK(Ok());
index_++;
}
private:
ArcIndexType index_;
const ArcIndexType limit_;
};
// TODO(b/385094969): Remove this class.
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcStaticGraph<NodeIndexType,
ArcIndexType>::OppositeIncomingArcIterator {
public:
OppositeIncomingArcIterator(const ReverseArcStaticGraph& graph,
NodeIndexType node)
IncomingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node)
: limit_(graph.ReverseArcLimit(node)),
index_(graph.reverse_start_[node]) {
index_(graph.reverse_start_[node]),
graph_(graph) {
DCHECK(graph.IsNodeValid(node));
DCHECK_LE(index_, limit_);
}
OppositeIncomingArcIterator(const ReverseArcStaticGraph& graph,
NodeIndexType node, ArcIndexType arc)
: limit_(graph.ReverseArcLimit(node)) {
index_ = arc == Base::kNilArc ? limit_ : arc;
IncomingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node,
ArcIndexType arc)
: limit_(graph.ReverseArcLimit(node)), graph_(graph) {
index_ = arc == Base::kNilArc ? limit_
: (arc == graph.ReverseArcLimit(node)
? graph.ReverseArcLimit(node)
: graph.OppositeArc(arc));
DCHECK(graph.IsNodeValid(node));
DCHECK_GE(index_, graph.reverse_start_[node]);
DCHECK_LE(index_, limit_);
}
bool Ok() const { return index_ != limit_; }
ArcIndexType Index() const { return index_; }
ArcIndexType Index() const {
return this->index_ == this->limit_ ? this->limit_
: graph_.OppositeArc(this->index_);
}
void Next() {
DCHECK(Ok());
index_++;
}
DEFINE_STL_ITERATOR_FUNCTIONS(OppositeIncomingArcIterator);
protected:
const ArcIndexType limit_;
ArcIndexType index_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ReverseArcStaticGraph<NodeIndexType, ArcIndexType>::IncomingArcIterator
: public OppositeIncomingArcIterator {
public:
IncomingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node)
: OppositeIncomingArcIterator(graph, node), graph_(graph) {}
IncomingArcIterator(const ReverseArcStaticGraph& graph, NodeIndexType node,
ArcIndexType arc)
: OppositeIncomingArcIterator(graph, node,
arc == Base::kNilArc
? Base::kNilArc
: (arc == graph.ReverseArcLimit(node)
? graph.ReverseArcLimit(node)
: graph.OppositeArc(arc))),
graph_(graph) {}
ArcIndexType Index() const {
return this->index_ == this->limit_ ? this->limit_
: graph_.OppositeArc(this->index_);
}
DEFINE_STL_ITERATOR_FUNCTIONS(IncomingArcIterator);
private:
const ArcIndexType limit_;
ArcIndexType index_;
const ReverseArcStaticGraph& graph_;
};
@@ -2091,25 +1932,6 @@ class CompleteBipartiteGraph
ArcIndexType from) const;
IntegerRange<NodeIndexType> operator[](NodeIndexType node) const;
// Deprecated interface.
class OutgoingArcIterator {
public:
OutgoingArcIterator(const CompleteBipartiteGraph& graph, NodeIndexType node)
: index_(static_cast<ArcIndexType>(graph.right_nodes_) * node),
limit_(node >= graph.left_nodes_
? index_
: static_cast<ArcIndexType>(graph.right_nodes_) *
(node + 1)) {}
bool Ok() const { return index_ < limit_; }
ArcIndexType Index() const { return index_; }
void Next() { index_++; }
private:
ArcIndexType index_;
const ArcIndexType limit_;
};
private:
const NodeIndexType left_nodes_;
const NodeIndexType right_nodes_;

View File

@@ -18,7 +18,7 @@
#include <cstddef>
#include <iterator>
#include <vector>
#include <utility>
#include "absl/log/check.h"
@@ -37,13 +37,24 @@ namespace util {
// And a client will use it like this:
//
// for (const ArcIndex arc : graph.OutgoingArcs(node)) { ... }
//
// Note that `BeginEndWrapper` is conceptually a borrowed range as per the C++
// standard (`std::ranges::borrowed_range`):
// "The concept borrowed_range defines the requirements of a range such that a
// function can take it by value and return iterators obtained from it without
// danger of dangling". We cannot `static_assert` this property though as
// `std::ranges` is prohibited in google3.
template <typename Iterator>
class BeginEndWrapper {
public:
using const_iterator = Iterator;
using value_type = typename std::iterator_traits<Iterator>::value_type;
// If `Iterator` is default-constructible, an empty range.
BeginEndWrapper() = default;
BeginEndWrapper(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
Iterator begin() const { return begin_; }
Iterator end() const { return end_; }
size_t size() const { return end_ - begin_; }
@@ -51,8 +62,8 @@ class BeginEndWrapper {
bool empty() const { return begin() == end(); }
private:
const Iterator begin_;
const Iterator end_;
Iterator begin_;
Iterator end_;
};
// Inline wrapper methods, to make the client code even simpler.
@@ -227,6 +238,50 @@ class IntegerRange : public BeginEndWrapper<IntegerRangeIterator<IntegerType>> {
}
};
// A helper class for implementing list graph iterators: This does pointer
// chasing on `next` until `sentinel` is found. `Tag` allows distinguishing
// different iterators with the same index type and sentinel.
template <typename IndexT, IndexT sentinel, typename Tag>
class ChasingIterator
#if __cplusplus < 202002L
: public std::iterator<std::input_iterator_tag, IndexT>
#endif
{
public:
// TODO(b/385094969): This should be `IntegerType` for integers,
// `IntegerType:value_type` for strong signed integer types.
using difference_type = std::ptrdiff_t;
using value_type = IndexT;
ChasingIterator() : index_(sentinel), next_(nullptr) {}
ChasingIterator(IndexT index, const IndexT* next)
: index_(index), next_(next) {}
IndexT operator*() const { return index_; }
ChasingIterator& operator++() {
index_ = next_[index_];
return *this;
}
ChasingIterator operator++(int) {
auto tmp = *this;
index_ = next_[index_];
return tmp;
}
friend bool operator==(const ChasingIterator& l, const ChasingIterator& r) {
return l.index_ == r.index_;
}
friend bool operator!=(const ChasingIterator& l, const ChasingIterator& r) {
return l.index_ != r.index_;
}
private:
IndexT index_;
const IndexT* next_;
};
} // namespace util
#endif // UTIL_GRAPH_ITERATORS_H_