From cbaf52fbe1aaf7fc34cd585739b4f9fc10af1ad8 Mon Sep 17 00:00:00 2001 From: PeterN Date: Sat, 2 Mar 2019 17:08:45 +0000 Subject: Codechange: Sort and filter sign names directly rather than through string system. (#7304) This provides a notable performance benefit in the Sign List window when there are many signs. --- src/signs_gui.cpp | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'src/signs_gui.cpp') diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 15adef089..56af6e665 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -41,11 +41,11 @@ struct SignList { */ typedef GUIList GUISignList; - static const Sign *last_sign; GUISignList signs; StringFilter string_filter; ///< The match string to be used when the GUIList is (re)-sorted. static bool match_case; ///< Should case sensitive matching be used? + static char default_name[64]; ///< Default sign name, used if Sign::name is NULL. /** * Creates a SignList with filtering disabled by default. @@ -74,19 +74,17 @@ struct SignList { /** Sort signs by their name */ static int CDECL SignNameSorter(const Sign * const *a, const Sign * const *b) { - static char buf_cache[64]; - char buf[64]; + /* Signs are very very rarely using the default text, but there can also be + * a lot of them. Therefore a worthwhile performance gain can be made by + * directly comparing Sign::name instead of going through the string + * system for each comparison. */ + const char *a_name = (*a)->name; + const char *b_name = (*b)->name; - SetDParam(0, (*a)->index); - GetString(buf, STR_SIGN_NAME, lastof(buf)); + if (a_name == NULL) a_name = SignList::default_name; + if (b_name == NULL) b_name = SignList::default_name; - if (*b != last_sign) { - last_sign = *b; - SetDParam(0, (*b)->index); - GetString(buf_cache, STR_SIGN_NAME, lastof(buf_cache)); - } - - int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting). + int r = strnatcmp(a_name, b_name); // Sort by name (natural sorting). return r != 0 ? r : ((*a)->index - (*b)->index); } @@ -94,21 +92,18 @@ struct SignList { void SortSignsList() { if (!this->signs.Sort(&SignNameSorter)) return; - - /* Reset the name sorter sort cache */ - this->last_sign = NULL; } /** Filter sign list by sign name */ static bool CDECL SignNameFilter(const Sign * const *a, StringFilter &filter) { - /* Get sign string */ - char buf1[MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH]; - SetDParam(0, (*a)->index); - GetString(buf1, STR_SIGN_NAME, lastof(buf1)); + /* Same performance benefit as above for sorting. */ + const char *a_name = (*a)->name; + + if (a_name == NULL) a_name = SignList::default_name; filter.ResetState(); - filter.AddLine(buf1); + filter.AddLine(a_name); return filter.GetState(); } @@ -138,8 +133,8 @@ struct SignList { } }; -const Sign *SignList::last_sign = NULL; bool SignList::match_case = false; +char SignList::default_name[64]; /** Enum referring to the Hotkeys in the sign list window */ enum SignListHotkeys { @@ -171,6 +166,15 @@ struct SignListWindow : Window, SignList { this->BuildSortSignList(); } + virtual void OnInit() + { + /* Default sign name, used if Sign::name is NULL. */ + GetString(SignList::default_name, STR_DEFAULT_SIGN_NAME, lastof(SignList::default_name)); + this->signs.ForceResort(); + this->SortSignsList(); + this->SetDirty(); + } + /** * This function sets the filter string of the sign list. The contents of * the edit widget is not updated by this function. Depending on if the @@ -188,7 +192,7 @@ struct SignListWindow : Window, SignList { virtual void OnPaint() { - if (this->signs.NeedRebuild()) this->BuildSortSignList(); + if (!this->IsShaded() && this->signs.NeedRebuild()) this->BuildSortSignList(); this->DrawWidgets(); } -- cgit v1.2.3-70-g09d2