Skip to content

Commit a2ca546

Browse files
committed
add basic cedar public function [compatible with gse]
1 parent 66eab32 commit a2ca546

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

fn.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,189 @@
44

55
package cedar
66

7+
import (
8+
"errors"
9+
)
10+
11+
var (
12+
// ErrNoKey not have key error
13+
ErrNoKey = errors.New("cedar: not have key")
14+
// ErrNoVal not have value error
15+
ErrNoVal = errors.New("cedar: not have val")
16+
// ErrInvalidKey invalid key error
17+
ErrInvalidKey = errors.New("cedar: invalid key")
18+
// ErrInvalidValue invalid value error
19+
ErrInvalidVal = errors.New("cedar: invalid val")
20+
)
21+
722
func isReduced(reduced ...bool) bool {
823
if len(reduced) > 0 && !reduced[0] {
924
return false
1025
}
1126

1227
return true
1328
}
29+
30+
func (cd *Cedar) get(key []byte, from, pos int) *int {
31+
to := cd.getNode(key, from, pos)
32+
return &cd.array[to].baseV
33+
}
34+
35+
// GetVal get follow node by key, split by update()
36+
func (cd *Cedar) getNode(key []byte, from, pos int, redched ...bool) int {
37+
for ; pos < len(key); pos++ {
38+
if isReduced(redched...) {
39+
value := cd.array[from].baseV
40+
if value >= 0 && value != ValLimit {
41+
to := cd.follow(from, 0)
42+
cd.array[to].baseV = value
43+
}
44+
}
45+
46+
from = cd.follow(from, key[pos])
47+
}
48+
49+
to := from
50+
if cd.array[from].baseV < 0 || !isReduced(redched...) {
51+
to = cd.follow(from, 0)
52+
}
53+
54+
return to
55+
}
56+
57+
// Jump jump a node `from` to another node by following the `path`, split by find()
58+
func (cd *Cedar) Jump(key []byte, from int, reduced ...bool) (to int, err error) {
59+
// pos := 0
60+
// recursively matching the key.
61+
for _, k := range key {
62+
if cd.array[from].baseV >= 0 && isReduced(reduced...) {
63+
return from, ErrNoKey
64+
}
65+
66+
to = cd.array[from].base() ^ int(k)
67+
if cd.array[to].check != from {
68+
return from, ErrNoKey
69+
}
70+
from = to
71+
}
72+
73+
return to, nil
74+
}
75+
76+
// Find key from double array trie, with `from` as the cursor to traverse the nodes.
77+
func (cd *Cedar) Find(key []byte, from int, reduced ...bool) (int, error) {
78+
to, err := cd.Jump(key, from, reduced...)
79+
if isReduced(reduced...) {
80+
if cd.array[from].baseV >= 0 {
81+
if err == nil && to != 0 {
82+
return cd.array[to].baseV, nil
83+
}
84+
return 0, ErrNoKey
85+
}
86+
}
87+
88+
// return the value of the node if `check` is correctly marked fpr the ownership,
89+
// otherwise it means no value is stored.
90+
n := cd.array[cd.array[to].base()]
91+
if n.check != to {
92+
return 0, ErrNoKey
93+
}
94+
return n.baseV, nil
95+
}
96+
97+
// Value get the path value
98+
func (cd *Cedar) Value(path int) (val int, err error) {
99+
val = cd.array[path].baseV
100+
if val >= 0 {
101+
return val, nil
102+
}
103+
104+
to := cd.array[path].base()
105+
if cd.array[to].check == path && cd.array[to].baseV >= 0 {
106+
return cd.array[to].baseV, nil
107+
}
108+
109+
return 0, ErrNoVal
110+
}
111+
112+
// Insert the key for the value
113+
func (cd *Cedar) Insert(key []byte, val int) error {
114+
if val < 0 || val >= ValLimit {
115+
return ErrInvalidVal
116+
}
117+
118+
p := cd.get(key, 0, 0)
119+
*p = val
120+
121+
return nil
122+
}
123+
124+
// Update the key for the value, it is public interface that works on &str
125+
func (cd *Cedar) Update(key []byte, value int, redched ...bool) error {
126+
p := cd.get(key, 0, 0)
127+
128+
if *p == ValLimit && isReduced(redched...) {
129+
*p = value
130+
return nil
131+
}
132+
133+
*p += value
134+
return nil
135+
}
136+
137+
// Delete the key from the trie, the internal interface that works on &[u8]
138+
func (cd *Cedar) Delete(key []byte, redched ...bool) error {
139+
// move the cursor to the right place and use erase__ to delete it.
140+
to, err := cd.Jump(key, 0)
141+
if err != nil {
142+
return ErrNoKey
143+
}
144+
145+
if cd.array[to].baseV < 0 && isReduced(redched...) {
146+
base := cd.array[to].base()
147+
if cd.array[base].check == to {
148+
to = base
149+
}
150+
}
151+
152+
if !isReduced(redched...) {
153+
to = cd.array[to].base()
154+
}
155+
156+
from := to
157+
for to > 0 {
158+
if isReduced(redched...) {
159+
from = cd.array[to].check
160+
}
161+
base := cd.array[from].base()
162+
label := byte(to ^ base)
163+
164+
hasSibling := cd.nInfos[to].sibling != 0 || cd.nInfos[from].child != label
165+
// if the node has siblings, then remove `e` from the sibling.
166+
if hasSibling {
167+
cd.popSibling(from, base, label)
168+
}
169+
170+
// maintain the data structures.
171+
cd.pushENode(to)
172+
// traverse to the parent.
173+
to = from
174+
175+
// if it has sibling then this layer has more than one nodes, then we are done.
176+
if hasSibling {
177+
break
178+
}
179+
}
180+
181+
return nil
182+
}
183+
184+
// Get get the key value
185+
func (cd *Cedar) Get(key []byte) (value int, err error) {
186+
to, err := cd.Jump(key, 0)
187+
if err != nil {
188+
return 0, err
189+
}
190+
191+
return cd.Value(to)
192+
}

0 commit comments

Comments
 (0)