song/StringFilter: add enum Position
Replaces two conflicting bools.
This commit is contained in:
@@ -90,8 +90,12 @@ SongFilter::SongFilter(TagType tag, const char *value, bool fold_case)
|
||||
{
|
||||
/* for compatibility with MPD 0.20 and older, "fold_case" also
|
||||
switches on "substring" */
|
||||
const auto position = fold_case
|
||||
? StringFilter::Position::ANYWHERE
|
||||
: StringFilter::Position::FULL;
|
||||
|
||||
and_filter.AddItem(std::make_unique<TagSongFilter>(tag,
|
||||
StringFilter(value, fold_case, fold_case, false, false)));
|
||||
StringFilter(value, fold_case, position, false)));
|
||||
}
|
||||
|
||||
/* this destructor exists here just so it won't get inlined */
|
||||
@@ -209,25 +213,41 @@ ParseStringFilter(const char *&s, bool fold_case)
|
||||
if (auto after_contains = StringAfterPrefixIgnoreCase(s, "contains ")) {
|
||||
s = StripLeft(after_contains);
|
||||
auto value = ExpectQuoted(s);
|
||||
return {std::move(value), fold_case, true, false, false};
|
||||
return {
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::ANYWHERE,
|
||||
false,
|
||||
};
|
||||
}
|
||||
|
||||
if (auto after_not_contains = StringAfterPrefixIgnoreCase(s, "!contains ")) {
|
||||
s = StripLeft(after_not_contains);
|
||||
auto value = ExpectQuoted(s);
|
||||
return {std::move(value), fold_case, true, false, true};
|
||||
return {
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::ANYWHERE,
|
||||
true,
|
||||
};
|
||||
}
|
||||
|
||||
if (auto after_starts_with = StringAfterPrefixIgnoreCase(s, "starts_with ")) {
|
||||
s = StripLeft(after_starts_with);
|
||||
auto value = ExpectQuoted(s);
|
||||
return {std::move(value), fold_case, false, true, false};
|
||||
return {
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::PREFIX,
|
||||
false,
|
||||
};
|
||||
}
|
||||
|
||||
if (auto after_not_starts_with = StringAfterPrefixIgnoreCase(s, "!starts_with ")) {
|
||||
s = StripLeft(after_not_starts_with);
|
||||
auto value = ExpectQuoted(s);
|
||||
return {std::move(value), fold_case, false, true, true};
|
||||
return {
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::PREFIX,
|
||||
true,
|
||||
};
|
||||
}
|
||||
|
||||
bool negated = false;
|
||||
@@ -237,7 +257,11 @@ ParseStringFilter(const char *&s, bool fold_case)
|
||||
negated = s[0] == '!';
|
||||
s = StripLeft(s + 2);
|
||||
auto value = ExpectQuoted(s);
|
||||
StringFilter f(std::move(value), fold_case, false, false, negated);
|
||||
StringFilter f{
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::FULL,
|
||||
negated,
|
||||
};
|
||||
f.SetRegex(std::make_shared<UniqueRegex>(f.GetValue().c_str(),
|
||||
false, false,
|
||||
fold_case));
|
||||
@@ -253,7 +277,11 @@ ParseStringFilter(const char *&s, bool fold_case)
|
||||
s = StripLeft(s + 2);
|
||||
auto value = ExpectQuoted(s);
|
||||
|
||||
return {std::move(value), fold_case, false, false, negated};
|
||||
return {
|
||||
std::move(value), fold_case,
|
||||
StringFilter::Position::FULL,
|
||||
negated,
|
||||
};
|
||||
}
|
||||
|
||||
ISongFilterPtr
|
||||
@@ -399,11 +427,14 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
|
||||
case LOCATE_TAG_FILE_TYPE:
|
||||
/* for compatibility with MPD 0.20 and older,
|
||||
"fold_case" also switches on "substring" */
|
||||
and_filter.AddItem(std::make_unique<UriSongFilter>(StringFilter(value,
|
||||
fold_case,
|
||||
fold_case,
|
||||
false,
|
||||
false)));
|
||||
and_filter.AddItem(std::make_unique<UriSongFilter>(StringFilter{
|
||||
value,
|
||||
fold_case,
|
||||
fold_case
|
||||
? StringFilter::Position::ANYWHERE
|
||||
: StringFilter::Position::FULL,
|
||||
false,
|
||||
}));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -412,12 +443,14 @@ SongFilter::Parse(const char *tag_string, const char *value, bool fold_case)
|
||||
|
||||
/* for compatibility with MPD 0.20 and older,
|
||||
"fold_case" also switches on "substring" */
|
||||
and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag),
|
||||
StringFilter(value,
|
||||
fold_case,
|
||||
fold_case,
|
||||
false,
|
||||
false)));
|
||||
and_filter.AddItem(std::make_unique<TagSongFilter>(TagType(tag), StringFilter{
|
||||
value,
|
||||
fold_case,
|
||||
fold_case
|
||||
? StringFilter::Position::ANYWHERE
|
||||
: StringFilter::Position::FULL,
|
||||
false,
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -33,17 +33,31 @@ StringFilter::MatchWithoutNegation(const char *s) const noexcept
|
||||
#endif
|
||||
|
||||
if (fold_case) {
|
||||
return substring
|
||||
? fold_case.IsIn(s)
|
||||
: (starts_with
|
||||
? fold_case.StartsWith(s)
|
||||
: fold_case == s);
|
||||
switch (position) {
|
||||
case Position::FULL:
|
||||
break;
|
||||
|
||||
case Position::ANYWHERE:
|
||||
return fold_case.IsIn(s);
|
||||
|
||||
case Position::PREFIX:
|
||||
return fold_case.StartsWith(s);
|
||||
}
|
||||
|
||||
return fold_case == s;
|
||||
} else {
|
||||
return substring
|
||||
? StringFind(s, value.c_str()) != nullptr
|
||||
: (starts_with
|
||||
? StringIsEqual(s, value.c_str(), value.length())
|
||||
: value == s);
|
||||
switch (position) {
|
||||
case Position::FULL:
|
||||
break;
|
||||
|
||||
case Position::ANYWHERE:
|
||||
return StringFind(s, value.c_str()) != nullptr;
|
||||
|
||||
case Position::PREFIX:
|
||||
return StringIsEqual(s, value.c_str(), value.length());
|
||||
}
|
||||
|
||||
return value == s;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -27,10 +27,24 @@
|
||||
#include "lib/pcre/UniqueRegex.hxx"
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class StringFilter {
|
||||
public:
|
||||
enum class Position : uint_least8_t {
|
||||
/** compare the whole haystack */
|
||||
FULL,
|
||||
|
||||
/** find the phrase anywhere in the haystack */
|
||||
ANYWHERE,
|
||||
|
||||
/** check if the haystack starts with the given prefix */
|
||||
PREFIX,
|
||||
};
|
||||
|
||||
private:
|
||||
std::string value;
|
||||
|
||||
/**
|
||||
@@ -42,26 +56,19 @@ class StringFilter {
|
||||
std::shared_ptr<UniqueRegex> regex;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Search for substrings instead of matching the whole string?
|
||||
*/
|
||||
bool substring;
|
||||
|
||||
/**
|
||||
* Search for substrings instead of matching the whole string?
|
||||
*/
|
||||
bool starts_with;
|
||||
Position position;
|
||||
|
||||
bool negated;
|
||||
|
||||
public:
|
||||
template<typename V>
|
||||
StringFilter(V &&_value, bool _fold_case, bool _substring, bool _starts_with, bool _negated)
|
||||
StringFilter(V &&_value, bool _fold_case, Position _position, bool _negated)
|
||||
:value(std::forward<V>(_value)),
|
||||
fold_case(_fold_case
|
||||
? IcuCompare(value)
|
||||
: IcuCompare()),
|
||||
substring(_substring), starts_with(_starts_with), negated(_negated) {}
|
||||
position(_position),
|
||||
negated(_negated) {}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return value.empty();
|
||||
@@ -102,11 +109,16 @@ public:
|
||||
if (IsRegex())
|
||||
return negated ? "!~" : "=~";
|
||||
|
||||
if (substring)
|
||||
switch (position) {
|
||||
case Position::FULL:
|
||||
break;
|
||||
|
||||
case Position::ANYWHERE:
|
||||
return negated ? "!contains" : "contains";
|
||||
|
||||
if (starts_with)
|
||||
case Position::PREFIX:
|
||||
return negated ? "!starts_with" : "starts_with";
|
||||
}
|
||||
|
||||
return negated ? "!=" : "==";
|
||||
}
|
||||
|
Reference in New Issue
Block a user