2026-06-09 21:04:04 +02:00
|
|
|
package treerack
|
|
|
|
|
|
|
|
|
|
type arena struct {
|
|
|
|
|
|
|
|
|
|
// indicates fixed size pages from the pool
|
|
|
|
|
f bool
|
|
|
|
|
|
|
|
|
|
// tolerates pages of different size, but expects the page size to be min w + 1
|
|
|
|
|
p *pool[[]int]
|
|
|
|
|
|
|
|
|
|
// the max size of the stored data blocks. Expected to be larger than 0
|
|
|
|
|
w int
|
|
|
|
|
|
|
|
|
|
// pages storing the cursors for the indexes. The cursors point to the position of the first record
|
|
|
|
|
// for an index in a. The total range of indexes can be larger then the sum of the page lengths,
|
|
|
|
|
// depending on the offset. Initialized to -1, which means a cursor not pointing to a data item
|
2026-06-10 00:43:27 +02:00
|
|
|
// c [][]int
|
|
|
|
|
c []int
|
2026-06-09 21:04:04 +02:00
|
|
|
|
|
|
|
|
// pages storing the records. Every record belongs to an index in c. The size of a record is w
|
|
|
|
|
// + 1, where w fields represent the data, and one field hold the cursor pointing to the next record
|
|
|
|
|
// belonging to the same index. The cursors point to the cursor position, the data fields are before the
|
|
|
|
|
// cursor position. This means 0 is not a valid value for a cursor, and represents an empty record
|
|
|
|
|
// placeholder. The pages in a are initialized to 0. Records are not split between pages
|
2026-06-10 00:43:27 +02:00
|
|
|
// a [][]int
|
|
|
|
|
a []int
|
2026-06-09 21:04:04 +02:00
|
|
|
|
|
|
|
|
// virtual size of c. The actual size is l - o
|
|
|
|
|
l int
|
|
|
|
|
|
|
|
|
|
// offset in between the total virtual range of the indexes and the first index available in c. By
|
|
|
|
|
// default it is 0, until one or more pages are removed from the beginning of c as a result of prune.
|
|
|
|
|
// All the other indicators and the input indexes are interpreted for the total virtual range of the
|
|
|
|
|
// arena
|
|
|
|
|
o int
|
|
|
|
|
|
|
|
|
|
// available size for records. The virtual total length of the pages in a starting from the original
|
|
|
|
|
// zero.
|
|
|
|
|
m int
|
|
|
|
|
|
|
|
|
|
// virutal total size occupied by records. Effectively, the next available position in a, unless s >= m - w -
|
|
|
|
|
// 1
|
|
|
|
|
s int
|
|
|
|
|
|
|
|
|
|
// total size of pages trimmed from the arena
|
|
|
|
|
t int
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func newArena(w int, p *pool[[]int], f bool, size int) *arena {
|
2026-06-09 21:04:04 +02:00
|
|
|
return &arena{
|
|
|
|
|
f: f,
|
|
|
|
|
p: p,
|
|
|
|
|
w: w,
|
2026-06-10 00:43:27 +02:00
|
|
|
c: make([]int, 0, size),
|
|
|
|
|
a: make([]int, 0, size*3),
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) findPosition(pages [][]int, p int) ([]int, int) {
|
|
|
|
|
if a.f {
|
|
|
|
|
if len(pages) == 0 {
|
|
|
|
|
return nil, -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := len(pages[0])
|
|
|
|
|
if p >= s*len(pages) {
|
|
|
|
|
return nil, -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pages[p/s], p % s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len(pages); i++ {
|
|
|
|
|
if p < len(pages[i]) {
|
|
|
|
|
return pages[i], p
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p -= len(pages[i])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil, -1
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func matchValues(v []int, id, to int) bool {
|
|
|
|
|
return v[0] == id && v[1] == to
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) cursor(index int) *int {
|
2026-06-10 00:43:27 +02:00
|
|
|
if len(a.c) <= index {
|
2026-06-09 21:04:04 +02:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
return &a.c[index]
|
2026-06-09 21:04:04 +02:00
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
/*
|
|
|
|
|
index -= a.o
|
|
|
|
|
if index < 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p, i := a.findPosition(a.c, index)
|
|
|
|
|
if i < 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &p[i]
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) stepCursor(c *int) *int {
|
2026-06-10 00:43:27 +02:00
|
|
|
return &a.a[*c]
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
p, i := a.findPosition(a.a, *c-a.t)
|
|
|
|
|
return &p[i]
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) recordAt(c int) []int {
|
2026-06-10 00:43:27 +02:00
|
|
|
return a.a[c-a.w : c+1]
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
p, i := a.findPosition(a.a, c-a.t)
|
|
|
|
|
return p[i-a.w : i+1]
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) allocCursor(index int) {
|
2026-06-10 00:43:27 +02:00
|
|
|
if len(a.c) > index {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cap(a.c) > index {
|
|
|
|
|
l := len(a.c)
|
|
|
|
|
a.c = a.c[:index+1]
|
|
|
|
|
for i := l; i < len(a.c); i++ {
|
|
|
|
|
a.c[i] = -1
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
return
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
2026-06-10 00:43:27 +02:00
|
|
|
|
|
|
|
|
c := make([]int, index+1+index/4)
|
|
|
|
|
copy(c, a.c)
|
|
|
|
|
for i := len(a.c); i < len(c); i++ {
|
|
|
|
|
c[i] = -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.c = c
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
for index >= a.l {
|
|
|
|
|
p := a.p.get()
|
|
|
|
|
for i := range p {
|
|
|
|
|
p[i] = -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.c = append(a.c, p)
|
|
|
|
|
a.l += len(p)
|
|
|
|
|
}
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) allocArena() {
|
2026-06-10 00:43:27 +02:00
|
|
|
/*
|
|
|
|
|
if a.s+a.w+1 <= a.m {
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-06-09 21:04:04 +02:00
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
p := a.p.get()
|
|
|
|
|
for i := range p {
|
|
|
|
|
p[i] = 0
|
|
|
|
|
}
|
2026-06-09 21:04:04 +02:00
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
a.a = append(a.a, p)
|
|
|
|
|
a.m += len(p)
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) append(c, id, to int) int {
|
|
|
|
|
a.a = append(a.a, id, to, c)
|
|
|
|
|
return len(a.a) - 1
|
2026-06-09 21:04:04 +02:00
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
/*
|
|
|
|
|
p := a.a[len(a.a)-1]
|
|
|
|
|
i := a.s - a.m + len(p)
|
|
|
|
|
if i < 0 {
|
|
|
|
|
i = 0
|
|
|
|
|
a.s = a.m - len(p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copy(p[i:i+a.w], v)
|
|
|
|
|
a.s += a.w + 1
|
|
|
|
|
p[i+a.w] = c
|
|
|
|
|
return a.s - 1
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) clearCursor(c *int, id, to int) {
|
2026-06-09 21:04:04 +02:00
|
|
|
for c != nil && *c > 0 {
|
|
|
|
|
r := a.recordAt(*c)
|
2026-06-10 00:43:27 +02:00
|
|
|
if matchValues(r[:len(r)-1], id, to) {
|
2026-06-09 21:04:04 +02:00
|
|
|
*c, r[a.w] = r[a.w], 0
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = a.stepCursor(c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) lastActivePosition(p []int) int {
|
2026-06-10 00:43:27 +02:00
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
for i := len(p) - len(p)%(a.w+1) - 1; i > 0; i -= a.w + 1 {
|
|
|
|
|
if p[i] == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return i
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
return -1
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) trim() {
|
2026-06-10 00:43:27 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
for {
|
|
|
|
|
if len(a.a) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.lastActivePosition(a.a[0]) > 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.p.put(a.a[0])
|
|
|
|
|
a.t += len(a.a[0])
|
|
|
|
|
a.a = a.a[1:]
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
for {
|
|
|
|
|
if len(a.a) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last := len(a.a) - 1
|
|
|
|
|
p := a.lastActivePosition(a.a[last])
|
|
|
|
|
if p > 0 {
|
|
|
|
|
a.s = a.m - len(a.a[last]) + p + 1
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.p.put(a.a[last])
|
|
|
|
|
a.m -= len(a.a[last])
|
|
|
|
|
a.s = a.m
|
|
|
|
|
a.a = a.a[:last]
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
2026-06-10 00:43:27 +02:00
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) len() int {
|
|
|
|
|
return a.l
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) has(index, id, to int) bool {
|
2026-06-09 21:04:04 +02:00
|
|
|
for c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {
|
|
|
|
|
r := a.recordAt(*c)
|
2026-06-10 00:43:27 +02:00
|
|
|
if matchValues(r[:len(r)-1], id, to) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) hasID(index, id int) bool {
|
|
|
|
|
for c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {
|
|
|
|
|
r := a.recordAt(*c)
|
|
|
|
|
if r[0] == id {
|
2026-06-09 21:04:04 +02:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// it does not copy the data
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) get(index, id, to int) [][]int {
|
2026-06-09 21:04:04 +02:00
|
|
|
var values [][]int
|
|
|
|
|
for c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {
|
|
|
|
|
r := a.recordAt(*c)
|
|
|
|
|
v := r[:len(r)-1]
|
2026-06-10 00:43:27 +02:00
|
|
|
if matchValues(v, id, to) {
|
2026-06-09 21:04:04 +02:00
|
|
|
values = append(values, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return values
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) getLargest(index int, id int) int {
|
|
|
|
|
l := -1
|
|
|
|
|
for c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {
|
|
|
|
|
r := a.recordAt(*c)
|
|
|
|
|
if r[0] == id && r[1] > l {
|
|
|
|
|
l = r[1]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return l
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 21:04:04 +02:00
|
|
|
// it does not copy the data
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) set(index, id, to int) {
|
|
|
|
|
if a.has(index, id, to) {
|
2026-06-09 21:04:04 +02:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.allocCursor(index)
|
|
|
|
|
c := a.cursor(index)
|
|
|
|
|
|
|
|
|
|
// index can be in pruned range
|
|
|
|
|
if c == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.allocArena()
|
2026-06-10 00:43:27 +02:00
|
|
|
*c = a.append(*c, id, to)
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
func (a *arena) del(index, id, to int) {
|
2026-06-09 21:04:04 +02:00
|
|
|
c := a.cursor(index)
|
2026-06-10 00:43:27 +02:00
|
|
|
a.clearCursor(c, id, to)
|
2026-06-09 21:04:04 +02:00
|
|
|
a.trim()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (a *arena) prune(from, to int) {
|
2026-06-10 00:43:27 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
var p int
|
|
|
|
|
for _, c := range a.c {
|
|
|
|
|
if p+len(c) <= from-a.o {
|
|
|
|
|
p += len(c)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if p >= to-a.o {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := max(0, from-a.o-p); i < min(len(c), to-a.o-p); i++ {
|
|
|
|
|
a.clearCursor(&c[i])
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 21:04:04 +02:00
|
|
|
p += len(c)
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
for {
|
|
|
|
|
if len(a.c) == 0 {
|
2026-06-09 21:04:04 +02:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
var used bool
|
|
|
|
|
c := a.c[0]
|
|
|
|
|
if a.o+len(c) > to {
|
2026-06-09 21:04:04 +02:00
|
|
|
break
|
|
|
|
|
}
|
2026-06-10 00:43:27 +02:00
|
|
|
|
|
|
|
|
for _, ci := range c {
|
|
|
|
|
if ci > 0 {
|
|
|
|
|
used = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if used {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.o += len(c)
|
|
|
|
|
a.p.put(c)
|
|
|
|
|
a.c = a.c[1:]
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
for {
|
|
|
|
|
if len(a.c) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var used bool
|
|
|
|
|
last := len(a.c) - 1
|
|
|
|
|
c := a.c[last]
|
|
|
|
|
for _, ci := range c {
|
|
|
|
|
if ci > 0 {
|
|
|
|
|
used = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if used {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.l -= len(c)
|
|
|
|
|
a.p.put(c)
|
|
|
|
|
a.c = a.c[:last]
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-10 00:43:27 +02:00
|
|
|
a.trim()
|
|
|
|
|
*/
|
2026-06-09 21:04:04 +02:00
|
|
|
}
|