OpenTTD Source 20260206-master-g4d4e37dbf1
linkgraph.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../stdafx.h"
11#include "../core/pool_func.hpp"
12#include "linkgraph.h"
13
14#include "../safeguards.h"
15
16/* Initialize the link-graph-pool */
19
20
27{
28 this->xy = xy;
29 this->supply = 0;
30 this->demand = demand;
31 this->station = st;
33}
34
47
53void LinkGraph::ShiftDates(TimerGameEconomy::Date interval)
54{
55 this->last_compression += interval;
56 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
57 BaseNode &source = this->nodes[node1];
58 if (source.last_update != EconomyTime::INVALID_DATE) source.last_update += interval;
59 for (BaseEdge &edge : this->nodes[node1].edges) {
60 if (edge.last_unrestricted_update != EconomyTime::INVALID_DATE) edge.last_unrestricted_update += interval;
61 if (edge.last_restricted_update != EconomyTime::INVALID_DATE) edge.last_restricted_update += interval;
62 }
63 }
64}
65
66void LinkGraph::Compress()
67{
68 this->last_compression = TimerGameEconomy::Date{(TimerGameEconomy::date + this->last_compression).base() / 2};
69 for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
70 this->nodes[node1].supply /= 2;
71 for (BaseEdge &edge : this->nodes[node1].edges) {
72 if (edge.capacity > 0) {
73 uint new_capacity = std::max(1U, edge.capacity / 2);
74 if (edge.capacity < (1 << 16)) {
75 edge.travel_time_sum = edge.travel_time_sum * new_capacity / edge.capacity;
76 } else if (edge.travel_time_sum != 0) {
77 edge.travel_time_sum = std::max<uint64_t>(1, edge.travel_time_sum / 2);
78 }
79 edge.capacity = new_capacity;
80 edge.usage /= 2;
81 }
82 }
83 }
84}
85
91{
92 TimerGameEconomy::Date age = TimerGameEconomy::date - this->last_compression + 1;
93 TimerGameEconomy::Date other_age = TimerGameEconomy::date - other->last_compression + 1;
94 NodeID first = this->Size();
95 for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
96 Station *st = Station::Get(other->nodes[node1].station);
97 NodeID new_node = this->AddNode(st);
98 this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age);
99 st->goods[this->cargo].link_graph = this->index;
100 st->goods[this->cargo].node = new_node;
101
102 for (BaseEdge &e : other->nodes[node1].edges) {
103 BaseEdge &new_edge = this->nodes[new_node].edges.emplace_back(first + e.dest_node);
104 new_edge.capacity = LinkGraph::Scale(e.capacity, age, other_age);
105 new_edge.usage = LinkGraph::Scale(e.usage, age, other_age);
106 new_edge.travel_time_sum = LinkGraph::Scale(e.travel_time_sum, age, other_age);
107 }
108 }
109 delete other;
110}
111
117{
118 assert(id < this->Size());
119
120 NodeID last_node = this->Size() - 1;
121 Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id;
122 /* Erase node by swapping with the last element. Node index is referenced
123 * directly from station goods entries so the order and position must remain. */
124 this->nodes[id] = this->nodes.back();
125 this->nodes.pop_back();
126 for (auto &n : this->nodes) {
127 /* Find iterator position where an edge to id would be. */
128 auto [first, last] = std::equal_range(n.edges.begin(), n.edges.end(), id);
129 /* Remove potential node (erasing an empty range is safe). */
130 auto insert = n.edges.erase(first, last);
131 /* As the edge list is sorted, a potential edge to last_node will always be the last edge. */
132 if (!n.edges.empty() && n.edges.back().dest_node == last_node) {
133 /* Change dest ID and move into the spot of the deleted edge. */
134 n.edges.back().dest_node = id;
135 n.edges.insert(insert, n.edges.back());
136 n.edges.pop_back();
137 }
138 }
139}
140
150{
151 const GoodsEntry &good = st->goods[this->cargo];
152
153 NodeID new_node = this->Size();
154 this->nodes.emplace_back(st->xy, st->index, good.status.Test(GoodsEntry::State::Acceptance));
155
156 return new_node;
157}
158
168void LinkGraph::BaseNode::AddEdge(NodeID to, uint capacity, uint usage, uint32_t travel_time, EdgeUpdateModes modes)
169{
170 assert(!this->HasEdgeTo(to));
171
172 BaseEdge &edge = *this->edges.emplace(std::upper_bound(this->edges.begin(), this->edges.end(), to), to);
173 edge.capacity = capacity;
174 edge.usage = usage;
175 edge.travel_time_sum = static_cast<uint64_t>(travel_time) * capacity;
178}
179
188void LinkGraph::BaseNode::UpdateEdge(NodeID to, uint capacity, uint usage, uint32_t travel_time, EdgeUpdateModes modes)
189{
190 assert(capacity > 0);
191 assert(usage <= capacity);
192 if (!this->HasEdgeTo(to)) {
193 this->AddEdge(to, capacity, usage, travel_time, modes);
194 } else {
195 this->GetEdge(to)->Update(capacity, usage, travel_time, modes);
196 }
197}
198
204{
205 auto [first, last] = std::equal_range(this->edges.begin(), this->edges.end(), to);
206 this->edges.erase(first, last);
207}
208
219void LinkGraph::BaseEdge::Update(uint capacity, uint usage, uint32_t travel_time, EdgeUpdateModes modes)
220{
221 assert(this->capacity > 0);
222 assert(capacity >= usage);
223
224 if (modes.Test(EdgeUpdateMode::Increase)) {
225 if (this->travel_time_sum == 0) {
226 this->travel_time_sum = static_cast<uint64_t>(this->capacity + capacity) * travel_time;
227 } else if (travel_time == 0) {
228 this->travel_time_sum += this->travel_time_sum / this->capacity * capacity;
229 } else {
230 this->travel_time_sum += static_cast<uint64_t>(travel_time) * capacity;
231 }
232 this->capacity += capacity;
233 this->usage += usage;
234 } else if (modes.Test(EdgeUpdateMode::Refresh)) {
235 if (this->travel_time_sum == 0) {
236 this->capacity = std::max(this->capacity, capacity);
237 this->travel_time_sum = static_cast<uint64_t>(travel_time) * this->capacity;
238 } else if (capacity > this->capacity) {
239 this->travel_time_sum = this->travel_time_sum / this->capacity * capacity;
240 this->capacity = capacity;
241 }
242 this->usage = std::max(this->usage, usage);
243 }
246}
247
253void LinkGraph::Init(uint size)
254{
255 assert(this->Size() == 0);
256 this->nodes.resize(size);
257}
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
A connected component of a link graph.
Definition linkgraph.h:37
void Merge(LinkGraph *other)
Merge a link graph with another one.
Definition linkgraph.cpp:90
void Init(uint size)
Resize the component and fill it with empty nodes and edges.
CargoType cargo
Cargo of this component's link graph.
Definition linkgraph.h:264
NodeVector nodes
Nodes in the component.
Definition linkgraph.h:266
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates by given interval.
Definition linkgraph.cpp:53
NodeID AddNode(const Station *st)
Add a node to the component and create empty edges associated with it.
NodeID Size() const
Get the current size of the component.
Definition linkgraph.h:230
void RemoveNode(NodeID id)
Remove a node from the link graph by overwriting it with the last node.
static uint Scale(uint val, TimerGameEconomy::Date target_age, TimerGameEconomy::Date orig_age)
Scale a value from a link graph of age orig_age for usage in one of age target_age.
Definition linkgraph.h:186
LinkGraph(LinkGraphID index, CargoType cargo=INVALID_CARGO)
Real constructor.
Definition linkgraph.h:196
TimerGameEconomy::Date last_compression
Last time the capacities and supplies were compressed.
Definition linkgraph.h:265
static constexpr TimerGame< struct Economy >::Date INVALID_DATE
static Date date
Current date in days (day counter).
Declaration of link graph classes used for cargo distribution.
LinkGraphPool _link_graph_pool
The actual pool with link graphs.
Pool< LinkGraph, LinkGraphID, 32 > LinkGraphPool
Type of the pool for link graph components.
Definition linkgraph.h:27
@ Refresh
Refresh capacity.
@ Unrestricted
Use unrestricted link.
@ Increase
Increase capacity.
@ Restricted
Use restricted link.
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
TileIndex xy
Base tile of the station.
Stores station stats for a single cargo.
States status
Status of this cargo, see State.
@ Acceptance
Set when the station accepts the cargo currently for final deliveries.
An edge in the link graph.
Definition linkgraph.h:42
TimerGameEconomy::Date last_restricted_update
When the restricted part of the link was last updated.
Definition linkgraph.h:47
uint64_t travel_time_sum
Sum of the travel times of the link, in ticks.
Definition linkgraph.h:45
NodeID dest_node
Destination of the edge.
Definition linkgraph.h:48
uint usage
Usage of the link.
Definition linkgraph.h:44
void Update(uint capacity, uint usage, uint32_t time, EdgeUpdateModes modes)
Update an edge.
BaseEdge(NodeID dest_node=INVALID_NODE)
Create an edge.
Definition linkgraph.cpp:38
TimerGameEconomy::Date last_unrestricted_update
When the unrestricted part of the link was last updated.
Definition linkgraph.h:46
uint capacity
Capacity of the link.
Definition linkgraph.h:43
Node of the link graph.
Definition linkgraph.h:90
StationID station
Station ID.
Definition linkgraph.h:93
TimerGameEconomy::Date last_update
When the supply was last updated.
Definition linkgraph.h:95
BaseNode(TileIndex xy=INVALID_TILE, StationID st=StationID::Invalid(), uint demand=0)
Create a node or clear it.
Definition linkgraph.cpp:26
uint supply
Supply at the station.
Definition linkgraph.h:91
void RemoveEdge(NodeID to)
Remove an outgoing edge from this node.
void AddEdge(NodeID to, uint capacity, uint usage, uint32_t time, EdgeUpdateModes modes)
Fill an edge with values from a link.
TileIndex xy
Location of the station referred to by the node.
Definition linkgraph.h:94
uint demand
Acceptance at the station.
Definition linkgraph.h:92
void UpdateEdge(NodeID to, uint capacity, uint usage, uint32_t time, EdgeUpdateModes modes)
Creates an edge if none exists yet or updates an existing edge.
bool HasEdgeTo(NodeID dest) const
Check if an edge to a destination is present.
Definition linkgraph.h:138
static Station * Get(auto index)
Station data structure.
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92