From 25930a6b86d330b8b402670286e55eb4cbff0a6c Mon Sep 17 00:00:00 2001 From: Nicholas Feinberg Date: Thu, 14 Aug 2014 21:01:06 -0700 Subject: Refactor. --- crawl-ref/source/strings.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'crawl-ref/source/strings.h') diff --git a/crawl-ref/source/strings.h b/crawl-ref/source/strings.h index ea6d51462f..fad53580f7 100644 --- a/crawl-ref/source/strings.h +++ b/crawl-ref/source/strings.h @@ -48,6 +48,60 @@ string &trim_string(string &str); string &trim_string_right(string &str); string trimmed_string(string s); +/** + * Find the enumerator e between begin and end that satisfies pred(e) and + * whose name, as given by namefunc(e), has the earliest occurrence of the + * substring spec. + * + * @param spec The substring to search for. + * @param begin The beginning of the enumerator range to search in. + * @param end One past the end of the enum range to search in. + * @param pred A function from Enum to bool. Enumerators that do not + * satisfy the predicate are ignored. + * @param namefunc A function from Enum to string or const char * giving + * the name of the enumerator. + * @return The enumerator that satisfies pred and whose name contains the + * spec substring beginning at the earliest position. If no such + * enumerator exists, returns end. If there are multiple strings + * containing the spec as a prefix, returns the shortest such string + * (so exact matches are preferred); otherwise ties are broken in + * an unspecified manner. + */ +template +Enum find_earliest_match(string spec, Enum begin, Enum end, + Pred pred, NameFunc namefunc) +{ + Enum selected = end; + const size_t speclen = spec.length(); + size_t bestpos = string::npos; + size_t bestlen = string::npos; + for (size_t i = begin; i < (size_t) end; ++i) + { + const Enum curr = static_cast(i); + + if (!pred(curr)) + continue; + + const string name = lowercase_string(namefunc(curr)); + const size_t pos = name.find(spec); + const size_t len = name.length(); + + if (pos < bestpos || pos == 0 && len < bestlen) + { + // Exit early if we found an exact match. + if (pos == 0 && len == speclen) + return curr; + + // npos is never less than bestpos, so the spec was found. + bestpos = pos; + if (pos == 0) + bestlen = len; + selected = curr; + } + } + return selected; +} + template string comma_separated_line(Z start, Z end, const string &andc = " and ", const string &comma = ", ") -- cgit v1.2.3-54-g00ecf