diff --git a/src/oldpool.h b/src/oldpool.h index 80e121cb62..5e5b53c59b 100644 --- a/src/oldpool.h +++ b/src/oldpool.h @@ -29,14 +29,14 @@ protected: const char* name; ///< Name of the pool (just for debugging) - uint max_blocks; ///< The max amount of blocks this pool can have - uint block_size_bits; ///< The size of each block in bits - uint item_size; ///< How many bytes one block is + 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 /// Pointer to a function that is called after a new block is added - OldMemoryPoolNewBlock *new_block_proc; + const OldMemoryPoolNewBlock *new_block_proc; /// Pointer to a function that is called to clean a block - OldMemoryPoolCleanBlock *clean_block_proc; + const OldMemoryPoolCleanBlock *clean_block_proc; uint current_blocks; ///< How many blocks we have in our pool uint total_items; ///< How many items we now have in this pool @@ -44,20 +44,45 @@ protected: public: byte **blocks; ///< An array of blocks (one block hold all the items) - inline uint GetSize() + /** + * Get the size of this pool, i.e. the total number of items you + * can put into it at the current moment; the pool might still + * be able to increase the size of the pool. + * @return the size of the pool + */ + inline uint GetSize() const { return this->total_items; } - inline bool CanAllocateMoreBlocks() + /** + * Can this pool allocate more blocks, i.e. is the maximum amount + * of allocated blocks not yet reached? + * @return the if and only if the amount of allocable blocks is + * less than the amount of allocated blocks. + */ + inline bool CanAllocateMoreBlocks() const { return this->current_blocks < this->max_blocks; } - inline uint GetBlockCount() + /** + * Get the maximum number of allocable blocks. + * @return the numebr of blocks + */ + inline uint GetBlockCount() const { return this->current_blocks; } + + /** + * Get the name of this pool. + * @return the name + */ + inline const char *GetName() const + { + return this->name; + } }; template @@ -66,7 +91,13 @@ struct OldMemoryPool : public OldMemoryPoolBase { OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) : OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {} - inline T *Get(uint index) + /** + * Get the pool entry at the given index. + * @param index the index into the pool + * @pre index < this->GetSize() + * @return the pool entry. + */ + inline T *Get(uint index) const { assert(index < this->GetSize()); return (T*)(this->blocks[index >> this->block_size_bits] + @@ -99,11 +130,9 @@ static inline bool AddBlockIfNeeded(OldMemoryPoolBase *array, uint index) { retu template *Tpool> static void PoolNewBlock(uint start_item) { - /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. - * TODO - This is just a temporary stage, this will be removed. */ for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) { + t = new (t) T(); t->index = start_item++; - t->PreInit(); } } @@ -125,6 +154,128 @@ static void PoolCleanBlock(uint start_item, uint end_item) } +/** + * Generalization for all pool items that are saved in the savegame. + * It specifies all the mechanics to access the pool easily. + */ +template *Tpool> +struct PoolItem { + /** + * The pool-wide index of this object. + */ + Tid index; + + /** + * We like to have the correct class destructed. + */ + virtual ~PoolItem() + { + } + + /** + * Called on each object when the pool is being destroyed, so one + * can free allocated memory without the need for freeing for + * example orders. + */ + virtual void QuickFree() + { + } + + /** + * An overriden version of new that allocates memory on the pool. + * @param size the size of the variable (unused) + * @return the memory that is 'allocated' + */ + void *operator new (size_t size) + { + return AllocateRaw(); + } + + /** + * 'Free' the memory allocated by the overriden new. + * @param p the memory to 'free' + */ + void operator delete(void *p) + { + } + + /** + * An overriden version of new, so you can directly allocate a new object with + * the correct index when one is loading the savegame. + * @param size the size of the variable (unused) + * @param index the index of the object + * @return the memory that is 'allocated' + */ + void *operator new (size_t size, int index) + { + if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName()); + + return Tpool->Get(index); + } + + /** + * 'Free' the memory allocated by the overriden new. + * @param p the memory to 'free' + * @param index the original parameter given to create the memory + */ + void operator delete(void *p, int index) + { + } + + /** + * An overriden version of new, so you can use the vehicle instance + * instead of a newly allocated piece of memory. + * @param size the size of the variable (unused) + * @param pn the already existing object to use as 'storage' backend + * @return the memory that is 'allocated' + */ + void *operator new(size_t size, T *pn) + { + return pn; + } + + /** + * 'Free' the memory allocated by the overriden new. + * @param p the memory to 'free' + * @param pn the pointer that was given to 'new' on creation. + */ + void operator delete(void *p, T *pn) + { + } + + /** + * Is this a valid object or not? + * @return true if and only if it is valid + */ + virtual bool IsValid() const + { + return false; + } + +private: + /** + * Allocate a pool item; possibly allocate a new block in the pool. + * @return the allocated pool item (or NULL when the pool is full). + */ + static T *AllocateRaw() + { + for (T *t = Tpool->Get(0); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) { + if (!t->IsValid()) { + Tid index = t->index; + + memset(t, 0, sizeof(T)); + t->index = index; + return t; + } + } + + /* Check if we can add a block to the pool */ + if (Tpool->AddBlockToPool()) return AllocateRaw(); + + return NULL; + } +}; + #define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \ enum { \ diff --git a/src/station.cpp b/src/station.cpp index 0f7db16ff8..4633f1d188 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -91,29 +91,6 @@ void Station::QuickFree() free(this->speclist); } -void *Station::operator new(size_t size) -{ - Station *st = AllocateRaw(); - return st; -} - -void *Station::operator new(size_t size, int st_idx) -{ - if (!AddBlockIfNeeded(&_Station_pool, st_idx)) - error("Stations: failed loading savegame: too many stations"); - - Station *st = GetStation(st_idx); - return st; -} - -void Station::operator delete(void *p) -{ -} - -void Station::operator delete(void *p, int st_idx) -{ -} - /** Called when new facility is built on the station. If it is the first facility * it initializes also 'xy' and 'random_bits' members */ void Station::AddFacility(byte new_facility_bit, TileIndex facil_xy) @@ -176,30 +153,6 @@ bool Station::TileBelongsToRailStation(TileIndex tile) const return IsTileType(tile, MP_STATION) && GetStationIndex(tile) == index && IsRailwayStation(tile); } -/*static*/ Station *Station::AllocateRaw() -{ - Station *st = NULL; - - /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. - * TODO - This is just a temporary stage, this will be removed. */ - for (st = GetStation(0); st != NULL; st = (st->index + 1U < GetStationPoolSize()) ? GetStation(st->index + 1U) : NULL) { - if (!st->IsValid()) { - 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 AllocateRaw(); - - _error_message = STR_3008_TOO_MANY_STATIONS_LOADING; - return NULL; -} - - /** Obtain the length of a platform * @pre tile must be a railway station tile * @param tile A tile that contains the platform in question @@ -426,36 +379,6 @@ StationRect& StationRect::operator = (Rect src) /* RoadStop implementation */ /************************************************************************/ -/** Allocates a new RoadStop onto the pool, or recycles an unsed one - * @return a pointer to the new roadstop - */ -void *RoadStop::operator new(size_t size) -{ - RoadStop *rs = AllocateRaw(); - return rs; -} - -/** Gets a RoadStop with a given index and allocates it when needed - * @return a pointer to the roadstop - */ -void *RoadStop::operator new(size_t size, int index) -{ - if (!AddBlockIfNeeded(&_RoadStop_pool, index)) { - error("RoadStops: failed loading savegame: too many RoadStops"); - } - - RoadStop *rs = GetRoadStop(index); - return rs; -} - -void RoadStop::operator delete(void *p) -{ -} - -void RoadStop::operator delete(void *p, int index) -{ -} - /** Initializes a RoadStop */ RoadStop::RoadStop(TileIndex tile) : xy(tile), @@ -483,37 +406,13 @@ RoadStop::~RoadStop() DEBUG(ms, cDebugCtorLevel , "I- at %d[0x%x]", xy, xy); - xy = INVALID_TILE; -} - -/** Low-level function for allocating a RoadStop on the pool */ -RoadStop *RoadStop::AllocateRaw() -{ - RoadStop *rs; - - /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. - * TODO - This is just a temporary stage, this will be removed. */ - for (rs = GetRoadStop(0); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) { - if (!rs->IsValid()) { - RoadStopID 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 AllocateRaw(); - - return NULL; + xy = 0; } /** Determines whether a RoadStop is a valid (i.e. existing) one */ bool RoadStop::IsValid() const { - return xy != INVALID_TILE; + return xy != 0; } /** Checks whether there is a free bay in this road stop */ diff --git a/src/station.h b/src/station.h index e35ce7d3ad..b679499d7b 100644 --- a/src/station.h +++ b/src/station.h @@ -15,6 +15,12 @@ #include "cargopacket.h" #include +struct Station; +struct RoadStop; + +DECLARE_OLD_POOL(Station, Station, 6, 1000) +DECLARE_OLD_POOL(RoadStop, RoadStop, 5, 2000) + static const byte INITIAL_STATION_RATING = 175; struct GoodsEntry { @@ -35,7 +41,7 @@ struct GoodsEntry { }; /** A Stop for a Road Vehicle */ -struct RoadStop { +struct RoadStop : PoolItem { /** Types of RoadStops */ enum Type { BUS, ///< A standard stop for buses @@ -47,23 +53,12 @@ struct RoadStop { static const uint MAX_BAY_COUNT = 2; ///< The maximum number of loading bays TileIndex xy; ///< Position on the map - RoadStopID index; ///< Global (i.e. pool-wide) index byte status; ///< Current status of the Stop. Like which spot is taken. Access using *Bay and *Busy functions. byte num_vehicles; ///< Number of vehicles currently slotted to this stop struct RoadStop *next; ///< Next stop of the given type at this station - RoadStop(TileIndex tile); - ~RoadStop(); - - void PreInit() { this->xy = INVALID_TILE; } - void QuickFree() {} - - void *operator new (size_t size); - void operator delete(void *rs); - - /* For loading games */ - void *operator new (size_t size, int index); - void operator delete(void *rs, int index); + RoadStop(TileIndex tile = 0); + virtual ~RoadStop(); bool IsValid() const; @@ -75,8 +70,6 @@ struct RoadStop { void FreeBay(uint nr); bool IsEntranceBusy() const; void SetEntranceBusy(bool busy); -protected: - static RoadStop *AllocateRaw(); }; struct StationSpecList { @@ -108,7 +101,7 @@ struct StationRect : public Rect { StationRect& operator = (Rect src); }; -struct Station { +struct Station : PoolItem { public: RoadStop *GetPrimaryRoadStop(RoadStop::Type type) const { @@ -151,7 +144,6 @@ struct Station { Date build_date; uint64 airport_flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 - StationID index; byte last_vehicle_type; std::list loading_vehicles; @@ -165,19 +157,10 @@ struct Station { static const int cDebugCtorLevel = 3; Station(TileIndex tile = 0); - ~Station(); + virtual ~Station(); - void PreInit() {} void QuickFree(); - /* normal new/delete operators. Used when building/removing station */ - void *operator new (size_t size); - void operator delete(void *p); - - /* new/delete operators accepting station index. Used when loading station from savegame. */ - void *operator new (size_t size, int st_idx); - void operator delete(void *p, int st_idx); - void AddFacility(byte new_facility_bit, TileIndex facil_xy); void MarkDirty() const; void MarkTilesDirty(bool cargo_change) const; @@ -186,9 +169,6 @@ struct Station { uint GetPlatformLength(TileIndex tile) const; bool IsBuoy() const; bool IsValid() const; - -protected: - static Station *AllocateRaw(); }; enum StationType { @@ -238,8 +218,6 @@ void UpdateAllStationVirtCoord(); void RebuildStationLists(); void ResortStationLists(); -DECLARE_OLD_POOL(Station, Station, 6, 1000) - static inline StationID GetMaxStationIndex() { /* TODO - This isn't the real content of the function, but @@ -266,8 +244,6 @@ static inline bool IsValidStationID(StationID index) /* Stuff for ROADSTOPS */ -DECLARE_OLD_POOL(RoadStop, RoadStop, 5, 2000) - #define FOR_ALL_ROADSTOPS_FROM(rs, start) for (rs = GetRoadStop(start); rs != NULL; rs = (rs->index + 1U < GetRoadStopPoolSize()) ? GetRoadStop(rs->index + 1U) : NULL) if (rs->IsValid()) #define FOR_ALL_ROADSTOPS(rs) FOR_ALL_ROADSTOPS_FROM(rs, 0) diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index b5ca877f18..045da52a42 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -927,7 +927,7 @@ CommandCost CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, } else { /* allocate and initialize new station */ st = new Station(tile_org); - if (st == NULL) return CMD_ERROR; + if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ st_auto_delete = st; @@ -1358,7 +1358,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } else { /* allocate and initialize new station */ st = new Station(tile); - if (st == NULL) return CMD_ERROR; + if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); /* ensure that in case of error (or no DC_EXEC) the new station gets deleted upon return */ st_auto_delete = st; @@ -1652,7 +1652,7 @@ CommandCost CmdBuildAirport(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* allocate and initialize new station */ st = new Station(tile); - if (st == NULL) return CMD_ERROR; + if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ st_auto_delete = st; @@ -1774,7 +1774,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /* allocate and initialize new station */ Station *st = new Station(tile); - if (st == NULL) return CMD_ERROR; + if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ AutoPtrT st_auto_delete(st); @@ -1939,7 +1939,7 @@ CommandCost CmdBuildDock(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) } else { /* allocate and initialize new station */ st = new Station(tile); - if (st == NULL) return CMD_ERROR; + if (st == NULL) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING); /* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */ st_auto_delete = st;