From 0b3e1c4706849be107954ad1b8d6bf82ef3dcc28 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 5 Sep 2013 18:22:39 +0200 Subject: [PATCH] TagBuilder: new class for constructing Tag objects Obsoletes Tag::BeginAdd() and the complicated "bulk add" code. --- Makefile.am | 1 + src/tag/TagBuilder.cxx | 108 ++++++++++++++++++++++++++++++++++++ src/tag/TagBuilder.hxx | 121 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 src/tag/TagBuilder.cxx create mode 100644 src/tag/TagBuilder.hxx diff --git a/Makefile.am b/Makefile.am index b775b9d40..37f44822d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -424,6 +424,7 @@ TAG_LIBS = \ libtag_a_SOURCES =\ src/tag/TagType.h \ src/tag/Tag.cxx src/tag/Tag.hxx \ + src/tag/TagBuilder.cxx src/tag/TagBuilder.hxx \ src/tag/TagItem.hxx \ src/tag/TagHandler.cxx src/tag/TagHandler.hxx \ src/tag/TagSettings.c src/tag/TagSettings.h \ diff --git a/src/tag/TagBuilder.cxx b/src/tag/TagBuilder.cxx new file mode 100644 index 000000000..d1babdadb --- /dev/null +++ b/src/tag/TagBuilder.cxx @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "TagBuilder.hxx" +#include "TagSettings.h" +#include "TagPool.hxx" +#include "TagString.hxx" +#include "Tag.hxx" + +#include + +#include +#include + +void +TagBuilder::Clear() +{ + time = -1; + has_playlist = false; + + tag_pool_lock.lock(); + for (auto i : items) + tag_pool_put_item(i); + tag_pool_lock.unlock(); + + items.clear(); +} + +Tag * +TagBuilder::Commit() +{ + Tag *tag = new Tag(); + tag->time = time; + tag->has_playlist = has_playlist; + + /* move all TagItem pointers to the new Tag object without + touching the TagPool reference counters; the + vector::clear() call is important to detach them from this + object */ + const unsigned n_items = items.size(); + tag->num_items = n_items; + tag->items = g_new(TagItem *, n_items); + std::copy_n(items.begin(), n_items, tag->items); + items.clear(); + + /* now ensure that this object is fresh (will not delete any + items because we've already moved them out) */ + Clear(); + + return tag; +} + +inline void +TagBuilder::AddItemInternal(tag_type type, const char *value, size_t length) +{ + assert(value != nullptr); + assert(length > 0); + + char *p = FixTagString(value, length); + if (p != nullptr) { + value = p; + length = strlen(value); + } + + tag_pool_lock.lock(); + auto i = tag_pool_get_item(type, value, length); + tag_pool_lock.unlock(); + + g_free(p); + + items.push_back(i); +} + +void +TagBuilder::AddItem(tag_type type, const char *value, size_t length) +{ + assert(value != nullptr); + + if (length == 0 || ignore_tag_items[type]) + return; + + AddItemInternal(type, value, length); +} + +void +TagBuilder::AddItem(tag_type type, const char *value) +{ + assert(value != nullptr); + + AddItem(type, value, strlen(value)); +} diff --git a/src/tag/TagBuilder.hxx b/src/tag/TagBuilder.hxx new file mode 100644 index 000000000..c882f4d53 --- /dev/null +++ b/src/tag/TagBuilder.hxx @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TAG_BUILDER_HXX +#define MPD_TAG_BUILDER_HXX + +#include "TagType.h" +#include "gcc.h" + +#include + +#include + +struct TagItem; +struct Tag; + +/** + * A class that constructs #Tag objects. + */ +class TagBuilder { + /** + * The duration of the song (in seconds). A value of zero + * means that the length is unknown. If the duration is + * really between zero and one second, you should round up to + * 1. + */ + int time; + + /** + * Does this file have an embedded playlist (e.g. embedded CUE + * sheet)? + */ + bool has_playlist; + + /** an array of tag items */ + std::vector items; + +public: + /** + * Create an empty tag. + */ + TagBuilder() + :time(-1), has_playlist(false) {} + + ~TagBuilder() { + Clear(); + } + + TagBuilder(const TagBuilder &other) = delete; + TagBuilder &operator=(const TagBuilder &other) = delete; + + /** + * Returns true if the object contains any information. + */ + gcc_pure + bool IsDefined() const { + return time >= 0 || has_playlist || !items.empty(); + } + + void Clear(); + + /** + * Create a new #Tag instance from data in this object. The + * returned object is owned by the caller. This object is + * empty afterwards. + */ + Tag *Commit(); + + void SetTime(int _time) { + time = _time; + } + + void SetHasPlaylist(bool _has_playlist) { + has_playlist = _has_playlist; + } + + void Reserve(unsigned n) { + items.reserve(n); + } + + /** + * Appends a new tag item. + * + * @param type the type of the new tag item + * @param value the value of the tag item (not null-terminated) + * @param len the length of #value + */ + gcc_nonnull_all + void AddItem(tag_type type, const char *value, size_t length); + + /** + * Appends a new tag item. + * + * @param type the type of the new tag item + * @param value the value of the tag item (null-terminated) + */ + gcc_nonnull_all + void AddItem(tag_type type, const char *value); + +private: + gcc_nonnull_all + void AddItemInternal(tag_type type, const char *value, size_t length); +}; + +#endif