Separate document text and memory.
Text is now a substring of memory, starting at index 0. We now realloc memory when needed and only copy the existing data around instead of allocating a new string, copying all the data and freeing the old string. This leads to possibly less allocation calls, depending on the allocator and less copying necesssary.
This commit is contained in:
parent
f80dc1d35c
commit
ee594a1b2f
60
src/main.zig
60
src/main.zig
@ -70,11 +70,20 @@ pub fn respondGeneric(id: i64, response: []const u8) !void {
|
||||
}
|
||||
|
||||
pub fn openDocument(uri: []const u8, text: []const u8) !void {
|
||||
const du = try std.mem.dupe(allocator, u8, uri);
|
||||
_ = try documents.put(du, .{
|
||||
.uri = du,
|
||||
.text = try std.mem.dupe(allocator, u8, text),
|
||||
const duped_uri = try std.mem.dupe(allocator, u8, uri);
|
||||
const duped_text = try std.mem.dupe(allocator, u8, text);
|
||||
|
||||
const res = try documents.put(duped_uri, .{
|
||||
.uri = duped_uri,
|
||||
.text = duped_text,
|
||||
.mem = duped_text,
|
||||
});
|
||||
|
||||
if (res) |existing_entry| {
|
||||
try log("Opened already open file: {}", .{uri});
|
||||
allocator.free(existing_entry.key);
|
||||
allocator.free(existing_entry.value.mem);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn publishDiagnostics(document: types.TextDocument) !void {
|
||||
@ -304,15 +313,42 @@ pub fn processJsonRpc(json: []const u8) !void {
|
||||
.character = range.Object.getValue("end").?.Object.getValue("character").?.Integer
|
||||
};
|
||||
|
||||
const old_text = document.text;
|
||||
const before = old_text[0..try document.positionToIndex(start_pos)];
|
||||
const after = old_text[try document.positionToIndex(end_pos)..document.text.len];
|
||||
document.text = try std.mem.concat(allocator, u8, &[3][]const u8{ before, change.Object.getValue("text").?.String, after });
|
||||
allocator.free(old_text);
|
||||
const change_text = change.Object.getValue("text").?.String;
|
||||
const start_index = try document.positionToIndex(start_pos);
|
||||
const end_index = try document.positionToIndex(end_pos);
|
||||
|
||||
const old_len = document.text.len;
|
||||
const new_len = old_len + change_text.len;
|
||||
if (new_len > document.mem.len) {
|
||||
// We need to reallocate memory.
|
||||
// We reallocate twice the current filesize or the new length, if it's more than that
|
||||
// so that we can reduce the amount of realloc calls.
|
||||
// We can tune this to find a better size if needed.
|
||||
const realloc_len = std.math.max(2 * old_len, new_len);
|
||||
document.mem = try allocator.realloc(document.mem, realloc_len);
|
||||
}
|
||||
|
||||
// The first part of the string, [0 .. start_index] need not be changed.
|
||||
// We then copy the last part of the string, [end_index ..] to its
|
||||
// new position, [start_index + change_len .. ]
|
||||
std.mem.copy(u8, document.mem[start_index + change_text.len..][0 .. old_len - end_index], document.mem[end_index .. old_len]);
|
||||
// Finally, we copy the changes over.
|
||||
std.mem.copy(u8, document.mem[start_index..][0 .. change_text.len], change_text);
|
||||
|
||||
// Reset the text substring.
|
||||
document.text = document.mem[0 .. new_len];
|
||||
} else {
|
||||
const old_text = document.text;
|
||||
document.text = try std.mem.dupe(allocator, u8, change.Object.getValue("text").?.String);
|
||||
allocator.free(old_text);
|
||||
const change_text = change.Object.getValue("text").?.String;
|
||||
const old_len = document.text.len;
|
||||
|
||||
if (change_text.len > document.mem.len) {
|
||||
// Like above.
|
||||
const realloc_len = std.math.max(2 * old_len, change_text.len);
|
||||
document.mem = try allocator.realloc(document.mem, realloc_len);
|
||||
}
|
||||
|
||||
std.mem.copy(u8, document.mem[0 .. change_text.len], change_text);
|
||||
document.text = document.mem[0 .. change_text.len];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,10 @@ pub const PublishDiagnosticsParams = struct {
|
||||
|
||||
pub const TextDocument = struct {
|
||||
uri: DocumentUri,
|
||||
// This is a substring of mem starting at 0
|
||||
text: String,
|
||||
// This holds the memory that we have actually allocated.
|
||||
mem: []u8,
|
||||
|
||||
pub fn positionToIndex(self: *const TextDocument, position: Position) !usize {
|
||||
var split_iterator = std.mem.split(self.text, "\n");
|
||||
|
Loading…
Reference in New Issue
Block a user