From 41a7203c28d2cc7550f1bb05f767950d388326cd Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 12 Jul 2014 17:22:39 +0200 Subject: [PATCH] Tag: add class const_iterator and methods begin(), end() Enables using range-based "for". --- src/SongFilter.cxx | 10 ++-- src/TagPrint.cxx | 6 +-- src/TagSave.cxx | 5 +- src/db/Count.cxx | 4 +- src/db/DatabasePrint.cxx | 4 +- src/db/Helpers.cxx | 4 +- src/encoder/plugins/VorbisEncoderPlugin.cxx | 3 +- src/output/plugins/RoarOutputPlugin.cxx | 12 +++-- src/output/plugins/ShoutOutputPlugin.cxx | 8 +-- src/tag/Set.cxx | 17 +++---- src/tag/Tag.cxx | 6 +-- src/tag/Tag.hxx | 54 +++++++++++++++++++++ test/test_translate_song.cxx | 3 +- 13 files changed, 89 insertions(+), 47 deletions(-) diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index 0640ae19e..7a8e6fd12 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -92,10 +92,10 @@ SongFilter::Item::Match(const Tag &_tag) const bool visited_types[TAG_NUM_OF_ITEM_TYPES]; std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false); - for (unsigned i = 0; i < _tag.num_items; i++) { - visited_types[_tag.items[i]->type] = true; + for (const auto &i : _tag) { + visited_types[i.type] = true; - if (Match(*_tag.items[i])) + if (Match(i)) return true; } @@ -112,12 +112,10 @@ SongFilter::Item::Match(const Tag &_tag) const if (tag == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) { /* if we're looking for "album artist", but only "artist" exists, use that */ - for (unsigned i = 0; i < _tag.num_items; i++) { - const TagItem &item = *_tag.items[i]; + for (const auto &item : _tag) if (item.type == TAG_ARTIST && StringMatch(item.value)) return true; - } } } diff --git a/src/TagPrint.cxx b/src/TagPrint.cxx index 228b5fd90..297bf45e3 100644 --- a/src/TagPrint.cxx +++ b/src/TagPrint.cxx @@ -47,9 +47,7 @@ void tag_print(Client &client, const Tag &tag) if (tag.time >= 0) client_printf(client, SONG_TIME "%i\n", tag.time); - for (unsigned i = 0; i < tag.num_items; i++) { + for (const auto &i : tag) client_printf(client, "%s: %s\n", - tag_item_names[tag.items[i]->type], - tag.items[i]->value); - } + tag_item_names[i.type], i.value); } diff --git a/src/TagSave.cxx b/src/TagSave.cxx index 3a291e115..7666287af 100644 --- a/src/TagSave.cxx +++ b/src/TagSave.cxx @@ -32,8 +32,7 @@ tag_save(FILE *file, const Tag &tag) if (tag.has_playlist) fprintf(file, "Playlist: yes\n"); - for (unsigned i = 0; i < tag.num_items; i++) + for (const auto &i : tag) fprintf(file, "%s: %s\n", - tag_item_names[tag.items[i]->type], - tag.items[i]->value); + tag_item_names[i.type], i.value); } diff --git a/src/db/Count.cxx b/src/db/Count.cxx index ec3eacd1f..4fd53a73b 100644 --- a/src/db/Count.cxx +++ b/src/db/Count.cxx @@ -73,9 +73,7 @@ static bool CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag) { bool found = false; - for (unsigned i = 0; i < tag.num_items; ++i) { - const TagItem &item = *tag.items[i]; - + for (const auto &item : tag) { if (item.type == group) { auto r = map.insert(std::make_pair(item.value, SearchStats())); diff --git a/src/db/DatabasePrint.cxx b/src/db/DatabasePrint.cxx index f6663311e..498aedf97 100644 --- a/src/db/DatabasePrint.cxx +++ b/src/db/DatabasePrint.cxx @@ -184,12 +184,10 @@ PrintUniqueTag(Client &client, TagType tag_type, assert(value != nullptr); client_printf(client, "%s: %s\n", tag_item_names[tag_type], value); - for (unsigned i = 0, n = tag.num_items; i < n; i++) { - const TagItem &item = *tag.items[i]; + for (const auto &item : tag) if (item.type != tag_type) client_printf(client, "%s: %s\n", tag_item_names[item.type], item.value); - } return true; } diff --git a/src/db/Helpers.cxx b/src/db/Helpers.cxx index b849e73e8..089b2b17d 100644 --- a/src/db/Helpers.cxx +++ b/src/db/Helpers.cxx @@ -43,9 +43,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums, if (tag.time > 0) stats.total_duration += tag.time; - for (unsigned i = 0; i < tag.num_items; ++i) { - const TagItem &item = *tag.items[i]; - + for (const auto &item : tag) { switch (item.type) { case TAG_ARTIST: #if defined(__clang__) || GCC_CHECK_VERSION(4,8) diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx index 7fdb3066f..ecc784a47 100644 --- a/src/encoder/plugins/VorbisEncoderPlugin.cxx +++ b/src/encoder/plugins/VorbisEncoderPlugin.cxx @@ -272,8 +272,7 @@ vorbis_encoder_pre_tag(Encoder *_encoder, gcc_unused Error &error) static void copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag *tag) { - for (unsigned i = 0; i < tag->num_items; i++) { - const TagItem &item = *tag->items[i]; + for (const auto &item : *tag) { char *name = g_ascii_strup(tag_item_names[item.type], -1); vorbis_comment_add_tag(vc, name, item.value); g_free(name); diff --git a/src/output/plugins/RoarOutputPlugin.cxx b/src/output/plugins/RoarOutputPlugin.cxx index ac4dd8a4e..ae6bdf1b1 100644 --- a/src/output/plugins/RoarOutputPlugin.cxx +++ b/src/output/plugins/RoarOutputPlugin.cxx @@ -374,20 +374,22 @@ RoarOutput::SendTag(const Tag &tag) vals[0].key = const_cast("LENGTH"); vals[0].value = timebuf; - for (unsigned i = 0; i < tag.num_items && cnt < 32; i++) - { + for (const auto &item : tag) { + if (cnt >= 32) + break; + bool is_uuid = false; - const char *key = roar_tag_convert(tag.items[i]->type, + const char *key = roar_tag_convert(item.type, &is_uuid); if (key != nullptr) { vals[cnt].key = const_cast(key); if (is_uuid) { snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s", - tag.items[i]->value); + item.value); vals[cnt].value = uuid_buf[cnt]; } else { - vals[cnt].value = tag.items[i]->value; + vals[cnt].value = const_cast(item.value); } cnt++; diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx index a16c8fecd..0341e1cf7 100644 --- a/src/output/plugins/ShoutOutputPlugin.cxx +++ b/src/output/plugins/ShoutOutputPlugin.cxx @@ -470,13 +470,13 @@ shout_tag_to_metadata(const Tag *tag, char *dest, size_t size) artist[0] = 0; title[0] = 0; - for (unsigned i = 0; i < tag->num_items; i++) { - switch (tag->items[i]->type) { + for (const auto &item : *tag) { + switch (item.type) { case TAG_ARTIST: - strncpy(artist, tag->items[i]->value, size); + strncpy(artist, item.value, size); break; case TAG_TITLE: - strncpy(title, tag->items[i]->value, size); + strncpy(title, item.value, size); break; default: diff --git a/src/tag/Set.cxx b/src/tag/Set.cxx index 59f66bf84..47a8423bf 100644 --- a/src/tag/Set.cxx +++ b/src/tag/Set.cxx @@ -30,10 +30,10 @@ 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); + + for (const auto &item : src) { + if (item.type == src_type) { + dest.AddItem(dest_type, item.value); found = true; } } @@ -87,11 +87,10 @@ TagSet::CheckUnique(TagType dest_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); + + for (const auto &item : tag) { + if (item.type == src_type) { + InsertUnique(tag, dest_type, item.value, group_mask); found = true; } } diff --git a/src/tag/Tag.cxx b/src/tag/Tag.cxx index 448f3b26a..1b338ae8d 100644 --- a/src/tag/Tag.cxx +++ b/src/tag/Tag.cxx @@ -118,9 +118,9 @@ Tag::GetValue(TagType type) const { assert(type < TAG_NUM_OF_ITEM_TYPES); - for (unsigned i = 0; i < num_items; i++) - if (items[i]->type == type) - return items[i]->value; + for (const auto &item : *this) + if (item.type == type) + return item.value; return nullptr; } diff --git a/src/tag/Tag.hxx b/src/tag/Tag.hxx index 5d3aaad0c..74221417f 100644 --- a/src/tag/Tag.hxx +++ b/src/tag/Tag.hxx @@ -25,6 +25,7 @@ #include "Compiler.h" #include +#include #include @@ -136,6 +137,59 @@ struct Tag { */ gcc_pure bool HasType(TagType type) const; + + class const_iterator { + friend struct Tag; + const TagItem *const*cursor; + + constexpr const_iterator(const TagItem *const*_cursor) + :cursor(_cursor) {} + + public: + constexpr const TagItem &operator*() const { + return **cursor; + } + + constexpr const TagItem *operator->() const { + return *cursor; + } + + const_iterator &operator++() { + ++cursor; + return *this; + } + + const_iterator operator++(int) { + auto result = cursor++; + return const_iterator{result}; + } + + const_iterator &operator--() { + --cursor; + return *this; + } + + const_iterator operator--(int) { + auto result = cursor--; + return const_iterator{result}; + } + + constexpr bool operator==(const_iterator other) const { + return cursor == other.cursor; + } + + constexpr bool operator!=(const_iterator other) const { + return cursor != other.cursor; + } + }; + + const_iterator begin() const { + return const_iterator{items}; + } + + const_iterator end() const { + return const_iterator{items + num_items}; + } }; /** diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx index bcd3e8646..374fd34a2 100644 --- a/test/test_translate_song.cxx +++ b/test/test_translate_song.cxx @@ -160,8 +160,7 @@ ToString(const Tag &tag) std::string result = buffer; - for (unsigned i = 0, n = tag.num_items; i != n; ++i) { - const TagItem &item = *tag.items[i]; + for (const auto &item : tag) { result.push_back('|'); result.append(tag_item_names[item.type]); result.push_back('=');