# HG changeset patch # User Peter Nelson # Date 2024-01-05 18:59:38 # Node ID f5d30cdebeffac52c5437357bba0845fca5e3bae # Parent e01ac5d31ebeb79043bb242200d24fe226f863c4 Codechange: Build station and depot vehicle lists from shared order lists. (#11676) The brings some performance advantages: * No need to iterate all vehicles and check for primary vehicle as only vehicles that can have orders are listed. * Shared orders only need to be tested once instead of for each vehicle sharing them. * Vehicle tests only need to be performed on the first shared vehicle instead of all. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -510,6 +510,7 @@ add_files( vehiclelist.cpp vehiclelist.h vehiclelist_cmd.h + vehiclelist_func.h viewport.cpp viewport_cmd.h viewport_func.h diff --git a/src/script/api/script_vehiclelist.cpp b/src/script/api/script_vehiclelist.cpp --- a/src/script/api/script_vehiclelist.cpp +++ b/src/script/api/script_vehiclelist.cpp @@ -14,6 +14,7 @@ #include "script_station.hpp" #include "../../depot_map.h" #include "../../vehicle_base.h" +#include "../../vehiclelist_func.h" #include "../../train.h" #include "../../core/backup_type.hpp" #include <../squirrel/sqvm.h> @@ -111,16 +112,12 @@ ScriptVehicleList_Station::ScriptVehicle bool is_deity = ScriptCompanyMode::IsDeity(); CompanyID owner = ScriptObject::GetCompany(); - for (const Vehicle *v : Vehicle::Iterate()) { - if ((v->owner == owner || is_deity) && v->IsPrimaryVehicle()) { - for (const Order *order : v->Orders()) { - if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id) { - this->AddItem(v->index); - break; - } - } - } - } + + FindVehiclesWithOrder( + [is_deity, owner](const Vehicle *v) { return is_deity || v->owner == owner; }, + [station_id](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id; }, + [this](const Vehicle *v) { this->AddItem(v->index); } + ); } ScriptVehicleList_Depot::ScriptVehicleList_Depot(TileIndex tile) @@ -162,16 +159,12 @@ ScriptVehicleList_Depot::ScriptVehicleLi bool is_deity = ScriptCompanyMode::IsDeity(); CompanyID owner = ScriptObject::GetCompany(); - for (const Vehicle *v : Vehicle::Iterate()) { - if ((v->owner == owner || is_deity) && v->IsPrimaryVehicle() && v->type == type) { - for (const Order *order : v->Orders()) { - if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest) { - this->AddItem(v->index); - break; - } - } - } - } + + FindVehiclesWithOrder( + [is_deity, owner, type](const Vehicle *v) { return (is_deity || v->owner == owner) && v->type == type; }, + [dest](const Order *order) { return order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest; }, + [this](const Vehicle *v) { this->AddItem(v->index); } + ); } ScriptVehicleList_SharedOrders::ScriptVehicleList_SharedOrders(VehicleID vehicle_id) diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -10,6 +10,7 @@ #include "stdafx.h" #include "train.h" #include "vehiclelist.h" +#include "vehiclelist_func.h" #include "group.h" #include "safeguards.h" @@ -116,17 +117,11 @@ bool GenerateVehicleSortList(VehicleList switch (vli.type) { case VL_STATION_LIST: - for (const Vehicle *v : Vehicle::Iterate()) { - if (v->type == vli.vtype && v->IsPrimaryVehicle()) { - for (const Order *order : v->Orders()) { - if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) - && order->GetDestination() == vli.index) { - list->push_back(v); - break; - } - } - } - } + FindVehiclesWithOrder( + [&vli](const Vehicle *v) { return v->type == vli.vtype; }, + [&vli](const Order *order) { return (order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == vli.index; }, + [&list](const Vehicle *v) { list->push_back(v); } + ); break; case VL_SHARED_ORDERS: { @@ -161,16 +156,11 @@ bool GenerateVehicleSortList(VehicleList break; case VL_DEPOT_LIST: - for (const Vehicle *v : Vehicle::Iterate()) { - if (v->type == vli.vtype && v->IsPrimaryVehicle()) { - for (const Order *order : v->Orders()) { - if (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index) { - list->push_back(v); - break; - } - } - } - } + FindVehiclesWithOrder( + [&vli](const Vehicle *v) { return v->type == vli.vtype; }, + [&vli](const Order *order) { return order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index; }, + [&list](const Vehicle *v) { list->push_back(v); } + ); break; default: return false; diff --git a/src/vehiclelist_func.h b/src/vehiclelist_func.h new file mode 100644 --- /dev/null +++ b/src/vehiclelist_func.h @@ -0,0 +1,46 @@ +/* + * 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 . + */ + +/** @file vehiclelist_func.h Functions and type for generating vehicle lists. */ + +#ifndef VEHICLELIST_FUNC_H +#define VEHICLELIST_FUNC_H + +#include "order_base.h" +#include "vehicle_base.h" + +/** + * Find vehicles matching an order. + * This can be used, e.g. to find all vehicles that stop at a particular station. + * @param veh_pred Vehicle selection predicate. This is called only for the first vehicle using the order list. + * @param ord_pred Order selection predicate. + * @param veh_func Called for each vehicle that matches both vehicle and order predicates. + **/ +template +void FindVehiclesWithOrder(VehiclePredicate veh_pred, OrderPredicate ord_pred, VehicleFunc veh_func) +{ + for (const OrderList *orderlist : OrderList::Iterate()) { + + /* We assume all vehicles sharing an order list match the condition. */ + const Vehicle *v = orderlist->GetFirstSharedVehicle(); + if (!veh_pred(v)) continue; + + /* Vehicle is a candidate, search for a matching order. */ + for (const Order *order = orderlist->GetFirstOrder(); order != nullptr; order = order->next) { + + if (!ord_pred(order)) continue; + + /* An order matches, we can add all shared vehicles to the list. */ + for (; v != nullptr; v = v->NextShared()) { + veh_func(v); + } + break; + } + } +} + +#endif /* VEHICLELIST_FUNC_H */