Fix calculation of moves for unsorted queries
This commit is contained in:
parent
d22c65f28a
commit
cfb9f0635c
|
@ -314,44 +314,22 @@ struct RowInfo {
|
||||||
void calculate_moves_unsorted(std::vector<RowInfo>& new_rows, CollectionChangeIndices& changeset,
|
void calculate_moves_unsorted(std::vector<RowInfo>& new_rows, CollectionChangeIndices& changeset,
|
||||||
std::function<bool (size_t)> row_did_change)
|
std::function<bool (size_t)> row_did_change)
|
||||||
{
|
{
|
||||||
std::sort(begin(new_rows), end(new_rows), [](auto& lft, auto& rgt) {
|
|
||||||
return lft.tv_index < rgt.tv_index;
|
|
||||||
});
|
|
||||||
|
|
||||||
IndexSet::IndexInterator ins = changeset.insertions.begin(), del = changeset.deletions.begin();
|
|
||||||
int shift = 0;
|
|
||||||
for (auto& row : new_rows) {
|
for (auto& row : new_rows) {
|
||||||
while (del != changeset.deletions.end() && *del <= row.tv_index) {
|
// Calculate where this row would be with only previous insertions
|
||||||
++del;
|
// and deletions. We can ignore future insertions/deletions from moves
|
||||||
++shift;
|
// because move_last_over() can only move rows to lower indices
|
||||||
}
|
size_t expected = row.prev_tv_index
|
||||||
while (ins != changeset.insertions.end() && *ins <= row.tv_index) {
|
- changeset.deletions.count(0, row.prev_tv_index)
|
||||||
++ins;
|
+ changeset.insertions.count(0, row.tv_index);
|
||||||
--shift;
|
if (row.tv_index != expected) {
|
||||||
}
|
|
||||||
if (row.prev_tv_index == npos)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// For unsorted, non-LV queries a row can only move to an index before
|
|
||||||
// its original position due to a move_last_over
|
|
||||||
if (row.tv_index + shift != row.prev_tv_index) {
|
|
||||||
--shift;
|
|
||||||
changeset.moves.push_back({row.prev_tv_index, row.tv_index});
|
changeset.moves.push_back({row.prev_tv_index, row.tv_index});
|
||||||
|
changeset.insertions.add(row.tv_index);
|
||||||
|
changeset.deletions.add(row.prev_tv_index);
|
||||||
}
|
}
|
||||||
// FIXME: currently move implies modification, and so they're mutally exclusive
|
else if (!changeset.insertions.contains(row.tv_index) && row_did_change(row.shifted_row_index)) {
|
||||||
// this is correct for sorted, but for unsorted a row can move without actually changing
|
changeset.modifications.add(row.tv_index);
|
||||||
else if (row_did_change(row.shifted_row_index)) {
|
|
||||||
// FIXME: needlessly quadratic
|
|
||||||
if (!changeset.insertions.contains(row.tv_index))
|
|
||||||
changeset.modifications.add(row.tv_index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is required for merge(), but it would be nice if it wasn't
|
|
||||||
for (auto&& move : changeset.moves) {
|
|
||||||
changeset.insertions.add(move.to);
|
|
||||||
changeset.deletions.add(move.from);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using items = std::vector<std::pair<size_t, size_t>>;
|
using items = std::vector<std::pair<size_t, size_t>>;
|
||||||
|
@ -421,14 +399,6 @@ void find_longest_matches(items const& a, items const& b_ndx,
|
||||||
void calculate_moves_sorted(std::vector<RowInfo>& new_rows, CollectionChangeIndices& changeset,
|
void calculate_moves_sorted(std::vector<RowInfo>& new_rows, CollectionChangeIndices& changeset,
|
||||||
std::function<bool (size_t)> row_did_change)
|
std::function<bool (size_t)> row_did_change)
|
||||||
{
|
{
|
||||||
// Remove new insertions, as they're already reported in changeset
|
|
||||||
new_rows.erase(std::remove_if(begin(new_rows), end(new_rows),
|
|
||||||
[](auto& row) { return row.prev_tv_index == npos; }),
|
|
||||||
end(new_rows));
|
|
||||||
|
|
||||||
std::sort(begin(new_rows), end(new_rows),
|
|
||||||
[](auto& lft, auto& rgt) { return lft.tv_index < rgt.tv_index; });
|
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> old_candidates;
|
std::vector<std::pair<size_t, size_t>> old_candidates;
|
||||||
std::vector<std::pair<size_t, size_t>> new_candidates;
|
std::vector<std::pair<size_t, size_t>> new_candidates;
|
||||||
for (auto& row : new_rows) {
|
for (auto& row : new_rows) {
|
||||||
|
@ -542,6 +512,12 @@ CollectionChangeBuilder CollectionChangeBuilder::calculate(std::vector<size_t> c
|
||||||
for (; j < new_rows.size(); ++j)
|
for (; j < new_rows.size(); ++j)
|
||||||
ret.insertions.add(new_rows[j].tv_index);
|
ret.insertions.add(new_rows[j].tv_index);
|
||||||
|
|
||||||
|
new_rows.erase(std::remove_if(begin(new_rows), end(new_rows),
|
||||||
|
[](auto& row) { return row.prev_tv_index == npos; }),
|
||||||
|
end(new_rows));
|
||||||
|
std::sort(begin(new_rows), end(new_rows),
|
||||||
|
[](auto& lft, auto& rgt) { return lft.tv_index < rgt.tv_index; });
|
||||||
|
|
||||||
if (sort) {
|
if (sort) {
|
||||||
calculate_moves_sorted(new_rows, ret, row_did_change);
|
calculate_moves_sorted(new_rows, ret, row_did_change);
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,13 @@ TEST_CASE("collection change indices") {
|
||||||
REQUIRE_INDICES(c.deletions, 1);
|
REQUIRE_INDICES(c.deletions, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("mixed insert and delete") {
|
||||||
|
c = _impl::CollectionChangeBuilder::calculate({3, 5}, {0, 3}, all_modified, false);
|
||||||
|
REQUIRE_INDICES(c.deletions, 1);
|
||||||
|
REQUIRE_INDICES(c.insertions, 0);
|
||||||
|
REQUIRE(c.moves.empty());
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("unsorted reordering") {
|
SECTION("unsorted reordering") {
|
||||||
auto calc = [&](std::vector<size_t> values) {
|
auto calc = [&](std::vector<size_t> values) {
|
||||||
return _impl::CollectionChangeBuilder::calculate({1, 2, 3}, values, none_modified, false);
|
return _impl::CollectionChangeBuilder::calculate({1, 2, 3}, values, none_modified, false);
|
||||||
|
|
Loading…
Reference in New Issue