mirror of https://github.com/OpenTTD/OpenTTD
Codechange: rework StringFilter to not need MallocT anymore
parent
ff6ae5b87b
commit
8b7460759a
|
@ -76,7 +76,9 @@ inline size_t ttd_strnlen(const char *str, size_t maxlen)
|
||||||
bool IsValidChar(char32_t key, CharSetFilter afilter);
|
bool IsValidChar(char32_t key, CharSetFilter afilter);
|
||||||
|
|
||||||
size_t Utf8Decode(char32_t *c, const char *s);
|
size_t Utf8Decode(char32_t *c, const char *s);
|
||||||
inline size_t Utf8Decode(char32_t *c, std::string::iterator &s) { return Utf8Decode(c, &*s); }
|
/* std::string_view::iterator might be char *, in which case we do not want this templated variant to be taken. */
|
||||||
|
template <typename T> requires (!std::is_same_v<T, char *> && (std::is_same_v<std::string_view::iterator, T> || std::is_same_v<std::string::iterator, T>))
|
||||||
|
inline size_t Utf8Decode(char32_t *c, T &s) { return Utf8Decode(c, &*s); }
|
||||||
size_t Utf8Encode(char *buf, char32_t c);
|
size_t Utf8Encode(char *buf, char32_t c);
|
||||||
size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, char32_t c);
|
size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, char32_t c);
|
||||||
size_t Utf8Encode(std::back_insert_iterator<std::string> &buf, char32_t c);
|
size_t Utf8Encode(std::back_insert_iterator<std::string> &buf, char32_t c);
|
||||||
|
|
|
@ -25,34 +25,34 @@ static const char32_t STATE_QUOTE2 = '"';
|
||||||
* Set the term to filter on.
|
* Set the term to filter on.
|
||||||
* @param str Filter term
|
* @param str Filter term
|
||||||
*/
|
*/
|
||||||
void StringFilter::SetFilterTerm(const char *str)
|
void StringFilter::SetFilterTerm(std::string_view str)
|
||||||
{
|
{
|
||||||
this->word_index.clear();
|
this->word_index.clear();
|
||||||
this->word_index.shrink_to_fit();
|
this->word_index.shrink_to_fit();
|
||||||
this->word_matches = 0;
|
this->word_matches = 0;
|
||||||
free(this->filter_buffer);
|
|
||||||
|
|
||||||
assert(str != nullptr);
|
|
||||||
|
|
||||||
char *dest = MallocT<char>(strlen(str) + 1);
|
|
||||||
this->filter_buffer = dest;
|
|
||||||
|
|
||||||
char32_t state = STATE_WHITESPACE;
|
char32_t state = STATE_WHITESPACE;
|
||||||
const char *pos = str;
|
auto pos = str.begin();
|
||||||
WordState *word = nullptr;
|
auto word_begin = str.end();
|
||||||
size_t len;
|
auto word_end = pos;
|
||||||
for (;; pos += len) {
|
|
||||||
|
/* Helper to prevent duplicating code. */
|
||||||
|
auto add_word = [&] () {
|
||||||
|
if (word_begin != str.end()) {
|
||||||
|
this->word_index.emplace_back(std::string(word_begin, word_end + 1), false);
|
||||||
|
word_begin = str.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t len; pos < str.end(); pos += len) {
|
||||||
char32_t c;
|
char32_t c;
|
||||||
len = Utf8Decode(&c, pos);
|
len = Utf8Decode(&c, pos);
|
||||||
|
|
||||||
if (c == 0 || (state == STATE_WORD && IsWhitespace(c))) {
|
if (state == STATE_WORD && IsWhitespace(c)) {
|
||||||
/* Finish word */
|
/* Finish word */
|
||||||
if (word != nullptr) {
|
add_word();
|
||||||
*(dest++) = '\0';
|
|
||||||
word = nullptr;
|
|
||||||
}
|
|
||||||
state = STATE_WHITESPACE;
|
state = STATE_WHITESPACE;
|
||||||
if (c != 0) continue; else break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == STATE_WHITESPACE) {
|
if (state == STATE_WHITESPACE) {
|
||||||
|
@ -74,22 +74,14 @@ void StringFilter::SetFilterTerm(const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add to word */
|
/* Add to word */
|
||||||
if (word == nullptr) {
|
if (word_begin == str.end()) {
|
||||||
word = &this->word_index.emplace_back(WordState{ dest, false });
|
word_begin = pos;
|
||||||
}
|
}
|
||||||
|
word_end = pos;
|
||||||
memcpy(dest, pos, len);
|
|
||||||
dest += len;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/* Add the last word of the string. */
|
||||||
* Set the term to filter on.
|
add_word();
|
||||||
* @param str Filter term
|
|
||||||
*/
|
|
||||||
void StringFilter::SetFilterTerm(const std::string &str)
|
|
||||||
{
|
|
||||||
this->SetFilterTerm(str.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,12 +111,12 @@ void StringFilter::AddLine(const char *str)
|
||||||
for (WordState &ws : this->word_index) {
|
for (WordState &ws : this->word_index) {
|
||||||
if (!ws.match) {
|
if (!ws.match) {
|
||||||
if (this->locale_aware) {
|
if (this->locale_aware) {
|
||||||
if (match_case ? StrNaturalContains(str, ws.start) : StrNaturalContainsIgnoreCase(str, ws.start)) {
|
if (match_case ? StrNaturalContains(str, ws.word) : StrNaturalContainsIgnoreCase(str, ws.word)) {
|
||||||
ws.match = true;
|
ws.match = true;
|
||||||
this->word_matches++;
|
this->word_matches++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((match_case ? strstr(str, ws.start) : strcasestr(str, ws.start)) != nullptr) {
|
if ((match_case ? strstr(str, ws.word.c_str()) : strcasestr(str, ws.word.c_str())) != nullptr) {
|
||||||
ws.match = true;
|
ws.match = true;
|
||||||
this->word_matches++;
|
this->word_matches++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,12 @@ struct StringFilter {
|
||||||
private:
|
private:
|
||||||
/** State of a single filter word */
|
/** State of a single filter word */
|
||||||
struct WordState {
|
struct WordState {
|
||||||
const char *start; ///< Word to filter for.
|
std::string word; ///< Word to filter for.
|
||||||
bool match; ///< Already matched?
|
bool match; ///< Already matched?
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *filter_buffer; ///< Parsed filter string. Words separated by 0.
|
|
||||||
std::vector<WordState> word_index; ///< Word index and filter state.
|
std::vector<WordState> word_index; ///< Word index and filter state.
|
||||||
uint word_matches; ///< Summary of filter state: Number of words matched.
|
uint word_matches = 0; ///< Summary of filter state: Number of words matched.
|
||||||
|
|
||||||
const bool *case_sensitive; ///< Match case-sensitively (usually a static variable).
|
const bool *case_sensitive; ///< Match case-sensitively (usually a static variable).
|
||||||
bool locale_aware; ///< Match words using the current locale.
|
bool locale_aware; ///< Match words using the current locale.
|
||||||
|
@ -47,11 +46,9 @@ public:
|
||||||
* Constructor for filter.
|
* Constructor for filter.
|
||||||
* @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. nullptr means always case-insensitive.
|
* @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. nullptr means always case-insensitive.
|
||||||
*/
|
*/
|
||||||
StringFilter(const bool *case_sensitive = nullptr, bool locale_aware = true) : filter_buffer(nullptr), word_matches(0), case_sensitive(case_sensitive), locale_aware(locale_aware) {}
|
StringFilter(const bool *case_sensitive = nullptr, bool locale_aware = true) : case_sensitive(case_sensitive), locale_aware(locale_aware) {}
|
||||||
~StringFilter() { free(this->filter_buffer); }
|
|
||||||
|
|
||||||
void SetFilterTerm(const char *str);
|
void SetFilterTerm(std::string_view str);
|
||||||
void SetFilterTerm(const std::string &str);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether any filter words were entered.
|
* Check whether any filter words were entered.
|
||||||
|
|
Loading…
Reference in New Issue