- Remove outdated `undo-state.md` - Add two code quality/optimization reports that were used to guide previous work: - `code-report.md` (optimization) - `code-report-quality.md` (stability and code health) - Add `themes.md`. - Update undo system docs and roadmap.
204 lines
3.3 KiB
C++
204 lines
3.3 KiB
C++
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
#include "GapBuffer.h"
|
|
|
|
|
|
GapBuffer::GapBuffer() = default;
|
|
|
|
|
|
GapBuffer::GapBuffer(std::size_t initialCapacity)
|
|
: buffer_(nullptr), size_(0), capacity_(0)
|
|
{
|
|
if (initialCapacity > 0) {
|
|
Reserve(initialCapacity);
|
|
}
|
|
}
|
|
|
|
|
|
GapBuffer::GapBuffer(const GapBuffer &other)
|
|
: buffer_(nullptr), size_(0), capacity_(0)
|
|
{
|
|
if (other.capacity_ > 0) {
|
|
Reserve(other.capacity_);
|
|
if (other.size_ > 0) {
|
|
std::memcpy(buffer_, other.buffer_, other.size_);
|
|
size_ = other.size_;
|
|
}
|
|
setTerminator();
|
|
}
|
|
}
|
|
|
|
|
|
GapBuffer &
|
|
GapBuffer::operator=(const GapBuffer &other)
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
if (other.capacity_ > capacity_) {
|
|
Reserve(other.capacity_);
|
|
}
|
|
if (other.size_ > 0) {
|
|
std::memcpy(buffer_, other.buffer_, other.size_);
|
|
}
|
|
size_ = other.size_;
|
|
setTerminator();
|
|
return *this;
|
|
}
|
|
|
|
|
|
GapBuffer::GapBuffer(GapBuffer &&other) noexcept
|
|
: buffer_(other.buffer_), size_(other.size_), capacity_(other.capacity_)
|
|
{
|
|
other.buffer_ = nullptr;
|
|
other.size_ = 0;
|
|
other.capacity_ = 0;
|
|
}
|
|
|
|
|
|
GapBuffer &
|
|
GapBuffer::operator=(GapBuffer &&other) noexcept
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
delete[] buffer_;
|
|
buffer_ = other.buffer_;
|
|
size_ = other.size_;
|
|
capacity_ = other.capacity_;
|
|
other.buffer_ = nullptr;
|
|
other.size_ = 0;
|
|
other.capacity_ = 0;
|
|
return *this;
|
|
}
|
|
|
|
|
|
GapBuffer::~GapBuffer()
|
|
{
|
|
delete[] buffer_;
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Reserve(const std::size_t newCapacity)
|
|
{
|
|
if (newCapacity <= capacity_) [[likely]]
|
|
return;
|
|
// Allocate space for terminator as well
|
|
char *nb = new char[newCapacity + 1];
|
|
if (size_ > 0 && buffer_) {
|
|
std::memcpy(nb, buffer_, size_);
|
|
}
|
|
delete[] buffer_;
|
|
buffer_ = nb;
|
|
capacity_ = newCapacity;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::AppendChar(const char c)
|
|
{
|
|
ensureCapacityFor(1);
|
|
buffer_[size_++] = c;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Append(const char *s, const std::size_t len)
|
|
{
|
|
if (!s || len == 0) [[unlikely]]
|
|
return;
|
|
ensureCapacityFor(len);
|
|
std::memcpy(buffer_ + size_, s, len);
|
|
size_ += len;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Append(const GapBuffer &other)
|
|
{
|
|
if (other.size_ == 0)
|
|
return;
|
|
Append(other.buffer_, other.size_);
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::PrependChar(char c)
|
|
{
|
|
ensureCapacityFor(1);
|
|
// shift right by 1
|
|
if (size_ > 0) [[likely]] {
|
|
std::memmove(buffer_ + 1, buffer_, size_);
|
|
}
|
|
buffer_[0] = c;
|
|
++size_;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Prepend(const char *s, std::size_t len)
|
|
{
|
|
if (!s || len == 0) [[unlikely]]
|
|
return;
|
|
ensureCapacityFor(len);
|
|
if (size_ > 0) [[likely]] {
|
|
std::memmove(buffer_ + len, buffer_, size_);
|
|
}
|
|
std::memcpy(buffer_, s, len);
|
|
size_ += len;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Prepend(const GapBuffer &other)
|
|
{
|
|
if (other.size_ == 0)
|
|
return;
|
|
Prepend(other.buffer_, other.size_);
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::Clear()
|
|
{
|
|
size_ = 0;
|
|
setTerminator();
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::ensureCapacityFor(std::size_t delta)
|
|
{
|
|
if (capacity_ - size_ >= delta) [[likely]]
|
|
return;
|
|
auto required = size_ + delta;
|
|
Reserve(growCapacity(capacity_, required));
|
|
}
|
|
|
|
|
|
std::size_t
|
|
GapBuffer::growCapacity(std::size_t current, std::size_t required)
|
|
{
|
|
// geometric growth, at least required
|
|
std::size_t newCap = current ? current : 8;
|
|
while (newCap < required)
|
|
newCap = newCap + (newCap >> 1); // 1.5x growth
|
|
return newCap;
|
|
}
|
|
|
|
|
|
void
|
|
GapBuffer::setTerminator() const
|
|
{
|
|
if (!buffer_) {
|
|
return;
|
|
}
|
|
|
|
buffer_[size_] = '\0';
|
|
} |