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