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  }