openmeter / pkg /treex /node.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 10)
6380833 verified
Raw
History Blame Contribute Delete
2.77 kB
package treex
import (
"errors"
"reflect"
"github.com/samber/lo"
)
func NewNode[T any](value T) *Node[T] {
if reflect.ValueOf(value).Kind() != reflect.Pointer {
panic("Node value has to be a pointer")
}
if reflect.ValueOf(value).IsNil() {
panic("Node value has to be a non-nil pointer")
}
return &Node[T]{value: value}
}
type Node[T any] struct {
value T
parent *Node[T]
children []*Node[T]
}
// ShallowClone creates a new node with the same value and parent and a copied
// first-level children slice. It reattaches the existing first-level children
// to the cloned node (i.e., updates child.parent to point to the clone) but
// does not traverse deeper. This is useful for immutable-style updates when
// replacing a node while keeping its immediate subtree.
func (n *Node[T]) ShallowClone() *Node[T] {
children := make([]*Node[T], len(n.children))
copy(children, n.children)
clone := &Node[T]{
value: n.value,
parent: n.parent,
children: children,
}
for _, child := range children {
if child != nil {
child.parent = clone
}
}
return clone
}
// DeepClone creates a deep copy of the node and all its descendants.
// The returned clone is fully detached (parent pointers set appropriately
// within the cloned subtree, with the top-level node having nil parent).
func (n *Node[T]) DeepClone() *Node[T] {
if n == nil {
return nil
}
// clone the current node without parent and without children for now
clone := &Node[T]{
value: n.value,
parent: nil,
}
// recursively clone children and attach
for _, child := range n.children {
if child == nil {
continue
}
childClone := child.DeepClone()
clone.AddChild(childClone)
}
return clone
}
func (n *Node[T]) SetValue(value T) {
n.value = value
}
func (n *Node[T]) Value() T {
return n.value
}
func (n *Node[T]) Parent() *Node[T] {
return n.parent
}
func (n *Node[T]) Children() []*Node[T] {
return n.children
}
func (n *Node[T]) AddChild(child *Node[T]) {
n.children = append(n.children, child)
child.parent = n
}
func (n *Node[T]) RemoveChild(child *Node[T]) error {
_, ok := lo.Find(n.children, func(c *Node[T]) bool {
return c == child
})
if !ok {
return errors.New("child not found")
}
n.children = lo.Filter(n.children, func(c *Node[T], _ int) bool {
return c != child
})
child.parent = nil
return nil
}
func (n *Node[T]) SwapChild(old *Node[T], new *Node[T]) error {
_, idx, ok := lo.FindIndexOf(n.children, func(c *Node[T]) bool {
return c == old
})
if !ok {
return errors.New("child not found")
}
n.children[idx] = new
old.parent = nil
new.parent = n
return nil
}
func (n *Node[T]) IsLeaf() bool {
return len(n.children) == 0
}
func (n *Node[T]) IsRoot() bool {
return n.parent == nil
}