aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/marktree.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/marktree.c')
-rw-r--r--src/nvim/marktree.c437
1 files changed, 377 insertions, 60 deletions
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index b555b3b4ae..0ebebf409e 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -47,21 +47,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <uv.h>
#include "klib/kvec.h"
-#include "nvim/garray.h"
+#include "nvim/macros_defs.h"
+#include "nvim/map_defs.h"
#include "nvim/marktree.h"
#include "nvim/memory.h"
#include "nvim/pos_defs.h"
// only for debug functions
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/garray.h"
#include "nvim/garray_defs.h"
-#include "nvim/macros_defs.h"
#define T MT_BRANCH_FACTOR
-#define ILEN (sizeof(MTNode) + (2 * T) * sizeof(void *))
+#define ILEN (sizeof(MTNode) + sizeof(struct mtnode_inner_s))
#define ID_INCR (((uint64_t)1) << 2)
@@ -146,7 +147,8 @@ static inline int marktree_getp_aux(const MTNode *x, MTKey k, bool *match)
bool dummy_match;
bool *m = match ? match : &dummy_match;
- int begin = 0, end = x->n;
+ int begin = 0;
+ int end = x->n;
if (x->n == 0) {
*m = false;
return -1;
@@ -179,6 +181,8 @@ static MTNode *id2node(MarkTree *b, uint64_t id)
return pmap_get(uint64_t)(b->id2node, id);
}
+#define ptr s->i_ptr
+#define meta s->i_meta
// put functions
// x must be an internal node, which is not full
@@ -224,15 +228,17 @@ static inline void split_node(MarkTree *b, MTNode *x, const int i, MTKey next)
}
if (y->level) {
memcpy(z->ptr, &y->ptr[T], sizeof(MTNode *) * T);
+ memcpy(z->meta, &y->meta[T], sizeof(z->meta[0]) * T);
for (int j = 0; j < T; j++) {
z->ptr[j]->parent = z;
z->ptr[j]->p_idx = (int16_t)j;
}
}
y->n = T - 1;
- memmove(&x->ptr[i + 2], &x->ptr[i + 1],
- sizeof(MTNode *) * (size_t)(x->n - i));
+ memmove(&x->ptr[i + 2], &x->ptr[i + 1], sizeof(MTNode *) * (size_t)(x->n - i));
+ memmove(&x->meta[i + 2], &x->meta[i + 1], sizeof(x->meta[0]) * (size_t)(x->n - i));
x->ptr[i + 1] = z;
+ meta_describe_node(x->meta[i + 1], z);
z->parent = x; // == y->parent
for (int j = i + 1; j < x->n + 2; j++) {
x->ptr[j]->p_idx = (int16_t)j;
@@ -244,6 +250,13 @@ static inline void split_node(MarkTree *b, MTNode *x, const int i, MTKey next)
refkey(b, x, i);
x->n++;
+ uint32_t meta_inc[4];
+ meta_describe_key(meta_inc, x->key[i]);
+ for (int m = 0; m < kMTMetaCount; m++) {
+ // y used contain all of z and x->key[i], discount those
+ x->meta[i][m] -= (x->meta[i + 1][m] + meta_inc[m]);
+ }
+
for (int j = 0; j < T - 1; j++) {
relative(x->key[i].pos, &z->key[j].pos);
}
@@ -260,7 +273,7 @@ static inline void split_node(MarkTree *b, MTNode *x, const int i, MTKey next)
}
// x must not be a full node (even if there might be internal space)
-static inline void marktree_putp_aux(MarkTree *b, MTNode *x, MTKey k)
+static inline void marktree_putp_aux(MarkTree *b, MTNode *x, MTKey k, uint32_t *meta_inc)
{
// TODO(bfredl): ugh, make sure this is the _last_ valid (pos, gravity) position,
// to minimize movement
@@ -283,7 +296,10 @@ static inline void marktree_putp_aux(MarkTree *b, MTNode *x, MTKey k)
if (i > 0) {
relative(x->key[i - 1].pos, &k.pos);
}
- marktree_putp_aux(b, x->ptr[i], k);
+ marktree_putp_aux(b, x->ptr[i], k, meta_inc);
+ for (int m = 0; m < kMTMetaCount; m++) {
+ x->meta[i][m] += meta_inc[m];
+ }
}
}
@@ -303,7 +319,8 @@ void marktree_put(MarkTree *b, MTKey key, int end_row, int end_col, bool end_rig
|(uint16_t)(end_right ? MT_FLAG_RIGHT_GRAVITY : 0));
end_key.pos = (MTPos){ end_row, end_col };
marktree_put_key(b, end_key);
- MarkTreeIter itr[1] = { 0 }, end_itr[1] = { 0 };
+ MarkTreeIter itr[1] = { 0 };
+ MarkTreeIter end_itr[1] = { 0 };
marktree_lookup(b, mt_lookup_key(key), itr);
marktree_lookup(b, mt_lookup_key(end_key), end_itr);
@@ -413,7 +430,7 @@ void marktree_intersect_pair(MarkTree *b, uint64_t id, MarkTreeIter *itr, MarkTr
}
}
}
- marktree_itr_next_skip(b, itr, skip, true, NULL);
+ marktree_itr_next_skip(b, itr, skip, true, NULL, NULL);
}
#undef iat
}
@@ -426,24 +443,75 @@ static MTNode *marktree_alloc_node(MarkTree *b, bool internal)
return x;
}
+// really meta_inc[kMTMetaCount]
+static void meta_describe_key_inc(uint32_t *meta_inc, MTKey *k)
+{
+ if (!mt_end(*k)) {
+ meta_inc[kMTMetaInline] += (k->flags & MT_FLAG_DECOR_VIRT_TEXT_INLINE) ? 1 : 0;
+ meta_inc[kMTMetaLines] += (k->flags & MT_FLAG_DECOR_VIRT_LINES) ? 1 : 0;
+ meta_inc[kMTMetaSignHL] += (k->flags & MT_FLAG_DECOR_SIGNHL) ? 1 : 0;
+ meta_inc[kMTMetaSignText] += (k->flags & MT_FLAG_DECOR_SIGNTEXT) ? 1 : 0;
+ }
+}
+
+static void meta_describe_key(uint32_t *meta_inc, MTKey k)
+{
+ memset(meta_inc, 0, kMTMetaCount * sizeof(*meta_inc));
+ meta_describe_key_inc(meta_inc, &k);
+}
+
+// if x is internal, asumes x->meta[..] of children are correct
+static void meta_describe_node(uint32_t *meta_node, MTNode *x)
+{
+ memset(meta_node, 0, kMTMetaCount * sizeof(meta_node[0]));
+ for (int i = 0; i < x->n; i++) {
+ meta_describe_key_inc(meta_node, &x->key[i]);
+ }
+ if (x->level) {
+ for (int i = 0; i < x->n + 1; i++) {
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_node[m] += x->meta[i][m];
+ }
+ }
+ }
+}
+
+static bool meta_has(const uint32_t *meta_count, MetaFilter meta_filter)
+{
+ uint32_t count = 0;
+ for (int m = 0; m < kMTMetaCount; m++) {
+ count += meta_count[m] & meta_filter[m];
+ }
+ return count > 0;
+}
+
void marktree_put_key(MarkTree *b, MTKey k)
{
k.flags |= MT_FLAG_REAL; // let's be real.
if (!b->root) {
b->root = marktree_alloc_node(b, true);
}
- b->n_keys++;
MTNode *r = b->root;
if (r->n == 2 * T - 1) {
MTNode *s = marktree_alloc_node(b, true);
b->root = s; s->level = r->level + 1; s->n = 0;
s->ptr[0] = r;
+ for (int m = 0; m < kMTMetaCount; m++) {
+ s->meta[0][m] = b->meta_root[m];
+ }
r->parent = s;
r->p_idx = 0;
split_node(b, s, 0, k);
r = s;
}
- marktree_putp_aux(b, r, k);
+
+ uint32_t meta_inc[4];
+ meta_describe_key(meta_inc, k);
+ marktree_putp_aux(b, r, k, meta_inc);
+ for (int m = 0; m < 4; m++) {
+ b->meta_root[m] += meta_inc[m];
+ }
+ b->n_keys++;
}
/// INITIATING DELETION PROTOCOL:
@@ -495,6 +563,7 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
}
}
+ // 2.
if (itr->x->level) {
if (rev) {
abort();
@@ -509,6 +578,9 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
MTNode *x = itr->x;
assert(x->level == 0);
MTKey intkey = x->key[itr->i];
+
+ uint32_t meta_inc[4];
+ meta_describe_key(meta_inc, intkey);
if (x->n > itr->i + 1) {
memmove(&x->key[itr->i], &x->key[itr->i + 1],
sizeof(MTKey) * (size_t)(x->n - itr->i - 1));
@@ -554,11 +626,16 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
}
}
+ for (int m = 0; m < kMTMetaCount; m++) {
+ p->meta[lnode->p_idx][m] -= meta_inc[m];
+ }
+
lnode = p;
ilvl--;
} while (lnode != cur);
MTKey deleted = cur->key[curi];
+ meta_describe_key(meta_inc, deleted);
cur->key[curi] = intkey;
refkey(b, cur, curi);
// if `did_bubble` then we already added `start_id` to some parent
@@ -583,6 +660,20 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
itr->i--;
}
+ MTNode *lnode = cur;
+ while (lnode->parent) {
+ uint32_t *meta_p = lnode->parent->meta[lnode->p_idx];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_p[m] -= meta_inc[m];
+ }
+
+ lnode = lnode->parent;
+ }
+ for (int m = 0; m < kMTMetaCount; m++) {
+ assert(b->meta_root[m] >= meta_inc[m]);
+ b->meta_root[m] -= meta_inc[m];
+ }
+
// 5.
bool itr_dirty = false;
int rlvl = itr->lvl - 1;
@@ -643,6 +734,10 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
if (b->root->level) {
MTNode *oldroot = b->root;
b->root = b->root->ptr[0];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ assert(b->meta_root[m] == oldroot->meta[0][m]);
+ }
+
b->root->parent = NULL;
marktree_free_node(b, oldroot);
} else {
@@ -679,13 +774,44 @@ uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
return other;
}
+void marktree_revise_flags(MarkTree *b, MarkTreeIter *itr, uint16_t new_flags)
+{
+ uint32_t meta_old[4];
+ meta_describe_key(meta_old, rawkey(itr));
+ rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK;
+ rawkey(itr).flags |= new_flags;
+
+ uint32_t meta_new[4];
+ meta_describe_key(meta_new, rawkey(itr));
+
+ if (!memcmp(meta_old, meta_new, sizeof(meta_old))) {
+ return;
+ }
+
+ MTNode *lnode = itr->x;
+ while (lnode->parent) {
+ uint32_t *meta_p = lnode->parent->meta[lnode->p_idx];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_p[m] += meta_new[m] - meta_old[m];
+ }
+
+ lnode = lnode->parent;
+ }
+
+ for (int m = 0; m < kMTMetaCount; m++) {
+ b->meta_root[m] += meta_new[m] - meta_old[m];
+ }
+}
+
/// similar to intersect_common but modify x and y in place to retain
/// only the items which are NOT in common
static void intersect_merge(Intersection *restrict m, Intersection *restrict x,
Intersection *restrict y)
{
- size_t xi = 0, yi = 0;
- size_t xn = 0, yn = 0;
+ size_t xi = 0;
+ size_t yi = 0;
+ size_t xn = 0;
+ size_t yn = 0;
while (xi < kv_size(*x) && yi < kv_size(*y)) {
if (kv_A(*x, xi) == kv_A(*y, yi)) {
// TODO(bfredl): kvi_pushp is actually quite complex, break out kvi_resize() to a function?
@@ -717,8 +843,10 @@ static void intersect_merge(Intersection *restrict m, Intersection *restrict x,
static void intersect_mov(Intersection *restrict x, Intersection *restrict y,
Intersection *restrict w, Intersection *restrict d)
{
- size_t wi = 0, yi = 0;
- size_t wn = 0, yn = 0;
+ size_t wi = 0;
+ size_t yi = 0;
+ size_t wn = 0;
+ size_t yn = 0;
size_t xi = 0;
while (wi < kv_size(*w) || xi < kv_size(*x)) {
if (wi < kv_size(*w) && (xi >= kv_size(*x) || kv_A(*x, xi) >= kv_A(*w, wi))) {
@@ -810,7 +938,8 @@ bool intersect_mov_test(const uint64_t *x, size_t nx, const uint64_t *y, size_t
/// intersection: i = x & y
static void intersect_common(Intersection *i, Intersection *x, Intersection *y)
{
- size_t xi = 0, yi = 0;
+ size_t xi = 0;
+ size_t yi = 0;
while (xi < kv_size(*x) && yi < kv_size(*y)) {
if (kv_A(*x, xi) == kv_A(*y, yi)) {
kvi_push(*i, kv_A(*x, xi));
@@ -827,7 +956,8 @@ static void intersect_common(Intersection *i, Intersection *x, Intersection *y)
// inplace union: x |= y
static void intersect_add(Intersection *x, Intersection *y)
{
- size_t xi = 0, yi = 0;
+ size_t xi = 0;
+ size_t yi = 0;
while (xi < kv_size(*x) && yi < kv_size(*y)) {
if (kv_A(*x, xi) == kv_A(*y, yi)) {
xi++;
@@ -854,7 +984,8 @@ static void intersect_add(Intersection *x, Intersection *y)
// inplace asymmetric difference: x &= ~y
static void intersect_sub(Intersection *restrict x, Intersection *restrict y)
{
- size_t xi = 0, yi = 0;
+ size_t xi = 0;
+ size_t yi = 0;
size_t xn = 0;
while (xi < kv_size(*x) && yi < kv_size(*y)) {
if (kv_A(*x, xi) == kv_A(*y, yi)) {
@@ -898,11 +1029,12 @@ static void bubble_up(MTNode *x)
static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
{
- MTNode *x = p->ptr[i], *y = p->ptr[i + 1];
- Intersection m;
- kvi_init(m);
+ MTNode *x = p->ptr[i];
+ MTNode *y = p->ptr[i + 1];
+ Intersection mi;
+ kvi_init(mi);
- intersect_merge(&m, &x->intersect, &y->intersect);
+ intersect_merge(&mi, &x->intersect, &y->intersect);
x->key[x->n] = p->key[i];
refkey(b, x, x->n);
@@ -910,6 +1042,9 @@ static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
relative(p->key[i - 1].pos, &x->key[x->n].pos);
}
+ uint32_t meta_inc[4];
+ meta_describe_key(meta_inc, x->key[x->n]);
+
memmove(&x->key[x->n + 1], y->key, (size_t)y->n * sizeof(MTKey));
for (int k = 0; k < y->n; k++) {
refkey(b, x, x->n + 1 + k);
@@ -919,6 +1054,7 @@ static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
// bubble down: ranges that intersected old-x but not old-y or vice versa
// must be moved to their respective children
memmove(&x->ptr[x->n + 1], y->ptr, ((size_t)y->n + 1) * sizeof(MTNode *));
+ memmove(&x->meta[x->n + 1], y->meta, ((size_t)y->n + 1) * sizeof(y->meta[0]));
for (int k = 0; k < x->n + 1; k++) {
// TODO(bfredl): dedicated impl for "Z |= Y"
for (size_t idx = 0; idx < kv_size(x->intersect); idx++) {
@@ -937,9 +1073,14 @@ static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
}
}
x->n += y->n + 1;
+ for (int m = 0; m < kMTMetaCount; m++) {
+ // x now contains everything of y plus old p->key[i]
+ p->meta[i][m] += (p->meta[i + 1][m] + meta_inc[m]);
+ }
+
memmove(&p->key[i], &p->key[i + 1], (size_t)(p->n - i - 1) * sizeof(MTKey));
- memmove(&p->ptr[i + 1], &p->ptr[i + 2],
- (size_t)(p->n - i - 1) * sizeof(MTKey *));
+ memmove(&p->ptr[i + 1], &p->ptr[i + 2], (size_t)(p->n - i - 1) * sizeof(MTKey *));
+ memmove(&p->meta[i + 1], &p->meta[i + 2], (size_t)(p->n - i - 1) * sizeof(p->meta[0]));
for (int j = i + 1; j < p->n; j++) { // note: one has been deleted
p->ptr[j]->p_idx = (int16_t)j;
}
@@ -950,7 +1091,7 @@ static MTNode *merge_node(MarkTree *b, MTNode *p, int i)
// move of a kvec_withinit_t, messy!
// TODO(bfredl): special case version of intersect_merge(x_out, x_in_m_out, y) to avoid this
- kvi_move(&x->intersect, &m);
+ kvi_move(&x->intersect, &mi);
return x;
}
@@ -975,20 +1116,39 @@ void kvi_move(Intersection *dest, Intersection *src)
// key inside x, if x is the first leaf)
static void pivot_right(MarkTree *b, MTPos p_pos, MTNode *p, const int i)
{
- MTNode *x = p->ptr[i], *y = p->ptr[i + 1];
+ MTNode *x = p->ptr[i];
+ MTNode *y = p->ptr[i + 1];
memmove(&y->key[1], y->key, (size_t)y->n * sizeof(MTKey));
if (y->level) {
memmove(&y->ptr[1], y->ptr, ((size_t)y->n + 1) * sizeof(MTNode *));
+ memmove(&y->meta[1], y->meta, ((size_t)y->n + 1) * sizeof(y->meta[0]));
for (int j = 1; j < y->n + 2; j++) {
y->ptr[j]->p_idx = (int16_t)j;
}
}
+
y->key[0] = p->key[i];
refkey(b, y, 0);
p->key[i] = x->key[x->n - 1];
refkey(b, p, i);
+
+ uint32_t meta_inc_y[4];
+ meta_describe_key(meta_inc_y, y->key[0]);
+ uint32_t meta_inc_x[4];
+ meta_describe_key(meta_inc_x, p->key[i]);
+
+ for (int m = 0; m < kMTMetaCount; m++) {
+ p->meta[i + 1][m] += meta_inc_y[m];
+ p->meta[i][m] -= meta_inc_x[m];
+ }
+
if (x->level) {
y->ptr[0] = x->ptr[x->n];
+ memcpy(y->meta[0], x->meta[x->n], sizeof(y->meta[0]));
+ for (int m = 0; m < kMTMetaCount; m++) {
+ p->meta[i + 1][m] += y->meta[0][m];
+ p->meta[i][m] -= y->meta[0][m];
+ }
y->ptr[0]->parent = y;
y->ptr[0]->p_idx = 0;
}
@@ -1040,7 +1200,8 @@ static void pivot_right(MarkTree *b, MTPos p_pos, MTNode *p, const int i)
static void pivot_left(MarkTree *b, MTPos p_pos, MTNode *p, int i)
{
- MTNode *x = p->ptr[i], *y = p->ptr[i + 1];
+ MTNode *x = p->ptr[i];
+ MTNode *y = p->ptr[i + 1];
// reverse from how we "always" do it. but pivot_left
// is just the inverse of pivot_right, so reverse it literally.
@@ -1056,14 +1217,30 @@ static void pivot_left(MarkTree *b, MTPos p_pos, MTNode *p, int i)
refkey(b, x, x->n);
p->key[i] = y->key[0];
refkey(b, p, i);
+
+ uint32_t meta_inc_x[4];
+ meta_describe_key(meta_inc_x, x->key[x->n]);
+ uint32_t meta_inc_y[4];
+ meta_describe_key(meta_inc_y, p->key[i]);
+ for (int m = 0; m < kMTMetaCount; m++) {
+ p->meta[i][m] += meta_inc_x[m];
+ p->meta[i + 1][m] -= meta_inc_y[m];
+ }
+
if (x->level) {
x->ptr[x->n + 1] = y->ptr[0];
+ memcpy(x->meta[x->n + 1], y->meta[0], sizeof(y->meta[0]));
+ for (int m = 0; m < kMTMetaCount; m++) {
+ p->meta[i + 1][m] -= y->meta[0][m];
+ p->meta[i][m] += y->meta[0][m];
+ }
x->ptr[x->n + 1]->parent = x;
x->ptr[x->n + 1]->p_idx = (int16_t)(x->n + 1);
}
memmove(y->key, &y->key[1], (size_t)(y->n - 1) * sizeof(MTKey));
if (y->level) {
memmove(y->ptr, &y->ptr[1], (size_t)y->n * sizeof(MTNode *));
+ memmove(y->meta, &y->meta[1], (size_t)y->n * sizeof(y->meta[0]));
for (int j = 0; j < y->n; j++) { // note: last item deleted
y->ptr[j]->p_idx = (int16_t)j;
}
@@ -1117,8 +1294,8 @@ void marktree_clear(MarkTree *b)
b->root = NULL;
}
map_destroy(uint64_t, b->id2node);
- *b->id2node = (PMap(uint64_t)) MAP_INIT;
b->n_keys = 0;
+ memset(b->meta_root, 0, kMTMetaCount * sizeof(b->meta_root[0]));
assert(b->n_nodes == 0);
}
@@ -1219,11 +1396,11 @@ void marktree_restore_pair(MarkTree *b, MTKey key)
bool marktree_itr_get(MarkTree *b, int32_t row, int col, MarkTreeIter *itr)
{
- return marktree_itr_get_ext(b, MTPos(row, col), itr, false, false, NULL);
+ return marktree_itr_get_ext(b, MTPos(row, col), itr, false, false, NULL, NULL);
}
bool marktree_itr_get_ext(MarkTree *b, MTPos p, MarkTreeIter *itr, bool last, bool gravity,
- MTPos *oldbase)
+ MTPos *oldbase, MetaFilter meta_filter)
{
if (b->n_keys == 0) {
itr->x = NULL;
@@ -1246,6 +1423,12 @@ bool marktree_itr_get_ext(MarkTree *b, MTPos p, MarkTreeIter *itr, bool last, bo
if (itr->x->level == 0) {
break;
}
+ if (meta_filter) {
+ if (!meta_has(itr->x->meta[itr->i], meta_filter)) {
+ // this takes us to the interal position after the first rejected node
+ break;
+ }
+ }
itr->s[itr->lvl].i = itr->i;
itr->s[itr->lvl].oldcol = itr->pos.col;
@@ -1264,7 +1447,8 @@ bool marktree_itr_get_ext(MarkTree *b, MTPos p, MarkTreeIter *itr, bool last, bo
if (last) {
return marktree_itr_prev(b, itr);
} else if (itr->i >= itr->x->n) {
- return marktree_itr_next(b, itr);
+ // no need for "meta_filter" here, this just goes up one step
+ return marktree_itr_next_skip(b, itr, true, false, NULL, NULL);
}
return true;
}
@@ -1321,16 +1505,21 @@ int marktree_itr_last(MarkTree *b, MarkTreeIter *itr)
bool marktree_itr_next(MarkTree *b, MarkTreeIter *itr)
{
- return marktree_itr_next_skip(b, itr, false, false, NULL);
+ return marktree_itr_next_skip(b, itr, false, false, NULL, NULL);
}
static bool marktree_itr_next_skip(MarkTree *b, MarkTreeIter *itr, bool skip, bool preload,
- MTPos oldbase[])
+ MTPos oldbase[], MetaFilter meta_filter)
{
if (!itr->x) {
return false;
}
itr->i++;
+ if (meta_filter && itr->x->level > 0) {
+ if (!meta_has(itr->x->meta[itr->i], meta_filter)) {
+ skip = true;
+ }
+ }
if (itr->x->level == 0 || skip) {
if (preload && itr->x->level == 0 && skip) {
// skip rest of this leaf node
@@ -1372,14 +1561,98 @@ static bool marktree_itr_next_skip(MarkTree *b, MarkTreeIter *itr, bool skip, bo
if (preload && itr->x->level) {
itr->i = -1;
break;
- } else {
- itr->i = 0;
+ }
+ itr->i = 0;
+ if (meta_filter && itr->x->level) {
+ if (!meta_has(itr->x->meta[0], meta_filter)) {
+ // itr->x has filtered keys but x->ptr[0] does not, don't enter the latter
+ break;
+ }
}
}
}
return true;
}
+bool marktree_itr_get_filter(MarkTree *b, int32_t row, int col, int stop_row, int stop_col,
+ MetaFilter meta_filter, MarkTreeIter *itr)
+{
+ if (!meta_has(b->meta_root, meta_filter)) {
+ return false;
+ }
+ if (!marktree_itr_get_ext(b, MTPos(row, col), itr, false, false, NULL, meta_filter)) {
+ return false;
+ }
+
+ return marktree_itr_check_filter(b, itr, stop_row, stop_col, meta_filter);
+}
+
+/// use after marktree_itr_get_overlap() to continue in a filtered fashion
+///
+/// not strictly needed but steps out to the right parent node where there
+/// might be "start" keys matching the filter ("end" keys are properly handled
+/// by marktree_itr_step_overlap() already)
+bool marktree_itr_step_out_filter(MarkTree *b, MarkTreeIter *itr, MetaFilter meta_filter)
+{
+ if (!meta_has(b->meta_root, meta_filter)) {
+ itr->x = NULL;
+ return false;
+ }
+
+ while (itr->x && itr->x->parent) {
+ if (meta_has(itr->x->parent->meta[itr->x->p_idx], meta_filter)) {
+ return true;
+ }
+
+ itr->i = itr->x->n;
+
+ // no filter needed, just reuse the code path for step to parent
+ marktree_itr_next_skip(b, itr, true, false, NULL, NULL);
+ }
+
+ return itr->x;
+}
+
+bool marktree_itr_next_filter(MarkTree *b, MarkTreeIter *itr, int stop_row, int stop_col,
+ MetaFilter meta_filter)
+{
+ if (!marktree_itr_next_skip(b, itr, false, false, NULL, meta_filter)) {
+ return false;
+ }
+
+ return marktree_itr_check_filter(b, itr, stop_row, stop_col, meta_filter);
+}
+
+const uint32_t meta_map[4] = { MT_FLAG_DECOR_VIRT_TEXT_INLINE, MT_FLAG_DECOR_VIRT_LINES,
+ MT_FLAG_DECOR_SIGNHL, MT_FLAG_DECOR_SIGNTEXT };
+static bool marktree_itr_check_filter(MarkTree *b, MarkTreeIter *itr, int stop_row, int stop_col,
+ MetaFilter meta_filter)
+{
+ MTPos stop_pos = MTPos(stop_row, stop_col);
+
+ uint32_t key_filter = 0;
+ for (int m = 0; m < kMTMetaCount; m++) {
+ key_filter |= meta_map[m]&meta_filter[m];
+ }
+
+ while (true) {
+ if (pos_leq(stop_pos, marktree_itr_pos(itr))) {
+ itr->x = NULL;
+ return false;
+ }
+
+ MTKey k = rawkey(itr);
+ if (!mt_end(k) && (k.flags & key_filter)) {
+ return true;
+ }
+
+ // this skips subtrees, but not keys, thus the outer loop
+ if (!marktree_itr_next_skip(b, itr, false, false, NULL, meta_filter)) {
+ return false;
+ }
+ }
+}
+
bool marktree_itr_prev(MarkTree *b, MarkTreeIter *itr)
{
if (!itr->x) {
@@ -1558,7 +1831,7 @@ bool marktree_itr_step_overlap(MarkTree *b, MarkTreeIter *itr, MTPair *pair)
}
unrelative(itr->pos, &k.pos);
MTKey start = marktree_lookup(b, id, NULL);
- if (pos_less(itr->intersect_pos, start.pos)) {
+ if (pos_leq(itr->intersect_pos, start.pos)) {
continue;
}
*pair = mtpair_from(start, k);
@@ -1590,6 +1863,33 @@ static void swap_keys(MarkTree *b, MarkTreeIter *itr1, MarkTreeIter *itr2, Damag
kvi_push(*damage, ((Damage){ mt_lookup_key(rawkey(itr2)), itr2->x, itr1->x,
itr2->i, itr1->i }));
}
+
+ uint32_t meta_inc_1[4];
+ meta_describe_key(meta_inc_1, rawkey(itr1));
+ uint32_t meta_inc_2[4];
+ meta_describe_key(meta_inc_2, rawkey(itr2));
+
+ if (memcmp(meta_inc_1, meta_inc_2, sizeof(meta_inc_1)) != 0) {
+ MTNode *x1 = itr1->x;
+ MTNode *x2 = itr2->x;
+ while (x1 != x2) {
+ if (x1->level <= x2->level) {
+ // as the root node uniquely has the highest level, x1 cannot be it
+ uint32_t *meta_node = x1->parent->meta[x1->p_idx];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_node[m] += meta_inc_2[m] - meta_inc_1[m];
+ }
+ x1 = x1->parent;
+ }
+ if (x2->level < x1->level) {
+ uint32_t *meta_node = x2->parent->meta[x2->p_idx];
+ for (int m = 0; m < kMTMetaCount; m++) {
+ meta_node[m] += meta_inc_1[m] - meta_inc_2[m];
+ }
+ x2 = x2->parent;
+ }
+ }
+ }
}
MTKey key1 = rawkey(itr1);
@@ -1604,7 +1904,8 @@ static void swap_keys(MarkTree *b, MarkTreeIter *itr1, MarkTreeIter *itr2, Damag
static int damage_cmp(const void *s1, const void *s2)
{
- Damage *d1 = (Damage *)s1, *d2 = (Damage *)s2;
+ Damage *d1 = (Damage *)s1;
+ Damage *d2 = (Damage *)s2;
assert(d1->id != d2->id);
return d1->id > d2->id ? 1 : -1;
}
@@ -1620,11 +1921,12 @@ bool marktree_splice(MarkTree *b, int32_t start_line, int start_col, int old_ext
bool same_line = old_extent.row == 0 && new_extent.row == 0;
unrelative(start, &old_extent);
unrelative(start, &new_extent);
- MarkTreeIter itr[1] = { 0 }, enditr[1] = { 0 };
+ MarkTreeIter itr[1] = { 0 };
+ MarkTreeIter enditr[1] = { 0 };
MTPos oldbase[MT_MAX_DEPTH] = { 0 };
- marktree_itr_get_ext(b, start, itr, false, true, oldbase);
+ marktree_itr_get_ext(b, start, itr, false, true, oldbase, NULL);
if (!itr->x) {
// den e FÄRDIG
return false;
@@ -1637,7 +1939,7 @@ bool marktree_splice(MarkTree *b, int32_t start_line, int start_col, int old_ext
if (!pos_leq(old_extent, ipos)
|| (old_extent.row == ipos.row && old_extent.col == ipos.col
&& !mt_right(rawkey(itr)))) {
- marktree_itr_get_ext(b, old_extent, enditr, true, true, NULL);
+ marktree_itr_get_ext(b, old_extent, enditr, true, true, NULL, NULL);
assert(enditr->x);
// "assert" (itr <= enditr)
} else {
@@ -1692,7 +1994,7 @@ continue_same_node:
oldbase[itr->lvl + 1] = rawkey(itr).pos;
unrelative(oldbase[itr->lvl], &oldbase[itr->lvl + 1]);
rawkey(itr).pos = loc_start;
- marktree_itr_next_skip(b, itr, false, false, oldbase);
+ marktree_itr_next_skip(b, itr, false, false, oldbase, NULL);
} else {
rawkey(itr).pos = loc_start;
if (itr->i < itr->x->n - 1) {
@@ -1725,7 +2027,7 @@ past_continue_same_node:
oldbase[itr->lvl + 1] = oldpos;
unrelative(oldbase[itr->lvl], &oldbase[itr->lvl + 1]);
- marktree_itr_next_skip(b, itr, false, false, oldbase);
+ marktree_itr_next_skip(b, itr, false, false, oldbase, NULL);
} else {
if (itr->i < itr->x->n - 1) {
itr->i++;
@@ -1760,7 +2062,7 @@ past_continue_same_node:
if (done) {
break;
}
- marktree_itr_next_skip(b, itr, true, false, NULL);
+ marktree_itr_next_skip(b, itr, true, false, NULL, NULL);
}
if (kv_size(damage)) {
@@ -1825,11 +2127,12 @@ past_continue_same_node:
void marktree_move_region(MarkTree *b, int start_row, colnr_T start_col, int extent_row,
colnr_T extent_col, int new_row, colnr_T new_col)
{
- MTPos start = { start_row, start_col }, size = { extent_row, extent_col };
+ MTPos start = { start_row, start_col };
+ MTPos size = { extent_row, extent_col };
MTPos end = size;
unrelative(start, &end);
MarkTreeIter itr[1] = { 0 };
- marktree_itr_get_ext(b, start, itr, false, true, NULL);
+ marktree_itr_get_ext(b, start, itr, false, true, NULL, NULL);
kvec_t(MTKey) saved = KV_INITIAL_VALUE;
while (itr->x) {
MTKey k = marktree_itr_current(itr);
@@ -1957,13 +2260,10 @@ MTPos marktree_get_altpos(MarkTree *b, MTKey mark, MarkTreeIter *itr)
return marktree_get_alt(b, mark, itr).pos;
}
+/// @return alt mark for a paired mark or mark itself for unpaired mark
MTKey marktree_get_alt(MarkTree *b, MTKey mark, MarkTreeIter *itr)
{
- MTKey end = MT_INVALID_KEY;
- if (mt_paired(mark)) {
- end = marktree_lookup_ns(b, mark.ns, mark.id, !mt_end(mark), itr);
- }
- return end;
+ return mt_paired(mark) ? marktree_lookup_ns(b, mark.ns, mark.id, !mt_end(mark), itr) : mark;
}
static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr)
@@ -1984,9 +2284,12 @@ static void marktree_itr_fix_pos(MarkTree *b, MarkTreeIter *itr)
// for unit test
void marktree_put_test(MarkTree *b, uint32_t ns, uint32_t id, int row, int col, bool right_gravity,
- int end_row, int end_col, bool end_right)
+ int end_row, int end_col, bool end_right, bool meta_inline)
{
- uint16_t flags = mt_flags(right_gravity, false, false, false);
+ uint16_t flags = mt_flags(right_gravity, false, false, false, false);
+ // The specific choice is irrelevant here, we pick one counted decor
+ // type to test the counting and filtering logic.
+ flags |= meta_inline ? MT_FLAG_DECOR_VIRT_TEXT_INLINE : 0;
MTKey key = { { row, col }, ns, id, flags, { .hl = DECOR_HIGHLIGHT_INLINE_INIT } };
marktree_put(b, key, end_row, end_col, end_right);
}
@@ -2021,7 +2324,8 @@ void marktree_check(MarkTree *b)
MTPos dummy;
bool last_right = false;
- size_t nkeys = marktree_check_node(b, b->root, &dummy, &last_right);
+
+ size_t nkeys = marktree_check_node(b, b->root, &dummy, &last_right, b->meta_root);
assert(b->n_keys == nkeys);
assert(b->n_keys == map_size(b->id2node));
#else
@@ -2031,7 +2335,8 @@ void marktree_check(MarkTree *b)
}
#ifndef NDEBUG
-size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right)
+size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right,
+ const uint32_t *meta_node_ref)
{
assert(x->n <= 2 * T - 1);
// TODO(bfredl): too strict if checking "in repair" post-delete tree.
@@ -2040,7 +2345,7 @@ size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right
for (int i = 0; i < x->n; i++) {
if (x->level) {
- n_keys += marktree_check_node(b, x->ptr[i], last, last_right);
+ n_keys += marktree_check_node(b, x->ptr[i], last, last_right, x->meta[i]);
} else {
*last = (MTPos) { 0, 0 };
}
@@ -2057,7 +2362,7 @@ size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right
}
if (x->level) {
- n_keys += marktree_check_node(b, x->ptr[x->n], last, last_right);
+ n_keys += marktree_check_node(b, x->ptr[x->n], last, last_right, x->meta[x->n]);
unrelative(x->key[x->n - 1].pos, last);
for (int i = 0; i < x->n + 1; i++) {
@@ -2072,6 +2377,13 @@ size_t marktree_check_node(MarkTree *b, MTNode *x, MTPos *last, bool *last_right
} else if (x->n > 0) {
*last = x->key[x->n - 1].pos;
}
+
+ uint32_t meta_node[4];
+ meta_describe_node(meta_node, x);
+ for (int m = 0; m < kMTMetaCount; m++) {
+ assert(meta_node_ref[m] == meta_node[m]);
+ }
+
return n_keys;
}
@@ -2201,7 +2513,12 @@ String mt_inspect(MarkTree *b, bool keys, bool dot)
return ga_take_string(ga);
}
-void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
+static inline uint64_t mt_dbg_id(uint64_t id)
+{
+ return (id >> 1) & 0xffffffff;
+}
+
+static void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
{
static char buf[1024];
GA_PUT("[");
@@ -2241,7 +2558,7 @@ void mt_inspect_node(MarkTree *b, garray_T *ga, bool keys, MTNode *n, MTPos off)
ga_concat(ga, "]");
}
-void mt_inspect_dotfile_node(MarkTree *b, garray_T *ga, MTNode *n, MTPos off, char *parent)
+static void mt_inspect_dotfile_node(MarkTree *b, garray_T *ga, MTNode *n, MTPos off, char *parent)
{
static char buf[1024];
char namebuf[64];