patch 9.1.1435: completion: various flaws in fuzzy completion
Problem: completion: various flaws in fuzzy completion Solution: fix the issues (Girish Palya) - Remove the brittle `qsort()` on `compl_match_array`. - Add a stable, non-recursive `mergesort` for the internal doubly linked list of matches. - The sort now happens directly on the internal representation (`compl_T`), preserving sync with external structures and making sorting stable. - Update fuzzy match logic to enforce `max_matches` limits after sorting. - Remove `trim_compl_match_array()`, which is no longer necessary. - Fixe test failures by correctly setting `selected` index and maintaining match consistency. - Introduce `mergesort_list()` in `misc2.c`, which operates generically over doubly linked lists. - Remove `pum_score` and `pum_idx` variables fixes: #17387 closes: #17430 Signed-off-by: Girish Palya <girishji@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
738df3887f
commit
8cd42a58b4
124
src/misc2.c
124
src/misc2.c
@ -3202,3 +3202,127 @@ cmp_keyvalue_value_ni(const void *a, const void *b)
|
||||
kv2->value.length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterative merge sort for doubly linked list.
|
||||
* O(NlogN) worst case, and stable.
|
||||
* - The list is divided into blocks of increasing size (1, 2, 4, 8, ...).
|
||||
* - Each pair of blocks is merged in sorted order.
|
||||
* - Merged blocks are reconnected to build the sorted list.
|
||||
*/
|
||||
void *
|
||||
mergesort_list(
|
||||
void *head,
|
||||
void *(*get_next)(void *),
|
||||
void (*set_next)(void *, void *),
|
||||
void *(*get_prev)(void *),
|
||||
void (*set_prev)(void *, void *),
|
||||
int (*compare)(const void *, const void *))
|
||||
{
|
||||
if (!head || !get_next(head))
|
||||
return head;
|
||||
|
||||
// Count length
|
||||
int n = 0;
|
||||
void* curr = head;
|
||||
while (curr)
|
||||
{
|
||||
n++;
|
||||
curr = get_next(curr);
|
||||
}
|
||||
|
||||
int size;
|
||||
for (size = 1; size < n; size *= 2)
|
||||
{
|
||||
void* new_head = NULL;
|
||||
void* tail = NULL;
|
||||
curr = head;
|
||||
|
||||
while (curr)
|
||||
{
|
||||
// Split two runs
|
||||
void *left = curr;
|
||||
void *right = left;
|
||||
int i;
|
||||
for (i = 0; i < size && right; ++i)
|
||||
right = get_next(right);
|
||||
|
||||
void *next = right;
|
||||
for (i = 0; i < size && next; ++i)
|
||||
next = get_next(next);
|
||||
|
||||
// Break links
|
||||
void *l_end = right ? get_prev(right) : NULL;
|
||||
if (l_end)
|
||||
set_next(l_end, NULL);
|
||||
if (right)
|
||||
set_prev(right, NULL);
|
||||
|
||||
void *r_end = next ? get_prev(next) : NULL;
|
||||
if (r_end)
|
||||
set_next(r_end, NULL);
|
||||
if (next)
|
||||
set_prev(next, NULL);
|
||||
|
||||
// Merge
|
||||
void *merged = NULL;
|
||||
void *merged_tail = NULL;
|
||||
|
||||
while (left || right)
|
||||
{
|
||||
void *chosen = NULL;
|
||||
if (!left)
|
||||
{
|
||||
chosen = right;
|
||||
right = get_next(right);
|
||||
}
|
||||
else if (!right)
|
||||
{
|
||||
chosen = left;
|
||||
left = get_next(left);
|
||||
}
|
||||
else if (compare(left, right) <= 0)
|
||||
{
|
||||
chosen = left;
|
||||
left = get_next(left);
|
||||
}
|
||||
else
|
||||
{
|
||||
chosen = right;
|
||||
right = get_next(right);
|
||||
}
|
||||
|
||||
if (merged_tail)
|
||||
{
|
||||
set_next(merged_tail, chosen);
|
||||
set_prev(chosen, merged_tail);
|
||||
merged_tail = chosen;
|
||||
}
|
||||
else
|
||||
{
|
||||
merged = merged_tail = chosen;
|
||||
set_prev(chosen, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to full list
|
||||
if (!new_head)
|
||||
new_head = merged;
|
||||
else
|
||||
{
|
||||
set_next(tail, merged);
|
||||
set_prev(merged, tail);
|
||||
}
|
||||
|
||||
// Move tail to end
|
||||
while (get_next(merged_tail))
|
||||
merged_tail = get_next(merged_tail);
|
||||
tail = merged_tail;
|
||||
|
||||
curr = next;
|
||||
}
|
||||
|
||||
head = new_head;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user