1
0
Fork 0

Codechange: Improve performance of evaluating group hierarchy.

Store a list of child groups in each group, to avoid having to iterate the group pool to find its children.
pull/14270/head
Peter Nelson 2025-05-21 17:14:28 +01:00 committed by Peter Nelson
parent 8f3f25de4b
commit 000a79c093
3 changed files with 63 additions and 23 deletions

View File

@ -11,6 +11,7 @@
#define GROUP_H #define GROUP_H
#include "group_type.h" #include "group_type.h"
#include "core/flatset_type.hpp"
#include "core/pool_type.hpp" #include "core/pool_type.hpp"
#include "company_type.h" #include "company_type.h"
#include "vehicle_type.h" #include "vehicle_type.h"
@ -78,6 +79,7 @@ struct Group : GroupPool::PoolItem<&_group_pool> {
Livery livery{}; ///< Custom colour scheme for vehicles in this group Livery livery{}; ///< Custom colour scheme for vehicles in this group
GroupStatistics statistics{}; ///< NOSAVE: Statistics and caches on the vehicles in the group. GroupStatistics statistics{}; ///< NOSAVE: Statistics and caches on the vehicles in the group.
FlatSet<GroupID> children; ///< NOSAVE: child groups belonging to this group.
bool folded = false; ///< NOSAVE: Is this group folded in the group view? bool folded = false; ///< NOSAVE: Is this group folded in the group view?
GroupID parent = GroupID::Invalid(); ///< Parent group GroupID parent = GroupID::Invalid(); ///< Parent group
@ -104,6 +106,7 @@ inline bool IsAllGroupID(GroupID id_g)
} }
void UpdateGroupChildren();
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e); uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e);
uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type); uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type);
uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type); uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type);

View File

@ -41,6 +41,16 @@ void GroupStatistics::Clear()
this->num_engines.clear(); this->num_engines.clear();
} }
/**
* Update children list for each group.
*/
void UpdateGroupChildren()
{
for (Group *g : Group::Iterate()) {
if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.insert(g->index);
}
}
/** /**
* Get number of vehicles of a specific engine ID. * Get number of vehicles of a specific engine ID.
* @param engine Engine ID. * @param engine Engine ID.
@ -294,12 +304,11 @@ static void PropagateChildLivery(const Group *g, bool reset_cache)
} }
} }
for (Group *cg : Group::Iterate()) { for (const GroupID &childgroup : g->children) {
if (cg->parent == g->index) { Group *cg = Group::Get(childgroup);
if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1; if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2; if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
PropagateChildLivery(cg, reset_cache); PropagateChildLivery(cg, reset_cache);
}
} }
} }
@ -333,7 +342,7 @@ std::tuple<CommandCost, GroupID> CmdCreateGroup(DoCommandFlags flags, VehicleTyp
if (!Group::CanAllocateItem()) return { CMD_ERROR, GroupID::Invalid() }; if (!Group::CanAllocateItem()) return { CMD_ERROR, GroupID::Invalid() };
const Group *pg = Group::GetIfValid(parent_group); Group *pg = Group::GetIfValid(parent_group);
if (pg != nullptr) { if (pg != nullptr) {
if (pg->owner != _current_company) return { CMD_ERROR, GroupID::Invalid() }; if (pg->owner != _current_company) return { CMD_ERROR, GroupID::Invalid() };
if (pg->vehicle_type != vt) return { CMD_ERROR, GroupID::Invalid() }; if (pg->vehicle_type != vt) return { CMD_ERROR, GroupID::Invalid() };
@ -353,6 +362,7 @@ std::tuple<CommandCost, GroupID> CmdCreateGroup(DoCommandFlags flags, VehicleTyp
g->livery.colour1 = pg->livery.colour1; g->livery.colour1 = pg->livery.colour1;
g->livery.colour2 = pg->livery.colour2; g->livery.colour2 = pg->livery.colour2;
g->flags = pg->flags; g->flags = pg->flags;
pg->children.insert(g->index);
} }
InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).ToWindowNumber()); InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).ToWindowNumber());
@ -380,10 +390,8 @@ CommandCost CmdDeleteGroup(DoCommandFlags flags, GroupID group_id)
Command<CMD_REMOVE_ALL_VEHICLES_GROUP>::Do(flags, group_id); Command<CMD_REMOVE_ALL_VEHICLES_GROUP>::Do(flags, group_id);
/* Delete sub-groups */ /* Delete sub-groups */
for (const Group *gp : Group::Iterate()) { for (const GroupID &childgroup : g->children) {
if (gp->parent == g->index) { Command<CMD_DELETE_GROUP>::Do(flags, childgroup);
Command<CMD_DELETE_GROUP>::Do(flags, gp->index);
}
} }
if (flags.Test(DoCommandFlag::Execute)) { if (flags.Test(DoCommandFlag::Execute)) {
@ -401,6 +409,11 @@ CommandCost CmdDeleteGroup(DoCommandFlags flags, GroupID group_id)
c->freegroups.ReleaseID(g->number); c->freegroups.ReleaseID(g->number);
} }
if (g->parent != GroupID::Invalid()) {
Group *pg = Group::Get(g->parent);
pg->children.erase(g->index);
}
VehicleType vt = g->vehicle_type; VehicleType vt = g->vehicle_type;
/* Delete the Replace Vehicle Windows */ /* Delete the Replace Vehicle Windows */
@ -445,6 +458,9 @@ CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID gro
} }
} }
} else if (mode == AlterGroupMode::SetParent) { } else if (mode == AlterGroupMode::SetParent) {
/* Do nothing if the parent group isn't actually changed. */
if (g->parent == parent_id) return CommandCost();
/* Set group parent */ /* Set group parent */
const Group *pg = Group::GetIfValid(parent_id); const Group *pg = Group::GetIfValid(parent_id);
@ -458,7 +474,10 @@ CommandCost CmdAlterGroup(DoCommandFlags flags, AlterGroupMode mode, GroupID gro
} }
if (flags.Test(DoCommandFlag::Execute)) { if (flags.Test(DoCommandFlag::Execute)) {
if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.erase(g->index);
g->parent = (pg == nullptr) ? GroupID::Invalid() : pg->index; g->parent = (pg == nullptr) ? GroupID::Invalid() : pg->index;
if (g->parent != GroupID::Invalid()) Group::Get(g->parent)->children.insert(g->index);
GroupStatistics::UpdateAutoreplace(g->owner); GroupStatistics::UpdateAutoreplace(g->owner);
if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) { if (!HasBit(g->livery.in_use, 0) || !HasBit(g->livery.in_use, 1)) {
@ -696,8 +715,8 @@ static void SetGroupFlag(Group *g, GroupFlag flag, bool set, bool children)
if (!children) return; if (!children) return;
for (Group *pg : Group::Iterate()) { for (const GroupID &childgroup : g->children) {
if (pg->parent == g->index) SetGroupFlag(pg, flag, set, true); SetGroupFlag(Group::Get(childgroup), flag, set, true);
} }
} }
@ -790,11 +809,14 @@ void UpdateTrainGroupID(Train *v)
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e) uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
{ {
uint count = 0; uint count = 0;
const Engine *e = Engine::Get(id_e);
for (const Group *g : Group::Iterate()) { if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
if (g->parent == id_g) count += GetGroupNumEngines(company, g->index, id_e); for (const GroupID &childgroup : g->children) {
count += GetGroupNumEngines(company, childgroup, id_e);
}
} }
return count + GroupStatistics::Get(company, id_g, e->type).GetNumEngines(id_e);
return count + GroupStatistics::Get(company, id_g, Engine::Get(id_e)->type).GetNumEngines(id_e);
} }
/** /**
@ -808,9 +830,13 @@ uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type) uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type)
{ {
uint count = 0; uint count = 0;
for (const Group *g : Group::Iterate()) {
if (g->parent == id_g) count += GetGroupNumVehicle(company, g->index, type); if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
for (const GroupID &childgroup : g->children) {
count += GetGroupNumVehicle(company, childgroup, type);
}
} }
return count + GroupStatistics::Get(company, id_g, type).num_vehicle; return count + GroupStatistics::Get(company, id_g, type).num_vehicle;
} }
@ -825,9 +851,13 @@ uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type)
uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type) uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type)
{ {
uint count = 0; uint count = 0;
for (const Group *g : Group::Iterate()) {
if (g->parent == id_g) count += GetGroupNumVehicleMinAge(company, g->index, type); if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
for (const GroupID &childgroup : g->children) {
count += GetGroupNumVehicleMinAge(company, childgroup, type);
}
} }
return count + GroupStatistics::Get(company, id_g, type).num_vehicle_min_age; return count + GroupStatistics::Get(company, id_g, type).num_vehicle_min_age;
} }
@ -842,9 +872,13 @@ uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type)
Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType type) Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType type)
{ {
Money sum = 0; Money sum = 0;
for (const Group *g : Group::Iterate()) {
if (g->parent == id_g) sum += GetGroupProfitLastYearMinAge(company, g->index, type); if (Group *g = Group::GetIfValid(id_g); g != nullptr) {
for (const GroupID &childgroup : g->children) {
sum += GetGroupProfitLastYearMinAge(company, childgroup, type);
}
} }
return sum + GroupStatistics::Get(company, id_g, type).profit_last_year_min_age; return sum + GroupStatistics::Get(company, id_g, type).profit_last_year_min_age;
} }

View File

@ -575,6 +575,9 @@ bool AfterLoadGame()
* that otherwise won't exist in the tree. */ * that otherwise won't exist in the tree. */
RebuildViewportKdtree(); RebuildViewportKdtree();
/* Group hierarchy may be evaluated during conversion, so ensure its correct early on. */
UpdateGroupChildren();
if (IsSavegameVersionBefore(SLV_98)) _gamelog.GRFAddList(_grfconfig); if (IsSavegameVersionBefore(SLV_98)) _gamelog.GRFAddList(_grfconfig);
if (IsSavegameVersionBefore(SLV_119)) { if (IsSavegameVersionBefore(SLV_119)) {