setup flatbuffer
This commit is contained in:
parent
2667bba08e
commit
8a01e2d1b9
@ -1 +1 @@
|
|||||||
Subproject commit 3c6d214aa7e3058f8de1a4ff380fd1bb8ce56036
|
Subproject commit 38e4e44b4dbecd8b0cbe878adb4f8da397a1ae45
|
||||||
@ -3,208 +3,283 @@ import math;
|
|||||||
import alloc;
|
import alloc;
|
||||||
import util;
|
import util;
|
||||||
|
|
||||||
struct GapBuffer
|
struct FlatBuffer
|
||||||
{
|
{
|
||||||
|
Arena arena;
|
||||||
u8[] data;
|
u8[] data;
|
||||||
u64 length;
|
u64 length;
|
||||||
u64 gap_start;
|
u64 line_count;
|
||||||
u64 gap_end;
|
|
||||||
u64 gap_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GapBuffer
|
struct Range
|
||||||
CreateGapBuffer(u8[] data)
|
|
||||||
{
|
{
|
||||||
// Match 4k page sizes
|
u32 x;
|
||||||
u64 capacity = RoundUp(cast(u64)data.length, KB(4));
|
u32 y;
|
||||||
if (data.length % KB(4) == 0)
|
}
|
||||||
{
|
|
||||||
capacity += KB(4);
|
FlatBuffer
|
||||||
}
|
CreateFlatBuffer(u8[] data)
|
||||||
|
{
|
||||||
|
u64 capacity = RoundUp(cast(u64)(data.length) * 2, KB(4));
|
||||||
|
|
||||||
u8[] buf = MAllocArray!(u8)(capacity);
|
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,
|
data: buf,
|
||||||
length: data.length,
|
length: cast(u64)data.length,
|
||||||
gap_start: data.length,
|
line_count: line_count,
|
||||||
gap_end: data.length + (capacity - data.length),
|
);
|
||||||
gap_size: capacity - cast(u64)(data.length),
|
|
||||||
};
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 + 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)
|
||||||
{
|
{
|
||||||
Shift(buffer, buffer.data.length);
|
if (insert.ptr[i] == '\n')
|
||||||
|
{
|
||||||
|
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.length += length;
|
||||||
buffer.gap_start += length;
|
|
||||||
buffer.gap_size -= length;
|
Reset(&buffer.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Shift(GapBuffer* buffer, i64 pos)
|
Insert(FlatBuffer* buffer, u8[] insert, u64 length, Range pos)
|
||||||
{
|
{
|
||||||
if (pos < 0)
|
assert(pos.y <= buffer.line_count, "Insert failure: y provided is greater than line_count");
|
||||||
{
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
else if (pos > buffer.length)
|
|
||||||
{
|
|
||||||
pos = buffer.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 old_pos = buffer.gap_start;
|
Insert(buffer, insert, length, RangeToPos(buffer, pos));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GetLines(GapBuffer* buffer, u8[][] lines, u64 start_line)
|
GetLines(FlatBuffer* buffer, u8[][] lines, u64 start_line, u64 length)
|
||||||
{
|
{
|
||||||
Shift(buffer, buffer.data.length);
|
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");
|
||||||
u64 count;
|
i64 start = -1;
|
||||||
u64 start;
|
u64 line = 0;
|
||||||
foreach(i, ch; buffer.data)
|
u64 current_line = 0;
|
||||||
|
for(u64 i = 0; i < buffer.length; i += 1)
|
||||||
{
|
{
|
||||||
if (count == lines.length)
|
if (current_line == length)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch == '\n')
|
bool new_line = (buffer.data.ptr[i] == '\n');
|
||||||
{
|
if (line < start_line && new_line)
|
||||||
scope(exit) count += 1;
|
|
||||||
|
|
||||||
if (count < start_line)
|
|
||||||
{
|
{
|
||||||
|
line += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
lines[count][start .. i-start] = buffer.data[start .. i];
|
if (start < 0 && new_line)
|
||||||
lines[count][i-start] = '\0';
|
{
|
||||||
start = i + 1;
|
lines[current_line] = buffer.data[i .. i+1];
|
||||||
|
current_line += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
u64
|
||||||
MoveCursorL(GapBuffer* buffer, u64 length)
|
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
|
unittest
|
||||||
{
|
{
|
||||||
// Inserts
|
import std.stdio;
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
Insert(&buf, insert, insert.length, 0);
|
||||||
|
|
||||||
u8[][] line_buf = new u8[][](1, 1024);
|
string result1 = "This is a string inserted into the beginning of the buffer. This is a test string for testing the FlatBuffer struct.";
|
||||||
GetLines(&buf, line_buf, 0);
|
foreach(i, ch; result1)
|
||||||
|
|
||||||
u64 count = 0;
|
|
||||||
foreach(i, ch; test_str_2)
|
|
||||||
{
|
{
|
||||||
assert(buf.data[count] == ch, "Buffer doesn't match test_str_2");
|
assert(buf.data[i] == ch, "FlatBuffer Insert failure: buffers do not match");
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
assert(buf.data[i] == ch, "FlatBuffer Delete failure: buffers do not match");
|
||||||
count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string test_str_3 = "not ";
|
insert = StringToU8("replaced line inserted into the beginning of ");
|
||||||
insert = (cast(u8*)test_str_3.ptr)[0 .. test_str_3.length];
|
Replace(&buf, insert, insert.length, 10, 21);
|
||||||
Insert(&buf, insert, insert.length, 8);
|
|
||||||
GetLines(&buf, line_buf, 0);
|
|
||||||
|
|
||||||
string result = "This is not an additional string. This is a test string for testing the GapBuffer struct.";
|
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, "FlatBuffer Replace failure: buffers do not match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlatBuffer lines
|
||||||
|
{
|
||||||
|
u8[] data = StringToU8("This is a line.\nThis is a second line,\nalong with a third line.");
|
||||||
|
FlatBuffer buf = CreateFlatBuffer(data);
|
||||||
|
|
||||||
|
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)
|
foreach(i, ch; result)
|
||||||
{
|
{
|
||||||
assert(buf.data[i] == ch, "Buffer doesn't match result");
|
assert(buf.data[i] == ch, "FlatBuffer Insert pos failure: buffers do not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
foreach(j, ch; res)
|
||||||
|
{
|
||||||
|
assert(lines[i][j] == ch, "FlatBuffer GetLines failure: result strings do not match");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grow Buffer
|
insert = StringToU8("replaced line.\nThis is the previous ");
|
||||||
{
|
Insert(&buf, insert, insert.length, Range(x: 10, y: 0));
|
||||||
u8[] data;
|
lines = new u8[][](4, 1024);
|
||||||
GapBuffer buf = CreateGapBuffer(data);
|
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; 0 .. buf.data.length)
|
foreach(i, res; result_arr)
|
||||||
{
|
{
|
||||||
Insert(&buf, ['a'], 1, 0);
|
foreach(j, ch; res)
|
||||||
}
|
|
||||||
|
|
||||||
foreach(i; 0 .. 1024)
|
|
||||||
{
|
{
|
||||||
Insert(&buf, ['b'], 1, 0);
|
assert(lines[i][j] == ch, "FlatBuffer GetLines 2 failure: result strings do not match");
|
||||||
}
|
|
||||||
|
|
||||||
u8[][] line_buf = new u8[][](1, 8096);
|
|
||||||
GetLines(&buf, line_buf, 0);
|
|
||||||
|
|
||||||
foreach(i; 0 .. 5120)
|
|
||||||
{
|
|
||||||
if (i < 1024)
|
|
||||||
{
|
|
||||||
assert(line_buf[0][i] == 'b');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(line_buf[0][i] == 'a');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user