1
0
Fork 0

Codechange: Restructure RoadStop Entries to reduce pointers. (#14069)

A RoadStop must own both west and east `Entry`s, but they are allocated separately.

Combine this allocation into one instead.
pull/14083/head
Peter Nelson 2025-04-23 08:29:34 +01:00 committed by GitHub
parent 41ed5f9822
commit 6d5aee0545
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 62 deletions

View File

@ -74,9 +74,8 @@ void CheckCaches()
for (const RoadStop *rs : RoadStop::Iterate()) {
if (IsBayRoadStopTile(rs->xy)) continue;
assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NE).CheckIntegrity(rs);
rs->GetEntry(DIAGDIR_NW).CheckIntegrity(rs);
}
std::vector<NewGRFCache> grf_cache;

View File

@ -80,8 +80,8 @@ protected:
if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
/* When we're the first road stop in a 'queue' of them we increase
* cost based on the fill percentage of the whole queue. */
const RoadStop::Entry *entry = rs->GetEntry(dir);
cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
const RoadStop::Entry &entry = rs->GetEntry(dir);
cost += entry.GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry.GetLength();
}
} else {
/* Increase cost for filled road stops */

View File

@ -28,8 +28,7 @@ RoadStop::~RoadStop()
{
/* When we are the head we need to free the entries */
if (this->status.Test(RoadStopStatusFlag::BaseEntry)) {
delete this->east;
delete this->west;
delete this->entries;
}
if (CleaningPool()) return;
@ -62,7 +61,7 @@ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const
*/
void RoadStop::MakeDriveThrough()
{
assert(this->east == nullptr && this->west == nullptr);
assert(this->entries == nullptr);
RoadStopType rst = GetRoadStopType(this->xy);
Axis axis = GetDriveThroughStopAxis(this->xy);
@ -79,48 +78,43 @@ void RoadStop::MakeDriveThrough()
RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : nullptr;
/* Amount of road stops that will be added to the 'northern' head */
int added = 1;
if (north && rs_north->east != nullptr) { // (east != nullptr) == (west != nullptr)
uint16_t added = 1;
if (north && rs_north->entries != nullptr) {
/* There is a more northern one, so this can join them */
this->east = rs_north->east;
this->west = rs_north->west;
this->entries = rs_north->entries;
if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr)
if (south && rs_south->entries != nullptr) {
/* There more southern tiles too, they must 'join' us too */
rs_south->status.Reset(RoadStopStatusFlag::BaseEntry);
this->east->occupied += rs_south->east->occupied;
this->west->occupied += rs_south->west->occupied;
this->entries->east.occupied += rs_south->entries->east.occupied;
this->entries->west.occupied += rs_south->entries->west.occupied;
/* Free the now unneeded entry structs */
delete rs_south->east;
delete rs_south->west;
/* Free the now unneeded entries struct */
delete rs_south->entries;
/* Make all 'children' of the southern tile take the new master */
for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) {
rs_south = RoadStop::GetByTile(south_tile, rst);
if (rs_south->east == nullptr) break;
rs_south->east = rs_north->east;
rs_south->west = rs_north->west;
if (rs_south->entries == nullptr) break;
rs_south->entries = rs_north->entries;
added++;
}
}
} else if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr)
} else if (south && rs_south->entries != nullptr) {
/* There is one to the south, but not to the north... so we become 'parent' */
this->east = rs_south->east;
this->west = rs_south->west;
this->entries = rs_south->entries;
this->status.Set(RoadStopStatusFlag::BaseEntry);
rs_south->status.Reset(RoadStopStatusFlag::BaseEntry);
} else {
/* We are the only... so we are automatically the master */
this->east = new Entry();
this->west = new Entry();
this->entries = new Entries();
this->status.Set(RoadStopStatusFlag::BaseEntry);
}
/* Now update the lengths */
added *= TILE_SIZE;
this->east->length += added;
this->west->length += added;
this->entries->east.length += added;
this->entries->west.length += added;
}
/**
@ -129,7 +123,7 @@ void RoadStop::MakeDriveThrough()
*/
void RoadStop::ClearDriveThrough()
{
assert(this->east != nullptr && this->west != nullptr);
assert(this->entries != nullptr);
RoadStopType rst = GetRoadStopType(this->xy);
Axis axis = GetDriveThroughStopAxis(this->xy);
@ -155,8 +149,7 @@ void RoadStop::ClearDriveThrough()
/* There are more southern tiles too, they must be split;
* first make the new southern 'base' */
rs_south->status.Set(RoadStopStatusFlag::BaseEntry);
rs_south->east = new Entry();
rs_south->west = new Entry();
rs_south->entries = new Entries();
/* Keep track of the base because we need it later on */
RoadStop *rs_south_base = rs_south;
@ -165,8 +158,7 @@ void RoadStop::ClearDriveThrough()
/* Make all (even more) southern stops part of the new entry queue */
for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) {
rs_south = RoadStop::GetByTile(south_tile, rst);
rs_south->east = rs_south_base->east;
rs_south->west = rs_south_base->west;
rs_south->entries = rs_south_base->entries;
}
/* Find the other end; the northern most tile */
@ -180,32 +172,30 @@ void RoadStop::ClearDriveThrough()
* rebuild it from scratch as that removes lots of maintenance code
* for the vehicle list and it's faster in real games as long as you
* do not keep split and merge road stop every tick by the millions. */
rs_south_base->east->Rebuild(rs_south_base);
rs_south_base->west->Rebuild(rs_south_base);
rs_south_base->entries->east.Rebuild(rs_south_base);
rs_south_base->entries->west.Rebuild(rs_south_base);
assert(rs_north->status.Test(RoadStopStatusFlag::BaseEntry));
rs_north->east->Rebuild(rs_north);
rs_north->west->Rebuild(rs_north);
rs_north->entries->east.Rebuild(rs_north);
rs_north->entries->west.Rebuild(rs_north);
} else {
/* Only we left, so simple update the length. */
rs_north->east->length -= TILE_SIZE;
rs_north->west->length -= TILE_SIZE;
rs_north->entries->east.length -= TILE_SIZE;
rs_north->entries->west.length -= TILE_SIZE;
}
} else if (south) {
/* There is only something to the south. Hand over the base entry */
rs_south->status.Set(RoadStopStatusFlag::BaseEntry);
rs_south->east->length -= TILE_SIZE;
rs_south->west->length -= TILE_SIZE;
rs_south->entries->east.length -= TILE_SIZE;
rs_south->entries->west.length -= TILE_SIZE;
} else {
/* We were the last */
delete this->east;
delete this->west;
delete this->entries;
}
/* Make sure we don't get used for something 'incorrect' */
this->status.Reset(RoadStopStatusFlag::BaseEntry);
this->east = nullptr;
this->west = nullptr;
this->entries = nullptr;
}
/**
@ -220,7 +210,7 @@ void RoadStop::Leave(RoadVehicle *rv)
this->SetEntranceBusy(false);
} else {
/* Otherwise just leave the drive through's entry cache. */
this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
this->GetEntry(DirToDiagDir(rv->direction)).Leave(rv);
}
}
@ -248,7 +238,7 @@ bool RoadStop::Enter(RoadVehicle *rv)
}
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
this->GetEntry(DirToDiagDir(rv->direction)).Enter(rv);
/* Indicate a drive-through stop */
SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
@ -335,7 +325,7 @@ void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
assert(rs->status.Test(RoadStopStatusFlag::BaseEntry));
Axis axis = GetDriveThroughStopAxis(rs->xy);
if (side == -1) side = (rs->east == this);
if (side == -1) side = (&rs->entries->east == this);
auto entry_dir = GetEntryDirection(side, axis);
std::vector<const RoadVehicle *> vehicles;
@ -376,6 +366,6 @@ void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const
assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - TileOffsByAxis(GetDriveThroughStopAxis(rs->xy))));
Entry temp;
temp.Rebuild(rs, rs->east == this);
temp.Rebuild(rs, &rs->entries->east == this);
if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
}

View File

@ -31,15 +31,12 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
/** Container for each entry point of a drive through road stop */
struct Entry {
private:
int length = 0; ///< The length of the stop in tile 'units'
int occupied = 0; ///< The amount of occupied stop in tile 'units'
uint16_t length = 0; ///< The length of the stop in tile 'units'
uint16_t occupied = 0; ///< The amount of occupied stop in tile 'units'
public:
friend struct RoadStop; ///< Oh yeah, the road stop may play with me.
/** Create an entry */
Entry() {}
/**
* Get the length of this drive through stop.
* @return the length in tile units.
@ -64,6 +61,12 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
void Rebuild(const RoadStop *rs, int side = -1);
};
/** Container for both east and west entry points. */
struct Entries {
Entry east{}; ///< Information for vehicles that entered from the east
Entry west{}; ///< Information for vehicles that entered from the west
};
RoadStopStatusFlags status{RoadStopStatusFlag::Bay0Free, RoadStopStatusFlag::Bay1Free}; ///< Current status of the Stop. Access using *Bay and *Busy functions.
TileIndex xy = INVALID_TILE; ///< Position on the map
RoadStop *next = nullptr; ///< Next stop of the given type at this station
@ -119,9 +122,9 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
* @param dir The direction to get the entry for.
* @return the entry
*/
inline const Entry *GetEntry(DiagDirection dir) const
inline const Entry &GetEntry(DiagDirection dir) const
{
return HasBit((int)dir, 1) ? this->west : this->east;
return dir >= DIAGDIR_SW ? this->entries->west : this->entries->east;
}
/**
@ -129,9 +132,9 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
* @param dir The direction to get the entry for.
* @return the entry
*/
inline Entry *GetEntry(DiagDirection dir)
inline Entry &GetEntry(DiagDirection dir)
{
return HasBit((int)dir, 1) ? this->west : this->east;
return dir >= DIAGDIR_SW ? this->entries->west : this->entries->east;
}
void MakeDriveThrough();
@ -147,8 +150,7 @@ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> {
static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next);
private:
Entry *east = nullptr; ///< The vehicles that entered from the east
Entry *west = nullptr; ///< The vehicles that entered from the west
Entries *entries = nullptr; ///< Information about available and allocated bays.
/**
* Allocates a bay

View File

@ -151,8 +151,8 @@ void AfterLoadRoadStops()
for (RoadStop *rs : RoadStop::Iterate()) {
if (!rs->status.Test(RoadStop::RoadStopStatusFlag::BaseEntry)) continue;
rs->GetEntry(DIAGDIR_NE)->Rebuild(rs);
rs->GetEntry(DIAGDIR_NW)->Rebuild(rs);
rs->GetEntry(DIAGDIR_NE).Rebuild(rs);
rs->GetEntry(DIAGDIR_NW).Rebuild(rs);
}
}