Changeset - r28405:f5d30cdebeff
[Not reviewed]
master
0 3 1
Peter Nelson - 11 months ago 2024-01-05 18:59:38
peter1138@openttd.org
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.
4 files changed with 71 insertions and 41 deletions:
0 comments (0 inline, 0 general)
src/CMakeLists.txt
Show inline comments
 
@@ -510,6 +510,7 @@ add_files(
 
    vehiclelist.cpp
 
    vehiclelist.h
 
    vehiclelist_cmd.h
 
    vehiclelist_func.h
 
    viewport.cpp
 
    viewport_cmd.h
 
    viewport_func.h
src/script/api/script_vehiclelist.cpp
Show inline comments
 
@@ -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)
src/vehiclelist.cpp
Show inline comments
 
@@ -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;
src/vehiclelist_func.h
Show inline comments
 
new file 100644
 
/*
 
 * 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 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 <class VehiclePredicate, class OrderPredicate, class VehicleFunc>
 
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 */
0 comments (0 inline, 0 general)