kbtree: allow iterators to start at arbitrary position

This commit is contained in:
Björn Linse 2016-07-29 20:27:50 +02:00
parent 1eff241ec6
commit 6712e08bba
3 changed files with 83 additions and 23 deletions

View File

@ -74,6 +74,12 @@
#include "nvim/os/time.h" #include "nvim/os/time.h"
#include "nvim/os/input.h" #include "nvim/os/input.h"
typedef enum {
kBLSUnchanged = 0,
kBLSChanged = 1,
kBLSDeleted = 2,
} BufhlLineStatus;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.c.generated.h" # include "buffer.c.generated.h"
#endif #endif
@ -5228,21 +5234,21 @@ void bufhl_clear_line_range(buf_T *buf,
return; return;
} }
linenr_T first_changed = MAXLNUM, last_changed = -1; linenr_T first_changed = MAXLNUM, last_changed = -1;
// TODO: implement kb_itr_interval and jump directly to the first line
kbitr_t itr; kbitr_t itr;
BufhlLine *l; BufhlLine *l, t = {line_start};
for (kb_itr_first(bufhl, buf->b_bufhl_info, &itr); if (!kb_itr_get(bufhl, buf->b_bufhl_info, &t, &itr)) {
kb_itr_valid(&itr); kb_itr_next(bufhl, buf->b_bufhl_info, &itr);
kb_itr_next(bufhl, buf->b_bufhl_info, &itr)) { }
for (; kb_itr_valid(&itr); kb_itr_next(bufhl, buf->b_bufhl_info, &itr)) {
l = kb_itr_key(BufhlLine *, &itr); l = kb_itr_key(BufhlLine *, &itr);
linenr_T line = l->line; linenr_T line = l->line;
if (line < line_start) { if (line > line_end) {
continue;
} else if (line > line_end) {
break; break;
} }
if (line_start <= line && line <= line_end) { if (line_start <= line && line <= line_end) {
if (bufhl_clear_line(buf->b_bufhl_info, src_id, line)) { BufhlLineStatus status = bufhl_clear_line(buf->b_bufhl_info, src_id, line);
if (status != kBLSUnchanged) {
if (line > last_changed) { if (line > last_changed) {
last_changed = line; last_changed = line;
} }
@ -5250,6 +5256,9 @@ void bufhl_clear_line_range(buf_T *buf,
first_changed = line; first_changed = line;
} }
} }
if (status == kBLSDeleted) {
kb_del_itr(bufhl, buf->b_bufhl_info, &itr);
}
} }
} }
@ -5264,8 +5273,8 @@ void bufhl_clear_line_range(buf_T *buf,
/// @param bufhl_info The highlight info for the buffer /// @param bufhl_info The highlight info for the buffer
/// @param src_id Highlight source group to clear, or -1 to clear all groups. /// @param src_id Highlight source group to clear, or -1 to clear all groups.
/// @param lnum Linenr where the highlight should be cleared /// @param lnum Linenr where the highlight should be cleared
static bool bufhl_clear_line(bufhl_info_T *bufhl_info, int src_id, static BufhlLineStatus bufhl_clear_line(bufhl_info_T *bufhl_info, int src_id,
linenr_T lnum) linenr_T lnum)
{ {
BufhlLine *lineinfo = bufhl_tree_ref(bufhl_info, lnum, false); BufhlLine *lineinfo = bufhl_tree_ref(bufhl_info, lnum, false);
size_t oldsize = kv_size(lineinfo->items); size_t oldsize = kv_size(lineinfo->items);
@ -5286,9 +5295,9 @@ static bool bufhl_clear_line(bufhl_info_T *bufhl_info, int src_id,
if (kv_size(lineinfo->items) == 0) { if (kv_size(lineinfo->items) == 0) {
kv_destroy(lineinfo->items); kv_destroy(lineinfo->items);
kb_del(bufhl, bufhl_info, lineinfo); return kBLSDeleted;
} }
return kv_size(lineinfo->items) != oldsize; return kv_size(lineinfo->items) != oldsize ? kBLSChanged : kBLSUnchanged;
} }
/// Remove all highlights and free the highlight data /// Remove all highlights and free the highlight data
@ -5315,15 +5324,19 @@ void bufhl_mark_adjust(buf_T* buf,
// we need to detect this case and // we need to detect this case and
kbitr_t itr; kbitr_t itr;
BufhlLine *l; BufhlLine *l, t = {line1};
for (kb_itr_first(bufhl, buf->b_bufhl_info, &itr); if (!kb_itr_get(bufhl, buf->b_bufhl_info, &t, &itr)) {
kb_itr_valid(&itr); kb_itr_next(bufhl, buf->b_bufhl_info, &itr);
kb_itr_next(bufhl, buf->b_bufhl_info, &itr)) { }
for (; kb_itr_valid(&itr); kb_itr_next(bufhl, buf->b_bufhl_info, &itr)) {
l = kb_itr_key(BufhlLine *, &itr); l = kb_itr_key(BufhlLine *, &itr);
if (l->line >= line1 && l->line <= line2) { if (l->line >= line1 && l->line <= line2) {
if (amount == MAXLNUM) { if (amount == MAXLNUM) {
bufhl_clear_line(buf->b_bufhl_info, -1, l->line); if (bufhl_clear_line(buf->b_bufhl_info, -1, l->line) == kBLSDeleted) {
continue; kb_del_itr(bufhl, buf->b_bufhl_info, &itr);
} else {
assert(false);
}
} else { } else {
l->line += amount; l->line += amount;
} }

View File

@ -28,7 +28,7 @@ typedef struct {
colnr_T valid_to; colnr_T valid_to;
} bufhl_lineinfo_T; } bufhl_lineinfo_T;
#define BUFHL_CMP(a, b) (((b)->line - (a)->line)) #define BUFHL_CMP(a, b) (((a)->line - (b)->line))
KBTREE_INIT(bufhl, BufhlLine *, BUFHL_CMP) KBTREE_INIT(bufhl, BufhlLine *, BUFHL_CMP)
typedef kbtree_t(bufhl) bufhl_info_T; typedef kbtree_t(bufhl) bufhl_info_T;
#endif // NVIM_BUFHL_DEFS_H #endif // NVIM_BUFHL_DEFS_H

View File

@ -57,7 +57,9 @@ typedef struct {
int off_key, off_ptr, ilen, elen; \ int off_key, off_ptr, ilen, elen; \
int n, t; \ int n, t; \
int n_keys, n_nodes; \ int n_keys, n_nodes; \
} kbtree_##name##_t; } kbtree_##name##_t; \
#define __KB_INIT(name, key_t) \ #define __KB_INIT(name, key_t) \
static inline kbtree_##name##_t *kb_init_##name(unsigned int size) \ static inline kbtree_##name##_t *kb_init_##name(unsigned int size) \
@ -75,7 +77,7 @@ typedef struct {
b->root = (kbnode_t*)calloc(1, (unsigned int)b->ilen); \ b->root = (kbnode_t*)calloc(1, (unsigned int)b->ilen); \
++b->n_nodes; \ ++b->n_nodes; \
return b; \ return b; \
} } \
#define __kb_destroy(b) do { \ #define __kb_destroy(b) do { \
int i; \ int i; \
@ -346,7 +348,48 @@ typedef struct {
if (itr->p < itr->stack) return 0; \ if (itr->p < itr->stack) return 0; \
if (itr->p->x && itr->p->i < itr->p->x->n) return 1; \ if (itr->p->x && itr->p->i < itr->p->x->n) return 1; \
} \ } \
} } \
static inline int kb_itr_prev_##name(kbtree_##name##_t *b, kbitr_t *itr) \
{ \
if (itr->p < itr->stack) return 0; \
for (;;) { \
while (itr->p->x && itr->p->i >= 0) { \
itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[itr->p->i] : 0; \
itr->p[1].i = itr->p[1].x ? itr->p[1].x->n : -1; \
++itr->p; \
} \
--itr->p; \
if (itr->p < itr->stack) return 0; \
--itr->p->i; \
if (itr->p->x && itr->p->i >= 0) return 1; \
} \
} \
static int kb_itr_getp_##name(kbtree_##name##_t *b, const key_t * __restrict k, kbitr_t *itr) \
{ \
int i, r = 0; \
itr->p = itr->stack; \
itr->p->x = b->root; \
while (itr->p->x) { \
i = __kb_getp_aux_##name(itr->p->x, k, &r); \
itr->p->i = i; \
if (i >= 0 && r == 0) return 1; \
++itr->p->i; \
itr->p[1].x = itr->p->x->is_internal? __KB_PTR(b, itr->p->x)[i + 1] : 0; \
++itr->p; \
} \
return 0; \
} \
static int kb_itr_get_##name(kbtree_##name##_t *b, const key_t k, kbitr_t *itr) \
{ \
return kb_itr_getp_##name(b,&k,itr); \
} \
static inline void kb_del_itr_##name(kbtree_##name##_t *b, kbitr_t *itr) \
{ \
key_t k = kb_itr_key(key_t, itr); \
kb_delp_##name(b, &k); \
kb_itr_getp_##name(b, &k, itr); \
}
#define KBTREE_INIT(name, key_t, __cmp) \ #define KBTREE_INIT(name, key_t, __cmp) \
__KB_TREE_T(name) \ __KB_TREE_T(name) \
@ -373,7 +416,11 @@ typedef struct {
#define kb_intervalp(name, b, k, l, u) kb_intervalp_##name(b, k, l, u) #define kb_intervalp(name, b, k, l, u) kb_intervalp_##name(b, k, l, u)
#define kb_itr_first(name, b, i) kb_itr_first_##name(b, i) #define kb_itr_first(name, b, i) kb_itr_first_##name(b, i)
#define kb_itr_get(name, b, k, i) kb_itr_get_##name(b, k, i)
#define kb_itr_getp(name, b, k, i) kb_itr_getp_##name(b, k, i)
#define kb_itr_next(name, b, i) kb_itr_next_##name(b, i) #define kb_itr_next(name, b, i) kb_itr_next_##name(b, i)
#define kb_itr_prev(name, b, i) kb_itr_prev_##name(b, i)
#define kb_del_itr(name, b, i) kb_del_itr_##name(b, i)
#define kb_itr_key(type, itr) __KB_KEY(type, (itr)->p->x)[(itr)->p->i] #define kb_itr_key(type, itr) __KB_KEY(type, (itr)->p->x)[(itr)->p->i]
#define kb_itr_valid(itr) ((itr)->p >= (itr)->stack) #define kb_itr_valid(itr) ((itr)->p >= (itr)->stack)