util/AllocatedArray: migrate from {Const,Writable}Buffer to std::span

This commit is contained in:
Max Kellermann 2022-05-11 16:19:44 +02:00 committed by Max Kellermann
parent 23dd613ff9
commit 5fb97b81d1
15 changed files with 93 additions and 103 deletions

View File

@ -51,8 +51,8 @@ mod_loadfile(const Domain *domain, DecoderClient *client, InputStream &is)
auto buffer = AllocatedArray<std::byte>(buffer_size);
std::byte *const end = buffer.end();
std::byte *p = buffer.begin();
std::byte *p = buffer.data();
std::byte *const end = p + buffer.size();
while (true) {
size_t ret = decoder_read(client, is, p, end - p);

View File

@ -73,7 +73,7 @@ static ModPlugFile *
LoadModPlugFile(DecoderClient *client, InputStream &is)
{
const auto buffer = mod_loadfile(&modplug_domain, client, is);
if (buffer.IsNull()) {
if (buffer == nullptr) {
LogWarning(modplug_domain, "could not load stream");
return nullptr;
}

View File

@ -73,7 +73,7 @@ mod_decode(DecoderClient &client, InputStream &is)
char audio_buffer[OPENMPT_FRAME_SIZE];
const auto buffer = mod_loadfile(&openmpt_domain, &client, is);
if (buffer.IsNull()) {
if (buffer == nullptr) {
LogWarning(openmpt_domain, "could not load stream");
return;
}
@ -128,7 +128,7 @@ static bool
openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept
try {
const auto buffer = mod_loadfile(&openmpt_domain, nullptr, is);
if (buffer.IsNull()) {
if (buffer == nullptr) {
LogWarning(openmpt_domain, "could not load stream");
return false;
}

View File

@ -43,21 +43,21 @@ IcuCaseFold(std::string_view src) noexcept
try {
#ifdef HAVE_ICU
const auto u = UCharFromUTF8(src);
if (u.IsNull())
if (u.data() == nullptr)
return {src};
AllocatedArray<UChar> folded(u.size() * 2U);
UErrorCode error_code = U_ZERO_ERROR;
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
u.begin(), u.size(),
size_t folded_length = u_strFoldCase(folded.data(), folded.size(),
u.data(), u.size(),
U_FOLD_CASE_DEFAULT,
&error_code);
if (folded_length == 0 || error_code != U_ZERO_ERROR)
return {src};
folded.SetSize(folded_length);
return UCharToUTF8({folded.begin(), folded.size()});
return UCharToUTF8(std::basic_string_view{folded.data(), folded.size()});
#else
#error not implemented

View File

@ -141,11 +141,11 @@ IcuConverter::FromUTF8(std::string_view s) const
// TODO: dynamic buffer?
char buffer[4096], *target = buffer;
const UChar *source = u.begin();
const UChar *source = u.data();
UErrorCode code = U_ZERO_ERROR;
ucnv_fromUnicode(converter, &target, buffer + std::size(buffer),
&source, u.end(),
&source, u.data() + u.size(),
nullptr, true, &code);
if (code != U_ZERO_ERROR)

View File

@ -38,7 +38,7 @@ UCharFromUTF8(std::string_view src)
UErrorCode error_code = U_ZERO_ERROR;
int32_t dest_length;
u_strFromUTF8(dest.begin(), dest_capacity, &dest_length,
u_strFromUTF8(dest.data(), dest_capacity, &dest_length,
src.data(), src.size(),
&error_code);
if (U_FAILURE(error_code))

View File

@ -760,7 +760,7 @@ Play_44_1_Silence(snd_pcm_t *pcm)
throw Alsa::MakeError(err, "snd_pcm_prepare() failed");
AllocatedArray<int16_t> buffer{channels * period_size};
buffer = {};
buffer = std::span<const int16_t>{};
/* play at least 250ms of silence */
for (snd_pcm_uframes_t remaining_frames = rate / 4;;) {

View File

@ -172,7 +172,7 @@ HttpdOutput::ReadPage()
if (size == 0)
return nullptr;
return std::make_shared<Page>(ConstBuffer{buffer, size});
return std::make_shared<Page>(std::span{buffer, size});
}
inline void

View File

@ -114,5 +114,5 @@ icy_server_metadata_page(const Tag &tag, const TagType *types) noexcept
if (icy_string == nullptr)
return nullptr;
return std::make_shared<Page>(ConstBuffer<std::byte>{(const std::byte *)icy_string.c_str(), uint8_t(icy_string[0]) * 16U + 1U});
return std::make_shared<Page>(std::span{(const std::byte *)icy_string.c_str(), uint8_t(icy_string[0]) * 16U + 1U});
}

View File

@ -95,8 +95,8 @@ SnapcastClient::OnSocketReady(unsigned flags) noexcept
/* discard old chunks */
continue;
const ConstBuffer<std::byte> payload = chunk->payload;
if (!SendWireChunk(payload.ToVoid(), chunk->time)) {
const std::span payload = chunk->payload;
if (!SendWireChunk(payload, chunk->time)) {
// TODO: handle EAGAIN
LockClose();
return;
@ -110,23 +110,23 @@ SnapcastClient::OnSocketReady(unsigned flags) noexcept
}
static bool
Send(SocketDescriptor s, ConstBuffer<void> buffer) noexcept
Send(SocketDescriptor s, std::span<const std::byte> buffer) noexcept
{
auto nbytes = s.Write(buffer.data, buffer.size);
return nbytes == ssize_t(buffer.size);
auto nbytes = s.Write(buffer.data(), buffer.size());
return nbytes == ssize_t(buffer.size());
}
template<typename T>
static bool
SendT(SocketDescriptor s, const T &buffer) noexcept
{
return Send(s, ConstBuffer<T>{&buffer, 1}.ToVoid());
return Send(s, std::as_bytes(std::span{&buffer, 1}));
}
static bool
Send(SocketDescriptor s, StringView buffer) noexcept
Send(SocketDescriptor s, std::string_view buffer) noexcept
{
return Send(s, buffer.ToVoid());
return Send(s, std::as_bytes(std::span{buffer}));
}
static bool
@ -158,10 +158,10 @@ static bool
SendCodecHeader(SocketDescriptor s, const PackedBE16 id,
const SnapcastBase &request,
const StringView codec,
const ConstBuffer<void> payload) noexcept
const std::span<const std::byte> payload) noexcept
{
const PackedLE32 codec_size = codec.size;
const PackedLE32 payload_size = payload.size;
const PackedLE32 payload_size = payload.size();
SnapcastBase base{};
base.type = uint16_t(SnapcastMessageType::CODEC_HEADER);
@ -169,7 +169,7 @@ SendCodecHeader(SocketDescriptor s, const PackedBE16 id,
base.refers_to = request.id;
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
base.size = sizeof(codec_size) + codec.size +
sizeof(payload_size) + payload.size;
sizeof(payload_size) + payload.size();
return SendT(s, base) &&
SendT(s, codec_size) && Send(s, codec) &&
@ -212,25 +212,25 @@ SnapcastClient::SendTime(const SnapcastBase &request_header,
static bool
SendWireChunk(SocketDescriptor s, const PackedBE16 id,
const ConstBuffer<void> payload,
const std::span<const std::byte> payload,
std::chrono::steady_clock::time_point t) noexcept
{
SnapcastWireChunk hdr{};
hdr.timestamp = ToSnapcastTimestamp(t);
hdr.size = payload.size;
hdr.size = payload.size();
SnapcastBase base{};
base.type = uint16_t(SnapcastMessageType::WIRE_CHUNK);
base.id = id;
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
base.size = sizeof(hdr) + payload.size;
base.size = sizeof(hdr) + payload.size();
// TODO: no blocking send()
return SendT(s, base) && SendT(s, hdr) && Send(s, payload);
}
bool
SnapcastClient::SendWireChunk(ConstBuffer<void> payload,
SnapcastClient::SendWireChunk(std::span<const std::byte> payload,
std::chrono::steady_clock::time_point t) noexcept
{
return ::SendWireChunk(GetSocket(), next_id++, payload, t);
@ -238,21 +238,21 @@ SnapcastClient::SendWireChunk(ConstBuffer<void> payload,
static bool
SendStreamTags(SocketDescriptor s, const PackedBE16 id,
const ConstBuffer<void> payload) noexcept
const std::span<const std::byte> payload) noexcept
{
const PackedLE32 payload_size = payload.size;
const PackedLE32 payload_size = payload.size();
SnapcastBase base{};
base.type = uint16_t(SnapcastMessageType::STREAM_TAGS);
base.id = id;
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
base.size = sizeof(payload_size) + payload.size;
base.size = sizeof(payload_size) + payload.size();
return SendT(s, base) && SendT(s, payload_size) && Send(s, payload);
}
void
SnapcastClient::SendStreamTags(ConstBuffer<void> payload) noexcept
SnapcastClient::SendStreamTags(std::span<const std::byte> payload) noexcept
{
::SendStreamTags(GetSocket(), next_id++, payload);
}
@ -270,7 +270,7 @@ SnapcastClient::OnSocketInput(void *data, size_t length) noexcept
ConsumeInput(sizeof(base) + base.size);
const ConstBuffer<void> payload{&base + 1, base.size};
const std::span<const std::byte> payload{(const std::byte *)(&base + 1), base.size};
switch (SnapcastMessageType(uint16_t(base.type))) {
case SnapcastMessageType::HELLO:
@ -284,8 +284,8 @@ SnapcastClient::OnSocketInput(void *data, size_t length) noexcept
break;
case SnapcastMessageType::TIME:
if (payload.size >= sizeof(SnapcastTime))
SendTime(base, *(const SnapcastTime *)payload.data);
if (payload.size() >= sizeof(SnapcastTime))
SendTime(base, *(const SnapcastTime *)(const void *)payload.data());
break;
default:

View File

@ -26,6 +26,7 @@
#include <chrono>
#include <cstdint>
#include <span>
struct SnapcastBase;
struct SnapcastTime;
@ -60,7 +61,7 @@ public:
void LockClose() noexcept;
void SendStreamTags(ConstBuffer<void> payload) noexcept;
void SendStreamTags(std::span<const std::byte> payload) noexcept;
/**
* Caller must lock the mutex.
@ -84,7 +85,7 @@ public:
private:
SnapcastChunkPtr LockPopQueue() noexcept;
bool SendWireChunk(ConstBuffer<void> payload,
bool SendWireChunk(std::span<const std::byte> payload,
std::chrono::steady_clock::time_point t) noexcept;
bool SendServerSettings(const SnapcastBase &request) noexcept;

View File

@ -161,9 +161,8 @@ public:
return "pcm";
}
ConstBuffer<void> GetCodecHeader() const noexcept {
ConstBuffer<std::byte> result(codec_header);
return result.ToVoid();
std::span<const std::byte> GetCodecHeader() const noexcept {
return codec_header;
}
/* virtual methods from class AudioOutput */

View File

@ -127,7 +127,7 @@ ReadEncoder(Encoder &encoder)
std::byte buffer[4096];
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
const ConstBuffer<std::byte> src(buffer, nbytes);
const std::span<const std::byte> src{buffer, nbytes};
return AllocatedArray<std::byte>{src};
}
@ -181,7 +181,7 @@ SnapcastOutput::Close() noexcept
ClearQueue(chunks);
codec_header = nullptr;
codec_header = std::span<const std::byte>{};
delete encoder;
}
@ -294,12 +294,12 @@ SnapcastOutput::SendTag(const Tag &tag)
if (json.empty())
return;
const ConstBuffer payload(json.data(), json.size());
const auto payload = std::as_bytes(std::span{json});
const std::scoped_lock<Mutex> protect(mutex);
// TODO: enqueue StreamTags, don't send directly
for (auto &client : clients)
client.SendStreamTags(payload.ToVoid());
client.SendStreamTags(payload);
#else
(void)tag;
#endif
@ -348,7 +348,7 @@ SnapcastOutput::Play(const void *chunk, size_t size)
if (chunks.empty())
inject_event.Schedule();
const ConstBuffer payload{buffer, nbytes};
const std::span<const std::byte> payload{buffer, nbytes};
chunks.push(std::make_shared<SnapcastChunk>(now, AllocatedArray{payload}));
}

View File

@ -216,7 +216,7 @@ TagBuilder::AddItemInternal(TagType type, StringView value) noexcept
assert(!value.empty());
auto f = FixTagString(value);
if (!f.IsNull())
if (f != nullptr)
value = { f.data(), f.size() };
AddItemUnchecked(type, value);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 Max Kellermann <max.kellermann@gmail.com>
* Copyright 2010-2022 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -27,14 +27,11 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ALLOCATED_ARRAY_HXX
#define ALLOCATED_ARRAY_HXX
#include "ConstBuffer.hxx"
#include "WritableBuffer.hxx"
#pragma once
#include <algorithm>
#include <cassert>
#include <span>
#include <utility>
/**
@ -42,7 +39,7 @@
*/
template<class T>
class AllocatedArray {
typedef WritableBuffer<T> Buffer;
using Buffer = std::span<T>;
public:
using size_type = typename Buffer::size_type;
@ -51,10 +48,10 @@ public:
using pointer = typename Buffer::pointer;
using const_pointer = typename Buffer::const_pointer;
using iterator = typename Buffer::iterator;
using const_iterator = typename Buffer::const_iterator;
using const_iterator = typename Buffer::iterator;
protected:
Buffer buffer{nullptr};
Buffer buffer{};
public:
constexpr AllocatedArray() = default;
@ -62,16 +59,15 @@ public:
explicit AllocatedArray(size_type _size) noexcept
:buffer{new T[_size], _size} {}
explicit AllocatedArray(ConstBuffer<T> src) noexcept {
if (src == nullptr)
explicit AllocatedArray(std::span<const T> src) noexcept {
if (src.data() == nullptr)
return;
buffer = {new T[src.size], src.size};
std::copy_n(src.data, src.size, buffer.data);
buffer = {new T[src.size()], src.size()};
std::copy(src.begin(), src.end(), buffer.begin());
}
AllocatedArray(std::nullptr_t n) noexcept
:buffer(n) {}
AllocatedArray(std::nullptr_t) noexcept {}
explicit AllocatedArray(const AllocatedArray &other) noexcept
:AllocatedArray(other.buffer) {}
@ -80,27 +76,28 @@ public:
:buffer(other.release()) {}
~AllocatedArray() noexcept {
delete[] buffer.data;
delete[] buffer.data();
}
AllocatedArray &operator=(ConstBuffer<T> src) noexcept {
assert(size() == 0 || buffer.data != nullptr);
assert(src.size == 0 || src.data != nullptr);
AllocatedArray &operator=(std::span<const T> src) noexcept {
assert(empty() || buffer.data() != nullptr);
assert(src.empty() || src.data() != nullptr);
ResizeDiscard(src.size);
std::copy_n(src.data, src.size, buffer.data);
ResizeDiscard(src.size());
std::copy(src.begin(), src.end(), buffer.begin());
return *this;
}
AllocatedArray &operator=(const AllocatedArray &other) noexcept {
assert(size() == 0 || buffer.data != nullptr);
assert(other.size() == 0 || other.buffer.data != nullptr);
assert(empty() || buffer.data() != nullptr);
assert(other.empty() || other.buffer.data() != nullptr);
if (&other == this)
return *this;
ResizeDiscard(other.size());
std::copy_n(other.buffer.data, other.buffer.size, buffer.data);
std::copy_n(other.buffer.begin(), other.buffer.end(),
buffer.begin());
return *this;
}
@ -111,29 +108,25 @@ public:
}
AllocatedArray &operator=(std::nullptr_t n) noexcept {
delete[] buffer.data;
buffer = n;
delete[] buffer.data();
buffer = {};
return *this;
}
operator ConstBuffer<T>() const noexcept {
operator std::span<const T>() const noexcept {
return buffer;
}
operator WritableBuffer<T>() noexcept {
operator std::span<T>() noexcept {
return buffer;
}
constexpr bool IsNull() const noexcept {
return buffer.IsNull();
}
constexpr bool operator==(std::nullptr_t) const noexcept {
return buffer == nullptr;
return buffer.data() == nullptr;
}
constexpr bool operator!=(std::nullptr_t) const noexcept {
return buffer != nullptr;
return buffer.data() != nullptr;
}
/**
@ -147,22 +140,22 @@ public:
* Returns the number of allocated elements.
*/
constexpr size_type size() const noexcept {
return buffer.size;
return buffer.size();
}
/**
* Returns the number of allocated elements.
*/
constexpr size_type capacity() const noexcept {
return buffer.size;
return buffer.size();
}
pointer data() noexcept {
return buffer.data;
return buffer.data();
}
const_pointer data() const noexcept {
return buffer.data;
return buffer.data();
}
reference front() noexcept {
@ -200,7 +193,7 @@ public:
}
constexpr const_iterator begin() const noexcept {
return buffer.cbegin();
return buffer.begin();
}
iterator end() noexcept {
@ -208,19 +201,18 @@ public:
}
constexpr const_iterator end() const noexcept {
return buffer.cend();
return buffer.end();
}
/**
* Resizes the array, discarding old data.
*/
void ResizeDiscard(size_type _size) noexcept {
if (_size == buffer.size)
if (_size == buffer.size())
return;
delete[] buffer.data;
buffer.size = _size;
buffer.data = new T[buffer.size];
delete[] buffer.data();
buffer = {new T[_size], _size};
}
/**
@ -229,7 +221,7 @@ public:
* avoid expensive heap operations.
*/
void GrowDiscard(size_type _size) noexcept {
if (_size > buffer.size)
if (_size > buffer.size())
ResizeDiscard(_size);
}
@ -238,16 +230,16 @@ public:
* range of elements, starting from the beginning.
*/
void GrowPreserve(size_type _size, size_type preserve) noexcept {
if (_size <= buffer.size)
if (_size <= buffer.size())
return;
T *new_data = new T[_size];
std::move(buffer.data, buffer.data + preserve, new_data);
std::move(buffer.begin(), std::next(buffer.begin(), preserve),
new_data);
delete[] buffer.data;
buffer.data = new_data;
buffer.size = _size;
delete[] buffer.data();
buffer = {new_data, _size};
}
/**
@ -256,17 +248,15 @@ public:
* they are still allocated).
*/
void SetSize(size_type _size) noexcept {
assert(_size <= buffer.size);
assert(_size <= buffer.size());
buffer.size = _size;
buffer = buffer.first(_size);
}
/**
* Give up ownership of the allocated buffer and return it.
*/
Buffer release() noexcept {
return std::exchange(buffer, nullptr);
return std::exchange(buffer, std::span<T>{});
}
};
#endif