mirror of https://github.com/OpenTTD/OpenTTD
Codechange: [Linkgraph] Store edges in each node and not in a global matrix.
parent
2fee8ecdda
commit
fe27db3dfd
|
@ -94,6 +94,8 @@ public:
|
||||||
|
|
||||||
constexpr reference operator[](size_type idx) const { return first[idx]; }
|
constexpr reference operator[](size_type idx) const { return first[idx]; }
|
||||||
|
|
||||||
|
constexpr pointer data() const noexcept { return first; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pointer first;
|
pointer first;
|
||||||
pointer last;
|
pointer last;
|
||||||
|
|
|
@ -23,7 +23,7 @@ INSTANTIATE_POOL_METHODS(LinkGraph)
|
||||||
* @param st ID of the associated station.
|
* @param st ID of the associated station.
|
||||||
* @param demand Demand for cargo at the station.
|
* @param demand Demand for cargo at the station.
|
||||||
*/
|
*/
|
||||||
inline void LinkGraph::BaseNode::Init(TileIndex xy, StationID st, uint demand)
|
LinkGraph::BaseNode::BaseNode(TileIndex xy, StationID st, uint demand)
|
||||||
{
|
{
|
||||||
this->xy = xy;
|
this->xy = xy;
|
||||||
this->supply = 0;
|
this->supply = 0;
|
||||||
|
@ -35,7 +35,7 @@ inline void LinkGraph::BaseNode::Init(TileIndex xy, StationID st, uint demand)
|
||||||
/**
|
/**
|
||||||
* Create an edge.
|
* Create an edge.
|
||||||
*/
|
*/
|
||||||
inline void LinkGraph::BaseEdge::Init()
|
LinkGraph::BaseEdge::BaseEdge()
|
||||||
{
|
{
|
||||||
this->capacity = 0;
|
this->capacity = 0;
|
||||||
this->usage = 0;
|
this->usage = 0;
|
||||||
|
@ -57,7 +57,7 @@ void LinkGraph::ShiftDates(int interval)
|
||||||
BaseNode &source = this->nodes[node1];
|
BaseNode &source = this->nodes[node1];
|
||||||
if (source.last_update != INVALID_DATE) source.last_update += interval;
|
if (source.last_update != INVALID_DATE) source.last_update += interval;
|
||||||
for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
|
for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
|
||||||
BaseEdge &edge = this->edges[node1][node2];
|
BaseEdge &edge = this->nodes[node1].edges[node2];
|
||||||
if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
|
if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval;
|
||||||
if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
|
if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ void LinkGraph::Compress()
|
||||||
for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
|
for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
|
||||||
this->nodes[node1].supply /= 2;
|
this->nodes[node1].supply /= 2;
|
||||||
for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
|
for (NodeID node2 = 0; node2 < this->Size(); ++node2) {
|
||||||
BaseEdge &edge = this->edges[node1][node2];
|
BaseEdge &edge = this->nodes[node1].edges[node2];
|
||||||
if (edge.capacity > 0) {
|
if (edge.capacity > 0) {
|
||||||
uint new_capacity = std::max(1U, edge.capacity / 2);
|
uint new_capacity = std::max(1U, edge.capacity / 2);
|
||||||
if (edge.capacity < (1 << 16)) {
|
if (edge.capacity < (1 << 16)) {
|
||||||
|
@ -101,10 +101,10 @@ void LinkGraph::Merge(LinkGraph *other)
|
||||||
st->goods[this->cargo].link_graph = this->index;
|
st->goods[this->cargo].link_graph = this->index;
|
||||||
st->goods[this->cargo].node = new_node;
|
st->goods[this->cargo].node = new_node;
|
||||||
for (NodeID node2 = 0; node2 < node1; ++node2) {
|
for (NodeID node2 = 0; node2 < node1; ++node2) {
|
||||||
BaseEdge &forward = this->edges[new_node][first + node2];
|
BaseEdge &forward = this->nodes[new_node].edges[first + node2];
|
||||||
BaseEdge &backward = this->edges[first + node2][new_node];
|
BaseEdge &backward = this->nodes[first + node2].edges[new_node];
|
||||||
forward = other->edges[node1][node2];
|
forward = other->nodes[node1].edges[node2];
|
||||||
backward = other->edges[node2][node1];
|
backward = other->nodes[node2].edges[node1];
|
||||||
forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
|
forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age);
|
||||||
forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
|
forward.usage = LinkGraph::Scale(forward.usage, age, other_age);
|
||||||
forward.travel_time_sum = LinkGraph::Scale(forward.travel_time_sum, age, other_age);
|
forward.travel_time_sum = LinkGraph::Scale(forward.travel_time_sum, age, other_age);
|
||||||
|
@ -114,8 +114,8 @@ void LinkGraph::Merge(LinkGraph *other)
|
||||||
backward.travel_time_sum = LinkGraph::Scale(backward.travel_time_sum, age, other_age);
|
backward.travel_time_sum = LinkGraph::Scale(backward.travel_time_sum, age, other_age);
|
||||||
if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
|
if (backward.next_edge != INVALID_NODE) backward.next_edge += first;
|
||||||
}
|
}
|
||||||
BaseEdge &new_start = this->edges[new_node][new_node];
|
BaseEdge &new_start = this->nodes[new_node].edges[new_node];
|
||||||
new_start = other->edges[node1][node1];
|
new_start = other->nodes[node1].edges[node1];
|
||||||
if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
|
if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first;
|
||||||
}
|
}
|
||||||
delete other;
|
delete other;
|
||||||
|
@ -132,7 +132,7 @@ void LinkGraph::RemoveNode(NodeID id)
|
||||||
NodeID last_node = this->Size() - 1;
|
NodeID last_node = this->Size() - 1;
|
||||||
for (NodeID i = 0; i <= last_node; ++i) {
|
for (NodeID i = 0; i <= last_node; ++i) {
|
||||||
(*this)[i].RemoveEdge(id);
|
(*this)[i].RemoveEdge(id);
|
||||||
BaseEdge *node_edges = this->edges[i];
|
auto node_edges = this->nodes[i].edges;
|
||||||
NodeID prev = i;
|
NodeID prev = i;
|
||||||
NodeID next = node_edges[i].next_edge;
|
NodeID next = node_edges[i].next_edge;
|
||||||
while (next != INVALID_NODE) {
|
while (next != INVALID_NODE) {
|
||||||
|
@ -150,10 +150,9 @@ void LinkGraph::RemoveNode(NodeID id)
|
||||||
* directly from station goods entries so the order and position must remain. */
|
* directly from station goods entries so the order and position must remain. */
|
||||||
this->nodes[id] = this->nodes.back();
|
this->nodes[id] = this->nodes.back();
|
||||||
this->nodes.pop_back();
|
this->nodes.pop_back();
|
||||||
this->edges.EraseColumn(id);
|
for (auto &n : this->nodes) {
|
||||||
/* Not doing EraseRow here, as having the extra invalid row doesn't hurt
|
n.edges.pop_back();
|
||||||
* and removing it would trigger a lot of memmove. The data has already
|
}
|
||||||
* been copied around in the loop above. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,23 +168,15 @@ NodeID LinkGraph::AddNode(const Station *st)
|
||||||
const GoodsEntry &good = st->goods[this->cargo];
|
const GoodsEntry &good = st->goods[this->cargo];
|
||||||
|
|
||||||
NodeID new_node = this->Size();
|
NodeID new_node = this->Size();
|
||||||
this->nodes.emplace_back();
|
this->nodes.emplace_back(st->xy, st->index, HasBit(good.status, GoodsEntry::GES_ACCEPTANCE));
|
||||||
/* Avoid reducing the height of the matrix as that is expensive and we
|
|
||||||
* most likely will increase it again later which is again expensive. */
|
|
||||||
this->edges.Resize(new_node + 1U, std::max(new_node + 1U, this->edges.Height()));
|
|
||||||
|
|
||||||
this->nodes[new_node].Init(st->xy, st->index,
|
for (auto &n : this->nodes) {
|
||||||
HasBit(good.status, GoodsEntry::GES_ACCEPTANCE));
|
n.edges.resize(this->Size());
|
||||||
|
}
|
||||||
BaseEdge *new_edges = this->edges[new_node];
|
|
||||||
|
|
||||||
/* Reset the first edge starting at the new node */
|
/* Reset the first edge starting at the new node */
|
||||||
new_edges[new_node].next_edge = INVALID_NODE;
|
this->nodes[new_node].edges[new_node].next_edge = INVALID_NODE;
|
||||||
|
|
||||||
for (NodeID i = 0; i <= new_node; ++i) {
|
|
||||||
new_edges[i].Init();
|
|
||||||
this->edges[i][new_node].Init();
|
|
||||||
}
|
|
||||||
return new_node;
|
return new_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,8 +191,8 @@ NodeID LinkGraph::AddNode(const Station *st)
|
||||||
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, uint32 travel_time, EdgeUpdateMode mode)
|
void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, uint32 travel_time, EdgeUpdateMode mode)
|
||||||
{
|
{
|
||||||
assert(this->index != to);
|
assert(this->index != to);
|
||||||
BaseEdge &edge = this->edges[to];
|
BaseEdge &edge = this->node.edges[to];
|
||||||
BaseEdge &first = this->edges[this->index];
|
BaseEdge &first = this->node.edges[this->index];
|
||||||
edge.capacity = capacity;
|
edge.capacity = capacity;
|
||||||
edge.usage = usage;
|
edge.usage = usage;
|
||||||
edge.travel_time_sum = static_cast<uint64>(travel_time) * capacity;
|
edge.travel_time_sum = static_cast<uint64>(travel_time) * capacity;
|
||||||
|
@ -222,7 +213,7 @@ void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, uint32 tr
|
||||||
{
|
{
|
||||||
assert(capacity > 0);
|
assert(capacity > 0);
|
||||||
assert(usage <= capacity);
|
assert(usage <= capacity);
|
||||||
if (this->edges[to].capacity == 0) {
|
if (this->node.edges[to].capacity == 0) {
|
||||||
this->AddEdge(to, capacity, usage, travel_time, mode);
|
this->AddEdge(to, capacity, usage, travel_time, mode);
|
||||||
} else {
|
} else {
|
||||||
(*this)[to].Update(capacity, usage, travel_time, mode);
|
(*this)[to].Update(capacity, usage, travel_time, mode);
|
||||||
|
@ -236,7 +227,7 @@ void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, uint32 tr
|
||||||
void LinkGraph::Node::RemoveEdge(NodeID to)
|
void LinkGraph::Node::RemoveEdge(NodeID to)
|
||||||
{
|
{
|
||||||
if (this->index == to) return;
|
if (this->index == to) return;
|
||||||
BaseEdge &edge = this->edges[to];
|
BaseEdge &edge = this->node.edges[to];
|
||||||
edge.capacity = 0;
|
edge.capacity = 0;
|
||||||
edge.last_unrestricted_update = INVALID_DATE;
|
edge.last_unrestricted_update = INVALID_DATE;
|
||||||
edge.last_restricted_update = INVALID_DATE;
|
edge.last_restricted_update = INVALID_DATE;
|
||||||
|
@ -244,16 +235,16 @@ void LinkGraph::Node::RemoveEdge(NodeID to)
|
||||||
edge.travel_time_sum = 0;
|
edge.travel_time_sum = 0;
|
||||||
|
|
||||||
NodeID prev = this->index;
|
NodeID prev = this->index;
|
||||||
NodeID next = this->edges[this->index].next_edge;
|
NodeID next = this->node.edges[this->index].next_edge;
|
||||||
while (next != INVALID_NODE) {
|
while (next != INVALID_NODE) {
|
||||||
if (next == to) {
|
if (next == to) {
|
||||||
/* Will be removed, skip it. */
|
/* Will be removed, skip it. */
|
||||||
this->edges[prev].next_edge = edge.next_edge;
|
this->node.edges[prev].next_edge = edge.next_edge;
|
||||||
edge.next_edge = INVALID_NODE;
|
edge.next_edge = INVALID_NODE;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
prev = next;
|
prev = next;
|
||||||
next = this->edges[next].next_edge;
|
next = this->node.edges[next].next_edge;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,12 +296,9 @@ void LinkGraph::Edge::Update(uint capacity, uint usage, uint32 travel_time, Edge
|
||||||
void LinkGraph::Init(uint size)
|
void LinkGraph::Init(uint size)
|
||||||
{
|
{
|
||||||
assert(this->Size() == 0);
|
assert(this->Size() == 0);
|
||||||
this->edges.Resize(size, size);
|
|
||||||
this->nodes.resize(size);
|
this->nodes.resize(size);
|
||||||
|
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (auto &n : this->nodes) {
|
||||||
this->nodes[i].Init();
|
n.edges.resize(size);
|
||||||
BaseEdge *column = this->edges[i];
|
|
||||||
for (uint j = 0; j < size; ++j) column[j].Init();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
#include "../core/pool_type.hpp"
|
#include "../core/pool_type.hpp"
|
||||||
#include "../core/smallmap_type.hpp"
|
#include "../core/smallmap_type.hpp"
|
||||||
#include "../core/smallmatrix_type.hpp"
|
|
||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../cargotype.h"
|
#include "../cargotype.h"
|
||||||
#include "../date_func.h"
|
#include "../date_func.h"
|
||||||
|
@ -38,21 +37,6 @@ extern LinkGraphPool _link_graph_pool;
|
||||||
*/
|
*/
|
||||||
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
|
class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> {
|
||||||
public:
|
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.
|
|
||||||
TileIndex xy; ///< Location of the station referred to by the node.
|
|
||||||
Date last_update; ///< When the supply was last updated.
|
|
||||||
void Init(TileIndex xy = INVALID_TILE, StationID st = INVALID_STATION, uint demand = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An edge in the link graph. Corresponds to a link between two stations or at
|
* 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
|
* least the distance between them. Edges from one node to itself contain the
|
||||||
|
@ -66,7 +50,25 @@ public:
|
||||||
Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated.
|
Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated.
|
||||||
Date last_restricted_update; ///< When the restricted part of the link was last updated.
|
Date last_restricted_update; ///< When the restricted part of the link was last updated.
|
||||||
NodeID next_edge; ///< Destination of next valid edge starting at the same source node.
|
NodeID next_edge; ///< Destination of next valid edge starting at the same source node.
|
||||||
void Init();
|
|
||||||
|
BaseEdge();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
TileIndex xy; ///< Location of the station referred to by the node.
|
||||||
|
Date last_update; ///< When the supply was last updated.
|
||||||
|
|
||||||
|
std::vector<BaseEdge> edges;
|
||||||
|
|
||||||
|
BaseNode(TileIndex xy = INVALID_TILE, StationID st = INVALID_STATION, uint demand = 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,26 +127,22 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for a node (const or not) allowing retrieval, but no modification.
|
* Wrapper for a node (const or not) allowing retrieval, but no modification.
|
||||||
* @tparam Tedge Actual node class, may be "const BaseNode" or just "BaseNode".
|
* @tparam Tnode Actual node class, may be "const BaseNode" or just "BaseNode".
|
||||||
* @tparam Tedge Actual edge class, may be "const BaseEdge" or just "BaseEdge".
|
|
||||||
*/
|
*/
|
||||||
template<typename Tnode, typename Tedge>
|
template<typename Tnode>
|
||||||
class NodeWrapper {
|
class NodeWrapper {
|
||||||
protected:
|
protected:
|
||||||
Tnode &node; ///< Node being wrapped.
|
Tnode &node; ///< Node being wrapped.
|
||||||
Tedge *edges; ///< Outgoing edges for wrapped node.
|
NodeID index; ///< ID of wrapped node.
|
||||||
NodeID index; ///< ID of wrapped node.
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a node.
|
* Wrap a node.
|
||||||
* @param node Node to be wrapped.
|
* @param node Node to be wrapped.
|
||||||
* @param edges Outgoing edges for node to be wrapped.
|
|
||||||
* @param index ID of node to be wrapped.
|
* @param index ID of node to be wrapped.
|
||||||
*/
|
*/
|
||||||
NodeWrapper(Tnode &node, Tedge *edges, NodeID index) : node(node),
|
NodeWrapper(Tnode &node, NodeID index) : node(node), index(index) {}
|
||||||
edges(edges), index(index) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get supply of wrapped node.
|
* Get supply of wrapped node.
|
||||||
|
@ -187,8 +185,8 @@ public:
|
||||||
template <class Tedge, class Tedge_wrapper, class Titer>
|
template <class Tedge, class Tedge_wrapper, class Titer>
|
||||||
class BaseEdgeIterator {
|
class BaseEdgeIterator {
|
||||||
protected:
|
protected:
|
||||||
Tedge *base; ///< Array of edges being iterated.
|
span<Tedge> base; ///< Array of edges being iterated.
|
||||||
NodeID current; ///< Current offset in edges array.
|
NodeID current; ///< Current offset in edges array.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A "fake" pointer to enable operator-> on temporaries. As the objects
|
* A "fake" pointer to enable operator-> on temporaries. As the objects
|
||||||
|
@ -218,7 +216,7 @@ public:
|
||||||
* @param base Array of edges to be iterated.
|
* @param base Array of edges to be iterated.
|
||||||
* @param current ID of current node (to locate the first edge).
|
* @param current ID of current node (to locate the first edge).
|
||||||
*/
|
*/
|
||||||
BaseEdgeIterator (Tedge *base, NodeID current) :
|
BaseEdgeIterator (span<Tedge> base, NodeID current) :
|
||||||
base(base),
|
base(base),
|
||||||
current(current == INVALID_NODE ? current : base[current].next_edge)
|
current(current == INVALID_NODE ? current : base[current].next_edge)
|
||||||
{}
|
{}
|
||||||
|
@ -254,7 +252,7 @@ public:
|
||||||
template<class Tother>
|
template<class Tother>
|
||||||
bool operator==(const Tother &other)
|
bool operator==(const Tother &other)
|
||||||
{
|
{
|
||||||
return this->base == other.base && this->current == other.current;
|
return this->base.data() == other.base.data() && this->current == other.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,7 +265,7 @@ public:
|
||||||
template<class Tother>
|
template<class Tother>
|
||||||
bool operator!=(const Tother &other)
|
bool operator!=(const Tother &other)
|
||||||
{
|
{
|
||||||
return this->base != other.base || this->current != other.current;
|
return this->base.data() != other.base.data() || this->current != other.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -319,7 +317,7 @@ public:
|
||||||
* @param edges Array of edges to be iterated over.
|
* @param edges Array of edges to be iterated over.
|
||||||
* @param current ID of current edge's end node.
|
* @param current ID of current edge's end node.
|
||||||
*/
|
*/
|
||||||
ConstEdgeIterator(const BaseEdge *edges, NodeID current) :
|
ConstEdgeIterator(span<const BaseEdge> edges, NodeID current) :
|
||||||
BaseEdgeIterator<const BaseEdge, ConstEdge, ConstEdgeIterator>(edges, current) {}
|
BaseEdgeIterator<const BaseEdge, ConstEdge, ConstEdgeIterator>(edges, current) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -334,7 +332,7 @@ public:
|
||||||
* @param edges Array of edges to be iterated over.
|
* @param edges Array of edges to be iterated over.
|
||||||
* @param current ID of current edge's end node.
|
* @param current ID of current edge's end node.
|
||||||
*/
|
*/
|
||||||
EdgeIterator(BaseEdge *edges, NodeID current) :
|
EdgeIterator(span<BaseEdge> edges, NodeID current) :
|
||||||
BaseEdgeIterator<BaseEdge, Edge, EdgeIterator>(edges, current) {}
|
BaseEdgeIterator<BaseEdge, Edge, EdgeIterator>(edges, current) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -342,16 +340,14 @@ public:
|
||||||
* Constant node class. Only retrieval operations are allowed on both the
|
* Constant node class. Only retrieval operations are allowed on both the
|
||||||
* node itself and its edges.
|
* node itself and its edges.
|
||||||
*/
|
*/
|
||||||
class ConstNode : public NodeWrapper<const BaseNode, const BaseEdge> {
|
class ConstNode : public NodeWrapper<const BaseNode> {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param lg LinkGraph to get the node from.
|
* @param lg LinkGraph to get the node from.
|
||||||
* @param node ID of the node.
|
* @param node ID of the node.
|
||||||
*/
|
*/
|
||||||
ConstNode(const LinkGraph *lg, NodeID node) :
|
ConstNode(const LinkGraph *lg, NodeID node) : NodeWrapper<const BaseNode>(lg->nodes[node], node) {}
|
||||||
NodeWrapper<const BaseNode, const BaseEdge>(lg->nodes[node], lg->edges[node], node)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a ConstEdge. This is not a reference as the wrapper objects are
|
* Get a ConstEdge. This is not a reference as the wrapper objects are
|
||||||
|
@ -359,34 +355,32 @@ public:
|
||||||
* @param to ID of end node of edge.
|
* @param to ID of end node of edge.
|
||||||
* @return Constant edge wrapper.
|
* @return Constant edge wrapper.
|
||||||
*/
|
*/
|
||||||
ConstEdge operator[](NodeID to) const { return ConstEdge(this->edges[to]); }
|
ConstEdge operator[](NodeID to) const { return ConstEdge(this->node.edges[to]); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an iterator pointing to the start of the edges array.
|
* Get an iterator pointing to the start of the edges array.
|
||||||
* @return Constant edge iterator.
|
* @return Constant edge iterator.
|
||||||
*/
|
*/
|
||||||
ConstEdgeIterator Begin() const { return ConstEdgeIterator(this->edges, this->index); }
|
ConstEdgeIterator Begin() const { return ConstEdgeIterator(this->node.edges, this->index); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an iterator pointing beyond the end of the edges array.
|
* Get an iterator pointing beyond the end of the edges array.
|
||||||
* @return Constant edge iterator.
|
* @return Constant edge iterator.
|
||||||
*/
|
*/
|
||||||
ConstEdgeIterator End() const { return ConstEdgeIterator(this->edges, INVALID_NODE); }
|
ConstEdgeIterator End() const { return ConstEdgeIterator(this->node.edges, INVALID_NODE); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updatable node class. The node itself as well as its edges can be modified.
|
* Updatable node class. The node itself as well as its edges can be modified.
|
||||||
*/
|
*/
|
||||||
class Node : public NodeWrapper<BaseNode, BaseEdge> {
|
class Node : public NodeWrapper<BaseNode> {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
* @param lg LinkGraph to get the node from.
|
* @param lg LinkGraph to get the node from.
|
||||||
* @param node ID of the node.
|
* @param node ID of the node.
|
||||||
*/
|
*/
|
||||||
Node(LinkGraph *lg, NodeID node) :
|
Node(LinkGraph *lg, NodeID node) : NodeWrapper<BaseNode>(lg->nodes[node], node) {}
|
||||||
NodeWrapper<BaseNode, BaseEdge>(lg->nodes[node], lg->edges[node], node)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an Edge. This is not a reference as the wrapper objects are not
|
* Get an Edge. This is not a reference as the wrapper objects are not
|
||||||
|
@ -394,19 +388,19 @@ public:
|
||||||
* @param to ID of end node of edge.
|
* @param to ID of end node of edge.
|
||||||
* @return Edge wrapper.
|
* @return Edge wrapper.
|
||||||
*/
|
*/
|
||||||
Edge operator[](NodeID to) { return Edge(this->edges[to]); }
|
Edge operator[](NodeID to) { return Edge(this->node.edges[to]); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an iterator pointing to the start of the edges array.
|
* Get an iterator pointing to the start of the edges array.
|
||||||
* @return Edge iterator.
|
* @return Edge iterator.
|
||||||
*/
|
*/
|
||||||
EdgeIterator Begin() { return EdgeIterator(this->edges, this->index); }
|
EdgeIterator Begin() { return EdgeIterator(this->node.edges, this->index); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an iterator pointing beyond the end of the edges array.
|
* Get an iterator pointing beyond the end of the edges array.
|
||||||
* @return Constant edge iterator.
|
* @return Constant edge iterator.
|
||||||
*/
|
*/
|
||||||
EdgeIterator End() { return EdgeIterator(this->edges, INVALID_NODE); }
|
EdgeIterator End() { return EdgeIterator(this->node.edges, INVALID_NODE); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the node's supply and set last_update to the current date.
|
* Update the node's supply and set last_update to the current date.
|
||||||
|
@ -442,7 +436,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<BaseNode> NodeVector;
|
typedef std::vector<BaseNode> NodeVector;
|
||||||
typedef SmallMatrix<BaseEdge> EdgeMatrix;
|
|
||||||
|
|
||||||
/** Minimum effective distance for timeout calculation. */
|
/** Minimum effective distance for timeout calculation. */
|
||||||
static const uint MIN_TIMEOUT_DISTANCE = 32;
|
static const uint MIN_TIMEOUT_DISTANCE = 32;
|
||||||
|
@ -539,11 +532,11 @@ protected:
|
||||||
friend SaveLoadTable GetLinkGraphJobDesc();
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
||||||
friend class SlLinkgraphNode;
|
friend class SlLinkgraphNode;
|
||||||
friend class SlLinkgraphEdge;
|
friend class SlLinkgraphEdge;
|
||||||
|
friend class LinkGraphJob;
|
||||||
|
|
||||||
CargoID cargo; ///< Cargo of this component's link graph.
|
CargoID cargo; ///< Cargo of this component's link graph.
|
||||||
Date last_compression; ///< Last time the capacities and supplies were compressed.
|
Date last_compression; ///< Last time the capacities and supplies were compressed.
|
||||||
NodeVector nodes; ///< Nodes in the component.
|
NodeVector nodes; ///< Nodes in the component.
|
||||||
EdgeMatrix edges; ///< Edges in the component.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* LINKGRAPH_H */
|
#endif /* LINKGRAPH_H */
|
||||||
|
|
|
@ -180,39 +180,12 @@ LinkGraphJob::~LinkGraphJob()
|
||||||
void LinkGraphJob::Init()
|
void LinkGraphJob::Init()
|
||||||
{
|
{
|
||||||
uint size = this->Size();
|
uint size = this->Size();
|
||||||
this->nodes.resize(size);
|
this->nodes.reserve(size);
|
||||||
this->edges.Resize(size, size);
|
|
||||||
for (uint i = 0; i < size; ++i) {
|
for (uint i = 0; i < size; ++i) {
|
||||||
this->nodes[i].Init(this->link_graph[i].Supply());
|
this->nodes.emplace_back(this->link_graph.nodes[i]);
|
||||||
EdgeAnnotation *node_edges = this->edges[i];
|
|
||||||
for (uint j = 0; j < size; ++j) {
|
|
||||||
node_edges[j].Init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize a linkgraph job edge.
|
|
||||||
*/
|
|
||||||
void LinkGraphJob::EdgeAnnotation::Init()
|
|
||||||
{
|
|
||||||
this->demand = 0;
|
|
||||||
this->flow = 0;
|
|
||||||
this->unsatisfied_demand = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize a Linkgraph job node. The underlying memory is expected to be
|
|
||||||
* freshly allocated, without any constructors having been called.
|
|
||||||
* @param supply Initial undelivered supply.
|
|
||||||
*/
|
|
||||||
void LinkGraphJob::NodeAnnotation::Init(uint supply)
|
|
||||||
{
|
|
||||||
this->undelivered_supply = supply;
|
|
||||||
new (&this->flows) FlowStatMap;
|
|
||||||
new (&this->paths) PathList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add this path as a new child to the given base path, thus making this path
|
* Add this path as a new child to the given base path, thus making this path
|
||||||
* a "fork" of the base path.
|
* a "fork" of the base path.
|
||||||
|
|
|
@ -36,7 +36,6 @@ private:
|
||||||
uint demand; ///< Transport demand between the nodes.
|
uint demand; ///< Transport demand between the nodes.
|
||||||
uint unsatisfied_demand; ///< Demand over this edge that hasn't been satisfied yet.
|
uint unsatisfied_demand; ///< Demand over this edge that hasn't been satisfied yet.
|
||||||
uint flow; ///< Planned flow over this edge.
|
uint flow; ///< Planned flow over this edge.
|
||||||
void Init();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,11 +45,16 @@ private:
|
||||||
uint undelivered_supply; ///< Amount of supply that hasn't been distributed yet.
|
uint undelivered_supply; ///< Amount of supply that hasn't been distributed yet.
|
||||||
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back.
|
||||||
FlowStatMap flows; ///< Planned flows to other nodes.
|
FlowStatMap flows; ///< Planned flows to other nodes.
|
||||||
void Init(uint supply);
|
|
||||||
|
std::vector<EdgeAnnotation> edges;
|
||||||
|
|
||||||
|
NodeAnnotation(const LinkGraph::BaseNode &node) : undelivered_supply(node.supply), paths(), flows()
|
||||||
|
{
|
||||||
|
this->edges.resize(node.edges.size());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
typedef std::vector<NodeAnnotation> NodeAnnotationVector;
|
||||||
typedef SmallMatrix<EdgeAnnotation> EdgeAnnotationMatrix;
|
|
||||||
|
|
||||||
friend SaveLoadTable GetLinkGraphJobDesc();
|
friend SaveLoadTable GetLinkGraphJobDesc();
|
||||||
friend class LinkGraphSchedule;
|
friend class LinkGraphSchedule;
|
||||||
|
@ -61,7 +65,6 @@ protected:
|
||||||
std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
|
std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
|
||||||
Date join_date; ///< Date when the job is to be joined.
|
Date join_date; ///< Date when the job is to be joined.
|
||||||
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
||||||
EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation.
|
|
||||||
std::atomic<bool> job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
||||||
std::atomic<bool> job_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
std::atomic<bool> job_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale.
|
||||||
|
|
||||||
|
@ -146,7 +149,7 @@ public:
|
||||||
* Iterator for job edges.
|
* Iterator for job edges.
|
||||||
*/
|
*/
|
||||||
class EdgeIterator : public LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator> {
|
class EdgeIterator : public LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator> {
|
||||||
EdgeAnnotation *base_anno; ///< Array of annotations to be (indirectly) iterated.
|
span<EdgeAnnotation> base_anno; ///< Array of annotations to be (indirectly) iterated.
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -154,10 +157,14 @@ public:
|
||||||
* @param base_anno Array of annotations to be iterated.
|
* @param base_anno Array of annotations to be iterated.
|
||||||
* @param current Start offset of iteration.
|
* @param current Start offset of iteration.
|
||||||
*/
|
*/
|
||||||
EdgeIterator(const LinkGraph::BaseEdge *base, EdgeAnnotation *base_anno, NodeID current) :
|
EdgeIterator(span<const LinkGraph::BaseEdge> base, span<EdgeAnnotation> base_anno, NodeID current) :
|
||||||
LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator>(base, current),
|
LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator>(base, current),
|
||||||
base_anno(base_anno) {}
|
base_anno(base_anno) {}
|
||||||
|
|
||||||
|
EdgeIterator() :
|
||||||
|
LinkGraph::BaseEdgeIterator<const LinkGraph::BaseEdge, Edge, EdgeIterator>(span<const LinkGraph::BaseEdge>(), INVALID_NODE),
|
||||||
|
base_anno() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dereference.
|
* Dereference.
|
||||||
* @return Pair of the edge currently pointed to and the ID of its
|
* @return Pair of the edge currently pointed to and the ID of its
|
||||||
|
@ -184,8 +191,8 @@ public:
|
||||||
*/
|
*/
|
||||||
class Node : public LinkGraph::ConstNode {
|
class Node : public LinkGraph::ConstNode {
|
||||||
private:
|
private:
|
||||||
NodeAnnotation &node_anno; ///< Annotation being wrapped.
|
NodeAnnotation &node_anno; ///< Annotation being wrapped.
|
||||||
EdgeAnnotation *edge_annos; ///< Edge annotations belonging to this node.
|
span<EdgeAnnotation> edge_annos; ///< Edge annotations belonging to this node.
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,7 +202,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Node (LinkGraphJob *lgj, NodeID node) :
|
Node (LinkGraphJob *lgj, NodeID node) :
|
||||||
LinkGraph::ConstNode(&lgj->link_graph, node),
|
LinkGraph::ConstNode(&lgj->link_graph, node),
|
||||||
node_anno(lgj->nodes[node]), edge_annos(lgj->edges[node])
|
node_anno(lgj->nodes[node]), edge_annos(lgj->nodes[node].edges)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -204,21 +211,21 @@ public:
|
||||||
* @param to Remote end of the edge.
|
* @param to Remote end of the edge.
|
||||||
* @return Edge between this node and "to".
|
* @return Edge between this node and "to".
|
||||||
*/
|
*/
|
||||||
Edge operator[](NodeID to) const { return Edge(this->edges[to], this->edge_annos[to]); }
|
Edge operator[](NodeID to) const { return Edge(this->node.edges[to], this->edge_annos[to]); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator for the "begin" of the edge array. Only edges with capacity
|
* Iterator for the "begin" of the edge array. Only edges with capacity
|
||||||
* are iterated. The others are skipped.
|
* are iterated. The others are skipped.
|
||||||
* @return Iterator pointing to the first edge.
|
* @return Iterator pointing to the first edge.
|
||||||
*/
|
*/
|
||||||
EdgeIterator Begin() const { return EdgeIterator(this->edges, this->edge_annos, index); }
|
EdgeIterator Begin() const { return EdgeIterator(this->node.edges, this->edge_annos, index); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator for the "end" of the edge array. Only edges with capacity
|
* Iterator for the "end" of the edge array. Only edges with capacity
|
||||||
* are iterated. The others are skipped.
|
* are iterated. The others are skipped.
|
||||||
* @return Iterator pointing beyond the last edge.
|
* @return Iterator pointing beyond the last edge.
|
||||||
*/
|
*/
|
||||||
EdgeIterator End() const { return EdgeIterator(this->edges, this->edge_annos, INVALID_NODE); }
|
EdgeIterator End() const { return EdgeIterator(this->node.edges, this->edge_annos, INVALID_NODE); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get amount of supply that hasn't been delivered, yet.
|
* Get amount of supply that hasn't been delivered, yet.
|
||||||
|
|
|
@ -103,9 +103,7 @@ public:
|
||||||
* Construct a GraphEdgeIterator.
|
* Construct a GraphEdgeIterator.
|
||||||
* @param job Job to iterate on.
|
* @param job Job to iterate on.
|
||||||
*/
|
*/
|
||||||
GraphEdgeIterator(LinkGraphJob &job) : job(job),
|
GraphEdgeIterator(LinkGraphJob &job) : job(job), i(), end() {}
|
||||||
i(nullptr, nullptr, INVALID_NODE), end(nullptr, nullptr, INVALID_NODE)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the node to start iterating at.
|
* Setup the node to start iterating at.
|
||||||
|
|
|
@ -43,24 +43,25 @@ public:
|
||||||
void Save(Node *bn) const override
|
void Save(Node *bn) const override
|
||||||
{
|
{
|
||||||
uint16 size = 0;
|
uint16 size = 0;
|
||||||
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
|
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->nodes[_linkgraph_from].edges[to].next_edge) {
|
||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
SlSetStructListLength(size);
|
SlSetStructListLength(size);
|
||||||
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
|
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->nodes[_linkgraph_from].edges[to].next_edge) {
|
||||||
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetDescription());
|
SlObject(&_linkgraph->nodes[_linkgraph_from].edges[to], this->GetDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Load(Node *bn) const override
|
void Load(Node *bn) const override
|
||||||
{
|
{
|
||||||
uint16 max_size = _linkgraph->Size();
|
uint16 max_size = _linkgraph->Size();
|
||||||
|
_linkgraph->nodes[_linkgraph_from].edges.resize(max_size);
|
||||||
|
|
||||||
if (IsSavegameVersionBefore(SLV_191)) {
|
if (IsSavegameVersionBefore(SLV_191)) {
|
||||||
/* We used to save the full matrix ... */
|
/* We used to save the full matrix ... */
|
||||||
for (NodeID to = 0; to < max_size; ++to) {
|
for (NodeID to = 0; to < max_size; ++to) {
|
||||||
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetLoadDescription());
|
SlObject(&_linkgraph->nodes[_linkgraph_from].edges[to], this->GetLoadDescription());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -68,12 +69,12 @@ public:
|
||||||
size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
|
size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
|
||||||
|
|
||||||
/* ... but as that wasted a lot of space we save a sparse matrix now. */
|
/* ... but as that wasted a lot of space we save a sparse matrix now. */
|
||||||
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->edges[_linkgraph_from][to].next_edge) {
|
for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _linkgraph->nodes[_linkgraph_from].edges[to].next_edge) {
|
||||||
if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
|
if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
|
||||||
used_size--;
|
used_size--;
|
||||||
|
|
||||||
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
|
if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
|
||||||
SlObject(&_linkgraph->edges[_linkgraph_from][to], this->GetLoadDescription());
|
SlObject(&_linkgraph->nodes[_linkgraph_from].edges[to], this->GetLoadDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
|
if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
|
||||||
|
|
Loading…
Reference in New Issue