=== ai/default/default.c
==================================================================
--- ai/default/default.c (revision 313)
+++ ai/default/default.c (local)
@@ -439,14 +439,18 @@
static Town *AiFindRandomTown(void)
{
- Town *t = GetTown(RandomRange(_total_towns));
- return (t->xy != 0) ? t : NULL;
+ return GetRandomTown();
}
static Industry *AiFindRandomIndustry(void)
{
- Industry *i = GetIndustry(RandomRange(_total_industries));
- return (i->xy != 0) ? i : NULL;
+ /* XXX: There used to be code here that would do a RandomRange() and see if
+ * the found index was in use, if not, return NULL. This means that
+ * depending on the amount of "index fragmentation", this function would
+ * regularly fail to find an industry.
+ * This function will now always find an industry, except when the pool is
+ * empty... This might mean a functional behaviour, is that bad? */
+ return GetRandomIndustry();
}
static void AiFindSubsidyIndustryRoute(FoundRoute *fr)
@@ -1388,7 +1392,7 @@
t = AiFindRandomTown();
if (t != NULL) {
// Find a random oil rig industry
- in = GetIndustry(RandomRange(_total_industries));
+ in = GetRandomIndustry();
if (in != NULL && in->type == IT_OIL_RIG) {
if (DistanceManhattan(t->xy, in->xy) < 60)
break;
@@ -3563,8 +3567,8 @@
p->ai.state = AIS_1;
// Get a list of all stations that are in use by a vehicle
- in_use = malloc(GetStationPoolSize());
- memset(in_use, 0, GetStationPoolSize());
+ in_use = malloc(GetNumStationsUsed());
+ memset(in_use, 0, GetNumStationsUsed());
FOR_ALL_ORDERS(ord) {
if (ord->type == OT_GOTO_STATION) in_use[ord->station] = 1;
}
=== ai/trolly/trolly.c
==================================================================
--- ai/trolly/trolly.c (revision 313)
+++ ai/trolly/trolly.c (local)
@@ -388,9 +388,9 @@
if (p->ainew.temp == -1) {
// First, we pick a random spot to search from
if (p->ainew.from_type == AI_CITY)
- p->ainew.temp = AI_RandomRange(_total_towns);
+ p->ainew.temp = AI_RandomRange(GetNumTownsUsed());
else
- p->ainew.temp = AI_RandomRange(_total_industries);
+ p->ainew.temp = AI_RandomRange(GetNumIndustriesUsed());
}
if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) {
@@ -399,9 +399,9 @@
// to try again
p->ainew.temp++;
if (p->ainew.from_type == AI_CITY) {
- if (p->ainew.temp >= (int)_total_towns) p->ainew.temp = 0;
+ if (p->ainew.temp >= (int)GetNumTownsUsed()) p->ainew.temp = 0;
} else {
- if (p->ainew.temp >= _total_industries) p->ainew.temp = 0;
+ if (p->ainew.temp >= (int)GetNumIndustriesUsed()) p->ainew.temp = 0;
}
// Don't do an attempt if we are trying the same id as the last time...
@@ -423,9 +423,9 @@
if (p->ainew.temp == -1) {
// First, we pick a random spot to search to
if (p->ainew.to_type == AI_CITY)
- p->ainew.temp = AI_RandomRange(_total_towns);
+ p->ainew.temp = AI_RandomRange(GetNumTownsUsed());
else
- p->ainew.temp = AI_RandomRange(_total_industries);
+ p->ainew.temp = AI_RandomRange(GetNumIndustriesUsed());
}
// The same city is not allowed
@@ -526,9 +526,9 @@
// to try again
p->ainew.temp++;
if (p->ainew.to_type == AI_CITY) {
- if (p->ainew.temp >= (int)_total_towns) p->ainew.temp = 0;
+ if (p->ainew.temp >= (int)GetNumTownsUsed()) p->ainew.temp = 0;
} else {
- if (p->ainew.temp >= _total_industries) p->ainew.temp = 0;
+ if (p->ainew.temp >= (int)GetNumIndustriesUsed()) p->ainew.temp = 0;
}
// Don't do an attempt if we are trying the same id as the last time...
=== aircraft_cmd.c
==================================================================
--- aircraft_cmd.c (revision 313)
+++ aircraft_cmd.c (local)
@@ -137,10 +137,10 @@
int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
int32 value;
- Vehicle *vl[3], *v, *u, *w;
UnitID unit_num;
const AircraftVehicleInfo *avi;
Engine *e;
+ uint num_vehicles;
if (!IsEngineBuildable(p1, VEH_Aircraft)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
@@ -154,9 +154,10 @@
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
avi = AircraftVehInfo(p1);
+ num_vehicles = ( (avi->subtype & 1) == 0 ? 3 : 2 );
+
// allocate 2 or 3 vehicle structs, depending on type
- if (!AllocateVehicles(vl, (avi->subtype & 1) == 0 ? 3 : 2) ||
- IsOrderPoolFull()) {
+ if (GetNumVehiclesFree() < num_vehicles || IsOrderPoolFull()) {
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
}
@@ -165,8 +166,9 @@
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
if (flags & DC_EXEC) {
- uint x;
- uint y;
+ Vehicle *vl[3], *v, *u, *w;
+ uint x, y;
+ AllocateVehicles(vl, num_vehicles);
v = vl[0];
u = vl[1];
@@ -332,7 +334,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -361,7 +363,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -397,7 +399,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -417,7 +419,7 @@
const Station *st = GetStation(next_airport_index);
// If an airport doesn't have terminals (so no landing space for airports),
// it surely doesn't have any hangars
- if (!IsValidStation(st) || st->airport_tile == 0 || GetAirport(st->airport_type)->nof_depots == 0) {
+ if (st != NULL || st->airport_tile == 0 || GetAirport(st->airport_type)->nof_depots == 0) {
StationID station;
if (p2 != 0) return CMD_ERROR;
@@ -447,7 +449,6 @@
return 0;
}
-
/** Refits an aircraft to the specified cargo type.
* @param tile unused
* @param p1 vehicle ID of the aircraft to refit
@@ -462,7 +463,7 @@
CargoID new_cid = GB(p2, 0, 8);
const AircraftVehicleInfo *avi;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
=== console_cmds.c
==================================================================
--- console_cmds.c (revision 313)
+++ console_cmds.c (local)
@@ -132,15 +132,13 @@
}
FOR_ALL_VEHICLES(v) {
- if (IsValidVehicle(v)) {
- /* Code ripped from CmdStartStopTrain. Can't call it, because of
- * ownership problems, so we'll duplicate some code, for now */
- if (v->type == VEH_Train)
- v->u.rail.days_since_order_progr = 0;
- v->vehstatus |= VS_STOPPED;
- InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
- InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- }
+ /* Code ripped from CmdStartStopTrain. Can't call it, because of
+ * ownership problems, so we'll duplicate some code, for now */
+ if (v->type == VEH_Train)
+ v->u.rail.days_since_order_progr = 0;
+ v->vehstatus |= VS_STOPPED;
+ InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+ InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
return true;
}
=== depot.c
==================================================================
--- depot.c (revision 313)
+++ depot.c (local)
@@ -11,24 +11,16 @@
#include "order.h"
enum {
- /* Max depots: 64000 (8 * 8000) */
- DEPOT_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */
- DEPOT_POOL_MAX_BLOCKS = 8000,
+ DEPOT_PUDDLE_SIZE = 8,
};
-/**
- * Called if a new block is added to the depot-pool
- */
-static void DepotPoolNewBlock(uint start_item)
-{
- Depot *depot;
+/* Forward declare init/destroy procs, referenced by INDEXED_POOL */
+static void InitializeDepot(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyDepot(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_DEPOTS_FROM(depot, start_item)
- depot->index = start_item++;
-}
-
/* Initialize the town-pool */
-MemoryPool _depot_pool = { "Depots", DEPOT_POOL_MAX_BLOCKS, DEPOT_POOL_BLOCK_SIZE_BITS, sizeof(Depot), &DepotPoolNewBlock, NULL, 0, 0, NULL };
+static IndexedPoolSettings _depot_pool_settings = INDEXED_POOL(Depot, DEPOT_PUDDLE_SIZE);
+IndexedPool _depot_pool;
/**
@@ -48,61 +40,34 @@
return NULL;
}
-/**
- * Allocate a new depot
- */
-Depot *AllocateDepot(void)
+static void InitializeDepot(const IndexedPool* pool, void* drop, DropIndex index)
{
- Depot *depot;
-
- FOR_ALL_DEPOTS(depot) {
- if (!IsValidDepot(depot)) {
- uint index = depot->index;
-
- memset(depot, 0, sizeof(Depot));
- depot->index = index;
-
- return depot;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_depot_pool))
- return AllocateDepot();
-
- return NULL;
+ ZERO_AND_INDEX(Depot, drop);
}
/**
- * Delete a depot
+ * Clean up a depot
*/
-void DoDeleteDepot(TileIndex tile)
+static void DestroyDepot(const IndexedPool* pool, void* drop, DropIndex index)
{
Order order;
- Depot *depot;
+ Depot *depot = (Depot*)drop;
- /* Get the depot */
- depot = GetDepotByTile(tile);
-
/* Clear the tile */
- DoClearSquare(tile);
+ DoClearSquare(depot->xy);
- /* Clear the depot */
- depot->xy = 0;
-
/* Clear the depot from all order-lists */
order.type = OT_GOTO_DEPOT;
order.station = depot->index;
- DeleteDestinationFromVehicleOrder(order);
+ DeleteOrderFromAllVehicles(order);
/* Delete the depot-window */
- DeleteWindowById(WC_VEHICLE_DEPOT, tile);
+ DeleteWindowById(WC_VEHICLE_DEPOT, depot->xy);
}
-void InitializeDepot(void)
+void InitializeDepots(void)
{
- CleanPool(&_depot_pool);
- AddBlockToPool(&_depot_pool);
+ IndexedPoolInitialize(&_depot_pool, &_depot_pool_settings);
}
@@ -118,10 +83,8 @@
Depot *depot;
FOR_ALL_DEPOTS(depot) {
- if (IsValidDepot(depot)) {
- SlSetArrayIndex(depot->index);
- SlObject(depot, _depot_desc);
- }
+ SlSetArrayIndex(depot->index);
+ SlObject(depot, _depot_desc);
}
}
@@ -130,13 +93,10 @@
int index;
while ((index = SlIterateArray()) != -1) {
- Depot *depot;
-
- if (!AddBlockIfNeeded(&_depot_pool, index))
+ if (IndexedPoolAllocateIndex(&_depot_pool, index) == NULL)
error("Depots: failed loading savegame: too many depots");
- depot = GetDepot(index);
- SlObject(depot, _depot_desc);
+ SlObject(GetDepot(index), _depot_desc);
}
}
=== depot.h
==================================================================
--- depot.h (revision 313)
+++ depot.h (local)
@@ -16,41 +16,21 @@
struct Depot {
TileIndex xy;
TownID town_index;
- StationID index;
+ DepotID index; /* TODO: StationID? */
};
-extern MemoryPool _depot_pool;
+extern IndexedPool _depot_pool;
-/**
- * Get the pointer to the depot with index 'index'
- */
-static inline Depot *GetDepot(uint index)
-{
- return (Depot*)GetItemFromPool(&_depot_pool, index);
-}
+#define FOR_ALL_DEPOTS(d) FOR_ALL_IN_POOL(_depot_pool, d)
+INDEXED_POOL_FUNCTIONS(Depot, Depots, _depot_pool)
-/**
- * Get the current size of the DepotPool
- */
-static inline uint16 GetDepotPoolSize(void)
-{
- return _depot_pool.total_items;
-}
-
-static inline bool IsDepotIndex(uint index)
-{
- return index < GetDepotPoolSize();
-}
-
-#define FOR_ALL_DEPOTS_FROM(d, start) for (d = GetDepot(start); d != NULL; d = (d->index + 1 < GetDepotPoolSize()) ? GetDepot(d->index + 1) : NULL)
-#define FOR_ALL_DEPOTS(d) FOR_ALL_DEPOTS_FROM(d, 0)
-
#define MIN_SERVINT_PERCENT 5
#define MAX_SERVINT_PERCENT 90
#define MIN_SERVINT_DAYS 30
#define MAX_SERVINT_DAYS 800
-/** Get the service interval domain.
+/**
+ * Get the service interval domain.
* Get the new proposed service interval for the vehicle is indeed, clamped
* within the given bounds. @see MIN_SERVINT_PERCENT ,etc.
* @param index proposed service interval
@@ -66,14 +46,6 @@
VARDEF TileIndex _last_built_ship_depot_tile;
/**
- * Check if a depot really exists.
- */
-static inline bool IsValidDepot(const Depot* depot)
-{
- return depot->xy != 0; /* XXX: Replace by INVALID_TILE someday */
-}
-
-/**
* Check if a tile is a depot of the given type.
*/
static inline bool IsTileDepotType(TileIndex tile, TransportType type)
@@ -135,15 +107,18 @@
03 (exit towards NW) we need either bit 0 or 4 set in tileh: 0x4C >> 3 = 1001
So ((0x4C >> p2) & tileh) determines whether the depot can be built on the current tileh
*/
+
+Depot *GetDepotByTile(TileIndex tile);
+void InitializeDepots(void);
+
static inline bool CanBuildDepotByTileh(uint32 direction, Slope tileh)
{
return (0x4C >> direction) & tileh;
}
+static inline void DoClearDepot(TileIndex tile)
+{
+ DeleteDepot(GetDepotByTile(tile));
+}
-Depot *GetDepotByTile(TileIndex tile);
-void InitializeDepot(void);
-Depot *AllocateDepot(void);
-void DoDeleteDepot(TileIndex tile);
-
#endif /* DEPOT_H */
=== economy.c
==================================================================
--- economy.c (revision 313)
+++ economy.c (local)
@@ -260,7 +260,7 @@
if (new_player != OWNER_SPECTATOR) {
FOR_ALL_TOWNS(t) {
/* If a player takes over, give the ratings to that player. */
- if (IsValidTown(t) && HASBIT(t->have_ratings, old_player)) {
+ if (HASBIT(t->have_ratings, old_player)) {
if (HASBIT(t->have_ratings, new_player)) {
// use max of the two ratings.
t->ratings[new_player] = max(t->ratings[new_player], t->ratings[old_player]);
@@ -271,10 +271,8 @@
}
/* Reset ratings for the town */
- if (IsValidTown(t)) {
- t->ratings[old_player] = 500;
- CLRBIT(t->have_ratings, old_player);
- }
+ t->ratings[old_player] = 500;
+ CLRBIT(t->have_ratings, old_player);
}
}
}
@@ -891,12 +889,12 @@
fr->distance = (uint)-1;
- fr->from = from = GetTown(RandomRange(_total_towns));
- if (from->xy == 0 || from->population < 400)
+ fr->from = from = GetRandomTown();
+ if (from->population < 400)
return;
- fr->to = to = GetTown(RandomRange(_total_towns));
- if (from==to || to->xy == 0 || to->population < 400 || to->pct_pass_transported > 42)
+ fr->to = to = GetRandomTown();
+ if (from==to || to->population < 400 || to->pct_pass_transported > 42)
return;
fr->distance = DistanceManhattan(from->xy, to->xy);
@@ -910,7 +908,7 @@
fr->distance = (uint)-1;
- fr->from = i = GetIndustry(RandomRange(_total_industries));
+ fr->from = i = GetIndustry(RandomRange(GetNumIndustries()));
if (i->xy == 0)
return;
@@ -935,7 +933,7 @@
if (cargo == CT_GOODS || cargo == CT_FOOD) {
// The destination is a town
- Town *t = GetTown(RandomRange(_total_towns));
+ Town *t = GetRandomTown();
// Only want big towns
if (t->xy == 0 || t->population < 900)
@@ -944,7 +942,7 @@
fr->to = t;
} else {
// The destination is an industry
- Industry *i2 = GetIndustry(RandomRange(_total_industries));
+ Industry *i2 = GetIndustry(RandomRange(GetNumIndustries()));
// The industry must accept the cargo
if (i == i2 || i2->xy == 0 ||
=== engine.c
==================================================================
--- engine.c (revision 313)
+++ engine.c (local)
@@ -501,49 +501,27 @@
* Engine Replacement stuff
************************************************************************/
-static void EngineRenewPoolNewBlock(uint start_item); /* Forward declare for initializer of _engine_renew_pool */
enum {
- ENGINE_RENEW_POOL_BLOCK_SIZE_BITS = 3,
- ENGINE_RENEW_POOL_MAX_BLOCKS = 8000,
+ ENGINE_RENEW_PUDDLE_SIZE = 128
};
-MemoryPool _engine_renew_pool = { "EngineRe", ENGINE_RENEW_POOL_MAX_BLOCKS, ENGINE_RENEW_POOL_BLOCK_SIZE_BITS, sizeof(EngineRenew), &EngineRenewPoolNewBlock, NULL, 0, 0, NULL };
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeEngineRenew(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyEngineRenew(const IndexedPool* pool, void* drop, DropIndex index);
-static inline uint16 GetEngineRenewPoolSize(void)
-{
- return _engine_renew_pool.total_items;
-}
+/* Initialize the engine_renew-pool */
+static IndexedPoolSettings _engine_renew_pool_settings = INDEXED_POOL(EngineRenew, ENGINE_RENEW_PUDDLE_SIZE);
+IndexedPool _engine_renew_pool;
-#define FOR_ALL_ENGINE_RENEWS_FROM(er, start) for (er = GetEngineRenew(start); er != NULL; er = (er->index + 1 < GetEngineRenewPoolSize()) ? GetEngineRenew(er->index + 1) : NULL)
-#define FOR_ALL_ENGINE_RENEWS(er) FOR_ALL_ENGINE_RENEWS_FROM(er, 0)
-
-static void EngineRenewPoolNewBlock(uint start_item)
+static void InitializeEngineRenew(const IndexedPool* pool, void* drop, DropIndex index)
{
- EngineRenew *er;
-
- FOR_ALL_ENGINE_RENEWS_FROM(er, start_item) {
- er->index = start_item++;
- er->from = INVALID_ENGINE;
- }
+ EngineRenew* er = (EngineRenew*)drop;
+ ZERO_AND_INDEX(EngineRenew, er)
}
-
-static EngineRenew *AllocateEngineRenew(void)
+static void DestroyEngineRenew(const IndexedPool* pool, void* drop, DropIndex index)
{
- EngineRenew *er;
-
- FOR_ALL_ENGINE_RENEWS(er) {
- if (er->from == INVALID_ENGINE) {
- er->to = INVALID_ENGINE;
- er->next = NULL;
- return er;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_engine_renew_pool)) return AllocateEngineRenew();
-
- return NULL;
+ /* Nothing to do here */
}
/**
@@ -562,9 +540,11 @@
void RemoveAllEngineReplacement(EngineRenewList* erl)
{
EngineRenew* er = (EngineRenew*)(*erl); /* Fetch first element */
+ EngineRenew* next;
while (er) {
- er->from = INVALID_ENGINE; /* "Deallocate" all elements */
- er = er->next;
+ next = er->next;
+ DeleteEngineRenew(er);
+ er = next;
}
*erl = NULL; /* Empty list */
}
@@ -614,7 +594,7 @@
} else {
prev->next = er->next; /* Cut this element out */
}
- er->from = INVALID_ENGINE; /* Deallocate */
+ DeleteEngineRenew(er);
}
return 0;
}
@@ -639,10 +619,8 @@
EngineRenew *er;
FOR_ALL_ENGINE_RENEWS(er) {
- if (er->from != INVALID_ENGINE) {
- SlSetArrayIndex(er->index);
- SlObject(er, _engine_renew_desc);
- }
+ SlSetArrayIndex(er->index);
+ SlObject(er, _engine_renew_desc);
}
}
@@ -653,7 +631,7 @@
while ((index = SlIterateArray()) != -1) {
EngineRenew *er;
- if (!AddBlockIfNeeded(&_engine_renew_pool, index))
+ if (IndexedPoolAllocateIndex(&_engine_renew_pool, index) == NULL)
error("EngineRenews: failed loading savegame: too many EngineRenews");
er = GetEngineRenew(index);
@@ -717,7 +695,5 @@
void InitializeEngines(void)
{
- /* Clean the engine renew pool and create 1 block in it */
- CleanPool(&_engine_renew_pool);
- AddBlockToPool(&_engine_renew_pool);
+ IndexedPoolInitialize(&_engine_renew_pool, &_engine_renew_pool_settings);
}
=== engine.h
==================================================================
--- engine.h (revision 313)
+++ engine.h (local)
@@ -259,7 +259,7 @@
* it.
*/
struct EngineRenew {
- uint16 index;
+ EngineRenewID index;
EngineID from;
EngineID to;
struct EngineRenew *next;
@@ -272,20 +272,13 @@
* placed here so the only exception to this rule, the saveload code, can use
* it.
*/
-extern MemoryPool _engine_renew_pool;
+extern IndexedPool _engine_renew_pool;
+#define FOR_ALL_ENGINE_RENEWS_FROM(v, start) FOR_ALL_IN_POOL_FROM(_engine_renew_pool, v, start)
+#define FOR_ALL_ENGINE_RENEWS(v) FOR_ALL_IN_POOL(_engine_renew_pool, v)
+#define FOR_ALL_ENGINE_RENEWS_EVERY_N_TICKS(v, n, ctr) FOR_ALL_EVERY_N_TICKS(_engine_renew_pool, v, n, ctr)
+INDEXED_POOL_FUNCTIONS(EngineRenew, EngineRenews, _engine_renew_pool)
/**
- * DO NOT USE outside of engine.c. Is
- * placed here so the only exception to this rule, the saveload code, can use
- * it.
- */
-static inline EngineRenew *GetEngineRenew(uint16 index)
-{
- return (EngineRenew*)GetItemFromPool(&_engine_renew_pool, index);
-}
-
-
-/**
* A list to group EngineRenew directives together (such as per-player).
*/
typedef EngineRenew* EngineRenewList;
=== graph_gui.c
==================================================================
--- graph_gui.c (revision 313)
+++ graph_gui.c (local)
@@ -1109,12 +1109,12 @@
const uint16 cmp1 = *(const uint16 *)a;
const uint16 cmp2 = *(const uint16 *)b;
- ss = GetSign(cmp1);
+ ss = GetSignStruct(cmp1);
GetString(buf1, ss->str);
if (cmp2 != _last_sign_idx) {
_last_sign_idx = cmp2;
- ss = GetSign(cmp2);
+ ss = GetSignStruct(cmp2);
GetString(_bufcache, ss->str);
}
@@ -1129,7 +1129,7 @@
_num_sign_sort = 0;
/* Create array for sorting */
- _sign_sort = realloc(_sign_sort, GetSignPoolSize() * sizeof(_sign_sort[0]));
+ _sign_sort = realloc(_sign_sort, GetNumSignStructs() * sizeof(_sign_sort[0]));
if (_sign_sort == NULL)
error("Could not allocate memory for the sign-sorting-list");
@@ -1172,7 +1172,7 @@
/* Start drawing the signs */
for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
- ss = GetSign(_sign_sort[i]);
+ ss = GetSignStruct(_sign_sort[i]);
if (ss->owner != OWNER_NONE)
DrawPlayerIcon(ss->owner, 4, y + 1);
@@ -1197,7 +1197,7 @@
if (id_v >= w->vscroll.count)
return;
- ss = GetSign(_sign_sort[id_v]);
+ ss = GetSignStruct(_sign_sort[id_v]);
ScrollMainWindowToTile(TileVirtXY(ss->x, ss->y));
} break;
}
=== industry.h
==================================================================
--- industry.h (revision 313)
+++ industry.h (local)
@@ -31,9 +31,11 @@
byte last_prod_year;
byte was_cargo_delivered;
- uint16 index;
+ IndustryID index;
};
+extern IndexedPool _industry_pool;
+
typedef struct IndustryTileTable {
TileIndexDiffC ti;
IndustryGfx gfx;
@@ -65,37 +67,9 @@
const IndustrySpec *GetIndustrySpec(IndustryType thistype);
-extern MemoryPool _industry_pool;
+#define FOR_ALL_INDUSTRIES(i) FOR_ALL_IN_POOL(_industry_pool, i)
+INDEXED_POOL_FUNCTIONS(Industry, Industries, _industry_pool)
-/**
- * Check if an Industry really exists.
- */
-static inline bool IsValidIndustry(Industry* industry)
-{
- return industry->xy != 0; /* XXX: Replace by INVALID_TILE someday */
-}
-
-/**
- * Get the pointer to the industry with index 'index'
- */
-static inline Industry *GetIndustry(uint index)
-{
- return (Industry*)GetItemFromPool(&_industry_pool, index);
-}
-
-/**
- * Get the current size of the IndustryPool
- */
-static inline uint16 GetIndustryPoolSize(void)
-{
- return _industry_pool.total_items;
-}
-
-#define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1 < GetIndustryPoolSize()) ? GetIndustry(i->index + 1) : NULL)
-#define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0)
-
-VARDEF int _total_industries; // For the AI: the amount of industries active
-
VARDEF uint16 *_industry_sort;
VARDEF bool _industry_sort_dirty;
=== industry_cmd.c
==================================================================
--- industry_cmd.c (revision 313)
+++ industry_cmd.c (local)
@@ -23,31 +23,52 @@
#include "table/industry_land.h"
#include "table/build_industry.h"
+
+static byte _industry_sound_ctr;
+static TileIndex _industry_sound_tile;
+
+void ShowIndustryViewWindow(int industry);
+void BuildOilRig(TileIndex tile);
+void DeleteOilRig(TileIndex tile);
+
enum {
- /* Max industries: 64000 (8 * 8000) */
- INDUSTRY_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */
- INDUSTRY_POOL_MAX_BLOCKS = 8000,
+ INDUSTRY_PUDDLE_SIZE = 8,
};
-/**
- * Called if a new block is added to the industry-pool
- */
-static void IndustryPoolNewBlock(uint start_item)
-{
- Industry *i;
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeIndustry(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyIndustry(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_INDUSTRIES_FROM(i, start_item) i->index = start_item++;
+/* The industry pool */
+static IndexedPoolSettings _industry_pool_settings = INDEXED_POOL(Industry, INDUSTRY_PUDDLE_SIZE);
+IndexedPool _industry_pool;
+
+static void InitializeIndustry(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ ZERO_AND_INDEX(Industry, drop);
}
-/* Initialize the industry-pool */
-MemoryPool _industry_pool = { "Industry", INDUSTRY_POOL_MAX_BLOCKS, INDUSTRY_POOL_BLOCK_SIZE_BITS, sizeof(Industry), &IndustryPoolNewBlock, NULL, 0, 0, NULL };
+static void DestroyIndustry(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ Industry* i = (Industry*)drop;
-static byte _industry_sound_ctr;
-static TileIndex _industry_sound_tile;
+ /* Clear all tiles belonging to this industry */
+ BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
+ if (IsTileType(tile_cur, MP_INDUSTRY)) {
+ if (GetIndustryIndex(tile_cur) == i->index) {
+ DoClearSquare(tile_cur);
+ }
+ } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
+ DeleteOilRig(tile_cur);
+ }
+ END_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
-void ShowIndustryViewWindow(int industry);
-void BuildOilRig(TileIndex tile);
-void DeleteOilRig(TileIndex tile);
+ i->xy = 0;
+ _industry_sort_dirty = true;
+ DeleteSubsidyWithIndustry(i->index);
+ DeleteWindowById(WC_INDUSTRY_VIEW, i->index);
+ InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+}
static const IndustryType _industry_close_mode[IT_END] = {
/* COAL_MINE */ INDUSTRYLIFE_PRODUCTION,
@@ -743,25 +764,6 @@
/* not used */
}
-void DeleteIndustry(Industry *i)
-{
- BEGIN_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
- if (IsTileType(tile_cur, MP_INDUSTRY)) {
- if (GetIndustryIndex(tile_cur) == i->index) {
- DoClearSquare(tile_cur);
- }
- } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) {
- DeleteOilRig(tile_cur);
- }
- END_TILE_LOOP(tile_cur, i->width, i->height, i->xy);
-
- i->xy = 0;
- _industry_sort_dirty = true;
- DeleteSubsidyWithIndustry(i->index);
- DeleteWindowById(WC_INDUSTRY_VIEW, i->index);
- InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
-}
-
static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
static bool IsBadFarmFieldTile(TileIndex tile)
@@ -1005,7 +1007,7 @@
if (_game_mode == GM_EDITOR) return;
FOR_ALL_INDUSTRIES(i) {
- if (i->xy != 0) ProduceIndustryGoods(i);
+ ProduceIndustryGoods(i);
}
}
@@ -1120,8 +1122,7 @@
if (_patches.multiple_industry_per_town) return t;
FOR_ALL_INDUSTRIES(i) {
- if (i->xy != 0 &&
- i->type == (byte)type &&
+ if (i->type == (byte)type &&
i->town == t) {
_error_message = STR_0287_ONLY_ONE_ALLOWED_PER_TOWN;
return NULL;
@@ -1241,8 +1242,7 @@
FOR_ALL_INDUSTRIES(i) {
// check if an industry that accepts the same goods is nearby
- if (i->xy != 0 &&
- DistanceMax(tile, i->xy) <= 14 &&
+ if (DistanceMax(tile, i->xy) <= 14 &&
indspec->accepts_cargo[0] != CT_INVALID &&
indspec->accepts_cargo[0] == i->accepts_cargo[0] && (
_game_mode != GM_EDITOR ||
@@ -1254,8 +1254,7 @@
}
// check "not close to" field.
- if (i->xy != 0 &&
- (i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) &&
+ if ((i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) &&
DistanceMax(tile, i->xy) <= 14) {
_error_message = STR_INDUSTRY_TOO_CLOSE;
return false;
@@ -1264,27 +1263,6 @@
return true;
}
-static Industry *AllocateIndustry(void)
-{
- Industry *i;
-
- FOR_ALL_INDUSTRIES(i) {
- if (i->xy == 0) {
- uint index = i->index;
-
- if (i->index > _total_industries) _total_industries = i->index;
-
- memset(i, 0, sizeof(*i));
- i->index = index;
-
- return i;
- }
- }
-
- /* Check if we can add a block to the pool */
- return AddBlockToPool(&_industry_pool) ? AllocateIndustry() : NULL;
-}
-
static void DoCreateNewIndustry(Industry *i, TileIndex tile, int type, const IndustryTileTable *it, const Town *t, byte owner)
{
const IndustrySpec *indspec = GetIndustrySpec(type);
@@ -1735,15 +1713,14 @@
PlayerID old_player = _current_player;
_current_player = OWNER_NONE;
- FOR_ALL_INDUSTRIES(i) {
- if (i->xy != 0) UpdateIndustryStatistics(i);
- }
+ FOR_ALL_INDUSTRIES(i)
+ UpdateIndustryStatistics(i);
/* 3% chance that we start a new industry */
if (CHANCE16(3, 100)) {
MaybeNewIndustry(Random());
- } else if (!_patches.smooth_economy && _total_industries > 0) {
- i = GetIndustry(RandomRange(_total_industries));
+ } else if (!_patches.smooth_economy && GetNumIndustries() > 0) {
+ i = GetIndustry(RandomRange(GetNumIndustries()));
if (i->xy != 0) ChangeIndustryProduction(i);
}
@@ -1757,10 +1734,8 @@
void InitializeIndustries(void)
{
- CleanPool(&_industry_pool);
- AddBlockToPool(&_industry_pool);
+ IndexedPoolInitialize(&_industry_pool, &_industry_pool_settings);
- _total_industries = 0;
_industry_sort_dirty = true;
}
@@ -1828,18 +1803,14 @@
{
int index;
- _total_industries = 0;
-
while ((index = SlIterateArray()) != -1) {
Industry *i;
- if (!AddBlockIfNeeded(&_industry_pool, index))
+ if (IndexedPoolAllocateIndex(&_industry_pool, index) == NULL)
error("Industries: failed loading savegame: too many industries");
i = GetIndustry(index);
SlObject(i, _industry_desc);
-
- if (index > _total_industries) _total_industries = index;
}
}
=== industry_gui.c
==================================================================
--- industry_gui.c (revision 313)
+++ industry_gui.c (local)
@@ -533,12 +533,12 @@
int n = 0;
/* Create array for sorting */
- _industry_sort = realloc(_industry_sort, GetIndustryPoolSize() * sizeof(_industry_sort[0]));
+ _industry_sort = realloc(_industry_sort, GetNumIndustries() * sizeof(_industry_sort[0]));
if (_industry_sort == NULL)
error("Could not allocate memory for the industry-sorting-list");
FOR_ALL_INDUSTRIES(i) {
- if (i->xy != 0) _industry_sort[n++] = i->index;
+ _industry_sort[n++] = i->index;
}
_num_industry_sort = n;
_last_industry_idx = 0xFFFF; // used for "cache"
=== macros.h
==================================================================
--- macros.h (revision 313)
+++ macros.h (local)
@@ -4,6 +4,7 @@
#define MACROS_H
#include "map.h"
+#include "limits.h"
/// Fetch n bits starting at bit s from x
#define GB(x, s, n) (((x) >> (s)) & ((1U << (n)) - 1))
@@ -147,6 +148,7 @@
static inline void swap_int16(int16 *a, int16 *b) { int16 t = *a; *a = *b; *b = t; }
static inline void swap_int32(int32 *a, int32 *b) { int32 t = *a; *a = *b; *b = t; }
static inline void swap_tile(TileIndex *a, TileIndex *b) { TileIndex t = *a; *a = *b; *b = t; }
+static inline void swap_pointer(void **a, void **b) { void* t = *a; *a = *b; *b = t; }
static inline uint16 ReadLE16Aligned(const void* x)
@@ -177,4 +179,20 @@
*/
#define ALIGN(x, n) (((x) + (n) - 1) & ~((n) - 1))
+/**
+ * Returns the highest value a given type can have. Returns 0xFF for byte, and
+ * 0xFFFF for uint16, for example.
+ */
+#define MAX_VALUE(type) ((((uint64)1) << sizeof(type) * CHAR_BIT) - 1)
+/* uint64 is used to prevent intermediate rounding for 64 bit types */
+
+/**
+ * Returns the number of indices available when using a given type as index.
+ * Keeps one index free for the INVALID_SOMETHING value, which should be equal
+ * to MAX_VALUE(type)
+ */
+#define NUM_INDICES(type) MAX_VALUE(type)
+/* One element is reserved automatically, because MAX_VALUE returns the
+ * maximum index, and we return the number of available indices (off-by-one). */
+
#endif /* MACROS_H */
=== misc.c
==================================================================
--- misc.c (revision 313)
+++ misc.c (local)
@@ -92,7 +92,7 @@
void InitializeVehicles(void);
void InitializeWaypoints(void);
-void InitializeDepot(void);
+void InitializeDepots(void);
void InitializeEngines(void);
void InitializeOrders(void);
void InitializeClearLand(void);
@@ -151,7 +151,7 @@
InitializeEngines();
InitializeVehicles();
InitializeWaypoints();
- InitializeDepot();
+ InitializeDepots();
InitializeOrders();
InitNewsItemStructs();
@@ -474,16 +474,12 @@
/**
* Runs the day_proc for every DAY_TICKS vehicle starting at daytick.
*/
-static void RunVehicleDayProc(uint daytick)
+static void RunVehicleDayProc(void)
{
- uint total = _vehicle_pool.total_items;
- uint i;
+ Vehicle* v;
- for (i = daytick; i < total; i += DAY_TICKS) {
- Vehicle* v = GetVehicle(i);
-
- if (v->type != 0) _on_new_vehicle_day_proc[v->type - 0x10](v);
- }
+ FOR_ALL_VEHICLES_EVERY_N_TICKS(v, DAY_TICKS, _vehicle_tick_ctr)
+ _on_new_vehicle_day_proc[v->type - 0x10](v);
}
void IncreaseDate(void)
@@ -495,7 +491,7 @@
return;
}
- RunVehicleDayProc(_date_fract);
+ RunVehicleDayProc();
/* increase day, and check if a new day is there? */
_tick_counter++;
@@ -620,7 +616,7 @@
SLEG_VAR(_date, SLE_UINT16),
SLEG_VAR(_date_fract, SLE_UINT16),
SLEG_VAR(_tick_counter, SLE_UINT16),
- SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16),
+ SLEG_VAR(_vehicle_tick_ctr, SLE_UINT16),
SLEG_VAR(_age_cargo_skip_counter,SLE_UINT8),
SLEG_VAR(_avail_aircraft, SLE_UINT8),
SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
@@ -629,13 +625,13 @@
SLEG_VAR(_station_tick_ctr, SLE_UINT16),
SLEG_VAR(_random_seeds[0][0], SLE_UINT32),
SLEG_VAR(_random_seeds[0][1], SLE_UINT32),
- SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9),
- SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION),
+ SLEG_CONDVAR(_town_tick_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9),
+ SLEG_CONDVAR(_town_tick_ctr, SLE_UINT32, 10, SL_MAX_VERSION),
SLEG_VAR(_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32),
SLEG_VAR(_trees_tick_ctr, SLE_UINT8),
SLEG_CONDVAR(_pause, SLE_UINT8, 4, SL_MAX_VERSION),
- SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION),
+ SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION), /* TODO: Unused */
SLEG_END()
};
=== newgrf_spritegroup.c
==================================================================
--- newgrf_spritegroup.c (revision 313)
+++ newgrf_spritegroup.c (local)
@@ -8,66 +8,52 @@
#include "newgrf_spritegroup.h"
enum {
- SPRITEGROUP_POOL_BLOCK_SIZE_BITS = 4, /* (1 << 4) == 16 items */
- SPRITEGROUP_POOL_MAX_BLOCKS = 8000,
+ SPRITE_GROUP_PUDDLE_SIZE = 128
};
-static uint _spritegroup_count = 0;
-static MemoryPool _spritegroup_pool;
+/* Forward declare to be used in the pool settings below */
+void DestroySpriteGroup(const MemoryPool* pool, void* drop);
+/** Hold the settings of the spritegroup pool. Unlike most other pools, this
+ * is no indexed pool. Drops have no identifying ID, but the pool mainly acts
+ * like a (fast) malloc/free replacement. */
+static MemoryPoolSettings _sprite_group_pool_settings = {"SpriteGroup", POOL_NO_LIMIT, SPRITE_GROUP_PUDDLE_SIZE, sizeof(SpriteGroup), POOL_FAST, NULL, (const PoolDestroyDrop*) &DestroySpriteGroup};
+static MemoryPool _sprite_group_pool;
-static void SpriteGroupPoolCleanBlock(uint start_item, uint end_item)
+void DestroySpriteGroup(const MemoryPool* pool, void* drop)
{
- uint i;
+ SpriteGroup *group = (SpriteGroup*)drop;
+ /* Free dynamically allocated memory */
+ switch (group->type) {
+ case SGT_REAL:
+ free(group->g.real.loaded);
+ free(group->g.real.loading);
+ break;
- for (i = start_item; i <= end_item; i++) {
- SpriteGroup *group = (SpriteGroup*)GetItemFromPool(&_spritegroup_pool, i);
+ case SGT_DETERMINISTIC:
+ free(group->g.determ.adjusts);
+ free(group->g.determ.ranges);
+ break;
- /* Free dynamically allocated memory */
- switch (group->type) {
- case SGT_REAL:
- free(group->g.real.loaded);
- free(group->g.real.loading);
- break;
+ case SGT_RANDOMIZED:
+ free(group->g.random.groups);
+ break;
- case SGT_DETERMINISTIC:
- free(group->g.determ.adjusts);
- free(group->g.determ.ranges);
- break;
-
- case SGT_RANDOMIZED:
- free(group->g.random.groups);
- break;
-
- default:
- break;
- }
+ default:
+ break;
}
}
-
-/* Initialize the SpriteGroup pool */
-static MemoryPool _spritegroup_pool = { "SpriteGr", SPRITEGROUP_POOL_MAX_BLOCKS, SPRITEGROUP_POOL_BLOCK_SIZE_BITS, sizeof(SpriteGroup), NULL, &SpriteGroupPoolCleanBlock, 0, 0, NULL };
-
-
/* Allocate a new SpriteGroup */
SpriteGroup *AllocateSpriteGroup(void)
{
- /* This is totally different to the other pool allocators, as we never remove an item from the pool. */
- if (_spritegroup_count == _spritegroup_pool.total_items) {
- if (!AddBlockToPool(&_spritegroup_pool)) return NULL;
- }
-
- return (SpriteGroup*)GetItemFromPool(&_spritegroup_pool, _spritegroup_count++);
+ return (SpriteGroup*) PoolAllocateDrop(&_sprite_group_pool);
}
void InitializeSpriteGroupPool(void)
{
- CleanPool(&_spritegroup_pool);
- AddBlockToPool(&_spritegroup_pool);
-
- _spritegroup_count = 0;
+ PoolInitialize(&_sprite_group_pool, &_sprite_group_pool_settings);
}
=== npf.c
==================================================================
--- npf.c (revision 313)
+++ npf.c (local)
@@ -784,7 +784,7 @@
FOR_ALL_DEPOTS(depot) {
/* Check if this is really a valid depot, it is of the needed type and
* owner */
- if (IsValidDepot(depot) && IsTileDepotType(depot->xy, type) && IsTileOwner(depot->xy, owner))
+ if (IsTileDepotType(depot->xy, type) && IsTileOwner(depot->xy, owner))
/* If so, let's add it to the queue, sorted by distance */
depots.push(&depots, depot, DistanceManhattan(tile, depot->xy));
}
=== oldloader.c
==================================================================
--- oldloader.c (revision 313)
+++ oldloader.c (local)
@@ -338,35 +338,10 @@
}
}
-static void FixOldVehicles(void)
-{
- /* Check for shared orders, and link them correctly */
- Vehicle* v;
-
- FOR_ALL_VEHICLES(v) {
- Vehicle *u;
-
- if (v->type == 0) continue;
-
- FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
- if (u->type == 0) continue;
-
- /* If a vehicle has the same orders, add the link to eachother
- * in both vehicles */
- if (v->orders == u->orders) {
- v->next_shared = u;
- u->prev_shared = v;
- break;
- }
- }
- }
-}
-
/*
* End -- Stuff to fix the savegames to be OpenTTD compatible
*/
-
/* Help:
* - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
* be given via base in LoadChunk() as real pointer
@@ -488,12 +463,12 @@
OCL_END()
};
-static bool LoadOldTown(LoadgameState *ls, int num)
+static bool LoadOldTown(LoadgameState *ls, int index)
{
- if (!AddBlockIfNeeded(&_town_pool, num))
+ if(IndexedPoolAllocateIndex(&_town_pool, index) == NULL)
error("Towns: failed loading savegame: too many towns");
- return LoadChunk(ls, GetTown(num), town_chunk);
+ return LoadChunk(ls, GetTown(index), town_chunk);
}
static uint16 _old_order;
@@ -502,20 +477,20 @@
OCL_END()
};
-static bool LoadOldOrder(LoadgameState *ls, int num)
+static bool LoadOldOrder(LoadgameState *ls, int index)
{
- if (!AddBlockIfNeeded(&_order_pool, num))
+ if(IndexedPoolAllocateIndex(&_order_pool, index) == NULL)
error("Orders: failed loading savegame: too many orders");
if (!LoadChunk(ls, NULL, order_chunk)) return false;
- AssignOrder(GetOrder(num), UnpackOldOrder(_old_order));
+ AssignOrder(GetOrder(index), UnpackOldOrder(_old_order));
/* Relink the orders to eachother (in TTD(Patch) the orders for one
vehicle are behind eachother, with OT_NOTHING as indication that
it is the last order */
- if (num > 0 && GetOrder(num)->type != OT_NOTHING)
- GetOrder(num - 1)->next = GetOrder(num);
+ if (index > 0 && GetOrder(index)->type != OT_NOTHING)
+ GetOrder(index - 1)->next = GetOrder(index);
return true;
}
@@ -526,15 +501,15 @@
OCL_END()
};
-static bool LoadOldDepot(LoadgameState *ls, int num)
+static bool LoadOldDepot(LoadgameState *ls, int index)
{
- if (!AddBlockIfNeeded(&_depot_pool, num))
+ if (IndexedPoolAllocateIndex(&_depot_pool, index) == NULL)
error("Depots: failed loading savegame: too many depots");
- if (!LoadChunk(ls, GetDepot(num), depot_chunk)) return false;
+ if (!LoadChunk(ls, GetDepot(index), depot_chunk)) return false;
- if (GetDepot(num)->xy != 0) {
- GetDepot(num)->town_index = REMAP_TOWN_IDX(_old_town_index);
+ if (GetDepot(index)->xy != 0) {
+ GetDepot(index)->town_index = REMAP_TOWN_IDX(_old_town_index);
}
return true;
@@ -638,15 +613,15 @@
OCL_END()
};
-static bool LoadOldStation(LoadgameState *ls, int num)
+static bool LoadOldStation(LoadgameState *ls, int index)
{
Station *st;
- if (!AddBlockIfNeeded(&_station_pool, num))
+ if (IndexedPoolAllocateIndex(&_station_pool, index) == NULL)
error("Stations: failed loading savegame: too many stations");
- st = GetStation(num);
- _current_station_id = num;
+ st = GetStation(index);
+ _current_station_id = index;
if (!LoadChunk(ls, st, station_chunk))
return false;
@@ -712,14 +687,14 @@
OCL_END()
};
-static bool LoadOldIndustry(LoadgameState *ls, int num)
+static bool LoadOldIndustry(LoadgameState *ls, int index)
{
Industry *i;
- if (!AddBlockIfNeeded(&_industry_pool, num))
+ if (IndexedPoolAllocateIndex(&_industry_pool, index) == NULL)
error("Industries: failed loading savegame: too many industries");
- i = GetIndustry(num);
+ i = GetIndustry(index);
if (!LoadChunk(ls, i, industry_chunk)) return false;
if (i->xy != 0) {
@@ -1203,7 +1178,7 @@
_current_vehicle_id = num * _old_vehicle_multiplier + i;
- if (!AddBlockIfNeeded(&_vehicle_pool, _current_vehicle_id))
+ if (IndexedPoolAllocateIndex(&_vehicle_pool, _current_vehicle_id) == NULL)
error("Vehicles: failed loading savegame: too many vehicles");
v = GetVehicle(_current_vehicle_id);
@@ -1253,12 +1228,12 @@
OCL_END()
};
-static bool LoadOldSign(LoadgameState *ls, int num)
+static bool LoadOldSign(LoadgameState *ls, int index)
{
- if (!AddBlockIfNeeded(&_sign_pool, num))
+ if (IndexedPoolAllocateIndex(&_signstruct_pool, index) == NULL)
error("Signs: failed loading savegame: too many signs");
- return LoadChunk(ls, GetSign(num), sign_chunk);
+ return LoadChunk(ls, GetSignStruct(index), sign_chunk);
}
static const OldChunks engine_chunk[] = {
@@ -1430,7 +1405,7 @@
OCL_CHUNK( 40, LoadOldSign ),
OCL_CHUNK(256, LoadOldEngine ),
- OCL_VAR ( OC_UINT16, 1, &_vehicle_id_ctr_day ),
+ OCL_VAR ( OC_UINT16, 1, &_vehicle_tick_ctr ),
OCL_CHUNK( 8, LoadOldSubsidy ),
@@ -1511,9 +1486,6 @@
/* Fix some general stuff */
_opt.landscape = _opt.landscape & 0xF;
- /* Remap some pointers */
- _cur_town_ctr = REMAP_TOWN_IDX(_old_cur_town_ctr);
-
/* _old_map3 is changed in _map3_lo and _map3_hi */
for (i = 0; i < OLD_MAP_SIZE; i++) {
_m[i].m3 = _old_map3[i * 2];
@@ -1537,7 +1509,7 @@
/* Fix the game to be compatible with OpenTTD */
FixOldTowns();
FixOldStations();
- FixOldVehicles();
+ FixSharedOrders();
AddTypeToEngines();
=== openttd.c
==================================================================
--- openttd.c (revision 313)
+++ openttd.c (local)
@@ -251,12 +251,19 @@
static void UnInitializeDynamicVariables(void)
{
/* Dynamic stuff needs to be free'd somewhere... */
- CleanPool(&_town_pool);
- CleanPool(&_industry_pool);
- CleanPool(&_station_pool);
- CleanPool(&_vehicle_pool);
- CleanPool(&_sign_pool);
- CleanPool(&_order_pool);
+ /* XXX: Shouldn't this be freed where it was allocated? Function like
+ * DestroyVehicles(), etc? */
+ IndexedPoolEmpty(&_signstruct_pool);
+ IndexedPoolEmpty(&_town_pool);
+ IndexedPoolEmpty(&_industry_pool);
+ IndexedPoolEmpty(&_station_pool);
+ IndexedPoolEmpty(&_roadstop_pool);
+ IndexedPoolEmpty(&_depot_pool);
+ IndexedPoolEmpty(&_vehicle_pool);
+ IndexedPoolEmpty(&_waypoint_pool);
+ /* Note that order is important here! Vehicles and depots will automatically
+ * clean out orders! */
+ IndexedPoolEmpty(&_order_pool);
free(_station_sort);
free(_town_sort);
=== openttd.h
==================================================================
--- openttd.h (revision 313)
+++ openttd.h (local)
@@ -61,13 +61,23 @@
typedef struct NewsItem NewsItem;
typedef struct Industry Industry;
typedef struct DrawPixelInfo DrawPixelInfo;
+typedef byte PlayerID;
+typedef byte VehicleOrderID; /** ID of an order within its current vehicle. */
+typedef byte CargoID;
+
+/* These IDs are all used in pool. */
+typedef uint16 TownID;
typedef uint16 VehicleID;
+typedef uint16 WaypointID;
typedef uint16 StationID;
-typedef uint16 TownID;
-typedef byte PlayerID;
-typedef byte OrderID;
-typedef byte CargoID;
+typedef uint16 DepotID;
+typedef uint16 SignStructID;
+typedef uint16 OrderID;
+typedef uint16 RoadStopID;
typedef uint16 StringID;
+typedef uint16 IndustryID;
+typedef uint16 EngineRenewID;
+
typedef uint32 SpriteID; ///< The number of a sprite, without mapping bits and colortables
typedef uint32 PalSpriteID; ///< The number of a sprite plus all the mapping bits and colortables
typedef uint32 CursorID;
=== order.h
==================================================================
--- order.h (revision 313)
+++ order.h (local)
@@ -89,7 +89,7 @@
typedef struct {
VehicleID clone;
- OrderID orderindex;
+ VehicleOrderID orderindex;
Order order[MAX_BACKUP_ORDER_COUNT + 1];
uint16 service_interval;
char name[32];
@@ -98,49 +98,20 @@
VARDEF TileIndex _backup_orders_tile;
VARDEF BackuppedOrders _backup_orders_data[1];
-extern MemoryPool _order_pool;
+extern IndexedPool _order_pool;
-/**
- * Get the pointer to the order with index 'index'
- */
-static inline Order *GetOrder(uint index)
-{
- return (Order*)GetItemFromPool(&_order_pool, index);
-}
+#define FOR_ALL_ORDERS(order) FOR_ALL_IN_POOL(_order_pool, order)
+INDEXED_POOL_FUNCTIONS(Order, Orders, _order_pool);
/**
- * Get the current size of the OrderPool
+ * Iterates all the orders of the given vehicle. Expands to a for loop (add {}
+ * to taste), with order (Order*) set to each order in turn.
*/
-static inline uint16 GetOrderPoolSize(void)
-{
- return _order_pool.total_items;
-}
-
-#define FOR_ALL_ORDERS_FROM(order, start) for (order = GetOrder(start); order != NULL; order = (order->index + 1 < GetOrderPoolSize()) ? GetOrder(order->index + 1) : NULL)
-#define FOR_ALL_ORDERS(order) FOR_ALL_ORDERS_FROM(order, 0)
-
-
#define FOR_VEHICLE_ORDERS(v, order) for (order = v->orders; order != NULL; order = order->next)
-static inline bool HasOrderPoolFree(uint amount)
-{
- const Order *order;
-
- /* There is always room if not all blocks in the pool are reserved */
- if (_order_pool.current_blocks < _order_pool.max_blocks)
- return true;
-
- FOR_ALL_ORDERS(order)
- if (order->type == OT_NOTHING)
- if (--amount == 0)
- return true;
-
- return false;
-}
-
static inline bool IsOrderPoolFull(void)
{
- return !HasOrderPoolFree(1);
+ return GetNumOrdersFree() == 0;
}
/* Pack and unpack routines */
@@ -164,7 +135,7 @@
/* Functions */
void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *order);
void RestoreVehicleOrders(const Vehicle* v, const BackuppedOrders* order);
-void DeleteDestinationFromVehicleOrder(Order dest);
+void DeleteOrderFromAllVehicles(Order dest);
void InvalidateVehicleOrder(const Vehicle *v);
bool VehicleHasDepotOrders(const Vehicle *v);
void CheckOrders(const Vehicle*);
=== order_cmd.c
==================================================================
--- order_cmd.c (revision 313)
+++ order_cmd.c (local)
@@ -18,23 +18,26 @@
enum {
/* Max orders: 64000 (64 * 1000) */
- ORDER_POOL_BLOCK_SIZE_BITS = 6, /* In bits, so (1 << 6) == 64 */
- ORDER_POOL_MAX_BLOCKS = 1000,
+ ORDER_PUDDLE_SIZE = 64,
};
-/**
- * Called if a new block is added to the order-pool
- */
-static void OrderPoolNewBlock(uint start_item)
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeOrder(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyOrder(const IndexedPool* pool, void* drop, DropIndex index);
+
+/* Initialize the order-pool */
+static IndexedPoolSettings _order_pool_settings = INDEXED_POOL(Order, ORDER_PUDDLE_SIZE);
+IndexedPool _order_pool;
+
+static void InitializeOrder(const IndexedPool* pool, void* drop, DropIndex index)
{
- Order *order;
+ ZERO_AND_INDEX(Order, drop);
+}
- FOR_ALL_ORDERS_FROM(order, start_item) order->index = start_item++;
+static void DestroyOrder(const IndexedPool* pool, void* drop, DropIndex index)
+{
}
-/* Initialize the order-pool */
-MemoryPool _order_pool = { "Orders", ORDER_POOL_MAX_BLOCKS, ORDER_POOL_BLOCK_SIZE_BITS, sizeof(Order), &OrderPoolNewBlock, NULL, 0, 0, NULL };
-
/**
*
* Unpacks a order from savegames made with TTD(Patch)
@@ -103,35 +106,6 @@
/**
*
- * Allocate a new order
- *
- * @return Order* if a free space is found, else NULL.
- *
- */
-static Order *AllocateOrder(void)
-{
- Order *order;
-
- FOR_ALL_ORDERS(order) {
- if (order->type == OT_NOTHING) {
- uint index = order->index;
-
- memset(order, 0, sizeof(*order));
- order->index = index;
- order->next = NULL;
-
- return order;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_order_pool)) return AllocateOrder();
-
- return NULL;
-}
-
-/**
- *
* Assign data to an order (from an other order)
* This function makes sure that the index is maintained correctly
*
@@ -172,10 +146,10 @@
{
Vehicle *v;
VehicleID veh = GB(p1, 0, 16);
- OrderID sel_ord = GB(p1, 16, 16);
+ VehicleOrderID sel_ord = GB(p1, 16, 16);
Order new_order = UnpackOrder(p2);
- if (!IsVehicleIndex(veh)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh)) return CMD_ERROR;
v = GetVehicle(veh);
if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR;
@@ -185,11 +159,10 @@
case OT_GOTO_STATION: {
const Station *st;
- if (!IsStationIndex(new_order.station)) return CMD_ERROR;
+ if (!IsValidStationID(new_order.station)) return CMD_ERROR;
st = GetStation(new_order.station);
- if (!IsValidStation(st) ||
- (st->airport_type != AT_OILRIG && !(IsBuoy(st)) && !CheckOwnership(st->owner))) {
+ if (st->airport_type != AT_OILRIG && !(IsBuoy(st)) && !CheckOwnership(st->owner)) {
return CMD_ERROR;
}
@@ -247,11 +220,10 @@
if (v->type == VEH_Aircraft) {
const Station* st;
- if (!IsStationIndex(new_order.station)) return CMD_ERROR;
+ if (!IsValidStationID(new_order.station)) return CMD_ERROR;
st = GetStation(new_order.station);
- if (!IsValidStation(st) ||
- (st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
+ if ((st->airport_type != AT_OILRIG && !CheckOwnership(st->owner)) ||
!(st->facilities & FACIL_AIRPORT) ||
GetAirport(st->airport_type)->nof_depots == 0) {
return CMD_ERROR;
@@ -259,10 +231,10 @@
} else {
const Depot* dp;
- if (!IsDepotIndex(new_order.station)) return CMD_ERROR;
- dp = GetDepot(new_order.station);
+ if (!IsValidDepotID(new_order.station)) return CMD_ERROR;
+ dp = GetDepot((OrderID)new_order.station);
- if (!IsValidDepot(dp) || !CheckOwnership(GetTileOwner(dp->xy)))
+ if (!CheckOwnership(GetTileOwner(dp->xy)))
return CMD_ERROR;
switch (v->type) {
@@ -305,7 +277,7 @@
if (v->type != VEH_Train) return CMD_ERROR;
- if (!IsWaypointIndex(new_order.station)) return CMD_ERROR;
+ if (!IsValidWaypointID(new_order.station)) return CMD_ERROR;
wp = GetWaypoint(new_order.station);
if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR;
@@ -435,10 +407,10 @@
{
Vehicle *v, *u;
VehicleID veh_id = p1;
- OrderID sel_ord = p2;
+ VehicleOrderID sel_ord = p2;
Order *order;
- if (!IsVehicleIndex(veh_id)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
v = GetVehicle(veh_id);
if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR;
@@ -510,13 +482,13 @@
Vehicle *v;
VehicleID veh_id = p1;
- if (!IsVehicleIndex(veh_id)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh_id)) return CMD_ERROR;
v = GetVehicle(veh_id);
if (v->type == 0 || !CheckOwnership(v->owner)) return CMD_ERROR;
if (flags & DC_EXEC) {
/* Goto next order */
- OrderID b = v->cur_order_index + 1;
+ VehicleOrderID b = v->cur_order_index + 1;
if (b >= v->num_orders) b = 0;
v->cur_order_index = b;
@@ -554,10 +526,10 @@
{
Vehicle *v;
Order *order;
- OrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
+ VehicleOrderID sel_ord = GB(p1, 16, 16); // XXX - automatically truncated to 8 bits.
VehicleID veh = GB(p1, 0, 16);
- if (!IsVehicleIndex(veh)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh)) return CMD_ERROR;
if (p2 != OFB_FULL_LOAD && p2 != OFB_UNLOAD && p2 != OFB_NON_STOP && p2 != OFB_TRANSFER) return CMD_ERROR;
v = GetVehicle(veh);
@@ -623,7 +595,7 @@
VehicleID veh_src = GB(p1, 16, 16);
VehicleID veh_dst = GB(p1, 0, 16);
- if (!IsVehicleIndex(veh_dst)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh_dst)) return CMD_ERROR;
dst = GetVehicle(veh_dst);
@@ -633,7 +605,7 @@
case CO_SHARE: {
Vehicle *src;
- if (!IsVehicleIndex(veh_src)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
src = GetVehicle(veh_src);
@@ -680,7 +652,7 @@
Vehicle *src;
int delta;
- if (!IsVehicleIndex(veh_src)) return CMD_ERROR;
+ if (!IsValidVehicleID(veh_src)) return CMD_ERROR;
src = GetVehicle(veh_src);
@@ -708,9 +680,10 @@
}
}
- /* make sure there are orders available */
- delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
- if (!HasOrderPoolFree(delta))
+ /* make sure there are enough orders available */
+ delta = ( IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders );
+
+ if (delta > 0 && GetNumOrdersFree() < (uint)delta)
return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
if (flags & DC_EXEC) {
@@ -836,10 +809,10 @@
int32 CmdRestoreOrderIndex(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v;
- OrderID cur_ord = GB(p2, 0, 16);
+ VehicleOrderID cur_ord = GB(p2, 0, 16);
uint16 serv_int = GB(p2, 16, 16);
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
/* Check the vehicle type and ownership, and if the service interval and order are in range */
@@ -934,7 +907,7 @@
* @param dest type and station has to be set. This order will be removed from all orders of vehicles
*
*/
-void DeleteDestinationFromVehicleOrder(Order dest)
+void DeleteOrderFromAllVehicles(Order dest)
{
Vehicle *v;
Order *order;
@@ -1002,7 +975,7 @@
*/
void DeleteVehicleOrders(Vehicle *v)
{
- Order *order, *cur;
+ Order *next, *cur;
DeleteOrderWarnings(v);
@@ -1040,21 +1013,11 @@
v->orders = NULL;
v->num_orders = 0;
- order = NULL;
while (cur != NULL) {
- if (order != NULL) {
- order->type = OT_NOTHING;
- order->next = NULL;
- }
-
- order = cur;
- cur = cur->next;
+ next = cur->next;
+ DeleteOrder(cur);
+ cur = next;
}
-
- if (order != NULL) {
- order->type = OT_NOTHING;
- order->next = NULL;
- }
}
/**
@@ -1087,8 +1050,7 @@
void InitializeOrders(void)
{
- CleanPool(&_order_pool);
- AddBlockToPool(&_order_pool);
+ IndexedPoolInitialize(&_order_pool, &_order_pool_settings);
_backup_orders_tile = 0;
}
@@ -1109,10 +1071,8 @@
Order *order;
FOR_ALL_ORDERS(order) {
- if (order->type != OT_NOTHING) {
- SlSetArrayIndex(order->index);
- SlObject(order, _order_desc);
- }
+ SlSetArrayIndex(order->index);
+ SlObject(order, _order_desc);
}
}
@@ -1135,7 +1095,7 @@
SlArray(orders, len, SLE_UINT16);
for (i = 0; i < len; ++i) {
- if (!AddBlockIfNeeded(&_order_pool, i))
+ if (IndexedPoolAllocateIndex(&_order_pool, i) == NULL)
error("Orders: failed loading savegame: too many orders");
AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
@@ -1149,7 +1109,7 @@
SlArray(orders, len, SLE_UINT32);
for (i = 0; i < len; ++i) {
- if (!AddBlockIfNeeded(&_order_pool, i))
+ if (IndexedPoolAllocateIndex(&_order_pool, i) == NULL)
error("Orders: failed loading savegame: too many orders");
AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
@@ -1170,7 +1130,7 @@
while ((index = SlIterateArray()) != -1) {
Order *order;
- if (!AddBlockIfNeeded(&_order_pool, index))
+ if (IndexedPoolAllocateIndex(&_order_pool, index) == NULL)
error("Orders: failed loading savegame: too many orders");
order = GetOrder(index);
=== order_gui.c
==================================================================
--- order_gui.c (revision 313)
+++ order_gui.c (local)
@@ -414,7 +414,7 @@
xy = GetStation(ord->station)->xy ;
break;
case OT_GOTO_DEPOT: /* goto depot order */
- xy = GetDepot(ord->station)->xy;
+ xy = GetDepot((DepotID)ord->station)->xy;
break;
case OT_GOTO_WAYPOINT: /* goto waypoint order */
xy = GetWaypoint(ord->station)->xy;
=== pool.c
==================================================================
--- pool.c (revision 313)
+++ pool.c (local)
@@ -7,81 +7,405 @@
#include "pool.h"
/**
- * Clean a pool in a safe way (does free all blocks)
+ * Initialise a newly allocated (or emptied) puddle. Will put all the drops in
+ * the puddle into the appropriate free drops stack
*/
-void CleanPool(MemoryPool *pool)
+static void PoolInitPuddle(MemoryPool* pool, Puddle* puddle, FreeDrop* drops)
{
+ uint drop_size = pool->settings->drop_size;
+ uint puddle_size = pool->settings->puddle_size;
uint i;
+ FreeDrop* last_drop;
- DEBUG(misc, 4)("[Pool] (%s) Cleaning pool..", pool->name);
+ /* In this function we use some casts to byte*, to ensure we get the correct
+ * memory locations. If we would just do arithmetic with FreeDrop*,
+ * arithmetic would be multiplied by sizeof(FreeDrop). Just dividing by that
+ * amount is not guaranteed to work either I expect, because of alignment
+ * issues. */
- /* Free all blocks */
- for (i = 0; i < pool->current_blocks; i++) {
- if (pool->clean_block_proc != NULL) {
- pool->clean_block_proc(i * (1 << pool->block_size_bits), (i + 1) * (1 << pool->block_size_bits) - 1);
- }
- free(pool->blocks[i]);
+ last_drop = (FreeDrop*)((byte*)drops + (puddle_size-1) * drop_size);
+ /* Terminate the list first */
+ if (pool->settings->strategy == POOL_FAST)
+ last_drop->next = pool->free_stack;
+ else
+ last_drop->next = NULL;
+ /* Attach the first drop. We'll attach it to both the puddle and the pool,
+ * even though only one will be used. */
+ pool->free_stack = drops;
+ puddle->free_stack = drops;
+ /* Build the body of the linked list. We skip the last drop, since it is
+ * already terminated */
+ for (i=0;i<(puddle_size-1);i++) {
+ FreeDrop* drop = (FreeDrop*)((byte*)drops + i * drop_size);
+ FreeDrop* next_drop = (FreeDrop*)((byte*)drops + (i+1) * drop_size);
+ drop->next = next_drop;
}
- /* Free the block itself */
- free(pool->blocks);
-
- /* Clear up some critical data */
- pool->total_items = 0;
- pool->current_blocks = 0;
- pool->blocks = NULL;
+ /* Tie up the remaining ends */
+ puddle->drops = drops;
+ puddle->free_drops = puddle_size;
}
/**
- * This function tries to increase the size of array by adding
- * 1 block too it
- *
- * @return Returns false if the pool could not be increased
+ * Adds a puddle to the pool.
+ * @return false if there was an error allocating.
+ * @todo This might reserve memory for more than max_drops drops. The drops
+ * will never actually be allocated, but the memory might be wasted. The last
+ * puddle should probably be smaller.
*/
-bool AddBlockToPool(MemoryPool *pool)
+static bool PoolAddPuddle(MemoryPool* pool)
{
- /* Is the pool at his max? */
- if (pool->max_blocks == pool->current_blocks)
- return false;
+ Puddle* puddles;
+ FreeDrop* drops;
+ uint drop_size = pool->settings->drop_size;
+ uint puddle_size = pool->settings->puddle_size;
- pool->total_items = (pool->current_blocks + 1) * (1 << pool->block_size_bits);
+
+ /* See if our puddles array is big enough */
+ if (pool->num_puddles == pool->puddles_length) {
+ /* Cache this value so it remains unchanged if allocation fails */
+ uint puddles_length = pool->puddles_length;
+ /* We need to increase the puddles array first */
+ if (puddles_length == 0)
+ /* Start with room for 5 puddles */
+ puddles_length = 5;
+ else
+ /* Double on subsequent increases */
+ puddles_length *= 2;
- DEBUG(misc, 4)("[Pool] (%s) Increasing size of pool to %d items (%d bytes)", pool->name, pool->total_items, pool->total_items * pool->item_size);
+ puddles = (Puddle*)realloc(pool->puddles, sizeof(Puddle) * puddles_length);
+ if (puddles == NULL)
+ return false; /* Error allocating */
+ pool->puddles = puddles;
+ pool->puddles_length = puddles_length;
+ }
+
+ /* Allocate a new puddle */
+ drops = (FreeDrop*)malloc(puddle_size * drop_size);
+ if (drops == NULL)
+ return false; /* Error allocating */
- /* Increase the poolsize */
- pool->blocks = realloc(pool->blocks, sizeof(pool->blocks[0]) * (pool->current_blocks + 1));
- if (pool->blocks == NULL)
- error("Pool: (%s) could not allocate memory for blocks", pool->name);
+ PoolInitPuddle(pool, &pool->puddles[pool->num_puddles], drops);
+ pool->free_drops += puddle_size;
+ pool->num_puddles++;
- /* Allocate memory to the new block item */
- pool->blocks[pool->current_blocks] = malloc(pool->item_size * (1 << pool->block_size_bits));
- if (pool->blocks[pool->current_blocks] == NULL)
- error("Pool: (%s) could not allocate memory for blocks", pool->name);
+ return true;
+}
- /* Clean the content of the new block */
- memset(pool->blocks[pool->current_blocks], 0, pool->item_size * (1 << pool->block_size_bits));
+static inline bool PoolDropInPuddle(MemoryPool* pool, Puddle* puddle, FreeDrop* drop) {
+ return (
+ drop >= puddle->drops &&
+ drop < (FreeDrop*)((byte*)puddle->drops + pool->settings->drop_size * pool->settings->puddle_size)
+ );
+}
- /* Call a custom function if defined (e.g. to fill indexes) */
- if (pool->new_block_proc != NULL)
- pool->new_block_proc(pool->current_blocks * (1 << pool->block_size_bits));
+void PoolInitialize(MemoryPool* pool, const MemoryPoolSettings* settings)
+{
+ /* Set default values. Note that we set values regardless of strategy,
+ * meaning some of the values won't be used. But hey, who cares? */
+ pool->settings = settings;
+ pool->num_puddles = 0;
+ pool->puddles_length = 0;
+ pool->free_drops = 0;
+ pool->puddles = NULL;
+ pool->free_stack = NULL;
+ pool->first_free_puddle = 0;
+ pool->num_drops = 0;
+}
- /* We have a new block */
- pool->current_blocks++;
+void* PoolAllocateDrop(MemoryPool* pool)
+{
+ PoolInitializeDrop* proc = pool->settings->init_drop_proc;
+ FreeDrop* drop;
+ Puddle* puddle;
- return true;
+ if (pool->settings->max_drops != POOL_NO_LIMIT && pool->num_drops >= pool->settings->max_drops)
+ return NULL; /* Maximum drops reached */
+
+ /* Do we need to allocate more memory? */
+ if (pool->free_drops == 0)
+ if (!PoolAddPuddle(pool))
+ /* Error allocating */
+ return NULL;
+ assert(pool->free_drops);
+
+ switch(pool->settings->strategy) {
+ case POOL_FAST:
+ /* Fetch the top drop from the free stack */
+ drop = pool->free_stack;
+ pool->free_stack = drop->next;
+ break;
+
+ case POOL_SMALL:
+ puddle = &pool->puddles[pool->first_free_puddle];
+
+ /* Fetch the top drop from the puddle's free stack */
+ drop = puddle->free_stack;
+ puddle->free_stack = drop->next;
+
+ puddle->free_drops--;
+ if (puddle->free_drops == 0)
+ pool->first_free_puddle++;
+
+ /* Note that when allocating a drop, the sort order of puddles will
+ * always remain unchanged. Also, if the puddle becomes full, we can
+ * safely just increment first_free_puddle, since the next puddle cannot
+ * be full (it would have sorted before the current puddle then). */
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ pool->free_drops--;
+ pool->num_drops++;
+
+ /* Call the callback if needed */
+ if (proc) proc(pool, drop);
+
+ return drop;
}
-/**
- * Adds blocks to the pool if needed (and possible) till index fits inside the pool
- *
- * @return Returns false if adding failed
- */
-bool AddBlockIfNeeded(MemoryPool *pool, uint index)
+void PoolFreeDrop(MemoryPool* pool, void* ptr)
{
- while (index >= pool->total_items) {
- if (!AddBlockToPool(pool))
- return false;
+ PoolDestroyDrop* proc = pool->settings->destroy_drop_proc;
+ uint puddle_index;
+ uint swap_index;
+ Puddle swap_puddle;
+ Puddle* puddle = NULL;
+ FreeDrop* drop = (FreeDrop*)ptr;
+
+ /* Call the callback if needed */
+ if (proc) proc(pool, drop);
+
+ switch(pool->settings->strategy) {
+ case POOL_FAST:
+ /* Push the drop on the free stack */
+ drop->next = pool->free_stack;
+ pool->free_stack = drop;
+ break;
+
+ case POOL_SMALL:
+ /* Find the pool in which the drop was allocated */
+ for(puddle_index=0;puddle_indexnum_puddles;puddle_index++) {
+ puddle = &pool->puddles[puddle_index];
+ /* Check if the drop is in the memory area of this puddle */
+ if (PoolDropInPuddle(pool, puddle, drop))
+ break;
+ puddle = NULL;
+ }
+ assert(puddle != NULL);
+
+ /* Push the drop on the puddle's free stack */
+ drop->next = puddle->free_stack;
+ puddle->free_stack = drop;
+
+ puddle->free_drops++;
+
+ /* See if we need to reorder this puddle to keep the puddles sorted by
+ * usage (ascending by free_drops) */
+ swap_index = puddle_index + 1;
+ while (swap_index < pool->num_puddles && pool->puddles[swap_index].free_drops < puddle->free_drops)
+ swap_index++; /* Find the highest index for which the puddle has more free drops. */
+ swap_index--; /* We need to swap with one puddle before that */
+ if (swap_index != puddle_index) {
+ /* Since free_drops is only changed by one, we don't have to push back
+ * all puddles between the new and old position of the puddle, we can
+ * simply just swap them */
+ swap_puddle = *puddle;
+ *puddle = pool->puddles[swap_index];
+ puddle = &pool->puddles[swap_index];
+ *puddle = swap_puddle;
+ }
+ if (puddle->free_drops == pool->settings->puddle_size) {
+ /* We've freed a complete puddle, let's free its memory */
+ free(puddle->drops);
+ /* We can just decrement this to record the puddle is now empty, since
+ * due to sorting, an unused puddle is always at the end */
+ pool->num_puddles--;
+ pool->free_drops -= pool->settings->puddle_size;
+ }
+ break;
+
+ default:
+ NOT_REACHED();
}
- return true;
+ pool->free_drops++;
+ pool->num_drops--;
}
+
+void PoolEmpty(MemoryPool* pool, bool reuse)
+{
+ uint i;
+ if (reuse) {
+ /* Reinitialise values */
+ pool->free_stack = NULL;
+ pool->free_drops = pool->settings->puddle_size * pool->num_puddles;
+ pool->first_free_puddle = 0;
+ pool->num_drops = 0;
+ }
+ for (i=0;inum_puddles;i++) {
+ Puddle* puddle = &pool->puddles[i];
+ if (reuse)
+ /* Reinitialize the puddle, filling the free stack with the drops */
+ PoolInitPuddle(pool, puddle, puddle->drops);
+ else
+ /* Free the memory used by this puddle */
+ free(puddle->drops);
+ }
+
+ if (!reuse)
+ /* Free the last memory used by the pool */
+ free(pool->puddles);
+}
+
+void IndexedPoolInitialize(IndexedPool* pool, const IndexedPoolSettings* settings)
+{
+ pool->settings = settings;
+ pool->lowest_free_index = 0;
+ pool->highest_used_index = 0;
+ pool->drops_length = 0;
+ pool->free_indices = 0;
+ pool->drops = NULL; /* We won't allocate any indices yet, will happen on first allocate */
+ PoolInitialize(&pool->sub_pool, &settings->pool_settings);
+}
+
+DropIndex IndexedPoolAllocateDrop(IndexedPool* pool)
+{
+ DropIndex index = pool->lowest_free_index;
+ /* Find a free index */
+ while (index < pool->drops_length && pool->drops[index] != NULL)
+ index++;
+
+ /* When we end up here, either index == drops_length, or we have found
+ * a free index. Either case means that index is an unused index, and
+ * IndexedPoolAllocateIndex will make sure the drops array gets realloc'd if
+ * needed */
+
+ pool->lowest_free_index = index + 1;
+
+ if (IndexedPoolAllocateIndex(pool, index) != NULL)
+ return index;
+ else
+ /* Error allocating */
+ return INVALID_DROP;
+}
+
+void* IndexedPoolAllocateIndex(IndexedPool* pool, DropIndex index)
+{
+ if (index > pool->highest_used_index)
+ pool->highest_used_index = index;
+
+ if (pool->sub_pool.settings->max_drops != POOL_NO_LIMIT && index >= pool->sub_pool.settings->max_drops)
+ return NULL;
+
+ /* Check if our drops array is long enough */
+ if (index >= pool->drops_length) {
+ void** ptr;
+ uint new_length = pool->drops_length;
+ uint i;
+ if (new_length == 0) new_length = pool->sub_pool.settings->puddle_size;
+ while(index >= new_length)
+ /* Enlarge it till it fits */
+ new_length *= 2;
+ ptr = realloc(pool->drops, new_length * sizeof(pool->drops[0]));
+ /* Check for allocation error */
+ if (!ptr) return NULL;
+ /* Save and initialize the newly allocated memory, if succesful */
+ pool->drops = ptr;
+ pool->free_indices += new_length - pool->drops_length;
+ for (i=pool->drops_length; idrops[i] = NULL;
+ pool->drops_length = new_length;
+ }
+
+ /* Allocate a new drop if needed */
+ if (pool->drops[index] == NULL) {
+ IndexedPoolInitializeDrop* proc = pool->settings->init_drop_proc;
+
+ pool->drops[index] = PoolAllocateDrop(&pool->sub_pool);
+ if (pool->drops[index] == NULL)
+ return NULL; /* Allocation failed */
+ pool->free_indices--;
+
+ /* Call initialisation proc if needed */
+ if (proc)
+ proc(pool, pool->drops[index], index);
+ }
+
+ return pool->drops[index];
+}
+
+void IndexedPoolFreeDrop(IndexedPool* pool, DropIndex index)
+{
+ IndexedPoolDestroyDrop* proc = pool->settings->destroy_drop_proc;
+ void* drop = IndexedPoolGetItem(pool, index);
+ assert(drop != NULL);
+
+ /* Call the callback before freeing the drop */
+ if (proc) proc(pool, drop, index);
+
+ /* Free the actual drop */
+ PoolFreeDrop(&pool->sub_pool, drop);
+
+ /* Free the index */
+ pool->drops[index] = NULL;
+
+ /* See if lowest_free_index was changed */
+ if (index < pool->lowest_free_index)
+ pool->lowest_free_index = index;
+
+ pool->free_indices++;
+}
+
+uint IndexedPoolNumUsed(IndexedPool* pool)
+{
+ if (pool->sub_pool.num_drops == 0)
+ return 0;
+
+ /* index >= the highest used index, so we might need to look at lower
+ * indices to find the actual highest used index.
+ * We don't need to check for highest_used_index underflowing, because it
+ * will always find a used index (since num_used > 0, see above). */
+ while (IndexedPoolGetItem(pool, pool->highest_used_index) == NULL) pool->highest_used_index--; /* Look down while we haven't found an allocated index */
+
+ return pool->highest_used_index + 1; /* The number of used indices is one greater than the highest used index */
+}
+
+uint IndexedPoolNumFree(const IndexedPool* pool)
+{
+ /* TODO: What if max_drops is POOL_NO_LIMIT? */
+ return pool->sub_pool.settings->max_drops - pool->sub_pool.num_drops;
+}
+
+uint IndexedPoolNumAllocated(const IndexedPool* pool)
+{
+ return pool->sub_pool.num_drops;
+}
+
+void IndexedPoolEmpty(IndexedPool* pool)
+{
+ uint i;
+ IndexedPoolDestroyDrop* proc = pool->settings->destroy_drop_proc;
+
+ /* Destroy the drops */
+ if (proc) {
+ /* If there is a callback, call it for all allocated indices */
+ for (i=0;idrops_length;i++) {
+ void* drop = IndexedPoolGetItem(pool, i);
+ if (drop != NULL)
+ proc(pool, drop, i);
+ /* Note that we do not free the drop here, instead we will just call
+ * PoolEmpty() below */
+ }
+ }
+
+ /* Free the indices */
+ if (pool->drops != NULL)
+ free(pool->drops);
+ pool->drops_length = 0;
+
+ /* Free the actual drops */
+ PoolEmpty(&pool->sub_pool, false);
+}
=== pool.h
==================================================================
--- pool.h (revision 313)
+++ pool.h (local)
@@ -3,57 +3,555 @@
#ifndef POOL_H
#define POOL_H
+#include "functions.h"
+
+/**
+ * @file pool.h
+ * @brief Provides functions to work with pools of memory.
+ *
+ * @section memuse Historical background on memory usage
+ *
+ * In a lot of places, we need memory allocation of certain structs (Vehicles,
+ * Stations, etc.). Originally these were statically allocated as an array of
+ * the given struct type. The main problem with this approach is that the
+ * number of available items is fixed (therefore way too large at first, but
+ * limited later on).
+ *
+ * Naive solutions would be to just realloc() the memory or malloc() the
+ * individual structs. Both of these would mean severe performance penalties,
+ * the latter would also remove the ability to address items by their ID
+ * (translate a VehicleID to a Vehicle* for example).
+ *
+ * The solution we will choose here is a mix of using realloc() and malloc()
+ * to minimise performance penalty. We will be using pools, puddles and drops.
+ * would be to just malloc() a block of memory
+ *
+ * @section pools Using pools
+ *
+ * For allocating memory, we use pools. A pool is a pile of memory from which
+ * we can allocate and deallocate drops. A drop would correspond to a Vehicle
+ * or Station struct for example. All drops within a given pool have the same
+ * size, and typically contain the same struct.
+ *
+ * We acknowledge two uses for pools.
+ * @subsection normalpools Normal pools
+ * These are pools which replace "normal" calls to malloc and free. Typical
+ * uses are elements of linked lists, hashes, etc.
+ *
+ * The interface for this is limited: You can allocated drops, free drops,
+ * and empty the pool.
+ *
+ * This type of pool will generally be used for memory that is need for short
+ * amounts of time, like buckets for a hash table or nodes in the pathfinder.
+ * This mainly needs fast allocation and freeing of drops.
+ * The pool will therefore use O(1) allocs and frees, at the cost of lots of
+ * fragmentation after freeing nodes. (It also supports avoiding fragmentation
+ * for use with indexed pools, see below).
+ *
+ * @subsection indexedpools Indexed Pools
+ * These are pools for which we need to associate an index with each drop.
+ * Typical uses are structs that need to be referenced from the map arrays
+ * (which doesn't support pointers) such as Stations and Towns.
+ *
+ * The interface for this consists of allocating drops (either with a specific
+ * index, or just any free index), freeing drops by passing the index, finding
+ * the drop corresponding to a given index and emptying the pool.
+ *
+ * Indexed pools will be build on top of normal pools. Unlike normal pools,
+ * they will try to prevent fragmentation and reclaim memory whenever
+ * possibly. It will however never move drops around in memory, since that
+ * would invalidate existing pointers.
+ *
+ * @section pools_implementation Implementation of pools using puddles and drops
+ *
+ * Internally, a pool consists of a number of puddles. Each puddle contains a
+ * fixed number of drops (specified at pool initialisation). When a pool is
+ * initialised, a single puddle is allocated (using malloc).
+ *
+ * From this puddle, single drops can be allocated and freed again.
+ * When all the drops in a pool have been allocated, a new puddle will be
+ * malloc'd. A pool will keep track of it's puddles (which will not be
+ * adjacent in memory) using an array of puddle pointers. This array is
+ * initially malloc'd and realloc'd when it fills up. To properly support
+ * both types of pools, we define two strategies for allocating and freeing
+ * individiual drops.
+ *
+ * @subsection fast_strategy Fast strategy
+ * This is for normal pools that will only be used for a small period of time
+ * in which they will do a lot of allocs and de-allocs. Allocing and freeing
+ * will be O(1) operations. The downside of optimising for speed will be lots
+ * of fragmentation, ie it will hardly ever happen that an entire puddle
+ * becomes empty, so it can be reclaimed. If that does indeed happen, we will
+ * not reclaim it, since we will probably need it again right away, or we will
+ * be done soon anyway.
+ *
+ * When the pool is emptied, optionally only a part of the memory will be
+ * reclaimed so it can be reused easily. We will always reclaim some memory,
+ * since otherwise one peak usage of a pool will keep a lot of unused memory
+ * allocated forever.
+ *
+ * This strategy's implementation is straight-forward. We keep a stack (linked
+ * list) of free drops (using the memory of the drop itself to store the
+ * link). When we need to allocate a new drop, we pop the first drop from the
+ * stack, if a drop gets freed we push it on the stack. Whenever a new pool
+ * gets allocated we will push all the drops in it to the stack.
+ *
+ * @subsection small_strategy Small strategy
+ * This is for indexed pools, or normal pools which will be used over a longer
+ * period of time, with only a few allocs and deallocs. This strategy will
+ * make sure that new allocs always happen in the puddle that's the most full.
+ * This ensures that free drops will group together, possibly allowing the
+ * pool to return one or more puddles to the OS.
+ *
+ * The implementation of this strategy is a little more complicated. Since we
+ * need to be able to allocate a drop in the fullest puddle, we need to keep a
+ * seperate stack of free drops for each puddle. We also need to find the
+ * fullest puddle quickly, so we'll keep the list of puddles sorted by number
+ * of allocated drops (fullest first). Since the first few will probably be
+ * full, we will also keep the index of the first non-full puddle.
+ *
+ * The sorting will be done whenever a drop is allocated or freed. Since the
+ * number of allocated drops will only increase or decrease by one, we can
+ * suffice by swapping the puddle with another (possibly a few) upwards or
+ * downwards.
+ *
+ * The trickiest part of this is when a drop is freed. We will need to find
+ * out in which puddle the drop belongs to put it in the right free drops
+ * stack. We will do this by iterating all the puddles and checking the
+ * address range.
+ *
+ * Lastly, whenever a puddle becomes empty, we will return the memory it uses
+ * to the OS.
+ */
+
+/**
+ * This is the type to store information about a memory pool.
+ */
typedef struct MemoryPool MemoryPool;
-/* The function that is called after a new block is added
- start_item is the first item of the new made block */
-typedef void MemoryPoolNewBlock(uint start_item);
-/* The function that is called before a block is cleaned up */
-typedef void MemoryPoolCleanBlock(uint start_item, uint end_item);
+/**
+ * A callback function to be called after a drop has been allocated.
+ * @param pool The pool in which the drop was allocated.
+ * @param drop A pointer to the newly allocated drop.
+ * GetMemoryPool(pool) == POOL_NORMAL \endcode
+ */
+typedef void PoolInitializeDrop(const MemoryPool* pool, void* drop);
/**
- * Stuff for dynamic vehicles. Use the wrappers to access the MemoryPool
- * please try to avoid manual calls!
+ * A callback function to be called just before a drop will be freed.
+ * @param pool The pool in which the drop was allocated.
+ * @param drop A pointer to the about to be freed drop.
+ * @param index The index of the about to be freed drop.
*/
+typedef void PoolDestroyDrop(const MemoryPool* pool, void* drop);
+
+typedef enum MemoryPoolStrategies {
+ POOL_FAST,
+ POOL_SMALL,
+} MemoryPoolStrategy;
+
+enum {
+ POOL_NO_LIMIT = 0,
+};
+
+/** Used to pass settings for a new pool to \c PoolInitialize() */
+typedef struct MemoryPoolSettings {
+ const char name[16]; /**< Name of the pool (just for debugging). */
+ const uint max_drops; /**< The max amount of drops this pool can have (Artificial limit), or POOL_NO_LIMIT for no limit. */
+ const uint puddle_size; /**< The size of each puddle */
+ const uint drop_size; /**< How many bytes one item is. */
+ const MemoryPoolStrategy strategy; /**< The strategy to use for allocating and freeing drops */
+
+ const PoolInitializeDrop* init_drop_proc;
+ /**< Pointer to a function that is called after a drop is allocated or NULL */
+ const PoolDestroyDrop* destroy_drop_proc;
+ /**< Pointer to a function that is called before a drop is freed or NULL */
+
+} MemoryPoolSettings;
+
+/**
+ * Initializes a new memory pool. Must be called before calling any other
+ * function on the pool. May also be used on emptied pools (with reuse=false)
+ * to change the settings.
+ * @param pool The pool to initialize.
+ * @param settings The settings to use for this pool.
+ * @warning The settings are not copied, but stored by reference. You should
+ * _not_ change the settings after initializing a pool with them!
+ */
+void PoolInitialize(MemoryPool* pool, const MemoryPoolSettings* settings);
+
+/**
+ * Allocate a new drop, possibly expanding the pool if needed.
+ * @return A pointer to the drop of memory, NULL if the drop could not be
+ * allocated.
+ * @param pool The pool in which to allocate the drop.
+ */
+void* PoolAllocateDrop(MemoryPool* pool);
+
+/**
+ * Free a previously allocated drop.
+ * @param pool The pool in which the drop was allocated.
+ * @param drop The drop to free.
+ */
+void PoolFreeDrop(MemoryPool* pool, void* drop);
+
+/**
+ * Empties the pool, deallocating all allocated drops.
+ * @param pool The pool to empty.
+ * @param reuse If you are planning to reuse the pool. If this is true, the
+ * pool will retain most of its resources, otherwise it will free
+ * all resources.
+ * @note that you can always just reuse this a pool, though it will be faster
+ * if reuse was true. Reinitializing is not neccesary, and will even
+ * cause memory leaks when reuse=true!
+ */
+void PoolEmpty(MemoryPool* pool, bool reuse);
+
+/**
+ * Keeps info about free drops. Used to build a linked list of free drops.
+ */
+typedef struct FreeDrop FreeDrop;
+struct FreeDrop {
+ FreeDrop* next;
+};
+
+/**
+ * Keeps info about a puddle.
+ */
+typedef struct Puddle {
+ uint free_drops; /**< How many drops in this puddle are free (used for the small strategy only) */
+ FreeDrop* free_stack; /**< A pointer to the first free drop in this puddle (used for the small strategy only) */
+ FreeDrop* drops; /**< An array of drops in the puddle */
+} Puddle;
+
+/**
+ * Keeps info about a pool. Never use directly!
+ */
struct MemoryPool {
- const char name[10]; ///< Name of the pool (just for debugging)
+ const MemoryPoolSettings* settings; /**< The settings for this pool */
+ uint num_puddles; /**< The number of puddles actually in use */
+ uint puddles_length; /**< The length of the puddles array */
+ uint free_drops; /**< How many drops are in the pool are free. This is the number of drops in allocated puddles, this is number is not related to the max_drops in the settings! */
+ uint num_drops; /**< The total number of drops allocated */
- const uint max_blocks; ///< The max amount of blocks this pool can have
- const uint block_size_bits; ///< The size of each block in bits
- const uint item_size; ///< How many bytes one block is
+ Puddle* puddles; /**< An array of puddles (Sorted by Puddle.free_drops for the small strategy). */
+ FreeDrop* free_stack; /**< A pointer to the first free drop in the pool (used for the fast strategy only) */
- /// Pointer to a function that is called after a new block is added
- MemoryPoolNewBlock *new_block_proc;
- /// Pointer to a function that is called to clean a block
- MemoryPoolCleanBlock *clean_block_proc;
+ uint first_free_puddle; /**< The index of the first puddle that still has free elements (used for the small strategy only) */
+};
- uint current_blocks; ///< How many blocks we have in our pool
- uint total_items; ///< How many items we now have in this pool
+/**
+ * This is the type to store information about an indexed pool.
+ */
+typedef struct IndexedPool IndexedPool;
- byte **blocks; ///< An array of blocks (one block hold all the items)
+/**
+ * This is used to index drops in an index pool.
+ */
+typedef uint DropIndex;
+
+enum {
+ INVALID_DROP = ~((uint)0), /**< Used to signify failed allocation of a drop */
};
/**
- * Those are the wrappers:
- * CleanPool cleans the pool up, but you can use AddBlockToPool directly again
- * (no need to call CreatePool!)
- * AddBlockToPool adds 1 more block to the pool. Returns false if there is no
- * more room
+ * A callback function to be called after a drop has been allocated.
+ * @param pool The pool in which the drop was allocated.
+ * @param drop A pointer to the newly allocated drop.
+ * @param index The index of the newly allocated drop. Unused if \code
+ * GetMemoryPool(pool) == POOL_NORMAL \endcode
*/
-void CleanPool(MemoryPool *array);
-bool AddBlockToPool(MemoryPool *array);
+typedef void IndexedPoolInitializeDrop(const IndexedPool* pool, void* drop, DropIndex index);
/**
- * Adds blocks to the pool if needed (and possible) till index fits inside the pool
- *
- * @return Returns false if adding failed
+ * A callback function to be called just before a drop will be freed.
+ * @param pool The pool in which the drop was allocated.
+ * @param drop A pointer to the about to be freed drop.
+ * @param index The index of the about to be freed drop.
*/
-bool AddBlockIfNeeded(MemoryPool *array, uint index);
+typedef void IndexedPoolDestroyDrop(const IndexedPool* pool, void* drop, DropIndex index);
-static inline byte *GetItemFromPool(const MemoryPool *pool, uint index)
+/** Used to pass settings for a new indexed pool to \c IndexedPoolInitialize() */
+typedef struct IndexedPoolSettings {
+ const char name[16]; /**< Name of the pool (just for debugging). */
+ const IndexedPoolInitializeDrop* init_drop_proc;
+ /**< Pointer to a function that is called after a drop is allocated or NULL */
+ const IndexedPoolDestroyDrop* destroy_drop_proc;
+ /**< Pointer to a function that is called before a drop is freed or NULL. */
+ const MemoryPoolSettings pool_settings;
+ /**< Settings to use for the underlying memory
+ pool. \c strategy should generally be
+ POOL_SMALL, init_drop_proc and
+ destroy_drop_proc should be NULL */
+} IndexedPoolSettings;
+
+/**
+ * Initializes a new indexed pool. Must be called before calling any other
+ * function on the pool. May also be used on emptied pools to change the
+ * settings.
+ * @param pool The pool to initialize.
+ * @param settings The settings to use for this pool.
+ * @warning The settings are not copied, but stored by reference. You should
+ * _not_ change the settings after initializing a pool with them!
+ */
+void IndexedPoolInitialize(IndexedPool* pool, const IndexedPoolSettings* settings);
+
+/**
+ * Allocate a new drop, possibly expanding the pool if needed.
+ * @return The index of the allocated drop, or INVALID_DROP if the drop could
+ * not be allocated.
+ * @param pool The pool in which to allocate the drop.
+ */
+DropIndex IndexedPoolAllocateDrop(IndexedPool* pool);
+
+/**
+ * Allocate a given index, possibly expanding the pool if needed. If the given
+ * index was already allocated, just return the appropriate drop.
+ * @return A pointer to the drop or NULL If allocation failed.
+ * @param pool The pool in which to allocate the drop.
+ * @param index The index that needs to be allocated.
+ */
+void* IndexedPoolAllocateIndex(IndexedPool* pool, DropIndex index);
+
+/**
+ * Free a previously allocated drop.
+ * @param pool The pool in which the drop was allocated.
+ * @param index The index of the drop to free.
+ */
+void IndexedPoolFreeDrop(IndexedPool* pool, DropIndex index);
+
+/**
+ * Empties the pool, deallocating all allocated drops. This pool is still
+ * usable afterwards.
+ * @param pool The pool to empty.
+ */
+void IndexedPoolEmpty(IndexedPool* pool);
+
+/**
+ * Returns the number of used indices, counting unused indices that lie between
+ * used indices as used. This value can be used for looping all items in the
+ * pool (with the < operator). Be careful to skip the unused items, though.
+ * In other words, this returns one greater than the largest allocated index.
+ * @note This is not the complement of \c IndexedPoolNumFree(), that would be
+ * \c IndexedPoolNumAllocated().
+ */
+uint IndexedPoolNumUsed(IndexedPool* pool);
+
+/**
+ * Returns the number of unallocated indices in the pool. In other words,
+ * returns the numer of times IndexedPoolAllocateDrop can be called before it
+ * will fail due to reaching the maximum number of drops.
+ */
+uint IndexedPoolNumFree(const IndexedPool* pool);
+
+/**
+ * Returns the numer of allocated indices. This does not count unused indices
+ * between allocated indices as \c IndexedPoolNumUsed() does and might count a
+ * few extra unused indices at the end.
+ */
+uint IndexedPoolNumAllocated(const IndexedPool* pool);
+
+/**
+ * Keeps info about an indexed pool. Never use directly!
+ */
+struct IndexedPool {
+ const IndexedPoolSettings* settings;/**< The settings for this pool */
+ uint lowest_free_index; /**< An index that is guaranteed to be <= the lowest free index. Is not to be guaranteed to be equal, so that allocating an index is cheaper. */
+ uint highest_used_index; /**< An index that is guaranteed to be >= the highest used index. Is not to be guaranteed to be equal, so that freeing an index is cheaper. */
+ void** drops; /**< An array mapping indices to pointers to drops. */
+ MemoryPool sub_pool; /**< The pool used to allocate drops */
+ uint drops_length; /**< The length of the drops array */
+ uint free_indices; /**< The number of free indices in the drops array. Not related to the total maximum in the settings. */
+};
+
+/**
+ * Looks up the given index in the pool and returns the corresponding drop.
+ * @param pool The pool in which to look.
+ * @param index The index of the drop to return.
+ * @return The drop with the given index, or NULL if the drop was not
+ * allocated. Also returns NULL for INVALID_DROP.
+ */
+static inline void* IndexedPoolGetItem(const IndexedPool* pool, DropIndex index)
{
- assert(index < pool->total_items);
- return (pool->blocks[index >> pool->block_size_bits] + (index & ((1 << pool->block_size_bits) - 1)) * pool->item_size);
+ if (index < pool->drops_length)
+ return pool->drops[index];
+ else
+ return NULL;
}
+/**
+ * Looks up the next allocated index after the given index, skipping n indices
+ * every time. For example, this will first check if index + n is allocated.
+ * If so, it will return. If not, it will check index + 2*n, after that it
+ * will check index + 3*n, etc, until it finds one. Will return the found
+ * index, or INVALID_DROP if there was no such index.
+ * @param pool The pool in which the index should be looked up.
+ * @param index The index after which to look.
+ */
+static inline DropIndex IndexedPoolGetNextSkip(IndexedPool* pool, DropIndex index, uint n)
+{
+ /* Look for the next allocated index */
+ do {
+ index += n;
+ if (index >= IndexedPoolNumUsed(pool))
+ return INVALID_DROP;
+ }
+ while (IndexedPoolGetItem(pool, index) == NULL);
+
+ return index;
+}
+/**
+ * Looks up the next allocated index after the given index.
+ * @param pool The pool in which the index should be looked up.
+ * @param index The index after which to look.
+ * @param The smallest allocated index > index, or INVALID_DROP if there is
+ * no such index is found.
+ */
+static inline DropIndex IndexedPoolGetNext(IndexedPool* pool, DropIndex index)
+{
+ return IndexedPoolGetNextSkip(pool, index, 1);
+}
+
+/**
+ * Same as FOR_ALL_IN_POOL, but only iterates elements with index >= start.
+ */
+#define FOR_ALL_IN_POOL_FROM(pool, ptr, start) \
+ for (ptr = IndexedPoolGetItem(&pool, start); \
+ ptr != NULL; \
+ ptr = IndexedPoolGetItem(&pool, IndexedPoolGetNext(&pool, ptr->index)) \
+ )
+
+/**
+ * Loop all elements in the pool. Behaves similar to a normal for loop, you
+ * should put {} after it if appropriate. Will store a pointer to the current
+ * element in ptr.
+ * @note This will only work for elements that have an "index" field that
+ * contains the index of the element.
+ */
+#define FOR_ALL_IN_POOL(pool, ptr) FOR_ALL_IN_POOL_FROM(pool, ptr, 0)
+
+/**
+ * This loop is designed to iterate all elements in a pool, every so much
+ * ticks. You should use this for loop once every tick, the loop will make
+ * sure that each element (index) gets iterated exactly once every n ticks.
+ * @warning This requires ptr to have a field "index" which contains the index
+ * of the drop!
+ * @param pool The pool in which to iterate elements
+ * @param ptr A pointer in which the pointer to the element is stored.
+ * @param n The number of ticks between iterations of the same element.
+ * Different frequencies per pool are supported, but each should
+ * have a different ctr variable. In other words, don't change
+ * the value of n between ticks when using the same ctr variable.
+ * @param ctr A variable of type DropIndex, used to store the state between
+ * ticks. Can be initialized to any value, should not be modified
+ * except for by this macro.
+ */
+#define FOR_ALL_EVERY_N_TICKS(pool, ptr, n, ctr) \
+ for (ctr %= n,ptr = IndexedPoolGetItem(&pool, ctr++); \
+ ptr != NULL; \
+ ptr = IndexedPoolGetItem(&pool, IndexedPoolGetNextSkip(&pool, ptr->index, n)) \
+ )
+ /* This loop works by iterating indices [0, n, 2n, 3n, ...] on the first
+ * run. On the second run, it iterates [1, n+1, 2n+1, 3n+1, ...]. This goes
+ * on until it iterates [(n-1), n+(n-1), 2n+(n-1), 3n+(n-1), ...]. After
+ * that, it iterates the first series again. In other words, we iterate
+ * [(x % n)n+y], where x is the number of ticks passed, and y is the number
+ * of the iteration within the current tick.
+ *
+ * A first implementation that comes to mind is:
+ * \code
+ * while ( ctr < poolsize ) {
+ * ctr += n; // Were iterating xn+y
+ * do_stuff(ctr);
+ * }
+ * ctr %= n; //
+ * ctr++;
+ * \endcode
+ *
+ * The problem with this code is twofold: We need to do things inside the
+ * main loop, which means no variable declarations can be made after the
+ * macro. Second, we need to do stuff after the loop, which means a second
+ * macro to close the loop.
+ * We can solve the first by using a for loop instead of while. The second
+ * we can solve by moving the termination code to the start of the loop.
+ * This means we can put it in the first element of the for statement.
+ * The added advantage to this, is that the counter needs no initialisation,
+ * it'll wrap into valid range because of the %, and it we don't really care
+ * where we start the iteration (at which value of x). We do need to save
+ * the value!
+ * Also, we use the IndexedPoolGetNextSkip function to replace ctr += n,
+ * since that will skip unallocated elements. This also means we store the
+ * counter in ptr->index instead of the ctr variable.
+ */
+
+/**
+ * Shortcut macro for defining IndexedPoolSettings. Assumes the type that is
+ * used to store indices for this pool is named TypeID, where Type is of
+ * course the given type.
+ * The pool will have the POOL_SMALL strategy, a drop size appropriate for the
+ * given type and a maximum number of elements chosen such that there will
+ * never be an index that doesn't fit in an index of type TypeID, while saving
+ * the largest possible index as an invalid index.
+ * @param type The type of the elements to be stored in this pool.
+ * @param puddle_size The number of elements that will be allocated at a time.
+ * @param init_proc A function that will be called for each new element.
+ * @param destroy_proc A function that will be called for each removed element.
+ */
+#define INDEXED_POOL(type, puddle_size) \
+ { #type, (const IndexedPoolInitializeDrop*)&Initialize##type, (const IndexedPoolDestroyDrop*)&Destroy##type, { #type "_sub", MAX_VALUE(type##ID), puddle_size, sizeof(type), POOL_SMALL, NULL, NULL}}
+
+/**
+ * To be used in a DestroyProc. Shortcut that zeroes the drop and sets the
+ * index field of the struct to the right index.
+ */
+#define ZERO_AND_INDEX(type, drop) \
+ memset(drop, 0, sizeof(type)), \
+ ((type*)drop)->index = index;
+
+/*
+ * Will define \c GetType(), \c GetNumTypes(), \c AllocateType, \c
+ * DeleteType(), \c IsValidTypeID() and \c GetRandomType().
+ */
+#define INDEXED_POOL_FUNCTIONS(type, plural, pool) \
+ static inline type* Get##type(type##ID index) { \
+ /*return (type*)IndexedPoolGetItem(&pool, index); */ \
+ type* ret = (type*)IndexedPoolGetItem(&pool, index); \
+ assert (ret->index == index); \
+ return ret; \
+ } \
+ \
+ static inline uint GetNum##plural(void) { \
+ return IndexedPoolNumAllocated(&pool); \
+ } \
+ \
+ static inline uint GetNum##plural##Used(void) { \
+ return IndexedPoolNumUsed(&pool); \
+ } \
+ \
+ static inline uint GetNum##plural##Free(void) { \
+ return IndexedPoolNumFree(&pool); \
+ } \
+ \
+ static inline type* Allocate##type(void) { \
+ DropIndex index = IndexedPoolAllocateDrop(&pool); \
+ if (index == INVALID_DROP) return NULL; \
+ return Get##type((type##ID)index); \
+ } \
+ \
+ static inline void Delete##type(type* ptr) { \
+ IndexedPoolFreeDrop(&pool, ptr->index); \
+ } \
+ \
+ static inline type* GetRandom##type(void) { \
+ uint num = RandomRange(GetNum##plural()); /* The nth drop we will return. This is _not_ the index, since there may be indices missing */ \
+ type##ID index = 0; \
+ uint i; \
+ for (i=0;ibuckets_in_use = (bool*)(h->buckets + num_buckets);
h->freeh = false;
for (i = 0; i < num_buckets; i++) h->buckets_in_use[i] = false;
+ PoolInitialize(&h->pool, &_hash_pool_settings);
}
Hash* new_Hash(Hash_HashProc* hash, int num_buckets)
@@ -484,30 +500,14 @@
void delete_Hash(Hash* h, bool free_values)
{
- uint i;
+ /* Clear out the buckets and the values */
+ clear_Hash(h, free_values);
- /* Iterate all buckets */
- for (i = 0; i < h->num_buckets; i++) {
- if (h->buckets_in_use[i]) {
- HashNode* node;
-
- /* Free the first value */
- if (free_values) free(h->buckets[i].value);
- node = h->buckets[i].next;
- while (node != NULL) {
- HashNode* prev = node;
-
- node = node->next;
- /* Free the value */
- if (free_values) free(prev->value);
- /* Free the node */
- free(prev);
- }
- }
- }
+ /* Free all other memory */
free(h->buckets);
- /* No need to free buckets_in_use, it is always allocated in one
+ /* No need to free buckets_in_use, it is always allocated in the same
* malloc with buckets */
+ PoolEmpty(&h->pool, false);
#ifdef HASH_DEBUG
debug("Freeing Hash: %p", h);
#endif
@@ -587,7 +587,11 @@
node = node->next;
if (free_values) free(prev->value);
+#ifdef HASHPOOL
+ PoolFreeDrop(&h->pool, prev);
+#else
free(prev);
+#endif
}
}
}
@@ -664,7 +668,9 @@
/* Copy the second to the first */
*node = *next;
/* Free the second */
-#ifndef NOFREE
+#ifdef HASHPOOL
+ PoolFreeDrop(&h->pool, next);
+#else
free(next);
#endif
} else {
@@ -680,7 +686,9 @@
/* Link previous and next nodes */
prev->next = node->next;
/* Free the node */
-#ifndef NOFREE
+#ifdef HASHPOOL
+ PoolFreeDrop(&h->pool, node);
+#else
free(node);
#endif
}
@@ -709,7 +717,11 @@
node = h->buckets + hash;
} else {
/* Add it after prev */
+#ifdef HASHPOOL
+ node = PoolAllocateDrop(&h->pool);
+#else
node = malloc(sizeof(*node));
+#endif
prev->next = node;
}
node->next = NULL;
=== queue.h
==================================================================
--- queue.h (revision 313)
+++ queue.h (local)
@@ -1,5 +1,7 @@
/* $Id$ */
+#include "pool.h"
+
#ifndef QUEUE_H
#define QUEUE_H
@@ -143,8 +145,8 @@
struct HashNode {
uint key1;
uint key2;
- void* value;
- HashNode* next;
+ void* value; /**< The value associated with this bucket */
+ HashNode* next; /**< Pointer to the next bucket, if there is one */
};
/**
* Generates a hash code from the given key pair. You should make sure that
@@ -152,21 +154,24 @@
*/
typedef uint Hash_HashProc(uint key1, uint key2);
typedef struct Hash {
- /* The hash function used */
+ /** The hash function used */
Hash_HashProc* hash;
- /* The amount of items in the hash */
+ /** The amount of items in the hash */
uint size;
- /* The number of buckets allocated */
+ /** The number of buckets allocated */
uint num_buckets;
- /* A pointer to an array of num_buckets buckets. */
+ /** A pointer to an array of num_buckets buckets. */
HashNode* buckets;
- /* A pointer to an array of numbuckets booleans, which will be true if
+ /**
+ * A pointer to an array of numbuckets booleans, which will be true if
* there are any Nodes in the bucket */
bool* buckets_in_use;
- /* If true, buckets will be freed in delete_hash */
+ /** If true, buckets will be freed in delete_hash */
bool freeb;
- /* If true, the pointer to this struct will be freed in delete_hash */
+ /** If true, the pointer to this struct will be freed in delete_hash */
bool freeh;
+ /** Memorypool to store the buckets */
+ MemoryPool pool;
} Hash;
/* Call these function to manipulate a hash */
=== rail_cmd.c
==================================================================
--- rail_cmd.c (revision 313)
+++ rail_cmd.c (local)
@@ -941,7 +941,7 @@
if (flags & DC_EXEC) {
DiagDirection dir = GetRailDepotDirection(tile);
- DoDeleteDepot(tile);
+ DoClearDepot(tile);
UpdateSignalsOnSegment(tile, dir);
}
=== road_cmd.c
==================================================================
--- road_cmd.c (revision 313)
+++ road_cmd.c (local)
@@ -281,7 +281,7 @@
/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
* if a non-player is building the road */
- if ((p1 >> 4) || (_current_player < MAX_PLAYERS && p2 != 0) || !IsTownIndex(p2)) return CMD_ERROR;
+ if ((p1 >> 4) || (_current_player < MAX_PLAYERS && p2 != 0) || !IsValidTownID(p2)) return CMD_ERROR;
pieces = p1;
tileh = GetTileSlope(tile, NULL);
@@ -595,7 +595,8 @@
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
- if (flags & DC_EXEC) DoDeleteDepot(tile);
+ if (flags & DC_EXEC) { DoClearDepot(tile);
+ }
return _price.remove_road_depot;
}
=== roadveh_cmd.c
==================================================================
--- roadveh_cmd.c (revision 313)
+++ roadveh_cmd.c (local)
@@ -210,7 +210,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -252,7 +252,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -353,7 +353,7 @@
Vehicle *v;
const Depot *dep;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -400,7 +400,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -419,7 +419,6 @@
return 0;
}
-
static void MarkRoadVehDirty(Vehicle *v)
{
v->cur_image = GetRoadVehImage(v, v->direction);
@@ -674,7 +673,7 @@
}
v->dest_tile = dest;
} else if (order->type == OT_GOTO_DEPOT) {
- v->dest_tile = GetDepot(order->station)->xy;
+ v->dest_tile = GetDepot((DepotID)order->station)->xy;
}
InvalidateVehicleOrder(v);
=== roadveh_gui.c
==================================================================
--- roadveh_gui.c (revision 313)
+++ roadveh_gui.c (local)
@@ -256,7 +256,7 @@
} break;
case OT_GOTO_DEPOT: {
- Depot *depot = GetDepot(v->current_order.station);
+ Depot *depot = GetDepot((DepotID)v->current_order.station);
SetDParam(0, depot->town_index);
SetDParam(1, v->cur_speed / 2);
str = STR_HEADING_FOR_ROAD_DEPOT + _patches.vehicle_speed;
=== saveload.c
==================================================================
--- saveload.c (revision 313)
+++ saveload.c (local)
@@ -1002,8 +1002,12 @@
//********************************************
enum {
- SAVE_POOL_BLOCK_SIZE_BITS = 17,
- SAVE_POOL_MAX_BLOCKS = 500
+ /**
+ * Since we will mainly use the pool to manage indices and allocation of
+ * large blocks for us, each puddle will only contain 1 (large) drop.
+ * */
+ SAVEGAME_PUDDLE_SIZE = 1,
+ SAVEGAME_DROP_SIZE = 128 * 1024, /**< Allocation 128K blocks at a time */
};
#include "network.h"
@@ -1011,45 +1015,56 @@
#include "table/sprites.h"
#include "gfx.h"
#include "gui.h"
+#include "pool.h"
typedef struct ThreadedSave {
- MemoryPool *save;
- uint count;
+ IndexedPool savegame_pool; /**< The memory pool that stores a savegame while it is being written */
+ uint count; /**< The number of bytes that have been written to the memory pool */
bool ff_state;
bool saveinprogress;
CursorID cursor;
} ThreadedSave;
-/* A maximum size of of 128K * 500 = 64.000KB savegames */
-static MemoryPool _save_pool = {"Savegame", SAVE_POOL_MAX_BLOCKS, SAVE_POOL_BLOCK_SIZE_BITS, sizeof(byte), NULL, NULL, 0, 0, NULL};
+/* A pool to allocate memory for the savegame as needed. This pool is indexed,
+ * so it will keep the memory ordered. */
+static IndexedPoolSettings _savegame_pool_settings = {"Savegame", NULL, NULL, {"Savegame_sub", 0, SAVEGAME_PUDDLE_SIZE, SAVEGAME_DROP_SIZE, POOL_FAST, NULL, NULL} };
static ThreadedSave _ts;
static bool InitMem(void)
{
- _ts.save = &_save_pool;
_ts.count = 0;
- CleanPool(_ts.save);
- AddBlockToPool(_ts.save);
+ IndexedPoolInitialize(&_ts.savegame_pool, &_savegame_pool_settings);
/* A block from the pool is a contigious area of memory, so it is safe to write to it sequentially */
- _sl.bufsize = _ts.save->total_items;
- _sl.buf = (byte*)GetItemFromPool(_ts.save, _ts.count);
+ _sl.bufsize = SAVEGAME_DROP_SIZE;
+ _sl.buf = (byte*)IndexedPoolAllocateIndex(&_ts.savegame_pool, _ts.count/SAVEGAME_DROP_SIZE);
return true;
}
static void UnInitMem(void)
{
- CleanPool(_ts.save);
- _ts.save = NULL;
+ IndexedPoolEmpty(&_ts.savegame_pool);
}
static void WriteMem(uint size)
{
+ /* This will be called to write the buffer to "disk". Since the chunk
+ * handlers write directly into the memory pool, we will just swap the
+ * buffer with a new one.
+ * This will always work when a full buffer needs to be written. If the
+ * buffer is not full, we cannot swap it, since it would produce a "hole" in
+ * the memory pool. Since the last WriteMem call is usually with a non-full
+ * buffer, we will allow writing a non-full buffer only once, after that,
+ * nothing should be written anymore.
+ * We check this by checking if the count is still a multiple of the
+ * dropsize. If so, we have written only full buffers. If not, we have
+ * written a non-full buffer at least once. */
+ assert(_ts.count % SAVEGAME_DROP_SIZE == 0);
_ts.count += size;
- /* Allocate new block and new buffer-pointer */
- AddBlockIfNeeded(_ts.save, _ts.count);
- _sl.buf = (byte*)GetItemFromPool(_ts.save, _ts.count);
+ /* Allocate new buffer if this was not the last one */
+ if (size == SAVEGAME_DROP_SIZE)
+ _sl.buf = (byte*)IndexedPoolAllocateIndex(&_ts.savegame_pool, _ts.count/SAVEGAME_DROP_SIZE);
}
//********************************************
@@ -1245,32 +1260,32 @@
switch (rt) {
case REF_ORDER: {
- if (!AddBlockIfNeeded(&_order_pool, index))
+ if (IndexedPoolAllocateIndex(&_order_pool, index) == NULL)
error("Orders: failed loading savegame: too many orders");
return GetOrder(index);
}
case REF_VEHICLE: {
- if (!AddBlockIfNeeded(&_vehicle_pool, index))
+ if (IndexedPoolAllocateIndex(&_vehicle_pool, index) == NULL)
error("Vehicles: failed loading savegame: too many vehicles");
return GetVehicle(index);
}
case REF_STATION: {
- if (!AddBlockIfNeeded(&_station_pool, index))
+ if (IndexedPoolAllocateIndex(&_station_pool, index) == NULL)
error("Stations: failed loading savegame: too many stations");
return GetStation(index);
}
case REF_TOWN: {
- if (!AddBlockIfNeeded(&_town_pool, index))
+ if (IndexedPoolAllocateIndex(&_town_pool, index) == NULL)
error("Towns: failed loading savegame: too many towns");
return GetTown(index);
}
case REF_ROADSTOPS: {
- if (!AddBlockIfNeeded(&_roadstop_pool, index))
+ if (IndexedPoolAllocateIndex(&_roadstop_pool, index) == NULL)
error("RoadStops: failed loading savegame: too many RoadStops");
return GetRoadStop(index);
}
case REF_ENGINE_RENEWS: {
- if (!AddBlockIfNeeded(&_engine_renew_pool, index))
+ if (IndexedPoolAllocateIndex(&_engine_renew_pool, index) == NULL)
error("EngineRenews: failed loading savegame: too many EngineRenews");
return GetEngineRenew(index);
}
@@ -1283,7 +1298,7 @@
if (index == INVALID_VEHICLE)
return NULL;
- if (!AddBlockIfNeeded(&_vehicle_pool, index))
+ if (IndexedPoolAllocateIndex(&_vehicle_pool, index) == NULL)
error("Vehicles: failed loading savegame: too many vehicles");
return GetVehicle(index);
}
@@ -1391,7 +1406,7 @@
static Thread* save_thread;
-/** We have written the whole game into memory, _save_pool, now find
+/** We have written the whole game into memory, _ts.savegame_pool, now find
* and appropiate compressor and start writing to file.
*/
static void* SaveFileToDisk(void *arg)
@@ -1424,18 +1439,20 @@
{
uint i;
- uint count = 1 << _ts.save->block_size_bits;
-
+ uint num_blocks = _ts.count / SAVEGAME_DROP_SIZE + 1;
+ /* Assert that there are not "holes" in the pool, ie unallocated indices */
+ assert(IndexedPoolNumAllocated(&_ts.savegame_pool) == IndexedPoolNumUsed(&_ts.savegame_pool));
assert(_ts.count == _sl.offs_base);
- for (i = 0; i != _ts.save->current_blocks - 1; i++) {
- _sl.buf = _ts.save->blocks[i];
- fmt->writer(count);
+ for (i = 0; i != num_blocks - 1; i++) {
+ _sl.buf = IndexedPoolGetItem(&_ts.savegame_pool, i);
+ assert(_sl.buf != NULL);
+ fmt->writer(SAVEGAME_DROP_SIZE);
}
/* The last block is (almost) always not fully filled, so only write away
* as much data as it is in there */
- _sl.buf = _ts.save->blocks[i];
- fmt->writer(_ts.count - (i * count));
+ _sl.buf = IndexedPoolGetItem(&_ts.savegame_pool, i);
+ fmt->writer(_ts.count - (i * SAVEGAME_DROP_SIZE));
}
fmt->uninit_write();
@@ -1537,7 +1554,8 @@
SlSaveChunks();
SlWriteFill(); // flush the save buffer
- if (_network_server ||
+ /* XXX: DONTCOMMIT: Disable threaded saving, it breaks in a debugger? */
+ if (true || _network_server ||
(save_thread = OTTDCreateThread(&SaveFileToDisk, (void*)"")) == NULL) {
DEBUG(misc, 1) ("[Sl] Cannot create savegame thread, reverting to single-threaded mode...");
SaveFileToDisk(NULL);
=== ship_cmd.c
==================================================================
--- ship_cmd.c (revision 313)
+++ ship_cmd.c (local)
@@ -80,7 +80,7 @@
} else {
FOR_ALL_DEPOTS(depot) {
tile = depot->xy;
- if (IsValidDepot(depot) && IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) {
+ if (IsTileDepotType(tile, TRANSPORT_WATER) && IsTileOwner(tile, v->owner)) {
dist = DistanceManhattan(tile, tile2);
if (dist < best_dist) {
best_dist = dist;
@@ -237,7 +237,7 @@
v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
}
} else if (order->type == OT_GOTO_DEPOT) {
- v->dest_tile = GetDepot(order->station)->xy;
+ v->dest_tile = GetDepot((DepotID)order->station)->xy;
} else {
v->dest_tile = 0;
}
@@ -907,7 +907,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -940,7 +940,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -970,7 +970,7 @@
Vehicle *v;
const Depot *dep;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1008,7 +1008,6 @@
return 0;
}
-
/** Refits a ship to the specified cargo type.
* @param tile unused
* @param p1 vehicle ID of the ship to refit
@@ -1021,7 +1020,7 @@
int32 cost;
CargoID new_cid = p2 & 0xFF; //gets the cargo number
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
=== ship_gui.c
==================================================================
--- ship_gui.c (revision 313)
+++ ship_gui.c (local)
@@ -494,7 +494,7 @@
} break;
case OT_GOTO_DEPOT: {
- Depot *depot = GetDepot(v->current_order.station);
+ Depot *depot = GetDepot((DepotID)v->current_order.station);
SetDParam(0, depot->town_index);
SetDParam(1, v->cur_speed / 2);
str = STR_HEADING_FOR_SHIP_DEPOT + _patches.vehicle_speed;
=== signs.c
==================================================================
--- signs.c (revision 313)
+++ signs.c (local)
@@ -13,24 +13,16 @@
static SignStruct *_new_sign_struct;
enum {
- /* Max signs: 64000 (4 * 16000) */
- SIGN_POOL_BLOCK_SIZE_BITS = 2, /* In bits, so (1 << 2) == 4 */
- SIGN_POOL_MAX_BLOCKS = 16000,
+ SIGN_PUDDLE_SIZE = 4,
};
-/**
- * Called if a new block is added to the sign-pool
- */
-static void SignPoolNewBlock(uint start_item)
-{
- SignStruct *ss;
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeSignStruct(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroySignStruct(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_SIGNS_FROM(ss, start_item)
- ss->index = start_item++;
-}
-
/* Initialize the sign-pool */
-MemoryPool _sign_pool = { "Signs", SIGN_POOL_MAX_BLOCKS, SIGN_POOL_BLOCK_SIZE_BITS, sizeof(SignStruct), &SignPoolNewBlock, NULL, 0, 0, NULL };
+static IndexedPoolSettings _signstruct_pool_settings = INDEXED_POOL(SignStruct, SIGN_PUDDLE_SIZE);
+IndexedPool _signstruct_pool;
/**
*
@@ -54,9 +46,7 @@
SignStruct *ss;
FOR_ALL_SIGNS(ss)
- if (ss->str != 0)
- UpdateSignVirtCoords(ss);
-
+ UpdateSignVirtCoords(ss);
}
/**
@@ -74,34 +64,20 @@
ss->sign.top + 45);
}
-/**
- *
- * Allocates a new sign
- *
- * @return The pointer to the new sign, or NULL if there is no more free space
- */
-static SignStruct *AllocateSign(void)
+static void InitializeSignStruct(const IndexedPool* pool, void* drop, DropIndex index)
{
- SignStruct *ss;
- FOR_ALL_SIGNS(ss) {
- if (ss->str == 0) {
- uint index = ss->index;
+ ZERO_AND_INDEX(SignStruct, drop);
+}
- memset(ss, 0, sizeof(SignStruct));
- ss->index = index;
-
- return ss;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_sign_pool))
- return AllocateSign();
-
- return NULL;
+static void DestroySignStruct(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ SignStruct* ss = (SignStruct*)drop;
+ /* Delete the name */
+ DeleteName(ss->str);
}
-/** Place a sign at the given coordinates. Ownership of sign has
+/**
+ * Place a sign at the given coordinates. Ownership of sign has
* no effect whatsoever except for the colour the sign gets for easy recognition,
* but everybody is able to rename/remove it.
* @param tile tile to place sign at
@@ -113,7 +89,7 @@
SignStruct *ss;
/* Try to locate a new sign */
- ss = AllocateSign();
+ ss = AllocateSignStruct();
if (ss == NULL) return_cmd_error(STR_2808_TOO_MANY_SIGNS);
/* When we execute, really make the sign */
@@ -145,7 +121,7 @@
*/
int32 CmdRenameSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- if (!IsSignIndex(p1)) return CMD_ERROR;
+ if (!IsValidSignStructID(p1)) return CMD_ERROR;
/* If _cmd_text 0 means the new text for the sign is non-empty.
* So rename the sign. If it is empty, it has no name, so delete it */
@@ -155,7 +131,7 @@
if (str == 0) return CMD_ERROR;
if (flags & DC_EXEC) {
- SignStruct *ss = GetSign(p1);
+ SignStruct *ss = GetSignStruct(p1);
/* Delete the old name */
DeleteName(ss->str);
@@ -175,13 +151,12 @@
}
} else { /* Delete sign */
if (flags & DC_EXEC) {
- SignStruct *ss = GetSign(p1);
+ SignStruct *ss = GetSignStruct(p1);
- /* Delete the name */
- DeleteName(ss->str);
- ss->str = 0;
-
MarkSignDirty(ss);
+
+ DeleteSignStruct(ss);
+
InvalidateWindow(WC_SIGN_LIST, 0);
_sign_sort_dirty = true;
}
@@ -221,8 +196,7 @@
*/
void InitializeSigns(void)
{
- CleanPool(&_sign_pool);
- AddBlockToPool(&_sign_pool);
+ IndexedPoolInitialize(&_signstruct_pool, &_signstruct_pool_settings);
}
static const SaveLoad _sign_desc[] = {
@@ -246,11 +220,8 @@
SignStruct *ss;
FOR_ALL_SIGNS(ss) {
- /* Don't save empty signs */
- if (ss->str != 0) {
- SlSetArrayIndex(ss->index);
- SlObject(ss, _sign_desc);
- }
+ SlSetArrayIndex(ss->index);
+ SlObject(ss, _sign_desc);
}
}
@@ -263,13 +234,10 @@
{
int index;
while ((index = SlIterateArray()) != -1) {
- SignStruct *ss;
+ if (IndexedPoolAllocateIndex(&_signstruct_pool, index) == NULL)
+ error("Depots: failed loading savegame: too many depots");
- if (!AddBlockIfNeeded(&_sign_pool, index))
- error("Signs: failed loading savegame: too many signs");
-
- ss = GetSign(index);
- SlObject(ss, _sign_desc);
+ SlObject(GetSignStruct((SignStructID)index), _sign_desc);
}
_sign_sort_dirty = true;
=== signs.h
==================================================================
--- signs.h (revision 313)
+++ signs.h (local)
@@ -14,43 +14,14 @@
PlayerID owner; // placed by this player. Anyone can delete them though.
// OWNER_NONE for gray signs from old games.
- uint16 index;
+ SignStructID index;
} SignStruct;
-extern MemoryPool _sign_pool;
+extern IndexedPool _signstruct_pool;
-/**
- * Check if a Sign really exists.
- */
-static inline bool IsValidSign(const SignStruct* ss)
-{
- return ss->str != 0;
-}
+#define FOR_ALL_SIGNS(ss) FOR_ALL_IN_POOL(_signstruct_pool, ss)
+INDEXED_POOL_FUNCTIONS(SignStruct, SignStructs, _signstruct_pool);
-/**
- * Get the pointer to the sign with index 'index'
- */
-static inline SignStruct *GetSign(uint index)
-{
- return (SignStruct*)GetItemFromPool(&_sign_pool, index);
-}
-
-/**
- * Get the current size of the SignPool
- */
-static inline uint16 GetSignPoolSize(void)
-{
- return _sign_pool.total_items;
-}
-
-static inline bool IsSignIndex(uint index)
-{
- return index < GetSignPoolSize();
-}
-
-#define FOR_ALL_SIGNS_FROM(ss, start) for (ss = GetSign(start); ss != NULL; ss = (ss->index + 1 < GetSignPoolSize()) ? GetSign(ss->index + 1) : NULL)
-#define FOR_ALL_SIGNS(ss) FOR_ALL_SIGNS_FROM(ss, 0)
-
VARDEF bool _sign_sort_dirty;
VARDEF uint16 *_sign_sort;
=== station.h
==================================================================
--- station.h (revision 313)
+++ station.h (local)
@@ -34,7 +34,7 @@
TileIndex xy;
bool used;
byte status;
- uint32 index;
+ RoadStopID index;
byte num_vehicles;
StationID station;
struct RoadStop *next;
@@ -138,56 +138,20 @@
VARDEF SortStruct *_station_sort;
-extern MemoryPool _station_pool;
+extern IndexedPool _station_pool;
-/**
- * Get the pointer to the station with index 'index'
- */
-static inline Station *GetStation(StationID index)
-{
- return (Station*)GetItemFromPool(&_station_pool, index);
-}
+#define FOR_ALL_STATIONS(st) FOR_ALL_IN_POOL(_station_pool, st)
+#define FOR_ALL_STATIONS_EVERY_N_TICKS(st, n, ctr) FOR_ALL_EVERY_N_TICKS(_station_pool, st, n, ctr)
+INDEXED_POOL_FUNCTIONS(Station, Stations, _station_pool)
-/**
- * Get the current size of the StationPool
- */
-static inline uint16 GetStationPoolSize(void)
-{
- return _station_pool.total_items;
-}
-static inline bool IsStationIndex(StationID index)
-{
- return index < GetStationPoolSize();
-}
-
-#define FOR_ALL_STATIONS_FROM(st, start) for (st = GetStation(start); st != NULL; st = (st->index + 1 < GetStationPoolSize()) ? GetStation(st->index + 1) : NULL)
-#define FOR_ALL_STATIONS(st) FOR_ALL_STATIONS_FROM(st, 0)
-
-
/* Stuff for ROADSTOPS */
-extern MemoryPool _roadstop_pool;
+extern IndexedPool _roadstop_pool;
-/**
- * Get the pointer to the roadstop with index 'index'
- */
-static inline RoadStop *GetRoadStop(uint index)
-{
- return (RoadStop*)GetItemFromPool(&_roadstop_pool, index);
-}
+#define FOR_ALL_ROADSTOPS(rs) FOR_ALL_IN_POOL(_roadstop_pool, rs)
+INDEXED_POOL_FUNCTIONS(RoadStop, RoadStops, _roadstop_pool)
-/**
- * Get the current size of the RoadStoptPool
- */
-static inline uint16 GetRoadStopPoolSize(void)
-{
- return _roadstop_pool.total_items;
-}
-
-#define FOR_ALL_ROADSTOPS_FROM(rs, start) for (rs = GetRoadStop(start); rs != NULL; rs = (rs->index + 1 < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1) : NULL)
-#define FOR_ALL_ROADSTOPS(rs) FOR_ALL_ROADSTOPS_FROM(rs, 0)
-
/* End of stuff for ROADSTOPS */
@@ -203,18 +167,11 @@
RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type);
RoadStop * GetPrimaryRoadStop(const Station *st, RoadStopType type);
-uint GetNumRoadStops(const Station* st, RoadStopType type);
-RoadStop * AllocateRoadStop( void );
void ClearSlot(Vehicle *v);
/**
- * Check if a station really exists.
+ * @todo Replace all manual checks for HVOT_BUOY with this function.
*/
-static inline bool IsValidStation(const Station *st)
-{
- return st->xy != 0; /* XXX: Replace by INVALID_TILE someday */
-}
-
static inline bool IsBuoy(const Station* st)
{
return st->had_vehicle_of_type & HVOT_BUOY; /* XXX: We should really ditch this ugly coding and switch to something sane... */
=== station_cmd.c
==================================================================
--- station_cmd.c (revision 313)
+++ station_cmd.c (local)
@@ -31,51 +31,26 @@
#include "industry_map.h"
enum {
- /* Max stations: 64000 (64 * 1000) */
- STATION_POOL_BLOCK_SIZE_BITS = 6, /* In bits, so (1 << 6) == 64 */
- STATION_POOL_MAX_BLOCKS = 1000,
-
- /* Max roadstops: 64000 (32 * 2000) */
- ROADSTOP_POOL_BLOCK_SIZE_BITS = 5, /* In bits, so (1 << 5) == 32 */
- ROADSTOP_POOL_MAX_BLOCKS = 2000,
+ STATION_PUDDLE_SIZE = 64,
+ STATION_TICK_FREQ = 250,
+ /**< This frequency is based on revision 1. Back then, one station (index)
+ * would get a big tick each tick, and there were 250 station indices. */
+ ROADSTOP_PUDDLE_SIZE = 32,
};
-/**
- * Called if a new block is added to the station-pool
- */
-static void StationPoolNewBlock(uint start_item)
-{
- Station *st;
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeStation(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyStation(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_STATIONS_FROM(st, start_item) st->index = start_item++;
-}
+static void InitializeRoadStop(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyRoadStop(const IndexedPool* pool, void* drop, DropIndex index);
-static void StationPoolCleanBlock(uint start_item, uint end_item)
-{
- uint i;
+static IndexedPoolSettings _station_pool_settings = INDEXED_POOL(Station, STATION_PUDDLE_SIZE);
+IndexedPool _station_pool;
+static IndexedPoolSettings _roadstop_pool_settings = INDEXED_POOL(RoadStop, ROADSTOP_PUDDLE_SIZE);
+IndexedPool _roadstop_pool;
- for (i = start_item; i <= end_item; i++) {
- Station *st = GetStation(i);
- free(st->speclist);
- st->speclist = NULL;
- }
-}
-/**
- * Called if a new block is added to the roadstop-pool
- */
-static void RoadStopPoolNewBlock(uint start_item)
-{
- RoadStop *rs;
-
- FOR_ALL_ROADSTOPS_FROM(rs, start_item) rs->index = start_item++;
-}
-
-/* Initialize the station-pool and roadstop-pool */
-MemoryPool _station_pool = { "Stations", STATION_POOL_MAX_BLOCKS, STATION_POOL_BLOCK_SIZE_BITS, sizeof(Station), &StationPoolNewBlock, &StationPoolCleanBlock, 0, 0, NULL };
-MemoryPool _roadstop_pool = { "RoadStop", ROADSTOP_POOL_MAX_BLOCKS, ROADSTOP_POOL_BLOCK_SIZE_BITS, sizeof(RoadStop), &RoadStopPoolNewBlock, NULL, 0, 0, NULL };
-
-
// FIXME -- need to be embedded into Airport variable. Is dynamically
// deducteable from graphics-tile array, so will not be needed
const byte _airport_size_x[] = {4, 6, 1, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
@@ -97,15 +72,37 @@
}
}
-static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index)
+static void InitializeRoadStop(const IndexedPool* pool, void* drop, DropIndex index)
{
+ RoadStop* rs = (RoadStop*)drop;
+ ZERO_AND_INDEX(RoadStop, rs);
+ rs->status = 3; //stop is free
+ rs->xy = INVALID_TILE;
+ rs->next = NULL;
+ rs->prev = NULL;
+ rs->num_vehicles = 0;
+}
+
+static void DestroyRoadStop(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ RoadStop* rs = (RoadStop*)drop;
+ Vehicle* v;
+ /* Clear the slot assignment of all vehicles heading for this road stop */
+ if (rs->num_vehicles != 0) {
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_Road && v->u.road.slot == rs) {
+ ClearSlot(v);
+ }
+ }
+ }
+ assert(rs->num_vehicles == 0);
+}
+
+static void SetupRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index)
+{
road_stop->xy = tile;
- road_stop->used = true;
- road_stop->status = 3; //stop is free
- road_stop->next = NULL;
- road_stop->prev = previous;
road_stop->station = index;
- road_stop->num_vehicles = 0;
+ road_stop->prev = previous;
}
RoadStop* GetPrimaryRoadStop(const Station* st, RoadStopType type)
@@ -131,7 +128,7 @@
return rs;
}
-uint GetNumRoadStops(const Station* st, RoadStopType type)
+uint GetNumRoadStopsInStation(const Station* st, RoadStopType type)
{
uint num = 0;
const RoadStop *rs;
@@ -142,27 +139,6 @@
return num;
}
-RoadStop *AllocateRoadStop(void)
-{
- RoadStop *rs;
-
- FOR_ALL_ROADSTOPS(rs) {
- if (!rs->used) {
- uint index = rs->index;
-
- memset(rs, 0, sizeof(*rs));
- rs->index = index;
-
- return rs;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_roadstop_pool)) return AllocateRoadStop();
-
- return NULL;
-}
-
/* Calculate the radius of the station. Basicly it is the biggest
radius that is available within the station */
static uint FindCatchmentRadius(const Station* st)
@@ -262,26 +238,9 @@
return true;
}
-static Station *AllocateStation(void)
+static void InitializeStation(const IndexedPool* pool, void* drop, DropIndex index)
{
- Station *st = NULL;
-
- FOR_ALL_STATIONS(st) {
- if (st->xy == 0) {
- StationID index = st->index;
-
- memset(st, 0, sizeof(Station));
- st->index = index;
-
- return st;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_station_pool)) return AllocateStation();
-
- _error_message = STR_3008_TOO_MANY_STATIONS_LOADING;
- return NULL;
+ ZERO_AND_INDEX(Station, drop);
}
@@ -351,7 +310,7 @@
Station *s;
FOR_ALL_STATIONS(s) {
- if (s != st && s->xy != 0 && s->town==t) {
+ if (s != st && s->town==t) {
uint str = M(s->string_id);
if (str <= 0x20) {
if (str == M(STR_SV_STNAME_FOREST))
@@ -452,7 +411,7 @@
Station* st;
FOR_ALL_STATIONS(st) {
- if (st->xy != 0 && (owner == OWNER_SPECTATOR || st->owner == owner)) {
+ if (owner == OWNER_SPECTATOR || st->owner == owner) {
uint cur_dist = DistanceManhattan(tile, st->xy);
if (cur_dist < threshold) {
@@ -515,9 +474,8 @@
{
Station* st;
- FOR_ALL_STATIONS(st) {
- if (st->xy != 0) UpdateStationVirtCoord(st);
- }
+ FOR_ALL_STATIONS(st)
+ UpdateStationVirtCoord(st);
}
// Update the station virt coords while making the modified parts dirty.
@@ -1352,7 +1310,6 @@
int32 CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Station *st;
- RoadStop *road_stop;
RoadStop **currstop;
RoadStop *prev = NULL;
int32 cost;
@@ -1381,16 +1338,18 @@
}
//give us a road stop in the list, and check if something went wrong
- road_stop = AllocateRoadStop();
- if (road_stop == NULL) {
+ if (GetNumRoadStopsFree() == 0) {
return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
}
if (st != NULL &&
- GetNumRoadStops(st, RS_BUS) + GetNumRoadStops(st, RS_TRUCK) >= ROAD_STOP_LIMIT) {
+ GetNumRoadStopsInStation(st, RS_BUS) + GetNumRoadStopsInStation(st, RS_TRUCK) >= ROAD_STOP_LIMIT) {
return_cmd_error(type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS);
}
-
+ /* Find a spot in the station's roadstop list to put the roadstop.
+ * Will create a station if necessary. Will fill prev with the
+ * roadstop after which to append the new one and currstop with the
+ * spot for the new stop */
if (st != NULL) {
if (st->owner != OWNER_NONE && st->owner != _current_player) {
return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
@@ -1423,11 +1382,12 @@
cost += (type) ? _price.build_truck_station : _price.build_bus_station;
if (flags & DC_EXEC) {
+ RoadStop *road_stop = AllocateRoadStop();
//point to the correct item in the _busstops or _truckstops array
*currstop = road_stop;
//initialize an empty station
- InitializeRoadStop(road_stop, prev, tile, st->index);
+ SetupRoadStop(road_stop, prev, tile, st->index);
if (!st->facilities) st->xy = tile;
st->facilities |= (type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP;
st->owner = _current_player;
@@ -1467,21 +1427,8 @@
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (flags & DC_EXEC) {
- Vehicle* v;
-
- /* Clear the slot assignment of all vehicles heading for this road stop */
- if (cur_stop->num_vehicles != 0) {
- FOR_ALL_VEHICLES(v) {
- if (v->type == VEH_Road && v->u.road.slot == cur_stop) {
- ClearSlot(v);
- }
- }
- }
- assert(cur_stop->num_vehicles == 0);
-
DoClearSquare(tile);
- cur_stop->used = false;
if (cur_stop->prev != NULL) cur_stop->prev->next = cur_stop->next;
if (cur_stop->next != NULL) cur_stop->next->prev = cur_stop->prev;
@@ -1495,7 +1442,9 @@
//need to set the primary element to the next stop
*primary_stop = (*primary_stop)->next;
}
-
+
+ /* Remove from pool. Will also clear vehicles heading towards it. */
+ IndexedPoolFreeDrop(&_roadstop_pool, cur_stop->index);
UpdateStationVirtCoordDirty(st);
DeleteStationIfEmpty(st);
}
@@ -1585,7 +1534,7 @@
{
uint num = 0;
FOR_ALL_STATIONS(st) {
- if (st->xy != 0 && st->town == t && st->facilities&FACIL_AIRPORT && st->airport_type != AT_OILRIG)
+ if (st->town == t && st->facilities&FACIL_AIRPORT && st->airport_type != AT_OILRIG)
num++;
}
if (num >= 2) {
@@ -1776,9 +1725,11 @@
const Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->type == VEH_Ship) {
+ /* Iterate all ships */
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
if (order->type == OT_GOTO_STATION && order->station == st->index) {
+ /* Order targets this station */
return true;
}
}
@@ -2255,33 +2206,29 @@
return 0;
}
-/** Removes a station from the list.
- * This is done by setting the .xy property to 0,
- * and doing some maintenance, especially clearing vehicle orders.
+ /**
+ * Clean up a station by clearing vehicle orders and invalidating windows.
* Aircraft-Hangar orders need special treatment here, as the hangars are
* actually part of a station (tiletype is STATION), but the order type
* is OT_GOTO_DEPOT.
- * @param st Station to be deleted
*/
-static void DeleteStation(Station *st)
+static void DestroyStation(const IndexedPool* pool, void* drop, DropIndex index)
{
+ Station *st = (Station*)drop;
Order order;
- StationID index;
Vehicle *v;
- st->xy = 0;
DeleteName(st->string_id);
MarkStationDirty(st);
_global_station_sort_dirty = true; // delete station, remove sign
InvalidateWindowClasses(WC_STATION_LIST);
- index = st->index;
DeleteWindowById(WC_STATION_VIEW, index);
//Now delete all orders that go to the station
order.type = OT_GOTO_STATION;
order.station = index;
- DeleteDestinationFromVehicleOrder(order);
+ DeleteOrderFromAllVehicles(order);
//And do the same with aircraft that have the station as a hangar-stop
FOR_ALL_VEHICLES(v) {
@@ -2300,6 +2247,10 @@
if (invalidate) InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
}
+ /* Free custom station speclist. st->speclist might be NULL, for non-train
+ * stations. */
+ if (st->speclist != NULL) free(st->speclist);
+
//Subsidies need removal as well
DeleteSubsidyWithStation(index);
}
@@ -2309,7 +2260,7 @@
Station *st;
FOR_ALL_STATIONS(st) {
- if (st->xy != 0 && st->owner < MAX_PLAYERS) DeleteStation(st);
+ if (st->owner < MAX_PLAYERS) DeleteStation(st);
}
}
@@ -2433,20 +2384,17 @@
void OnTick_Station(void)
{
- uint i;
Station *st;
if (_game_mode == GM_EDITOR) return;
+
+ /* Call big tick every STATION_TICK_FREQ ticks */
+ FOR_ALL_STATIONS_EVERY_N_TICKS(st, STATION_TICK_FREQ, _station_tick_ctr)
+ StationHandleBigTick(st);
- i = _station_tick_ctr;
- if (++_station_tick_ctr == GetStationPoolSize()) _station_tick_ctr = 0;
-
- st = GetStation(i);
- if (st->xy != 0) StationHandleBigTick(st);
-
- FOR_ALL_STATIONS(st) {
- if (st->xy != 0) StationHandleSmallTick(st);
- }
+ /* Call small tick every tick */
+ FOR_ALL_STATIONS(st)
+ StationHandleSmallTick(st);
}
void StationMonthlyLoop(void)
@@ -2459,8 +2407,7 @@
Station *st;
FOR_ALL_STATIONS(st) {
- if (st->xy != 0 && st->owner == owner &&
- DistanceManhattan(tile, st->xy) <= radius) {
+ if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) {
uint i;
for (i = 0; i != NUM_CARGO; i++) {
@@ -2495,10 +2442,10 @@
StringID str;
Station *st;
- if (!IsStationIndex(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+ if (!IsValidStationID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
st = GetStation(p1);
- if (!IsValidStation(st) || !CheckOwnership(st->owner)) return CMD_ERROR;
+ if (!CheckOwnership(st->owner)) return CMD_ERROR;
str = AllocateNameUnique(_cmd_text, 6);
if (str == 0) return CMD_ERROR;
@@ -2669,7 +2616,6 @@
DEBUG(misc, 0) ("Couldn't allocate station-name for oilrig at 0x%X, reverting to oilrig only...", tile);
return;
}
-
st->town = ClosestTownFromTile(tile, (uint)-1);
st->sign.width_1 = 0;
@@ -2699,6 +2645,10 @@
st->goods[j].rating = 175;
st->goods[j].last_speed = 0;
st->goods[j].last_age = 255;
+
+ UpdateStationVirtCoordDirty(st);
+ UpdateStationAcceptance(st, false);
+ return;
}
UpdateStationVirtCoordDirty(st);
@@ -2715,6 +2665,7 @@
st->airport_tile = 0;
st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK);
st->airport_flags = 0;
+ /** XXX: Need pool free? */
UpdateStationVirtCoordDirty(st);
DeleteStation(st);
}
@@ -2772,13 +2723,11 @@
void InitializeStations(void)
{
- /* Clean the station pool and create 1 block in it */
- CleanPool(&_station_pool);
- AddBlockToPool(&_station_pool);
+ /* Initialize the station pool */
+ IndexedPoolInitialize(&_station_pool, &_station_pool_settings);
- /* Clean the roadstop pool and create 1 block in it */
- CleanPool(&_roadstop_pool);
- AddBlockToPool(&_roadstop_pool);
+ /* Initialize the roadstop pool */
+ IndexedPoolInitialize(&_roadstop_pool, &_roadstop_pool_settings);
_station_tick_ctr = 0;
@@ -2915,10 +2864,8 @@
Station *st;
// Write the stations
FOR_ALL_STATIONS(st) {
- if (st->xy != 0) {
- SlSetArrayIndex(st->index);
- SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
- }
+ SlSetArrayIndex(st->index);
+ SlAutolength((AutolengthProc*)SaveLoad_STNS, st);
}
}
@@ -2927,11 +2874,10 @@
int index;
while ((index = SlIterateArray()) != -1) {
Station *st;
-
- if (!AddBlockIfNeeded(&_station_pool, index))
+ st = (Station*)IndexedPoolAllocateIndex(&_station_pool, index);
+ if (st == NULL)
error("Stations: failed loading savegame: too many stations");
- st = GetStation(index);
SaveLoad_STNS(st);
// this means it's an oldstyle savegame without support for nonuniform stations
@@ -2952,20 +2898,17 @@
if (st->bus_stops == NULL)
error("Station: too many busstations in savegame");
- InitializeRoadStop(st->bus_stops, NULL, st->bus_tile_obsolete, st->index);
+ SetupRoadStop(st->bus_stops, NULL, st->bus_tile_obsolete, st->index);
}
if (st->lorry_tile_obsolete != 0) {
st->truck_stops = AllocateRoadStop();
if (st->truck_stops == NULL)
error("Station: too many truckstations in savegame");
- InitializeRoadStop(st->truck_stops, NULL, st->lorry_tile_obsolete, st->index);
+ SetupRoadStop(st->truck_stops, NULL, st->lorry_tile_obsolete, st->index);
}
}
}
-
- /* This is to ensure all pointers are within the limits of _stations_size */
- if (_station_tick_ctr > GetStationPoolSize()) _station_tick_ctr = 0;
}
static void Save_ROADSTOP(void)
@@ -2973,10 +2916,8 @@
RoadStop *rs;
FOR_ALL_ROADSTOPS(rs) {
- if (rs->used) {
- SlSetArrayIndex(rs->index);
- SlObject(rs, _roadstop_desc);
- }
+ SlSetArrayIndex(rs->index);
+ SlObject(rs, _roadstop_desc);
}
}
@@ -2988,10 +2929,10 @@
while ((index = SlIterateArray()) != -1) {
RoadStop *rs;
- if (!AddBlockIfNeeded(&_roadstop_pool, index))
+ rs = (RoadStop*)IndexedPoolAllocateIndex(&_roadstop_pool, index);
+ if (rs == NULL)
error("RoadStops: failed loading savegame: too many RoadStops");
- rs = GetRoadStop(index);
SlObject(rs, _roadstop_desc);
}
=== station_gui.c
==================================================================
--- station_gui.c (revision 313)
+++ station_gui.c (local)
@@ -85,12 +85,12 @@
memset(_num_station_sort, 0, sizeof(_num_station_sort));
/* Create array for sorting */
- _station_sort = realloc(_station_sort, GetStationPoolSize() * sizeof(_station_sort[0]));
+ _station_sort = realloc(_station_sort, GetNumStations() * sizeof(_station_sort[0]));
if (_station_sort == NULL)
error("Could not allocate memory for the station-sorting-list");
FOR_ALL_STATIONS(st) {
- if (st->xy != 0 && st->owner != OWNER_NONE) {
+ if (st->owner != OWNER_NONE) {
_station_sort[n].index = st->index;
_station_sort[n++].owner = st->owner;
_num_station_sort[st->owner]++; // add number of stations of player
=== town.h
==================================================================
--- town.h (revision 313)
+++ town.h (local)
@@ -79,9 +79,7 @@
uint32 GetWorldPopulation(void);
void UpdateTownVirtCoord(Town *t);
-void InitializeTown(void);
void ShowTownViewWindow(TownID town);
-void DeleteTown(Town *t);
void ExpandTown(Town *t);
Town *CreateRandomTown(uint attempts, uint size_mode);
@@ -149,46 +147,16 @@
TOWN_HAS_STADIUM = 2 // There can be only one stadium by town.
};
+extern IndexedPool _town_pool;
+
bool CheckforTownRating(uint32 flags, Town *t, byte type);
VARDEF TownID *_town_sort;
-extern MemoryPool _town_pool;
+#define FOR_ALL_TOWNS(town) FOR_ALL_IN_POOL(_town_pool, town)
+#define FOR_ALL_TOWNS_EVERY_N_TICKS(town, n, ctr) FOR_ALL_EVERY_N_TICKS(_town_pool, town, n, ctr)
+INDEXED_POOL_FUNCTIONS(Town, Towns, _town_pool)
-/**
- * Check if a Town really exists.
- */
-static inline bool IsValidTown(const Town* town)
-{
- return town->xy != 0; /* XXX: Replace by INVALID_TILE someday */
-}
-
-/**
- * Get the pointer to the town with index 'index'
- */
-static inline Town *GetTown(uint index)
-{
- return (Town*)GetItemFromPool(&_town_pool, index);
-}
-
-/**
- * Get the current size of the TownPool
- */
-static inline uint16 GetTownPoolSize(void)
-{
- return _town_pool.total_items;
-}
-
-static inline bool IsTownIndex(uint index)
-{
- return index < GetTownPoolSize();
-}
-
-#define FOR_ALL_TOWNS_FROM(t, start) for (t = GetTown(start); t != NULL; t = (t->index + 1 < GetTownPoolSize()) ? GetTown(t->index + 1) : NULL)
-#define FOR_ALL_TOWNS(t) FOR_ALL_TOWNS_FROM(t, 0)
-
-VARDEF uint _total_towns; // For the AI: the amount of towns active
-
VARDEF bool _town_sort_dirty;
VARDEF byte _town_sort_order;
=== town_cmd.c
==================================================================
--- town_cmd.c (revision 313)
+++ town_cmd.c (local)
@@ -29,25 +29,67 @@
#include "table/town_land.h"
enum {
- /* Max towns: 64000 (8 * 8000) */
- TOWN_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */
- TOWN_POOL_MAX_BLOCKS = 8000,
+ TOWN_PUDDLE_SIZE = 64,
+ TOWN_TICK_FREQ = 100, /* XXX: Value? */
};
-/**
- * Called if a new block is added to the town-pool
- */
-static void TownPoolNewBlock(uint start_item)
-{
- Town *t;
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeTown(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyTown(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_TOWNS_FROM(t, start_item)
- t->index = start_item++;
+/* Initialize the town-pool */
+static IndexedPoolSettings _town_pool_settings = INDEXED_POOL(Town, TOWN_PUDDLE_SIZE);
+IndexedPool _town_pool;
+
+
+static void InitializeTown(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ ZERO_AND_INDEX(Town, drop);
}
-/* Initialize the town-pool */
-MemoryPool _town_pool = { "Towns", TOWN_POOL_MAX_BLOCKS, TOWN_POOL_BLOCK_SIZE_BITS, sizeof(Town), &TownPoolNewBlock, NULL, 0, 0, NULL };
+static void DestroyTown(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ Industry *i;
+ TileIndex tile;
+ Town* t = (Town*)drop;
+ // Delete town authority window
+ // and remove from list of sorted towns
+ DeleteWindowById(WC_TOWN_VIEW, t->index);
+ _town_sort_dirty = true;
+
+ // Delete all industries belonging to the town
+ /* TODO: Should we do this here? */
+ FOR_ALL_INDUSTRIES(i) {
+ if (i->xy && i->town == t)
+ DeleteIndustry(i);
+ }
+
+ // Go through all tiles and delete those belonging to the town
+ for (tile = 0; tile < MapSize(); ++tile) {
+ switch (GetTileType(tile)) {
+ case MP_HOUSE:
+ if (GetTownByTile(tile) == t)
+ DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+ break;
+
+ case MP_STREET:
+ case MP_TUNNELBRIDGE:
+ if (IsTileOwner(tile, OWNER_TOWN) &&
+ ClosestTownFromTile(tile, (uint)-1) == t)
+ DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ DeleteName(t->townnametype);
+
+ MarkWholeScreenDirty();
+}
+
// Local
static int _grow_town_result;
@@ -407,23 +449,13 @@
void OnTick_Town(void)
{
+ Town *t;
+ static DropIndex tick_ctr = 0;
+
if (_game_mode == GM_EDITOR) return;
- /* Make sure each town's tickhandler invocation frequency is about the
- * same - TOWN_GROWTH_FREQUENCY - independent on the number of towns. */
- for (_cur_town_iter += GetTownPoolSize();
- _cur_town_iter >= TOWN_GROWTH_FREQUENCY;
- _cur_town_iter -= TOWN_GROWTH_FREQUENCY) {
- uint32 i = _cur_town_ctr;
- Town *t;
-
- if (++_cur_town_ctr >= GetTownPoolSize())
- _cur_town_ctr = 0;
-
- t = GetTown(i);
-
- if (t->xy != 0) TownTickHandler(t);
- }
+ FOR_ALL_TOWNS_EVERY_N_TICKS(t, TOWN_TICK_FREQ, tick_ctr)
+ TownTickHandler(t);
}
static RoadBits GetTownRoadMask(TileIndex tile)
@@ -887,15 +919,16 @@
t->max_mail = t->population >> 4;
}
-static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, uint size_mode)
+/**
+ * Allocate and initialize a town. Will not check if a town can be allocated,
+ * assumes the town pool is not full.
+ */
+static Town* DoCreateTown(TileIndex tile, uint32 townnameparts, uint size_mode)
{
int x, i;
+ Town* t = AllocateTown();
+ assert(t);
- // clear the town struct
- i = t->index;
- memset(t, 0, sizeof(Town));
- t->index = i;
-
t->xy = tile;
t->num_houses = 0;
t->time_until_rebuild = 10;
@@ -952,32 +985,9 @@
t->num_houses -= x;
UpdateTownRadius(t);
UpdateTownMaxPass(t);
+ return t;
}
-static Town *AllocateTown(void)
-{
- Town *t;
- FOR_ALL_TOWNS(t) {
- if (t->xy == 0) {
- uint index = t->index;
-
- if (t->index > _total_towns)
- _total_towns = t->index;
-
- memset(t, 0, sizeof(Town));
- t->index = index;
-
- return t;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_town_pool))
- return AllocateTown();
-
- return NULL;
-}
-
/** Create a new town.
* This obviously only works in the scenario editor. Function not removed
* as it might be possible in the future to fund your own town :)
@@ -987,7 +997,6 @@
*/
int32 CmdBuildTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- Town *t;
uint32 townnameparts;
/* Only in the scenario editor */
@@ -1013,13 +1022,12 @@
return_cmd_error(STR_023A_TOO_MANY_TOWNS);
// Allocate town struct
- t = AllocateTown();
- if (t == NULL) return_cmd_error(STR_023A_TOO_MANY_TOWNS);
+ if (GetNumTownsFree() == 0) return_cmd_error(STR_023A_TOO_MANY_TOWNS);
// Create the town
if (flags & DC_EXEC) {
_generating_world = true;
- DoCreateTown(t, tile, townnameparts, p1);
+ DoCreateTown(tile, townnameparts, p1);
_generating_world = false;
}
return 0;
@@ -1028,7 +1036,6 @@
Town *CreateRandomTown(uint attempts, uint size_mode)
{
TileIndex tile;
- Town *t;
uint32 townnameparts;
do {
@@ -1045,12 +1052,10 @@
// Get a unique name for the town.
if (!CreateTownName(&townnameparts)) break;
- // Allocate a town struct
- t = AllocateTown();
- if (t == NULL) break;
+ if (GetNumTownsFree() == 0)
+ break;
- DoCreateTown(t, tile, townnameparts, size_mode);
- return t;
+ return DoCreateTown(tile, townnameparts, size_mode);
} while (--attempts);
return NULL;
}
@@ -1069,11 +1074,9 @@
// give it a last try, but now more aggressive
if (num == 0 && CreateRandomTown(10000, 0) == NULL) {
- Town *t;
- FOR_ALL_TOWNS(t) { if (IsValidTown(t)) {num = 1; break;}}
-
- //XXX can we handle that more gracefully?
- if (num == 0 && _game_mode != GM_EDITOR) error("Could not generate any town");
+ /* XXX: I think the code that used to be here meant the following, but why
+ * is stuff even here? :-S */
+ if (_game_mode != GM_EDITOR && GetNumTowns() == 0) error("Could not generate any town");
return false;
}
@@ -1352,7 +1355,7 @@
StringID str;
Town *t;
- if (!IsTownIndex(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+ if (!IsValidTownID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
t = GetTown(p1);
@@ -1374,49 +1377,6 @@
}
// Called from GUI
-void DeleteTown(Town *t)
-{
- Industry *i;
- TileIndex tile;
-
- // Delete town authority window
- // and remove from list of sorted towns
- DeleteWindowById(WC_TOWN_VIEW, t->index);
- _town_sort_dirty = true;
-
- // Delete all industries belonging to the town
- FOR_ALL_INDUSTRIES(i) {
- if (i->xy && i->town == t)
- DeleteIndustry(i);
- }
-
- // Go through all tiles and delete those belonging to the town
- for (tile = 0; tile < MapSize(); ++tile) {
- switch (GetTileType(tile)) {
- case MP_HOUSE:
- if (GetTownByTile(tile) == t)
- DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
- break;
-
- case MP_STREET:
- case MP_TUNNELBRIDGE:
- if (IsTileOwner(tile, OWNER_TOWN) &&
- ClosestTownFromTile(tile, (uint)-1) == t)
- DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
- break;
-
- default:
- break;
- }
- }
-
- t->xy = 0;
- DeleteName(t->townnametype);
-
- MarkWholeScreenDirty();
-}
-
-// Called from GUI
void ExpandTown(Town *t)
{
int amount, n;
@@ -1605,7 +1565,7 @@
int32 cost;
Town *t;
- if (!IsTownIndex(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR;
+ if (!IsValidTownID(p1) || p2 > lengthof(_town_action_proc)) return CMD_ERROR;
t = GetTown(p1);
@@ -1841,17 +1801,13 @@
{
Subsidy *s;
- /* Clean the town pool and create 1 block in it */
- CleanPool(&_town_pool);
- AddBlockToPool(&_town_pool);
+ IndexedPoolInitialize(&_town_pool, &_town_pool_settings);
memset(_subsidies, 0, sizeof(_subsidies));
for (s=_subsidies; s != endof(_subsidies); s++)
s->cargo_type = CT_INVALID;
- _cur_town_ctr = 0;
- _cur_town_iter = 0;
- _total_towns = 0;
+ _town_tick_ctr = 0;
_town_sort_dirty = true;
}
@@ -1952,25 +1908,15 @@
{
int index;
- _total_towns = 0;
-
while ((index = SlIterateArray()) != -1) {
Town *t;
-
- if (!AddBlockIfNeeded(&_town_pool, index))
+
+ t = IndexedPoolAllocateIndex(&_town_pool, index);
+ if (t == NULL)
error("Towns: failed loading savegame: too many towns");
- t = GetTown(index);
SlObject(t, _town_desc);
-
- if ((uint)index > _total_towns)
- _total_towns = index;
}
-
- /* This is to ensure all pointers are within the limits of
- * the size of the TownPool */
- if (_cur_town_ctr >= GetTownPoolSize())
- _cur_town_ctr = 0;
}
void AfterLoadTown(void)
=== town_gui.c
==================================================================
--- town_gui.c (revision 313)
+++ town_gui.c (local)
@@ -410,12 +410,12 @@
uint n = 0;
/* Create array for sorting */
- _town_sort = realloc(_town_sort, GetTownPoolSize() * sizeof(_town_sort[0]));
+ _town_sort = realloc(_town_sort, GetNumTowns() * sizeof(_town_sort[0]));
if (_town_sort == NULL)
error("Could not allocate memory for the town-sorting-list");
FOR_ALL_TOWNS(t) {
- if (t->xy != 0) _town_sort[n++] = t->index;
+ _town_sort[n++] = t->index;
}
_num_town_sort = n;
=== train.h
==================================================================
--- train.h (revision 313)
+++ train.h (local)
@@ -173,19 +173,6 @@
CLRBIT(v->subtype, Train_Multiheaded);
}
-/** Get the next real (non-articulated part) vehicle in the consist.
- * @param v Vehicle.
- * @return Next vehicle in the consist.
- */
-static inline Vehicle *GetNextVehicle(const Vehicle *v)
-{
- Vehicle *u = v->next;
- while (u != NULL && IsArticulatedPart(u)) {
- u = u->next;
- }
- return u;
-}
-
/** Check if an engine has an articulated part.
* @param v Vehicle.
* @return True if the engine has an articulated part.
@@ -195,16 +182,40 @@
return (v->next != NULL && IsArticulatedPart(v->next));
}
+/**
+ * Get the next part of a multi-part engine.
+ * Will only work on a multi-part engine (EngineHasArticPart(v) == true),
+ * result is undefined for normal engine.
+ */
+static inline Vehicle *GetNextArticPart(const Vehicle *v)
+{
+ assert(EngineHasArticPart(v));
+ return v->next;
+}
+
+
/** Get the last part of a multi-part engine.
* @param v Vehicle.
* @return Last part of the engine.
*/
static inline Vehicle *GetLastEnginePart(Vehicle *v)
{
- while (EngineHasArticPart(v)) v = v->next;
+ while (EngineHasArticPart(v)) v = GetNextArticPart(v);
return v;
}
+/** Get the next real (non-articulated part) vehicle in the consist.
+ * @param v Vehicle.
+ * @return Next vehicle in the consist.
+ */
+static inline Vehicle *GetNextVehicle(const Vehicle *v)
+{
+ while (EngineHasArticPart(v))
+ v = GetNextArticPart(v);
+ /* v now contains the last artic part in the engine */
+ return v->next;
+}
+
void ConvertOldMultiheadToNew(void);
void ConnectMultiheadedTrains(void);
=== train_cmd.c
==================================================================
--- train_cmd.c (revision 313)
+++ train_cmd.c (local)
@@ -565,17 +565,18 @@
num_vehicles = 1 + CountArticulatedParts(rvi, engine);
if (!(flags & DC_QUERY_COST)) {
- Vehicle *vl[11]; // Allow for wagon and upto 10 artic parts.
- Vehicle* v;
- int x;
- int y;
-
- if (!AllocateVehicles(vl, num_vehicles))
+ if (GetNumVehiclesFree() < num_vehicles)
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
if (flags & DC_EXEC) {
+ Vehicle* vl[11]; // Allow for wagon and upto 10 artic parts.
+ Vehicle* v;
+ int x;
+ int y;
Vehicle *u, *w;
DiagDirection dir;
+
+ AllocateVehicles(vl, num_vehicles);
v = vl[0];
v->spritenum = rvi->image_index;
@@ -736,12 +737,10 @@
num_vehicles += CountArticulatedParts(rvi, p1);
if (!(flags & DC_QUERY_COST)) {
- Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads
- if (!AllocateVehicles(vl, num_vehicles) || IsOrderPoolFull())
+ /* Vehicle or order pool full? */
+ if (GetNumVehiclesFree() < num_vehicles || IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
- v = vl[0];
-
unit_num = GetFreeUnitNumber(VEH_Train);
if (unit_num > _patches.max_trains)
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
@@ -750,7 +749,10 @@
DiagDirection dir = GetRailDepotDirection(tile);
int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
+ Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads
+ AllocateVehicles(vl, num_vehicles);
+ v = vl[0];
v->unitnumber = unit_num;
v->direction = DiagDirToDir(dir);
v->tile = tile;
@@ -948,7 +950,7 @@
VehicleID d = GB(p1, 16, 16);
Vehicle *src, *dst, *src_head, *dst_head;
- if (!IsVehicleIndex(s)) return CMD_ERROR;
+ if (!IsValidVehicleID(s)) return CMD_ERROR;
src = GetVehicle(s);
@@ -1216,7 +1218,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1251,7 +1253,7 @@
Vehicle *new_f = NULL;
int32 cost = 0;
- if (!IsVehicleIndex(p1) || p2 > 2) return CMD_ERROR;
+ if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1647,7 +1649,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1696,7 +1698,7 @@
{
Vehicle *v;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1719,7 +1721,7 @@
int32 cost;
uint num;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -1889,7 +1891,7 @@
Vehicle *v;
TrainFindDepotData tfdd;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -2377,7 +2379,7 @@
break;
case OT_GOTO_DEPOT:
- v->dest_tile = GetDepot(order->station)->xy;
+ v->dest_tile = GetDepot((DepotID)order->station)->xy;
result = CheckReverseTrain(v);
break;
=== train_gui.c
==================================================================
--- train_gui.c (revision 313)
+++ train_gui.c (local)
@@ -955,7 +955,7 @@
} break;
case OT_GOTO_DEPOT: {
- Depot *dep = GetDepot(v->current_order.station);
+ Depot *dep = GetDepot((DepotID)v->current_order.station);
SetDParam(0, dep->town_index);
str = STR_HEADING_FOR_TRAIN_DEPOT + _patches.vehicle_speed;
SetDParam(1, v->u.rail.last_speed);
=== variables.h
==================================================================
--- variables.h (revision 313)
+++ variables.h (local)
@@ -44,9 +44,6 @@
// Amount of game ticks
VARDEF uint16 _tick_counter;
-// This one is not used anymore.
-VARDEF VehicleID _vehicle_id_ctr_day;
-
// Skip aging of cargo?
VARDEF byte _age_cargo_skip_counter;
@@ -59,17 +56,22 @@
// Also save scrollpos_x, scrollpos_y and zoom
VARDEF uint16 _disaster_delay;
-// Determines what station to operate on in the
-// tick handler.
-VARDEF uint16 _station_tick_ctr;
-
VARDEF uint32 _random_seeds[2][2];
-// Iterator through all towns in OnTick_Town
-VARDEF uint32 _cur_town_ctr;
-// Frequency iterator at the same place
+/* Counters for different periodic tick routines (daily vehicle proc, towntick
+ * procs, etc.). */
+
+VARDEF StationID _station_tick_ctr;
+// This one used to be called _cur_town_ctr
+VARDEF TownID _town_tick_ctr;
+// This one used to be called _vehicle_id_ctr_day
+VARDEF VehicleID _vehicle_tick_ctr;
+
+/* This one is no longer used, but still present in savegames */
VARDEF uint32 _cur_town_iter;
+
+
VARDEF uint _cur_player_tick_index;
VARDEF uint _next_competitor_start;
=== vehicle.c
==================================================================
--- vehicle.c (revision 313)
+++ vehicle.c (local)
@@ -29,6 +29,8 @@
#define INVALID_COORD (-0x8000)
#define GEN_HASH(x,y) (((x & 0x1F80)>>7) + ((y & 0xFC0)))
+/* TODO: Remove artic parts when deleting a vehicle */
+
/*
* These command macros are used to call vehicle type specific commands with non type specific commands
* it should be used like: DoCommandP(x, y, p1, p2, flags, CMD_STARTSTOP_VEH(v->type))
@@ -62,25 +64,85 @@
enum {
- /* Max vehicles: 64000 (512 * 125) */
- VEHICLES_POOL_BLOCK_SIZE_BITS = 9, /* In bits, so (1 << 9) == 512 */
- VEHICLES_POOL_MAX_BLOCKS = 125,
-
- BLOCKS_FOR_SPECIAL_VEHICLES = 2, ///< Blocks needed for special vehicles
+ VEHICLE_PUDDLE_SIZE = 128
};
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeVehicle(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyVehicle(const IndexedPool* pool, void* drop, DropIndex index);
+
+/* Initialize the vehicle-pool */
+static IndexedPoolSettings _vehicle_pool_settings = INDEXED_POOL(Vehicle, VEHICLE_PUDDLE_SIZE);
+IndexedPool _vehicle_pool;
+
+/* Forward declare for use in DestoryVehicle */
+static void UpdateVehiclePosHash(Vehicle* v, int x, int y);
+
+static void InitializeVehicle(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ Vehicle* v = (Vehicle*)drop;
+ ZERO_AND_INDEX(Vehicle, v);
+
+ v->left_coord = INVALID_COORD;
+ v->first = NULL;
+ v->next = NULL;
+ v->next_hash = INVALID_VEHICLE;
+ v->string_id = 0;
+ v->next_shared = NULL;
+ v->prev_shared = NULL;
+ v->depot_list = NULL;
+ v->random_bits = 0;
+}
+
+static void DestroyVehicle(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ Vehicle* v = (Vehicle*)drop;
+
+ DeleteVehicleNews(v->index, INVALID_STRING_ID);
+ DeleteName(v->string_id);
+ UpdateVehiclePosHash(v, INVALID_COORD, 0);
+
+ if (v->orders != NULL)
+ DeleteVehicleOrders(v);
+
+ /* TODO: Arctic parts? */
+}
+
/**
- * Called if a new block is added to the vehicle-pool
+ * Will allocate the number of vehicles and put them into the given array. You
+ * should make sure the all the allocated arrays fit.
+ * @param vl An array of vehicle pointers in which to store the allocted
+ * vehicles.
+ * @param num The number of vehicles to allocate.
+ * @return Will return false if the pool was full, true if allocation
+ * succeeded.
*/
-static void VehiclePoolNewBlock(uint start_item)
+bool AllocateVehicles(Vehicle** vl, uint num)
{
- Vehicle *v;
+ uint i;
+ /* Pool full? */
+ if (GetNumVehiclesFree() < num)
+ return false;
- FOR_ALL_VEHICLES_FROM(v, start_item) v->index = start_item++;
+ /* Allocate the vehicles */
+ for (i=0; icur_image;
@@ -228,46 +288,24 @@
}
FOR_ALL_VEHICLES(v) {
- if (v->type != 0) {
- switch (v->type) {
- case VEH_Train: v->cur_image = GetTrainImage(v, v->direction); break;
- case VEH_Road: v->cur_image = GetRoadVehImage(v, v->direction); break;
- case VEH_Ship: v->cur_image = GetShipImage(v, v->direction); break;
- case VEH_Aircraft:
- if (v->subtype == 0 || v->subtype == 2) {
- v->cur_image = GetAircraftImage(v, v->direction);
- if (v->next != NULL) v->next->cur_image = v->cur_image;
- }
- break;
- default: break;
- }
-
- v->left_coord = INVALID_COORD;
- VehiclePositionChanged(v);
+ switch (v->type) {
+ case VEH_Train: v->cur_image = GetTrainImage(v, v->direction); break;
+ case VEH_Road: v->cur_image = GetRoadVehImage(v, v->direction); break;
+ case VEH_Ship: v->cur_image = GetShipImage(v, v->direction); break;
+ case VEH_Aircraft:
+ if (v->subtype == 0 || v->subtype == 2) {
+ v->cur_image = GetAircraftImage(v, v->direction);
+ if (v->next != NULL) v->next->cur_image = v->cur_image;
+ }
+ break;
+ default: break;
}
+
+ v->left_coord = INVALID_COORD;
+ VehiclePositionChanged(v);
}
}
-static Vehicle *InitializeVehicle(Vehicle *v)
-{
- VehicleID index = v->index;
- memset(v, 0, sizeof(Vehicle));
- v->index = index;
-
- assert(v->orders == NULL);
-
- v->left_coord = INVALID_COORD;
- v->first = NULL;
- v->next = NULL;
- v->next_hash = INVALID_VEHICLE;
- v->string_id = 0;
- v->next_shared = NULL;
- v->prev_shared = NULL;
- v->depot_list = NULL;
- v->random_bits = 0;
- return v;
-}
-
/**
* Get a value for a vehicle's random_bits.
* @return A random value from 0 to 255.
@@ -277,91 +315,6 @@
return GB(Random(), 0, 8);
}
-Vehicle *ForceAllocateSpecialVehicle(void)
-{
- /* This stays a strange story.. there should always be room for special
- * vehicles (special effects all over the map), but with 65k of vehicles
- * is this realistic to double-check for that? For now we just reserve
- * BLOCKS_FOR_SPECIAL_VEHICLES times block_size vehicles that may only
- * be used for special vehicles.. should work nicely :) */
-
- Vehicle *v;
-
- FOR_ALL_VEHICLES(v) {
- /* No more room for the special vehicles, return NULL */
- if (v->index >= (1 << _vehicle_pool.block_size_bits) * BLOCKS_FOR_SPECIAL_VEHICLES)
- return NULL;
-
- if (v->type == 0)
- return InitializeVehicle(v);
- }
-
- return NULL;
-}
-
-/*
- * finds a free vehicle in the memory or allocates a new one
- * returns a pointer to the first free vehicle or NULL if all vehicles are in use
- * *skip_vehicles is an offset to where in the array we should begin looking
- * this is to avoid looping though the same vehicles more than once after we learned that they are not free
- * this feature is used by AllocateVehicles() since it need to allocate more than one and when
- * another block is added to _vehicle_pool, since we only do that when we know it's already full
- */
-static Vehicle *AllocateSingleVehicle(VehicleID *skip_vehicles)
-{
- /* See note by ForceAllocateSpecialVehicle() why we skip the
- * first blocks */
- Vehicle *v;
- const int offset = (1 << VEHICLES_POOL_BLOCK_SIZE_BITS) * BLOCKS_FOR_SPECIAL_VEHICLES;
-
- if (*skip_vehicles < (_vehicle_pool.total_items - offset)) { // make sure the offset in the array is not larger than the array itself
- FOR_ALL_VEHICLES_FROM(v, offset + *skip_vehicles) {
- (*skip_vehicles)++;
- if (v->type == 0)
- return InitializeVehicle(v);
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_vehicle_pool))
- return AllocateSingleVehicle(skip_vehicles);
-
- return NULL;
-}
-
-
-Vehicle *AllocateVehicle(void)
-{
- VehicleID counter = 0;
- return AllocateSingleVehicle(&counter);
-}
-
-
-/** Allocates a lot of vehicles and frees them again
-* @param vl pointer to an array of vehicles to get allocated. Can be NULL if the vehicles aren't needed (makes it test only)
-* @param num number of vehicles to allocate room for
-* returns true if there is room to allocate all the vehicles
-*/
-bool AllocateVehicles(Vehicle **vl, int num)
-{
- int i;
- Vehicle *v;
- VehicleID counter = 0;
-
- for (i = 0; i != num; i++) {
- v = AllocateSingleVehicle(&counter);
- if (v == NULL) {
- return false;
- }
- if (vl != NULL) {
- vl[i] = v;
- }
- }
-
- return true;
-}
-
-
static VehicleID _vehicle_position_hash[0x1000];
void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
@@ -442,16 +395,8 @@
void InitializeVehicles(void)
{
- int i;
+ IndexedPoolInitialize(&_vehicle_pool, &_vehicle_pool_settings);
- /* Clean the vehicle pool, and reserve enough blocks
- * for the special vehicles, plus one for all the other
- * vehicles (which is increased on-the-fly) */
- CleanPool(&_vehicle_pool);
- AddBlockToPool(&_vehicle_pool);
- for (i = 0; i < BLOCKS_FOR_SPECIAL_VEHICLES; i++)
- AddBlockToPool(&_vehicle_pool);
-
// clear it...
memset(_vehicle_position_hash, -1, sizeof(_vehicle_position_hash));
}
@@ -536,28 +481,6 @@
return count;
}
-void DeleteVehicle(Vehicle *v)
-{
- Vehicle *u;
- bool has_artic_part = false;
-
- DeleteVehicleNews(v->index, INVALID_STRING_ID);
-
- do {
- u = v->next;
- has_artic_part = EngineHasArticPart(v);
- DeleteName(v->string_id);
- if (v->type == VEH_Road) ClearSlot(v);
- v->type = 0;
- UpdateVehiclePosHash(v, INVALID_COORD, 0);
- v->next_hash = INVALID_VEHICLE;
-
- if (v->orders != NULL)
- DeleteVehicleOrders(v);
- v = u;
- } while (v != NULL && has_artic_part);
-}
-
void DeleteVehicleChain(Vehicle *v)
{
do {
@@ -1501,8 +1424,9 @@
Vehicle *v_front, *v;
Vehicle *w_front, *w, *w_rear;
int cost, total_cost = 0;
+ uint num_vehicles;
- if (!IsVehicleIndex(p1)) return CMD_ERROR;
+ if (!IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
v_front = v;
w = NULL;
@@ -1523,19 +1447,10 @@
if (v->type == VEH_Train && (!IsFrontEngine(v) || v->u.rail.crash_anim_pos >= 4400)) return CMD_ERROR;
// check that we can allocate enough vehicles
- if (!(flags & DC_EXEC)) {
- int veh_counter = 0;
- do {
- veh_counter++;
- } while ((v = v->next) != NULL);
+ num_vehicles = CountVehiclesInChain(v);
+ if (GetNumVehiclesFree() < num_vehicles)
+ return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
- if (!AllocateVehicles(NULL, veh_counter)) {
- return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
- }
- }
-
- v = v_front;
-
do {
if (IsMultiheaded(v) && !IsTrainEngine(v)) {
@@ -1860,7 +1775,7 @@
Vehicle *v;
StringID str;
- if (!IsVehicleIndex(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
+ if (!IsValidVehicleID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
v = GetVehicle(p1);
@@ -1893,7 +1808,7 @@
Vehicle* v;
uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
- if (serv_int != p2 || !IsVehicleIndex(p1)) return CMD_ERROR;
+ if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
v = GetVehicle(p1);
@@ -2346,9 +2261,7 @@
Vehicle *v;
while ((index = SlIterateArray()) != -1) {
- Vehicle *v;
-
- if (!AddBlockIfNeeded(&_vehicle_pool, index))
+ if(IndexedPoolAllocateIndex(&_vehicle_pool, index) == NULL)
error("Vehicles: failed loading savegame: too many vehicles");
v = GetVehicle(index);
@@ -2368,28 +2281,31 @@
/* Check for shared order-lists (we now use pointers for that) */
if (CheckSavegameVersionOldStyle(5, 2)) {
- FOR_ALL_VEHICLES(v) {
- Vehicle *u;
+ FixSharedOrders();
+ }
+}
- if (v->type == 0)
- continue;
+const ChunkHandler _veh_chunk_handlers[] = {
+ { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
+};
- FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
- if (u->type == 0)
- continue;
+void FixSharedOrders(void)
+{
+ /* Check for shared orders, and link them correctly */
+ Vehicle *v;
- /* If a vehicle has the same orders, add the link to eachother
- in both vehicles */
- if (v->orders == u->orders) {
- v->next_shared = u;
- u->prev_shared = v;
- break;
- }
+ FOR_ALL_VEHICLES(v) {
+ Vehicle *u;
+
+ FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
+ /* If a vehicle has the same orders, add the link to eachother
+ in both vehicles */
+ if (v->orders == u->orders) {
+ v->next_shared = u;
+ u->prev_shared = v;
+ break;
}
}
}
}
-const ChunkHandler _veh_chunk_handlers[] = {
- { 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY | CH_LAST},
-};
=== vehicle.h
==================================================================
--- vehicle.h (revision 313)
+++ vehicle.h (local)
@@ -189,10 +189,10 @@
/* Begin Order-stuff */
Order current_order; ///< The current order (+ status, like: loading)
- OrderID cur_order_index; ///< The index to the current order
+ VehicleOrderID cur_order_index; ///< The index to the current order
Order *orders; ///< Pointer to the first order for this vehicle
- OrderID num_orders; ///< How many orders there are in the list
+ VehicleOrderID num_orders; ///< How many orders there are in the list
Vehicle *next_shared; ///< If not NULL, this points to the next vehicle that shared the order
Vehicle *prev_shared; ///< If not NULL, this points to the prev vehicle that shared the order
@@ -245,9 +245,7 @@
typedef void *VehicleFromPosProc(Vehicle *v, void *data);
void VehicleServiceInDepot(Vehicle *v);
-Vehicle *AllocateVehicle(void);
-bool AllocateVehicles(Vehicle **vl, int num);
-Vehicle *ForceAllocateVehicle(void);
+bool AllocateVehicles(Vehicle **vl, uint num);
Vehicle *ForceAllocateSpecialVehicle(void);
void VehiclePositionChanged(Vehicle *v);
void AfterLoadVehicles(void);
@@ -255,7 +253,6 @@
Vehicle *GetPrevVehicleInChain(const Vehicle *v);
Vehicle *GetFirstVehicleInChain(const Vehicle *v);
uint CountVehiclesInChain(const Vehicle* v);
-void DeleteVehicle(Vehicle *v);
void DeleteVehicleChain(Vehicle *v);
void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks(void);
@@ -340,45 +337,16 @@
#define BEGIN_ENUM_WAGONS(v) do {
#define END_ENUM_WAGONS(v) } while ( (v=v->next) != NULL);
-extern MemoryPool _vehicle_pool;
-
-/**
- * Get the pointer to the vehicle with index 'index'
+/*
+ * Vehicle pool
*/
-static inline Vehicle *GetVehicle(VehicleID index)
-{
- return (Vehicle*)GetItemFromPool(&_vehicle_pool, index);
-}
+extern IndexedPool _vehicle_pool;
-/**
- * Get the current size of the VehiclePool
- */
-static inline uint16 GetVehiclePoolSize(void)
-{
- return _vehicle_pool.total_items;
-}
+#define FOR_ALL_VEHICLES_FROM(v, start) FOR_ALL_IN_POOL_FROM(_vehicle_pool, v, start)
+#define FOR_ALL_VEHICLES(v) FOR_ALL_IN_POOL(_vehicle_pool, v)
+#define FOR_ALL_VEHICLES_EVERY_N_TICKS(v, n, ctr) FOR_ALL_EVERY_N_TICKS(_vehicle_pool, v, n, ctr)
+INDEXED_POOL_FUNCTIONS(Vehicle, Vehicles, _vehicle_pool)
-#define FOR_ALL_VEHICLES_FROM(v, start) for (v = GetVehicle(start); v != NULL; v = (v->index + 1 < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL)
-#define FOR_ALL_VEHICLES(v) FOR_ALL_VEHICLES_FROM(v, 0)
-
-/**
- * Check if a Vehicle really exists.
- */
-static inline bool IsValidVehicle(const Vehicle *v)
-{
- return v->type != 0;
-}
-
-/**
- * Check if an index is a vehicle-index (so between 0 and max-vehicles)
- *
- * @return Returns true if the vehicle-id is in range
- */
-static inline bool IsVehicleIndex(uint index)
-{
- return index < GetVehiclePoolSize();
-}
-
/* Returns order 'index' of a vehicle or NULL when it doesn't exists */
static inline Order *GetVehicleOrder(const Vehicle *v, int index)
{
@@ -415,6 +383,12 @@
return u;
}
+/**
+ * Finds identical orders in different vehicles and links those vehicles
+ * appropriately. This is used for loading older savegames.
+ */
+void FixSharedOrders(void);
+
// NOSAVE: Return values from various commands.
VARDEF VehicleID _new_train_id;
VARDEF VehicleID _new_wagon_id;
@@ -424,7 +398,9 @@
VARDEF VehicleID _new_vehicle_id;
VARDEF uint16 _returned_refit_capacity;
-#define INVALID_VEHICLE 0xFFFF
+enum {
+ INVALID_VEHICLE = 0xFFFF,
+};
/**
* Get the colour map for an engine. This used for unbuilt engines in the user interface.
=== vehicle_gui.c
==================================================================
--- vehicle_gui.c (revision 313)
+++ vehicle_gui.c (local)
@@ -123,7 +123,8 @@
if (!(vl->flags & VL_REBUILD)) return;
- sort_list = malloc(GetVehiclePoolSize() * sizeof(sort_list[0]));
+ /* Create array for sorting */
+ sort_list = malloc(GetNumVehicles() * sizeof(sort_list[0]));
if (sort_list == NULL) {
error("Could not allocate memory for the vehicle-sorting-list");
}
=== water_cmd.c
==================================================================
--- water_cmd.c (revision 313)
+++ water_cmd.c (local)
@@ -104,7 +104,7 @@
if (flags & DC_EXEC) {
/* Kill the depot, which is registered at the northernmost tile. Use that one */
- DoDeleteDepot(tile2 < tile ? tile2 : tile);
+ DoClearDepot(tile2 < tile ? tile2 : tile);
MakeWater(tile);
MakeWater(tile2);
=== waypoint.c
==================================================================
--- waypoint.c (revision 313)
+++ waypoint.c (local)
@@ -21,47 +21,41 @@
enum {
/* Max waypoints: 64000 (8 * 8000) */
- WAYPOINT_POOL_BLOCK_SIZE_BITS = 3, /* In bits, so (1 << 3) == 8 */
- WAYPOINT_POOL_MAX_BLOCKS = 8000,
+ WAYPOINT_PUDDLE_SIZE = 8,
MAX_WAYPOINTS_PER_TOWN = 64,
};
-/**
- * Called if a new block is added to the waypoint-pool
- */
-static void WaypointPoolNewBlock(uint start_item)
-{
- Waypoint *wp;
+/* Forward declare init/destroy proc, referenced by INDEXED_POOL */
+static void InitializeWaypoint(const IndexedPool* pool, void* drop, DropIndex index);
+static void DestroyWaypoint(const IndexedPool* pool, void* drop, DropIndex index);
- FOR_ALL_WAYPOINTS_FROM(wp, start_item)
- wp->index = start_item++;
+/* Initialize the waypoint-pool */
+static IndexedPoolSettings _waypoint_pool_settings = INDEXED_POOL(Waypoint, WAYPOINT_PUDDLE_SIZE);
+IndexedPool _waypoint_pool;
+
+static void InitializeWaypoint(const IndexedPool* pool, void* drop, DropIndex index)
+{
+ Waypoint* wp = (Waypoint*)drop;
+ ZERO_AND_INDEX(Waypoint, wp);
}
-/* Initialize the town-pool */
-MemoryPool _waypoint_pool = { "Waypoints", WAYPOINT_POOL_MAX_BLOCKS, WAYPOINT_POOL_BLOCK_SIZE_BITS, sizeof(Waypoint), &WaypointPoolNewBlock, NULL, 0, 0, NULL };
+/* Forward declare so it can be used in DestroyWaypoint */
+static void RedrawWaypointSign(const Waypoint *wp);
-/* Create a new waypoint */
-static Waypoint* AllocateWaypoint(void)
+static void DestroyWaypoint(const IndexedPool* pool, void* drop, DropIndex index)
{
- Waypoint *wp;
+ Waypoint* wp = (Waypoint*)drop;
+ Order order;
- FOR_ALL_WAYPOINTS(wp) {
- if (wp->xy == 0) {
- uint index = wp->index;
+ order.type = OT_GOTO_WAYPOINT;
+ order.station = wp->index;
+ DeleteOrderFromAllVehicles(order);
- memset(wp, 0, sizeof(Waypoint));
- wp->index = index;
+ if (wp->string != STR_NULL)
+ DeleteName(wp->string);
- return wp;
- }
- }
-
- /* Check if we can add a block to the pool */
- if (AddBlockToPool(&_waypoint_pool))
- return AllocateWaypoint();
-
- return NULL;
+ RedrawWaypointSign(wp);
}
/* Update the sign for the waypoint */
@@ -247,23 +241,6 @@
return _price.build_train_depot;
}
-/* Internal handler to delete a waypoint */
-static void DoDeleteWaypoint(Waypoint *wp)
-{
- Order order;
-
- wp->xy = 0;
-
- order.type = OT_GOTO_WAYPOINT;
- order.station = wp->index;
- DeleteDestinationFromVehicleOrder(order);
-
- if (wp->string != STR_NULL)
- DeleteName(wp->string);
-
- RedrawWaypointSign(wp);
-}
-
/* Daily loop for waypoints */
void WaypointsDailyLoop(void)
{
@@ -272,7 +249,7 @@
/* Check if we need to delete a waypoint */
FOR_ALL_WAYPOINTS(wp) {
if (wp->deleted && !--wp->deleted) {
- DoDeleteWaypoint(wp);
+ DeleteWaypoint(wp);
}
}
}
@@ -331,7 +308,7 @@
Waypoint *wp;
StringID str;
- if (!IsWaypointIndex(p1)) return CMD_ERROR;
+ if (!IsValidWaypointID(p1)) return CMD_ERROR;
if (_cmd_text[0] != '\0') {
str = AllocateNameUnique(_cmd_text, 0);
@@ -444,8 +421,7 @@
void InitializeWaypoints(void)
{
- CleanPool(&_waypoint_pool);
- AddBlockToPool(&_waypoint_pool);
+ IndexedPoolInitialize(&_waypoint_pool, &_waypoint_pool_settings);
}
static const SaveLoad _waypoint_desc[] = {
@@ -482,7 +458,7 @@
while ((index = SlIterateArray()) != -1) {
Waypoint *wp;
- if (!AddBlockIfNeeded(&_waypoint_pool, index))
+ if (IndexedPoolAllocateIndex(&_waypoint_pool, index) == NULL)
error("Waypoints: failed loading savegame: too many waypoints");
wp = GetWaypoint(index);
=== waypoint.h
==================================================================
--- waypoint.h (revision 313)
+++ waypoint.h (local)
@@ -8,7 +8,7 @@
struct Waypoint {
TileIndex xy; ///< Tile of waypoint
- StationID index; ///< Index of waypoint
+ WaypointID index; ///< Index of waypoint /* TODO: StationID? */
TownID town_index; ///< Town associated with the waypoint
byte town_cn; ///< The Nth waypoint for this town (consecutive number)
@@ -29,32 +29,15 @@
RAIL_WAYPOINT_TRACK_MASK = 1,
};
-extern MemoryPool _waypoint_pool;
-
-/**
- * Get the pointer to the waypoint with index 'index'
+/*
+ * Waypoint pool
*/
-static inline Waypoint *GetWaypoint(uint index)
-{
- return (Waypoint*)GetItemFromPool(&_waypoint_pool, index);
-}
+extern IndexedPool _waypoint_pool;
-/**
- * Get the current size of the WaypointPool
- */
-static inline uint16 GetWaypointPoolSize(void)
-{
- return _waypoint_pool.total_items;
-}
+#define FOR_ALL_WAYPOINTS(w) FOR_ALL_IN_POOL(_waypoint_pool, w)
+#define FOR_ALL_WAYPOINTS_EVERY_N_TICKS(v, n, ctr) FOR_ALL_EVERY_N_TICKS(_waypoint_pool, v, n, ctr)
+INDEXED_POOL_FUNCTIONS(Waypoint, Waypoints, _waypoint_pool)
-static inline bool IsWaypointIndex(uint index)
-{
- return index < GetWaypointPoolSize();
-}
-
-#define FOR_ALL_WAYPOINTS_FROM(wp, start) for (wp = GetWaypoint(start); wp != NULL; wp = (wp->index + 1 < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1) : NULL)
-#define FOR_ALL_WAYPOINTS(wp) FOR_ALL_WAYPOINTS_FROM(wp, 0)
-
static inline bool IsRailWaypoint(TileIndex tile)
{
return (_m[tile].m5 & 0xFC) == 0xC4;