// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// Tree data structure for storing marks at (row, col) positions and updating
// them to arbitrary text changes. Derivative work of kbtree in klib, whose
// copyright notice is reproduced below. Also inspired by the design of the
// marker tree data structure of the Atom editor, regarding efficient updates
// to text changes.
//
// Marks are inserted using marktree_put. Text changes are processed using
// marktree_splice. All read and delete operations use the iterator.
// use marktree_itr_get to put an iterator at a given position or
// marktree_lookup to lookup a mark by its id (iterator optional in this case).
// Use marktree_itr_current and marktree_itr_next/prev to read marks in a loop.
// marktree_del_itr deletes the current mark of the iterator and implicitly
// moves the iterator to the next mark.
//
// Work is ongoing to fully support ranges (mark pairs).
// Copyright notice for kbtree (included in heavily modified form):
//
// Copyright 1997-1999, 2001, John-Mark Gurney.
// 2008-2009, Attractive Chaos <attractor@live.co.uk>
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Changes done by by the neovim project follow the Apache v2 license available
// at the repo root.
#include <assert.h>
#include "nvim/garray.h"
#include "nvim/lib/kvec.h"
#include "nvim/marktree.h"
#define T MT_BRANCH_FACTOR
#define ILEN (sizeof(mtnode_t)+(2 * T) * sizeof(void *))
#define RIGHT_GRAVITY (((uint64_t)1) << 63)
#define ANTIGRAVITY(id) ((id)&(RIGHT_GRAVITY-1))
#define IS_RIGHT(id) ((id)&RIGHT_GRAVITY)
#define PAIRED MARKTREE_PAIRED_FLAG
#define END_FLAG MARKTREE_END_FLAG
#define ID_INCR (((uint64_t)1) << 2)
#define rawkey(itr) (itr->node->key[itr->i])
static bool pos_leq(mtpos_t a, mtpos_t b)
{
return a.row < b.row || (a.row == b.row && a.col <= b.col);
}
static void relative(mtpos_t base, mtpos_t *val)
{
assert(pos_leq(base, *val));
if (val->row == base.row) {
val->row = 0;
val->col -= base.col;
} else {
val->row -= base.row;
}
}
static void unrelative(mtpos_t base, mtpos_t *val)
{
if (val->row == 0) {
val->row = base.row;
val->col += base.col;
} else {
val->row += base.row;
}
}
static void compose(mtpos_t *base, mtpos_t val)
{
if (val.row == 0) {
base->col += val.col;
} else {
base->row += val.row;
base->col = val.col;
}
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "marktree.c.generated.h"
#endif
#define mt_generic_cmp(a, b) (((b) < (a)) - ((a) < (b)))
static int key_cmp(mtkey_t a, mtkey_t b)
{
int cmp = mt_generic_cmp(a.pos.row, b.pos.row);
if (cmp != 0) {
return cmp;
}
cmp = mt_generic_cmp(a.pos.col, b.pos.col);
if (cmp != 0) {
return cmp;
}
// NB: keeping the events at the same pos sorted by id is actually not
// necessary only make sure that START is before END etc.
return mt_generic_cmp(a.id, b.id);
}
static inline int marktree_getp_aux(const mtnode_t *x, mtkey_t k, int *r)
{
int tr, *rr, begin = 0, end = x->n;
if (x->n == 0) {
return -1;
}
rr = r? r : &tr;
while (begin < end) {
int mid = (begin + end) >> 1;
if (key_cmp(x->key[mid], k) < 0) {
begin = mid + 1;
} else {
end = mid;
}
}
if (begin == x->n) {
*rr = 1; return x->n - 1;
}
if ((*rr = key_cmp(k, x->key[begin])) < 0) {
begin--;
}
return begin;
}
static inline void refkey(MarkTree *b, mtnode_t *x, int i)
{
pmap_put(uint64_t)(b->id2node, ANTIGRAVITY(x->key[i].id), x);
}
// put functions
// x must be an internal node, which is not full
// x->ptr[i] should be a full node, i e x->ptr[i]->n == 2*T-1
static inline void split_node(MarkTree *b, mtnode_t *x, const int i)
{
mtnode_t *y = x->ptr[i];
mtnode_t *z;
z = (mtnode_t *)xcalloc(1, y->level ? ILEN : sizeof(mtnode_t));
b->n_nodes++;
z->level = y->level;
z->n = T - 1;
memcpy(z->key, &y->key[T], sizeof(mtkey_t) * (T - 1));
for (int j = 0; j < T-1; j++) {
refkey(b, z, j);
}
if (y->level) {
memcpy(z->ptr, &y->ptr[T], sizeof(mtnode_t *) * T);
for (int j = 0; j < T; j++) {
z->ptr[j]->parent = z;
}
}
y->n = T - 1;
memmove(&x->ptr[i + 2], &x->ptr[i + 1],
sizeof(mtnode_t *) * (size_t)(x->n - i));
x->ptr[i + 1] = z;
z->parent = x; // == y->parent
memmove(&x->key[i + 1], &x->key[i], sizeof(mtkey_t) * (size_t)(x->n - i));
// move key to internal layer:
x->key[i] = y->key[T -
|