aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/tag.c46
-rw-r--r--src/tag.h9
2 files changed, 55 insertions, 0 deletions
diff --git a/src/tag.c b/src/tag.c
index 180dbb86a..343f4d91c 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -318,6 +318,52 @@ struct tag *tag_dup(const struct tag *tag)
return ret;
}
+struct tag *
+tag_merge(const struct tag *base, const struct tag *add)
+{
+ struct tag *ret;
+ unsigned n;
+
+ assert(base != NULL);
+ assert(add != NULL);
+
+ /* allocate new tag object */
+
+ ret = tag_new();
+ ret->time = add->time > 0 ? add->time : base->time;
+ ret->numOfItems = base->numOfItems + add->numOfItems;
+ ret->items = ret->numOfItems > 0 ? g_malloc(items_size(ret)) : NULL;
+
+ g_mutex_lock(tag_pool_lock);
+
+ /* copy all items from "add" */
+
+ for (unsigned i = 0; i < add->numOfItems; ++i)
+ ret->items[i] = tag_pool_dup_item(add->items[i]);
+
+ n = add->numOfItems;
+
+ /* copy additional items from "base" */
+
+ for (unsigned i = 0; i < base->numOfItems; ++i)
+ if (!tag_has_type(add, base->items[i]->type))
+ ret->items[n++] = tag_pool_dup_item(base->items[i]);
+
+ g_mutex_unlock(tag_pool_lock);
+
+ assert(n <= ret->numOfItems);
+
+ if (n < ret->numOfItems) {
+ /* some tags were not copied - shrink ret->items */
+ assert(n > 0);
+
+ ret->numOfItems = n;
+ ret->items = g_realloc(ret->items, items_size(ret));
+ }
+
+ return ret;
+}
+
bool tag_has_type(const struct tag *tag, enum tag_type type)
{
assert(tag != NULL);
diff --git a/src/tag.h b/src/tag.h
index c1c7d7e9a..7c7abf50a 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -90,6 +90,15 @@ static inline void tag_add_item(struct tag *tag, enum tag_type itemType,
struct tag *tag_dup(const struct tag *tag);
/**
+ * Merges the data from two tags. If both tags share data for the
+ * same tag_type, only data from "add" is used.
+ *
+ * @return a newly allocated tag, which must be freed with tag_free()
+ */
+struct tag *
+tag_merge(const struct tag *base, const struct tag *add);
+
+/**
* Returns true if the tag contains no items. This ignores the "time"
* attribute.
*/