github.com/goki/ki@v1.1.17/ki/admin.go (about) 1 // Copyright (c) 2018, The GoKi Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ki 6 7 import ( 8 "fmt" 9 "log" 10 "reflect" 11 "strings" 12 "sync" 13 "unsafe" 14 15 "github.com/goki/ki/kit" 16 ) 17 18 // admin has infrastructure level code, outside of ki interface 19 20 // InitNode initializes the node -- automatically called during Add/Insert 21 // Child -- sets the This pointer for this node as a Ki interface (pass 22 // pointer to node as this arg) -- Go cannot always access the true 23 // underlying type for structs using embedded Ki objects (when these objs 24 // are receivers to methods) so we need a This interface pointer that 25 // guarantees access to the Ki interface in a way that always reveals the 26 // underlying type (e.g., in reflect calls). Calls Init on Ki fields 27 // within struct, sets their names to the field name, and sets us as their 28 // parent. 29 func InitNode(this Ki) { 30 n := this.AsNode() 31 this.ClearFlagMask(int64(UpdateFlagsMask)) 32 if n.Ths != this { 33 n.Ths = this 34 n.Ths.OnInit() 35 KiInitKiFields(this) 36 } 37 } 38 39 // ThisCheck checks that the This pointer is set and issues a warning to 40 // log if not -- returns error if not set -- called when nodes are added 41 // and inserted. 42 func ThisCheck(k Ki) error { 43 if k.This() == nil { 44 err := fmt.Errorf("Ki Node %v ThisCheck: node has null 'this' pointer -- must call Init or InitName on root nodes!", k.Name()) 45 log.Print(err) 46 return err 47 } 48 return nil 49 } 50 51 // SetParent just sets parent of node (and inherits update count from 52 // parent, to keep consistent). 53 // Assumes not already in a tree or anything. 54 func SetParent(kid Ki, parent Ki) { 55 n := kid.AsNode() 56 n.Par = parent 57 kid.OnAdd() 58 n.FuncUpParent(0, nil, func(k Ki, level int, data any) bool { 59 k.OnChildAdded(kid) 60 return Continue 61 }) 62 if parent != nil && !parent.OnlySelfUpdate() { 63 parup := parent.IsUpdating() 64 n.FuncDownMeFirst(0, nil, func(k Ki, level int, d any) bool { 65 k.SetFlagState(parup, int(Updating)) 66 return true 67 }) 68 } 69 } 70 71 // MoveToParent deletes given node from its current parent and adds it as a child 72 // of given new parent. Parents could be in different trees or not. 73 func MoveToParent(kid Ki, parent Ki) { 74 oldPar := kid.Parent() 75 if oldPar != nil { 76 SetParent(kid, nil) 77 oldPar.DeleteChild(kid, false) 78 } 79 parent.AddChild(kid) 80 } 81 82 // AddNew adds a new child of the given the type 83 // with the given name to the given parent. 84 // It is a helper function that calls [Ki.AddNewChild]. 85 func AddNew[T Ki](par Ki, name string) { 86 par.AddNewChild(kit.TypeFor[T](), name) 87 } 88 89 // IsRoot tests if this node is the root node -- checks Parent = nil. 90 func IsRoot(k Ki) bool { 91 if k.This() == nil || k.Parent() == nil || k.Parent().This() == nil { 92 return true 93 } 94 return false 95 } 96 97 // Root returns the root node of given ki node in tree (the node with a nil parent). 98 func Root(k Ki) Ki { 99 if IsRoot(k) { 100 return k.This() 101 } 102 return Root(k.Parent()) 103 } 104 105 // Depth returns the current depth of the node. 106 // This is only valid in a given context, not a stable 107 // property of the node (e.g., used in FuncDownBreadthFirst). 108 func Depth(kn Ki) int { 109 return kn.AsNode().depth 110 } 111 112 // SetDepth sets the current depth of the node to given value. 113 func SetDepth(kn Ki, depth int) { 114 kn.AsNode().depth = depth 115 } 116 117 // UpdateReset resets Updating flag for this node and all children -- in 118 // case they are out-of-sync due to more complex tree maninpulations -- 119 // only call at a known point of non-updating. 120 func UpdateReset(kn Ki) { 121 if kn.OnlySelfUpdate() { 122 kn.ClearFlag(int(Updating)) 123 } else { 124 kn.FuncDownMeFirst(0, nil, func(k Ki, level int, d any) bool { 125 k.ClearFlag(int(Updating)) 126 return true 127 }) 128 } 129 } 130 131 ////////////////////////////////////////////////////////////////// 132 // Fields 133 134 // KiInitKiFields calls Init on all Ki fields 135 // within the struct, sets their names to the field name, 136 // and sets us as their parent. 137 func KiInitKiFields(this Ki) { 138 n := this.AsNode() 139 if KiHasKiFields(n) { 140 fnms := KiFieldNames(n) 141 val := reflect.ValueOf(this).Elem() 142 for _, fnm := range fnms { 143 fldval := val.FieldByName(fnm) 144 fk := kit.PtrValue(fldval).Interface().(Ki) 145 fk.SetFlag(int(IsField)) 146 fk.InitName(fk, fnm) 147 SetParent(fk, this) 148 } 149 } 150 } 151 152 // FieldRoot returns the field root object for this node -- the node that 153 // owns the branch of the tree rooted in one of its fields -- i.e., the 154 // first non-Field parent node after the first Field parent node -- can be 155 // nil if no such thing exists for this node. 156 func FieldRoot(kn Ki) Ki { 157 var root Ki 158 gotField := false 159 kn.FuncUpParent(0, kn, func(k Ki, level int, d any) bool { 160 if !gotField { 161 if k.IsField() { 162 gotField = true 163 } 164 return Continue 165 } 166 if !k.IsField() { 167 root = k 168 return Break 169 } 170 return Continue 171 }) 172 return root 173 } 174 175 // KiFieldOffs returns the uintptr offsets for Ki fields of this Node. 176 // Cached for fast access, but use HasKiFields for even faster checking. 177 func KiFieldOffs(n *Node) []uintptr { 178 if n.fieldOffs != nil { 179 return n.fieldOffs 180 } 181 // we store the offsets for the fields in type properties 182 tprops := *kit.Types.Properties(Type(n.This()), true) // true = makeNew 183 if foff, ok := kit.TypeProp(tprops, "__FieldOffs"); ok { 184 n.fieldOffs = foff.([]uintptr) 185 return n.fieldOffs 186 } 187 foff, _ := KiFieldsInit(n) 188 return foff 189 } 190 191 // KiHasKiFields returns true if this node has Ki Node fields that are 192 // included in recursive descent traversal of the tree. This is very 193 // efficient compared to accessing the field information on the type 194 // so it should be checked first -- caches the info on the node in flags. 195 func KiHasKiFields(n *Node) bool { 196 if n.HasFlag(int(HasKiFields)) { 197 return true 198 } 199 if n.HasFlag(int(HasNoKiFields)) { 200 return false 201 } 202 foffs := KiFieldOffs(n) 203 if len(foffs) == 0 { 204 n.SetFlag(int(HasNoKiFields)) 205 return false 206 } 207 n.SetFlag(int(HasKiFields)) 208 return true 209 } 210 211 // NumKiFields returns the number of Ki Node fields on this node. 212 // This calls HasKiFields first so it is also efficient. 213 func NumKiFields(n *Node) int { 214 if !KiHasKiFields(n) { 215 return 0 216 } 217 foffs := KiFieldOffs(n) 218 return len(foffs) 219 } 220 221 // KiField returns the Ki Node field at given index, from KiFieldOffs list. 222 // Returns nil if index is out of range. This is generally used for 223 // generic traversal methods and thus does not have a Try version. 224 func KiField(n *Node, idx int) Ki { 225 if !KiHasKiFields(n) { 226 return nil 227 } 228 foffs := KiFieldOffs(n) 229 if idx >= len(foffs) || idx < 0 { 230 return nil 231 } 232 fn := (*Node)(unsafe.Pointer(uintptr(unsafe.Pointer(n)) + foffs[idx])) 233 return fn.This() 234 } 235 236 // KiFieldByName returns field Ki element by name -- returns false if not found. 237 func KiFieldByName(n *Node, name string) Ki { 238 if !KiHasKiFields(n) { 239 return nil 240 } 241 foffs := KiFieldOffs(n) 242 op := uintptr(unsafe.Pointer(n)) 243 for _, fo := range foffs { 244 fn := (*Node)(unsafe.Pointer(op + fo)) 245 if fn.Nm == name { 246 return fn.This() 247 } 248 } 249 return nil 250 } 251 252 // KiFieldNames returns the field names for Ki fields of this Node. Cached for fast access. 253 func KiFieldNames(n *Node) []string { 254 // we store the offsets for the fields in type properties 255 tprops := *kit.Types.Properties(Type(n.This()), true) // true = makeNew 256 if fnms, ok := kit.TypeProp(tprops, "__FieldNames"); ok { 257 return fnms.([]string) 258 } 259 _, fnm := KiFieldsInit(n) 260 return fnm 261 } 262 263 // KiFieldsInit initializes cached data about the KiFields in this node 264 // offsets and names -- returns them 265 func KiFieldsInit(n *Node) (foff []uintptr, fnm []string) { 266 foff = make([]uintptr, 0) 267 fnm = make([]string, 0) 268 kitype := KiType 269 FlatFieldsValueFunc(n.This(), func(stru any, typ reflect.Type, field reflect.StructField, fieldVal reflect.Value) bool { 270 if fieldVal.Kind() == reflect.Struct && kit.EmbedImplements(field.Type, kitype) { 271 foff = append(foff, field.Offset) 272 fnm = append(fnm, field.Name) 273 } 274 return true 275 }) 276 tprops := *kit.Types.Properties(Type(n), true) // true = makeNew 277 kit.SetTypeProp(tprops, "__FieldOffs", foff) 278 n.fieldOffs = foff 279 kit.SetTypeProp(tprops, "__FieldNames", fnm) 280 return 281 } 282 283 // FieldByName returns field value by name (can be any type of field -- 284 // see KiFieldByName for Ki fields) -- returns nil if not found. 285 func FieldByName(kn Ki, field string) any { 286 return kit.FlatFieldInterfaceByName(kn.This(), field) 287 } 288 289 // FieldByNameTry returns field value by name (can be any type of field -- 290 // see KiFieldByName for Ki fields) -- returns error if not found. 291 func FieldByNameTry(kn Ki, field string) (any, error) { 292 fld := FieldByName(kn, field) 293 if fld != nil { 294 return fld, nil 295 } 296 return nil, fmt.Errorf("ki %v: field named: %v not found", kn.Path(), field) 297 } 298 299 // FieldTag returns given field tag for that field, or empty string if not set. 300 func FieldTag(kn Ki, field, tag string) string { 301 return kit.FlatFieldTag(Type(kn.This()), field, tag) 302 } 303 304 ////////////////////////////////////////////////// 305 // Unique Names 306 307 // UniqueNameCheck checks if all the children names are unique or not. 308 // returns true if all names are unique; false if not 309 // if not unique, call UniquifyNames or take other steps to ensure uniqueness. 310 func UniqueNameCheck(k Ki) bool { 311 kk := *k.Children() 312 sz := len(kk) 313 nmap := make(map[string]struct{}, sz) 314 for _, child := range kk { 315 if child == nil { 316 continue 317 } 318 nm := child.Name() 319 _, hasnm := nmap[nm] 320 if hasnm { 321 return false 322 } 323 nmap[nm] = struct{}{} 324 } 325 return true 326 } 327 328 // UniqueNameCheckAll checks entire tree from given node, 329 // if all the children names are unique or not. 330 // returns true if all names are unique; false if not 331 // if not unique, call UniquifyNames or take other steps to ensure uniqueness. 332 func UniqueNameCheckAll(kn Ki) bool { 333 allunq := true 334 kn.FuncDownMeFirst(0, nil, func(k Ki, level int, d any) bool { 335 unq := UniqueNameCheck(k) 336 if !unq { 337 allunq = false 338 return Break 339 } 340 return Continue 341 }) 342 return allunq 343 } 344 345 // UniquifyIndexAbove is the number of children above which UniquifyNamesAddIndex 346 // is called -- that is much faster for large numbers of children. 347 // Must be < 1000 348 var UniquifyIndexAbove = 1000 349 350 // UniquifyNamesAddIndex makes sure that the names are unique by automatically 351 // adding a suffix with index number, separated by underbar. 352 // Empty names get the parent name as a prefix. 353 // if there is an existing underbar, then whatever is after it is replaced with 354 // the unique index, ensuring that multiple calls are safe! 355 func UniquifyNamesAddIndex(kn Ki) { 356 kk := *kn.Children() 357 sz := len(kk) 358 sfmt := "%s_%05d" 359 switch { 360 case sz > 9999999: 361 sfmt = "%s_%10d" 362 case sz > 999999: 363 sfmt = "%s_%07d" 364 case sz > 99999: 365 sfmt = "%s_%06d" 366 } 367 parnm := "c" 368 if kn.Parent() != nil { 369 parnm = kn.Parent().Name() 370 } 371 for i, child := range kk { 372 if child == nil { 373 continue 374 } 375 nm := child.Name() 376 if nm == "" { 377 child.SetName(fmt.Sprintf(sfmt, parnm, i)) 378 } else { 379 ubi := strings.LastIndex(nm, "_") 380 if ubi > 0 { 381 nm = nm[ubi+1:] 382 } 383 child.SetName(fmt.Sprintf(sfmt, nm, i)) 384 } 385 } 386 } 387 388 // UniquifyNames makes sure that the names are unique. 389 // If number of children >= UniquifyIndexAbove, then UniquifyNamesAddIndex 390 // is called, for faster performance. 391 // Otherwise, existing names are preserved if they are unique, and only 392 // duplicates are renamed. This is a bit slower. 393 func UniquifyNames(kn Ki) { 394 kk := *kn.Children() 395 sz := len(kk) 396 if sz >= UniquifyIndexAbove { 397 UniquifyNamesAddIndex(kn) 398 return 399 } 400 parnm := "c" 401 if kn.Parent() != nil { 402 parnm = kn.Parent().Name() 403 } 404 nmap := make(map[string]struct{}, sz) 405 for i, child := range kk { 406 if child == nil { 407 continue 408 } 409 nm := child.Name() 410 if nm == "" { 411 nm = fmt.Sprintf("%s_%03d", parnm, i) 412 child.SetName(nm) 413 } else { 414 _, hasnm := nmap[nm] 415 if hasnm { 416 ubi := strings.LastIndex(nm, "_") 417 if ubi > 0 { 418 nm = nm[ubi+1:] 419 } 420 nm = fmt.Sprintf("%s_%03d", nm, i) 421 child.SetName(nm) 422 } 423 } 424 nmap[nm] = struct{}{} 425 } 426 } 427 428 // UniquifyNamesAll makes sure that the names are unique for entire tree 429 // If number of children >= UniquifyIndexAbove, then UniquifyNamesAddIndex 430 // is called, for faster performance. 431 // Otherwise, existing names are preserved if they are unique, and only 432 // duplicates are renamed. This is a bit slower. 433 func UniquifyNamesAll(kn Ki) { 434 kn.FuncDownMeFirst(0, nil, func(k Ki, level int, d any) bool { 435 UniquifyNames(k) 436 return Continue 437 }) 438 } 439 440 ////////////////////////////////////////////////////////////////////////////// 441 // Deletion manager 442 443 // Deleted manages all the deleted Ki elements, that are destined to then be 444 // destroyed, without having an additional pointer on the Ki object 445 type Deleted struct { 446 Dels []Ki 447 Mu sync.Mutex 448 } 449 450 // DelMgr is the manager of all deleted items 451 var DelMgr = Deleted{} 452 453 // Add the Ki elements to the deleted list 454 func (dm *Deleted) Add(kis ...Ki) { 455 dm.Mu.Lock() 456 if dm.Dels == nil { 457 dm.Dels = make([]Ki, 0) 458 } 459 dm.Dels = append(dm.Dels, kis...) 460 dm.Mu.Unlock() 461 } 462 463 // DestroyDeleted destroys any deleted items in list 464 func (dm *Deleted) DestroyDeleted() { 465 // pr := prof.Start("ki.DestroyDeleted") 466 // defer pr.End() 467 dm.Mu.Lock() 468 curdels := dm.Dels 469 dm.Dels = make([]Ki, 0) 470 dm.Mu.Unlock() 471 for _, k := range curdels { 472 if k == nil { 473 continue 474 } 475 k.Destroy() // destroy will add to the dels so we need to do this outside of lock 476 } 477 }