aboutsummaryrefslogtreecommitdiffstats
path: root/src/tag/TagBuilder.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/tag/TagBuilder.cxx180
1 files changed, 165 insertions, 15 deletions
diff --git a/src/tag/TagBuilder.cxx b/src/tag/TagBuilder.cxx
index 083b43d69..0882f9561 100644
--- a/src/tag/TagBuilder.cxx
+++ b/src/tag/TagBuilder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * 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
@@ -23,24 +23,94 @@
#include "TagPool.hxx"
#include "TagString.hxx"
#include "Tag.hxx"
+#include "util/WritableBuffer.hxx"
-#include <glib.h>
+#include <array>
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
-void
-TagBuilder::Clear()
+TagBuilder::TagBuilder(const Tag &other)
+ :duration(other.duration), has_playlist(other.has_playlist)
{
- time = -1;
- has_playlist = false;
+ items.reserve(other.num_items);
tag_pool_lock.lock();
+ for (unsigned i = 0, n = other.num_items; i != n; ++i)
+ items.push_back(tag_pool_dup_item(other.items[i]));
+ tag_pool_lock.unlock();
+}
+
+TagBuilder::TagBuilder(Tag &&other)
+ :duration(other.duration), has_playlist(other.has_playlist)
+{
+ /* move all TagItem pointers from the Tag object; we don't
+ need to contact the tag pool, because all we do is move
+ references */
+ items.reserve(other.num_items);
+ std::copy_n(other.items, other.num_items, std::back_inserter(items));
+
+ /* discard the pointers from the Tag object */
+ other.num_items = 0;
+ delete[] other.items;
+ other.items = nullptr;
+}
+
+TagBuilder &
+TagBuilder::operator=(const TagBuilder &other)
+{
+ /* copy all attributes */
+ duration = other.duration;
+ has_playlist = other.has_playlist;
+ items = other.items;
+
+ /* increment the tag pool refcounters */
+ tag_pool_lock.lock();
for (auto i : items)
- tag_pool_put_item(i);
+ tag_pool_dup_item(i);
tag_pool_lock.unlock();
+ return *this;
+}
+
+TagBuilder &
+TagBuilder::operator=(TagBuilder &&other)
+{
+ duration = other.duration;
+ has_playlist = other.has_playlist;
+ items = std::move(other.items);
+
+ return *this;
+}
+
+TagBuilder &
+TagBuilder::operator=(Tag &&other)
+{
+ duration = other.duration;
+ has_playlist = other.has_playlist;
+
+ /* move all TagItem pointers from the Tag object; we don't
+ need to contact the tag pool, because all we do is move
+ references */
items.clear();
+ items.reserve(other.num_items);
+ std::copy_n(other.items, other.num_items, std::back_inserter(items));
+
+ /* discard the pointers from the Tag object */
+ other.num_items = 0;
+ delete[] other.items;
+ other.items = nullptr;
+
+ return *this;
+}
+
+void
+TagBuilder::Clear()
+{
+ duration = SignedSongTime::Negative();
+ has_playlist = false;
+ RemoveAll();
}
void
@@ -48,7 +118,7 @@ TagBuilder::Commit(Tag &tag)
{
tag.Clear();
- tag.time = time;
+ tag.duration = duration;
tag.has_playlist = has_playlist;
/* move all TagItem pointers to the new Tag object without
@@ -57,7 +127,7 @@ TagBuilder::Commit(Tag &tag)
object */
const unsigned n_items = items.size();
tag.num_items = n_items;
- tag.items = g_new(TagItem *, n_items);
+ tag.items = new TagItem *[n_items];
std::copy_n(items.begin(), n_items, tag.items);
items.clear();
@@ -66,14 +136,58 @@ TagBuilder::Commit(Tag &tag)
Clear();
}
-Tag *
+Tag
TagBuilder::Commit()
{
+ Tag tag;
+ Commit(tag);
+ return tag;
+}
+
+Tag *
+TagBuilder::CommitNew()
+{
Tag *tag = new Tag();
Commit(*tag);
return tag;
}
+bool
+TagBuilder::HasType(TagType type) const
+{
+ for (auto i : items)
+ if (i->type == type)
+ return true;
+
+ return false;
+}
+
+void
+TagBuilder::Complement(const Tag &other)
+{
+ if (duration.IsNegative())
+ duration = other.duration;
+
+ has_playlist |= other.has_playlist;
+
+ /* build a table of tag types that were already present in
+ this object, which will not be copied from #other */
+ std::array<bool, TAG_NUM_OF_ITEM_TYPES> present;
+ present.fill(false);
+ for (const TagItem *i : items)
+ present[i->type] = true;
+
+ items.reserve(items.size() + other.num_items);
+
+ tag_pool_lock.lock();
+ for (unsigned i = 0, n = other.num_items; i != n; ++i) {
+ TagItem *item = other.items[i];
+ if (!present[item->type])
+ items.push_back(tag_pool_dup_item(item));
+ }
+ tag_pool_lock.unlock();
+}
+
inline void
TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
{
@@ -83,17 +197,17 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
#endif
assert(length > 0);
- char *p = FixTagString(value, length);
- if (p != nullptr) {
- value = p;
- length = strlen(value);
+ auto f = FixTagString(value, length);
+ if (!f.IsNull()) {
+ value = f.data;
+ length = f.size;
}
tag_pool_lock.lock();
auto i = tag_pool_get_item(type, value, length);
tag_pool_lock.unlock();
- g_free(p);
+ free(f.data);
items.push_back(i);
}
@@ -122,3 +236,39 @@ TagBuilder::AddItem(TagType type, const char *value)
AddItem(type, value, strlen(value));
}
+
+void
+TagBuilder::AddEmptyItem(TagType type)
+{
+ tag_pool_lock.lock();
+ auto i = tag_pool_get_item(type, "", 0);
+ tag_pool_lock.unlock();
+
+ items.push_back(i);
+}
+
+void
+TagBuilder::RemoveAll()
+{
+ tag_pool_lock.lock();
+ for (auto i : items)
+ tag_pool_put_item(i);
+ tag_pool_lock.unlock();
+
+ items.clear();
+}
+
+void
+TagBuilder::RemoveType(TagType type)
+{
+ const auto begin = items.begin(), end = items.end();
+
+ items.erase(std::remove_if(begin, end,
+ [type](TagItem *item) {
+ if (item->type != type)
+ return false;
+ tag_pool_put_item(item);
+ return true;
+ }),
+ end);
+}