mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r13245) -Codechange: Use SmallVectors for generating vehicle lists, simplifying calling code somewhat.
This commit is contained in:
parent
32380e257c
commit
da8bb14cec
|
@ -18,6 +18,29 @@ struct SmallVector {
|
|||
free(this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all items from the list.
|
||||
*/
|
||||
void Clear()
|
||||
{
|
||||
/* In fact we just reset the item counter avoiding the need to
|
||||
* probably reallocate the same amount of memory the list was
|
||||
* previously using. */
|
||||
this->items = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the list down to the smallest block size boundary.
|
||||
*/
|
||||
void Compact()
|
||||
{
|
||||
uint capacity = Align(this->items, S);
|
||||
if (capacity >= this->capacity) return;
|
||||
|
||||
this->capacity = capacity;
|
||||
this->data = ReallocT(this->data, this->capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append an item and return it.
|
||||
*/
|
||||
|
@ -31,6 +54,14 @@ struct SmallVector {
|
|||
return &this->data[this->items++];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of items in the list.
|
||||
*/
|
||||
uint Length() const
|
||||
{
|
||||
return this->items;
|
||||
}
|
||||
|
||||
const T *Begin() const
|
||||
{
|
||||
return this->data;
|
||||
|
@ -60,6 +91,16 @@ struct SmallVector {
|
|||
{
|
||||
return &this->data[index];
|
||||
}
|
||||
|
||||
const T &operator[](uint index) const
|
||||
{
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
T &operator[](uint index)
|
||||
{
|
||||
return this->data[index];
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SMALLVEC_H */
|
||||
|
|
186
src/vehicle.cpp
186
src/vehicle.cpp
|
@ -50,6 +50,7 @@
|
|||
#include "depot_map.h"
|
||||
#include "animated_tile_func.h"
|
||||
#include "effectvehicle_base.h"
|
||||
#include "core/alloc_func.hpp"
|
||||
|
||||
#include "table/sprites.h"
|
||||
#include "table/strings.h"
|
||||
|
@ -988,9 +989,7 @@ void AgeVehicle(Vehicle *v)
|
|||
*/
|
||||
CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
{
|
||||
Vehicle **vl = NULL;
|
||||
uint16 engine_list_length = 0;
|
||||
uint16 engine_count = 0;
|
||||
VehicleList list;
|
||||
CommandCost return_value = CMD_ERROR;
|
||||
uint stop_command;
|
||||
VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
|
||||
|
@ -1009,14 +1008,14 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
uint32 id = p1;
|
||||
uint16 window_type = p2 & VLW_MASK;
|
||||
|
||||
engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, window_type);
|
||||
GenerateVehicleSortList(&list, vehicle_type, _current_player, id, window_type);
|
||||
} else {
|
||||
/* Get the list of vehicles in the depot */
|
||||
BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
|
||||
BuildDepotVehicleList(vehicle_type, tile, &list, NULL);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < engine_count; i++) {
|
||||
const Vehicle *v = vl[i];
|
||||
for (uint i = 0; i < list.Length(); i++) {
|
||||
const Vehicle *v = list[i];
|
||||
|
||||
if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
|
||||
|
||||
|
@ -1038,7 +1037,6 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
}
|
||||
}
|
||||
|
||||
free(vl);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
@ -1050,9 +1048,7 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
*/
|
||||
CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
{
|
||||
Vehicle **engines = NULL;
|
||||
uint16 engine_list_length = 0;
|
||||
uint16 engine_count = 0;
|
||||
VehicleList list;
|
||||
|
||||
CommandCost cost(EXPENSES_NEW_VEHICLES);
|
||||
uint sell_command;
|
||||
|
@ -1067,15 +1063,13 @@ CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
}
|
||||
|
||||
/* Get the list of vehicles in the depot */
|
||||
BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
|
||||
&engines, &engine_list_length, &engine_count);
|
||||
BuildDepotVehicleList(vehicle_type, tile, &list, &list);
|
||||
|
||||
for (uint i = 0; i < engine_count; i++) {
|
||||
CommandCost ret = DoCommand(tile, engines[i]->index, 1, flags, sell_command);
|
||||
for (uint i = 0; i < list.Length(); i++) {
|
||||
CommandCost ret = DoCommand(tile, list[i]->index, 1, flags, sell_command);
|
||||
if (CmdSucceeded(ret)) cost.AddCost(ret);
|
||||
}
|
||||
|
||||
free(engines);
|
||||
if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
|
||||
return cost;
|
||||
}
|
||||
|
@ -1091,9 +1085,7 @@ CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
*/
|
||||
CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
{
|
||||
Vehicle **vl = NULL;
|
||||
uint16 engine_list_length = 0;
|
||||
uint16 engine_count = 0;
|
||||
VehicleList list;
|
||||
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
|
||||
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
|
||||
bool all_or_nothing = HasBit(p2, 0);
|
||||
|
@ -1101,10 +1093,10 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
|
||||
|
||||
/* Get the list of vehicles in the depot */
|
||||
BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, &vl, &engine_list_length, &engine_count);
|
||||
BuildDepotVehicleList(vehicle_type, tile, &list, &list);
|
||||
|
||||
for (uint i = 0; i < engine_count; i++) {
|
||||
Vehicle *v = vl[i];
|
||||
for (uint i = 0; i < list.Length(); i++) {
|
||||
Vehicle *v = (Vehicle*)list[i];
|
||||
|
||||
/* Ensure that the vehicle completely in the depot */
|
||||
if (!v->IsInDepot()) continue;
|
||||
|
@ -1119,22 +1111,18 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uin
|
|||
* We should never reach this if DC_EXEC is set since then it should
|
||||
* have failed the estimation guess. */
|
||||
assert(!(flags & DC_EXEC));
|
||||
/* Now we will have to return an error.
|
||||
* This goto will leave the loop and it's ok to do so because
|
||||
* there is no point in the rest of the loop. */
|
||||
goto error;
|
||||
/* Now we will have to return an error. */
|
||||
return CMD_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cost.GetCost() == 0) {
|
||||
error:
|
||||
/* Either we didn't replace anything or something went wrong.
|
||||
* Either way we want to return an error and not execute this command. */
|
||||
cost = CMD_ERROR;
|
||||
}
|
||||
|
||||
free(vl);
|
||||
return cost;
|
||||
}
|
||||
|
||||
|
@ -1304,13 +1292,6 @@ CommandCost CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
|||
}
|
||||
|
||||
|
||||
/* Extend the list size for BuildDepotVehicleList() */
|
||||
static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
|
||||
{
|
||||
*engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
|
||||
*engine_list = ReallocT(*engine_list, *engine_list_length);
|
||||
}
|
||||
|
||||
/** Generates a list of vehicles inside a depot
|
||||
* Will enlarge allocated space for the list if they are too small, so it's ok to call with (pointer to NULL array, pointer to uninitised uint16, pointer to 0)
|
||||
* If one of the lists is not needed (say wagons when finding ships), all the pointers regarding that list should be set to NULL
|
||||
|
@ -1325,21 +1306,39 @@ static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *e
|
|||
*/
|
||||
void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
|
||||
{
|
||||
/* This function should never be called without an array to store results */
|
||||
assert(!(engine_list == NULL && type != VEH_TRAIN));
|
||||
assert(!(type == VEH_TRAIN && engine_list == NULL && wagon_list == NULL));
|
||||
VehicleList engines;
|
||||
VehicleList wagons;
|
||||
|
||||
/* Both array and the length should either be NULL to disable the list or both should not be NULL */
|
||||
assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
|
||||
assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
|
||||
BuildDepotVehicleList(type, tile, &engines, &wagons);
|
||||
|
||||
assert(!(engine_list != NULL && engine_count == NULL));
|
||||
assert(!(wagon_list != NULL && wagon_count == NULL));
|
||||
if (engines.Length() > 0) {
|
||||
*engine_list = ReallocT(*engine_list, engines.Length());
|
||||
memcpy(*engine_list, engines[0], sizeof(engines[0]) * engines.Length());
|
||||
}
|
||||
if (engine_count != NULL) *engine_count = engines.Length();
|
||||
|
||||
if (engine_count != NULL) *engine_count = 0;
|
||||
if (wagon_count != NULL) *wagon_count = 0;
|
||||
if (wagon_list != NULL && wagon_list != engine_list) {
|
||||
if (wagons.Length() > 0) {
|
||||
*wagon_list = ReallocT(*wagon_list, wagons.Length());
|
||||
memcpy(*wagon_list, wagons[0], sizeof(wagons[0]) * wagons.Length());
|
||||
}
|
||||
if (wagon_count != NULL) *wagon_count = wagons.Length();
|
||||
}
|
||||
}
|
||||
|
||||
Vehicle *v;
|
||||
/**
|
||||
* Generate a list of vehicles inside a depot.
|
||||
* @param type Type of vehicle
|
||||
* @param tile The tile the depot is located on
|
||||
* @param engines Pointer to list to add vehicles to
|
||||
* @param wagons Pointer to list to add wagons to (can be NULL)
|
||||
*/
|
||||
void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engines, VehicleList *wagons)
|
||||
{
|
||||
engines->Clear();
|
||||
if (wagons != NULL && wagons != engines) wagons->Clear();
|
||||
|
||||
const Vehicle *v;
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
/* General tests for all vehicle types */
|
||||
if (v->type != type) continue;
|
||||
|
@ -1348,9 +1347,8 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_l
|
|||
switch (type) {
|
||||
case VEH_TRAIN:
|
||||
if (v->u.rail.track != TRACK_BIT_DEPOT) continue;
|
||||
if (wagon_list != NULL && IsFreeWagon(v)) {
|
||||
if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
|
||||
(*wagon_list)[(*wagon_count)++] = v;
|
||||
if (wagons != NULL && IsFreeWagon(v)) {
|
||||
*wagons->Append() = v;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -1362,9 +1360,13 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_l
|
|||
|
||||
if (!v->IsPrimaryVehicle()) continue;
|
||||
|
||||
if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
|
||||
(*engine_list)[(*engine_count)++] = v;
|
||||
*engines->Append() = v;
|
||||
}
|
||||
|
||||
/* Ensure the lists are not wasting too much space. If the lists are fresh
|
||||
* (i.e. built within a command) then this will actually do nothing. */
|
||||
engines->Compact();
|
||||
if (wagons != NULL && wagons != engines) wagons->Compact();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1385,78 +1387,95 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_l
|
|||
*/
|
||||
uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
|
||||
{
|
||||
uint n = 0;
|
||||
VehicleList list;
|
||||
GenerateVehicleSortList(&list, type, owner, index, window_type);
|
||||
|
||||
if (list.Length() > 0) {
|
||||
*sort_list = ReallocT(*sort_list, list.Length());
|
||||
memcpy(*sort_list, list[0], sizeof(list[0]) * list.Length());
|
||||
}
|
||||
|
||||
return list.Length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a list of vehicles based on window type.
|
||||
* @param list Pointer to list to add vehicles to
|
||||
* @param type Type of vehicle
|
||||
* @param owner Player to generate list for
|
||||
* @param index This parameter has different meanings depending on window_type
|
||||
* <ul>
|
||||
* <li>VLW_STATION_LIST: index of station to generate a list for</li>
|
||||
* <li>VLW_SHARED_ORDERS: index of order to generate a list for<li>
|
||||
* <li>VLW_STANDARD: not used<li>
|
||||
* <li>VLW_DEPOT_LIST: TileIndex of the depot/hangar to make the list for</li>
|
||||
* <li>VLW_GROUP_LIST: index of group to generate a list for</li>
|
||||
* </ul>
|
||||
* @param window_type The type of window the list is for, using the VLW_ flags in vehicle_gui.h
|
||||
*/
|
||||
void GenerateVehicleSortList(VehicleList *list, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
|
||||
{
|
||||
list->Clear();
|
||||
|
||||
const Vehicle *v;
|
||||
|
||||
switch (window_type) {
|
||||
case VLW_STATION_LIST: {
|
||||
case VLW_STATION_LIST:
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->type == type && v->IsPrimaryVehicle()) {
|
||||
const Order *order;
|
||||
|
||||
FOR_VEHICLE_ORDERS(v, order) {
|
||||
if (order->IsType(OT_GOTO_STATION) && order->GetDestination() == index) {
|
||||
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
|
||||
(*sort_list)[n++] = v;
|
||||
*list->Append() = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VLW_SHARED_ORDERS: {
|
||||
case VLW_SHARED_ORDERS:
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
/* Find a vehicle with the order in question */
|
||||
if (v->orders != NULL && v->orders->index == index) break;
|
||||
}
|
||||
|
||||
if (v != NULL && v->orders != NULL && v->orders->index == index) {
|
||||
/* Only try to make the list if we found a vehicle using the order in question */
|
||||
for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
|
||||
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
|
||||
(*sort_list)[n++] = v;
|
||||
if (v->orders != NULL && v->orders->index == index) {
|
||||
/* Add all vehicles from this vehicle's shared order list */
|
||||
for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
|
||||
*list->Append() = v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VLW_STANDARD: {
|
||||
case VLW_STANDARD:
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->type == type && v->owner == owner && v->IsPrimaryVehicle()) {
|
||||
/* TODO find a better estimate on the total number of vehicles for current player */
|
||||
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
|
||||
(*sort_list)[n++] = v;
|
||||
*list->Append() = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VLW_DEPOT_LIST: {
|
||||
case VLW_DEPOT_LIST:
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->type == type && v->IsPrimaryVehicle()) {
|
||||
const Order *order;
|
||||
|
||||
FOR_VEHICLE_ORDERS(v, order) {
|
||||
if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == index) {
|
||||
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
|
||||
(*sort_list)[n++] = v;
|
||||
*list->Append() = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VLW_GROUP_LIST:
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->type == type && v->IsPrimaryVehicle() &&
|
||||
v->owner == owner && v->group_id == index) {
|
||||
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
|
||||
|
||||
(*sort_list)[n++] = v;
|
||||
*list->Append() = v;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1464,16 +1483,7 @@ uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array
|
|||
default: NOT_REACHED(); break;
|
||||
}
|
||||
|
||||
if ((n + 100) < *length_of_array) {
|
||||
/* We allocated way too much for sort_list.
|
||||
* Now we will reduce how much we allocated.
|
||||
* We will still make it have room for 50 extra vehicles to prevent having
|
||||
* to move the whole array if just one vehicle is added later */
|
||||
*length_of_array = n + 50;
|
||||
*sort_list = ReallocT(*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
|
||||
}
|
||||
|
||||
return n;
|
||||
list->Compact();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,8 +68,11 @@ void TrainConsistChanged(Vehicle *v);
|
|||
void TrainPowerChanged(Vehicle *v);
|
||||
Money GetTrainRunningCost(const Vehicle *v);
|
||||
|
||||
/* Old style list kept for migration */
|
||||
uint GenerateVehicleSortList(const Vehicle*** sort_list, uint16 *length_of_array, VehicleType type, PlayerID owner, uint32 index, uint16 window_type);
|
||||
void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count);
|
||||
void GenerateVehicleSortList(VehicleList *list, VehicleType type, PlayerID owner, uint32 index, uint16 window_type);
|
||||
void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine_list, VehicleList *wagon_list);
|
||||
CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id);
|
||||
void VehicleEnterDepot(Vehicle *v);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#define VEHICLE_TYPE_H
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
#include "misc/smallvec.h"
|
||||
|
||||
typedef uint16 VehicleID;
|
||||
|
||||
|
@ -56,4 +57,6 @@ enum DepotCommand {
|
|||
DEPOT_COMMAND_MASK = 0xF,
|
||||
};
|
||||
|
||||
typedef SmallVector<const Vehicle*, 32> VehicleList;
|
||||
|
||||
#endif /* VEHICLE_TYPE_H */
|
||||
|
|
Loading…
Reference in New Issue