From 052f42132750db6c1a5bbe6308090d48908418fc Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 9 Apr 2024 17:54:42 +0100 Subject: [PATCH] Change: Use vector/iterators/algorithms instead of C-array/loops for NewGRF classes. --- src/airport_gui.cpp | 2 +- src/newgrf.cpp | 2 ++ src/newgrf_class.h | 13 +++---- src/newgrf_class_func.h | 76 ++++++++++++++--------------------------- 4 files changed, 35 insertions(+), 58 deletions(-) diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 3b346d2629..a52b876d7c 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -546,7 +546,7 @@ public: if (change_class) { /* If that fails, select the first available airport * from the first class where airports are available. */ - for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { + for (AirportClassID j = APC_BEGIN; j < AirportClass::GetClassCount(); j++) { AirportClass *apclass = AirportClass::Get(j); for (uint i = 0; i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index e5794882f7..662fc3e38b 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -458,6 +458,8 @@ struct StringIDMapping { StringIDMapping(uint32_t grfid, StringID source, std::function &&func) : grfid(grfid), source(source), func(std::move(func)) { } }; + +/** Strings to be mapped during load. */ static std::vector _string_to_grf_mapping; /** diff --git a/src/newgrf_class.h b/src/newgrf_class.h index 38e068a881..cd80d65410 100644 --- a/src/newgrf_class.h +++ b/src/newgrf_class.h @@ -19,17 +19,14 @@ template class NewGRFClass { private: - uint ui_count; ///< Number of specs in this class potentially available to the user. + uint ui_count = 0; ///< Number of specs in this class potentially available to the user. std::vector spec; ///< List of specifications. /** * The actual classes. - * @note We store pointers to members of this array in various places outside this class (e.g. to 'name' for GRF string resolving). - * Thus this must be a static array, and cannot be a self-resizing vector or similar. + * @note This may be reallocated during initialization so pointers may be invalidated. */ - static NewGRFClass classes[Tmax]; - - void ResetClass(); + static inline std::vector> classes; /** Initialise the defaults. */ static void InsertDefaults(); @@ -38,8 +35,12 @@ public: uint32_t global_id; ///< Global ID for class, e.g. 'DFLT', 'WAYP', etc. StringID name; ///< Name of this class. + /* Public constructor as emplace_back needs access. */ + NewGRFClass(uint32_t global_id, StringID name) : global_id(global_id), name(name) { } + void Insert(Tspec *spec); + Tid Index() const { return static_cast(std::distance(&*std::cbegin(NewGRFClass::classes), this)); } /** Get the number of allocated specs within the class. */ uint GetSpecCount() const { return static_cast(this->spec.size()); } /** Get the number of potentially user-available specs within the class. */ diff --git a/src/newgrf_class_func.h b/src/newgrf_class_func.h index b3de6ba9c1..ef9490a0c1 100644 --- a/src/newgrf_class_func.h +++ b/src/newgrf_class_func.h @@ -11,35 +11,19 @@ #include "table/strings.h" -/** Instantiate the array. */ -template -NewGRFClass NewGRFClass::classes[Tmax]; - -/** Reset the class, i.e. clear everything. */ -template -void NewGRFClass::ResetClass() -{ - this->global_id = 0; - this->name = STR_EMPTY; - this->ui_count = 0; - - this->spec.clear(); -} - /** Reset the classes, i.e. clear everything. */ template void NewGRFClass::Reset() { - for (Tid i = (Tid)0; i < Tmax; i++) { - classes[i].ResetClass(); - } + NewGRFClass::classes.clear(); + NewGRFClass::classes.shrink_to_fit(); - InsertDefaults(); + NewGRFClass::InsertDefaults(); } /** * Allocate a class with a given global class ID. - * @param cls_id The global class id, such as 'DFLT'. + * @param global_id The global class id, such as 'DFLT'. * @return The (non global!) class ID for the class. * @note Upon allocating the same global class ID for a * second time, this first allocation will be given. @@ -47,19 +31,19 @@ void NewGRFClass::Reset() template Tid NewGRFClass::Allocate(uint32_t global_id) { - for (Tid i = (Tid)0; i < Tmax; i++) { - if (classes[i].global_id == global_id) { - /* ClassID is already allocated, so reuse it. */ - return i; - } else if (classes[i].global_id == 0) { - /* This class is empty, so allocate it to the global id. */ - classes[i].global_id = global_id; - return i; - } + auto found = std::find_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [global_id](const auto &cls) { return cls.global_id == global_id; }); + + /* Id is already allocated, so reuse it. */ + if (found != std::end(NewGRFClass::classes)) return found->Index(); + + /* More slots available, allocate a slot to the global id. */ + if (NewGRFClass::classes.size() < Tmax) { + auto &cls = NewGRFClass::classes.emplace_back(global_id, STR_EMPTY); + return cls.Index(); } GrfMsg(2, "ClassAllocate: already allocated {} classes, using default", Tmax); - return (Tid)0; + return static_cast(0); } /** @@ -82,7 +66,7 @@ void NewGRFClass::Insert(Tspec *spec) template void NewGRFClass::Assign(Tspec *spec) { - assert(spec->cls_id < Tmax); + assert(static_cast(spec->cls_id) < NewGRFClass::classes.size()); Get(spec->cls_id)->Insert(spec); } @@ -94,8 +78,8 @@ void NewGRFClass::Assign(Tspec *spec) template NewGRFClass *NewGRFClass::Get(Tid cls_id) { - assert(cls_id < Tmax); - return classes + cls_id; + assert(static_cast(cls_id) < NewGRFClass::classes.size()); + return &NewGRFClass::classes[cls_id]; } /** @@ -105,9 +89,7 @@ NewGRFClass *NewGRFClass::Get(Tid cls_id) template uint NewGRFClass::GetClassCount() { - uint i; - for (i = 0; i < Tmax && classes[i].global_id != 0; i++) {} - return i; + return static_cast(NewGRFClass::classes.size()); } /** @@ -117,11 +99,7 @@ uint NewGRFClass::GetClassCount() template uint NewGRFClass::GetUIClassCount() { - uint cnt = 0; - for (uint i = 0; i < Tmax && classes[i].global_id != 0; i++) { - if (classes[i].GetUISpecCount() > 0) cnt++; - } - return cnt; + return std::count_if(std::begin(NewGRFClass::classes), std::end(NewGRFClass::classes), [](const auto &cls) { return cls.GetUISpecCount() > 0; }); } /** @@ -132,9 +110,9 @@ uint NewGRFClass::GetUIClassCount() template Tid NewGRFClass::GetUIClass(uint index) { - for (uint i = 0; i < Tmax && classes[i].global_id != 0; i++) { - if (classes[i].GetUISpecCount() == 0) continue; - if (index-- == 0) return (Tid)i; + for (const auto &cls : NewGRFClass::classes) { + if (cls.GetUISpecCount() == 0) continue; + if (index-- == 0) return cls.Index(); } NOT_REACHED(); } @@ -193,15 +171,11 @@ int NewGRFClass::GetUIFromIndex(int index) const template const Tspec *NewGRFClass::GetByGrf(uint32_t grfid, uint16_t local_id, int *index) { - uint j; - - for (Tid i = (Tid)0; i < Tmax; i++) { - uint count = static_cast(classes[i].spec.size()); - for (j = 0; j < count; j++) { - const Tspec *spec = classes[i].spec[j]; + for (const auto &cls : NewGRFClass::classes) { + for (const auto &spec : cls.spec) { if (spec == nullptr) continue; if (spec->grf_prop.grffile->grfid == grfid && spec->grf_prop.local_id == local_id) { - if (index != nullptr) *index = j; + if (index != nullptr) *index = static_cast(std::distance(cls.spec.data(), &spec)); return spec; } }