From b2051e28cd36c49b7c5d49b511646a3856d7eaf0 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 12 Feb 2024 15:47:31 +0800 Subject: WORKING: implement Buffer. --- include/cru/common/Buffer.h | 89 ++++++++++++++++++++++++++----- src/common/Buffer.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 13 deletions(-) diff --git a/include/cru/common/Buffer.h b/include/cru/common/Buffer.h index 5390ebb4..1fc894ae 100644 --- a/include/cru/common/Buffer.h +++ b/include/cru/common/Buffer.h @@ -2,8 +2,10 @@ #include "Base.h" +#include + namespace cru { -class Buffer { +class Buffer final { public: explicit Buffer(Index size); @@ -16,22 +18,74 @@ class Buffer { ~Buffer(); private: - Index GetSize() const; - Index GetUsedSize() const; - bool IsFull() const { return GetSize() == GetUsedSize(); } - bool IsNotFull() const { return !IsFull(); } + Index GetBufferSize() const { return size_; } + Index GetUsedSize() const { return used_size_; } + Index GetRestSize() const { return GetBufferSize() - GetUsedSize(); } + bool IsNull() const { return ptr_ == nullptr; } + bool IsFull() const { return GetBufferSize() == GetUsedSize(); } + + std::byte* GetPtr() { return GetPtrAt(0); } + const std::byte* GetPtr() const { return GetPtrAt(0); } + + std::byte* GetPtrAt(Index index) { return ptr_ + index; } + const std::byte* GetPtrAt(Index index) const { return ptr_ + index; } + + std::byte& GetRefAt(Index index) { return *GetPtrAt(index); } + const std::byte& GetRefAt(Index index) const { return *GetPtrAt(index); } + + std::byte* GetUsedEndPtr() { return GetPtrAt(GetUsedSize()); } + const std::byte* GetUsedEndPtr() const { return GetPtrAt(GetUsedSize()); } + + std::byte GetByteAt(Index index) const { return ptr_[index]; } + void SetByteAt(Index index, std::byte value) { ptr_[index] = value; } + + void AssignBytes(std::byte* src, Index src_size) { + return AssignBytes(0, src, 0, src_size); + } + void AssignBytes(Index dst_offset, std::byte* src, Index src_size) { + return AssignBytes(dst_offset, src, 0, src_size); + } + void AssignBytes(Index dst_offset, std::byte* src, Index src_offset, + Index src_size); + + void SetUsedSize(Index new_size); - std::byte& GetAt(Index index); - std::byte GetAt(Index index) const; + /** + * @brief Change the size of the buffer. + * + * Unless new size is the same as current size, the buffer is always released + * and a new one is allocated. If preserve_used is true, the used size and old + * data is copied to the new buffer. If new size is smaller than old used + * size, then exceeded data will be lost. + */ + void ResizeBuffer(Index new_size, bool preserve_used); + /** + * @brief Append data to the back of used bytes and increase used size. + * @return The actual size of data saved. + * + * If there is no enough space left for new data, the rest space will be + * written and the size of it will be returned, leaving exceeded data not + * saved. + */ Index PushEnd(std::byte* other, Index other_size); + + /** + * @brief Decrease used data size. + * @return The actual size decreased. + * + * If given size is bigger than current used size, the used size will be + * returned and set to 0. + */ Index PopEnd(Index size); - std::byte* Data(); - const std::byte* Data() const; + operator std::byte*() { return GetPtr(); } + operator const std::byte*() const { return GetPtr(); } - operator std::byte*() { return Data(); } - operator const std::byte*() const { return Data(); } + private: + void Copy_(const Buffer& other); + void Move_(Buffer&& other) noexcept; + void Delete_() noexcept; private: std::byte* ptr_; @@ -42,9 +96,18 @@ class Buffer { void swap(Buffer& left, Buffer& right); class BufferList { - public: + public: explicit BufferList(Index buffer_size); - private: + BufferList(const BufferList& other); + BufferList(BufferList&& other); + + BufferList& operator=(const BufferList& other); + BufferList& operator=(BufferList&& other); + + ~BufferList(); + + private: + std::list buffers_; }; } // namespace cru diff --git a/src/common/Buffer.cpp b/src/common/Buffer.cpp index e69de29b..62904b17 100644 --- a/src/common/Buffer.cpp +++ b/src/common/Buffer.cpp @@ -0,0 +1,124 @@ +#include "cru/common/Buffer.h" +#include +#include "cru/common/Exception.h" + +namespace cru { +namespace { +void CheckSize(Index size) { + if (size < 0) { + throw Exception(u"Size of buffer can't be smaller than 0."); + } +} +} // namespace + +Buffer::Buffer(Index size) { + CheckSize(size); + if (size == 0) { + ptr_ = nullptr; + size_ = used_size_ = 0; + } else { + ptr_ = new std::byte[size]; + size_ = size; + used_size_ = 0; + } +} + +Buffer::Buffer(const Buffer& other) { Copy_(other); } + +Buffer::Buffer(Buffer&& other) noexcept { Move_(std::move(other)); } + +Buffer& Buffer::operator=(const Buffer& other) { + if (this != &other) { + Delete_(); + Copy_(other); + } + return *this; +} + +Buffer& Buffer::operator=(Buffer&& other) noexcept { + if (this != &other) { + Delete_(); + Move_(std::move(other)); + } + return *this; +} + +Buffer::~Buffer() { Delete_(); } + +void Buffer::AssignBytes(Index dst_offset, std::byte* src, Index src_offset, + Index src_size) { + std::memcpy(ptr_ + dst_offset, src + src_offset, src_size); +} + +void Buffer::SetUsedSize(Index new_size) { used_size_ = new_size; } + +void Buffer::ResizeBuffer(Index new_size, bool preserve_used) { + if (new_size == 0) { + Delete_(); + ptr_ = nullptr; + size_ = used_size_ = 0; + return; + } + + auto old_ptr = ptr_; + + ptr_ = new std::byte[new_size]; + size_ = new_size; + + if (old_ptr) { + if (preserve_used) { + auto copy_size = std::min(used_size_, new_size); + std::memcpy(ptr_, old_ptr, copy_size); + used_size_ = copy_size; + } + delete[] old_ptr; + } +} + +Index Buffer::PushEnd(std::byte* other, Index other_size) { + auto copy_size = std::min(GetRestSize(), other_size); + + if (copy_size) { + std::memcpy(GetUsedEndPtr(), other, copy_size); + used_size_ += copy_size; + } + + return copy_size; +} + +Index Buffer::PopEnd(Index size) { + if (used_size_ < size) { + used_size_ = 0; + return used_size_; + } else { + used_size_ -= size; + return size; + } +} + +void Buffer::Copy_(const Buffer& other) { + if (other.ptr_ == nullptr) { + ptr_ = nullptr; + size_ = used_size_ = 0; + } else { + ptr_ = new std::byte[other.size_]; + size_ = other.size_; + used_size_ = other.used_size_; + std::memcpy(ptr_, other.ptr_, used_size_); + } +} + +void Buffer::Move_(Buffer&& other) noexcept { + ptr_ = other.ptr_; + size_ = other.size_; + used_size_ = other.used_size_; + other.ptr_ = nullptr; + other.size_ = other.used_size_ = 0; +} + +void Buffer::Delete_() noexcept { + if (ptr_) { + delete[] ptr_; + } +} +} // namespace cru -- cgit v1.2.3