1
0
Fork 0

Codechange: do not use MallocT for the pool

Needed to make the placement new operator use Tindex over size_t because of
ambiguity for the delete operator variant that also has the size.
pull/13632/head
Rubidium 2025-02-20 18:59:28 +01:00 committed by rubidium42
parent 426b03b31a
commit 09716dba75
24 changed files with 80 additions and 96 deletions

View File

@ -583,7 +583,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid(
c = new Company(STR_SV_UNNAMED, is_ai);
} else {
if (Company::IsValidID(company)) return nullptr;
c = new (company.base()) Company(STR_SV_UNNAMED, is_ai);
c = new (company) Company(STR_SV_UNNAMED, is_ai);
}
c->colour = colour;

View File

@ -10,9 +10,8 @@
#ifndef POOL_FUNC_HPP
#define POOL_FUNC_HPP
#include "alloc_func.hpp"
#include "bitmath_func.hpp"
#include "mem_func.hpp"
#include "math_func.hpp"
#include "pool_type.hpp"
#include "../error_func.h"
@ -27,23 +26,6 @@
requires std::is_base_of_v<PoolIDBase, Tindex> \
type Pool<Titem, Tindex, Tgrowth_step, Tpool_type, Tcache>
/**
* Create a clean pool.
* @param name The name for the pool.
*/
DEFINE_POOL_METHOD(inline)::Pool(const char *name) :
PoolBase(Tpool_type),
name(name),
first_free(0),
first_unused(0),
items(0),
#ifdef WITH_ASSERT
checked(0),
#endif /* WITH_ASSERT */
cleaning(false),
alloc_cache(nullptr)
{ }
/**
* Resizes the pool so 'index' can be addressed
* @param index index we will allocate later
@ -114,7 +96,7 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
item = reinterpret_cast<Titem *>(this->alloc_cache);
this->alloc_cache = this->alloc_cache->next;
} else {
item = reinterpret_cast<Titem *>(MallocT<uint8_t>(size));
item = reinterpret_cast<Titem *>(this->allocator.allocate(size));
}
this->data[index] = item;
SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
@ -169,11 +151,12 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
/**
* Deallocates memory used by this index and marks item as free
* @param size the size of the freed object
* @param index item to deallocate
* @pre unit is allocated (non-nullptr)
* @note 'delete nullptr' doesn't cause call of this function, so it is safe
*/
DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
DEFINE_POOL_METHOD(void)::FreeItem(size_t size, size_t index)
{
assert(index < this->data.size());
assert(this->data[index] != nullptr);
@ -182,7 +165,7 @@ DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
ac->next = this->alloc_cache;
this->alloc_cache = ac;
} else {
free(this->data[index]);
this->allocator.deallocate(reinterpret_cast<uint8_t*>(this->data[index]), size);
}
this->data[index] = nullptr;
this->first_free = std::min(this->first_free, index);
@ -212,7 +195,7 @@ DEFINE_POOL_METHOD(void)::CleanPool()
while (this->alloc_cache != nullptr) {
AllocCache *ac = this->alloc_cache;
this->alloc_cache = ac->next;
free(ac);
this->allocator.deallocate(reinterpret_cast<uint8_t*>(ac), sizeof(Titem));
}
}
}
@ -227,7 +210,7 @@ DEFINE_POOL_METHOD(void)::CleanPool()
#define INSTANTIATE_POOL_METHODS(name) \
template void * name ## Pool::GetNew(size_t size); \
template void * name ## Pool::GetNew(size_t size, size_t index); \
template void name ## Pool::FreeItem(size_t index); \
template void name ## Pool::FreeItem(size_t size, size_t index); \
template void name ## Pool::CleanPool();
#endif /* POOL_FUNC_HPP */

View File

@ -125,7 +125,7 @@ private:
* @tparam Tindex Type of the index for this pool
* @tparam Tgrowth_step Size of growths; if the pool is full increase the size by this amount
* @tparam Tpool_type Type of this pool
* @tparam Tcache Whether to perform 'alloc' caching, i.e. don't actually free/malloc just reuse the memory
* @tparam Tcache Whether to perform 'alloc' caching, i.e. don't actually deallocated/allocate just reuse the memory
* @warning when Tcache is enabled *all* instances of this pool's item must be of the same size.
*/
template <class Titem, typename Tindex, size_t Tgrowth_step, PoolType Tpool_type = PoolType::Normal, bool Tcache = false>
@ -137,20 +137,20 @@ public:
using BitmapStorage = size_t;
static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
const char * const name; ///< Name of this pool
const char * const name = nullptr; ///< Name of this pool
size_t first_free; ///< No item with index lower than this is free (doesn't say anything about this one!)
size_t first_unused; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !)
size_t items; ///< Number of used indexes (non-nullptr)
size_t first_free = 0; ///< No item with index lower than this is free (doesn't say anything about this one!)
size_t first_unused = 0; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !)
size_t items = 0; ///< Number of used indexes (non-nullptr)
#ifdef WITH_ASSERT
size_t checked; ///< Number of items we checked for
size_t checked = 0; ///< Number of items we checked for
#endif /* WITH_ASSERT */
bool cleaning; ///< True if cleaning pool (deleting all items)
bool cleaning = false; ///< True if cleaning pool (deleting all items)
std::vector<Titem *> data; ///< Pointers to Titem
std::vector<BitmapStorage> used_bitmap; ///< Bitmap of used indices.
std::vector<Titem *> data{}; ///< Pointers to Titem
std::vector<BitmapStorage> used_bitmap{}; ///< Bitmap of used indices.
Pool(const char *name);
Pool(const char *name) : PoolBase(Tpool_type), name(name) {}
void CleanPool() override;
/**
@ -304,12 +304,12 @@ public:
* @param p memory to free
* @note the item has to be allocated in the pool!
*/
inline void operator delete(void *p)
inline void operator delete(void *p, size_t size)
{
if (p == nullptr) return;
Titem *pn = static_cast<Titem *>(p);
assert(pn == Tpool->Get(Pool::GetRawIndex(pn->index)));
Tpool->FreeItem(Pool::GetRawIndex(pn->index));
Tpool->FreeItem(size, Pool::GetRawIndex(pn->index));
}
/**
@ -320,9 +320,9 @@ public:
* @note can never fail (return nullptr), use CanAllocate() to check first!
* @pre index has to be unused! Else it will crash
*/
inline void *operator new(size_t size, size_t index)
inline void *operator new(size_t size, Tindex index)
{
return Tpool->GetNew(size, index);
return Tpool->GetNew(size, index.base());
}
/**
@ -449,7 +449,8 @@ private:
};
/** Cache of freed pointers */
AllocCache *alloc_cache;
AllocCache *alloc_cache = nullptr;
std::allocator<uint8_t> allocator{};
void *AllocateItem(size_t size, size_t index);
void ResizeFor(size_t index);
@ -458,7 +459,7 @@ private:
void *GetNew(size_t size);
void *GetNew(size_t size, size_t index);
void FreeItem(size_t index);
void FreeItem(size_t size, size_t index);
static constexpr size_t GetRawIndex(size_t index) { return index; }
template <typename T> requires std::is_base_of_v<PoolIDBase, T>

View File

@ -610,7 +610,7 @@ void SetupEngines()
assert(std::size(mapping) >= _engine_counts[type]);
for (const EngineIDMapping &eid : mapping) {
new (eid.engine.base()) Engine(type, eid.internal_id);
new (eid.engine) Engine(type, eid.internal_id);
}
}
}

View File

@ -45,7 +45,7 @@ struct ERNWChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
EngineRenew *er = new (index) EngineRenew();
EngineRenew *er = new (EngineRenewID(index)) EngineRenew();
SlObject(er, slt);
/* Advanced vehicle lists, ungrouped vehicles got added */

View File

@ -162,7 +162,7 @@ struct CAPAChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
CargoPacket *cp = new (index) CargoPacket();
CargoPacket *cp = new (CargoPacketID(index)) CargoPacket();
SlObject(cp, slt);
}
}

View File

@ -536,7 +536,7 @@ struct PLYRChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Company *c = new (index) Company();
Company *c = new (CompanyID(index)) Company();
SlObject(c, slt);
_company_colours[index] = c->colour;
}

View File

@ -49,7 +49,7 @@ struct DEPTChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Depot *depot = new (index) Depot();
Depot *depot = new (DepotID(index)) Depot();
SlObject(depot, slt);
/* Set the town 'pointer' so we can restore it later. */

View File

@ -108,7 +108,7 @@ struct CAPYChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
CargoPayment *cp = new (index) CargoPayment();
CargoPayment *cp = new (CargoPaymentID(index)) CargoPayment();
SlObject(cp, slt);
}
}

View File

@ -44,7 +44,7 @@ struct GOALChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Goal *s = new (index) Goal();
Goal *s = new (GoalID(index)) Goal();
SlObject(s, slt);
}
}

View File

@ -50,7 +50,7 @@ struct GRPSChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Group *g = new (index) Group();
Group *g = new (GroupID(index)) Group();
SlObject(g, slt);
if (IsSavegameVersionBefore(SLV_189)) g->parent = GroupID::Invalid();

View File

@ -213,7 +213,7 @@ struct INDYChunkHandler : ChunkHandler {
SlIndustryProduced::ResetOldStructure();
while ((index = SlIterateArray()) != -1) {
Industry *i = new (index) Industry();
Industry *i = new (IndustryID(index)) Industry();
SlObject(i, slt);
/* Before savegame version 161, persistent storages were not stored in a pool. */

View File

@ -45,7 +45,7 @@ struct LEAEChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
LeagueTableElement *lte = new (index) LeagueTableElement();
LeagueTableElement *lte = new (LeagueTableElementID(index)) LeagueTableElement();
SlObject(lte, slt);
}
}
@ -76,7 +76,7 @@ struct LEATChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
LeagueTable *lt = new (index) LeagueTable();
LeagueTable *lt = new (LeagueTableID(index)) LeagueTable();
SlObject(lt, slt);
}
}

View File

@ -277,7 +277,7 @@ struct LGRPChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
LinkGraph *lg = new (index) LinkGraph();
LinkGraph *lg = new (LinkGraphID(index)) LinkGraph();
SlObject(lg, slt);
}
}
@ -305,7 +305,7 @@ struct LGRJChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
LinkGraphJob *lgj = new (index) LinkGraphJob();
LinkGraphJob *lgj = new (LinkGraphJobID(index)) LinkGraphJob();
SlObject(lgj, slt);
}
}

View File

@ -49,7 +49,7 @@ struct OBJSChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Object *o = new (index) Object();
Object *o = new (ObjectID(index)) Object();
SlObject(o, slt);
}
}

View File

@ -615,7 +615,7 @@ static const OldChunks town_chunk[] = {
static bool LoadOldTown(LoadgameState &ls, int num)
{
Town *t = new (num) Town();
Town *t = new (TownID(num)) Town();
if (!LoadChunk(ls, t, town_chunk)) return false;
if (t->xy != 0) {
@ -640,7 +640,7 @@ static bool LoadOldOrder(LoadgameState &ls, int num)
{
if (!LoadChunk(ls, nullptr, order_chunk)) return false;
Order *o = new (num) Order();
Order *o = new (OrderID(num)) Order();
o->AssignOrder(UnpackOldOrder(_old_order));
if (o->IsType(OT_NOTHING)) {
@ -682,7 +682,7 @@ static const OldChunks depot_chunk[] = {
static bool LoadOldDepot(LoadgameState &ls, int num)
{
Depot *d = new (num) Depot();
Depot *d = new (DepotID(num)) Depot();
if (!LoadChunk(ls, d, depot_chunk)) return false;
if (d->xy != 0) {
@ -770,7 +770,7 @@ static const OldChunks station_chunk[] = {
static bool LoadOldStation(LoadgameState &ls, int num)
{
Station *st = new (num) Station();
Station *st = new (StationID(num)) Station();
_current_station_id = st->index;
if (!LoadChunk(ls, st, station_chunk)) return false;
@ -852,7 +852,7 @@ static const OldChunks industry_chunk[] = {
static bool LoadOldIndustry(LoadgameState &ls, int num)
{
Industry *i = new (num) Industry();
Industry *i = new (IndustryID(num)) Industry();
if (!LoadChunk(ls, i, industry_chunk)) return false;
if (i->location.tile != 0) {
@ -978,7 +978,7 @@ static const OldChunks _company_chunk[] = {
static bool LoadOldCompany(LoadgameState &ls, int num)
{
Company *c = new (num) Company();
Company *c = new (CompanyID(num)) Company();
_current_company_id = (CompanyID)num;
@ -1260,12 +1260,12 @@ bool LoadOldVehicle(LoadgameState &ls, int num)
default: return false;
case 0x00 /* VEH_INVALID */: v = nullptr; break;
case 0x25 /* MONORAIL */:
case 0x20 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break;
case 0x21 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break;
case 0x22 /* VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break;
case 0x23 /* VEH_AIRCRAFT */: v = new (_current_vehicle_id) Aircraft(); break;
case 0x24 /* VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break;
case 0x26 /* VEH_DISASTER */: v = new (_current_vehicle_id) DisasterVehicle(); break;
case 0x20 /* VEH_TRAIN */: v = new (VehicleID(_current_vehicle_id)) Train(); break;
case 0x21 /* VEH_ROAD */: v = new (VehicleID(_current_vehicle_id)) RoadVehicle(); break;
case 0x22 /* VEH_SHIP */: v = new (VehicleID(_current_vehicle_id)) Ship(); break;
case 0x23 /* VEH_AIRCRAFT */: v = new (VehicleID(_current_vehicle_id)) Aircraft(); break;
case 0x24 /* VEH_EFFECT */: v = new (VehicleID(_current_vehicle_id)) EffectVehicle(); break;
case 0x26 /* VEH_DISASTER */: v = new (VehicleID(_current_vehicle_id)) DisasterVehicle(); break;
}
if (!LoadChunk(ls, v, vehicle_chunk)) return false;
@ -1338,12 +1338,12 @@ bool LoadOldVehicle(LoadgameState &ls, int num)
switch (ReadByte(ls)) {
default: SlErrorCorrupt("Invalid vehicle type");
case 0x00 /* VEH_INVALID */: v = nullptr; break;
case 0x10 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break;
case 0x11 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break;
case 0x12 /* VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break;
case 0x13 /* VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft(); break;
case 0x14 /* VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break;
case 0x15 /* VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break;
case 0x10 /* VEH_TRAIN */: v = new (VehicleID(_current_vehicle_id)) Train(); break;
case 0x11 /* VEH_ROAD */: v = new (VehicleID(_current_vehicle_id)) RoadVehicle(); break;
case 0x12 /* VEH_SHIP */: v = new (VehicleID(_current_vehicle_id)) Ship(); break;
case 0x13 /* VEH_AIRCRAFT*/: v = new (VehicleID(_current_vehicle_id)) Aircraft(); break;
case 0x14 /* VEH_EFFECT */: v = new (VehicleID(_current_vehicle_id)) EffectVehicle(); break;
case 0x15 /* VEH_DISASTER*/: v = new (VehicleID(_current_vehicle_id)) DisasterVehicle(); break;
}
if (!LoadChunk(ls, v, vehicle_chunk)) return false;
@ -1413,7 +1413,7 @@ static const OldChunks sign_chunk[] = {
static bool LoadOldSign(LoadgameState &ls, int num)
{
Sign *si = new (num) Sign();
Sign *si = new (SignID(num)) Sign();
if (!LoadChunk(ls, si, sign_chunk)) return false;
if (_old_string_id != 0) {
@ -1477,7 +1477,7 @@ static const OldChunks subsidy_chunk[] = {
static bool LoadOldSubsidy(LoadgameState &ls, int num)
{
Subsidy *s = new (num) Subsidy();
Subsidy *s = new (SubsidyID(num)) Subsidy();
bool ret = LoadChunk(ls, s, subsidy_chunk);
if (!IsValidCargoType(s->cargo_type)) delete s;
return ret;

View File

@ -148,7 +148,7 @@ struct ORDRChunkHandler : ChunkHandler {
SlCopy(&orders[0], len, SLE_UINT16);
for (size_t i = 0; i < len; ++i) {
Order *o = new (i) Order();
Order *o = new (OrderID(static_cast<uint32_t>(i))) Order();
o->AssignOrder(UnpackVersion4Order(orders[i]));
}
} else if (IsSavegameVersionBefore(SLV_5, 2)) {
@ -158,7 +158,7 @@ struct ORDRChunkHandler : ChunkHandler {
SlCopy(&orders[0], len, SLE_UINT32);
for (size_t i = 0; i < len; ++i) {
new (i) Order(GB(orders[i], 0, 8), GB(orders[i], 8, 8), GB(orders[i], 16, 16));
new (OrderID(static_cast<uint32_t>(i))) Order(GB(orders[i], 0, 8), GB(orders[i], 8, 8), GB(orders[i], 16, 16));
}
}
@ -181,7 +181,7 @@ struct ORDRChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Order *order = new (index) Order();
Order *order = new (OrderID(index)) Order();
SlObject(order, slt);
}
}
@ -229,7 +229,7 @@ struct ORDLChunkHandler : ChunkHandler {
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderList *list = new (index) OrderList(0);
OrderList *list = new (OrderListID(index)) OrderList(0);
SlObject(list, slt);
}
@ -294,7 +294,7 @@ struct BKORChunkHandler : ChunkHandler {
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup();
OrderBackup *ob = new (OrderBackupID(index)) OrderBackup();
SlObject(ob, slt);
}
}

View File

@ -49,7 +49,7 @@ struct SIGNChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Sign *si = new (index) Sign();
Sign *si = new (SignID(index)) Sign();
SlObject(si, slt);
/* Before version 6.1, signs didn't have owner.
* Before version 83, invalid signs were determined by si->str == 0.

View File

@ -79,7 +79,7 @@ void MoveBuoysToWaypoints()
/* Stations and waypoints are in the same pool, so if a station
* is deleted there must be place for a Waypoint. */
assert(Waypoint::CanAllocateItem());
Waypoint *wp = new (index.base()) Waypoint(xy);
Waypoint *wp = new (index) Waypoint(xy);
wp->town = town;
wp->string_id = train ? STR_SV_STNAME_WAYPOINT : STR_SV_STNAME_BUOY;
wp->name = name;
@ -512,7 +512,7 @@ struct STNSChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Station *st = new (index) Station();
Station *st = new (StationID(index)) Station();
_waiting_acceptance = 0;
SlObject(st, slt);
@ -714,7 +714,7 @@ struct STNNChunkHandler : ChunkHandler {
while ((index = SlIterateArray()) != -1) {
bool waypoint = static_cast<StationFacilities>(SlReadByte()).Test(StationFacility::Waypoint);
BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station();
BaseStation *bst = waypoint ? (BaseStation *)new (StationID(index)) Waypoint() : new (StationID(index)) Station();
SlObject(bst, slt);
}
}
@ -752,7 +752,7 @@ struct ROADChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
RoadStop *rs = new (index) RoadStop(INVALID_TILE);
RoadStop *rs = new (RoadStopID(index)) RoadStop(INVALID_TILE);
SlObject(rs, slt);
}

View File

@ -35,7 +35,7 @@ struct PSACChunkHandler : ChunkHandler {
while ((index = SlIterateArray()) != -1) {
assert(PersistentStorage::CanAllocateItem());
PersistentStorage *ps = new (index) PersistentStorage(0, 0, TileIndex{});
PersistentStorage *ps = new (PersistentStorageID(index)) PersistentStorage(0, 0, TileIndex{});
SlObject(ps, slt);
}
}

View File

@ -58,7 +58,7 @@ struct STPEChunkHandler : ChunkHandler {
int index;
uint32_t max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPageElement *s = new (index) StoryPageElement();
StoryPageElement *s = new (StoryPageElementID(index)) StoryPageElement();
SlObject(s, slt);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;
@ -100,7 +100,7 @@ struct STPAChunkHandler : ChunkHandler {
int index;
uint32_t max_sort_value = 0;
while ((index = SlIterateArray()) != -1) {
StoryPage *s = new (index) StoryPage();
StoryPage *s = new (StoryPageID(index)) StoryPage();
SlObject(s, slt);
if (s->sort_value > max_sort_value) {
max_sort_value = s->sort_value;

View File

@ -48,7 +48,7 @@ struct SUBSChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Subsidy *s = new (index) Subsidy();
Subsidy *s = new (SubsidyID(index)) Subsidy();
SlObject(s, slt);
}
}

View File

@ -300,7 +300,7 @@ struct CITYChunkHandler : ChunkHandler {
int index;
while ((index = SlIterateArray()) != -1) {
Town *t = new (index) Town();
Town *t = new (TownID(index)) Town();
SlObject(t, slt);
if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_END) && GetStringTab(t->townnametype) != TEXT_TAB_OLD_CUSTOM) {

View File

@ -1124,12 +1124,12 @@ struct VEHSChunkHandler : ChunkHandler {
VehicleType vtype = (VehicleType)SlReadByte();
switch (vtype) {
case VEH_TRAIN: v = new (index) Train(); break;
case VEH_ROAD: v = new (index) RoadVehicle(); break;
case VEH_SHIP: v = new (index) Ship(); break;
case VEH_AIRCRAFT: v = new (index) Aircraft(); break;
case VEH_EFFECT: v = new (index) EffectVehicle(); break;
case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
case VEH_TRAIN: v = new (VehicleID(index)) Train(); break;
case VEH_ROAD: v = new (VehicleID(index)) RoadVehicle(); break;
case VEH_SHIP: v = new (VehicleID(index)) Ship(); break;
case VEH_AIRCRAFT: v = new (VehicleID(index)) Aircraft(); break;
case VEH_EFFECT: v = new (VehicleID(index)) EffectVehicle(); break;
case VEH_DISASTER: v = new (VehicleID(index)) DisasterVehicle(); break;
case VEH_INVALID: // Savegame shouldn't contain invalid vehicles
default: SlErrorCorrupt("Invalid vehicle type");
}