This repository has been archived by the owner on Feb 8, 2018. It is now read-only.
/
freetree.go
114 lines (91 loc) · 2.79 KB
/
freetree.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright © 2015 Clement 'cmc' Rey <cr.rey.clement@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package freetree
import (
"unsafe"
"github.com/teh-cmc/mmm"
)
// -----------------------------------------------------------------------------
// FreeTree implements a binary search tree with zero GC overhead.
type FreeTree struct {
nodeChunk mmm.MemChunk
dataChunk mmm.MemChunk
root *freeNode
}
// NewFreeTree returns a new FreeTree using the data from a supplied SimpleTree.
func NewFreeTree(st *SimpleTree) (*FreeTree, error) {
nbNodes := st.nodes
nodeChunk, err := mmm.NewMemChunk(freeNode{}, nbNodes)
if err != nil {
return nil, err
}
dataChunk, err := mmm.NewMemChunk(st.root.data, nbNodes)
if err != nil {
return nil, err
}
ft := &FreeTree{nodeChunk: nodeChunk, dataChunk: dataChunk}
for _, n := range st.flattenNodes() {
node := (*freeNode)(unsafe.Pointer(ft.nodeChunk.Pointer(int(n.id))))
node.id = n.id
if n.left != nil {
node.left = nodeChunk.Pointer(int(n.left.id))
}
if n.right != nil {
node.right = nodeChunk.Pointer(int(n.right.id))
}
dataChunk.Write(int(n.id), n.data)
if n == st.root {
ft.root = node
}
}
return ft, nil
}
// Ascend returns the first element in the tree that is == `pivot`.
func (ft FreeTree) Ascend(pivot Comparable) Comparable {
return ft.ascend(pivot)
}
func (ft FreeTree) ascend(pivot Comparable) Comparable {
return ft.root.ascend(pivot, ft.dataChunk)
}
// Flatten returns the content of the tree as a ComparableArray.
func (ft FreeTree) Flatten() ComparableArray {
return ft.flatten()
}
func (ft FreeTree) flatten() ComparableArray {
ca := make(ComparableArray, 0, ft.nodeChunk.NbObjects())
return ft.root.flatten(ca, ft.dataChunk)
}
// Delete deletes the memory chunks associated with the tree.
func (ft *FreeTree) Delete() *FreeTree {
ft.root = nil
ft.dataChunk.Delete()
ft.nodeChunk.Delete()
return nil
}
// -----------------------------------------------------------------------------
type freeNode struct {
id uint
left, right uintptr
}
func (sn *freeNode) ascend(pivot Comparable, dataChunk mmm.MemChunk) Comparable {
if sn == nil {
return nil
}
data := dataChunk.Read(int(sn.id)).(Comparable)
if pivot.Less(data) {
return ((*freeNode)(unsafe.Pointer(sn.left))).ascend(pivot, dataChunk)
} else if data.Less(pivot) {
return ((*freeNode)(unsafe.Pointer(sn.right))).ascend(pivot, dataChunk)
}
return data
}
func (sn *freeNode) flatten(ca ComparableArray, dataChunk mmm.MemChunk) ComparableArray {
if sn == nil {
return ca
}
ca = ((*freeNode)(unsafe.Pointer(sn.left))).flatten(ca, dataChunk)
ca = ((*freeNode)(unsafe.Pointer(sn.right))).flatten(ca, dataChunk)
return append(ca, dataChunk.Read(int(sn.id)).(Comparable))
}