util/AllocatedArray: migrate from {Const,Writable}Buffer to std::span
This commit is contained in:
parent
23dd613ff9
commit
5fb97b81d1
@ -51,8 +51,8 @@ mod_loadfile(const Domain *domain, DecoderClient *client, InputStream &is)
|
|||||||
|
|
||||||
auto buffer = AllocatedArray<std::byte>(buffer_size);
|
auto buffer = AllocatedArray<std::byte>(buffer_size);
|
||||||
|
|
||||||
std::byte *const end = buffer.end();
|
std::byte *p = buffer.data();
|
||||||
std::byte *p = buffer.begin();
|
std::byte *const end = p + buffer.size();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t ret = decoder_read(client, is, p, end - p);
|
size_t ret = decoder_read(client, is, p, end - p);
|
||||||
|
@ -73,7 +73,7 @@ static ModPlugFile *
|
|||||||
LoadModPlugFile(DecoderClient *client, InputStream &is)
|
LoadModPlugFile(DecoderClient *client, InputStream &is)
|
||||||
{
|
{
|
||||||
const auto buffer = mod_loadfile(&modplug_domain, client, is);
|
const auto buffer = mod_loadfile(&modplug_domain, client, is);
|
||||||
if (buffer.IsNull()) {
|
if (buffer == nullptr) {
|
||||||
LogWarning(modplug_domain, "could not load stream");
|
LogWarning(modplug_domain, "could not load stream");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ mod_decode(DecoderClient &client, InputStream &is)
|
|||||||
char audio_buffer[OPENMPT_FRAME_SIZE];
|
char audio_buffer[OPENMPT_FRAME_SIZE];
|
||||||
|
|
||||||
const auto buffer = mod_loadfile(&openmpt_domain, &client, is);
|
const auto buffer = mod_loadfile(&openmpt_domain, &client, is);
|
||||||
if (buffer.IsNull()) {
|
if (buffer == nullptr) {
|
||||||
LogWarning(openmpt_domain, "could not load stream");
|
LogWarning(openmpt_domain, "could not load stream");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ static bool
|
|||||||
openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
openmpt_scan_stream(InputStream &is, TagHandler &handler) noexcept
|
||||||
try {
|
try {
|
||||||
const auto buffer = mod_loadfile(&openmpt_domain, nullptr, is);
|
const auto buffer = mod_loadfile(&openmpt_domain, nullptr, is);
|
||||||
if (buffer.IsNull()) {
|
if (buffer == nullptr) {
|
||||||
LogWarning(openmpt_domain, "could not load stream");
|
LogWarning(openmpt_domain, "could not load stream");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -43,21 +43,21 @@ IcuCaseFold(std::string_view src) noexcept
|
|||||||
try {
|
try {
|
||||||
#ifdef HAVE_ICU
|
#ifdef HAVE_ICU
|
||||||
const auto u = UCharFromUTF8(src);
|
const auto u = UCharFromUTF8(src);
|
||||||
if (u.IsNull())
|
if (u.data() == nullptr)
|
||||||
return {src};
|
return {src};
|
||||||
|
|
||||||
AllocatedArray<UChar> folded(u.size() * 2U);
|
AllocatedArray<UChar> folded(u.size() * 2U);
|
||||||
|
|
||||||
UErrorCode error_code = U_ZERO_ERROR;
|
UErrorCode error_code = U_ZERO_ERROR;
|
||||||
size_t folded_length = u_strFoldCase(folded.begin(), folded.size(),
|
size_t folded_length = u_strFoldCase(folded.data(), folded.size(),
|
||||||
u.begin(), u.size(),
|
u.data(), u.size(),
|
||||||
U_FOLD_CASE_DEFAULT,
|
U_FOLD_CASE_DEFAULT,
|
||||||
&error_code);
|
&error_code);
|
||||||
if (folded_length == 0 || error_code != U_ZERO_ERROR)
|
if (folded_length == 0 || error_code != U_ZERO_ERROR)
|
||||||
return {src};
|
return {src};
|
||||||
|
|
||||||
folded.SetSize(folded_length);
|
folded.SetSize(folded_length);
|
||||||
return UCharToUTF8({folded.begin(), folded.size()});
|
return UCharToUTF8(std::basic_string_view{folded.data(), folded.size()});
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error not implemented
|
#error not implemented
|
||||||
|
@ -141,11 +141,11 @@ IcuConverter::FromUTF8(std::string_view s) const
|
|||||||
|
|
||||||
// TODO: dynamic buffer?
|
// TODO: dynamic buffer?
|
||||||
char buffer[4096], *target = buffer;
|
char buffer[4096], *target = buffer;
|
||||||
const UChar *source = u.begin();
|
const UChar *source = u.data();
|
||||||
UErrorCode code = U_ZERO_ERROR;
|
UErrorCode code = U_ZERO_ERROR;
|
||||||
|
|
||||||
ucnv_fromUnicode(converter, &target, buffer + std::size(buffer),
|
ucnv_fromUnicode(converter, &target, buffer + std::size(buffer),
|
||||||
&source, u.end(),
|
&source, u.data() + u.size(),
|
||||||
nullptr, true, &code);
|
nullptr, true, &code);
|
||||||
|
|
||||||
if (code != U_ZERO_ERROR)
|
if (code != U_ZERO_ERROR)
|
||||||
|
@ -38,7 +38,7 @@ UCharFromUTF8(std::string_view src)
|
|||||||
|
|
||||||
UErrorCode error_code = U_ZERO_ERROR;
|
UErrorCode error_code = U_ZERO_ERROR;
|
||||||
int32_t dest_length;
|
int32_t dest_length;
|
||||||
u_strFromUTF8(dest.begin(), dest_capacity, &dest_length,
|
u_strFromUTF8(dest.data(), dest_capacity, &dest_length,
|
||||||
src.data(), src.size(),
|
src.data(), src.size(),
|
||||||
&error_code);
|
&error_code);
|
||||||
if (U_FAILURE(error_code))
|
if (U_FAILURE(error_code))
|
||||||
|
@ -760,7 +760,7 @@ Play_44_1_Silence(snd_pcm_t *pcm)
|
|||||||
throw Alsa::MakeError(err, "snd_pcm_prepare() failed");
|
throw Alsa::MakeError(err, "snd_pcm_prepare() failed");
|
||||||
|
|
||||||
AllocatedArray<int16_t> buffer{channels * period_size};
|
AllocatedArray<int16_t> buffer{channels * period_size};
|
||||||
buffer = {};
|
buffer = std::span<const int16_t>{};
|
||||||
|
|
||||||
/* play at least 250ms of silence */
|
/* play at least 250ms of silence */
|
||||||
for (snd_pcm_uframes_t remaining_frames = rate / 4;;) {
|
for (snd_pcm_uframes_t remaining_frames = rate / 4;;) {
|
||||||
|
@ -172,7 +172,7 @@ HttpdOutput::ReadPage()
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return std::make_shared<Page>(ConstBuffer{buffer, size});
|
return std::make_shared<Page>(std::span{buffer, size});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -114,5 +114,5 @@ icy_server_metadata_page(const Tag &tag, const TagType *types) noexcept
|
|||||||
if (icy_string == nullptr)
|
if (icy_string == nullptr)
|
||||||
return 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});
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ SnapcastClient::OnSocketReady(unsigned flags) noexcept
|
|||||||
/* discard old chunks */
|
/* discard old chunks */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const ConstBuffer<std::byte> payload = chunk->payload;
|
const std::span payload = chunk->payload;
|
||||||
if (!SendWireChunk(payload.ToVoid(), chunk->time)) {
|
if (!SendWireChunk(payload, chunk->time)) {
|
||||||
// TODO: handle EAGAIN
|
// TODO: handle EAGAIN
|
||||||
LockClose();
|
LockClose();
|
||||||
return;
|
return;
|
||||||
@ -110,23 +110,23 @@ SnapcastClient::OnSocketReady(unsigned flags) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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);
|
auto nbytes = s.Write(buffer.data(), buffer.size());
|
||||||
return nbytes == ssize_t(buffer.size);
|
return nbytes == ssize_t(buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static bool
|
static bool
|
||||||
SendT(SocketDescriptor s, const T &buffer) noexcept
|
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
|
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
|
static bool
|
||||||
@ -158,10 +158,10 @@ static bool
|
|||||||
SendCodecHeader(SocketDescriptor s, const PackedBE16 id,
|
SendCodecHeader(SocketDescriptor s, const PackedBE16 id,
|
||||||
const SnapcastBase &request,
|
const SnapcastBase &request,
|
||||||
const StringView codec,
|
const StringView codec,
|
||||||
const ConstBuffer<void> payload) noexcept
|
const std::span<const std::byte> payload) noexcept
|
||||||
{
|
{
|
||||||
const PackedLE32 codec_size = codec.size;
|
const PackedLE32 codec_size = codec.size;
|
||||||
const PackedLE32 payload_size = payload.size;
|
const PackedLE32 payload_size = payload.size();
|
||||||
|
|
||||||
SnapcastBase base{};
|
SnapcastBase base{};
|
||||||
base.type = uint16_t(SnapcastMessageType::CODEC_HEADER);
|
base.type = uint16_t(SnapcastMessageType::CODEC_HEADER);
|
||||||
@ -169,7 +169,7 @@ SendCodecHeader(SocketDescriptor s, const PackedBE16 id,
|
|||||||
base.refers_to = request.id;
|
base.refers_to = request.id;
|
||||||
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
|
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
|
||||||
base.size = sizeof(codec_size) + codec.size +
|
base.size = sizeof(codec_size) + codec.size +
|
||||||
sizeof(payload_size) + payload.size;
|
sizeof(payload_size) + payload.size();
|
||||||
|
|
||||||
return SendT(s, base) &&
|
return SendT(s, base) &&
|
||||||
SendT(s, codec_size) && Send(s, codec) &&
|
SendT(s, codec_size) && Send(s, codec) &&
|
||||||
@ -212,25 +212,25 @@ SnapcastClient::SendTime(const SnapcastBase &request_header,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
SendWireChunk(SocketDescriptor s, const PackedBE16 id,
|
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
|
std::chrono::steady_clock::time_point t) noexcept
|
||||||
{
|
{
|
||||||
SnapcastWireChunk hdr{};
|
SnapcastWireChunk hdr{};
|
||||||
hdr.timestamp = ToSnapcastTimestamp(t);
|
hdr.timestamp = ToSnapcastTimestamp(t);
|
||||||
hdr.size = payload.size;
|
hdr.size = payload.size();
|
||||||
|
|
||||||
SnapcastBase base{};
|
SnapcastBase base{};
|
||||||
base.type = uint16_t(SnapcastMessageType::WIRE_CHUNK);
|
base.type = uint16_t(SnapcastMessageType::WIRE_CHUNK);
|
||||||
base.id = id;
|
base.id = id;
|
||||||
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
|
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
|
||||||
base.size = sizeof(hdr) + payload.size;
|
base.size = sizeof(hdr) + payload.size();
|
||||||
|
|
||||||
// TODO: no blocking send()
|
// TODO: no blocking send()
|
||||||
return SendT(s, base) && SendT(s, hdr) && Send(s, payload);
|
return SendT(s, base) && SendT(s, hdr) && Send(s, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SnapcastClient::SendWireChunk(ConstBuffer<void> payload,
|
SnapcastClient::SendWireChunk(std::span<const std::byte> payload,
|
||||||
std::chrono::steady_clock::time_point t) noexcept
|
std::chrono::steady_clock::time_point t) noexcept
|
||||||
{
|
{
|
||||||
return ::SendWireChunk(GetSocket(), next_id++, payload, t);
|
return ::SendWireChunk(GetSocket(), next_id++, payload, t);
|
||||||
@ -238,21 +238,21 @@ SnapcastClient::SendWireChunk(ConstBuffer<void> payload,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
SendStreamTags(SocketDescriptor s, const PackedBE16 id,
|
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{};
|
SnapcastBase base{};
|
||||||
base.type = uint16_t(SnapcastMessageType::STREAM_TAGS);
|
base.type = uint16_t(SnapcastMessageType::STREAM_TAGS);
|
||||||
base.id = id;
|
base.id = id;
|
||||||
base.sent = ToSnapcastTimestamp(std::chrono::steady_clock::now());
|
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);
|
return SendT(s, base) && SendT(s, payload_size) && Send(s, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SnapcastClient::SendStreamTags(ConstBuffer<void> payload) noexcept
|
SnapcastClient::SendStreamTags(std::span<const std::byte> payload) noexcept
|
||||||
{
|
{
|
||||||
::SendStreamTags(GetSocket(), next_id++, payload);
|
::SendStreamTags(GetSocket(), next_id++, payload);
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ SnapcastClient::OnSocketInput(void *data, size_t length) noexcept
|
|||||||
|
|
||||||
ConsumeInput(sizeof(base) + base.size);
|
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))) {
|
switch (SnapcastMessageType(uint16_t(base.type))) {
|
||||||
case SnapcastMessageType::HELLO:
|
case SnapcastMessageType::HELLO:
|
||||||
@ -284,8 +284,8 @@ SnapcastClient::OnSocketInput(void *data, size_t length) noexcept
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SnapcastMessageType::TIME:
|
case SnapcastMessageType::TIME:
|
||||||
if (payload.size >= sizeof(SnapcastTime))
|
if (payload.size() >= sizeof(SnapcastTime))
|
||||||
SendTime(base, *(const SnapcastTime *)payload.data);
|
SendTime(base, *(const SnapcastTime *)(const void *)payload.data());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct SnapcastBase;
|
struct SnapcastBase;
|
||||||
struct SnapcastTime;
|
struct SnapcastTime;
|
||||||
@ -60,7 +61,7 @@ public:
|
|||||||
|
|
||||||
void LockClose() noexcept;
|
void LockClose() noexcept;
|
||||||
|
|
||||||
void SendStreamTags(ConstBuffer<void> payload) noexcept;
|
void SendStreamTags(std::span<const std::byte> payload) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock the mutex.
|
* Caller must lock the mutex.
|
||||||
@ -84,7 +85,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
SnapcastChunkPtr LockPopQueue() noexcept;
|
SnapcastChunkPtr LockPopQueue() noexcept;
|
||||||
|
|
||||||
bool SendWireChunk(ConstBuffer<void> payload,
|
bool SendWireChunk(std::span<const std::byte> payload,
|
||||||
std::chrono::steady_clock::time_point t) noexcept;
|
std::chrono::steady_clock::time_point t) noexcept;
|
||||||
|
|
||||||
bool SendServerSettings(const SnapcastBase &request) noexcept;
|
bool SendServerSettings(const SnapcastBase &request) noexcept;
|
||||||
|
@ -161,9 +161,8 @@ public:
|
|||||||
return "pcm";
|
return "pcm";
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void> GetCodecHeader() const noexcept {
|
std::span<const std::byte> GetCodecHeader() const noexcept {
|
||||||
ConstBuffer<std::byte> result(codec_header);
|
return codec_header;
|
||||||
return result.ToVoid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from class AudioOutput */
|
/* virtual methods from class AudioOutput */
|
||||||
|
@ -127,7 +127,7 @@ ReadEncoder(Encoder &encoder)
|
|||||||
std::byte buffer[4096];
|
std::byte buffer[4096];
|
||||||
|
|
||||||
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
|
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};
|
return AllocatedArray<std::byte>{src};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ SnapcastOutput::Close() noexcept
|
|||||||
|
|
||||||
ClearQueue(chunks);
|
ClearQueue(chunks);
|
||||||
|
|
||||||
codec_header = nullptr;
|
codec_header = std::span<const std::byte>{};
|
||||||
delete encoder;
|
delete encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,12 +294,12 @@ SnapcastOutput::SendTag(const Tag &tag)
|
|||||||
if (json.empty())
|
if (json.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ConstBuffer payload(json.data(), json.size());
|
const auto payload = std::as_bytes(std::span{json});
|
||||||
|
|
||||||
const std::scoped_lock<Mutex> protect(mutex);
|
const std::scoped_lock<Mutex> protect(mutex);
|
||||||
// TODO: enqueue StreamTags, don't send directly
|
// TODO: enqueue StreamTags, don't send directly
|
||||||
for (auto &client : clients)
|
for (auto &client : clients)
|
||||||
client.SendStreamTags(payload.ToVoid());
|
client.SendStreamTags(payload);
|
||||||
#else
|
#else
|
||||||
(void)tag;
|
(void)tag;
|
||||||
#endif
|
#endif
|
||||||
@ -348,7 +348,7 @@ SnapcastOutput::Play(const void *chunk, size_t size)
|
|||||||
if (chunks.empty())
|
if (chunks.empty())
|
||||||
inject_event.Schedule();
|
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}));
|
chunks.push(std::make_shared<SnapcastChunk>(now, AllocatedArray{payload}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ TagBuilder::AddItemInternal(TagType type, StringView value) noexcept
|
|||||||
assert(!value.empty());
|
assert(!value.empty());
|
||||||
|
|
||||||
auto f = FixTagString(value);
|
auto f = FixTagString(value);
|
||||||
if (!f.IsNull())
|
if (f != nullptr)
|
||||||
value = { f.data(), f.size() };
|
value = { f.data(), f.size() };
|
||||||
|
|
||||||
AddItemUnchecked(type, value);
|
AddItemUnchecked(type, value);
|
||||||
|
@ -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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -27,14 +27,11 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ALLOCATED_ARRAY_HXX
|
#pragma once
|
||||||
#define ALLOCATED_ARRAY_HXX
|
|
||||||
|
|
||||||
#include "ConstBuffer.hxx"
|
|
||||||
#include "WritableBuffer.hxx"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <span>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +39,7 @@
|
|||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
class AllocatedArray {
|
class AllocatedArray {
|
||||||
typedef WritableBuffer<T> Buffer;
|
using Buffer = std::span<T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using size_type = typename Buffer::size_type;
|
using size_type = typename Buffer::size_type;
|
||||||
@ -51,10 +48,10 @@ public:
|
|||||||
using pointer = typename Buffer::pointer;
|
using pointer = typename Buffer::pointer;
|
||||||
using const_pointer = typename Buffer::const_pointer;
|
using const_pointer = typename Buffer::const_pointer;
|
||||||
using iterator = typename Buffer::iterator;
|
using iterator = typename Buffer::iterator;
|
||||||
using const_iterator = typename Buffer::const_iterator;
|
using const_iterator = typename Buffer::iterator;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Buffer buffer{nullptr};
|
Buffer buffer{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr AllocatedArray() = default;
|
constexpr AllocatedArray() = default;
|
||||||
@ -62,16 +59,15 @@ public:
|
|||||||
explicit AllocatedArray(size_type _size) noexcept
|
explicit AllocatedArray(size_type _size) noexcept
|
||||||
:buffer{new T[_size], _size} {}
|
:buffer{new T[_size], _size} {}
|
||||||
|
|
||||||
explicit AllocatedArray(ConstBuffer<T> src) noexcept {
|
explicit AllocatedArray(std::span<const T> src) noexcept {
|
||||||
if (src == nullptr)
|
if (src.data() == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer = {new T[src.size], src.size};
|
buffer = {new T[src.size()], src.size()};
|
||||||
std::copy_n(src.data, src.size, buffer.data);
|
std::copy(src.begin(), src.end(), buffer.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatedArray(std::nullptr_t n) noexcept
|
AllocatedArray(std::nullptr_t) noexcept {}
|
||||||
:buffer(n) {}
|
|
||||||
|
|
||||||
explicit AllocatedArray(const AllocatedArray &other) noexcept
|
explicit AllocatedArray(const AllocatedArray &other) noexcept
|
||||||
:AllocatedArray(other.buffer) {}
|
:AllocatedArray(other.buffer) {}
|
||||||
@ -80,27 +76,28 @@ public:
|
|||||||
:buffer(other.release()) {}
|
:buffer(other.release()) {}
|
||||||
|
|
||||||
~AllocatedArray() noexcept {
|
~AllocatedArray() noexcept {
|
||||||
delete[] buffer.data;
|
delete[] buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatedArray &operator=(ConstBuffer<T> src) noexcept {
|
AllocatedArray &operator=(std::span<const T> src) noexcept {
|
||||||
assert(size() == 0 || buffer.data != nullptr);
|
assert(empty() || buffer.data() != nullptr);
|
||||||
assert(src.size == 0 || src.data != nullptr);
|
assert(src.empty() || src.data() != nullptr);
|
||||||
|
|
||||||
ResizeDiscard(src.size);
|
ResizeDiscard(src.size());
|
||||||
std::copy_n(src.data, src.size, buffer.data);
|
std::copy(src.begin(), src.end(), buffer.begin());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatedArray &operator=(const AllocatedArray &other) noexcept {
|
AllocatedArray &operator=(const AllocatedArray &other) noexcept {
|
||||||
assert(size() == 0 || buffer.data != nullptr);
|
assert(empty() || buffer.data() != nullptr);
|
||||||
assert(other.size() == 0 || other.buffer.data != nullptr);
|
assert(other.empty() || other.buffer.data() != nullptr);
|
||||||
|
|
||||||
if (&other == this)
|
if (&other == this)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
ResizeDiscard(other.size());
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,29 +108,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
AllocatedArray &operator=(std::nullptr_t n) noexcept {
|
AllocatedArray &operator=(std::nullptr_t n) noexcept {
|
||||||
delete[] buffer.data;
|
delete[] buffer.data();
|
||||||
buffer = n;
|
buffer = {};
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator ConstBuffer<T>() const noexcept {
|
operator std::span<const T>() const noexcept {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator WritableBuffer<T>() noexcept {
|
operator std::span<T>() noexcept {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsNull() const noexcept {
|
|
||||||
return buffer.IsNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(std::nullptr_t) const noexcept {
|
constexpr bool operator==(std::nullptr_t) const noexcept {
|
||||||
return buffer == nullptr;
|
return buffer.data() == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator!=(std::nullptr_t) const noexcept {
|
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.
|
* Returns the number of allocated elements.
|
||||||
*/
|
*/
|
||||||
constexpr size_type size() const noexcept {
|
constexpr size_type size() const noexcept {
|
||||||
return buffer.size;
|
return buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of allocated elements.
|
* Returns the number of allocated elements.
|
||||||
*/
|
*/
|
||||||
constexpr size_type capacity() const noexcept {
|
constexpr size_type capacity() const noexcept {
|
||||||
return buffer.size;
|
return buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer data() noexcept {
|
pointer data() noexcept {
|
||||||
return buffer.data;
|
return buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_pointer data() const noexcept {
|
const_pointer data() const noexcept {
|
||||||
return buffer.data;
|
return buffer.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() noexcept {
|
reference front() noexcept {
|
||||||
@ -200,7 +193,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const_iterator begin() const noexcept {
|
constexpr const_iterator begin() const noexcept {
|
||||||
return buffer.cbegin();
|
return buffer.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() noexcept {
|
iterator end() noexcept {
|
||||||
@ -208,19 +201,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const_iterator end() const noexcept {
|
constexpr const_iterator end() const noexcept {
|
||||||
return buffer.cend();
|
return buffer.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the array, discarding old data.
|
* Resizes the array, discarding old data.
|
||||||
*/
|
*/
|
||||||
void ResizeDiscard(size_type _size) noexcept {
|
void ResizeDiscard(size_type _size) noexcept {
|
||||||
if (_size == buffer.size)
|
if (_size == buffer.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
delete[] buffer.data;
|
delete[] buffer.data();
|
||||||
buffer.size = _size;
|
buffer = {new T[_size], _size};
|
||||||
buffer.data = new T[buffer.size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,7 +221,7 @@ public:
|
|||||||
* avoid expensive heap operations.
|
* avoid expensive heap operations.
|
||||||
*/
|
*/
|
||||||
void GrowDiscard(size_type _size) noexcept {
|
void GrowDiscard(size_type _size) noexcept {
|
||||||
if (_size > buffer.size)
|
if (_size > buffer.size())
|
||||||
ResizeDiscard(_size);
|
ResizeDiscard(_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,16 +230,16 @@ public:
|
|||||||
* range of elements, starting from the beginning.
|
* range of elements, starting from the beginning.
|
||||||
*/
|
*/
|
||||||
void GrowPreserve(size_type _size, size_type preserve) noexcept {
|
void GrowPreserve(size_type _size, size_type preserve) noexcept {
|
||||||
if (_size <= buffer.size)
|
if (_size <= buffer.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
T *new_data = new T[_size];
|
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;
|
delete[] buffer.data();
|
||||||
buffer.data = new_data;
|
buffer = {new_data, _size};
|
||||||
buffer.size = _size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -256,17 +248,15 @@ public:
|
|||||||
* they are still allocated).
|
* they are still allocated).
|
||||||
*/
|
*/
|
||||||
void SetSize(size_type _size) noexcept {
|
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.
|
* Give up ownership of the allocated buffer and return it.
|
||||||
*/
|
*/
|
||||||
Buffer release() noexcept {
|
Buffer release() noexcept {
|
||||||
return std::exchange(buffer, nullptr);
|
return std::exchange(buffer, std::span<T>{});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user