diff options
author | Max Kellermann <max@musicpd.org> | 2018-08-02 13:54:36 +0200 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2018-08-02 13:54:36 +0200 |
commit | d929d0c26f7bd654d17dd5c2cdff9fa60c26374b (patch) | |
tree | 0f626ffb79f62b8f441036b5550afc709b9d5312 /src | |
parent | 90201e997085f04f5ac28333d2fbc70fbd6809f0 (diff) |
song/Filter: move each class into a separate source
Diffstat (limited to 'src')
-rw-r--r-- | src/db/plugins/ProxyDatabasePlugin.cxx | 3 | ||||
-rw-r--r-- | src/db/plugins/upnp/UpnpDatabasePlugin.cxx | 3 | ||||
-rw-r--r-- | src/song/AndSongFilter.cxx | 63 | ||||
-rw-r--r-- | src/song/AndSongFilter.hxx | 55 | ||||
-rw-r--r-- | src/song/BaseSongFilter.cxx | 35 | ||||
-rw-r--r-- | src/song/BaseSongFilter.hxx | 48 | ||||
-rw-r--r-- | src/song/Filter.cxx | 156 | ||||
-rw-r--r-- | src/song/Filter.hxx | 193 | ||||
-rw-r--r-- | src/song/ISongFilter.hxx | 48 | ||||
-rw-r--r-- | src/song/ModifiedSinceSongFilter.cxx | 35 | ||||
-rw-r--r-- | src/song/ModifiedSinceSongFilter.hxx | 42 | ||||
-rw-r--r-- | src/song/StringFilter.cxx | 39 | ||||
-rw-r--r-- | src/song/StringFilter.hxx | 60 | ||||
-rw-r--r-- | src/song/TagSongFilter.cxx | 82 | ||||
-rw-r--r-- | src/song/TagSongFilter.hxx | 75 | ||||
-rw-r--r-- | src/song/UriSongFilter.cxx | 34 | ||||
-rw-r--r-- | src/song/UriSongFilter.hxx | 57 |
17 files changed, 683 insertions, 345 deletions
diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx index 7aeb08b4a..1a21f32c0 100644 --- a/src/db/plugins/ProxyDatabasePlugin.cxx +++ b/src/db/plugins/ProxyDatabasePlugin.cxx @@ -29,6 +29,9 @@ #include "song/LightSong.hxx" #include "db/Stats.hxx" #include "song/Filter.hxx" +#include "song/UriSongFilter.hxx" +#include "song/BaseSongFilter.hxx" +#include "song/TagSongFilter.hxx" #include "Compiler.h" #include "config/Block.hxx" #include "tag/Builder.hxx" diff --git a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx index a901a9675..b6ed6fdc5 100644 --- a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx +++ b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx @@ -30,6 +30,8 @@ #include "db/DatabaseError.hxx" #include "db/LightDirectory.hxx" #include "song/LightSong.hxx" +#include "song/Filter.hxx" +#include "song/TagSongFilter.hxx" #include "db/Stats.hxx" #include "config/Block.hxx" #include "tag/Builder.hxx" @@ -37,7 +39,6 @@ #include "tag/Mask.hxx" #include "fs/Traits.hxx" #include "Log.hxx" -#include "song/Filter.hxx" #include "util/SplitString.hxx" #include <string> diff --git a/src/song/AndSongFilter.cxx b/src/song/AndSongFilter.cxx new file mode 100644 index 000000000..f0b9f86df --- /dev/null +++ b/src/song/AndSongFilter.cxx @@ -0,0 +1,63 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "AndSongFilter.hxx" + +ISongFilterPtr +AndSongFilter::Clone() const noexcept +{ + auto result = std::make_unique<AndSongFilter>(); + + for (const auto &i : items) + result->items.emplace_back(i->Clone()); + + return result; +} + +std::string +AndSongFilter::ToExpression() const noexcept +{ + auto i = items.begin(); + const auto end = items.end(); + + if (std::next(i) == end) + return (*i)->ToExpression(); + + std::string e("("); + e += (*i)->ToExpression(); + + for (++i; i != end; ++i) { + e += " AND "; + e += (*i)->ToExpression(); + } + + e.push_back(')'); + return e; +} + +bool +AndSongFilter::Match(const LightSong &song) const noexcept +{ + for (const auto &i : items) + if (!i->Match(song)) + return false; + + return true; +} diff --git a/src/song/AndSongFilter.hxx b/src/song/AndSongFilter.hxx new file mode 100644 index 000000000..5c49a98c1 --- /dev/null +++ b/src/song/AndSongFilter.hxx @@ -0,0 +1,55 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_AND_SONG_FILTER_HXX +#define MPD_AND_SONG_FILTER_HXX + +#include "ISongFilter.hxx" +#include "Compiler.h" + +#include <list> + +/** + * Combine multiple #ISongFilter instances with logical "and". + */ +class AndSongFilter final : public ISongFilter { + std::list<ISongFilterPtr> items; + +public: + const auto &GetItems() const noexcept { + return items; + } + + template<typename I> + void AddItem(I &&_item) { + items.emplace_back(std::forward<I>(_item)); + } + + gcc_pure + bool IsEmpty() const noexcept { + return items.empty(); + } + + /* virtual methods from ISongFilter */ + ISongFilterPtr Clone() const noexcept override; + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; +}; + +#endif diff --git a/src/song/BaseSongFilter.cxx b/src/song/BaseSongFilter.cxx new file mode 100644 index 000000000..b30527478 --- /dev/null +++ b/src/song/BaseSongFilter.cxx @@ -0,0 +1,35 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "BaseSongFilter.hxx" +#include "LightSong.hxx" +#include "util/UriUtil.hxx" + +std::string +BaseSongFilter::ToExpression() const noexcept +{ + return "(base \"" + value + "\")"; +} + +bool +BaseSongFilter::Match(const LightSong &song) const noexcept +{ + return uri_is_child_or_same(value.c_str(), song.GetURI().c_str()); +} diff --git a/src/song/BaseSongFilter.hxx b/src/song/BaseSongFilter.hxx new file mode 100644 index 000000000..d5a049bf2 --- /dev/null +++ b/src/song/BaseSongFilter.hxx @@ -0,0 +1,48 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_BASE_SONG_FILTER_HXX +#define MPD_BASE_SONG_FILTER_HXX + +#include "ISongFilter.hxx" +#include "Compiler.h" + +class BaseSongFilter final : public ISongFilter { + std::string value; + +public: + BaseSongFilter(const BaseSongFilter &) = default; + + template<typename V> + explicit BaseSongFilter(V &&_value) + :value(std::forward<V>(_value)) {} + + const char *GetValue() const noexcept { + return value.c_str(); + } + + ISongFilterPtr Clone() const noexcept override { + return std::make_unique<BaseSongFilter>(*this); + } + + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; +}; + +#endif diff --git a/src/song/Filter.cxx b/src/song/Filter.cxx index 6259cefae..2f1e1180c 100644 --- a/src/song/Filter.cxx +++ b/src/song/Filter.cxx @@ -19,6 +19,10 @@ #include "config.h" #include "Filter.hxx" +#include "UriSongFilter.hxx" +#include "BaseSongFilter.hxx" +#include "TagSongFilter.hxx" +#include "ModifiedSinceSongFilter.hxx" #include "LightSong.hxx" #include "tag/ParseName.hxx" #include "tag/Tag.hxx" @@ -75,158 +79,6 @@ locate_parse_type(const char *str) noexcept return tag_name_parse_i(str); } -bool -StringFilter::Match(const char *s) const noexcept -{ -#if !CLANG_CHECK_VERSION(3,6) - /* disabled on clang due to -Wtautological-pointer-compare */ - assert(s != nullptr); -#endif - - if (fold_case) { - return fold_case.IsIn(s); - } else { - return StringIsEqual(s, value.c_str()); - } -} - -std::string -UriSongFilter::ToExpression() const noexcept -{ - return std::string("(" LOCATE_TAG_FILE_KEY " ") + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")"; -} - -bool -UriSongFilter::Match(const LightSong &song) const noexcept -{ - return filter.Match(song.GetURI().c_str()) != negated; -} - -std::string -BaseSongFilter::ToExpression() const noexcept -{ - return "(base \"" + value + "\")"; -} - -bool -BaseSongFilter::Match(const LightSong &song) const noexcept -{ - return uri_is_child_or_same(value.c_str(), song.GetURI().c_str()); -} - -std::string -TagSongFilter::ToExpression() const noexcept -{ - const char *name = type == TAG_NUM_OF_ITEM_TYPES - ? LOCATE_TAG_ANY_KEY - : tag_item_names[type]; - - return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")"; -} - -bool -TagSongFilter::MatchNN(const TagItem &item) const noexcept -{ - return (type == TAG_NUM_OF_ITEM_TYPES || item.type == type) && - filter.Match(item.value); -} - -bool -TagSongFilter::MatchNN(const Tag &tag) const noexcept -{ - bool visited_types[TAG_NUM_OF_ITEM_TYPES]; - std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false); - - for (const auto &i : tag) { - visited_types[i.type] = true; - - if (MatchNN(i)) - return true; - } - - if (type < TAG_NUM_OF_ITEM_TYPES && !visited_types[type]) { - /* If the search critieron was not visited during the - sweep through the song's tag, it means this field - is absent from the tag or empty. Thus, if the - searched string is also empty - then it's a match as well and we should return - true. */ - if (filter.empty()) - return true; - - if (type == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) { - /* if we're looking for "album artist", but - only "artist" exists, use that */ - for (const auto &item : tag) - if (item.type == TAG_ARTIST && - filter.Match(item.value)) - return true; - } - } - - return false; -} - -bool -TagSongFilter::Match(const LightSong &song) const noexcept -{ - return MatchNN(song.tag) != negated; -} - -std::string -ModifiedSinceSongFilter::ToExpression() const noexcept -{ - return std::string("(modified-since \"") + FormatISO8601(value).c_str() + "\")"; -} - -bool -ModifiedSinceSongFilter::Match(const LightSong &song) const noexcept -{ - return song.mtime >= value; -} - -ISongFilterPtr -AndSongFilter::Clone() const noexcept -{ - auto result = std::make_unique<AndSongFilter>(); - - for (const auto &i : items) - result->items.emplace_back(i->Clone()); - - return result; -} - -std::string -AndSongFilter::ToExpression() const noexcept -{ - auto i = items.begin(); - const auto end = items.end(); - - if (std::next(i) == end) - return (*i)->ToExpression(); - - std::string e("("); - e += (*i)->ToExpression(); - - for (++i; i != end; ++i) { - e += " AND "; - e += (*i)->ToExpression(); - } - - e.push_back(')'); - return e; -} - -bool -AndSongFilter::Match(const LightSong &song) const noexcept -{ - for (const auto &i : items) - if (!i->Match(song)) - return false; - - return true; -} - SongFilter::SongFilter(TagType tag, const char *value, bool fold_case) { and_filter.AddItem(std::make_unique<TagSongFilter>(tag, value, diff --git a/src/song/Filter.hxx b/src/song/Filter.hxx index b627e4b38..e22d96986 100644 --- a/src/song/Filter.hxx +++ b/src/song/Filter.hxx @@ -20,13 +20,10 @@ #ifndef MPD_SONG_FILTER_HXX #define MPD_SONG_FILTER_HXX -#include "lib/icu/Compare.hxx" +#include "AndSongFilter.hxx" #include "Compiler.h" -#include <memory> #include <string> -#include <list> -#include <chrono> #include <stdint.h> @@ -37,195 +34,7 @@ template<typename T> struct ConstBuffer; enum TagType : uint8_t; -struct Tag; -struct TagItem; struct LightSong; -class ISongFilter; -using ISongFilterPtr = std::unique_ptr<ISongFilter>; - -class ISongFilter { -public: - virtual ~ISongFilter() noexcept {} - - virtual ISongFilterPtr Clone() const noexcept = 0; - - /** - * Convert this object into an "expression". This is - * only useful for debugging. - */ - virtual std::string ToExpression() const noexcept = 0; - - gcc_pure - virtual bool Match(const LightSong &song) const noexcept = 0; -}; - -class StringFilter { - std::string value; - - /** - * This value is only set if case folding is enabled. - */ - IcuCompare fold_case; - -public: - template<typename V> - StringFilter(V &&_value, bool _fold_case) - :value(std::forward<V>(_value)), - fold_case(_fold_case - ? IcuCompare(value.c_str()) - : IcuCompare()) {} - - bool empty() const noexcept { - return value.empty(); - } - - const auto &GetValue() const noexcept { - return value; - } - - bool GetFoldCase() const noexcept { - return fold_case; - } - - gcc_pure - bool Match(const char *s) const noexcept; -}; - -class UriSongFilter final : public ISongFilter { - StringFilter filter; - - bool negated; - -public: - template<typename V> - UriSongFilter(V &&_value, bool fold_case, bool _negated) - :filter(std::forward<V>(_value), fold_case), - negated(_negated) {} - - const auto &GetValue() const noexcept { - return filter.GetValue(); - } - - bool GetFoldCase() const { - return filter.GetFoldCase(); - } - - bool IsNegated() const noexcept { - return negated; - } - - ISongFilterPtr Clone() const noexcept override { - return std::make_unique<UriSongFilter>(*this); - } - - std::string ToExpression() const noexcept override; - bool Match(const LightSong &song) const noexcept override; -}; - -class BaseSongFilter final : public ISongFilter { - std::string value; - -public: - BaseSongFilter(const BaseSongFilter &) = default; - - template<typename V> - explicit BaseSongFilter(V &&_value) - :value(std::forward<V>(_value)) {} - - const char *GetValue() const noexcept { - return value.c_str(); - } - - ISongFilterPtr Clone() const noexcept override { - return std::make_unique<BaseSongFilter>(*this); - } - - std::string ToExpression() const noexcept override; - bool Match(const LightSong &song) const noexcept override; -}; - -class TagSongFilter final : public ISongFilter { - TagType type; - - bool negated; - - StringFilter filter; - -public: - template<typename V> - TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated) - :type(_type), negated(_negated), - filter(std::forward<V>(_value), fold_case) {} - - TagType GetTagType() const { - return type; - } - - const auto &GetValue() const noexcept { - return filter.GetValue(); - } - - bool GetFoldCase() const { - return filter.GetFoldCase(); - } - - bool IsNegated() const noexcept { - return negated; - } - - ISongFilterPtr Clone() const noexcept override { - return std::make_unique<TagSongFilter>(*this); - } - - std::string ToExpression() const noexcept override; - bool Match(const LightSong &song) const noexcept override; - -private: - bool MatchNN(const Tag &tag) const noexcept; - bool MatchNN(const TagItem &tag) const noexcept; -}; - -class ModifiedSinceSongFilter final : public ISongFilter { - std::chrono::system_clock::time_point value; - -public: - explicit ModifiedSinceSongFilter(std::chrono::system_clock::time_point _value) noexcept - :value(_value) {} - - ISongFilterPtr Clone() const noexcept override { - return std::make_unique<ModifiedSinceSongFilter>(*this); - } - - std::string ToExpression() const noexcept override; - bool Match(const LightSong &song) const noexcept override; -}; - -/** - * Combine multiple #ISongFilter instances with logical "and". - */ -class AndSongFilter final : public ISongFilter { - std::list<ISongFilterPtr> items; - -public: - const auto &GetItems() const noexcept { - return items; - } - - template<typename I> - void AddItem(I &&_item) { - items.emplace_back(std::forward<I>(_item)); - } - - gcc_pure - bool IsEmpty() const noexcept { - return items.empty(); - } - - /* virtual methods from ISongFilter */ - ISongFilterPtr Clone() const noexcept override; - std::string ToExpression() const noexcept override; - bool Match(const LightSong &song) const noexcept override; -}; class SongFilter { AndSongFilter and_filter; diff --git a/src/song/ISongFilter.hxx b/src/song/ISongFilter.hxx new file mode 100644 index 000000000..22e746148 --- /dev/null +++ b/src/song/ISongFilter.hxx @@ -0,0 +1,48 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_I_SONG_FILTER_HXX +#define MPD_I_SONG_FILTER_HXX + +#include "Compiler.h" + +#include <memory> +#include <string> + +struct LightSong; +class ISongFilter; +using ISongFilterPtr = std::unique_ptr<ISongFilter>; + +class ISongFilter { +public: + virtual ~ISongFilter() noexcept {} + + virtual ISongFilterPtr Clone() const noexcept = 0; + + /** + * Convert this object into an "expression". This is + * only useful for debugging. + */ + virtual std::string ToExpression() const noexcept = 0; + + gcc_pure + virtual bool Match(const LightSong &song) const noexcept = 0; +}; + +#endif diff --git a/src/song/ModifiedSinceSongFilter.cxx b/src/song/ModifiedSinceSongFilter.cxx new file mode 100644 index 000000000..d429e1150 --- /dev/null +++ b/src/song/ModifiedSinceSongFilter.cxx @@ -0,0 +1,35 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "ModifiedSinceSongFilter.hxx" +#include "LightSong.hxx" +#include "util/TimeISO8601.hxx" + +std::string +ModifiedSinceSongFilter::ToExpression() const noexcept +{ + return std::string("(modified-since \"") + FormatISO8601(value).c_str() + "\")"; +} + +bool +ModifiedSinceSongFilter::Match(const LightSong &song) const noexcept +{ + return song.mtime >= value; +} diff --git a/src/song/ModifiedSinceSongFilter.hxx b/src/song/ModifiedSinceSongFilter.hxx new file mode 100644 index 000000000..f0bbe6c12 --- /dev/null +++ b/src/song/ModifiedSinceSongFilter.hxx @@ -0,0 +1,42 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_MODIFIED_SINCE_SONG_FILTER_HXX +#define MPD_MODIFIED_SINCE_SONG_FILTER_HXX + +#include "ISongFilter.hxx" + +#include <chrono> + +class ModifiedSinceSongFilter final : public ISongFilter { + std::chrono::system_clock::time_point value; + +public: + explicit ModifiedSinceSongFilter(std::chrono::system_clock::time_point _value) noexcept + :value(_value) {} + + ISongFilterPtr Clone() const noexcept override { + return std::make_unique<ModifiedSinceSongFilter>(*this); + } + + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; +}; + +#endif diff --git a/src/song/StringFilter.cxx b/src/song/StringFilter.cxx new file mode 100644 index 000000000..5ef9b33f7 --- /dev/null +++ b/src/song/StringFilter.cxx @@ -0,0 +1,39 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "StringFilter.hxx" +#include "util/StringCompare.hxx" + +#include <assert.h> + +bool +StringFilter::Match(const char *s) const noexcept +{ +#if !CLANG_CHECK_VERSION(3,6) + /* disabled on clang due to -Wtautological-pointer-compare */ + assert(s != nullptr); +#endif + + if (fold_case) { + return fold_case.IsIn(s); + } else { + return StringIsEqual(s, value.c_str()); + } +} diff --git a/src/song/StringFilter.hxx b/src/song/StringFilter.hxx new file mode 100644 index 000000000..da809f3a3 --- /dev/null +++ b/src/song/StringFilter.hxx @@ -0,0 +1,60 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_STRING_FILTER_HXX +#define MPD_STRING_FILTER_HXX + +#include "lib/icu/Compare.hxx" +#include "Compiler.h" + +#include <string> + +class StringFilter { + std::string value; + + /** + * This value is only set if case folding is enabled. + */ + IcuCompare fold_case; + +public: + template<typename V> + StringFilter(V &&_value, bool _fold_case) + :value(std::forward<V>(_value)), + fold_case(_fold_case + ? IcuCompare(value.c_str()) + : IcuCompare()) {} + + bool empty() const noexcept { + return value.empty(); + } + + const auto &GetValue() const noexcept { + return value; + } + + bool GetFoldCase() const noexcept { + return fold_case; + } + + gcc_pure + bool Match(const char *s) const noexcept; +}; + +#endif diff --git a/src/song/TagSongFilter.cxx b/src/song/TagSongFilter.cxx new file mode 100644 index 000000000..35939ee8a --- /dev/null +++ b/src/song/TagSongFilter.cxx @@ -0,0 +1,82 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "TagSongFilter.hxx" +#include "LightSong.hxx" +#include "tag/Tag.hxx" + +std::string +TagSongFilter::ToExpression() const noexcept +{ + const char *name = type == TAG_NUM_OF_ITEM_TYPES + ? "any" + : tag_item_names[type]; + + return std::string("(") + name + " " + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")"; +} + +bool +TagSongFilter::MatchNN(const TagItem &item) const noexcept +{ + return (type == TAG_NUM_OF_ITEM_TYPES || item.type == type) && + filter.Match(item.value); +} + +bool +TagSongFilter::MatchNN(const Tag &tag) const noexcept +{ + bool visited_types[TAG_NUM_OF_ITEM_TYPES]; + std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false); + + for (const auto &i : tag) { + visited_types[i.type] = true; + + if (MatchNN(i)) + return true; + } + + if (type < TAG_NUM_OF_ITEM_TYPES && !visited_types[type]) { + /* If the search critieron was not visited during the + sweep through the song's tag, it means this field + is absent from the tag or empty. Thus, if the + searched string is also empty + then it's a match as well and we should return + true. */ + if (filter.empty()) + return true; + + if (type == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) { + /* if we're looking for "album artist", but + only "artist" exists, use that */ + for (const auto &item : tag) + if (item.type == TAG_ARTIST && + filter.Match(item.value)) + return true; + } + } + + return false; +} + +bool +TagSongFilter::Match(const LightSong &song) const noexcept +{ + return MatchNN(song.tag) != negated; +} diff --git a/src/song/TagSongFilter.hxx b/src/song/TagSongFilter.hxx new file mode 100644 index 000000000..527339a3a --- /dev/null +++ b/src/song/TagSongFilter.hxx @@ -0,0 +1,75 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TAG_SONG_FILTER_HXX +#define MPD_TAG_SONG_FILTER_HXX + +#include "ISongFilter.hxx" +#include "StringFilter.hxx" + +#include <stdint.h> + +template<typename T> struct ConstBuffer; +enum TagType : uint8_t; +struct Tag; +struct TagItem; +struct LightSong; + +class TagSongFilter final : public ISongFilter { + TagType type; + + bool negated; + + StringFilter filter; + +public: + template<typename V> + TagSongFilter(TagType _type, V &&_value, bool fold_case, bool _negated) + :type(_type), negated(_negated), + filter(std::forward<V>(_value), fold_case) {} + + TagType GetTagType() const { + return type; + } + + const auto &GetValue() const noexcept { + return filter.GetValue(); + } + + bool GetFoldCase() const { + return filter.GetFoldCase(); + } + + bool IsNegated() const noexcept { + return negated; + } + + ISongFilterPtr Clone() const noexcept override { + return std::make_unique<TagSongFilter>(*this); + } + + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; + +private: + bool MatchNN(const Tag &tag) const noexcept; + bool MatchNN(const TagItem &tag) const noexcept; +}; + +#endif diff --git a/src/song/UriSongFilter.cxx b/src/song/UriSongFilter.cxx new file mode 100644 index 000000000..4445d8c08 --- /dev/null +++ b/src/song/UriSongFilter.cxx @@ -0,0 +1,34 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "UriSongFilter.hxx" +#include "LightSong.hxx" + +std::string +UriSongFilter::ToExpression() const noexcept +{ + return std::string("(file ") + (negated ? "!=" : "==") + " \"" + filter.GetValue() + "\")"; +} + +bool +UriSongFilter::Match(const LightSong &song) const noexcept +{ + return filter.Match(song.GetURI().c_str()) != negated; +} diff --git a/src/song/UriSongFilter.hxx b/src/song/UriSongFilter.hxx new file mode 100644 index 000000000..4c16ee19f --- /dev/null +++ b/src/song/UriSongFilter.hxx @@ -0,0 +1,57 @@ +/* + * Copyright 2003-2018 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_URI_SONG_FILTER_HXX +#define MPD_URI_SONG_FILTER_HXX + +#include "ISongFilter.hxx" +#include "StringFilter.hxx" + +class UriSongFilter final : public ISongFilter { + StringFilter filter; + + bool negated; + +public: + template<typename V> + UriSongFilter(V &&_value, bool fold_case, bool _negated) + :filter(std::forward<V>(_value), fold_case), + negated(_negated) {} + + const auto &GetValue() const noexcept { + return filter.GetValue(); + } + + bool GetFoldCase() const { + return filter.GetFoldCase(); + } + + bool IsNegated() const noexcept { + return negated; + } + + ISongFilterPtr Clone() const noexcept override { + return std::make_unique<UriSongFilter>(*this); + } + + std::string ToExpression() const noexcept override; + bool Match(const LightSong &song) const noexcept override; +}; + +#endif |