Optimize SelectionList::update in the case where changes are backward

This case arise on undo, reverse sorted changes that are not overlapping.
This commit is contained in:
Maxime Coste 2014-06-02 02:16:19 +01:00
parent a5e028e1b1
commit 23a1914d7e

View File

@ -121,35 +121,24 @@ struct PositionChangesTracker
} }
}; };
bool relevant(const Buffer::Change& change, ByteCoord coord)
{
return change.type == Buffer::Change::Insert ? change.begin <= coord
: change.begin < coord;
} }
void SelectionList::update() void update_forward(memoryview<Buffer::Change> changes, std::vector<Selection>& selections)
{ {
if (m_timestamp == m_buffer->timestamp())
return;
auto compare = [](const Buffer::Change& lhs, const Buffer::Change& rhs)
{ return lhs.begin < rhs.begin; };
auto relevant = [](const Buffer::Change& change, const ByteCoord& coord)
{ return change.type == Buffer::Change::Insert ? change.begin <= coord
: change.begin < coord; };
auto changes = m_buffer->changes_since(m_timestamp);
auto change_it = changes.begin();
while (change_it != changes.end())
{
auto change_end = std::is_sorted_until(change_it, changes.end(), compare);
PositionChangesTracker changes_tracker; PositionChangesTracker changes_tracker;
auto change_it = changes.begin();
auto advance_while_relevant = [&](const ByteCoord& pos) mutable { auto advance_while_relevant = [&](const ByteCoord& pos) mutable {
while (relevant(*change_it, pos) and change_it != change_end) while (relevant(*change_it, changes_tracker.get_new_coord(pos)) and
changes_tracker.update(*change_it++); change_it != changes.end())
while (change_it != change_end and
change_it->begin == changes_tracker.last_pos)
changes_tracker.update(*change_it++); changes_tracker.update(*change_it++);
}; };
for (auto& sel : m_selections) for (auto& sel : selections)
{ {
auto& sel_min = sel.min(); auto& sel_min = sel.min();
auto& sel_max = sel.max(); auto& sel_max = sel.max();
@ -159,7 +148,71 @@ void SelectionList::update()
advance_while_relevant(sel_max); advance_while_relevant(sel_max);
sel_max = changes_tracker.get_new_coord(sel_max); sel_max = changes_tracker.get_new_coord(sel_max);
} }
change_it = change_end; }
void update_backward(memoryview<Buffer::Change> changes, std::vector<Selection>& selections)
{
PositionChangesTracker changes_tracker;
using ReverseIt = std::reverse_iterator<const Buffer::Change*>;
auto change_it = ReverseIt(changes.end());
auto change_end = ReverseIt(changes.begin());
auto advance_while_relevant = [&](const ByteCoord& pos) mutable {
while (change_it != change_end)
{
auto change = *change_it;
change.begin = changes_tracker.get_new_coord(change.begin);
change.end = changes_tracker.get_new_coord(change.end);
if (not relevant(change, changes_tracker.get_new_coord(pos)))
break;
changes_tracker.update(change);
++change_it;
}
};
for (auto& sel : selections)
{
auto& sel_min = sel.min();
auto& sel_max = sel.max();
advance_while_relevant(sel_min);
sel_min = changes_tracker.get_new_coord(sel_min);
advance_while_relevant(sel_max);
sel_max = changes_tracker.get_new_coord(sel_max);
}
}
}
void SelectionList::update()
{
if (m_timestamp == m_buffer->timestamp())
return;
auto forward = [](const Buffer::Change& lhs, const Buffer::Change& rhs)
{ return lhs.begin < rhs.begin; };
auto backward = [](const Buffer::Change& lhs, const Buffer::Change& rhs)
{ return lhs.begin > rhs.end; };
auto changes = m_buffer->changes_since(m_timestamp);
auto change_it = changes.begin();
while (change_it != changes.end())
{
auto forward_end = std::is_sorted_until(change_it, changes.end(), forward);
auto backward_end = std::is_sorted_until(change_it, changes.end(), backward);
if (forward_end >= backward_end)
{
update_forward({ change_it, forward_end }, m_selections);
change_it = forward_end;
}
else
{
update_backward({ change_it, backward_end }, m_selections);
change_it = backward_end;
}
kak_assert(std::is_sorted(m_selections.begin(), m_selections.end(),
compare_selections));
} }
for (auto& sel : m_selections) for (auto& sel : m_selections)
{ {