Commit 41a7203c authored by Max Kellermann's avatar Max Kellermann

Tag: add class const_iterator and methods begin(), end()

Enables using range-based "for".
parent 543a58bb
...@@ -92,10 +92,10 @@ SongFilter::Item::Match(const Tag &_tag) const ...@@ -92,10 +92,10 @@ SongFilter::Item::Match(const Tag &_tag) const
bool visited_types[TAG_NUM_OF_ITEM_TYPES]; bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false); std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
for (unsigned i = 0; i < _tag.num_items; i++) { for (const auto &i : _tag) {
visited_types[_tag.items[i]->type] = true; visited_types[i.type] = true;
if (Match(*_tag.items[i])) if (Match(i))
return true; return true;
} }
...@@ -112,12 +112,10 @@ SongFilter::Item::Match(const Tag &_tag) const ...@@ -112,12 +112,10 @@ SongFilter::Item::Match(const Tag &_tag) const
if (tag == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) { if (tag == TAG_ALBUM_ARTIST && visited_types[TAG_ARTIST]) {
/* if we're looking for "album artist", but /* if we're looking for "album artist", but
only "artist" exists, use that */ only "artist" exists, use that */
for (unsigned i = 0; i < _tag.num_items; i++) { for (const auto &item : _tag)
const TagItem &item = *_tag.items[i];
if (item.type == TAG_ARTIST && if (item.type == TAG_ARTIST &&
StringMatch(item.value)) StringMatch(item.value))
return true; return true;
}
} }
} }
......
...@@ -47,9 +47,7 @@ void tag_print(Client &client, const Tag &tag) ...@@ -47,9 +47,7 @@ void tag_print(Client &client, const Tag &tag)
if (tag.time >= 0) if (tag.time >= 0)
client_printf(client, SONG_TIME "%i\n", tag.time); 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", client_printf(client, "%s: %s\n",
tag_item_names[tag.items[i]->type], tag_item_names[i.type], i.value);
tag.items[i]->value);
}
} }
...@@ -32,8 +32,7 @@ tag_save(FILE *file, const Tag &tag) ...@@ -32,8 +32,7 @@ tag_save(FILE *file, const Tag &tag)
if (tag.has_playlist) if (tag.has_playlist)
fprintf(file, "Playlist: yes\n"); fprintf(file, "Playlist: yes\n");
for (unsigned i = 0; i < tag.num_items; i++) for (const auto &i : tag)
fprintf(file, "%s: %s\n", fprintf(file, "%s: %s\n",
tag_item_names[tag.items[i]->type], tag_item_names[i.type], i.value);
tag.items[i]->value);
} }
...@@ -73,9 +73,7 @@ static bool ...@@ -73,9 +73,7 @@ static bool
CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag) CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
{ {
bool found = false; bool found = false;
for (unsigned i = 0; i < tag.num_items; ++i) { for (const auto &item : tag) {
const TagItem &item = *tag.items[i];
if (item.type == group) { if (item.type == group) {
auto r = map.insert(std::make_pair(item.value, auto r = map.insert(std::make_pair(item.value,
SearchStats())); SearchStats()));
......
...@@ -184,12 +184,10 @@ PrintUniqueTag(Client &client, TagType tag_type, ...@@ -184,12 +184,10 @@ PrintUniqueTag(Client &client, TagType tag_type,
assert(value != nullptr); assert(value != nullptr);
client_printf(client, "%s: %s\n", tag_item_names[tag_type], value); client_printf(client, "%s: %s\n", tag_item_names[tag_type], value);
for (unsigned i = 0, n = tag.num_items; i < n; i++) { for (const auto &item : tag)
const TagItem &item = *tag.items[i];
if (item.type != tag_type) if (item.type != tag_type)
client_printf(client, "%s: %s\n", client_printf(client, "%s: %s\n",
tag_item_names[item.type], item.value); tag_item_names[item.type], item.value);
}
return true; return true;
} }
......
...@@ -43,9 +43,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums, ...@@ -43,9 +43,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
if (tag.time > 0) if (tag.time > 0)
stats.total_duration += tag.time; stats.total_duration += tag.time;
for (unsigned i = 0; i < tag.num_items; ++i) { for (const auto &item : tag) {
const TagItem &item = *tag.items[i];
switch (item.type) { switch (item.type) {
case TAG_ARTIST: case TAG_ARTIST:
#if defined(__clang__) || GCC_CHECK_VERSION(4,8) #if defined(__clang__) || GCC_CHECK_VERSION(4,8)
......
...@@ -272,8 +272,7 @@ vorbis_encoder_pre_tag(Encoder *_encoder, gcc_unused Error &error) ...@@ -272,8 +272,7 @@ vorbis_encoder_pre_tag(Encoder *_encoder, gcc_unused Error &error)
static void static void
copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag *tag) copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag *tag)
{ {
for (unsigned i = 0; i < tag->num_items; i++) { for (const auto &item : *tag) {
const TagItem &item = *tag->items[i];
char *name = g_ascii_strup(tag_item_names[item.type], -1); char *name = g_ascii_strup(tag_item_names[item.type], -1);
vorbis_comment_add_tag(vc, name, item.value); vorbis_comment_add_tag(vc, name, item.value);
g_free(name); g_free(name);
......
...@@ -374,20 +374,22 @@ RoarOutput::SendTag(const Tag &tag) ...@@ -374,20 +374,22 @@ RoarOutput::SendTag(const Tag &tag)
vals[0].key = const_cast<char *>("LENGTH"); vals[0].key = const_cast<char *>("LENGTH");
vals[0].value = timebuf; 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; bool is_uuid = false;
const char *key = roar_tag_convert(tag.items[i]->type, const char *key = roar_tag_convert(item.type,
&is_uuid); &is_uuid);
if (key != nullptr) { if (key != nullptr) {
vals[cnt].key = const_cast<char *>(key); vals[cnt].key = const_cast<char *>(key);
if (is_uuid) { if (is_uuid) {
snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s", snprintf(uuid_buf[cnt], sizeof(uuid_buf[0]), "{UUID}%s",
tag.items[i]->value); item.value);
vals[cnt].value = uuid_buf[cnt]; vals[cnt].value = uuid_buf[cnt];
} else { } else {
vals[cnt].value = tag.items[i]->value; vals[cnt].value = const_cast<char *>(item.value);
} }
cnt++; cnt++;
......
...@@ -470,13 +470,13 @@ shout_tag_to_metadata(const Tag *tag, char *dest, size_t size) ...@@ -470,13 +470,13 @@ shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
artist[0] = 0; artist[0] = 0;
title[0] = 0; title[0] = 0;
for (unsigned i = 0; i < tag->num_items; i++) { for (const auto &item : *tag) {
switch (tag->items[i]->type) { switch (item.type) {
case TAG_ARTIST: case TAG_ARTIST:
strncpy(artist, tag->items[i]->value, size); strncpy(artist, item.value, size);
break; break;
case TAG_TITLE: case TAG_TITLE:
strncpy(title, tag->items[i]->value, size); strncpy(title, item.value, size);
break; break;
default: default:
......
...@@ -30,10 +30,10 @@ CopyTagItem(TagBuilder &dest, TagType dest_type, ...@@ -30,10 +30,10 @@ CopyTagItem(TagBuilder &dest, TagType dest_type,
const Tag &src, TagType src_type) const Tag &src, TagType src_type)
{ {
bool found = false; bool found = false;
const unsigned n = src.num_items;
for (unsigned i = 0; i < n; ++i) { for (const auto &item : src) {
if (src.items[i]->type == src_type) { if (item.type == src_type) {
dest.AddItem(dest_type, src.items[i]->value); dest.AddItem(dest_type, item.value);
found = true; found = true;
} }
} }
...@@ -87,11 +87,10 @@ TagSet::CheckUnique(TagType dest_type, ...@@ -87,11 +87,10 @@ TagSet::CheckUnique(TagType dest_type,
uint32_t group_mask) uint32_t group_mask)
{ {
bool found = false; bool found = false;
for (unsigned i = 0; i < tag.num_items; ++i) {
if (tag.items[i]->type == src_type) { for (const auto &item : tag) {
InsertUnique(tag, dest_type, if (item.type == src_type) {
tag.items[i]->value, InsertUnique(tag, dest_type, item.value, group_mask);
group_mask);
found = true; found = true;
} }
} }
......
...@@ -118,9 +118,9 @@ Tag::GetValue(TagType type) const ...@@ -118,9 +118,9 @@ Tag::GetValue(TagType type) const
{ {
assert(type < TAG_NUM_OF_ITEM_TYPES); assert(type < TAG_NUM_OF_ITEM_TYPES);
for (unsigned i = 0; i < num_items; i++) for (const auto &item : *this)
if (items[i]->type == type) if (item.type == type)
return items[i]->value; return item.value;
return nullptr; return nullptr;
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "Compiler.h" #include "Compiler.h"
#include <algorithm> #include <algorithm>
#include <iterator>
#include <stddef.h> #include <stddef.h>
...@@ -136,6 +137,59 @@ struct Tag { ...@@ -136,6 +137,59 @@ struct Tag {
*/ */
gcc_pure gcc_pure
bool HasType(TagType type) const; 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};
}
}; };
/** /**
......
...@@ -160,8 +160,7 @@ ToString(const Tag &tag) ...@@ -160,8 +160,7 @@ ToString(const Tag &tag)
std::string result = buffer; std::string result = buffer;
for (unsigned i = 0, n = tag.num_items; i != n; ++i) { for (const auto &item : tag) {
const TagItem &item = *tag.items[i];
result.push_back('|'); result.push_back('|');
result.append(tag_item_names[item.type]); result.append(tag_item_names[item.type]);
result.push_back('='); result.push_back('=');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment