From 8a01e2d1b9e826d53962a7361e993aaea1625f4b Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 17 Aug 2025 10:37:04 +1000 Subject: [PATCH] setup flatbuffer --- src/DLibs | 2 +- src/editor/buffer.d | 335 +++++++++++++++++++++++++++----------------- 2 files changed, 206 insertions(+), 131 deletions(-) diff --git a/src/DLibs b/src/DLibs index 3c6d214..38e4e44 160000 --- a/src/DLibs +++ b/src/DLibs @@ -1 +1 @@ -Subproject commit 3c6d214aa7e3058f8de1a4ff380fd1bb8ce56036 +Subproject commit 38e4e44b4dbecd8b0cbe878adb4f8da397a1ae45 diff --git a/src/editor/buffer.d b/src/editor/buffer.d index 26e47bf..544bcdf 100644 --- a/src/editor/buffer.d +++ b/src/editor/buffer.d @@ -3,208 +3,283 @@ import math; import alloc; import util; -struct GapBuffer +struct FlatBuffer { + Arena arena; u8[] data; u64 length; - u64 gap_start; - u64 gap_end; - u64 gap_size; + u64 line_count; } -GapBuffer -CreateGapBuffer(u8[] data) +struct Range { - // Match 4k page sizes - u64 capacity = RoundUp(cast(u64)data.length, KB(4)); - if (data.length % KB(4) == 0) - { - capacity += KB(4); - } + u32 x; + u32 y; +} + +FlatBuffer +CreateFlatBuffer(u8[] data) +{ + u64 capacity = RoundUp(cast(u64)(data.length) * 2, KB(4)); u8[] buf = MAllocArray!(u8)(capacity); + buf[0 .. data.length] = data[0 .. data.length]; - buf[0 .. data.length] = data[0 .. $]; + u64 line_count = 1; + for(u64 i = 0; i < cast(u64)data.length; i += 1) + { + if (data.ptr[i] == '\n') + { + line_count += 1; + } + } - GapBuffer buffer = { + return FlatBuffer( + arena: CreateArena(MB(1)), data: buf, - length: data.length, - gap_start: data.length, - gap_end: data.length + (capacity - data.length), - gap_size: capacity - cast(u64)(data.length), - }; - - return buffer; + length: cast(u64)data.length, + line_count: line_count, + ); } void -GrowBuffer(GapBuffer* buffer) +Insert(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos) { - u8[] temp_buf = buffer.data[0 .. buffer.length]; - GapBuffer temp_gap = CreateGapBuffer(temp_buf); - MFreeArray(buffer.data); - *buffer = temp_gap; -} - -void -Insert(GapBuffer* buffer, u8[] insert, u64 length, i64 pos) -{ - assert(length <= insert.length, "Insert Error: length is greater than insert buffer length"); - if (buffer.length + length > buffer.data.length) { - if (buffer.length < buffer.data.length) + FlatBuffer new_buf = CreateFlatBuffer(buffer.data); + MFreeArray(buffer.data); + *buffer = new_buf; + } + + for(u64 i = 0; i < length; i += 1) + { + if (insert.ptr[i] == '\n') { - Shift(buffer, buffer.data.length); + buffer.line_count += 1; } - GrowBuffer(buffer); } - Shift(buffer, pos); + u64 temp_len = buffer.length-pos; + u8[] temp = AllocArray!(u8)(&buffer.arena, temp_len); + + temp[0 .. temp_len] = buffer.data[pos .. pos+temp_len]; + buffer.data[pos .. pos+length] = insert[0 .. length]; + pos += length; + buffer.data[pos .. pos+temp_len] = temp[0 .. temp_len]; - buffer.data[buffer.gap_start .. buffer.gap_start+length] = insert[0 .. length]; buffer.length += length; - buffer.gap_start += length; - buffer.gap_size -= length; + + Reset(&buffer.arena); } void -Shift(GapBuffer* buffer, i64 pos) +Insert(FlatBuffer* buffer, u8[] insert, u64 length, Range pos) { - if (pos < 0) - { - pos = 0; - } - else if (pos > buffer.length) - { - pos = buffer.length; - } + assert(pos.y <= buffer.line_count, "Insert failure: y provided is greater than line_count"); - u64 old_pos = buffer.gap_start; - u64 new_pos = cast(u64)pos; - - u64 diff; - if (old_pos < new_pos) - { - diff = new_pos - old_pos; - buffer.data[buffer.gap_start .. buffer.gap_start+diff] = buffer.data[buffer.gap_end .. buffer.gap_end+diff]; - buffer.gap_start += diff; - buffer.gap_end += diff; - } - else if (old_pos > new_pos) - { - diff = old_pos - new_pos; - buffer.data[buffer.gap_end-diff .. buffer.gap_end] = buffer.data[buffer.gap_start-diff .. buffer.gap_start]; - buffer.gap_start -= diff; - buffer.gap_end -= diff; - } + Insert(buffer, insert, length, RangeToPos(buffer, pos)); } void -GetLines(GapBuffer* buffer, u8[][] lines, u64 start_line) +GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length) { - Shift(buffer, buffer.data.length); - - u64 count; - u64 start; - foreach(i, ch; buffer.data) + assert(length <= lines.length, "GetLines failure: selection cannot fit within lines buffer"); + assert(start_line < buffer.line_count, "GetLines failure: start is not less than line_count"); + i64 start = -1; + u64 line = 0; + u64 current_line = 0; + for(u64 i = 0; i < buffer.length; i += 1) { - if (count == lines.length) + if (current_line == length) { break; } - if (ch == '\n') + bool new_line = (buffer.data.ptr[i] == '\n'); + if (line < start_line && new_line) { - scope(exit) count += 1; + line += 1; + continue; + } - if (count < start_line) - { - continue; - } + if (start < 0 && new_line) + { + lines[current_line] = buffer.data[i .. i+1]; + current_line += 1; + continue; + } - lines[count][start .. i-start] = buffer.data[start .. i]; - lines[count][i-start] = '\0'; - start = i + 1; + if (start < 0) + { + start = cast(i64)i; + continue; + } + + if (new_line) + { + lines[current_line] = buffer.data[start .. i]; + current_line += 1; + start = -1; + continue; + } + + if (i == buffer.length-1) + { + lines[current_line] = buffer.data[start .. buffer.length]; } } } -void -MoveCursorL(GapBuffer* buffer, u64 length) +u64 +RangeToPos(FlatBuffer* buffer, Range range) { - assert(length, "MoveCursorL Error: 0 length provided"); + u64 buffer_pos; + u32 line, col; + for(u64 i = 0; i < buffer.length; i += 1) + { + if (range.y == line) + { + buffer_pos = i; + break; + } - u64 new_pos = length >= buffer.length ? buffer.length - length : 0; + if (buffer.data.ptr[i] == '\n') + { + line += 1; + } + } + + for(u64 i = buffer_pos; i < buffer.length; i += 1) + { + if (col == range.x) + { + buffer_pos = i; + break; + } + + col += 1; + + assert(buffer.data.ptr[i] != '\n', "Insert FlatBuffer Range failure: x position not in range of line"); + } + + return buffer_pos; +} + +void +Delete(FlatBuffer* buffer, u64 length, u64 pos) +{ + u64 end = pos+length; + assert(end <= buffer.length, "Delete failure: pos+length is not in range"); + + u8[] temp; + if (end != buffer.length) + { + temp = AllocArray!(u8)(&buffer.arena, buffer.length-end); + temp[0 .. temp.length] = buffer.data[end .. buffer.length]; + buffer.data[pos .. pos+temp.length] = temp[0 .. temp.length]; + } + + buffer.length -= length; +} + +void +Replace(FlatBuffer* buffer, u8[] insert, u64 length, u64 pos, u64 delete_length) +{ + Delete(buffer, delete_length, pos); + Insert(buffer, insert, insert.length, pos); } unittest { - // Inserts - { - string test_str = "This is a test string for testing the GapBuffer struct."; - string test_str_2 = "This is an additional string. "; - u8[] data = (cast(u8*)test_str.ptr)[0 .. test_str.length]; - GapBuffer buf = CreateGapBuffer(data); + import std.stdio; - u8[] insert = (cast(u8*)test_str_2.ptr)[0 .. test_str_2.length]; + u8[] StringToU8(string str) + { + return (cast(u8*)str.ptr)[0 .. str.length]; + } + + // FlatBuffer Insert/Delete/Replace + { + u8[] data = StringToU8("This is a test string for testing the FlatBuffer struct."); + FlatBuffer buf = CreateFlatBuffer(data); + + u8[] insert = StringToU8("This is a string inserted into the beginning of the buffer. "); Insert(&buf, insert, insert.length, 0); - u8[][] line_buf = new u8[][](1, 1024); - GetLines(&buf, line_buf, 0); - - u64 count = 0; - foreach(i, ch; test_str_2) - { - assert(buf.data[count] == ch, "Buffer doesn't match test_str_2"); - count += 1; + string result1 = "This is a string inserted into the beginning of the buffer. This is a test string for testing the FlatBuffer struct."; + foreach(i, ch; result1) + { + assert(buf.data[i] == ch, "FlatBuffer Insert failure: buffers do not match"); } - foreach(i, ch; test_str) + Delete(&buf, 17, 34); + + // 10, 21 + string result2 = "This is a string inserted into the buffer. This is a test string for testing the FlatBuffer struct."; + foreach(i, ch; result2) { - assert(buf.data[count] == ch, "Buffer doesn't match test_str"); - count += 1; + assert(buf.data[i] == ch, "FlatBuffer Delete failure: buffers do not match"); } - string test_str_3 = "not "; - insert = (cast(u8*)test_str_3.ptr)[0 .. test_str_3.length]; - Insert(&buf, insert, insert.length, 8); - GetLines(&buf, line_buf, 0); + insert = StringToU8("replaced line inserted into the beginning of "); + Replace(&buf, insert, insert.length, 10, 21); - string result = "This is not an additional string. This is a test string for testing the GapBuffer struct."; - foreach(i, ch; result) + string result3 = "This is a replaced line inserted into the beginning of the buffer. This is a test string for testing the FlatBuffer struct."; + foreach(i, ch; result3) { - assert(buf.data[i] == ch, "Buffer doesn't match result"); + assert(buf.data[i] == ch, "FlatBuffer Replace failure: buffers do not match"); } } - // Grow Buffer + // FlatBuffer lines { - u8[] data; - GapBuffer buf = CreateGapBuffer(data); + u8[] data = StringToU8("This is a line.\nThis is a second line,\nalong with a third line."); + FlatBuffer buf = CreateFlatBuffer(data); - foreach(i; 0 .. buf.data.length) + assert(buf.line_count == 3, "FlatBuffer line count mismatch"); + + u8[] insert = StringToU8("Maybe, "); + Insert(&buf, insert, insert.length, Range(x: 0, y: 1)); + + string result = "This is a line.\nMaybe, This is a second line,\nalong with a third line."; + foreach(i, ch; result) { - Insert(&buf, ['a'], 1, 0); + assert(buf.data[i] == ch, "FlatBuffer Insert pos failure: buffers do not match"); } - foreach(i; 0 .. 1024) + u8[][] lines = new u8[][](3, 1024); + GetLines(&buf, lines, 0, 3); + string[] result_arr = [ + "This is a line.", + "Maybe, This is a second line,", + "along with a third line.", + ]; + + foreach(i, res; result_arr) { - Insert(&buf, ['b'], 1, 0); - } - - u8[][] line_buf = new u8[][](1, 8096); - GetLines(&buf, line_buf, 0); - - foreach(i; 0 .. 5120) - { - if (i < 1024) + foreach(j, ch; res) { - assert(line_buf[0][i] == 'b'); + assert(lines[i][j] == ch, "FlatBuffer GetLines failure: result strings do not match"); } - else + } + + insert = StringToU8("replaced line.\nThis is the previous "); + Insert(&buf, insert, insert.length, Range(x: 10, y: 0)); + lines = new u8[][](4, 1024); + GetLines(&buf, lines, 0, 4); + result_arr = [ + "This is a replaced line.", + "This is the previous line.", + "Maybe, This is a second line,", + "along with a third line.", + ]; + + foreach(i, res; result_arr) + { + foreach(j, ch; res) { - assert(line_buf[0][i] == 'a'); + assert(lines[i][j] == ch, "FlatBuffer GetLines 2 failure: result strings do not match"); } } }