tag/Handler: pass StringView to OnTag() and OnPair()

Eliminates a number of allocations, because callers don't need to copy
the strings to a newly allocated buffer only to null-terminate them.
And most callers don't need to have a null-terminated string.
This commit is contained in:
Max Kellermann 2019-06-06 12:02:55 +02:00
parent 76eb550011
commit 548aa00111
19 changed files with 108 additions and 62 deletions

View File

@ -21,6 +21,7 @@
#include "tag/Tag.hxx"
#include "tag/Settings.hxx"
#include "client/Response.hxx"
#include "util/StringView.hxx"
void
tag_print_types(Response &r) noexcept
@ -31,6 +32,13 @@ tag_print_types(Response &r) noexcept
r.Format("tagtype: %s\n", tag_item_names[i]);
}
void
tag_print(Response &r, TagType type, StringView value) noexcept
{
r.Format("%s: %.*s\n", tag_item_names[type],
int(value.size), value.data);
}
void
tag_print(Response &r, TagType type, const char *value) noexcept
{

View File

@ -25,11 +25,15 @@
enum TagType : uint8_t;
struct Tag;
struct StringView;
class Response;
void
tag_print_types(Response &response) noexcept;
void
tag_print(Response &response, TagType type, StringView value) noexcept;
void
tag_print(Response &response, TagType type, const char *value) noexcept;

View File

@ -27,6 +27,7 @@
#include "client/Client.hxx"
#include "client/Response.hxx"
#include "util/CharUtil.hxx"
#include "util/StringView.hxx"
#include "util/UriUtil.hxx"
#include "tag/Handler.hxx"
#include "tag/Generic.hxx"
@ -110,13 +111,12 @@ handle_listfiles_local(Response &r, Path path_fs)
gcc_pure
static bool
IsValidName(const char *p) noexcept
IsValidName(const StringView s) noexcept
{
if (!IsAlphaASCII(*p))
if (s.empty() || !IsAlphaASCII(s.front()))
return false;
while (*++p) {
const char ch = *p;
for (const char ch : s) {
if (!IsAlphaASCII(ch) && ch != '_' && ch != '-')
return false;
}
@ -126,11 +126,9 @@ IsValidName(const char *p) noexcept
gcc_pure
static bool
IsValidValue(const char *p) noexcept
IsValidValue(const StringView s) noexcept
{
while (*p) {
const char ch = *p++;
for (const char ch : s) {
if ((unsigned char)ch < 0x20)
return false;
}
@ -145,9 +143,11 @@ public:
explicit PrintCommentHandler(Response &_response) noexcept
:NullTagHandler(WANT_PAIR), response(_response) {}
void OnPair(const char *key, const char *value) noexcept override {
void OnPair(StringView key, StringView value) noexcept override {
if (IsValidName(key) && IsValidValue(value))
response.Format("%s: %s\n", key, value);
response.Format("%.*s: %.*s\n",
int(key.size), key.data,
int(value.size), value.data);
}
};

View File

@ -38,6 +38,7 @@
#include "time/ChronoUtil.hxx"
#include "util/UriUtil.hxx"
#include "util/StringAPI.hxx"
#include "util/StringView.hxx"
#include "fs/AllocatedPath.hxx"
#include "Stats.hxx"
#include "PlaylistFile.hxx"
@ -147,7 +148,7 @@ public:
explicit PrintTagHandler(Response &_response) noexcept
:NullTagHandler(WANT_TAG), response(_response) {}
void OnTag(TagType type, const char *value) noexcept override {
void OnTag(TagType type, StringView value) noexcept override {
if (response.GetClient().tag_mask.Test(type))
tag_print(response, type, value);
}

View File

@ -24,6 +24,7 @@
#include "fs/Path.hxx"
#include "util/Domain.hxx"
#include "util/Macros.hxx"
#include "util/StringView.hxx"
#include "Log.hxx"
#include <adplug/adplug.h>
@ -85,7 +86,7 @@ adplug_scan_tag(TagType type, const std::string &value,
TagHandler &handler) noexcept
{
if (!value.empty())
handler.OnTag(type, value.c_str());
handler.OnTag(type, {value.data(), value.size()});
}
static bool

View File

@ -33,6 +33,7 @@
#include "CheckAudioFormat.hxx"
#include "util/bit_reverse.h"
#include "util/ByteOrder.hxx"
#include "util/StringView.hxx"
#include "tag/Handler.hxx"
#include "DsdLib.hxx"
#include "Log.hxx"
@ -205,15 +206,14 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is,
if (length == 0 || length > MAX_LENGTH)
return;
char string[MAX_LENGTH + 1];
char string[MAX_LENGTH];
char *label;
label = string;
if (!decoder_read_full(client, is, label, (size_t)length))
return;
string[length] = '\0';
handler.OnTag(type, label);
handler.OnTag(type, {label, length});
return;
}

View File

@ -24,6 +24,7 @@
#include "tag/Table.hxx"
#include "tag/Handler.hxx"
#include "tag/Id3MusicBrainz.hxx"
#include "util/StringView.hxx"
extern "C" {
#include <libavutil/dict.h>

View File

@ -29,6 +29,7 @@
#include "fs/FileSystem.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringFormat.hxx"
#include "util/StringView.hxx"
#include "util/UriUtil.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
@ -220,7 +221,7 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
handler.OnDuration(SongTime::FromMS(info.play_length));
if (track_count > 1)
handler.OnTag(TAG_TRACK, StringFormat<16>("%u", song_num + 1));
handler.OnTag(TAG_TRACK, StringFormat<16>("%u", song_num + 1).c_str());
if (info.song != nullptr) {
if (track_count > 1) {
@ -229,7 +230,7 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
StringFormat<1024>("%s (%u/%d)",
info.song, song_num + 1,
track_count);
handler.OnTag(TAG_TITLE, tag_title);
handler.OnTag(TAG_TITLE, tag_title.c_str());
} else
handler.OnTag(TAG_TITLE, info.song);
}

View File

@ -24,6 +24,7 @@
#include "fs/Path.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringView.hxx"
#include "Log.hxx"
#include <mikmod.h>

View File

@ -24,6 +24,7 @@
#include "util/WritableBuffer.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringView.hxx"
#include "Log.hxx"
#include <libmodplug/modplug.h>

View File

@ -31,6 +31,7 @@
#endif
#include "util/Macros.hxx"
#include "util/StringFormat.hxx"
#include "util/StringView.hxx"
#include "util/Domain.hxx"
#include "util/ByteOrder.hxx"
#include "Log.hxx"
@ -460,7 +461,7 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
const auto tag_title =
StringFormat<1024>("%s (%u/%u)",
title, track, n_tracks);
handler.OnTag(TAG_TITLE, tag_title);
handler.OnTag(TAG_TITLE, tag_title.c_str());
} else
handler.OnTag(TAG_TITLE, title);
@ -475,7 +476,7 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
handler.OnTag(TAG_DATE, date);
/* track */
handler.OnTag(TAG_TRACK, StringFormat<16>("%u", track));
handler.OnTag(TAG_TRACK, StringFormat<16>("%u", track).c_str());
}
static bool

View File

@ -24,6 +24,7 @@
#include "tag/Handler.hxx"
#include "util/Domain.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringView.hxx"
#include "Log.hxx"
#include <exception>

View File

@ -30,7 +30,7 @@
#include "tag/ReplayGain.hxx"
#include "tag/MixRamp.hxx"
#include "ReplayGainInfo.hxx"
#include "util/DivideString.hxx"
#include "util/StringView.hxx"
#include <assert.h>
@ -98,10 +98,10 @@ flac_scan_comment(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
TagHandler &handler) noexcept
{
if (handler.WantPair()) {
const char *comment = (const char *)entry->entry;
const DivideString split(comment, '=');
if (split.IsDefined() && !split.empty())
handler.OnPair(split.GetFirst(), split.GetSecond());
const StringView comment((const char *)entry->entry);
const auto split = StringView(comment).Split('=');
if (!split.first.empty() && !split.second.IsNull())
handler.OnPair(split.first, split.second);
}
for (const struct tag_table *i = xiph_tags; i->name != nullptr; ++i)

View File

@ -26,7 +26,7 @@
#include "tag/VorbisComment.hxx"
#include "tag/ReplayGain.hxx"
#include "ReplayGainInfo.hxx"
#include "util/DivideString.hxx"
#include "util/StringView.hxx"
bool
vorbis_comments_to_replay_gain(ReplayGainInfo &rgi, char **comments) noexcept
@ -69,9 +69,9 @@ static void
vorbis_scan_comment(const char *comment, TagHandler &handler) noexcept
{
if (handler.WantPair()) {
const DivideString split(comment, '=');
if (split.IsDefined() && !split.empty())
handler.OnPair(split.GetFirst(), split.GetSecond());
const auto split = StringView(comment).Split('=');
if (!split.first.empty() && !split.second.IsNull())
handler.OnPair(split.first, split.second);
}
for (const struct tag_table *i = xiph_tags; i->name != nullptr; ++i)

View File

@ -33,7 +33,7 @@
#include "TagFile.hxx"
#include "fs/Traits.hxx"
#include "fs/AllocatedPath.hxx"
#include "util/ASCII.hxx"
#include "util/StringView.hxx"
#include <memory>
@ -70,15 +70,14 @@ public:
ExtractCuesheetTagHandler() noexcept:NullTagHandler(WANT_PAIR) {}
void OnPair(const char *key, const char *value) noexcept override;
void OnPair(StringView key, StringView value) noexcept override;
};
void
ExtractCuesheetTagHandler::OnPair(const char *name, const char *value) noexcept
ExtractCuesheetTagHandler::OnPair(StringView name, StringView value) noexcept
{
if (cuesheet.empty() &&
StringEqualsCaseASCII(name, "cuesheet"))
cuesheet = value;
if (cuesheet.empty() && name.EqualsIgnoreCase("cuesheet"))
cuesheet = {value.data, value.size};
}
static std::unique_ptr<SongEnumerator>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@ -21,9 +21,20 @@
#include "Builder.hxx"
#include "AudioFormat.hxx"
#include "util/ASCII.hxx"
#include "util/StringFormat.hxx"
#include "util/CharUtil.hxx"
#include "util/StringView.hxx"
#include <stdlib.h>
#include <algorithm>
void
NullTagHandler::OnTag(TagType, StringView) noexcept
{
}
void
NullTagHandler::OnPair(StringView, StringView) noexcept
{
}
void
NullTagHandler::OnAudioFormat(gcc_unused AudioFormat af) noexcept
@ -36,23 +47,35 @@ AddTagHandler::OnDuration(SongTime duration) noexcept
tag.SetDuration(duration);
}
void
AddTagHandler::OnTag(TagType type, const char *value) noexcept
/**
* Skip leading zeroes and a non-decimal suffix.
*/
static StringView
NormalizeDecimal(StringView s)
{
if (type == TAG_TRACK || type == TAG_DISC) {
/* filter out this extra data and leading zeroes */
char *end;
unsigned n = strtoul(value, &end, 10);
if (value != end)
tag.AddItem(type, StringFormat<21>("%u", n));
} else
tag.AddItem(type, value);
auto start = std::find_if(s.begin(), s.end(),
[](char ch){ return ch != '0'; });
auto end = std::find_if(start, s.end(),
[](char ch){ return !IsDigitASCII(ch); });
return {start, end};
}
void
FullTagHandler::OnPair(const char *name, gcc_unused const char *value) noexcept
AddTagHandler::OnTag(TagType type, StringView value) noexcept
{
if (StringEqualsCaseASCII(name, "cuesheet"))
if (type == TAG_TRACK || type == TAG_DISC) {
/* filter out this extra data and leading zeroes */
value = NormalizeDecimal(value);
}
tag.AddItem(type, value);
}
void
FullTagHandler::OnPair(StringView name, StringView) noexcept
{
if (name.EqualsIgnoreCase("cuesheet"))
tag.SetHasPlaylist(true);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2018 The Music Player Daemon Project
* Copyright 2003-2019 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@ -24,6 +24,7 @@
#include "Chrono.hxx"
#include "util/Compiler.h"
struct StringView;
struct AudioFormat;
class TagBuilder;
@ -74,13 +75,13 @@ public:
* @param the value of the tag; the pointer will become
* invalid after returning
*/
virtual void OnTag(TagType type, const char *value) noexcept = 0;
virtual void OnTag(TagType type, StringView value) noexcept = 0;
/**
* A name-value pair has been read. It is the codec specific
* representation of tags.
*/
virtual void OnPair(const char *key, const char *value) noexcept = 0;
virtual void OnPair(StringView key, StringView value) noexcept = 0;
/**
* Declare the audio format of a song.
@ -106,10 +107,8 @@ public:
:TagHandler(_want_mask) {}
void OnDuration(gcc_unused SongTime duration) noexcept override {}
void OnTag(gcc_unused TagType type,
gcc_unused const char *value) noexcept override {}
void OnPair(gcc_unused const char *key,
gcc_unused const char *value) noexcept override {}
void OnTag(TagType type, StringView value) noexcept override;
void OnPair(StringView key, StringView value) noexcept override;
void OnAudioFormat(AudioFormat af) noexcept override;
};
@ -130,7 +129,7 @@ public:
:AddTagHandler(0, _builder) {}
void OnDuration(SongTime duration) noexcept override;
void OnTag(TagType type, const char *value) noexcept override;
void OnTag(TagType type, StringView value) noexcept override;
};
/**
@ -154,7 +153,7 @@ public:
AudioFormat *_audio_format=nullptr) noexcept
:FullTagHandler(0, _builder, _audio_format) {}
void OnPair(const char *key, const char *value) noexcept override;
void OnPair(StringView key, StringView value) noexcept override;
void OnAudioFormat(AudioFormat af) noexcept override;
};

View File

@ -27,6 +27,7 @@
#include "util/Alloc.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringStrip.hxx"
#include "util/StringView.hxx"
#include "Log.hxx"
#include <id3tag.h>

View File

@ -30,6 +30,7 @@
#include "AudioFormat.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringBuffer.hxx"
#include "util/StringView.hxx"
#include "util/PrintException.hxx"
#include <stdexcept>
@ -58,13 +59,16 @@ public:
printf("duration=%f\n", duration.ToDoubleS());
}
void OnTag(TagType type, const char *value) noexcept override {
printf("[%s]=%s\n", tag_item_names[type], value);
void OnTag(TagType type, StringView value) noexcept override {
printf("[%s]=%.*s\n", tag_item_names[type],
int(value.size), value.data);
empty = false;
}
void OnPair(const char *key, const char *value) noexcept override {
printf("\"%s\"=%s\n", key, value);
void OnPair(StringView key, StringView value) noexcept override {
printf("\"%.*s\"=%.*s\n",
int(key.size), key.data,
int(value.size), value.data);
}
void OnAudioFormat(AudioFormat af) noexcept override {