summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/strings.h
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/strings.h')
-rw-r--r--crawl-ref/source/strings.h54
1 files changed, 54 insertions, 0 deletions
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<class Enum, class Pred, class NameFunc>
+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<Enum>(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 <typename Z>
string comma_separated_line(Z start, Z end, const string &andc = " and ",
const string &comma = ", ")