@@ -105,13 +105,13 @@ static int32 ClickChangeDateCheat(int32
ConvertDateToYMD(_date, &ymd);
p1 = Clamp(p1, MIN_YEAR, MAX_YEAR);
if (p1 == _cur_year) return _cur_year;
Date new_date = ConvertYMDToDate(p1, ymd.month, ymd.day);
LinkGraphSchedule::Instance()->ShiftDates(new_date - _date);
LinkGraphSchedule::instance.ShiftDates(new_date - _date);
SetDate(new_date, _date_fract);
EnginesMonthlyLoop();
SetWindowDirty(WC_STATUS_BAR, 0);
InvalidateWindowClassesData(WC_BUILD_STATION, 0);
InvalidateWindowClassesData(WC_BUILD_OBJECT, 0);
ResetSignalVariant();
@@ -19,12 +19,19 @@
/* Initialize the link-graph-job-pool */
LinkGraphJobPool _link_graph_job_pool("LinkGraphJob");
INSTANTIATE_POOL_METHODS(LinkGraphJob)
/**
* Static instance of an invalid path.
* Note: This instance is created on task start.
* Lazy creation on first usage results in a data race between the CDist threads.
*/
/* static */ Path *Path::invalid_path = new Path(INVALID_NODE, true);
* Create a link graph job from a link graph. The link graph will be copied so
* that the calculations don't interfer with the normal operations on the
* original. The job is immediately started.
* @param orig Original LinkGraph to be copied.
LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
@@ -340,12 +340,14 @@ public:
* A leg of a path in the link graph. Paths can form trees by being "forked".
class Path {
public:
static Path *invalid_path;
Path(NodeID n, bool source = false);
/** Get the node this leg passes. */
inline NodeID GetNode() const { return this->node; }
/** Get the overall origin of the path. */
@@ -16,12 +16,19 @@
#include "mcf.h"
#include "flowmapper.h"
#include "../safeguards.h"
* Static instance of LinkGraphSchedule.
/* static */ LinkGraphSchedule LinkGraphSchedule::instance;
* Start the next job in the schedule.
void LinkGraphSchedule::SpawnNext()
{
if (this->schedule.empty()) return;
LinkGraph *next = this->schedule.front();
@@ -65,15 +72,14 @@ void LinkGraphSchedule::JoinNext()
* ThreadObject::New.
* @param j Pointer to a link graph job.
/* static */ void LinkGraphSchedule::Run(void *j)
LinkGraphJob *job = (LinkGraphJob *)j;
LinkGraphSchedule *schedule = LinkGraphSchedule::Instance();
for (uint i = 0; i < lengthof(schedule->handlers); ++i) {
schedule->handlers[i]->Run(*job);
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
instance.handlers[i]->Run(*job);
}
* Start all threads in the running list. This is only useful for save/load.
* Usually threads are started when the job is created.
@@ -87,18 +93,17 @@ void LinkGraphSchedule::SpawnAll()
* Clear all link graphs and jobs from the schedule.
/* static */ void LinkGraphSchedule::Clear()
LinkGraphSchedule *inst = LinkGraphSchedule::Instance();
for (JobList::iterator i(inst->running.begin()); i != inst->running.end(); ++i) {
for (JobList::iterator i(instance.running.begin()); i != instance.running.end(); ++i) {
(*i)->JoinThread();
inst->running.clear();
inst->schedule.clear();
instance.running.clear();
instance.schedule.clear();
* Shift all dates (join dates and edge annotations) of link graphs and link
* graph jobs by the number of days given.
* @param interval Number of days to be added or subtracted.
@@ -133,30 +138,21 @@ LinkGraphSchedule::~LinkGraphSchedule()
for (uint i = 0; i < lengthof(this->handlers); ++i) {
delete this->handlers[i];
* Retrieve the link graph schedule or create it if necessary.
/* static */ LinkGraphSchedule *LinkGraphSchedule::Instance()
static LinkGraphSchedule inst;
return &inst;
* Spawn or join a link graph job or compress a link graph if any link graph is
* due to do so.
void OnTick_LinkGraph()
if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
Date offset = _date % _settings_game.linkgraph.recalc_interval;
if (offset == 0) {
LinkGraphSchedule::Instance()->SpawnNext();
LinkGraphSchedule::instance.SpawnNext();
} else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
LinkGraphSchedule::Instance()->JoinNext();
LinkGraphSchedule::instance.JoinNext();
@@ -48,14 +48,14 @@ protected:
GraphList schedule; ///< Queue for new jobs.
JobList running; ///< Currently running jobs.
/* This is a tick where not much else is happening, so a small lag might go unnoticed. */
static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day.
static LinkGraphSchedule instance;
static LinkGraphSchedule *Instance();
static void Run(void *j);
static void Clear();
void SpawnNext();
void JoinNext();
void SpawnAll();
@@ -145,21 +145,20 @@ public:
* Setup the node to retrieve edges from.
* @param source Root of the current path tree.
* @param node Current node to be checked for outgoing flows.
void SetNode(NodeID source, NodeID node)
static const FlowStat::SharesMap empty;
const FlowStatMap &flows = this->job[node].Flows();
FlowStatMap::const_iterator it = flows.find(this->job[source].Station());
if (it != flows.end()) {
this->it = it->second.GetShares()->begin();
this->end = it->second.GetShares()->end();
} else {
this->it = empty.begin();
this->end = empty.end();
this->it = FlowStat::empty_sharesmap.begin();
this->end = FlowStat::empty_sharesmap.end();
* Get the next node for which a flow exists.
* @return ID of next node with flow.
@@ -376,17 +375,16 @@ void MCF1stPass::EliminateCycle(PathVect
* @param origin_id Origin of the paths to be checked.
* @param next_id Next node to be checked.
* @return If any cycles have been found and eliminated.
bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id)
static Path *invalid_path = new Path(INVALID_NODE, true);
Path *at_next_pos = path[next_id];
/* this node has already been searched */
if (at_next_pos == invalid_path) return false;
if (at_next_pos == Path::invalid_path) return false;
if (at_next_pos == NULL) {
/* Summarize paths; add up the paths with the same source and next hop
* in one path each. */
PathList &paths = this->job[next_id].Paths();
PathViaMap next_hops;
@@ -428,13 +426,13 @@ bool MCF1stPass::EliminateCycles(PathVec
/* All paths departing from this node have been searched. Mark as
* resolved if no cycles found. If cycles were found further cycles
* could be found in this branch, thus it has to be searched again next
* time we spot it.
path[next_id] = found ? NULL : invalid_path;
path[next_id] = found ? NULL : Path::invalid_path;
return found;
/* This node has already been visited => we have a cycle.
* Backtrack to find the exact flow. */
uint flow = this->FindCycleFlow(path, at_next_pos);
@@ -217,13 +217,13 @@ static void Load_LGRJ()
* Load the link graph schedule.
static void Load_LGRS()
SlObject(LinkGraphSchedule::Instance(), GetLinkGraphScheduleDesc());
SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc());
* Spawn the threads for running link graph calculations.
* Has to be done after loading as the cargo classes might have changed.
@@ -243,13 +243,13 @@ void AfterLoadLinkGraphs()
for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
(*lg)[node_id].UpdateLocation(Station::Get((*lg)[node_id].Station())->xy);
LinkGraphSchedule::Instance()->SpawnAll();
LinkGraphSchedule::instance.SpawnAll();
* Save all link graphs.
static void Save_LGRP()
@@ -275,21 +275,21 @@ static void Save_LGRJ()
* Save the link graph schedule.
static void Save_LGRS()
* Substitute pointers in link graph schedule.
static void Ptrs_LGRS()
extern const ChunkHandler _linkgraph_chunk_handlers[] = {
{ 'LGRP', Save_LGRP, Load_LGRP, NULL, NULL, CH_ARRAY },
{ 'LGRJ', Save_LGRJ, Load_LGRJ, NULL, NULL, CH_ARRAY },
{ 'LGRS', Save_LGRS, Load_LGRS, Ptrs_LGRS, NULL, CH_LAST }
@@ -103,13 +103,13 @@ Station::~Station()
st->goods[c].flows.DeleteFlows(this->index);
RerouteCargo(st, c, this->index, st->index);
lg->RemoveNode(this->goods[c].node);
if (lg->Size() == 0) {
LinkGraphSchedule::Instance()->Unqueue(lg);
LinkGraphSchedule::instance.Unqueue(lg);
delete lg;
Vehicle *v;
FOR_ALL_VEHICLES(v) {
@@ -34,12 +34,14 @@ static const byte INITIAL_STATION_RATING
* mean anything by itself.
class FlowStat {
typedef std::map<uint32, StationID> SharesMap;
static const SharesMap empty_sharesmap;
* Invalid constructor. This can't be called as a FlowStat must not be
* empty. However, the constructor must be defined and reachable for
* FlwoStat to be used in a std::map.
inline FlowStat() {NOT_REACHED();}
@@ -56,12 +56,19 @@
#include "table/strings.h"
#include "safeguards.h"
* Static instance of FlowStat::SharesMap.
/* static */ const FlowStat::SharesMap FlowStat::empty_sharesmap;
* Check whether the given tile is a hangar.
* @param t the tile to of whether it is a hangar.
* @pre IsTileType(t, MP_STATION)
* @return true if and only if the tile is a hangar.
bool IsHangar(TileIndex t)
@@ -3533,13 +3540,13 @@ void IncreaseStats(Station *st, CargoID
GoodsEntry &ge2 = st2->goods[cargo];
LinkGraph *lg = NULL;
if (ge1.link_graph == INVALID_LINK_GRAPH) {
if (ge2.link_graph == INVALID_LINK_GRAPH) {
if (LinkGraph::CanAllocateItem()) {
lg = new LinkGraph(cargo);
LinkGraphSchedule::Instance()->Queue(lg);
LinkGraphSchedule::instance.Queue(lg);
ge2.link_graph = lg->index;
ge2.node = lg->AddNode(st2);
DEBUG(misc, 0, "Can't allocate link graph");
@@ -3555,17 +3562,17 @@ void IncreaseStats(Station *st, CargoID
lg = LinkGraph::Get(ge1.link_graph);
if (ge1.link_graph != ge2.link_graph) {
LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph);
if (lg->Size() < lg2->Size()) {
lg2->Merge(lg); // Updates GoodsEntries of lg
lg = lg2;
LinkGraphSchedule::Instance()->Unqueue(lg2);
LinkGraphSchedule::instance.Unqueue(lg2);
lg->Merge(lg2); // Updates GoodsEntries of lg2
if (lg != NULL) {
(*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode);
@@ -3681,13 +3688,13 @@ static uint UpdateStationWaiting(Station
StationID next = ge.GetVia(st->index);
ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next);
if (ge.link_graph == INVALID_LINK_GRAPH) {
lg = new LinkGraph(type);
ge.link_graph = lg->index;
ge.node = lg->AddNode(st);
@@ -1122,13 +1122,13 @@ void ToggleDirtyBlocks()
void SetStartingYear(Year year)
_settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
/* If you open a savegame as scenario there may already be link graphs.*/
SetDate(new_date, 0);
* Choose the proper callback function for the main toolbar's help menu.
* @param index The menu index which was selected.
Status change: