diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tag.c | 46 | ||||
-rw-r--r-- | src/tag.h | 9 |
2 files changed, 55 insertions, 0 deletions
@@ -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); @@ -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. */ |