mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	 c3d21ad1bc
			
		
	
	c3d21ad1bc
	
	
	
		
			
			Co-authored-by: Wansmer <wansmer@gmail.com> Co-authored-by: Andrew Voynov <andrewvoynov.b@gmail.com> Co-authored-by: David Moberg <david.moberg@mediatek.com>
		
			
				
	
	
		
			545 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			545 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| local helpers = require("test.unit.helpers")(after_each)
 | |
| local itp = helpers.gen_itp(it)
 | |
| 
 | |
| local ffi     = helpers.ffi
 | |
| local eq      = helpers.eq
 | |
| local ok      = helpers.ok
 | |
| 
 | |
| local lib = helpers.cimport("./src/nvim/marktree.h")
 | |
| 
 | |
| local function tablelength(t)
 | |
|   local count = 0
 | |
|   for _ in pairs(t) do count = count + 1 end
 | |
|   return count
 | |
| end
 | |
| 
 | |
| local function pos_leq(a, b)
 | |
|   return a[1] < b[1] or (a[1] == b[1] and a[2] <= b[2])
 | |
| end
 | |
| 
 | |
| -- Checks that shadow and tree is consistent, and optionally
 | |
| -- return the order
 | |
| local function shadoworder(tree, shadow, iter, giveorder)
 | |
|   ok(iter ~= nil)
 | |
|   local status = lib.marktree_itr_first(tree, iter)
 | |
|   local count = 0
 | |
|   local pos2id, id2pos = {}, {}
 | |
|   local last
 | |
|   if not status and next(shadow) == nil then
 | |
|     return pos2id, id2pos
 | |
|   end
 | |
|   repeat
 | |
|     local mark = lib.marktree_itr_current(iter)
 | |
|     local id = tonumber(mark.id)
 | |
|     local spos = shadow[id]
 | |
|     if (mark.pos.row ~= spos[1] or mark.pos.col ~= spos[2]) then
 | |
|       error("invalid pos for "..id..":("..mark.pos.row..", "..mark.pos.col..") instead of ("..spos[1]..", "..spos[2]..")")
 | |
|     end
 | |
|     if lib.mt_right_test(mark) ~= spos[3] then
 | |
|         error("invalid gravity for "..id..":("..mark.pos.row..", "..mark.pos.col..")")
 | |
|     end
 | |
|     if count > 0 then
 | |
|       if not pos_leq(last, spos) then
 | |
|         error("DISORDER")
 | |
|       end
 | |
|     end
 | |
|     count = count + 1
 | |
|     last = spos
 | |
|     if giveorder then
 | |
|       pos2id[count] = id
 | |
|       id2pos[id] = count
 | |
|     end
 | |
|   until not lib.marktree_itr_next(tree, iter)
 | |
|   local shadowlen = tablelength(shadow)
 | |
|   if shadowlen ~= count then
 | |
|     error("missed some keys? (shadow "..shadowlen..", tree "..count..")")
 | |
|   end
 | |
|   return id2pos, pos2id
 | |
| end
 | |
| 
 | |
| local function shadowsplice(shadow, start, old_extent, new_extent)
 | |
|   local old_end = {start[1] + old_extent[1],
 | |
|                       (old_extent[1] == 0 and start[2] or 0) + old_extent[2]}
 | |
|   local new_end = {start[1] + new_extent[1],
 | |
|                       (new_extent[1] == 0 and start[2] or 0) + new_extent[2]}
 | |
|   local delta = {new_end[1] - old_end[1], new_end[2] - old_end[2]}
 | |
|   for _, pos in pairs(shadow) do
 | |
|     if pos_leq(start, pos) then
 | |
|       if pos_leq(pos, old_end) then
 | |
|         -- delete region
 | |
|         if pos[3] then -- right gravity
 | |
|           pos[1], pos[2] = new_end[1], new_end[2]
 | |
|         else
 | |
|           pos[1], pos[2] = start[1], start[2]
 | |
|         end
 | |
|       else
 | |
|         if pos[1] == old_end[1] then
 | |
|           pos[2] = pos[2] + delta[2]
 | |
|         end
 | |
|         pos[1] = pos[1] + delta[1]
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function dosplice(tree, shadow, start, old_extent, new_extent)
 | |
|   lib.marktree_splice(tree, start[1], start[2], old_extent[1], old_extent[2], new_extent[1], new_extent[2])
 | |
|   shadowsplice(shadow, start, old_extent, new_extent)
 | |
| end
 | |
| 
 | |
| local ns = 10
 | |
| local last_id = nil
 | |
| 
 | |
| local function put(tree, row, col, gravitate, end_row, end_col, end_gravitate)
 | |
|   last_id = last_id + 1
 | |
|   local my_id = last_id
 | |
| 
 | |
|   end_row = end_row or -1
 | |
|   end_col = end_col or -1
 | |
|   end_gravitate = end_gravitate or false
 | |
| 
 | |
|   lib.marktree_put_test(tree, ns, my_id, row, col, gravitate, end_row, end_col, end_gravitate);
 | |
|   return my_id
 | |
| end
 | |
| 
 | |
| describe('marktree', function()
 | |
|   before_each(function()
 | |
|     last_id = 0
 | |
|   end)
 | |
| 
 | |
|   itp('works', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
|     local shadow = {}
 | |
|     local iter = ffi.new("MarkTreeIter[1]")
 | |
|     local iter2 = ffi.new("MarkTreeIter[1]")
 | |
| 
 | |
|     for i = 1,100 do
 | |
|       for j = 1,100 do
 | |
|         local gravitate = (i%2) > 0
 | |
|         local id = put(tree, j, i, gravitate)
 | |
|         ok(id > 0)
 | |
|         eq(nil, shadow[id])
 | |
|         shadow[id] = {j,i,gravitate}
 | |
|       end
 | |
|       -- checking every insert is too slow, but this is ok
 | |
|       lib.marktree_check(tree)
 | |
|     end
 | |
| 
 | |
|     -- ss = lib.mt_inspect_rec(tree)
 | |
|     -- io.stdout:write(ffi.string(ss))
 | |
|     -- io.stdout:flush()
 | |
| 
 | |
|     local id2pos, pos2id = shadoworder(tree, shadow, iter)
 | |
|     eq({}, pos2id) -- not set if not requested
 | |
|     eq({}, id2pos)
 | |
| 
 | |
|     for i,ipos in pairs(shadow) do
 | |
|       local p = lib.marktree_lookup_ns(tree, ns, i, false, iter)
 | |
|       eq(ipos[1], p.pos.row)
 | |
|       eq(ipos[2], p.pos.col)
 | |
|       local k = lib.marktree_itr_current(iter)
 | |
|       eq(ipos[1], k.pos.row)
 | |
|       eq(ipos[2], k.pos.col, ipos[1])
 | |
|       lib.marktree_itr_next(tree, iter)
 | |
|       -- TODO(bfredl): use id2pos to check neighbour?
 | |
|       -- local k2 = lib.marktree_itr_current(iter)
 | |
|     end
 | |
| 
 | |
|     for i,ipos in pairs(shadow) do
 | |
|       lib.marktree_itr_get(tree, ipos[1], ipos[2], iter)
 | |
|       local k = lib.marktree_itr_current(iter)
 | |
|       eq(i, tonumber(k.id))
 | |
|       eq(ipos[1], k.pos.row)
 | |
|       eq(ipos[2], k.pos.col)
 | |
|     end
 | |
| 
 | |
|     ok(lib.marktree_itr_first(tree, iter))
 | |
|     local del = lib.marktree_itr_current(iter)
 | |
| 
 | |
|     lib.marktree_del_itr(tree, iter, false)
 | |
|     shadow[tonumber(del.id)] = nil
 | |
|     shadoworder(tree, shadow, iter)
 | |
| 
 | |
|     for _, ci in ipairs({0,-1,1,-2,2,-10,10}) do
 | |
|       for i = 1,100 do
 | |
|         lib.marktree_itr_get(tree, i, 50+ci, iter)
 | |
|         local k = lib.marktree_itr_current(iter)
 | |
|         local id = tonumber(k.id)
 | |
|         eq(shadow[id][1], k.pos.row)
 | |
|         eq(shadow[id][2], k.pos.col)
 | |
|         lib.marktree_del_itr(tree, iter, false)
 | |
|         shadow[id] = nil
 | |
|       end
 | |
|       lib.marktree_check(tree)
 | |
|       shadoworder(tree, shadow, iter)
 | |
|     end
 | |
| 
 | |
|     -- NB: this is quite rudimentary. We rely on
 | |
|     -- functional tests exercising splicing quite a bit
 | |
|     lib.marktree_check(tree)
 | |
|     dosplice(tree, shadow, {2,2}, {0,5}, {1, 2})
 | |
|     lib.marktree_check(tree)
 | |
|     shadoworder(tree, shadow, iter)
 | |
|     dosplice(tree, shadow, {30,2}, {30,5}, {1, 2})
 | |
|     lib.marktree_check(tree)
 | |
|     shadoworder(tree, shadow, iter)
 | |
| 
 | |
|     dosplice(tree, shadow, {5,3}, {0,2}, {0, 5})
 | |
|     shadoworder(tree, shadow, iter)
 | |
|     lib.marktree_check(tree)
 | |
| 
 | |
|     -- build then burn (HOORAY! HOORAY!)
 | |
|     while next(shadow) do
 | |
|       lib.marktree_itr_first(tree, iter)
 | |
|       -- delete every other key for fun and profit
 | |
|       while true do
 | |
|         local k = lib.marktree_itr_current(iter)
 | |
|         lib.marktree_del_itr(tree, iter, false)
 | |
|         ok(shadow[tonumber(k.id)] ~= nil)
 | |
|         shadow[tonumber(k.id)] = nil
 | |
|         local stat = lib.marktree_itr_next(tree, iter)
 | |
|         if not stat then
 | |
|           break
 | |
|         end
 | |
|       end
 | |
|       lib.marktree_check(tree)
 | |
|       shadoworder(tree, shadow, iter2)
 | |
|     end
 | |
| 
 | |
|     -- Check iterator validity for 2 specific edge cases:
 | |
|     -- https://github.com/neovim/neovim/pull/14719
 | |
|     lib.marktree_clear(tree)
 | |
|     for i = 1,20 do
 | |
|       put(tree, i, i, false)
 | |
|     end
 | |
| 
 | |
|     lib.marktree_itr_get(tree, 10, 10, iter)
 | |
|     lib.marktree_del_itr(tree, iter, false)
 | |
|     eq(11, iter[0].x.key[iter[0].i].pos.col)
 | |
| 
 | |
|     lib.marktree_itr_get(tree, 11, 11, iter)
 | |
|     lib.marktree_del_itr(tree, iter, false)
 | |
|     eq(12, iter[0].x.key[iter[0].i].pos.col)
 | |
|   end)
 | |
| 
 | |
|   itp("'intersect_mov' function works correctly", function()
 | |
|     local function mov(x, y, w)
 | |
|       local xa = ffi.new("uint64_t[?]", #x)
 | |
|       for i, xi in ipairs(x) do xa[i-1] = xi end
 | |
|       local ya = ffi.new("uint64_t[?]", #y)
 | |
|       for i, yi in ipairs(y) do ya[i-1] = yi end
 | |
|       local wa = ffi.new("uint64_t[?]", #w)
 | |
|       for i, wi in ipairs(w) do wa[i-1] = wi end
 | |
| 
 | |
|       local dummy_size = #x + #y + #w
 | |
|       local wouta = ffi.new("uint64_t[?]", dummy_size)
 | |
|       local douta = ffi.new("uint64_t[?]", dummy_size)
 | |
|       local wsize = ffi.new("size_t[1]")
 | |
|       wsize[0] = dummy_size
 | |
|       local dsize = ffi.new("size_t[1]")
 | |
|       dsize[0] = dummy_size
 | |
| 
 | |
|       local status = lib.intersect_mov_test(xa, #x, ya, #y, wa, #w, wouta, wsize, douta, dsize)
 | |
|       if status == 0 then error'wowza' end
 | |
| 
 | |
|       local wout, dout = {}, {}
 | |
|       for i = 0,tonumber(wsize[0])-1 do table.insert(wout, tonumber(wouta[i])) end
 | |
|       for i = 0,tonumber(dsize[0])-1 do table.insert(dout, tonumber(douta[i])) end
 | |
|       return {wout, dout}
 | |
|     end
 | |
| 
 | |
|     eq({{}, {}}, mov({}, {2, 3}, {2, 3}))
 | |
|     eq({{2, 3}, {}}, mov({}, {}, {2, 3}))
 | |
|     eq({{2, 3}, {}}, mov({2, 3}, {}, {}))
 | |
|     eq({{}, {2,3}}, mov({}, {2,3}, {}))
 | |
| 
 | |
|     eq({{1, 5}, {}}, mov({1,2,5}, {2, 3}, {3}))
 | |
|     eq({{1, 2}, {}}, mov({1,2,5}, {5, 10}, {10}))
 | |
|     eq({{1, 2}, {5}}, mov({1,2}, {5, 10}, {10}))
 | |
|     eq({{1,3,5,7,9}, {2,4,6,8,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {}))
 | |
|     eq({{1,3,5,7,9}, {2,6,10}}, mov({1,3,5,7,9}, {2,4,6,8,10}, {4, 8}))
 | |
|     eq({{1,4,7}, {2,5,8}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {}))
 | |
|     eq({{1,4,7}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {2,5,8}))
 | |
|     eq({{0,1,4,7,10}, {}}, mov({1,3,4,6,7,9}, {2,3,5,6,8,9}, {0,2,5,8,10}))
 | |
|   end)
 | |
| 
 | |
| 
 | |
|   local function check_intersections(tree)
 | |
|     lib.marktree_check(tree)
 | |
|     -- to debug stuff disable this branch
 | |
|     if true == true then
 | |
|       ok(lib.marktree_check_intersections(tree))
 | |
|       return
 | |
|     end
 | |
| 
 | |
|     local str1 = lib.mt_inspect(tree, true, true)
 | |
|     local dot1 = ffi.string(str1.data, str1.size)
 | |
| 
 | |
|     local val = lib.marktree_check_intersections(tree)
 | |
|     if not val then
 | |
|       local str2 = lib.mt_inspect(tree, true, true)
 | |
|       local dot2 = ffi.string(str2.data, str2.size)
 | |
|       print("actual:\n\n".."Xafile.dot".."\n\nexpected:\n\n".."Xefile.dot".."\n")
 | |
|       print("nivå", tree[0].root.level);
 | |
|       io.stdout:flush()
 | |
|       local afil = io.open("Xafile.dot", "wb")
 | |
|       afil:write(dot1)
 | |
|       afil:close()
 | |
|       local efil = io.open("Xefile.dot", "wb")
 | |
|       efil:write(dot2)
 | |
|       efil:close()
 | |
|       ok(false)
 | |
|     else
 | |
|       ffi.C.xfree(str1.data)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   itp('works with intersections', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     local ids = {}
 | |
| 
 | |
|     for i = 1,80 do
 | |
|       table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
 | |
|       check_intersections(tree)
 | |
|     end
 | |
|     for i = 1,80 do
 | |
|       lib.marktree_del_pair_test(tree, ns, ids[i])
 | |
|       check_intersections(tree)
 | |
|     end
 | |
|     ids = {}
 | |
| 
 | |
|     for i = 1,80 do
 | |
|       table.insert(ids, put(tree, 1, i, false, 2, 100-i, false))
 | |
|       check_intersections(tree)
 | |
|     end
 | |
| 
 | |
|     for i = 1,10 do
 | |
|       for j = 1,8 do
 | |
|         local ival = (j-1)*10+i
 | |
|         lib.marktree_del_pair_test(tree, ns, ids[ival])
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   itp('works with intersections with a big tree', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     local ids = {}
 | |
| 
 | |
|     for i = 1,1000 do
 | |
|       table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false))
 | |
|       if i % 10 == 1 then
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     check_intersections(tree)
 | |
|     eq(2000, tree[0].n_keys)
 | |
|     ok(tree[0].root.level >= 2)
 | |
| 
 | |
|     local iter = ffi.new("MarkTreeIter[1]")
 | |
| 
 | |
|     local k = 0
 | |
|     for i = 1,20 do
 | |
|       for j = 1,50 do
 | |
|         k = k + 1
 | |
|         local ival = (j-1)*20+i
 | |
|         if false == true then -- if there actually is a failure, this branch will fail out at the actual spot of the error
 | |
|           lib.marktree_lookup_ns(tree, ns, ids[ival], false, iter)
 | |
|           lib.marktree_del_itr(tree, iter, false)
 | |
|           check_intersections(tree)
 | |
| 
 | |
|           lib.marktree_lookup_ns(tree, ns, ids[ival], true, iter)
 | |
|           lib.marktree_del_itr(tree, iter, false)
 | |
|           check_intersections(tree)
 | |
|         else
 | |
|           lib.marktree_del_pair_test(tree, ns, ids[ival])
 | |
|           if k % 5 == 1 then
 | |
|             check_intersections(tree)
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     eq(0, tree[0].n_keys)
 | |
|   end)
 | |
| 
 | |
|   itp('works with intersections and marktree_splice', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     for i = 1,1000 do
 | |
|       put(tree, 1, i, false, 2, 1000-i, false)
 | |
|       if i % 10 == 1 then
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     check_intersections(tree)
 | |
|     eq(2000, tree[0].n_keys)
 | |
|     ok(tree[0].root.level >= 2)
 | |
| 
 | |
|     for _ = 1,10 do
 | |
|       lib.marktree_splice(tree, 0, 0, 0, 100, 0, 0)
 | |
|       check_intersections(tree)
 | |
|     end
 | |
|   end)
 | |
| 
 | |
|   itp('marktree_move should preserve key order', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
|     local iter = ffi.new("MarkTreeIter[1]")
 | |
|     local ids = {}
 | |
| 
 | |
|     -- new index and old index look the same, but still have to move because
 | |
|     -- pos will get updated
 | |
|     table.insert(ids, put(tree, 1, 1, false, 1, 3, false))
 | |
|     table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
 | |
|     table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
 | |
|     table.insert(ids, put(tree, 1, 3, false, 1, 3, false))
 | |
| 
 | |
|     lib.marktree_lookup_ns(tree, ns, ids[3], false, iter)
 | |
|     lib.marktree_move(tree, iter, 1, 2)
 | |
| 
 | |
|     check_intersections(tree)
 | |
|   end)
 | |
| 
 | |
|   itp('works with intersections and marktree_move', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     local ids = {}
 | |
| 
 | |
|     for i = 1,1000 do
 | |
|       table.insert(ids, put(tree, 1, i, false, 2, 1000-i, false))
 | |
|       if i % 10 == 1 then
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     local iter = ffi.new("MarkTreeIter[1]")
 | |
|     for i = 1,1000 do
 | |
|       local which = i%2
 | |
|       lib.marktree_lookup_ns(tree, ns, ids[i], which, iter)
 | |
|       lib.marktree_move(tree, iter, 1+which, 500+i)
 | |
|       if i % 10 == 1 then
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|   end)
 | |
| 
 | |
|   itp('works with intersections with a even bigger tree', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     local ids = {}
 | |
| 
 | |
|     -- too much overhead on ASAN
 | |
|     local size_factor = helpers.is_asan() and 3 or 10
 | |
| 
 | |
|     local at_row = {}
 | |
|     for i = 1, 10 do
 | |
|       at_row[i] = {}
 | |
|     end
 | |
| 
 | |
|     local size = 1000*size_factor
 | |
|     local k = 1
 | |
|     while k <= size do
 | |
|       for row1 = 1,9 do
 | |
|         for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
 | |
|           if k > size then
 | |
|             break
 | |
|           end
 | |
|           local id = put(tree, row1, k, false, row2, size-k, false)
 | |
|           table.insert(ids, id)
 | |
|           for i = row1+1, row2 do
 | |
|             table.insert(at_row[i], id)
 | |
|           end
 | |
|           --if tree[0].root.level == 4 then error("kk"..k) end
 | |
|           if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then
 | |
|             check_intersections(tree)
 | |
|           end
 | |
|           k = k + 1
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     eq(2*size, tree[0].n_keys)
 | |
|     ok(tree[0].root.level >= 3)
 | |
|     check_intersections(tree)
 | |
| 
 | |
|     local iter = ffi.new("MarkTreeIter[1]")
 | |
|     local pair = ffi.new("MTPair[1]")
 | |
|     for i = 1,10 do
 | |
|       -- use array as set and not {[id]=true} map, to detect duplicates
 | |
|       local set = {}
 | |
|       eq(true, ffi.C.marktree_itr_get_overlap(tree, i, 0, iter))
 | |
|       while ffi.C.marktree_itr_step_overlap(tree, iter, pair) do
 | |
|         local id = tonumber(pair[0].start.id)
 | |
|         table.insert(set, id)
 | |
|       end
 | |
|       table.sort(set)
 | |
|       eq(at_row[i], set)
 | |
|     end
 | |
| 
 | |
|     k = 0
 | |
|     for i = 1,100 do
 | |
|       for j = 1,(10*size_factor) do
 | |
|         k = k + 1
 | |
|         local ival = (j-1)*100+i
 | |
|         lib.marktree_del_pair_test(tree, ns, ids[ival])
 | |
|         -- just a few stickprov, if there is trouble we need to check
 | |
|         -- everyone using the code in the "big tree" case above
 | |
|         if k % 100*size_factor == 0 or (k > 3000 and k % 200 == 0) then
 | |
|           check_intersections(tree)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     eq(0, tree[0].n_keys)
 | |
|   end)
 | |
| 
 | |
|   itp('works with intersections with a even bigger tree and splice', function()
 | |
|     local tree = ffi.new("MarkTree[1]") -- zero initialized by luajit
 | |
| 
 | |
|     -- too much overhead on ASAN
 | |
|     local size_factor = helpers.is_asan() and 3 or 10
 | |
| 
 | |
|     local at_row = {}
 | |
|     for i = 1, 10 do
 | |
|       at_row[i] = {}
 | |
|     end
 | |
| 
 | |
|     local size = 1000*size_factor
 | |
|     local k = 1
 | |
|     while k <= size do
 | |
|       for row1 = 1,9 do
 | |
|         for row2 = row1,10 do -- note row2 can be == row1, leads to empty ranges being tested when k > size/2
 | |
|           if k > size then
 | |
|             break
 | |
|           end
 | |
|           local id = put(tree, row1, k, false, row2, size-k, false)
 | |
|           for i = row1+1, row2 do
 | |
|             table.insert(at_row[i], id)
 | |
|           end
 | |
|           --if tree[0].root.level == 4 then error("kk"..k) end
 | |
|           if k % 100*size_factor == 1 or (k < 2000 and k%100 == 1) then
 | |
|             check_intersections(tree)
 | |
|           end
 | |
|           k = k + 1
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     eq(2*size, tree[0].n_keys)
 | |
|     ok(tree[0].root.level >= 3)
 | |
|     check_intersections(tree)
 | |
| 
 | |
|     for _ = 1,10 do
 | |
|       for j = 3, 8 do
 | |
|         lib.marktree_splice(tree, j, 0, 0, 200, 0, 0)
 | |
|         check_intersections(tree)
 | |
|       end
 | |
|     end
 | |
|   end)
 | |
| end)
 |