DetachedSong: fork of struct Song

From now on, struct Song will be used by the database only, and
DetachedSong will be used by everybody else.  DetachedSong is easier
to use, but Song has lower overhead.
This commit is contained in:
Max Kellermann
2014-01-07 21:39:47 +01:00
parent 43847f2244
commit 322b061632
70 changed files with 811 additions and 779 deletions

View File

@@ -43,7 +43,7 @@ struct AsxParser {
* The list of songs (in reverse order because that's faster
* while adding).
*/
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
/**
* The current position in the XML file.
@@ -60,10 +60,9 @@ struct AsxParser {
TagType tag_type;
/**
* The current song. It is allocated after the "location"
* element.
* The current song URI. It is set by the "ref" element.
*/
Song *song;
std::string location;
TagBuilder tag_builder;
@@ -96,7 +95,7 @@ asx_start_element(gcc_unused GMarkupParseContext *context,
case AsxParser::ROOT:
if (StringEqualsCaseASCII(element_name, "entry")) {
parser->state = AsxParser::ENTRY;
parser->song = Song::NewRemote("asx:");
parser->location.clear();
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
}
@@ -107,17 +106,8 @@ asx_start_element(gcc_unused GMarkupParseContext *context,
const gchar *href = get_attribute(attribute_names,
attribute_values,
"href");
if (href != nullptr) {
/* create new song object; we cannot
replace the existing song's URI,
because that attribute is
immutable */
Song *song = Song::NewRemote(href);
if (parser->song != nullptr)
parser->song->Free();
parser->song = song;
}
if (href != nullptr)
parser->location = href;
} else if (StringEqualsCaseASCII(element_name, "author"))
/* is that correct? or should it be COMPOSER
or PERFORMER? */
@@ -142,12 +132,9 @@ asx_end_element(gcc_unused GMarkupParseContext *context,
case AsxParser::ENTRY:
if (StringEqualsCaseASCII(element_name, "entry")) {
if (strcmp(parser->song->uri, "asx:") != 0) {
assert(parser->song->tag == nullptr);
parser->song->tag = parser->tag_builder.CommitNew();
parser->songs.emplace_front(parser->song);
} else
parser->song->Free();
if (!parser->location.empty())
parser->songs.emplace_front(std::move(parser->location),
parser->tag_builder.Commit());
parser->state = AsxParser::ROOT;
} else
@@ -186,15 +173,6 @@ static const GMarkupParser asx_parser = {
nullptr,
};
static void
asx_parser_destroy(gpointer data)
{
AsxParser *parser = (AsxParser *)data;
if (parser->state >= AsxParser::ENTRY)
parser->song->Free();
}
/*
* The playlist object
*
@@ -215,7 +193,7 @@ asx_open_stream(InputStream &is)
context = g_markup_parse_context_new(&asx_parser,
G_MARKUP_TREAT_CDATA_AS_TEXT,
&parser, asx_parser_destroy);
&parser, nullptr);
while (true) {
nbytes = is.LockRead(buffer, sizeof(buffer), error2);

View File

@@ -36,7 +36,7 @@ class CuePlaylist final : public SongEnumerator {
:is(_is), tis(is) {
}
virtual Song *NextSong() override;
virtual DetachedSong *NextSong() override;
};
static SongEnumerator *
@@ -45,10 +45,10 @@ cue_playlist_open_stream(InputStream &is)
return new CuePlaylist(is);
}
Song *
DetachedSong *
CuePlaylist::NextSong()
{
Song *song = parser.Get();
DetachedSong *song = parser.Get();
if (song != nullptr)
return song;

View File

@@ -23,7 +23,7 @@
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "tag/Tag.hxx"
#include "Song.hxx"
#include "DetachedSong.hxx"
#include "Log.hxx"
extern "C" {
@@ -34,10 +34,9 @@ extern "C" {
#include <stdlib.h>
static void
add_song(std::forward_list<SongPointer> &songs, ds_track &track)
add_song(std::forward_list<DetachedSong> &songs, ds_track &track)
{
const char *dsp_scheme = despotify_playlist_plugin.schemes[0];
Song *song;
char uri[128];
char *ds_uri;
@@ -52,15 +51,12 @@ add_song(std::forward_list<SongPointer> &songs, ds_track &track)
return;
}
song = Song::NewRemote(uri);
song->tag = new Tag(mpd_despotify_tag_from_track(track));
songs.emplace_front(song);
songs.emplace_front(uri, mpd_despotify_tag_from_track(track));
}
static bool
parse_track(struct despotify_session *session,
std::forward_list<SongPointer> &songs,
std::forward_list<DetachedSong> &songs,
struct ds_link *link)
{
struct ds_track *track = despotify_link_get_track(session, link);
@@ -73,7 +69,7 @@ parse_track(struct despotify_session *session,
static bool
parse_playlist(struct despotify_session *session,
std::forward_list<SongPointer> &songs,
std::forward_list<DetachedSong> &songs,
struct ds_link *link)
{
ds_playlist *playlist = despotify_link_get_playlist(session, link);
@@ -103,7 +99,7 @@ despotify_playlist_open_uri(const char *url,
return nullptr;
}
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
bool parse_result;
switch (link->type) {

View File

@@ -30,7 +30,7 @@
#include "tag/TagHandler.hxx"
#include "tag/TagId3.hxx"
#include "tag/ApeTag.hxx"
#include "Song.hxx"
#include "DetachedSong.hxx"
#include "TagFile.hxx"
#include "cue/CueParser.hxx"
#include "fs/Traits.hxx"
@@ -69,7 +69,7 @@ public:
delete parser;
}
virtual Song *NextSong() override;
virtual DetachedSong *NextSong() override;
};
static void
@@ -124,10 +124,10 @@ embcue_playlist_open_uri(const char *uri,
return playlist;
}
Song *
DetachedSong *
EmbeddedCuePlaylist::NextSong()
{
Song *song = parser->Get();
DetachedSong *song = parser->Get();
if (song != nullptr)
return song;
@@ -145,14 +145,16 @@ EmbeddedCuePlaylist::NextSong()
parser->Feed(line);
song = parser->Get();
if (song != nullptr)
return song->ReplaceURI(filename.c_str());
if (song != nullptr) {
song->SetURI(filename);
return song;
}
}
parser->Finish();
song = parser->Get();
if (song != nullptr)
song = song->ReplaceURI(filename.c_str());
song->SetURI(filename);
return song;
}

View File

@@ -21,7 +21,7 @@
#include "ExtM3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "Song.hxx"
#include "DetachedSong.hxx"
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"
#include "util/StringUtil.hxx"
@@ -44,7 +44,7 @@ public:
strcmp(line.c_str(), "#EXTM3U") == 0;
}
virtual Song *NextSong() override;
virtual DetachedSong *NextSong() override;
};
static SongEnumerator *
@@ -101,20 +101,19 @@ extm3u_parse_tag(const char *line)
return tag.CommitNew();
}
Song *
DetachedSong *
ExtM3uPlaylist::NextSong()
{
Tag *tag = NULL;
std::string line;
const char *line_s;
Song *song;
do {
if (!tis.ReadLine(line)) {
delete tag;
return NULL;
}
line_s = line.c_str();
if (StringStartsWith(line_s, "#EXTINF:")) {
@@ -126,8 +125,8 @@ ExtM3uPlaylist::NextSong()
line_s = strchug_fast(line_s);
} while (line_s[0] == '#' || *line_s == 0);
song = Song::NewRemote(line_s);
song->tag = tag;
DetachedSong *song = new DetachedSong(line_s, std::move(*tag));
delete tag;
return song;
}

View File

@@ -21,7 +21,7 @@
#include "M3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "Song.hxx"
#include "DetachedSong.hxx"
#include "util/StringUtil.hxx"
#include "TextInputStream.hxx"
@@ -33,7 +33,7 @@ public:
:tis(is) {
}
virtual Song *NextSong() override;
virtual DetachedSong *NextSong() override;
};
static SongEnumerator *
@@ -42,7 +42,7 @@ m3u_open_stream(InputStream &is)
return new M3uPlaylist(is);
}
Song *
DetachedSong *
M3uPlaylist::NextSong()
{
std::string line;
@@ -56,7 +56,7 @@ M3uPlaylist::NextSong()
line_s = strchug_fast(line_s);
} while (line_s[0] == '#' || *line_s == 0);
return Song::NewRemote(line_s);
return new DetachedSong(line_s);
}
static const char *const m3u_suffixes[] = {

View File

@@ -22,7 +22,7 @@
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "InputStream.hxx"
#include "Song.hxx"
#include "DetachedSong.hxx"
#include "tag/TagBuilder.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -37,7 +37,7 @@
static constexpr Domain pls_domain("pls");
static void
pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
pls_parser(GKeyFile *keyfile, std::forward_list<DetachedSong> &songs)
{
gchar *value;
GError *error = nullptr;
@@ -61,8 +61,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
for (; num_entries > 0; --num_entries) {
char key[64];
sprintf(key, "File%u", num_entries);
value = g_key_file_get_string(keyfile, "playlist", key,
&error);
char *uri = g_key_file_get_string(keyfile, "playlist", key,
&error);
if(error) {
FormatError(pls_domain, "Invalid PLS entry %s: '%s'",
key, error->message);
@@ -70,9 +70,6 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
return;
}
Song *song = Song::NewRemote(value);
g_free(value);
TagBuilder tag;
sprintf(key, "Title%u", num_entries);
@@ -89,8 +86,8 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
if (length > 0)
tag.SetTime(length);
song->tag = tag.CommitNew();
songs.emplace_front(song);
songs.emplace_front(uri, tag.Commit());
g_free(uri);
}
}
@@ -135,7 +132,7 @@ pls_open_stream(InputStream &is)
return nullptr;
}
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
pls_parser(keyfile, songs);
g_key_file_free(keyfile);

View File

@@ -43,7 +43,7 @@ struct RssParser {
* The list of songs (in reverse order because that's faster
* while adding).
*/
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
/**
* The current position in the XML file.
@@ -60,10 +60,10 @@ struct RssParser {
TagType tag_type;
/**
* The current song. It is allocated after the "location"
* The current song URI. It is set by the "enclosure"
* element.
*/
Song *song;
std::string location;
TagBuilder tag_builder;
@@ -95,7 +95,7 @@ rss_start_element(gcc_unused GMarkupParseContext *context,
case RssParser::ROOT:
if (StringEqualsCaseASCII(element_name, "item")) {
parser->state = RssParser::ITEM;
parser->song = Song::NewRemote("rss:");
parser->location.clear();
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
}
@@ -106,18 +106,8 @@ rss_start_element(gcc_unused GMarkupParseContext *context,
const gchar *href = get_attribute(attribute_names,
attribute_values,
"url");
if (href != nullptr) {
/* create new song object; we cannot
replace the existing song's URI,
because that attribute is
immutable */
Song *song = Song::NewRemote(href);
if (parser->song != nullptr)
parser->song->Free();
parser->song = song;
}
if (href != nullptr)
parser->location = href;
} else if (StringEqualsCaseASCII(element_name, "title"))
parser->tag_type = TAG_TITLE;
else if (StringEqualsCaseASCII(element_name, "itunes:author"))
@@ -140,12 +130,9 @@ rss_end_element(gcc_unused GMarkupParseContext *context,
case RssParser::ITEM:
if (StringEqualsCaseASCII(element_name, "item")) {
if (strcmp(parser->song->uri, "rss:") != 0) {
assert(parser->song->tag == nullptr);
parser->song->tag = parser->tag_builder.CommitNew();
parser->songs.emplace_front(parser->song);
} else
parser->song->Free();
if (!parser->location.empty())
parser->songs.emplace_front(std::move(parser->location),
parser->tag_builder.Commit());
parser->state = RssParser::ROOT;
} else
@@ -183,15 +170,6 @@ static const GMarkupParser rss_parser = {
nullptr,
};
static void
rss_parser_destroy(gpointer data)
{
RssParser *parser = (RssParser *)data;
if (parser->state >= RssParser::ITEM)
parser->song->Free();
}
/*
* The playlist object
*
@@ -212,7 +190,7 @@ rss_open_stream(InputStream &is)
context = g_markup_parse_context_new(&rss_parser,
G_MARKUP_TREAT_CDATA_AS_TEXT,
&parser, rss_parser_destroy);
&parser, nullptr);
while (true) {
nbytes = is.LockRead(buffer, sizeof(buffer), error2);

View File

@@ -108,7 +108,7 @@ struct parse_data {
char* title;
int got_url; /* nesting level of last stream_url */
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
};
static int
@@ -214,16 +214,14 @@ handle_end_map(void *ctx)
char *u = g_strconcat(data->stream_url, "?client_id=",
soundcloud_config.apikey.c_str(), nullptr);
Song *s = Song::NewRemote(u);
g_free(u);
TagBuilder tag;
tag.SetTime(data->duration / 1000);
if (data->title != nullptr)
tag.AddItem(TAG_NAME, data->title);
s->tag = tag.CommitNew();
data->songs.emplace_front(s);
data->songs.emplace_front(u, tag.Commit());
g_free(u);
return 1;
}

View File

@@ -21,6 +21,7 @@
#include "XspfPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "DetachedSong.hxx"
#include "InputStream.hxx"
#include "tag/TagBuilder.hxx"
#include "util/Error.hxx"
@@ -41,7 +42,7 @@ struct XspfParser {
* The list of songs (in reverse order because that's faster
* while adding).
*/
std::forward_list<SongPointer> songs;
std::forward_list<DetachedSong> songs;
/**
* The current position in the XML file.
@@ -59,10 +60,9 @@ struct XspfParser {
TagType tag_type;
/**
* The current song. It is allocated after the "location"
* element.
* The current song URI. It is set by the "location" element.
*/
Song *song;
std::string location;
TagBuilder tag_builder;
@@ -95,7 +95,7 @@ xspf_start_element(gcc_unused GMarkupParseContext *context,
case XspfParser::TRACKLIST:
if (strcmp(element_name, "track") == 0) {
parser->state = XspfParser::TRACK;
parser->song = nullptr;
parser->location.clear();
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
}
@@ -149,11 +149,9 @@ xspf_end_element(gcc_unused GMarkupParseContext *context,
case XspfParser::TRACK:
if (strcmp(element_name, "track") == 0) {
if (parser->song != nullptr) {
assert(parser->song->tag == nullptr);
parser->song->tag = parser->tag_builder.CommitNew();
parser->songs.emplace_front(parser->song);
}
if (!parser->location.empty())
parser->songs.emplace_front(std::move(parser->location),
parser->tag_builder.Commit());
parser->state = XspfParser::TRACKLIST;
} else
@@ -181,7 +179,7 @@ xspf_text(gcc_unused GMarkupParseContext *context,
break;
case XspfParser::TRACK:
if (parser->song != nullptr &&
if (!parser->location.empty() &&
parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
parser->tag_builder.AddItem(parser->tag_type,
text, text_len);
@@ -189,11 +187,7 @@ xspf_text(gcc_unused GMarkupParseContext *context,
break;
case XspfParser::LOCATION:
if (parser->song == nullptr) {
char *uri = g_strndup(text, text_len);
parser->song = Song::NewRemote(uri);
g_free(uri);
}
parser->location.assign(text, text_len);
break;
}
@@ -207,15 +201,6 @@ static const GMarkupParser xspf_parser = {
nullptr,
};
static void
xspf_parser_destroy(gpointer data)
{
XspfParser *parser = (XspfParser *)data;
if (parser->state >= XspfParser::TRACK && parser->song != nullptr)
parser->song->Free();
}
/*
* The playlist object
*
@@ -236,7 +221,7 @@ xspf_open_stream(InputStream &is)
context = g_markup_parse_context_new(&xspf_parser,
G_MARKUP_TREAT_CDATA_AS_TEXT,
&parser, xspf_parser_destroy);
&parser, nullptr);
while (true) {
nbytes = is.LockRead(buffer, sizeof(buffer), error2);