diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/db/Helpers.cxx | 89 | ||||
-rw-r--r-- | src/tag/Set.cxx | 116 | ||||
-rw-r--r-- | src/tag/Set.hxx | 15 |
4 files changed, 132 insertions, 90 deletions
diff --git a/Makefile.am b/Makefile.am index 616e74e4f..bd69d3063 100644 --- a/Makefile.am +++ b/Makefile.am @@ -714,7 +714,7 @@ libtag_a_SOURCES =\ src/tag/TagString.cxx src/tag/TagString.hxx \ src/tag/TagPool.cxx src/tag/TagPool.hxx \ src/tag/TagTable.cxx src/tag/TagTable.hxx \ - src/tag/Set.hxx \ + src/tag/Set.cxx src/tag/Set.hxx \ src/tag/ApeLoader.cxx src/tag/ApeLoader.hxx \ src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \ src/tag/ApeTag.cxx src/tag/ApeTag.hxx diff --git a/src/db/Helpers.cxx b/src/db/Helpers.cxx index 25ea50a52..5b1e1d6c6 100644 --- a/src/db/Helpers.cxx +++ b/src/db/Helpers.cxx @@ -40,101 +40,14 @@ struct StringLess { typedef std::set<const char *, StringLess> StringSet; -/** - * Copy all tag items of the specified type. - */ -static bool -CopyTagItem(TagBuilder &dest, TagType dest_type, - const Tag &src, TagType src_type) -{ - bool found = false; - const unsigned n = src.num_items; - for (unsigned i = 0; i < n; ++i) { - if (src.items[i]->type == src_type) { - dest.AddItem(dest_type, src.items[i]->value); - found = true; - } - } - - return found; -} - -/** - * Copy all tag items of the specified type. Fall back to "Artist" if - * there is no "AlbumArtist". - */ -static void -CopyTagItem(TagBuilder &dest, const Tag &src, TagType type) -{ - if (!CopyTagItem(dest, type, src, type) && - type == TAG_ALBUM_ARTIST) - CopyTagItem(dest, type, src, TAG_ARTIST); -} - -/** - * Copy all tag items of the types in the mask. - */ -static void -CopyTagMask(TagBuilder &dest, const Tag &src, uint32_t mask) -{ - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) - if ((mask & (1u << i)) != 0) - CopyTagItem(dest, src, TagType(i)); -} - -static void -InsertUniqueTag(TagSet &set, const Tag &src, TagType type, const char *value, - uint32_t group_mask) -{ - TagBuilder builder; - if (value == nullptr) - builder.AddEmptyItem(type); - else - builder.AddItem(type, value); - CopyTagMask(builder, src, group_mask); -#if defined(__clang__) || GCC_CHECK_VERSION(4,8) - set.emplace(builder.Commit()); -#else - set.insert(builder.Commit()); -#endif -} - -static bool -CheckUniqueTag(TagSet &set, TagType dest_type, - const Tag &tag, TagType src_type, - uint32_t group_mask) -{ - bool found = false; - for (unsigned i = 0; i < tag.num_items; ++i) { - if (tag.items[i]->type == src_type) { - InsertUniqueTag(set, tag, dest_type, - tag.items[i]->value, - group_mask); - found = true; - } - } - - return found; -} - static bool CollectTags(TagSet &set, TagType tag_type, uint32_t group_mask, const LightSong &song) { - static_assert(sizeof(group_mask) * 8 >= TAG_NUM_OF_ITEM_TYPES, - "Mask is too small"); - - assert((group_mask & (1u << unsigned(tag_type))) == 0); - assert(song.tag != nullptr); const Tag &tag = *song.tag; - if (!CheckUniqueTag(set, tag_type, tag, tag_type, group_mask) && - (tag_type != TAG_ALBUM_ARTIST || - /* fall back to "Artist" if no "AlbumArtist" was found */ - !CheckUniqueTag(set, tag_type, tag, TAG_ARTIST, group_mask))) - InsertUniqueTag(set, tag, tag_type, nullptr, group_mask); - + set.InsertUnique(tag, tag_type, group_mask); return true; } diff --git a/src/tag/Set.cxx b/src/tag/Set.cxx new file mode 100644 index 000000000..59f66bf84 --- /dev/null +++ b/src/tag/Set.cxx @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2003-2014 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 "Set.hxx" +#include "TagBuilder.hxx" + +#include <assert.h> + +/** + * Copy all tag items of the specified type. + */ +static bool +CopyTagItem(TagBuilder &dest, TagType dest_type, + const Tag &src, TagType src_type) +{ + bool found = false; + const unsigned n = src.num_items; + for (unsigned i = 0; i < n; ++i) { + if (src.items[i]->type == src_type) { + dest.AddItem(dest_type, src.items[i]->value); + found = true; + } + } + + return found; +} + +/** + * Copy all tag items of the specified type. Fall back to "Artist" if + * there is no "AlbumArtist". + */ +static void +CopyTagItem(TagBuilder &dest, const Tag &src, TagType type) +{ + if (!CopyTagItem(dest, type, src, type) && + type == TAG_ALBUM_ARTIST) + CopyTagItem(dest, type, src, TAG_ARTIST); +} + +/** + * Copy all tag items of the types in the mask. + */ +static void +CopyTagMask(TagBuilder &dest, const Tag &src, uint32_t mask) +{ + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) + if ((mask & (1u << i)) != 0) + CopyTagItem(dest, src, TagType(i)); +} + +void +TagSet::InsertUnique(const Tag &src, TagType type, const char *value, + uint32_t group_mask) +{ + TagBuilder builder; + if (value == nullptr) + builder.AddEmptyItem(type); + else + builder.AddItem(type, value); + CopyTagMask(builder, src, group_mask); +#if defined(__clang__) || GCC_CHECK_VERSION(4,8) + emplace(builder.Commit()); +#else + insert(builder.Commit()); +#endif +} + +bool +TagSet::CheckUnique(TagType dest_type, + const Tag &tag, TagType src_type, + uint32_t group_mask) +{ + bool found = false; + for (unsigned i = 0; i < tag.num_items; ++i) { + if (tag.items[i]->type == src_type) { + InsertUnique(tag, dest_type, + tag.items[i]->value, + group_mask); + found = true; + } + } + + return found; +} + +void +TagSet::InsertUnique(const Tag &tag, + TagType type, uint32_t group_mask) +{ + static_assert(sizeof(group_mask) * 8 >= TAG_NUM_OF_ITEM_TYPES, + "Mask is too small"); + + assert((group_mask & (1u << unsigned(type))) == 0); + + if (!CheckUnique(type, tag, type, group_mask) && + (type != TAG_ALBUM_ARTIST || + /* fall back to "Artist" if no "AlbumArtist" was found */ + !CheckUnique(type, tag, TAG_ARTIST, group_mask))) + InsertUnique(tag, type, nullptr, group_mask); +} diff --git a/src/tag/Set.hxx b/src/tag/Set.hxx index 3b9654807..b5acfcb36 100644 --- a/src/tag/Set.hxx +++ b/src/tag/Set.hxx @@ -26,6 +26,7 @@ #include <set> #include <string.h> +#include <stdint.h> /** * Helper class for #TagSet which compares two #Tag objects. @@ -55,6 +56,18 @@ struct TagLess { /** * A set of #Tag objects. */ -typedef std::set<Tag, TagLess> TagSet; +class TagSet : public std::set<Tag, TagLess> { +public: + void InsertUnique(const Tag &tag, + TagType type, uint32_t group_mask); + +private: + void InsertUnique(const Tag &src, TagType type, const char *value, + uint32_t group_mask); + + bool CheckUnique(TagType dest_type, + const Tag &tag, TagType src_type, + uint32_t group_mask); +}; #endif |