From 915d62ceef54fc491efda040d9d43fbdf558b591 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 27 Nov 2016 17:24:59 -0500 Subject: [PATCH] add GapBuffer::insert() --- src/core/Encoding.h | 5 ++++ src/core/GapBuffer.cc | 62 +++++++++++++++++++++++++++++++++++++++++++ src/core/GapBuffer.h | 4 +++ 3 files changed, 71 insertions(+) diff --git a/src/core/Encoding.h b/src/core/Encoding.h index f85defc..617f302 100644 --- a/src/core/Encoding.h +++ b/src/core/Encoding.h @@ -13,6 +13,11 @@ public: CP_1252, }; + enum + { + MAX_CODE_POINT_SIZE = 8, + }; + static Type detect_encoding(const uint8_t * buffer, size_t length); static uint8_t num_bytes_in_code_point(Type type, const uint8_t * encoded); static const uint8_t * beginning_of_code_point(Type type, const uint8_t * encoded); diff --git a/src/core/GapBuffer.cc b/src/core/GapBuffer.cc index fe13f52..7c55ed9 100644 --- a/src/core/GapBuffer.cc +++ b/src/core/GapBuffer.cc @@ -43,6 +43,68 @@ void GapBuffer::compact() } } +/** + * Insert code_point into the gap buffer at position position. + * + * @param position Position in the gap buffer to insert the code point at. + * Must be <= size. + * @param code_point The code point to insert. + */ +void GapBuffer::insert(size_t position, uint32_t code_point) +{ + if (position > m_size) + return; + check_grow(); + move_gap(position); + size_t size = Encoding::encode(code_point, m_encoding, &m_buffer[m_gap_position]); + m_gap_position += size; + m_size += size; +} + +/** + * Verify that there is enough free space in the gap, and if not, grow the gap + * and move data. + */ +void GapBuffer::check_grow() +{ + if (gap_size() < Encoding::MAX_CODE_POINT_SIZE) + { + /* We're out of space. Allocate more and move. */ + size_t new_size = (m_buffer_size + (128u * 1024u)) & System::page_base_mask; + size_t new_num_pages = new_size >> System::page_size_log; + uint8_t * new_buffer = (uint8_t *)System::alloc_pages(new_num_pages); + memcpy(new_buffer, m_buffer, m_gap_position); + memcpy(&new_buffer[m_gap_position], &m_buffer[m_gap_position + gap_size()], m_size - m_gap_position); + + /* Free the old buffer */ + System::free_pages(m_buffer, m_buffer_size >> System::page_size_log); + + m_buffer = new_buffer; + m_buffer_size = new_size; + m_gap_position = m_size; + } +} + +/** + * Move the gap buffer gap position to the requested position. + * + * @param position New gap position. Must be <= m_size. + */ +void GapBuffer::move_gap(size_t position) +{ + if (position != m_gap_position) + { + if (position < m_gap_position) + { + memmove(&m_buffer[position + gap_size()], &m_buffer[position], m_gap_position - position); + } + else + { + memmove(&m_buffer[m_gap_position], &m_buffer[m_gap_position + gap_size()], position - m_gap_position); + } + } +} + void GapBuffer::Iterator::go_forward() { diff --git a/src/core/GapBuffer.h b/src/core/GapBuffer.h index 3e86bc5..0100b89 100644 --- a/src/core/GapBuffer.h +++ b/src/core/GapBuffer.h @@ -110,6 +110,7 @@ public: } size_t gap_size() const { return m_buffer_size - m_size; } void compact(); + void insert(size_t position, uint32_t code_point); protected: uint8_t * m_buffer; @@ -118,6 +119,9 @@ protected: size_t m_gap_position; Encoding::Type m_encoding; std::list> m_cursors; + + void check_grow(); + void move_gap(size_t position); }; #endif