2020-01-18 11:38:21 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
2021-05-14 21:53:04 +03:00
|
|
|
* Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
|
2020-01-18 11:38:21 +03:00
|
|
|
*
|
2021-04-22 11:24:48 +03:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 11:38:21 +03:00
|
|
|
*/
|
|
|
|
|
2018-10-10 12:53:07 +03:00
|
|
|
#pragma once
|
|
|
|
|
2020-07-27 15:15:37 +03:00
|
|
|
#include <AK/Span.h>
|
2019-09-11 20:35:14 +03:00
|
|
|
#include <AK/Types.h>
|
2019-03-16 15:12:13 +03:00
|
|
|
#include <AK/kmalloc.h>
|
2018-10-10 12:53:07 +03:00
|
|
|
|
|
|
|
namespace AK {
|
2021-05-14 21:53:04 +03:00
|
|
|
namespace Detail {
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
template<size_t inline_capacity>
|
|
|
|
class ByteBuffer {
|
2019-03-16 15:12:13 +03:00
|
|
|
public:
|
2021-05-14 21:53:04 +03:00
|
|
|
ByteBuffer() = default;
|
2019-03-16 15:12:13 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
~ByteBuffer()
|
2019-03-16 15:12:13 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
clear();
|
2019-03-16 15:12:13 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
ByteBuffer(ByteBuffer const& other)
|
2019-05-28 12:53:16 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
grow(other.size());
|
|
|
|
VERIFY(m_size == other.size());
|
|
|
|
__builtin_memcpy(data(), other.data(), other.size());
|
2019-05-28 12:53:16 +03:00
|
|
|
}
|
2021-05-14 21:53:04 +03:00
|
|
|
|
|
|
|
ByteBuffer(ByteBuffer&& other)
|
2019-05-28 12:53:16 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
move_from(move(other));
|
2019-05-28 12:53:16 +03:00
|
|
|
}
|
2019-03-16 15:12:13 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
ByteBuffer& operator=(ByteBuffer&& other)
|
2019-03-16 15:12:13 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
if (this != &other) {
|
|
|
|
if (!is_inline())
|
|
|
|
kfree(m_outline_buffer);
|
|
|
|
move_from(move(other));
|
|
|
|
}
|
|
|
|
return *this;
|
2019-03-16 15:12:13 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
ByteBuffer& operator=(ByteBuffer const& other)
|
|
|
|
{
|
|
|
|
if (this != &other) {
|
|
|
|
if (m_size > other.size())
|
|
|
|
internal_trim(other.size(), true);
|
|
|
|
else
|
|
|
|
grow(other.size());
|
|
|
|
__builtin_memcpy(data(), other.data(), other.size());
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
2019-03-16 15:12:13 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] static ByteBuffer create_uninitialized(size_t size)
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
return ByteBuffer(size);
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
2021-05-14 21:53:04 +03:00
|
|
|
|
|
|
|
[[nodiscard]] static ByteBuffer create_zeroed(size_t size)
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
auto buffer = create_uninitialized(size);
|
|
|
|
buffer.zero_fill();
|
|
|
|
VERIFY(size == 0 || (buffer[0] == 0 && buffer[size - 1] == 0));
|
|
|
|
return buffer;
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
2021-05-14 21:53:04 +03:00
|
|
|
|
|
|
|
[[nodiscard]] static ByteBuffer copy(void const* data, size_t size)
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
auto buffer = create_uninitialized(size);
|
2021-05-16 22:46:33 +03:00
|
|
|
if (size != 0)
|
|
|
|
__builtin_memcpy(buffer.data(), data, size);
|
2021-05-14 21:53:04 +03:00
|
|
|
return buffer;
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
2021-05-14 21:53:04 +03:00
|
|
|
|
|
|
|
[[nodiscard]] static ByteBuffer copy(ReadonlyBytes bytes)
|
2018-10-27 01:14:24 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
return copy(bytes.data(), bytes.size());
|
2018-10-27 01:14:24 +03:00
|
|
|
}
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
template<size_t other_inline_capacity>
|
|
|
|
bool operator==(ByteBuffer<other_inline_capacity> const& other) const
|
|
|
|
{
|
|
|
|
if (size() != other.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// So they both have data, and the same length.
|
|
|
|
return !__builtin_memcmp(data(), other.data(), size());
|
|
|
|
}
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
bool operator!=(ByteBuffer const& other) const { return !(*this == other); }
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-04-21 22:40:42 +03:00
|
|
|
[[nodiscard]] u8& operator[](size_t i)
|
2019-05-28 12:53:16 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
VERIFY(i < m_size);
|
|
|
|
return data()[i];
|
2019-05-28 12:53:16 +03:00
|
|
|
}
|
2021-05-14 21:53:04 +03:00
|
|
|
|
|
|
|
[[nodiscard]] u8 const& operator[](size_t i) const
|
2019-05-28 12:53:16 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
VERIFY(i < m_size);
|
|
|
|
return data()[i];
|
2019-05-28 12:53:16 +03:00
|
|
|
}
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] bool is_empty() const { return !m_size; }
|
|
|
|
[[nodiscard]] size_t size() const { return m_size; }
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] u8* data() { return is_inline() ? m_inline_buffer : m_outline_buffer; }
|
|
|
|
[[nodiscard]] u8 const* data() const { return is_inline() ? m_inline_buffer : m_outline_buffer; }
|
2020-07-27 15:15:37 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] Bytes bytes() { return { data(), size() }; }
|
|
|
|
[[nodiscard]] ReadonlyBytes bytes() const { return { data(), size() }; }
|
2020-12-31 02:35:15 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] AK::Span<u8> span() { return { data(), size() }; }
|
|
|
|
[[nodiscard]] AK::Span<const u8> span() const { return { data(), size() }; }
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] u8* offset_pointer(int offset) { return data() + offset; }
|
|
|
|
[[nodiscard]] u8 const* offset_pointer(int offset) const { return data() + offset; }
|
2018-10-10 12:53:07 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
[[nodiscard]] void* end_pointer() { return data() + m_size; }
|
|
|
|
[[nodiscard]] void const* end_pointer() const { return data() + m_size; }
|
2019-04-25 23:05:53 +03:00
|
|
|
|
2020-02-20 14:54:15 +03:00
|
|
|
void trim(size_t size)
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
internal_trim(size, false);
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
|
|
|
|
2021-04-21 22:40:42 +03:00
|
|
|
[[nodiscard]] ByteBuffer slice(size_t offset, size_t size) const
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2020-04-27 20:23:39 +03:00
|
|
|
// I cannot hand you a slice I don't have
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(offset + size <= this->size());
|
2020-04-27 20:23:39 +03:00
|
|
|
|
2018-12-21 04:10:45 +03:00
|
|
|
return copy(offset_pointer(offset), size);
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
if (!is_inline())
|
|
|
|
kfree(m_outline_buffer);
|
|
|
|
m_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void grow(size_t new_size)
|
2019-01-18 05:27:51 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
if (new_size <= m_size)
|
2021-05-14 13:00:57 +03:00
|
|
|
return;
|
2021-05-14 21:53:04 +03:00
|
|
|
if (new_size <= capacity()) {
|
|
|
|
m_size = new_size;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
u8* new_buffer;
|
|
|
|
auto new_capacity = kmalloc_good_size(new_size);
|
|
|
|
if (!is_inline()) {
|
|
|
|
new_buffer = (u8*)krealloc(m_outline_buffer, new_capacity);
|
|
|
|
VERIFY(new_buffer);
|
|
|
|
} else {
|
|
|
|
new_buffer = (u8*)kmalloc(new_capacity);
|
|
|
|
VERIFY(new_buffer);
|
|
|
|
__builtin_memcpy(new_buffer, data(), m_size);
|
|
|
|
}
|
|
|
|
m_outline_buffer = new_buffer;
|
|
|
|
m_outline_capacity = new_capacity;
|
|
|
|
m_size = new_size;
|
2019-01-18 05:27:51 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void append(void const* data, size_t data_size)
|
2019-03-18 16:38:30 +03:00
|
|
|
{
|
2020-04-08 18:04:37 +03:00
|
|
|
if (data_size == 0)
|
|
|
|
return;
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(data != nullptr);
|
2019-03-18 16:38:30 +03:00
|
|
|
int old_size = size();
|
|
|
|
grow(size() + data_size);
|
2020-03-08 13:57:24 +03:00
|
|
|
__builtin_memcpy(this->data() + old_size, data, data_size);
|
2019-03-18 16:38:30 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void operator+=(ByteBuffer const& other)
|
2020-11-06 11:09:51 +03:00
|
|
|
{
|
|
|
|
append(other.data(), other.size());
|
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void overwrite(size_t offset, void const* data, size_t data_size)
|
2020-04-03 04:52:31 +03:00
|
|
|
{
|
|
|
|
// make sure we're not told to write past the end
|
2021-02-23 22:42:32 +03:00
|
|
|
VERIFY(offset + data_size <= size());
|
2020-04-03 04:52:31 +03:00
|
|
|
__builtin_memcpy(this->data() + offset, data, data_size);
|
|
|
|
}
|
|
|
|
|
2021-02-21 13:07:14 +03:00
|
|
|
void zero_fill()
|
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
__builtin_memset(data(), 0, m_size);
|
2021-02-21 13:07:14 +03:00
|
|
|
}
|
|
|
|
|
2020-08-15 19:38:24 +03:00
|
|
|
operator Bytes() { return bytes(); }
|
|
|
|
operator ReadonlyBytes() const { return bytes(); }
|
|
|
|
|
2018-10-10 12:53:07 +03:00
|
|
|
private:
|
2021-05-14 21:53:04 +03:00
|
|
|
ByteBuffer(size_t size)
|
2018-10-10 12:53:07 +03:00
|
|
|
{
|
2021-05-14 21:53:04 +03:00
|
|
|
grow(size);
|
|
|
|
VERIFY(m_size == size);
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void move_from(ByteBuffer&& other)
|
|
|
|
{
|
|
|
|
m_size = other.m_size;
|
|
|
|
if (other.m_size > inline_capacity) {
|
|
|
|
m_outline_buffer = other.m_outline_buffer;
|
|
|
|
m_outline_capacity = other.m_outline_capacity;
|
|
|
|
} else
|
|
|
|
__builtin_memcpy(m_inline_buffer, other.m_inline_buffer, other.m_size);
|
|
|
|
other.m_size = 0;
|
|
|
|
}
|
2019-03-16 15:12:13 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
void internal_trim(size_t size, bool may_discard_existing_data)
|
|
|
|
{
|
|
|
|
VERIFY(size <= m_size);
|
|
|
|
if (!is_inline() && size <= inline_capacity) {
|
|
|
|
// m_inline_buffer and m_outline_buffer are part of a union, so save the pointer
|
|
|
|
auto outline_buffer = m_outline_buffer;
|
|
|
|
if (!may_discard_existing_data)
|
|
|
|
__builtin_memcpy(m_inline_buffer, outline_buffer, size);
|
|
|
|
kfree(outline_buffer);
|
|
|
|
}
|
|
|
|
m_size = size;
|
|
|
|
}
|
2021-02-21 13:07:14 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
bool is_inline() const { return m_size <= inline_capacity; }
|
|
|
|
size_t capacity() const { return is_inline() ? inline_capacity : m_outline_capacity; }
|
2019-03-16 15:12:13 +03:00
|
|
|
|
2021-05-14 21:53:04 +03:00
|
|
|
size_t m_size { 0 };
|
|
|
|
union {
|
|
|
|
u8 m_inline_buffer[inline_capacity];
|
|
|
|
struct {
|
|
|
|
u8* m_outline_buffer;
|
|
|
|
size_t m_outline_capacity;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
2019-03-16 15:12:13 +03:00
|
|
|
|
|
|
|
}
|
2018-10-10 12:53:07 +03:00
|
|
|
}
|