Complete all of tree except unmarshaling

pull/53/head
rwxrob 2 years ago
parent 39757a5c2a
commit 6e410c5810
No known key found for this signature in database
GPG Key ID: 2B9111F33082AE77

@ -9,7 +9,9 @@ import (
"log"
"strings"
"github.com/rwxrob/bonzai/each"
"github.com/rwxrob/bonzai/json"
"github.com/rwxrob/bonzai/util"
)
// Tree is an encapsulating struct to contain the Trunk of Nodes and
@ -22,6 +24,20 @@ type Tree struct {
Types []string
}
// Seed returns new detached Node from the same Tree
func (t *Tree) Seed(i ...any) *Node {
leaf := new(Node)
switch len(i) {
case 2:
leaf.V = i[1].(string)
fallthrough
case 1:
leaf.T = i[0].(int)
}
leaf.tree = t
return leaf
}
const (
UNKNOWN = 0
)
@ -153,7 +169,7 @@ func (n *Node) IsNull() bool { return n.first == nil && n.V == "" }
// use when debugging. Remember to log.SetOutput(os.Stdout) and
// log.SetFlags(0) when using this in Go example tests.
func (n *Node) Info() {
log.Printf(`------
each.Log(util.Lines(fmt.Sprintf(`------
Type: %v
Value: %q
IsRoot: %v
@ -162,7 +178,7 @@ IsLeaf: %v
IsBranch: %v
IsNull: %v`,
n.T, n.V, n.IsRoot(), n.IsDetached(),
n.IsLeaf(), n.IsBranch(), n.IsNull())
n.IsLeaf(), n.IsBranch(), n.IsNull())))
}
// ----------------- Node PrintAsJSON interface (plus) ----------------
@ -240,25 +256,11 @@ func (s Node) Log() { log.Print(s.JSON()) }
// ------------------------------- Nodes ------------------------------
// Spawn spawns new orphan Node for this same Tree
func (n *Node) spawn(i []any) *Node {
leaf := new(Node)
switch len(i) {
case 2:
leaf.V = i[1].(string)
fallthrough
case 1:
leaf.T = i[0].(int)
}
leaf.tree = n.tree
return leaf
}
// NewRight creates a new Node and grafts it to the right of the current
// one on the same branch. The type and initial value can optionally be
// passed as arguments.
func (n *Node) NewRight(i ...any) *Node {
leaf := n.spawn(i)
leaf := n.tree.Seed(i...)
n.GraftRight(leaf)
return leaf
}
@ -267,7 +269,7 @@ func (n *Node) NewRight(i ...any) *Node {
// on the same branch. The type and initial value can optionally be
// passed as arguments.
func (n *Node) NewLeft(i ...any) *Node {
leaf := n.spawn(i)
leaf := n.tree.Seed(i...)
n.GraftLeft(leaf)
return leaf
}
@ -276,32 +278,41 @@ func (n *Node) NewLeft(i ...any) *Node {
// adding it to the left of other branches and leaves below. The type
// and initial value can optionally be passed as arguments.
func (n *Node) NewUnder(i ...any) *Node {
leaf := n.spawn(i)
leaf := n.tree.Seed(i...)
n.GraftUnder(leaf)
return leaf
}
// Graft replaces current node with a completely new Node and returns it
// Graft replaces current node with a completely new Node and returns
// it. Anything under the grafted node will remain and anything under
// the node being replaced will go with it.
func (n *Node) Graft(c *Node) *Node {
c.up = n.up
c.left = n.left
c.right = n.right
// update branch parent
if n.up.last == n {
n.up.last = c
}
if n.up.first == n {
n.up.first = c
}
// update peers
if n.left != nil {
n.left.right = c
}
if n.right != nil {
n.right.left = c
}
// detach
n.up = nil
n.right = nil
n.left = nil
return n
return c
}
// GraftRight adds existing Node to the right of itself as a peer and
@ -350,7 +361,7 @@ func (n *Node) GraftUnder(c *Node) *Node {
n.last = c
return c
}
return n.first.GraftRight(c)
return n.last.GraftRight(c)
}
// Prune removes and returns itself and grafts everything together to
@ -386,14 +397,19 @@ func (n *Node) Take(from *Node) {
n.Take(from)
}
/*
/*
// Action is a first-class function type used when Visiting each Node.
// The return value will be sent to a channel as each Action completes.
// It can be an error or anything else.
type Action func(n *Node) interface{}
type Action func(n *Node) any
// Visit will call the Action function passing it every node traversing
// in the most predictable way, from top to bottom and left to right on
// each level of depth. If the optional rvals channel is passed the
// return values for the actions will be sent to it synchronously. This
// may be preferable for gathering data from the node tree in some
// cases. The Action could also be implemented as a closure function
// enclosing some state variable. If the rvals channel is nil it will
// not be opened.
func (n *Node) Visit(act Action, rvals chan interface{}) {
if rvals == nil {
act(n)
@ -403,7 +419,7 @@ func (n *Node) Visit(act Action, rvals chan interface{}) {
if n.first == nil {
return
}
for _, c := range n.Children() {
for _, c := range n.AllUnder() {
c.Visit(act, rvals)
}
return
@ -415,15 +431,21 @@ func (n *Node) Visit(act Action, rvals chan interface{}) {
// set the maximum number of simultaneous goroutines (which can usually
// be in the thousands) and must be 2 or more or will panic. If the
// channel of return values is not nil it will be sent all return values
// as Actions complete.
func (n *Node) VisitAsync(act Action, lim int, rvals chan interface{}) {
// as Actions complete. Note that this method uses twice the memory of
// the synchronous version and requires slightly more startup time as
// the node collection is done (which actually calls Visit in order to
// build the flattened list of all nodes). Therefore, VisitAsync should
// only be used when the action is likely to take a non-trivial amount
// of time to execute, for example, when there is significant IO
// involved (disk, Internet, etc.).
func (n *Node) VisitAsync(act Action, lim int, rvals chan any) {
nodes := []*Node{}
if lim < 2 {
panic("visitasync: limit must be 2 or more")
panic("limit must be 2 or more")
}
add := func(node *Node) interface{} {
add := func(node *Node) any {
nodes = append(nodes, node)
return nil
}
@ -459,5 +481,3 @@ func (n *Node) VisitAsync(act Action, lim int, rvals chan interface{}) {
}
}
*/

@ -1,8 +1,10 @@
package tree_test
import (
"fmt"
"log"
"os"
"time"
"github.com/rwxrob/bonzai/tree"
)
@ -25,6 +27,18 @@ func ExampleTree_Log() {
// {"Trunk":[1],"Types":["UNKNOWN","foo","bar"]}
}
func ExampleTree_Seed() {
defer log.SetOutput(os.Stderr)
defer log.SetFlags(log.Flags())
log.SetOutput(os.Stdout)
log.SetFlags(0)
t := tree.New([]string{"foo", "bar"})
s := t.Seed(2, "")
fmt.Println(s.IsRoot(), s.IsDetached(), s.IsNull())
// Output:
// true true true
}
func ExampleNode_Log() {
defer log.SetOutput(os.Stderr)
defer log.SetFlags(log.Flags())
@ -88,11 +102,13 @@ func ExampleNode_NewRight() {
}
func ExampleNode_NewLeft() {
n := tree.New([]string{"foo", "bar"}).Trunk
n.Print()
t := n.NewLeft(2, "some")
t.Print()
n.Left().Print()
//Output:
// [1]
// [2,"some"]
@ -107,6 +123,7 @@ func ExampleNode_NewUnder() {
n.FirstUnder().Print()
n.LastUnder().Print()
n.Print()
//Output:
// [1]
// [2,"some"]
@ -116,27 +133,208 @@ func ExampleNode_NewUnder() {
}
func ExampleNode_Graft() {
n := tree.New([]string{"foo", "bar"}).Trunk
t := tree.New([]string{"foo", "😭", "💔"})
n := t.Trunk
u := n.NewUnder(2, "graftme")
u.NewUnder(3, "under1") // should go with orig
u.NewUnder(3, "under2") // should go with orig
u.NewLeft(3, "left")
u.NewRight(3, "right")
x := u.Graft(t.Seed(3, "newbie"))
fmt.Println(u.AllUnder()) // still has leaves and branches
fmt.Println(x.AllUnder()) // never had them
fmt.Println(x.Left()) // new left
fmt.Println(x.Right()) // new right
fmt.Println(u.Left()) // detached
fmt.Println(u.Right()) // detached
fmt.Println(x.Branch())
//Output:
// [[3,"under1"] [3,"under2"]]
// []
// [3,"left"]
// [3,"right"]
// <nil>
// <nil>
// [1,[[3,"left"],[3,"newbie"],[3,"right"]]]
}
func ExampleNode_GraftRight() {
t := tree.New([]string{"foo", "😭", "💔"})
n := t.Trunk
u := n.NewUnder(3, "under")
x := u.GraftRight(t.Seed(3, "newbie"))
n.Print()
t := n.NewUnder(2, "some")
t.Print()
n.FirstUnder().Print()
n.LastUnder().Print()
u.Print()
x.Left().Print()
//Output:
// [1]
// [2,"some"]
// [2,"some"]
// [2,"some"]
// [1,[[3,"under"],[3,"newbie"]]]
// [3,"under"]
// [3,"under"]
}
/*
func (n *Node) Graft(c *Node) *Node {
func (n *Node) GraftRight(r *Node) *Node {
func (n *Node) GraftLeft(l *Node) *Node {
func (n *Node) GraftUnder(c *Node) *Node {
func (n *Node) Prune() *Node {
func (n *Node) Take(from *Node) {
func (n *Node) under() []*Node {
func (n *Node) Visit(act Action, rvals chan interface{}) {
func (n *Node) VisitAsync(act Action, lim int, rvals chan interface{}) {
*/
func ExampleNode_GraftLeft() {
t := tree.New([]string{"foo", "😭", "💔"})
n := t.Trunk
u := n.NewUnder(3, "under")
x := u.GraftLeft(t.Seed(3, "newbie"))
n.Print()
u.Print()
x.Right().Print()
//Output:
// [1,[[3,"newbie"],[3,"under"]]]
// [3,"under"]
// [3,"under"]
}
func ExampleNode_GraftUnder() {
t := tree.New([]string{"foo", "😭", "💔"})
n := t.Trunk
u := n.NewUnder(3, "under")
x := u.GraftUnder(t.Seed(3, "newbie"))
n.Print()
u.Print()
x.Branch().Print()
//Output:
// [1,[[3,[[3,"newbie"]]]]]
// [3,[[3,"newbie"]]]
// [3,[[3,"newbie"]]]
}
func ExampleNode_Prune() {
t := tree.New([]string{"foo", "😭", "💔"})
n := t.Trunk
u := n.NewUnder(2, "pruneme")
u1 := u.NewUnder(3, "under") // should go with orig
left := u.NewLeft(3, "left")
right := u.NewRight(3, "right")
x := u.Prune()
x.Print() // should take stuff under with it
u1.Branch().Print() // same as previous
left.Right().Print() // should be joined to the left now
right.Left().Print() // should be joined to right now
//Output:
// [2,[[3,"under"]]]
// [2,[[3,"under"]]]
// [3,"right"]
// [3,"left"]
}
func ExampleNode_Take() {
n := tree.New([]string{"foo", "😭", "💔"}).Trunk
u1 := n.NewUnder(2)
u2 := n.NewUnder(3)
u2.NewUnder(3)
u2.NewUnder(3)
u1.Print()
u2.Print()
u1.Take(u2)
u1.Print()
u2.Print()
// Output:
// [2]
// [3,[[3],[3]]]
// [2,[[3],[3]]]
// [3]
}
func ExampleNode_Visit() {
n := tree.New([]string{"🌴", "😭", "💔", "💀"}).Trunk
l2 := n.NewUnder(2, "two")
l_2 := l2.NewUnder(2, "_two")
l3 := n.NewUnder(3, "three")
l_3 := l3.NewUnder(3, "_three")
l4 := n.NewUnder(4, "four")
l_4 := l4.NewUnder(4, "_four")
n.Print()
l2.Print()
l_2.Print()
l3.Print()
l_3.Print()
l4.Print()
l_4.Print()
n.Visit(
func(n *tree.Node) any {
n.Print()
return nil
}, nil)
// Output:
// [1,[[2,[[2,"_two"]]],[3,[[3,"_three"]]],[4,[[4,"_four"]]]]]
// [2,[[2,"_two"]]]
// [2,"_two"]
// [3,[[3,"_three"]]]
// [3,"_three"]
// [4,[[4,"_four"]]]
// [4,"_four"]
// [1,[[2,[[2,"_two"]]],[3,[[3,"_three"]]],[4,[[4,"_four"]]]]]
// [2,[[2,"_two"]]]
// [2,"_two"]
// [3,[[3,"_three"]]]
// [3,"_three"]
// [4,[[4,"_four"]]]
// [4,"_four"]
}
func ExampleNode_VisitAsync() {
n := tree.New([]string{"🌴", "😭", "💔", "💀"}).Trunk
n.NewUnder(2, "two").NewUnder(2, "_two")
n.NewUnder(3, "three").NewUnder(3, "_three")
n.NewUnder(4, "four").NewUnder(4, "_four")
n.VisitAsync(
func(n *tree.Node) any {
n.Print()
time.Sleep(30 * time.Millisecond)
return nil
}, 3, nil)
// note that "unordered" output is required
// Unordered Output:
// [1,[[2,[[2,"_two"]]],[3,[[3,"_three"]]],[4,[[4,"_four"]]]]]
// [2,[[2,"_two"]]]
// [2,"_two"]
// [3,[[3,"_three"]]]
// [3,"_three"]
// [4,[[4,"_four"]]]
// [4,"_four"]
}
func ExampleNode_AllUnder() {
n := tree.New([]string{"🌴", "😭", "💔", "💀"}).Trunk
n.NewUnder(2)
n.NewUnder(3)
n.NewUnder(4)
n.Print()
// Output:
// [1,[[2],[3],[4]]]
}
func ExampleNode_JSON() {
n := tree.New([]string{"🌴", "😭", "💔", "💀"}).Trunk
n.NewUnder(2)
n.NewUnder(3)
n.NewUnder(4)
n.NewUnder(5)
n.Print()
// Output:
// [1,[[2],[3],[4],[5]]]
}

Loading…
Cancel
Save