-
Notifications
You must be signed in to change notification settings - Fork 7
/
admin.go
384 lines (351 loc) · 10.1 KB
/
admin.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
// Copyright (c) 2018, The GoKi Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ki
import (
"fmt"
"log"
"strconv"
"strings"
"sync"
"sync/atomic"
)
// admin has infrastructure level code, outside of ki interface
// InitNode initializes the node -- automatically called during Add/Insert
// Child -- sets the This pointer for this node as a Ki interface (pass
// pointer to node as this arg) -- Go cannot always access the true
// underlying type for structs using embedded Ki objects (when these objs
// are receivers to methods) so we need a This interface pointer that
// guarantees access to the Ki interface in a way that always reveals the
// underlying type (e.g., in reflect calls). Calls Init on Ki fields
// within struct, sets their names to the field name, and sets us as their
// parent.
func InitNode(this Ki) {
n := this.AsKi()
this.ClearUpdateFlags()
if n.Ths != this {
n.Ths = this
n.Ths.OnInit()
}
}
// ThisCheck checks that the This pointer is set and issues a warning to
// log if not -- returns error if not set -- called when nodes are added
// and inserted.
func ThisCheck(k Ki) error {
if k.This() == nil {
err := fmt.Errorf("Ki Node %v ThisCheck: node has null 'this' pointer -- must call Init or InitName on root nodes!", k.Name())
log.Println(err)
return err
}
return nil
}
// SetParent just sets parent of node (and inherits update count from
// parent, to keep consistent).
// Assumes not already in a tree or anything.
func SetParent(kid Ki, parent Ki) {
n := kid.AsKi()
n.Par = parent
if parent != nil {
pn := parent.AsKi()
c := atomic.AddUint64(&pn.NumLifetimeKids, 1)
if kid.Name() == "" {
kid.SetName(kid.KiType().IDName + "-" + strconv.FormatUint(c-1, 10)) // must subtract 1 so we start at 0
}
}
kid.This().OnAdd()
n.WalkUpParent(func(k Ki) bool {
k.This().OnChildAdded(kid)
return Continue
})
if parent != nil {
parup := parent.Is(Updating)
n.WalkPre(func(k Ki) bool {
k.SetFlag(parup, Updating)
return Continue
})
}
}
// MoveToParent deletes given node from its current parent and adds it as a child
// of given new parent. Parents could be in different trees or not.
func MoveToParent(kid Ki, parent Ki) {
oldPar := kid.Parent()
if oldPar != nil {
SetParent(kid, nil)
oldPar.DeleteChild(kid, false)
}
parent.AddChild(kid)
}
// DeleteFromParent calls OnChildDeleting on all parents of given node
// then calls OnDelete on the node, and finally sets the Parent to nil.
// Call this *before* deleting the child.
func DeleteFromParent(kid Ki) {
if kid.Parent() == nil {
return
}
n := kid.AsKi()
n.WalkUpParent(func(k Ki) bool {
k.This().OnChildDeleting(kid)
return Continue
})
kid.SetFlag(true, Deleted)
kid.This().OnDelete()
SetParent(kid, nil)
}
// DeletingChildren calls OnChildrenDeleting on given node
// and all parents thereof.
// Call this *before* deleting the children.
func DeletingChildren(k Ki) {
k.This().OnChildrenDeleting()
n := k.AsKi()
n.WalkUpParent(func(k Ki) bool {
k.This().OnChildrenDeleting()
return Continue
})
}
// New adds a new child of the given the type
// with the given name to the given parent.
// If the name is unspecified, it defaults to the
// ID (kebab-case) name of the type, plus the
// [Ki.NumLifetimeChildren] of its parent.
// It is a helper function that calls [Ki.NewChild].
func New[T Ki](par Ki, name ...string) T {
var n T
return par.NewChild(n.KiType(), name...).(T)
}
// NewRoot returns a new root node of the given the type
// with the given name. If the name is unspecified, it
// defaults to the ID (kebab-case) name of the type.
// It is a helper function that calls [Ki.InitName].
func NewRoot[T Ki](name ...string) T {
var n T
n = n.New().(T)
n.InitName(n, name...)
return n
}
// InsertNewChild is a generic helper function for [Ki.InsertNewChild]
func InsertNewChild[T Ki](par Ki, at int, name ...string) T {
var n T
return par.InsertNewChild(n.KiType(), at, name...).(T)
}
// ParentByType is a generic helper function for [Ki.ParentByType]
func ParentByType[T Ki](k Ki, embeds bool) T {
var n T
v, _ := k.ParentByType(n.KiType(), embeds).(T)
return v
}
// ParentByTypeTry is a generic helper function for [Ki.ParentByTypeTry]
func ParentByTypeTry[T Ki](k Ki, embeds bool) (T, error) {
var n T
vi, err := k.ParentByTypeTry(n.KiType(), embeds)
v, _ := vi.(T)
return v, err
}
// ChildByType is a generic helper function for [Ki.ChildByType]
func ChildByType[T Ki](k Ki, embeds bool, startIdx ...int) T {
var n T
v, _ := k.ChildByType(n.KiType(), embeds, startIdx...).(T)
return v
}
// ChildByTypeTry is a generic helper function for [Ki.ChildByTypeTry]
func ChildByTypeTry[T Ki](k Ki, embeds bool, startIdx ...int) (T, error) {
var n T
vi, err := k.ChildByTypeTry(n.KiType(), embeds, startIdx...)
v, _ := vi.(T)
return v, err
}
// IsRoot tests if this node is the root node -- checks Parent = nil.
func IsRoot(k Ki) bool {
if k.This() == nil || k.Parent() == nil || k.Parent().This() == nil {
return true
}
return false
}
// Root returns the root node of given ki node in tree (the node with a nil parent).
func Root(k Ki) Ki {
if IsRoot(k) {
return k.This()
}
return Root(k.Parent())
}
// Depth returns the current depth of the node.
// This is only valid in a given context, not a stable
// property of the node (e.g., used in WalkBreadth).
func Depth(kn Ki) int {
return kn.AsKi().depth
}
// SetDepth sets the current depth of the node to given value.
func SetDepth(kn Ki, depth int) {
kn.AsKi().depth = depth
}
// UpdateReset resets Updating flag for this node and all children -- in
// case they are out-of-sync due to more complex tree maninpulations --
// only call at a known point of non-updating.
func UpdateReset(kn Ki) {
kn.WalkPre(func(k Ki) bool {
k.SetFlag(false, Updating)
return true
})
}
//////////////////////////////////////////////////
// Unique Names
// UniqueNameCheck checks if all the children names are unique or not.
// returns true if all names are unique; false if not
// if not unique, call UniquifyNames or take other steps to ensure uniqueness.
func UniqueNameCheck(k Ki) bool {
kk := *k.Children()
sz := len(kk)
nmap := make(map[string]struct{}, sz)
for _, child := range kk {
if child == nil {
continue
}
nm := child.Name()
_, hasnm := nmap[nm]
if hasnm {
return false
}
nmap[nm] = struct{}{}
}
return true
}
// UniqueNameCheckAll checks entire tree from given node,
// if all the children names are unique or not.
// returns true if all names are unique; false if not
// if not unique, call UniquifyNames or take other steps to ensure uniqueness.
func UniqueNameCheckAll(kn Ki) bool {
allunq := true
kn.WalkPre(func(k Ki) bool {
unq := UniqueNameCheck(k)
if !unq {
allunq = false
return Break
}
return Continue
})
return allunq
}
// UniquifyIndexAbove is the number of children above which UniquifyNamesAddIndex
// is called -- that is much faster for large numbers of children.
// Must be < 1000
var UniquifyIndexAbove = 1000
// UniquifyNamesAddIndex makes sure that the names are unique by automatically
// adding a suffix with index number, separated by underbar.
// Empty names get the parent name as a prefix.
// if there is an existing underbar, then whatever is after it is replaced with
// the unique index, ensuring that multiple calls are safe!
func UniquifyNamesAddIndex(kn Ki) {
kk := *kn.Children()
sz := len(kk)
sfmt := "%s_%05d"
switch {
case sz > 9999999:
sfmt = "%s_%10d"
case sz > 999999:
sfmt = "%s_%07d"
case sz > 99999:
sfmt = "%s_%06d"
}
parnm := "c"
if kn.Parent() != nil {
parnm = kn.Parent().Name()
}
for i, child := range kk {
if child == nil {
continue
}
nm := child.Name()
if nm == "" {
child.SetName(fmt.Sprintf(sfmt, parnm, i))
} else {
ubi := strings.LastIndex(nm, "_")
if ubi > 0 {
nm = nm[ubi+1:]
}
child.SetName(fmt.Sprintf(sfmt, nm, i))
}
}
}
// UniquifyNames makes sure that the names are unique.
// If number of children >= UniquifyIndexAbove, then UniquifyNamesAddIndex
// is called, for faster performance.
// Otherwise, existing names are preserved if they are unique, and only
// duplicates are renamed. This is a bit slower.
func UniquifyNames(kn Ki) {
kk := *kn.Children()
sz := len(kk)
if sz >= UniquifyIndexAbove {
UniquifyNamesAddIndex(kn)
return
}
parnm := "c"
if kn.Parent() != nil {
parnm = kn.Parent().Name()
}
nmap := make(map[string]struct{}, sz)
for i, child := range kk {
if child == nil {
continue
}
nm := child.Name()
if nm == "" {
nm = fmt.Sprintf("%s_%03d", parnm, i)
child.SetName(nm)
} else {
_, hasnm := nmap[nm]
if hasnm {
ubi := strings.LastIndex(nm, "_")
if ubi > 0 {
nm = nm[ubi+1:]
}
nm = fmt.Sprintf("%s_%03d", nm, i)
child.SetName(nm)
}
}
nmap[nm] = struct{}{}
}
}
// UniquifyNamesAll makes sure that the names are unique for entire tree
// If number of children >= UniquifyIndexAbove, then UniquifyNamesAddIndex
// is called, for faster performance.
// Otherwise, existing names are preserved if they are unique, and only
// duplicates are renamed. This is a bit slower.
func UniquifyNamesAll(kn Ki) {
kn.WalkPre(func(k Ki) bool {
UniquifyNames(k)
return Continue
})
}
//////////////////////////////////////////////////////////////////////////////
// Deletion manager
// DeletedKi manages all the deleted Ki elements, that are destined to then be
// destroyed, without having an additional pointer on the Ki object
type DeletedKi struct {
Dels []Ki
Mu sync.Mutex
}
// DelMgr is the manager of all deleted items
var DelMgr = DeletedKi{}
// Add the Ki elements to the deleted list
func (dm *DeletedKi) Add(kis ...Ki) {
dm.Mu.Lock()
if dm.Dels == nil {
dm.Dels = make([]Ki, 0)
}
dm.Dels = append(dm.Dels, kis...)
dm.Mu.Unlock()
}
// DestroyDeleted destroys any deleted items in list
func (dm *DeletedKi) DestroyDeleted() {
// pr := prof.Start("ki.DestroyDeleted")
// defer pr.End()
dm.Mu.Lock()
curdels := dm.Dels
dm.Dels = make([]Ki, 0)
dm.Mu.Unlock()
for _, k := range curdels {
if k == nil {
continue
}
k.Destroy() // destroy will add to the dels so we need to do this outside of lock
}
}