Fix performance of diff-based reloading of buffers
It turns out diffing was pretty fast, but applying the diff was sub-optimal as it was constantly inserting/erasing lines which led to lots of unnecessary shifting. Fix this by manually tracking a read/write iterator and only shifting when necessary (on keeps, and inserts).
This commit is contained in:
parent
68e73d8a24
commit
43e8aadcaa
|
@ -219,40 +219,55 @@ void Buffer::reload(BufferLines lines, ByteOrderMark bom, EolFormat eolformat, F
|
||||||
[](const StringDataPtr& lhs, const StringDataPtr& rhs)
|
[](const StringDataPtr& lhs, const StringDataPtr& rhs)
|
||||||
{ return lhs->strview() == rhs->strview(); });
|
{ return lhs->strview() == rhs->strview(); });
|
||||||
|
|
||||||
auto it = m_lines.begin();
|
auto read_it = m_lines.begin();
|
||||||
|
auto write_it = m_lines.begin();
|
||||||
auto new_it = lines.begin();
|
auto new_it = lines.begin();
|
||||||
for (auto& [op, len] : diff)
|
for (auto [op, len] : diff)
|
||||||
{
|
{
|
||||||
|
kak_assert(read_it >= write_it);
|
||||||
if (op == DiffOp::Keep)
|
if (op == DiffOp::Keep)
|
||||||
{
|
{
|
||||||
it += len;
|
if (read_it != write_it)
|
||||||
|
std::move(read_it, read_it + len, write_it);
|
||||||
|
write_it += len;
|
||||||
|
read_it += len;
|
||||||
new_it += len;
|
new_it += len;
|
||||||
}
|
}
|
||||||
else if (op == DiffOp::Add)
|
else if (op == DiffOp::Add)
|
||||||
{
|
{
|
||||||
const LineCount cur_line = (int)(it - m_lines.begin());
|
const LineCount cur_line = (int)(write_it - m_lines.begin());
|
||||||
|
|
||||||
for (LineCount line = 0; line < len; ++line)
|
for (LineCount line = 0; line < len; ++line)
|
||||||
m_current_undo_group.push_back({Modification::Insert, cur_line + line, *(new_it + (int)line)});
|
m_current_undo_group.push_back({Modification::Insert, cur_line + line, *(new_it + (int)line)});
|
||||||
|
|
||||||
m_changes.push_back({Change::Insert, cur_line, cur_line + len});
|
m_changes.push_back({Change::Insert, cur_line, cur_line + len});
|
||||||
m_lines.insert(it, new_it, new_it + len);
|
|
||||||
it = m_lines.begin() + (int)(cur_line + len);
|
if (read_it != write_it)
|
||||||
|
{
|
||||||
|
auto count = std::min(len, static_cast<int>(read_it - write_it));
|
||||||
|
write_it = std::copy(new_it, new_it + count, write_it);
|
||||||
|
new_it += count;
|
||||||
|
if (len == count)
|
||||||
|
continue;
|
||||||
|
len -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto read_pos = read_it - m_lines.begin();
|
||||||
|
write_it = m_lines.insert(write_it, new_it, new_it + len) + len;
|
||||||
|
read_it = m_lines.begin() + read_pos + len;
|
||||||
new_it += len;
|
new_it += len;
|
||||||
}
|
}
|
||||||
else if (op == DiffOp::Remove)
|
else if (op == DiffOp::Remove)
|
||||||
{
|
{
|
||||||
const LineCount cur_line = (int)(it - m_lines.begin());
|
const LineCount cur_line = (int)(write_it - m_lines.begin());
|
||||||
|
|
||||||
for (LineCount line = len-1; line >= 0; --line)
|
for (LineCount line = len-1; line >= 0; --line)
|
||||||
m_current_undo_group.push_back({
|
m_current_undo_group.push_back({
|
||||||
Modification::Erase, cur_line + line,
|
Modification::Erase, cur_line + line,
|
||||||
m_lines.get_storage(cur_line + line)});
|
m_lines.get_storage(cur_line + line)});
|
||||||
|
|
||||||
it = m_lines.erase(it, it + len);
|
read_it += len;
|
||||||
m_changes.push_back({ Change::Erase, cur_line, cur_line + len });
|
m_changes.push_back({ Change::Erase, cur_line, cur_line + len });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_lines.erase(write_it, m_lines.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
commit_undo_group();
|
commit_undo_group();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user