Fix crash when sorting by capacity in autoreplace window

Move capacity cache into GUIList sort parameter

See: #690
pull/693/head
Jonathan G Rennison 4 weeks ago
parent 5e24882c18
commit 6d4f616706

@ -32,7 +32,7 @@
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group);
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
return Engine::Get(a.engine_id)->list_position < Engine::Get(b.engine_id)->list_position;
}

@ -36,7 +36,6 @@
#include "querystring_gui.h"
#include "stringfilter_type.h"
#include "hotkeys.h"
#include "3rdparty/cpp-btree/btree_map.h"
#include "widgets/build_vehicle_widget.h"
@ -206,29 +205,6 @@ bool _engine_sort_show_hidden_locos = false; ///< Las
bool _engine_sort_show_hidden_wagons = false; ///< Last set 'show hidden wagons' setting.
static CargoID _engine_sort_last_cargo_criteria[] = {CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY}; ///< Last set filter criteria, for each vehicle type.
struct BuildVehicleWindowBase;
struct EngineCapacityCache {
const BuildVehicleWindowBase *parent = nullptr;
CargoID current_cargo = INVALID_CARGO;
btree::btree_map<EngineID, uint> capacities;
void UpdateCargoFilter(const BuildVehicleWindowBase *parent, CargoID cargo_filter_criteria)
{
this->parent = parent;
if (cargo_filter_criteria >= NUM_CARGO) cargo_filter_criteria = INVALID_CARGO;
if (cargo_filter_criteria != this->current_cargo) {
this->current_cargo = cargo_filter_criteria;
this->capacities.clear();
}
}
uint GetArticulatedCapacity(EngineID eng, bool dual_headed = false);
};
static EngineCapacityCache *_engine_sort_capacity_cache = nullptr;
static uint8_t _last_sort_criteria_loco = 0;
static bool _last_sort_order_loco = false;
static CargoID _last_filter_criteria_loco = CargoFilterCriteria::CF_ANY;
@ -243,7 +219,7 @@ static CargoID _last_filter_criteria_wagon = CargoFilterCriteria::CF_ANY;
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int r = Engine::Get(a.engine_id)->list_position - Engine::Get(b.engine_id)->list_position;
@ -256,14 +232,14 @@ static bool EngineNumberSorter(const GUIEngineListItem &a, const GUIEngineListIt
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineIntroDateSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineIntroDateSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const auto va = Engine::Get(a.engine_id)->intro_date;
const auto vb = Engine::Get(b.engine_id)->intro_date;
const auto r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -273,13 +249,13 @@ static bool EngineIntroDateSorter(const GUIEngineListItem &a, const GUIEngineLis
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineVehicleCountSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineVehicleCountSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const GroupStatistics &stats = GroupStatistics::Get(_local_company, ALL_GROUP, Engine::Get(a.engine_id)->type);
const int r = ((int) stats.GetNumEngines(a.engine_id)) - ((int) stats.GetNumEngines(b.engine_id));
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -292,7 +268,7 @@ static EngineID _last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
static std::string last_name[2] = { {}, {} };
@ -311,7 +287,7 @@ static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem
int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -321,14 +297,14 @@ static bool EngineNameSorter(const GUIEngineListItem &a, const GUIEngineListItem
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineReliabilitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineReliabilitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const int va = Engine::Get(a.engine_id)->reliability;
const int vb = Engine::Get(b.engine_id)->reliability;
const int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -338,14 +314,14 @@ static bool EngineReliabilitySorter(const GUIEngineListItem &a, const GUIEngineL
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
Money va = Engine::Get(a.engine_id)->GetCost();
Money vb = Engine::Get(b.engine_id)->GetCost();
int r = ClampTo<int32_t>(va - vb);
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -355,14 +331,14 @@ static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineSpeedSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineSpeedSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int va = Engine::Get(a.engine_id)->GetDisplayMaxSpeed();
int vb = Engine::Get(b.engine_id)->GetDisplayMaxSpeed();
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -372,14 +348,14 @@ static bool EngineSpeedSorter(const GUIEngineListItem &a, const GUIEngineListIte
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EnginePowerSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EnginePowerSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int va = Engine::Get(a.engine_id)->GetPower();
int vb = Engine::Get(b.engine_id)->GetPower();
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -389,14 +365,14 @@ static bool EnginePowerSorter(const GUIEngineListItem &a, const GUIEngineListIte
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineTractiveEffortSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineTractiveEffortSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int va = Engine::Get(a.engine_id)->GetDisplayMaxTractiveEffort();
int vb = Engine::Get(b.engine_id)->GetDisplayMaxTractiveEffort();
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -406,18 +382,18 @@ static bool EngineTractiveEffortSorter(const GUIEngineListItem &a, const GUIEngi
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EngineRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EngineRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
Money va = Engine::Get(a.engine_id)->GetRunningCost();
Money vb = Engine::Get(b.engine_id)->GetRunningCost();
int r = ClampTo<int32_t>(va - vb);
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
static bool GenericEngineValueVsRunningCostSorter(const GUIEngineListItem &a, const uint value_a, const GUIEngineListItem &b, const uint value_b)
static bool GenericEngineValueVsRunningCostSorter(const GUIEngineListItem &a, const uint value_a, const GUIEngineListItem &b, const uint value_b, const GUIEngineListSortCache &cache)
{
const Engine *e_a = Engine::Get(a.engine_id);
const Engine *e_b = Engine::Get(b.engine_id);
@ -429,7 +405,7 @@ static bool GenericEngineValueVsRunningCostSorter(const GUIEngineListItem &a, co
if (r_a == 0) {
if (r_b == 0) {
/* If it is ambiguous which to return go with their ID */
if (value_a == value_b) return EngineNumberSorter(a, b);
if (value_a == value_b) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction != (value_a < value_b);
}
return !_engine_sort_direction;
@ -444,8 +420,8 @@ static bool GenericEngineValueVsRunningCostSorter(const GUIEngineListItem &a, co
* since we want consistent sorting.
* Also if both have no power then sort with reverse of running cost to simulate
* previous sorting behaviour for wagons. */
if (v_a == 0 && v_b == 0) return EngineRunningCostSorter(b, a);
if (v_a == v_b) return EngineNumberSorter(a, b);
if (v_a == 0 && v_b == 0) return EngineRunningCostSorter(b, a, cache);
if (v_a == v_b) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction != (v_a < v_b);
}
@ -455,9 +431,9 @@ static bool GenericEngineValueVsRunningCostSorter(const GUIEngineListItem &a, co
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
return GenericEngineValueVsRunningCostSorter(a, Engine::Get(a.engine_id)->GetPower(), b, Engine::Get(b.engine_id)->GetPower());
return GenericEngineValueVsRunningCostSorter(a, Engine::Get(a.engine_id)->GetPower(), b, Engine::Get(b.engine_id)->GetPower(), cache);
}
/* Train sorting functions */
@ -468,17 +444,17 @@ static bool EnginePowerVsRunningCostSorter(const GUIEngineListItem &a, const GUI
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
int va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
int va = cache.GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
int vb = cache.GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -488,15 +464,15 @@ static bool TrainEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngin
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool TrainEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool TrainEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const RailVehicleInfo *rvi_a = RailVehInfo(a.engine_id);
const RailVehicleInfo *rvi_b = RailVehInfo(b.engine_id);
uint va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
uint vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
uint va = cache.GetArticulatedCapacity(a.engine_id, rvi_a->railveh_type == RAILVEH_MULTIHEAD);
uint vb = cache.GetArticulatedCapacity(b.engine_id, rvi_b->railveh_type == RAILVEH_MULTIHEAD);
return GenericEngineValueVsRunningCostSorter(a, va, b, vb);
return GenericEngineValueVsRunningCostSorter(a, va, b, vb, cache);
}
/**
@ -505,14 +481,14 @@ static bool TrainEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, c
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int val_a = (RailVehInfo(a.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
int val_b = (RailVehInfo(b.engine_id)->railveh_type == RAILVEH_WAGON ? 1 : 0);
int r = val_a - val_b;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -524,14 +500,14 @@ static bool TrainEnginesThenWagonsSorter(const GUIEngineListItem &a, const GUIEn
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
int va = cache.GetArticulatedCapacity(a.engine_id);
int vb = cache.GetArticulatedCapacity(b.engine_id);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -541,11 +517,11 @@ static bool RoadVehEngineCapacitySorter(const GUIEngineListItem &a, const GUIEng
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool RoadVehEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool RoadVehEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int capacity_a = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int capacity_b = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b);
int capacity_a = cache.GetArticulatedCapacity(a.engine_id);
int capacity_b = cache.GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b, cache);
}
/* Ship vehicle sorting functions */
@ -556,14 +532,14 @@ static bool RoadVehEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a,
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int va = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int vb = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
int va = cache.GetArticulatedCapacity(a.engine_id);
int vb = cache.GetArticulatedCapacity(b.engine_id);
int r = va - vb;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -573,11 +549,11 @@ static bool ShipEngineCapacitySorter(const GUIEngineListItem &a, const GUIEngine
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool ShipEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool ShipEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
int capacity_a = _engine_sort_capacity_cache->GetArticulatedCapacity(a.engine_id);
int capacity_b = _engine_sort_capacity_cache->GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b);
int capacity_a = cache.GetArticulatedCapacity(a.engine_id);
int capacity_b = cache.GetArticulatedCapacity(b.engine_id);
return GenericEngineValueVsRunningCostSorter(a, capacity_a, b, capacity_b, cache);
}
/* Aircraft sorting functions */
@ -588,7 +564,7 @@ static bool ShipEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, co
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const Engine *e_a = Engine::Get(a.engine_id);
const Engine *e_b = Engine::Get(b.engine_id);
@ -604,7 +580,7 @@ static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngin
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
return EngineNumberSorter(a, b, cache);
}
}
return _engine_sort_direction ? r > 0 : r < 0;
@ -616,7 +592,7 @@ static bool AircraftEngineCargoSorter(const GUIEngineListItem &a, const GUIEngin
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool AircraftEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool AircraftEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
const Engine *e_a = Engine::Get(a.engine_id);
const Engine *e_b = Engine::Get(b.engine_id);
@ -625,7 +601,7 @@ static bool AircraftEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a
int va = e_a->GetDisplayDefaultCapacity(&mail_a);
int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
return GenericEngineValueVsRunningCostSorter(a, va + mail_a, b, vb + mail_b);
return GenericEngineValueVsRunningCostSorter(a, va + mail_a, b, vb + mail_b, cache);
}
/**
@ -634,7 +610,7 @@ static bool AircraftEngineCapacityVsRunningCostSorter(const GUIEngineListItem &a
* @param b second engine to compare
* @return for descending order: returns true if a < b. Vice versa for ascending order
*/
static bool AircraftRangeSorter(const GUIEngineListItem &a, const GUIEngineListItem &b)
static bool AircraftRangeSorter(const GUIEngineListItem &a, const GUIEngineListItem &b, const GUIEngineListSortCache &cache)
{
uint16_t r_a = Engine::Get(a.engine_id)->GetRange();
uint16_t r_b = Engine::Get(b.engine_id)->GetRange();
@ -642,7 +618,7 @@ static bool AircraftRangeSorter(const GUIEngineListItem &a, const GUIEngineListI
int r = r_a - r_b;
/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
if (r == 0) return EngineNumberSorter(a, b, cache);
return _engine_sort_direction ? r > 0 : r < 0;
}
@ -1503,13 +1479,30 @@ struct BuildVehicleWindowBase : Window {
}
};
uint EngineCapacityCache::GetArticulatedCapacity(EngineID eng, bool dual_headed)
/**
* Update cargo filter
* @param parent parent window, may be nullptr
* @param cargo_filter_criteria cargo filter criteria
*/
void GUIEngineListSortCache::UpdateCargoFilter(const BuildVehicleWindowBase *parent, CargoID cargo_filter_criteria)
{
this->parent = parent;
if (cargo_filter_criteria >= NUM_CARGO) cargo_filter_criteria = INVALID_CARGO;
if (cargo_filter_criteria != this->current_cargo) {
this->current_cargo = cargo_filter_criteria;
this->capacities.clear();
}
}
uint GUIEngineListSortCache::GetArticulatedCapacity(EngineID eng, bool dual_headed) const
{
auto iter = this->capacities.insert({ eng, 0 });
if (iter.second) {
/* New cache entry */
const Engine *e = Engine::Get(eng);
if (this->current_cargo != INVALID_CARGO && this->current_cargo != e->GetDefaultCargoType() && HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && e->refit_capacity_values == nullptr) {
if (this->current_cargo != INVALID_CARGO && this->current_cargo != e->GetDefaultCargoType() && HasBit(e->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && e->refit_capacity_values == nullptr && this->parent != nullptr) {
/* Expensive path simulating vehicle construction is required to determine capacity */
TestedEngineDetails te{};
this->parent->FillTestedEngineCapacity(eng, this->current_cargo, te);
@ -1537,7 +1530,6 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
int details_height; ///< Minimal needed height of the details panels, in text lines (found so far).
Scrollbar *vscroll;
TestedEngineDetails te; ///< Tested cost and capacity after refit.
EngineCapacityCache capacity_cache; ///< Engine capacity cache.
StringFilter string_filter; ///< Filter for vehicle name
QueryString vehicle_editbox; ///< Filter editbox
@ -1775,8 +1767,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
_last_engine[0] = _last_engine[1] = INVALID_ENGINE;
/* setup engine capacity cache */
this->capacity_cache.UpdateCargoFilter(this, this->cargo_filter_criteria);
_engine_sort_capacity_cache = &(this->capacity_cache);
list.SortParameterData().UpdateCargoFilter(this, this->cargo_filter_criteria);
/* make engines first, and then wagons, sorted by selected sort_criteria */
_engine_sort_direction = false;
@ -1916,8 +1907,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
}
/* setup engine capacity cache */
this->capacity_cache.UpdateCargoFilter(this, this->cargo_filter_criteria);
_engine_sort_capacity_cache = &(this->capacity_cache);
this->eng_list.SortParameterData().UpdateCargoFilter(this, this->cargo_filter_criteria);
_engine_sort_direction = this->descending_sort_order;
EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
@ -2358,7 +2348,6 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
bool show_hidden; ///< State of the 'show hidden' button.
int details_height; ///< Minimal needed height of the details panels (found so far).
TestedEngineDetails te; ///< Tested cost and capacity after refit.
EngineCapacityCache capacity_cache; ///< Engine capacity cache.
StringFilter string_filter; ///< Filter for vehicle name
QueryString vehicle_editbox { MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_VEHICLE_NAME_CHARS }; ///< Filter editbox
};
@ -2664,8 +2653,7 @@ struct BuildVehicleWindowTrainAdvanced final : BuildVehicleWindowBase {
_last_engine[0] = _last_engine[1] = INVALID_ENGINE;
/* setup engine capacity cache */
state.capacity_cache.UpdateCargoFilter(this, state.cargo_filter_criteria);
_engine_sort_capacity_cache = &(state.capacity_cache);
list.SortParameterData().UpdateCargoFilter(this, state.cargo_filter_criteria);
/* Sort */
_engine_sort_direction = state.descending_sort_order;

@ -374,7 +374,9 @@ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID eng
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare)
{
if (el.size() < 2) return;
std::sort(el.begin(), el.end(), compare);
std::sort(el.begin(), el.end(), [&](const GUIEngineListItem &a, const GUIEngineListItem &b) {
return compare(a, b, el.SortParameterData());
});
}
/**
@ -389,6 +391,8 @@ void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, si
if (num_items < 2) return;
assert(begin < el.size());
assert(begin + num_items <= el.size());
std::sort(el.begin() + begin, el.begin() + begin + num_items, compare);
std::sort(el.begin() + begin, el.begin() + begin + num_items, [&](const GUIEngineListItem &a, const GUIEngineListItem &b) {
return compare(a, b, el.SortParameterData());
});
}

@ -16,6 +16,25 @@
#include "vehicle_type.h"
#include "engine_base.h"
#include "window_type.h"
#include "3rdparty/cpp-btree/btree_map.h"
struct BuildVehicleWindowBase;
struct GUIEngineListSortCache {
const BuildVehicleWindowBase *parent = nullptr;
CargoID current_cargo = INVALID_CARGO;
mutable btree::btree_map<EngineID, uint> capacities;
void UpdateCargoFilter(const BuildVehicleWindowBase *parent, CargoID cargo_filter_criteria);
uint GetArticulatedCapacity(EngineID eng, bool dual_headed = false) const;
};
template <>
struct GUIListParamConfig<GUIEngineListSortCache>
{
using SortParameterReference = GUIEngineListSortCache;
static const bool constructor_init = false;
};
struct GUIEngineListItem {
EngineID engine_id; ///< Engine to display in build purchase list
@ -29,9 +48,9 @@ struct GUIEngineListItem {
bool operator == (const EngineID &other) const { return this->engine_id == other; }
};
typedef GUIList<GUIEngineListItem, std::nullptr_t, CargoID> GUIEngineList;
typedef GUIList<GUIEngineListItem, GUIEngineListSortCache, CargoID> GUIEngineList;
typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort.
typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&, const GUIEngineListSortCache &); ///< argument type for #EngList_Sort.
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare);
void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items);

Loading…
Cancel
Save