tag/IcyMetadataParser: use std::span

This commit is contained in:
Max Kellermann 2023-12-20 19:32:21 +01:00
parent b09654b53a
commit 3c5b864396
3 changed files with 36 additions and 42 deletions

View File

@ -81,7 +81,7 @@ IcyInputStream::Read(std::unique_lock<Mutex> &lock,
return 0;
}
size_t result = parser->ParseInPlace(ptr, nbytes);
size_t result = parser->ParseInPlace({static_cast<std::byte *>(ptr), nbytes});
if (result > 0) {
override_offset += result;
offset = override_offset;

View File

@ -156,28 +156,29 @@ icy_parse_tag(
return tag.CommitNew();
}
size_t
IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
std::size_t
IcyMetaDataParser::Meta(std::span<const std::byte> src) noexcept
{
const auto *p = (const unsigned char *)data;
assert(IsDefined());
assert(data_rest == 0);
assert(length > 0);
assert(!src.empty());
std::size_t consumed = 0;
if (meta_size == 0) {
/* read meta_size from the first byte of a meta
block */
meta_size = *p++ * 16;
meta_size = static_cast<std::size_t>(src.front()) * 16;
if (meta_size == 0) {
/* special case: no metadata */
data_rest = data_size;
return 1;
}
/* 1 byte was consumed (must be re-added later for the
return value */
--length;
src = src.subspan(1);
/* 1 byte was consumed */
++consumed;
/* initialize metadata reader, allocate enough
memory (+1 for the null terminator) */
@ -187,15 +188,12 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
assert(meta_position < meta_size);
if (length > meta_size - meta_position)
length = meta_size - meta_position;
if (src.size() > meta_size - meta_position)
src = src.first(meta_size - meta_position);
memcpy(meta_data + meta_position, p, length);
meta_position += length;
if (p != data)
/* re-add the first byte (which contained meta_size) */
++length;
memcpy(meta_data + meta_position, src.data(), src.size());
meta_position += src.size();
consumed += src.size();
if (meta_position == meta_size) {
/* parse */
@ -213,34 +211,29 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
data_rest = data_size;
}
return length;
return consumed;
}
size_t
IcyMetaDataParser::ParseInPlace(void *data, size_t length) noexcept
IcyMetaDataParser::ParseInPlace(std::span<std::byte> buffer) noexcept
{
auto *const dest0 = (std::byte *)data;
std::byte *dest = dest0;
const std::byte *src = dest0;
const auto begin = buffer.begin();
auto dest = begin;
auto src = buffer;
while (length > 0) {
size_t chunk = Data(length);
while (!src.empty()) {
std::size_t chunk = Data(src.size());
if (chunk > 0) {
memmove(dest, src, chunk);
dest += chunk;
src += chunk;
length -= chunk;
if (length == 0)
dest = std::copy_n(src.begin(), chunk, dest);
src = src.subspan(chunk);
if (src.empty())
break;
}
chunk = Meta(src, length);
if (chunk > 0) {
src += chunk;
length -= chunk;
}
chunk = Meta(src);
if (chunk > 0)
src = src.subspan(chunk);
}
return dest - dest0;
return std::distance(begin, dest);
}

View File

@ -10,6 +10,7 @@
#include <cstddef>
#include <memory>
#include <span>
class IcyMetaDataParser {
size_t data_size = 0, data_rest;
@ -66,18 +67,18 @@ public:
size_t Data(size_t length) noexcept;
/**
* Reads metadata from the stream. Returns the number of bytes
* consumed. If the return value is smaller than "length", the caller
* should invoke icy_data().
* Reads metadata from the stream. Returns the number of
* bytes consumed. If the return value is smaller than
* "src.size()", the caller should invoke Data().
*/
size_t Meta(const void *data, size_t length) noexcept;
std::size_t Meta(std::span<const std::byte> src) noexcept;
/**
* Parse data and eliminate metadata.
*
* @return the number of data bytes remaining in the buffer
*/
size_t ParseInPlace(void *data, size_t length) noexcept;
size_t ParseInPlace(std::span<std::byte> buffer) noexcept;
std::unique_ptr<Tag> ReadTag() noexcept {
return std::exchange(tag, nullptr);