mirror of
https://github.com/OpenTTD/OpenTTD
synced 2026-01-26 21:54:22 +01:00
Codechange: Remove StationIDStack and SmallStack.
Use a std::vector or std::span instead.
This commit is contained in:
committed by
Peter Nelson
parent
5c89dff677
commit
fd32d1447e
@@ -135,7 +135,8 @@ static StationID FindNearestHangar(const Aircraft *v)
|
|||||||
next_dest = Station::GetIfValid(v->current_order.GetDestination().ToStationID());
|
next_dest = Station::GetIfValid(v->current_order.GetDestination().ToStationID());
|
||||||
} else {
|
} else {
|
||||||
last_dest = GetTargetAirportIfValid(v);
|
last_dest = GetTargetAirportIfValid(v);
|
||||||
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
|
std::vector<StationID> next_station = v->GetNextStoppingStation();
|
||||||
|
if (!next_station.empty()) next_dest = Station::GetIfValid(next_station.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -404,13 +404,13 @@ void VehicleCargoList::AgeCargo()
|
|||||||
* @return MoveToAction to be performed.
|
* @return MoveToAction to be performed.
|
||||||
*/
|
*/
|
||||||
/* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next,
|
/* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next,
|
||||||
StationID current_station, bool accepted, StationIDStack next_station)
|
StationID current_station, bool accepted, std::span<const StationID> next_station)
|
||||||
{
|
{
|
||||||
if (cargo_next == StationID::Invalid()) {
|
if (cargo_next == StationID::Invalid()) {
|
||||||
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
|
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
|
||||||
} else if (cargo_next == current_station) {
|
} else if (cargo_next == current_station) {
|
||||||
return MTA_DELIVER;
|
return MTA_DELIVER;
|
||||||
} else if (next_station.Contains(cargo_next)) {
|
} else if (std::ranges::find(next_station, cargo_next) != std::end(next_station)) {
|
||||||
return MTA_KEEP;
|
return MTA_KEEP;
|
||||||
} else {
|
} else {
|
||||||
return MTA_TRANSFER;
|
return MTA_TRANSFER;
|
||||||
@@ -432,7 +432,7 @@ void VehicleCargoList::AgeCargo()
|
|||||||
* @param current_tile Current tile the cargo handling is happening on.
|
* @param current_tile Current tile the cargo handling is happening on.
|
||||||
* return If any cargo will be unloaded.
|
* return If any cargo will be unloaded.
|
||||||
*/
|
*/
|
||||||
bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
|
bool VehicleCargoList::Stage(bool accepted, StationID current_station, std::span<const StationID> next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
|
||||||
{
|
{
|
||||||
this->AssertCountConsistency();
|
this->AssertCountConsistency();
|
||||||
assert(this->action_counts[MTA_LOAD] == 0);
|
assert(this->action_counts[MTA_LOAD] == 0);
|
||||||
@@ -468,9 +468,9 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
|
|||||||
} else {
|
} else {
|
||||||
FlowStat new_shares = flow_it->second;
|
FlowStat new_shares = flow_it->second;
|
||||||
new_shares.ChangeShare(current_station, INT_MIN);
|
new_shares.ChangeShare(current_station, INT_MIN);
|
||||||
StationIDStack excluded = next_station;
|
for (auto station_it = next_station.rbegin(); station_it != next_station.rend(); ++station_it) {
|
||||||
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
|
if (!new_shares.GetShares()->empty()) break;
|
||||||
new_shares.ChangeShare(excluded.Pop(), INT_MIN);
|
new_shares.ChangeShare(*station_it, INT_MIN);
|
||||||
}
|
}
|
||||||
if (new_shares.GetShares()->empty()) {
|
if (new_shares.GetShares()->empty()) {
|
||||||
cargo_next = StationID::Invalid();
|
cargo_next = StationID::Invalid();
|
||||||
@@ -739,11 +739,11 @@ bool StationCargoList::ShiftCargo(Taction &action, StationID next)
|
|||||||
* @return Amount of cargo actually moved.
|
* @return Amount of cargo actually moved.
|
||||||
*/
|
*/
|
||||||
template <class Taction>
|
template <class Taction>
|
||||||
uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid)
|
uint StationCargoList::ShiftCargo(Taction action, std::span<const StationID> next, bool include_invalid)
|
||||||
{
|
{
|
||||||
uint max_move = action.MaxMove();
|
uint max_move = action.MaxMove();
|
||||||
while (!next.IsEmpty()) {
|
for (auto it = next.rbegin(); it != next.rend(); ++it) {
|
||||||
this->ShiftCargo(action, next.Pop());
|
this->ShiftCargo(action, *it);
|
||||||
if (action.MaxMove() == 0) break;
|
if (action.MaxMove() == 0) break;
|
||||||
}
|
}
|
||||||
if (include_invalid && action.MaxMove() > 0) {
|
if (include_invalid && action.MaxMove() > 0) {
|
||||||
@@ -814,7 +814,7 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_
|
|||||||
* @param current_tile Current tile the cargo handling is happening on.
|
* @param current_tile Current tile the cargo handling is happening on.
|
||||||
* @return Amount of cargo actually reserved.
|
* @return Amount of cargo actually reserved.
|
||||||
*/
|
*/
|
||||||
uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
|
uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, std::span<const StationID> next_station, TileIndex current_tile)
|
||||||
{
|
{
|
||||||
return this->ShiftCargo(CargoReservation(this, dest, max_move, current_tile), next_station, true);
|
return this->ShiftCargo(CargoReservation(this, dest, max_move, current_tile), next_station, true);
|
||||||
}
|
}
|
||||||
@@ -831,7 +831,7 @@ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDS
|
|||||||
* modes of loading are exclusive, though. If cargo is reserved we don't
|
* modes of loading are exclusive, though. If cargo is reserved we don't
|
||||||
* need to load unreserved cargo.
|
* need to load unreserved cargo.
|
||||||
*/
|
*/
|
||||||
uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
|
uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, std::span<const StationID> next_station, TileIndex current_tile)
|
||||||
{
|
{
|
||||||
uint move = std::min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
|
uint move = std::min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
|
||||||
if (move > 0) {
|
if (move > 0) {
|
||||||
@@ -839,7 +839,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
|
|||||||
dest->Reassign<VehicleCargoList::MTA_LOAD, VehicleCargoList::MTA_KEEP>(move);
|
dest->Reassign<VehicleCargoList::MTA_LOAD, VehicleCargoList::MTA_KEEP>(move);
|
||||||
return move;
|
return move;
|
||||||
} else {
|
} else {
|
||||||
return this->ShiftCargo(CargoLoad(this, dest, max_move, current_tile), next_station, true);
|
return this->ShiftCargo(CargoLoad{this, dest, max_move, current_tile}, next_station, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
|
|||||||
*/
|
*/
|
||||||
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
|
||||||
{
|
{
|
||||||
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
|
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), {&avoid, 1}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ protected:
|
|||||||
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
|
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
|
||||||
|
|
||||||
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
|
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
|
||||||
StationID current_station, bool accepted, StationIDStack next_station);
|
StationID current_station, bool accepted, std::span<const StationID> next_station);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** The station cargo list needs to control the unloading. */
|
/** The station cargo list needs to control the unloading. */
|
||||||
@@ -469,7 +469,7 @@ public:
|
|||||||
|
|
||||||
void InvalidateCache();
|
void InvalidateCache();
|
||||||
|
|
||||||
bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
|
bool Stage(bool accepted, StationID current_station, std::span<const StationID> next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks all cargo in the vehicle as to be kept. This is mostly useful for
|
* Marks all cargo in the vehicle as to be kept. This is mostly useful for
|
||||||
@@ -543,7 +543,7 @@ public:
|
|||||||
bool ShiftCargo(Taction &action, StationID next);
|
bool ShiftCargo(Taction &action, StationID next);
|
||||||
|
|
||||||
template <class Taction>
|
template <class Taction>
|
||||||
uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid);
|
uint ShiftCargo(Taction action, std::span<const StationID> next, bool include_invalid);
|
||||||
|
|
||||||
void Append(CargoPacket *cp, StationID next);
|
void Append(CargoPacket *cp, StationID next);
|
||||||
|
|
||||||
@@ -552,10 +552,10 @@ public:
|
|||||||
* @param next Station the cargo is headed for.
|
* @param next Station the cargo is headed for.
|
||||||
* @return If there is any cargo for that station.
|
* @return If there is any cargo for that station.
|
||||||
*/
|
*/
|
||||||
inline bool HasCargoFor(StationIDStack next) const
|
inline bool HasCargoFor(std::span<const StationID> next) const
|
||||||
{
|
{
|
||||||
while (!next.IsEmpty()) {
|
for (const StationID &station : next) {
|
||||||
if (this->packets.find(next.Pop()) != this->packets.end()) return true;
|
if (this->packets.find(station) != this->packets.end()) return true;
|
||||||
}
|
}
|
||||||
/* Packets for StationID::Invalid() can go anywhere. */
|
/* Packets for StationID::Invalid() can go anywhere. */
|
||||||
return this->packets.find(StationID::Invalid()) != this->packets.end();
|
return this->packets.find(StationID::Invalid()) != this->packets.end();
|
||||||
@@ -603,8 +603,8 @@ public:
|
|||||||
* amount of cargo to be moved. Second parameter is destination (if
|
* amount of cargo to be moved. Second parameter is destination (if
|
||||||
* applicable), return value is amount of cargo actually moved. */
|
* applicable), return value is amount of cargo actually moved. */
|
||||||
|
|
||||||
uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
|
uint Reserve(uint max_move, VehicleCargoList *dest, std::span<const StationID> next, TileIndex current_tile);
|
||||||
uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
|
uint Load(uint max_move, VehicleCargoList *dest, std::span<const StationID> next, TileIndex current_tile);
|
||||||
uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr);
|
uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr);
|
||||||
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
|
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ add_files(
|
|||||||
pool_type.hpp
|
pool_type.hpp
|
||||||
random_func.cpp
|
random_func.cpp
|
||||||
random_func.hpp
|
random_func.hpp
|
||||||
smallstack_type.hpp
|
|
||||||
string_builder.cpp
|
string_builder.cpp
|
||||||
string_builder.hpp
|
string_builder.hpp
|
||||||
string_consumer.cpp
|
string_consumer.cpp
|
||||||
|
|||||||
@@ -1,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of OpenTTD.
|
|
||||||
* 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.
|
|
||||||
* 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.
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file smallstack_type.hpp Minimal stack that uses a pool to avoid pointers and doesn't allocate any heap memory if there is only one valid item. */
|
|
||||||
|
|
||||||
#ifndef SMALLSTACK_TYPE_HPP
|
|
||||||
#define SMALLSTACK_TYPE_HPP
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simplified pool which stores values instead of pointers and doesn't
|
|
||||||
* redefine operator new/delete. It also never zeroes memory and always reuses
|
|
||||||
* it.
|
|
||||||
*/
|
|
||||||
template <typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
|
|
||||||
class SimplePool {
|
|
||||||
public:
|
|
||||||
inline SimplePool() : first_unused(0), first_free(0) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the item at position index.
|
|
||||||
* @return Item at index.
|
|
||||||
*/
|
|
||||||
inline Titem &Get(Tindex index) { return this->data[index]; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new item and return its index.
|
|
||||||
* @return Index of new item.
|
|
||||||
*/
|
|
||||||
inline Tindex Create()
|
|
||||||
{
|
|
||||||
Tindex index = this->FindFirstFree();
|
|
||||||
if (index < Tmax_size) {
|
|
||||||
this->data[index].valid = true;
|
|
||||||
this->first_free = index + 1;
|
|
||||||
this->first_unused = std::max(this->first_unused, this->first_free);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy (or rather invalidate) the item at the given index.
|
|
||||||
* @param index Index of item to be destroyed.
|
|
||||||
*/
|
|
||||||
inline void Destroy(Tindex index)
|
|
||||||
{
|
|
||||||
this->data[index].valid = false;
|
|
||||||
this->first_free = std::min(this->first_free, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
inline Tindex FindFirstFree()
|
|
||||||
{
|
|
||||||
Tindex index = this->first_free;
|
|
||||||
for (; index < this->first_unused; index++) {
|
|
||||||
if (!this->data[index].valid) return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= this->data.size() && index < Tmax_size) {
|
|
||||||
this->data.resize(index + 1);
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SimplePoolPoolItem : public Titem {
|
|
||||||
bool valid;
|
|
||||||
};
|
|
||||||
|
|
||||||
Tindex first_unused;
|
|
||||||
Tindex first_free;
|
|
||||||
|
|
||||||
std::vector<SimplePoolPoolItem> data;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for SmallStack. We cannot add this into SmallStack itself as
|
|
||||||
* certain compilers don't like it.
|
|
||||||
*/
|
|
||||||
template <typename Titem, typename Tindex>
|
|
||||||
struct SmallStackItem {
|
|
||||||
Tindex next; ///< Pool index of next item.
|
|
||||||
Titem value; ///< Value of current item.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new item.
|
|
||||||
* @param value Value of the item.
|
|
||||||
* @param next Next item in the stack.
|
|
||||||
*/
|
|
||||||
inline SmallStackItem(const Titem &value, Tindex next) :
|
|
||||||
next(next), value(value) {}
|
|
||||||
SmallStackItem() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimal stack that uses a pool to avoid pointers. It has some peculiar
|
|
||||||
* properties that make it useful for passing around lists of IDs but not much
|
|
||||||
* else:
|
|
||||||
* 1. It always includes an invalid item as bottom.
|
|
||||||
* 2. It doesn't have a deep copy operation but uses smart pointers instead.
|
|
||||||
* Every copy is thus implicitly shared.
|
|
||||||
* 3. Its items are immutable.
|
|
||||||
* 4. Due to 2. and 3. memory management can be done by "branch counting".
|
|
||||||
* Whenever you copy a smallstack, the first item on the heap increases its
|
|
||||||
* branch_count, signifying that there are multiple items "in front" of it.
|
|
||||||
* When deleting a stack items are deleted up to the point where
|
|
||||||
* branch_count > 0.
|
|
||||||
* 5. You can choose your own index type, so that you can align it with your
|
|
||||||
* value type. E.G. value types of 16 bits length like to be combined with
|
|
||||||
* index types of the same length.
|
|
||||||
* @tparam Titem Value type to be used.
|
|
||||||
* @tparam Tindex Index type to use for the pool.
|
|
||||||
* @tparam Tinvalid_value Value to construct invalid item to keep at the bottom of each stack.
|
|
||||||
* @tparam Tgrowth_step Growth step for pool.
|
|
||||||
* @tparam Tmax_size Maximum size for pool.
|
|
||||||
*/
|
|
||||||
template <typename Titem, typename Tindex, auto Tinvalid_value, Tindex Tgrowth_step, Tindex Tmax_size>
|
|
||||||
class SmallStack : public SmallStackItem<Titem, Tindex> {
|
|
||||||
public:
|
|
||||||
static constexpr Titem Tinvalid{Tinvalid_value};
|
|
||||||
|
|
||||||
typedef SmallStackItem<Titem, Tindex> Item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SmallStack item that can be kept in a pool.
|
|
||||||
*/
|
|
||||||
struct PooledSmallStack : public Item {
|
|
||||||
Tindex branch_count; ///< Number of branches in the tree structure this item is parent of
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SimplePool<PooledSmallStack, Tindex, Tgrowth_step, Tmax_size> SmallStackPool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a stack with one or two items in it.
|
|
||||||
* @param value Initial item. If not missing or Tinvalid there will be Tinvalid below it.
|
|
||||||
*/
|
|
||||||
inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the head of stack and all other items members that are unique to it.
|
|
||||||
*/
|
|
||||||
inline ~SmallStack()
|
|
||||||
{
|
|
||||||
while (this->next != Tmax_size) this->Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shallow copy the stack, marking the first item as branched.
|
|
||||||
* @param other Stack to copy from
|
|
||||||
*/
|
|
||||||
inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shallow copy the stack, marking the first item as branched.
|
|
||||||
* @param other Stack to copy from
|
|
||||||
* @return This smallstack.
|
|
||||||
*/
|
|
||||||
inline SmallStack &operator=(const SmallStack &other)
|
|
||||||
{
|
|
||||||
if (this == &other) return *this;
|
|
||||||
while (this->next != Tmax_size) this->Pop();
|
|
||||||
this->next = other.next;
|
|
||||||
this->value = other.value;
|
|
||||||
/* Deleting and branching are independent operations, so it's fine to
|
|
||||||
* acquire separate locks for them. */
|
|
||||||
this->Branch();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes a new item onto the stack if there is still space in the
|
|
||||||
* underlying pool. Otherwise the topmost item's value gets overwritten.
|
|
||||||
* @param item Item to be pushed.
|
|
||||||
*/
|
|
||||||
inline void Push(const Titem &item)
|
|
||||||
{
|
|
||||||
if (this->value != Tinvalid) {
|
|
||||||
Tindex new_item = SmallStack::GetPool().Create();
|
|
||||||
if (new_item != Tmax_size) {
|
|
||||||
PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
|
|
||||||
pushed.value = this->value;
|
|
||||||
pushed.next = this->next;
|
|
||||||
pushed.branch_count = 0;
|
|
||||||
this->next = new_item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->value = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pop an item from the stack.
|
|
||||||
* @return Current top of stack.
|
|
||||||
*/
|
|
||||||
inline Titem Pop()
|
|
||||||
{
|
|
||||||
Titem ret = this->value;
|
|
||||||
if (this->next == Tmax_size) {
|
|
||||||
this->value = Tinvalid;
|
|
||||||
} else {
|
|
||||||
PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
|
|
||||||
this->value = popped.value;
|
|
||||||
if (popped.branch_count == 0) {
|
|
||||||
SmallStack::GetPool().Destroy(this->next);
|
|
||||||
} else {
|
|
||||||
--popped.branch_count;
|
|
||||||
if (popped.next != Tmax_size) {
|
|
||||||
++(SmallStack::GetPool().Get(popped.next).branch_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Accessing popped here is no problem as the pool will only set
|
|
||||||
* the validity flag, not actually delete the item, on Destroy(). */
|
|
||||||
this->next = popped.next;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the stack is empty.
|
|
||||||
* @return If the stack is empty.
|
|
||||||
*/
|
|
||||||
inline bool IsEmpty() const
|
|
||||||
{
|
|
||||||
return this->value == Tinvalid && this->next == Tmax_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the given item is contained in the stack.
|
|
||||||
* @param item Item to look for.
|
|
||||||
* @return If the item is in the stack.
|
|
||||||
*/
|
|
||||||
inline bool Contains(const Titem &item) const
|
|
||||||
{
|
|
||||||
if (item == Tinvalid || item == this->value) return true;
|
|
||||||
if (this->next != Tmax_size) {
|
|
||||||
const SmallStack *in_list = this;
|
|
||||||
do {
|
|
||||||
in_list = static_cast<const SmallStack *>(
|
|
||||||
static_cast<const Item *>(&SmallStack::GetPool().Get(in_list->next)));
|
|
||||||
if (in_list->value == item) return true;
|
|
||||||
} while (in_list->next != Tmax_size);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static SmallStackPool &GetPool()
|
|
||||||
{
|
|
||||||
static SmallStackPool pool;
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a branch in the pool if necessary.
|
|
||||||
*/
|
|
||||||
inline void Branch()
|
|
||||||
{
|
|
||||||
if (this->next != Tmax_size) {
|
|
||||||
++(SmallStack::GetPool().Get(this->next).branch_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1270,7 +1270,7 @@ void PrepareUnload(Vehicle *front_v)
|
|||||||
assert(CargoPayment::CanAllocateItem());
|
assert(CargoPayment::CanAllocateItem());
|
||||||
front_v->cargo_payment = new CargoPayment(front_v);
|
front_v->cargo_payment = new CargoPayment(front_v);
|
||||||
|
|
||||||
StationIDStack next_station = front_v->GetNextStoppingStation();
|
std::vector<StationID> next_station = front_v->GetNextStoppingStation();
|
||||||
if (front_v->orders == nullptr || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
|
if (front_v->orders == nullptr || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
|
||||||
Station *st = Station::Get(front_v->last_station_visited);
|
Station *st = Station::Get(front_v->last_station_visited);
|
||||||
for (Vehicle *v = front_v; v != nullptr; v = v->Next()) {
|
for (Vehicle *v = front_v; v != nullptr; v = v->Next()) {
|
||||||
@@ -1433,7 +1433,7 @@ struct FinalizeRefitAction
|
|||||||
{
|
{
|
||||||
CargoArray &consist_capleft; ///< Capacities left in the consist.
|
CargoArray &consist_capleft; ///< Capacities left in the consist.
|
||||||
Station *st; ///< Station to reserve cargo from.
|
Station *st; ///< Station to reserve cargo from.
|
||||||
StationIDStack &next_station; ///< Next hops to reserve cargo for.
|
std::span<const StationID> next_station; ///< Next hops to reserve cargo for.
|
||||||
bool do_reserve; ///< If the vehicle should reserve.
|
bool do_reserve; ///< If the vehicle should reserve.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1443,7 +1443,7 @@ struct FinalizeRefitAction
|
|||||||
* @param next_station Next hops to reserve cargo for.
|
* @param next_station Next hops to reserve cargo for.
|
||||||
* @param do_reserve If we should reserve cargo or just add up the capacities.
|
* @param do_reserve If we should reserve cargo or just add up the capacities.
|
||||||
*/
|
*/
|
||||||
FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station, bool do_reserve) :
|
FinalizeRefitAction(CargoArray &consist_capleft, Station *st, std::span<const StationID> next_station, bool do_reserve) :
|
||||||
consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {}
|
consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1471,7 +1471,7 @@ struct FinalizeRefitAction
|
|||||||
* @param next_station Possible next stations the vehicle can travel to.
|
* @param next_station Possible next stations the vehicle can travel to.
|
||||||
* @param new_cargo_type Target cargo for refit.
|
* @param new_cargo_type Target cargo for refit.
|
||||||
*/
|
*/
|
||||||
static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, StationIDStack next_station, CargoType new_cargo_type)
|
static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, std::span<const StationID> next_station, CargoType new_cargo_type)
|
||||||
{
|
{
|
||||||
Vehicle *v_start = v->GetFirstEnginePart();
|
Vehicle *v_start = v->GetFirstEnginePart();
|
||||||
if (!IterateVehicleParts(v_start, IsEmptyAction())) return;
|
if (!IterateVehicleParts(v_start, IsEmptyAction())) return;
|
||||||
@@ -1538,16 +1538,16 @@ static bool MayLoadUnderExclusiveRights(const Station *st, const Vehicle *v)
|
|||||||
|
|
||||||
struct ReserveCargoAction {
|
struct ReserveCargoAction {
|
||||||
Station *st;
|
Station *st;
|
||||||
StationIDStack *next_station;
|
std::span<const StationID> next_station;
|
||||||
|
|
||||||
ReserveCargoAction(Station *st, StationIDStack *next_station) :
|
ReserveCargoAction(Station *st, std::span<const StationID> next_station) :
|
||||||
st(st), next_station(next_station) {}
|
st(st), next_station(next_station) {}
|
||||||
|
|
||||||
bool operator()(Vehicle *v)
|
bool operator()(Vehicle *v)
|
||||||
{
|
{
|
||||||
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
|
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
|
||||||
st->goods[v->cargo_type].GetOrCreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
|
st->goods[v->cargo_type].GetOrCreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
|
||||||
&v->cargo, *next_station, v->GetCargoTile());
|
&v->cargo, next_station, v->GetCargoTile());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -1563,7 +1563,7 @@ struct ReserveCargoAction {
|
|||||||
* @param consist_capleft If given, save free capacities after reserving there.
|
* @param consist_capleft If given, save free capacities after reserving there.
|
||||||
* @param next_station Station(s) the vehicle will stop at next.
|
* @param next_station Station(s) the vehicle will stop at next.
|
||||||
*/
|
*/
|
||||||
static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack *next_station)
|
static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, std::span<const StationID> next_station)
|
||||||
{
|
{
|
||||||
/* If there is a cargo payment not all vehicles of the consist have tried to do the refit.
|
/* If there is a cargo payment not all vehicles of the consist have tried to do the refit.
|
||||||
* In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain"
|
* In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain"
|
||||||
@@ -1618,14 +1618,14 @@ static void LoadUnloadVehicle(Vehicle *front)
|
|||||||
StationID last_visited = front->last_station_visited;
|
StationID last_visited = front->last_station_visited;
|
||||||
Station *st = Station::Get(last_visited);
|
Station *st = Station::Get(last_visited);
|
||||||
|
|
||||||
StationIDStack next_station = front->GetNextStoppingStation();
|
std::vector<StationID> next_station = front->GetNextStoppingStation();
|
||||||
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CARGO_AUTO_REFIT;
|
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CARGO_AUTO_REFIT;
|
||||||
CargoArray consist_capleft{};
|
CargoArray consist_capleft{};
|
||||||
if (_settings_game.order.improved_load && use_autorefit ?
|
if (_settings_game.order.improved_load && use_autorefit ?
|
||||||
front->cargo_payment == nullptr : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) {
|
front->cargo_payment == nullptr : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) {
|
||||||
ReserveConsist(st, front,
|
ReserveConsist(st, front,
|
||||||
(use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : nullptr,
|
(use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : nullptr,
|
||||||
&next_station);
|
next_station);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have not waited enough time till the next round of loading/unloading */
|
/* We have not waited enough time till the next round of loading/unloading */
|
||||||
|
|||||||
@@ -132,11 +132,11 @@ LinkGraphJob::~LinkGraphJob()
|
|||||||
!(*lg)[node_id].HasEdgeTo(dest_id) ||
|
!(*lg)[node_id].HasEdgeTo(dest_id) ||
|
||||||
(*lg)[node_id][dest_id].LastUpdate() == EconomyTime::INVALID_DATE) {
|
(*lg)[node_id][dest_id].LastUpdate() == EconomyTime::INVALID_DATE) {
|
||||||
/* Edge has been removed. Delete flows. */
|
/* Edge has been removed. Delete flows. */
|
||||||
StationIDStack erased = flows.DeleteFlows(to);
|
std::vector<StationID> erased = flows.DeleteFlows(to);
|
||||||
/* Delete old flows for source stations which have been deleted
|
/* Delete old flows for source stations which have been deleted
|
||||||
* from the new flows. This avoids flow cycles between old and
|
* from the new flows. This avoids flow cycles between old and
|
||||||
* new flows. */
|
* new flows. */
|
||||||
while (!erased.IsEmpty()) geflows.erase(erased.Pop());
|
for (const StationID &station : erased) geflows.erase(station);
|
||||||
} else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) {
|
} else if ((*lg)[node_id][dest_id].last_unrestricted_update == EconomyTime::INVALID_DATE) {
|
||||||
/* Edge is fully restricted. */
|
/* Edge is fully restricted. */
|
||||||
flows.RestrictFlows(to);
|
flows.RestrictFlows(to);
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; }
|
inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; }
|
||||||
|
|
||||||
StationIDStack GetNextStoppingStation(const Vehicle *v, VehicleOrderID first = INVALID_VEH_ORDER_ID, uint hops = 0) const;
|
std::vector<StationID> GetNextStoppingStation(const Vehicle *v, VehicleOrderID first = INVALID_VEH_ORDER_ID, uint hops = 0) const;
|
||||||
VehicleOrderID GetNextDecisionNode(VehicleOrderID next, uint hops) const;
|
VehicleOrderID GetNextDecisionNode(VehicleOrderID next, uint hops) const;
|
||||||
|
|
||||||
void InsertOrderAt(Order &&order, VehicleOrderID index);
|
void InsertOrderAt(Order &&order, VehicleOrderID index);
|
||||||
|
|||||||
@@ -361,14 +361,14 @@ VehicleOrderID OrderList::GetNextDecisionNode(VehicleOrderID next, uint hops) co
|
|||||||
* @pre The vehicle is currently loading and v->last_station_visited is meaningful.
|
* @pre The vehicle is currently loading and v->last_station_visited is meaningful.
|
||||||
* @note This function may draw a random number. Don't use it from the GUI.
|
* @note This function may draw a random number. Don't use it from the GUI.
|
||||||
*/
|
*/
|
||||||
StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderID first, uint hops) const
|
std::vector<StationID> OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderID first, uint hops) const
|
||||||
{
|
{
|
||||||
VehicleOrderID next = first;
|
VehicleOrderID next = first;
|
||||||
if (first == INVALID_VEH_ORDER_ID) {
|
if (first == INVALID_VEH_ORDER_ID) {
|
||||||
next = v->cur_implicit_order_index;
|
next = v->cur_implicit_order_index;
|
||||||
if (next >= this->GetNumOrders()) {
|
if (next >= this->GetNumOrders()) {
|
||||||
next = this->GetFirstOrder();
|
next = this->GetFirstOrder();
|
||||||
if (next == INVALID_VEH_ORDER_ID) return StationID::Invalid();
|
if (next == INVALID_VEH_ORDER_ID) return {};
|
||||||
} else {
|
} else {
|
||||||
/* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
|
/* GetNext never returns INVALID_VEH_ORDER_ID if there is a valid station in the list.
|
||||||
* As the given "next" is already valid and a station in the list, we
|
* As the given "next" is already valid and a station in the list, we
|
||||||
@@ -392,9 +392,9 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
|
|||||||
} else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
|
} else if (skip_to == INVALID_VEH_ORDER_ID || skip_to == first) {
|
||||||
next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
|
next = (advance == first) ? INVALID_VEH_ORDER_ID : advance;
|
||||||
} else {
|
} else {
|
||||||
StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops);
|
std::vector<StationID> st1 = this->GetNextStoppingStation(v, skip_to, hops);
|
||||||
StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops);
|
std::vector<StationID> st2 = this->GetNextStoppingStation(v, advance, hops);
|
||||||
while (!st2.IsEmpty()) st1.Push(st2.Pop());
|
std::copy(st2.rbegin(), st2.rend(), std::back_inserter(st1));
|
||||||
return st1;
|
return st1;
|
||||||
}
|
}
|
||||||
++hops;
|
++hops;
|
||||||
@@ -404,11 +404,11 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, VehicleOrderI
|
|||||||
if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
|
if (next == INVALID_VEH_ORDER_ID || ((orders[next].IsType(OT_GOTO_STATION) || orders[next].IsType(OT_IMPLICIT)) &&
|
||||||
orders[next].GetDestination() == v->last_station_visited &&
|
orders[next].GetDestination() == v->last_station_visited &&
|
||||||
(orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
|
(orders[next].GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) {
|
||||||
return StationID::Invalid();
|
return {};
|
||||||
}
|
}
|
||||||
} while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
|
} while (orders[next].IsType(OT_GOTO_DEPOT) || orders[next].GetDestination() == v->last_station_visited);
|
||||||
|
|
||||||
return orders[next].GetDestination().ToStationID();
|
return {orders[next].GetDestination().ToStationID()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public:
|
|||||||
|
|
||||||
void AddFlow(StationID origin, StationID via, uint amount);
|
void AddFlow(StationID origin, StationID via, uint amount);
|
||||||
void PassOnFlow(StationID origin, StationID via, uint amount);
|
void PassOnFlow(StationID origin, StationID via, uint amount);
|
||||||
StationIDStack DeleteFlows(StationID via);
|
std::vector<StationID> DeleteFlows(StationID via);
|
||||||
void RestrictFlows(StationID via);
|
void RestrictFlows(StationID via);
|
||||||
void ReleaseFlows(StationID via);
|
void ReleaseFlows(StationID via);
|
||||||
void FinalizeLocalConsumption(StationID self);
|
void FinalizeLocalConsumption(StationID self);
|
||||||
|
|||||||
@@ -5200,14 +5200,14 @@ void FlowStatMap::FinalizeLocalConsumption(StationID self)
|
|||||||
* @return IDs of source stations for which the complete FlowStat, not only a
|
* @return IDs of source stations for which the complete FlowStat, not only a
|
||||||
* share, has been erased.
|
* share, has been erased.
|
||||||
*/
|
*/
|
||||||
StationIDStack FlowStatMap::DeleteFlows(StationID via)
|
std::vector<StationID> FlowStatMap::DeleteFlows(StationID via)
|
||||||
{
|
{
|
||||||
StationIDStack ret;
|
std::vector<StationID> ret;
|
||||||
for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
|
for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) {
|
||||||
FlowStat &s_flows = f_it->second;
|
FlowStat &s_flows = f_it->second;
|
||||||
s_flows.ChangeShare(via, INT_MIN);
|
s_flows.ChangeShare(via, INT_MIN);
|
||||||
if (s_flows.GetShares()->empty()) {
|
if (s_flows.GetShares()->empty()) {
|
||||||
ret.Push(f_it->first);
|
ret.push_back(f_it->first);
|
||||||
this->erase(f_it++);
|
this->erase(f_it++);
|
||||||
} else {
|
} else {
|
||||||
++f_it;
|
++f_it;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#define STATION_TYPE_H
|
#define STATION_TYPE_H
|
||||||
|
|
||||||
#include "core/pool_type.hpp"
|
#include "core/pool_type.hpp"
|
||||||
#include "core/smallstack_type.hpp"
|
|
||||||
#include "tilearea_type.h"
|
#include "tilearea_type.h"
|
||||||
|
|
||||||
using StationID = PoolID<uint16_t, struct StationIDTag, 64000, 0xFFFF>;
|
using StationID = PoolID<uint16_t, struct StationIDTag, 64000, 0xFFFF>;
|
||||||
@@ -26,8 +25,6 @@ struct RoadStop;
|
|||||||
struct StationSpec;
|
struct StationSpec;
|
||||||
struct Waypoint;
|
struct Waypoint;
|
||||||
|
|
||||||
using StationIDStack = SmallStack<StationID, StationID::BaseType, StationID::Invalid().base(), 8, StationID::End().base()>;
|
|
||||||
|
|
||||||
/** Station types */
|
/** Station types */
|
||||||
enum class StationType : uint8_t {
|
enum class StationType : uint8_t {
|
||||||
Rail,
|
Rail,
|
||||||
|
|||||||
@@ -714,9 +714,9 @@ public:
|
|||||||
* Get the next station the vehicle will stop at.
|
* Get the next station the vehicle will stop at.
|
||||||
* @return ID of the next station the vehicle will stop at or StationID::Invalid().
|
* @return ID of the next station the vehicle will stop at or StationID::Invalid().
|
||||||
*/
|
*/
|
||||||
inline StationIDStack GetNextStoppingStation() const
|
inline std::vector<StationID> GetNextStoppingStation() const
|
||||||
{
|
{
|
||||||
return (this->orders == nullptr) ? StationID::Invalid() : this->orders->GetNextStoppingStation(this);
|
return (this->orders == nullptr) ? std::vector<StationID>{} : this->orders->GetNextStoppingStation(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetRefitCaps();
|
void ResetRefitCaps();
|
||||||
|
|||||||
Reference in New Issue
Block a user