mirror of https://github.com/OpenTTD/OpenTTD
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
parent
41ed5f9822
commit
6d5aee0545
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue