aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-02-12 15:47:31 +0800
committercrupest <crupest@outlook.com>2024-03-22 23:42:36 +0800
commitb2051e28cd36c49b7c5d49b511646a3856d7eaf0 (patch)
treebc0d8f48039288bba834342d7c47bce19f13d85b
parenta21be4edaa483b86872ad732fc4b93970a607952 (diff)
downloadcru-b2051e28cd36c49b7c5d49b511646a3856d7eaf0.tar.gz
cru-b2051e28cd36c49b7c5d49b511646a3856d7eaf0.tar.bz2
cru-b2051e28cd36c49b7c5d49b511646a3856d7eaf0.zip
WORKING: implement Buffer.
-rw-r--r--include/cru/common/Buffer.h89
-rw-r--r--src/common/Buffer.cpp124
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 <list>
+
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<Buffer> 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 <cstring>
+#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