2013-05-19 14:11:20 +00:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
|
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file linkgraph.h Declaration of link graph classes used for cargo distribution. */
|
|
|
|
|
|
|
|
#ifndef LINKGRAPH_H
|
|
|
|
#define LINKGRAPH_H
|
|
|
|
|
|
|
|
#include "../core/pool_type.hpp"
|
2016-10-31 00:21:01 +00:00
|
|
|
#include "../core/bitmath_func.hpp"
|
2013-05-19 14:11:20 +00:00
|
|
|
#include "../station_base.h"
|
|
|
|
#include "../cargotype.h"
|
|
|
|
#include "../date_func.h"
|
2023-06-07 22:29:52 +00:00
|
|
|
#include "../sl/saveload_common.h"
|
2013-05-19 14:11:20 +00:00
|
|
|
#include "linkgraph_type.h"
|
2022-12-05 18:17:25 +00:00
|
|
|
#include "../3rdparty/cpp-btree/btree_map.h"
|
2020-05-17 21:31:44 +00:00
|
|
|
#include <utility>
|
2023-07-03 22:34:52 +00:00
|
|
|
#include <vector>
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
class LinkGraph;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Type of the pool for link graph components. Each station can be in at up to
|
|
|
|
* 32 link graphs. So we allow for plenty of them to be created.
|
|
|
|
*/
|
2014-02-10 20:13:07 +00:00
|
|
|
typedef Pool<LinkGraph, LinkGraphID, 32, 0xFFFF> LinkGraphPool;
|
2013-05-19 14:11:20 +00:00
|
|
|
/** The actual pool with link graphs. */
|
|
|
|
extern LinkGraphPool _link_graph_pool;
|
|
|
|
|
2021-11-01 18:33:39 +00:00
|
|
|
namespace upstream_sl {
|
|
|
|
SaveLoadTable GetLinkGraphDesc();
|
|
|
|
SaveLoadTable GetLinkGraphJobDesc();
|
|
|
|
class SlLinkgraphNode;
|
|
|
|
class SlLinkgraphEdge;
|
|
|
|
}
|
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
/**
|
|
|
|
* A connected component of a link graph. Contains a complete set of stations
|
|
|
|
* connected by links as nodes and edges. Each component also holds a copy of
|
|
|
|
* the link graph settings at the time of its creation. The global settings
|
|
|
|
* might change between the creation and join time so we can't rely on them.
|
|
|
|
*/
|
|
|
|
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Node of the link graph. contains all relevant information from the associated
|
|
|
|
* station. It's copied so that the link graph job can work on its own data set
|
|
|
|
* in a separate thread.
|
|
|
|
*/
|
|
|
|
struct BaseNode {
|
|
|
|
uint supply; ///< Supply at the station.
|
|
|
|
uint demand; ///< Acceptance at the station.
|
|
|
|
StationID station; ///< Station ID.
|
2014-06-14 13:35:39 +00:00
|
|
|
TileIndex xy; ///< Location of the station referred to by the node.
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date last_update; ///< When the supply was last updated.
|
2014-06-14 13:35:39 +00:00
|
|
|
void Init(TileIndex xy = INVALID_TILE, StationID st = INVALID_STATION, uint demand = 0);
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An edge in the link graph. Corresponds to a link between two stations or at
|
|
|
|
* least the distance between them. Edges from one node to itself contain the
|
|
|
|
* ID of the opposite Node of the first active edge (i.e. not just distance) in
|
|
|
|
* the column as next_edge.
|
|
|
|
*/
|
|
|
|
struct BaseEdge {
|
2013-10-22 16:13:28 +00:00
|
|
|
uint capacity; ///< Capacity of the link.
|
|
|
|
uint usage; ///< Usage of the link.
|
2024-01-07 16:41:53 +00:00
|
|
|
uint64_t travel_time_sum; ///< Sum of the travel times of the link, in ticks.
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated.
|
|
|
|
EconTime::Date last_restricted_update; ///< When the restricted part of the link was last updated.
|
|
|
|
EconTime::Date last_aircraft_update; ///< When aircraft capacity of the link was last updated.
|
2022-12-05 18:17:25 +00:00
|
|
|
|
|
|
|
void Init()
|
|
|
|
{
|
|
|
|
this->capacity = 0;
|
|
|
|
this->usage = 0;
|
|
|
|
this->travel_time_sum = 0;
|
2024-02-13 21:34:09 +00:00
|
|
|
this->last_unrestricted_update = EconTime::INVALID_DATE;
|
|
|
|
this->last_restricted_update = EconTime::INVALID_DATE;
|
|
|
|
this->last_aircraft_update = EconTime::INVALID_DATE;
|
2022-12-05 18:17:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BaseEdge() { this->Init(); }
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
2022-12-05 18:17:25 +00:00
|
|
|
typedef std::vector<BaseNode> NodeVector;
|
|
|
|
typedef btree::btree_map<std::pair<NodeID, NodeID>, BaseEdge> EdgeMatrix;
|
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
/**
|
|
|
|
* Wrapper for an edge (const or not) allowing retrieval, but no modification.
|
|
|
|
* @tparam Tedge Actual edge class, may be "const BaseEdge" or just "BaseEdge".
|
|
|
|
*/
|
|
|
|
template<typename Tedge>
|
|
|
|
class EdgeWrapper {
|
|
|
|
protected:
|
2022-12-05 18:17:25 +00:00
|
|
|
Tedge *edge; ///< Actual edge to be used.
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrap a an edge.
|
|
|
|
* @param edge Edge to be wrapped.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
EdgeWrapper (Tedge &edge) : edge(&edge) {}
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get edge's capacity.
|
|
|
|
* @return Capacity.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
uint Capacity() const { return this->edge->capacity; }
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get edge's usage.
|
|
|
|
* @return Usage.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
uint Usage() const { return this->edge->usage; }
|
2013-05-19 14:11:20 +00:00
|
|
|
|
2021-07-24 09:07:10 +00:00
|
|
|
/**
|
|
|
|
* Get edge's average travel time.
|
|
|
|
* @return Travel time, in ticks.
|
|
|
|
*/
|
2024-01-07 16:41:53 +00:00
|
|
|
uint32_t TravelTime() const { return this->edge->travel_time_sum / this->edge->capacity; }
|
2021-07-24 09:07:10 +00:00
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
/**
|
2013-10-22 16:13:28 +00:00
|
|
|
* Get the date of the last update to the edge's unrestricted capacity.
|
|
|
|
* @return Last update.
|
|
|
|
*/
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date LastUnrestrictedUpdate() const { return this->edge->last_unrestricted_update; }
|
2013-10-22 16:13:28 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the date of the last update to the edge's restricted capacity.
|
|
|
|
* @return Last update.
|
|
|
|
*/
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date LastRestrictedUpdate() const { return this->edge->last_restricted_update; }
|
2013-10-22 16:13:28 +00:00
|
|
|
|
2022-01-02 01:15:54 +00:00
|
|
|
/**
|
|
|
|
* Get the date of the last update to the edge's aircraft capacity.
|
|
|
|
* @return Last update.
|
|
|
|
*/
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date LastAircraftUpdate() const { return this->edge->last_aircraft_update; }
|
2022-01-02 01:15:54 +00:00
|
|
|
|
2013-10-22 16:13:28 +00:00
|
|
|
/**
|
|
|
|
* Get the date of the last update to any part of the edge's capacity.
|
2013-05-19 14:11:20 +00:00
|
|
|
* @return Last update.
|
|
|
|
*/
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date LastUpdate() const { return std::max(this->edge->last_unrestricted_update, this->edge->last_restricted_update); }
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrapper for a node (const or not) allowing retrieval, but no modification.
|
|
|
|
* @tparam Tedge Actual node class, may be "const BaseNode" or just "BaseNode".
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
template<typename Tnode>
|
2013-05-19 14:11:20 +00:00
|
|
|
class NodeWrapper {
|
|
|
|
protected:
|
2022-12-05 18:17:25 +00:00
|
|
|
Tnode &node; ///< Node being wrapped.
|
|
|
|
NodeID index; ///< ID of wrapped node.
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wrap a node.
|
|
|
|
* @param node Node to be wrapped.
|
|
|
|
* @param index ID of node to be wrapped.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
NodeWrapper(Tnode &node, NodeID index) : node(node), index(index) {}
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get supply of wrapped node.
|
|
|
|
* @return Supply.
|
|
|
|
*/
|
|
|
|
uint Supply() const { return this->node.supply; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get demand of wrapped node.
|
|
|
|
* @return Demand.
|
|
|
|
*/
|
|
|
|
uint Demand() const { return this->node.demand; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get ID of station belonging to wrapped node.
|
|
|
|
* @return ID of node's station.
|
|
|
|
*/
|
|
|
|
StationID Station() const { return this->node.station; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get node's last update.
|
|
|
|
* @return Last update.
|
|
|
|
*/
|
2024-02-13 21:34:09 +00:00
|
|
|
EconTime::Date LastUpdate() const { return this->node.last_update; }
|
2014-06-14 13:35:39 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the location of the station associated with the node.
|
|
|
|
* @return Location of the station.
|
|
|
|
*/
|
|
|
|
TileIndex XY() const { return this->node.xy; }
|
2013-05-19 14:11:20 +00:00
|
|
|
|
2022-12-05 18:17:25 +00:00
|
|
|
NodeID GetNodeID() const { return this->index; }
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A constant edge class.
|
|
|
|
*/
|
|
|
|
typedef EdgeWrapper<const BaseEdge> ConstEdge;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An updatable edge class.
|
|
|
|
*/
|
|
|
|
class Edge : public EdgeWrapper<BaseEdge> {
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* @param edge Edge to be wrapped.
|
|
|
|
*/
|
|
|
|
Edge(BaseEdge &edge) : EdgeWrapper<BaseEdge>(edge) {}
|
2024-01-07 16:41:53 +00:00
|
|
|
void Update(uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode);
|
2024-02-13 21:34:09 +00:00
|
|
|
void Restrict() { this->edge->last_unrestricted_update = EconTime::INVALID_DATE; }
|
|
|
|
void Release() { this->edge->last_restricted_update = EconTime::INVALID_DATE; }
|
|
|
|
void ClearAircraft() { this->edge->last_aircraft_update = EconTime::INVALID_DATE; }
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constant node class. Only retrieval operations are allowed on both the
|
|
|
|
* node itself and its edges.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
class ConstNode : public NodeWrapper<const BaseNode> {
|
2013-05-19 14:11:20 +00:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
* @param lg LinkGraph to get the node from.
|
|
|
|
* @param node ID of the node.
|
|
|
|
*/
|
|
|
|
ConstNode(const LinkGraph *lg, NodeID node) :
|
2022-12-05 18:17:25 +00:00
|
|
|
NodeWrapper<const BaseNode>(lg->nodes[node], node)
|
2013-05-19 14:11:20 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updatable node class. The node itself as well as its edges can be modified.
|
|
|
|
*/
|
2022-12-05 18:17:25 +00:00
|
|
|
class Node : public NodeWrapper<BaseNode> {
|
2013-05-19 14:11:20 +00:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
* @param lg LinkGraph to get the node from.
|
|
|
|
* @param node ID of the node.
|
|
|
|
*/
|
|
|
|
Node(LinkGraph *lg, NodeID node) :
|
2022-12-05 18:17:25 +00:00
|
|
|
NodeWrapper<BaseNode>(lg->nodes[node], node)
|
2013-05-19 14:11:20 +00:00
|
|
|
{}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the node's supply and set last_update to the current date.
|
|
|
|
* @param supply Supply to be added.
|
|
|
|
*/
|
|
|
|
void UpdateSupply(uint supply)
|
|
|
|
{
|
|
|
|
this->node.supply += supply;
|
2024-02-13 21:34:09 +00:00
|
|
|
this->node.last_update = EconTime::CurDate();
|
2013-05-19 14:11:20 +00:00
|
|
|
}
|
|
|
|
|
2014-06-14 13:35:39 +00:00
|
|
|
/**
|
|
|
|
* Update the node's location on the map.
|
|
|
|
* @param xy New location.
|
|
|
|
*/
|
|
|
|
void UpdateLocation(TileIndex xy)
|
|
|
|
{
|
|
|
|
this->node.xy = xy;
|
|
|
|
}
|
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
/**
|
|
|
|
* Set the node's demand.
|
|
|
|
* @param demand New demand for the node.
|
|
|
|
*/
|
|
|
|
void SetDemand(uint demand)
|
|
|
|
{
|
|
|
|
this->node.demand = demand;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Minimum effective distance for timeout calculation. */
|
2013-10-22 16:19:31 +00:00
|
|
|
static const uint MIN_TIMEOUT_DISTANCE = 32;
|
2013-05-19 14:11:20 +00:00
|
|
|
|
2021-08-18 15:06:22 +00:00
|
|
|
/** Number of days before deleting links served only by vehicles stopped in depot. */
|
2023-12-19 01:03:18 +00:00
|
|
|
static constexpr DateDelta STALE_LINK_DEPOT_TIMEOUT = 1024;
|
2021-08-18 15:06:22 +00:00
|
|
|
|
2023-12-19 01:03:18 +00:00
|
|
|
/** Minimum number of ticks between subsequent compressions of a LG. */
|
2024-02-15 02:05:27 +00:00
|
|
|
static constexpr ScaledTickCounter COMPRESSION_INTERVAL = 256 * DAY_TICKS;
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Scale a value from a link graph of age orig_age for usage in one of age
|
|
|
|
* target_age. Make sure that the value stays > 0 if it was > 0 before.
|
|
|
|
* @param val Value to be scaled.
|
|
|
|
* @param target_age Age of the target link graph.
|
|
|
|
* @param orig_age Age of the original link graph.
|
|
|
|
* @return scaled value.
|
|
|
|
*/
|
|
|
|
inline static uint Scale(uint val, uint target_age, uint orig_age)
|
|
|
|
{
|
2021-01-08 10:16:18 +00:00
|
|
|
return val > 0 ? std::max(1U, val * target_age / orig_age) : 0;
|
2013-05-19 14:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Bare constructor, only for save/load. */
|
2024-01-06 15:15:37 +00:00
|
|
|
LinkGraph() : cargo(INVALID_CARGO), last_compression(0) {}
|
2013-05-19 14:11:20 +00:00
|
|
|
/**
|
|
|
|
* Real constructor.
|
|
|
|
* @param cargo Cargo the link graph is about.
|
|
|
|
*/
|
2024-02-15 02:05:27 +00:00
|
|
|
LinkGraph(CargoID cargo) : cargo(cargo), last_compression(_scaled_tick_counter) {}
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
void Init(uint size);
|
2023-12-19 01:03:18 +00:00
|
|
|
void ShiftDates(DateDelta interval);
|
2013-05-19 14:11:20 +00:00
|
|
|
void Compress();
|
|
|
|
void Merge(LinkGraph *other);
|
|
|
|
|
|
|
|
/* Splitting link graphs is intentionally not implemented.
|
|
|
|
* The overhead in determining connectedness would probably outweigh the
|
|
|
|
* benefit of having to deal with smaller graphs. In real world examples
|
|
|
|
* networks generally grow. Only rarely a network is permanently split.
|
|
|
|
* Reacting to temporary splits here would obviously create performance
|
|
|
|
* problems and detecting the temporary or permanent nature of splits isn't
|
|
|
|
* trivial. */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a node with the specified id.
|
|
|
|
* @param num ID of the node.
|
|
|
|
* @return the Requested node.
|
|
|
|
*/
|
|
|
|
inline Node operator[](NodeID num) { return Node(this, num); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a const reference to a node with the specified id.
|
|
|
|
* @param num ID of the node.
|
|
|
|
* @return the Requested node.
|
|
|
|
*/
|
|
|
|
inline ConstNode operator[](NodeID num) const { return ConstNode(this, num); }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current size of the component.
|
|
|
|
* @return Size.
|
|
|
|
*/
|
2021-05-26 19:32:43 +00:00
|
|
|
inline NodeID Size() const { return (NodeID)this->nodes.size(); }
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get date of last compression.
|
|
|
|
* @return Date of last compression.
|
|
|
|
*/
|
2024-02-15 02:05:27 +00:00
|
|
|
inline ScaledTickCounter LastCompression() const { return this->last_compression; }
|
2013-05-19 14:11:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the cargo ID this component's link graph refers to.
|
|
|
|
* @return Cargo ID.
|
|
|
|
*/
|
|
|
|
inline CargoID Cargo() const { return this->cargo; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scale a value to its monthly equivalent, based on last compression.
|
|
|
|
* @param base Value to be scaled.
|
|
|
|
* @return Scaled value.
|
|
|
|
*/
|
|
|
|
inline uint Monthly(uint base) const
|
|
|
|
{
|
2024-02-15 02:05:27 +00:00
|
|
|
return (uint)((static_cast<uint64_t>(base) * 30 * DAY_TICKS * DayLengthFactor()) / std::max<uint64_t>(_scaled_tick_counter - this->last_compression, DAY_TICKS));
|
2013-05-19 14:11:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NodeID AddNode(const Station *st);
|
|
|
|
void RemoveNode(NodeID id);
|
|
|
|
|
2024-01-07 16:41:53 +00:00
|
|
|
void UpdateEdge(NodeID from, NodeID to, uint capacity, uint usage, uint32_t time, EdgeUpdateMode mode);
|
2022-12-05 18:17:25 +00:00
|
|
|
void RemoveEdge(NodeID from, NodeID to);
|
|
|
|
|
2024-01-07 16:41:53 +00:00
|
|
|
inline uint64_t CalculateCostEstimate() const {
|
|
|
|
uint64_t size_squared = (uint32_t)this->Size() * (uint32_t)this->Size();
|
2016-10-31 00:21:01 +00:00
|
|
|
return size_squared * FindLastBit(size_squared * size_squared); // N^2 * 4log_2(N)
|
|
|
|
}
|
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
protected:
|
|
|
|
friend class LinkGraph::ConstNode;
|
|
|
|
friend class LinkGraph::Node;
|
2021-05-31 20:26:44 +00:00
|
|
|
friend SaveLoadTable GetLinkGraphDesc();
|
|
|
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
2019-09-23 16:30:09 +00:00
|
|
|
friend void Save_LinkGraph(LinkGraph &lg);
|
|
|
|
friend void Load_LinkGraph(LinkGraph &lg);
|
2013-05-19 14:11:20 +00:00
|
|
|
|
2021-11-01 18:33:39 +00:00
|
|
|
friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphDesc();
|
|
|
|
friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc();
|
|
|
|
friend upstream_sl::SlLinkgraphNode;
|
|
|
|
friend upstream_sl::SlLinkgraphEdge;
|
|
|
|
|
2024-02-15 02:05:27 +00:00
|
|
|
friend void LinkGraphFixupAfterLoad(bool compression_was_date);
|
2023-07-02 15:44:24 +00:00
|
|
|
|
2013-05-19 14:11:20 +00:00
|
|
|
CargoID cargo; ///< Cargo of this component's link graph.
|
2024-02-15 02:05:27 +00:00
|
|
|
ScaledTickCounter last_compression; ///< Last time the capacities and supplies were compressed.
|
2013-05-19 14:11:20 +00:00
|
|
|
NodeVector nodes; ///< Nodes in the component.
|
|
|
|
EdgeMatrix edges; ///< Edges in the component.
|
2022-12-05 18:17:25 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
const EdgeMatrix &GetEdges() const { return this->edges; }
|
|
|
|
|
|
|
|
const BaseEdge &GetBaseEdge(NodeID from, NodeID to) const
|
|
|
|
{
|
|
|
|
auto iter = this->edges.find(std::make_pair(from, to));
|
|
|
|
if (iter != this->edges.end()) return iter->second;
|
|
|
|
|
|
|
|
static LinkGraph::BaseEdge empty_edge = {};
|
|
|
|
return empty_edge;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstEdge GetConstEdge(NodeID from, NodeID to) const { return ConstEdge(this->GetBaseEdge(from, to)); }
|
|
|
|
|
|
|
|
template <typename F>
|
|
|
|
void IterateEdgesFromNode(NodeID from_id, F proc) const
|
|
|
|
{
|
|
|
|
auto iter = this->edges.lower_bound(std::make_pair(from_id, (NodeID)0));
|
|
|
|
while (iter != this->edges.end()) {
|
|
|
|
NodeID from = iter->first.first;
|
|
|
|
NodeID to = iter->first.second;
|
|
|
|
if (from != from_id) return;
|
|
|
|
if (from != to) {
|
|
|
|
proc(from, to, ConstEdge(iter->second));
|
|
|
|
}
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class EdgeIterationResult {
|
|
|
|
None,
|
|
|
|
EraseEdge,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct EdgeIterationHelper {
|
|
|
|
EdgeMatrix &edges;
|
|
|
|
EdgeMatrix::iterator &iter;
|
|
|
|
const NodeID from_id;
|
|
|
|
const NodeID to_id;
|
|
|
|
size_t expected_size;
|
|
|
|
|
|
|
|
EdgeIterationHelper(EdgeMatrix &edges, EdgeMatrix::iterator &iter, NodeID from_id, NodeID to_id) :
|
|
|
|
edges(edges), iter(iter), from_id(from_id), to_id(to_id), expected_size(0) {}
|
|
|
|
|
|
|
|
Edge GetEdge() { return Edge(this->iter->second); }
|
|
|
|
|
|
|
|
void RecordSize() { this->expected_size = this->edges.size(); }
|
|
|
|
|
|
|
|
bool RefreshIterationIfSizeChanged()
|
|
|
|
{
|
|
|
|
if (this->expected_size != this->edges.size()) {
|
|
|
|
/* Edges container has resized, our iterator is now invalid, so find it again */
|
|
|
|
this->iter = this->edges.find(std::make_pair(this->from_id, this->to_id));
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename F>
|
|
|
|
void MutableIterateEdgesFromNode(NodeID from_id, F proc)
|
|
|
|
{
|
|
|
|
EdgeMatrix::iterator iter = this->edges.lower_bound(std::make_pair(from_id, (NodeID)0));
|
|
|
|
while (iter != this->edges.end()) {
|
|
|
|
NodeID from = iter->first.first;
|
|
|
|
NodeID to = iter->first.second;
|
|
|
|
if (from != from_id) return;
|
|
|
|
EdgeIterationResult result = EdgeIterationResult::None;
|
|
|
|
if (from != to) {
|
|
|
|
result = proc(EdgeIterationHelper(this->edges, iter, from, to));
|
|
|
|
}
|
|
|
|
switch (result) {
|
|
|
|
case EdgeIterationResult::None:
|
|
|
|
++iter;
|
|
|
|
break;
|
|
|
|
case EdgeIterationResult::EraseEdge:
|
|
|
|
iter = this->edges.erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-19 14:11:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* LINKGRAPH_H */
|