aboutsummaryrefslogtreecommitdiff
path: root/src/base/Buffer.cpp
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-10-06 13:57:39 +0800
committercrupest <crupest@outlook.com>2024-10-06 13:57:39 +0800
commitdfe62dcf8bcefc523b466e127c3edc4dc2756629 (patch)
tree1c751a14ba0da07ca2ff805633f97568060aa4c9 /src/base/Buffer.cpp
parentf51eb955e188858272230a990565931e7403f23b (diff)
downloadcru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.tar.gz
cru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.tar.bz2
cru-dfe62dcf8bcefc523b466e127c3edc4dc2756629.zip
Rename common to base.
Diffstat (limited to 'src/base/Buffer.cpp')
-rw-r--r--src/base/Buffer.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/base/Buffer.cpp b/src/base/Buffer.cpp
new file mode 100644
index 00000000..1213364a
--- /dev/null
+++ b/src/base/Buffer.cpp
@@ -0,0 +1,277 @@
+#include "cru/base/Buffer.h"
+#include "cru/base/Exception.h"
+
+#include <cstring>
+
+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() {
+ ptr_ = nullptr;
+ size_ = used_begin_ = used_end_ = 0;
+}
+
+Buffer::Buffer(Index size) {
+ CheckSize(size);
+ if (size == 0) {
+ ptr_ = nullptr;
+ size_ = used_begin_ = used_end_ = 0;
+ } else {
+ ptr_ = new std::byte[size];
+ size_ = size;
+ used_begin_ = used_end_ = 0;
+ }
+ AssertValid();
+}
+
+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, bool use_memmove) {
+ CheckSize(src_size);
+
+ AssertValid();
+
+ (use_memmove ? std::memmove : std::memcpy)(ptr_ + dst_offset,
+ src + src_offset, src_size);
+ AssertValid();
+}
+
+void Buffer::ResizeBuffer(Index new_size, bool preserve_used) {
+ CheckSize(new_size);
+
+ AssertValid();
+
+ if (new_size == 0) {
+ Delete_();
+ ptr_ = nullptr;
+ size_ = used_begin_ = used_end_ = 0;
+ return;
+ }
+
+ auto old_ptr = ptr_;
+
+ ptr_ = new std::byte[new_size];
+ size_ = new_size;
+ used_begin_ = std::min(new_size, used_begin_);
+ used_end_ = std::min(new_size, used_end_);
+
+ if (old_ptr) {
+ if (preserve_used && used_begin_ < used_end_) {
+ std::memcpy(ptr_ + used_begin_, old_ptr + used_begin_,
+ used_end_ - used_begin_);
+ }
+ delete[] old_ptr;
+ }
+
+ AssertValid();
+}
+
+Index Buffer::PushFront(const std::byte* other, Index other_size,
+ bool use_memmove) {
+ CheckSize(other_size);
+
+ AssertValid();
+
+ auto copy_size = std::min(used_begin_, other_size);
+
+ if (copy_size) {
+ used_begin_ -= copy_size;
+ (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_begin_, other,
+ copy_size);
+ }
+
+ AssertValid();
+
+ return copy_size;
+}
+
+bool Buffer::PushBack(std::byte b) {
+ AssertValid();
+ if (IsUsedReachEnd()) {
+ return false;
+ }
+ ptr_[used_end_] = b;
+ used_end_++;
+ AssertValid();
+ return true;
+}
+
+Index Buffer::PushBack(const std::byte* other, Index other_size,
+ bool use_memmove) {
+ CheckSize(other_size);
+
+ AssertValid();
+
+ auto copy_size = std::min(size_ - used_end_, other_size);
+
+ if (copy_size) {
+ (use_memmove ? std::memmove : std::memcpy)(ptr_ + used_end_, other,
+ copy_size);
+ used_end_ += copy_size;
+ }
+
+ AssertValid();
+
+ return copy_size;
+}
+
+void Buffer::PushBackCount(Index count) {
+ if (count < 0 || count > GetBackFree()) {
+ throw Exception(u"Count out of range in PushBackCount.");
+ }
+ used_end_ += count;
+}
+
+Index Buffer::PopFront(Index size) {
+ CheckSize(size);
+
+ AssertValid();
+
+ auto move = std::min(used_begin_, size);
+ used_begin_ -= move;
+
+ AssertValid();
+
+ return move;
+}
+
+Index Buffer::PopFront(std::byte* buffer, Index size, bool use_memmove) {
+ CheckSize(size);
+
+ AssertValid();
+
+ auto pop_size = std::min(GetUsedSize(), size);
+
+ if (pop_size) {
+ used_begin_ += pop_size;
+ (use_memmove ? std::memmove : std::memcpy)(
+ buffer, GetUsedBeginPtr() - pop_size, pop_size);
+ }
+
+ AssertValid();
+
+ return pop_size;
+}
+
+Index Buffer::PopEnd(Index size) {
+ CheckSize(size);
+
+ AssertValid();
+
+ auto move = std::min(size_ - used_end_, size);
+ used_end_ += move;
+
+ AssertValid();
+
+ return move;
+}
+
+Index Buffer::PopEnd(std::byte* buffer, Index size, bool use_memmove) {
+ CheckSize(size);
+
+ AssertValid();
+
+ auto pop_size = std::min(GetUsedSize(), size);
+
+ if (pop_size) {
+ used_end_ -= pop_size;
+ (use_memmove ? std::memmove : std::memcpy)(buffer, GetUsedEndPtr(),
+ pop_size);
+ }
+
+ AssertValid();
+
+ return pop_size;
+}
+
+std::byte* Buffer::Detach(Index* size) {
+ AssertValid();
+
+ auto ptr = this->ptr_;
+ if (size) {
+ *size = this->size_;
+ }
+ this->ptr_ = nullptr;
+ this->size_ = this->used_begin_ = this->used_end_ = 0;
+
+ AssertValid();
+
+ return ptr;
+}
+
+void Buffer::Copy_(const Buffer& other) {
+ if (other.ptr_ == nullptr) {
+ ptr_ = nullptr;
+ size_ = used_begin_ = used_end_ = 0;
+ } else {
+ ptr_ = new std::byte[other.size_];
+ size_ = other.size_;
+ used_begin_ = other.used_begin_;
+ used_end_ = other.used_end_;
+ std::memcpy(ptr_ + used_begin_, other.ptr_ + used_begin_,
+ used_end_ - used_begin_);
+ }
+ AssertValid();
+}
+
+void Buffer::Move_(Buffer&& other) noexcept {
+ ptr_ = other.ptr_;
+ size_ = other.size_;
+ used_begin_ = other.used_begin_;
+ used_end_ = other.used_end_;
+ other.ptr_ = nullptr;
+ other.size_ = other.used_begin_ = other.used_end_ = 0;
+ AssertValid();
+}
+
+void Buffer::Delete_() noexcept {
+ if (ptr_) {
+ delete[] ptr_;
+ }
+}
+
+void Buffer::AssertValid() {
+ assert(size_ >= 0);
+ assert(used_begin_ >= 0);
+ assert(used_begin_ <= size_);
+ assert(used_end_ >= 0);
+ assert(used_end_ <= size_);
+ assert(used_end_ >= used_begin_);
+ assert((ptr_ == nullptr && size_ == 0) || (ptr_ != nullptr && size_ > 0));
+}
+
+void swap(Buffer& left, Buffer& right) noexcept {
+ using std::swap;
+ swap(left.ptr_, right.ptr_);
+ swap(left.size_, right.size_);
+ swap(left.used_begin_, right.used_begin_);
+ swap(left.used_end_, right.used_end_);
+}
+} // namespace cru