FlowStatMap: Replace RB-tree with btree-indexed vector

pull/104/head
Jonathan G Rennison 5 years ago
parent 0a1c1809ab
commit 90550d9642

@ -660,7 +660,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
if (flow_it == ge->flows.end()) {
cargo_next = INVALID_STATION;
} else {
FlowStat new_shares = flow_it->second;
FlowStat new_shares = *flow_it;
new_shares.ChangeShare(current_station, INT_MIN);
StationIDStack excluded = next_station;
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
@ -676,20 +676,20 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
/* Rewrite an invalid source station to some random other one to
* avoid keeping the cargo in the vehicle forever. */
if (cp->source == INVALID_STATION && !ge->flows.empty()) {
cp->source = ge->flows.begin()->first;
cp->source = ge->flows.FirstStationID();
}
bool restricted = false;
FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source));
if (flow_it == ge->flows.end()) {
cargo_next = INVALID_STATION;
} else {
cargo_next = flow_it->second.GetViaWithRestricted(restricted);
cargo_next = flow_it->GetViaWithRestricted(restricted);
}
action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station);
if (restricted && action == MTA_TRANSFER) {
/* If the flow is restricted we can't transfer to it. Choose an
* unrestricted one instead. */
cargo_next = flow_it->second.GetVia();
cargo_next = flow_it->GetVia();
action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station);
}
}

@ -57,7 +57,7 @@ void FlowMapper::Run(LinkGraphJob &job) const
* LinkGraph::Monthly(). */
uint runtime = (job.StartDateTicks() / DAY_TICKS) - job.LastCompression() + 1;
for (FlowStatMap::iterator i = flows.begin(); i != flows.end(); ++i) {
i->second.ScaleToMonthly(runtime);
i->ScaleToMonthly(runtime);
}
}
/* Clear paths. */

@ -146,27 +146,30 @@ void LinkGraphJob::FinaliseJob()
* somewhere. Do delete them and also reroute relevant cargo if
* automatic distribution has been turned off for that cargo. */
for (FlowStatMap::iterator it(ge.flows.begin()); it != ge.flows.end();) {
FlowStatMap::iterator new_it = flows.find(it->first);
FlowStatMap::iterator new_it = flows.find(it->GetOrigin());
if (new_it == flows.end()) {
if (_settings_game.linkgraph.GetDistributionType(this->Cargo()) != DT_MANUAL) {
it->second.Invalidate();
it->Invalidate();
++it;
} else {
FlowStat shares(INVALID_STATION, 1);
it->second.SwapShares(shares);
ge.flows.erase(it++);
FlowStat shares(INVALID_STATION, INVALID_STATION, 1);
it->SwapShares(shares);
it = ge.flows.erase(it);
for (FlowStat::SharesMap::const_iterator shares_it(shares.GetShares()->begin());
shares_it != shares.GetShares()->end(); ++shares_it) {
RerouteCargo(st, this->Cargo(), shares_it->second, st->index);
}
}
} else {
it->second.SwapShares(new_it->second);
it->SwapShares(*new_it);
flows.erase(new_it);
++it;
}
}
ge.flows.insert(flows.begin(), flows.end());
for (FlowStatMap::iterator it(flows.begin()); it != flows.end(); ++it) {
ge.flows.insert(std::move(*it));
}
ge.flows.SortStorage();
InvalidateWindowData(WC_STATION_VIEW, st->index, this->Cargo());
}
}

@ -187,8 +187,8 @@ public:
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();
this->it = it->GetShares()->begin();
this->end = it->GetShares()->end();
} else {
this->it = FlowStat::empty_sharesmap.begin();
this->end = FlowStat::empty_sharesmap.end();

@ -523,18 +523,18 @@ static void RealSave_STNN(BaseStation *bst)
_num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize();
_num_flows = 0;
for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) {
_num_flows += (uint32)it->second.GetShares()->size();
_num_flows += (uint32)it->GetShares()->size();
}
SlObjectSaveFiltered(&st->goods[i], _filtered_goods_desc.data());
for (FlowStatMap::const_iterator outer_it(st->goods[i].flows.begin()); outer_it != st->goods[i].flows.end(); ++outer_it) {
const FlowStat::SharesMap *shares = outer_it->second.GetShares();
const FlowStat::SharesMap *shares = outer_it->GetShares();
uint32 sum_shares = 0;
FlowSaveLoad flow;
flow.source = outer_it->first;
flow.source = outer_it->GetOrigin();
for (FlowStat::SharesMap::const_iterator inner_it(shares->begin()); inner_it != shares->end(); ++inner_it) {
flow.via = inner_it->second;
flow.share = inner_it->first - sum_shares;
flow.restricted = inner_it->first > outer_it->second.GetUnrestricted();
flow.restricted = inner_it->first > outer_it->GetUnrestricted();
sum_shares = inner_it->first;
assert(flow.share > 0);
@ -610,7 +610,7 @@ static void Load_STNN()
if (!IsSavegameVersionBefore(SLV_187)) flow.restricted = (buffer->ReadByte() != 0);
if (fs == nullptr || prev_source != flow.source) {
fs = &(st->goods[i].flows.insert(st->goods[i].flows.end(), std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted)))->second);
fs = &(*(st->goods[i].flows.insert(st->goods[i].flows.end(), FlowStat(flow.source, flow.via, flow.share, flow.restricted))));
} else {
fs->AppendShare(flow.via, flow.share, flow.restricted);
}

@ -195,11 +195,11 @@ void ScriptStationList_CargoPlanned::Add(StationID station_id, CargoID cargo, St
FlowStatMap::const_iterator iter = collector.GE()->flows.begin();
FlowStatMap::const_iterator end = collector.GE()->flows.end();
for (; iter != end; ++iter) {
const FlowStat::SharesMap *shares = iter->second.GetShares();
const FlowStat::SharesMap *shares = iter->GetShares();
uint prev = 0;
for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin();
flow_iter != shares->end(); ++flow_iter) {
collector.Update<Tselector>(iter->first, flow_iter->second, flow_iter->first - prev);
collector.Update<Tselector>(iter->GetOrigin(), flow_iter->second, flow_iter->first - prev);
prev = flow_iter->first;
}
}
@ -265,11 +265,11 @@ ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia
FlowStatMap::const_iterator iter = collector.GE()->flows.find(from);
if (iter == collector.GE()->flows.end()) return;
const FlowStat::SharesMap *shares = iter->second.GetShares();
const FlowStat::SharesMap *shares = iter->GetShares();
uint prev = 0;
for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin();
flow_iter != shares->end(); ++flow_iter) {
collector.Update<CS_FROM_BY_VIA>(iter->first, flow_iter->second, flow_iter->first - prev);
collector.Update<CS_FROM_BY_VIA>(iter->GetOrigin(), flow_iter->second, flow_iter->first - prev);
prev = flow_iter->first;
}
}

@ -24,12 +24,16 @@
#include "bitmap_type.h"
#include <map>
#include <vector>
#include <iterator>
#include <functional>
typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
extern StationPool _station_pool;
static const byte INITIAL_STATION_RATING = 175;
class FlowStatMap;
/**
* Flow statistics telling how much flow should be sent along a link. This is
* done by creating "flow shares" and using std::map's upper_bound() method to
@ -38,6 +42,7 @@ static const byte INITIAL_STATION_RATING = 175;
* mean anything by itself.
*/
class FlowStat {
friend FlowStatMap;
public:
typedef btree::btree_map<uint32, StationID> SharesMap;
@ -52,15 +57,17 @@ public:
/**
* Create a FlowStat with an initial entry.
* @param st Station the initial entry refers to.
* @param origin Origin station for this flow.
* @param via Station the initial entry refers to.
* @param flow Amount of flow for the initial entry.
* @param restricted If the flow to be added is restricted.
*/
inline FlowStat(StationID st, uint flow, bool restricted = false)
inline FlowStat(StationID origin, StationID via, uint flow, bool restricted = false)
{
assert(flow > 0);
this->shares[flow] = st;
this->shares[flow] = via;
this->unrestricted = restricted ? 0 : flow;
this->origin = origin;
}
/**
@ -148,14 +155,66 @@ public:
void Invalidate();
inline StationID GetOrigin() const
{
return this->origin;
}
private:
SharesMap shares; ///< Shares of flow to be sent via specified station (or consumed locally).
uint unrestricted; ///< Limit for unrestricted shares.
StationID origin;
};
static_assert(std::is_nothrow_move_constructible<FlowStat>::value, "FlowStat must be nothrow move constructible");
template<typename cv_value, typename cv_container, typename cv_index_iter>
class FlowStatMapIterator
{
friend FlowStatMap;
friend FlowStatMapIterator<FlowStat, FlowStatMap, btree::btree_map<StationID, uint16>::iterator>;
friend FlowStatMapIterator<const FlowStat, const FlowStatMap, btree::btree_map<StationID, uint16>::const_iterator>;
public:
typedef FlowStat value_type;
typedef cv_value& reference;
typedef cv_value* pointer;
typedef ptrdiff_t difference_type;
typedef std::forward_iterator_tag iterator_category;
FlowStatMapIterator(cv_container *fsm, cv_index_iter current) :
fsm(fsm), current(current) {}
FlowStatMapIterator(const FlowStatMapIterator<FlowStat, FlowStatMap, btree::btree_map<StationID, uint16>::iterator> &other) :
fsm(other.fsm), current(other.current) {}
reference operator*() const { return this->fsm->flows_storage[this->current->second]; }
pointer operator->() const { return &(this->fsm->flows_storage[this->current->second]); }
FlowStatMapIterator& operator++()
{
++this->current;
return *this;
}
bool operator==(const FlowStatMapIterator& rhs) const { return this->current == rhs.current; }
bool operator!=(const FlowStatMapIterator& rhs) const { return !(operator==(rhs)); }
private:
cv_container *fsm;
cv_index_iter current;
};
/** Flow descriptions by origin stations. */
class FlowStatMap : public std::map<StationID, FlowStat> {
class FlowStatMap {
std::vector<FlowStat> flows_storage;
btree::btree_map<StationID, uint16> flows_index;
public:
using iterator = FlowStatMapIterator<FlowStat, FlowStatMap, btree::btree_map<StationID, uint16>::iterator>;
using const_iterator = FlowStatMapIterator<const FlowStat, const FlowStatMap, btree::btree_map<StationID, uint16>::const_iterator>;
friend iterator;
friend const_iterator;
uint GetFlow() const;
uint GetFlowVia(StationID via) const;
uint GetFlowFrom(StationID from) const;
@ -167,6 +226,78 @@ public:
void RestrictFlows(StationID via);
void ReleaseFlows(StationID via);
void FinalizeLocalConsumption(StationID self);
private:
btree::btree_map<StationID, uint16>::iterator erase_priv(btree::btree_map<StationID, uint16>::iterator iter)
{
uint16 index = iter->second;
iter = this->flows_index.erase(iter);
if (index != this->flows_storage.size() - 1) {
this->flows_storage[index] = std::move(this->flows_storage.back());
this->flows_index[this->flows_storage[index].GetOrigin()] = index;
}
this->flows_storage.pop_back();
return iter;
}
public:
iterator begin() { return iterator(this, this->flows_index.begin()); }
const_iterator begin() const { return const_iterator(this, this->flows_index.begin()); }
iterator end() { return iterator(this, this->flows_index.end()); }
const_iterator end() const { return const_iterator(this, this->flows_index.end()); }
iterator find(StationID from)
{
return iterator(this, this->flows_index.find(from));
}
const_iterator find(StationID from) const
{
return const_iterator(this, this->flows_index.find(from));
}
bool empty() const
{
return this->flows_index.empty();
}
void erase(StationID st)
{
auto iter = this->flows_index.find(st);
if (iter != this->flows_index.end()) {
this->erase_priv(iter);
}
}
iterator erase(iterator iter)
{
return iterator(this, this->erase_priv(iter.current));
}
std::pair<iterator, bool> insert(FlowStat flow_stat)
{
StationID st = flow_stat.GetOrigin();
auto res = this->flows_index.insert(std::pair<StationID, uint16>(st, this->flows_storage.size()));
if (res.second) {
this->flows_storage.push_back(std::move(flow_stat));
}
return std::make_pair(iterator(this, res.first), res.second);
}
iterator insert(iterator hint, FlowStat flow_stat)
{
auto res = this->flows_index.insert(hint.current, std::pair<StationID, uint16>(flow_stat.GetOrigin(), this->flows_storage.size()));
if (res->second == this->flows_storage.size()) {
this->flows_storage.push_back(std::move(flow_stat));
}
return iterator(this, res);
}
StationID FirstStationID() const
{
return this->flows_index.begin()->first;
}
void SortStorage();
};
/**
@ -291,7 +422,7 @@ struct GoodsEntry {
inline StationID GetVia(StationID source) const
{
FlowStatMap::const_iterator flow_it(this->flows.find(source));
return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION;
return flow_it != this->flows.end() ? flow_it->GetVia() : INVALID_STATION;
}
/**
@ -305,7 +436,7 @@ struct GoodsEntry {
inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const
{
FlowStatMap::const_iterator flow_it(this->flows.find(source));
return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION;
return flow_it != this->flows.end() ? flow_it->GetVia(excluded, excluded2) : INVALID_STATION;
}
};

@ -4866,10 +4866,10 @@ void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow)
{
FlowStatMap::iterator origin_it = this->find(origin);
if (origin_it == this->end()) {
this->insert(std::make_pair(origin, FlowStat(via, flow)));
this->insert(FlowStat(origin, via, flow));
} else {
origin_it->second.ChangeShare(via, flow);
assert(!origin_it->second.GetShares()->empty());
origin_it->ChangeShare(via, flow);
assert(!origin_it->GetShares()->empty());
}
}
@ -4885,13 +4885,13 @@ void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
{
FlowStatMap::iterator prev_it = this->find(origin);
if (prev_it == this->end()) {
FlowStat fs(via, flow);
FlowStat fs(origin, via, flow);
fs.AppendShare(INVALID_STATION, flow);
this->insert(std::make_pair(origin, fs));
this->insert(std::move(fs));
} else {
prev_it->second.ChangeShare(via, flow);
prev_it->second.ChangeShare(INVALID_STATION, flow);
assert(!prev_it->second.GetShares()->empty());
prev_it->ChangeShare(via, flow);
prev_it->ChangeShare(INVALID_STATION, flow);
assert(!prev_it->GetShares()->empty());
}
}
@ -4902,7 +4902,7 @@ void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow)
void FlowStatMap::FinalizeLocalConsumption(StationID self)
{
for (FlowStatMap::iterator i = this->begin(); i != this->end(); ++i) {
FlowStat &fs = i->second;
FlowStat &fs = *i;
uint local = fs.GetShare(INVALID_STATION);
if (local > INT_MAX) { // make sure it fits in an int
fs.ChangeShare(self, -INT_MAX);
@ -4928,11 +4928,11 @@ StationIDStack FlowStatMap::DeleteFlows(StationID via)
{
StationIDStack ret;
for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
FlowStat &s_flows = f_it->second;
FlowStat &s_flows = *f_it;
s_flows.ChangeShare(via, INT_MIN);
if (s_flows.GetShares()->empty()) {
ret.Push(f_it->first);
this->erase(f_it++);
ret.Push(f_it->GetOrigin());
f_it = this->erase(f_it);
} else {
++f_it;
}
@ -4947,7 +4947,7 @@ StationIDStack FlowStatMap::DeleteFlows(StationID via)
void FlowStatMap::RestrictFlows(StationID via)
{
for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
it->second.RestrictShare(via);
it->RestrictShare(via);
}
}
@ -4958,7 +4958,7 @@ void FlowStatMap::RestrictFlows(StationID via)
void FlowStatMap::ReleaseFlows(StationID via)
{
for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) {
it->second.ReleaseShare(via);
it->ReleaseShare(via);
}
}
@ -4970,7 +4970,7 @@ uint FlowStatMap::GetFlow() const
{
uint ret = 0;
for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
ret += (--(i->second.GetShares()->end()))->first;
ret += (--(i->GetShares()->end()))->first;
}
return ret;
}
@ -4984,7 +4984,7 @@ uint FlowStatMap::GetFlowVia(StationID via) const
{
uint ret = 0;
for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) {
ret += i->second.GetShare(via);
ret += i->GetShare(via);
}
return ret;
}
@ -4998,7 +4998,7 @@ uint FlowStatMap::GetFlowFrom(StationID from) const
{
FlowStatMap::const_iterator i = this->find(from);
if (i == this->end()) return 0;
return (--(i->second.GetShares()->end()))->first;
return (--(i->GetShares()->end()))->first;
}
/**
@ -5011,7 +5011,20 @@ uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const
{
FlowStatMap::const_iterator i = this->find(from);
if (i == this->end()) return 0;
return i->second.GetShare(via);
return i->GetShare(via);
}
void FlowStatMap::SortStorage()
{
assert(this->flows_storage.size() == this->flows_index.size());
std::sort(this->flows_storage.begin(), this->flows_storage.end(), [](const FlowStat &a, const FlowStat &b) -> bool {
return a.origin < b.origin;
});
uint16 index = 0;
for (auto &it : this->flows_index) {
it.second = index;
index++;
}
}
extern const TileTypeProcs _tile_type_station_procs = {

@ -1513,9 +1513,9 @@ struct StationViewWindow : public Window {
const FlowStatMap &flows = st->goods[i].flows;
for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
StationID from = it->first;
StationID from = it->GetOrigin();
CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from);
const FlowStat::SharesMap *shares = it->second.GetShares();
const FlowStat::SharesMap *shares = it->GetShares();
uint32 prev_count = 0;
for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
StationID via = flow_it->second;
@ -1546,7 +1546,7 @@ struct StationViewWindow : public Window {
const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows;
FlowStatMap::const_iterator map_it = flowmap.find(source);
if (map_it != flowmap.end()) {
const FlowStat::SharesMap *shares = map_it->second.GetShares();
const FlowStat::SharesMap *shares = map_it->GetShares();
uint32 prev_count = 0;
for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) {
tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count);
@ -1596,9 +1596,9 @@ struct StationViewWindow : public Window {
{
const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i);
for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) {
StationID from = it->first;
StationID from = it->GetOrigin();
const CargoDataEntry *source_entry = source_dest->Retrieve(from);
const FlowStat::SharesMap *shares = it->second.GetShares();
const FlowStat::SharesMap *shares = it->GetShares();
for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) {
const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second);
for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) {

Loading…
Cancel
Save