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  }