From ff972ec4ffddf6b8ac62614144f106e4bc9a4665 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 14 Aug 2024 19:58:56 +0100 Subject: [PATCH] Codechange: Store custom station layouts in a map instead of nested vectors. (#12898) The map key is the platforms and length combined. This simplifies allocation and searching for layouts. --- src/newgrf.cpp | 10 +++++----- src/newgrf_station.h | 22 +++++++++++++--------- src/station_cmd.cpp | 14 +++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 5b51d43528..6f95e6408c 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2042,14 +2042,14 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte if (length == 0 || number == 0) break; - if (statspec->layouts.size() < length) statspec->layouts.resize(length); - if (statspec->layouts[length - 1].size() < number) statspec->layouts[length - 1].resize(number); + const uint8_t *buf_layout = buf.ReadBytes(length * number); - const uint8_t *layout = buf.ReadBytes(length * number); - statspec->layouts[length - 1][number - 1].assign(layout, layout + length * number); + /* Create entry in layouts and assign the layout to it. */ + auto &layout = statspec->layouts[GetStationLayoutKey(number, length)]; + layout.assign(buf_layout, buf_layout + length * number); /* Ensure the first bit, axis, is zero. The rest of the value is validated during rendering, as we don't know the range yet. */ - for (auto &tile : statspec->layouts[length - 1][number - 1]) { + for (auto &tile : layout) { if ((tile & ~1U) != tile) { GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number); tile &= ~1U; diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 2a5c711707..ff6ca8c493 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -170,15 +170,8 @@ struct StationSpec : NewGRFSpecBase { AnimationInfo animation; - /** - * Custom platform layouts. - * This is a 2D array containing an array of tiles. - * 1st layer is platform lengths. - * 2nd layer is tracks (width). - * These can be sparsely populated, and the upper limit is not defined but - * limited to 255. - */ - std::vector>> layouts; + /** Custom platform layouts, keyed by platform and length combined. */ + std::unordered_map> layouts; }; DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags); @@ -187,6 +180,17 @@ using StationClass = NewGRFClass; const StationSpec *GetStationSpec(TileIndex t); +/** + * Get the station layout key for a given station layout size. + * @param platforms Number of platforms. + * @param length Length of platforms. + * @returns Key of station layout. + */ +inline uint16_t GetStationLayoutKey(uint8_t platforms, uint8_t length) +{ + return (length << 8U) | platforms; +} + /** * Test if a StationClass is the waypoint class. * @param cls StationClass to test. diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 9b05e83d3b..497db97683 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1127,13 +1127,13 @@ static inline uint8_t *CreateMulti(uint8_t *layout, int n, uint8_t b) */ void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec) { - if (statspec != nullptr && statspec->layouts.size() >= plat_len && - statspec->layouts[plat_len - 1].size() >= numtracks && - !statspec->layouts[plat_len - 1][numtracks - 1].empty()) { - /* Custom layout defined, follow it. */ - memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1].data(), - static_cast(plat_len) * numtracks); - return; + if (statspec != nullptr) { + auto found = statspec->layouts.find(GetStationLayoutKey(numtracks, plat_len)); + if (found != std::end(statspec->layouts)) { + /* Custom layout defined, copy to buffer. */ + std::copy(std::begin(found->second), std::end(found->second), layout); + return; + } } if (plat_len == 1) {