Skip to content

Commit

Permalink
Codechange: Sort and filter sign names directly rather than through s…
Browse files Browse the repository at this point in the history
…tring system. (#7304)

This provides a notable performance benefit in the Sign List window when there are many signs.
  • Loading branch information
PeterN committed Mar 2, 2019
1 parent c3bc7d6 commit cbaf52f
Showing 1 changed file with 26 additions and 22 deletions.
48 changes: 26 additions & 22 deletions src/signs_gui.cpp
Expand Up @@ -41,11 +41,11 @@ struct SignList {
*/
typedef GUIList<const Sign *, StringFilter &> 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.
Expand Down Expand Up @@ -74,41 +74,36 @@ 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);
}

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();
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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();
}

Expand Down

0 comments on commit cbaf52f

Please sign in to comment.