mctx: implement BreadthFirstVisit

This commit is contained in:
Brian Picciano 2019-01-30 16:04:58 -05:00
parent 8e2cffd65b
commit 5bd0790f6e
2 changed files with 56 additions and 0 deletions

View File

@ -152,6 +152,24 @@ func ChildOf(ctx Context, name string) Context {
return childCtx return childCtx
} }
// BreadthFirstVisit visits this Context and all of its children, and their
// children, in a breadth-first order. If the callback returns false then the
// function returns without visiting any more Contexts.
//
// The exact order of visitation is non-deterministic.
func BreadthFirstVisit(ctx Context, callback func(Context) bool) {
queue := []Context{ctx}
for len(queue) > 0 {
if !callback(queue[0]) {
return
}
for _, child := range Children(queue[0]) {
queue = append(queue, child)
}
queue = queue[1:]
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// code related to mutable values // code related to mutable values

View File

@ -54,6 +54,44 @@ func TestInheritance(t *T) {
)) ))
} }
func TestBreadFirstVisit(t *T) {
ctx := New()
ctx1 := ChildOf(ctx, "1")
ctx1a := ChildOf(ctx1, "a")
ctx1b := ChildOf(ctx1, "b")
ctx2 := ChildOf(ctx, "2")
{
got := make([]Context, 0, 5)
BreadthFirstVisit(ctx, func(ctx Context) bool {
got = append(got, ctx)
return true
})
// since children are stored in a map the exact order is non-deterministic
massert.Fatal(t, massert.Any(
massert.Equal([]Context{ctx, ctx1, ctx2, ctx1a, ctx1b}, got),
massert.Equal([]Context{ctx, ctx1, ctx2, ctx1b, ctx1a}, got),
massert.Equal([]Context{ctx, ctx2, ctx1, ctx1a, ctx1b}, got),
massert.Equal([]Context{ctx, ctx2, ctx1, ctx1b, ctx1a}, got),
))
}
{
got := make([]Context, 0, 3)
BreadthFirstVisit(ctx, func(ctx Context) bool {
if len(Path(ctx)) > 1 {
return false
}
got = append(got, ctx)
return true
})
massert.Fatal(t, massert.Any(
massert.Equal([]Context{ctx, ctx1, ctx2}, got),
massert.Equal([]Context{ctx, ctx2, ctx1}, got),
))
}
}
func TestMutableValues(t *T) { func TestMutableValues(t *T) {
fn := func(v interface{}) interface{} { fn := func(v interface{}) interface{} {
if v == nil { if v == nil {