FlowStatMap: Replace RB-tree with btree-indexed vector

This commit is contained in:
Jonathan G Rennison
2019-09-28 04:20:01 +01:00
parent 0a1c1809ab
commit 90550d9642
9 changed files with 199 additions and 52 deletions

View File

@@ -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;
}
};