-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathgrouper_lazy_children.go
86 lines (71 loc) · 1.99 KB
/
grouper_lazy_children.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package core
import (
"fmt"
"strings"
"sync"
"slices"
)
var childrenMutex sync.Mutex
// Implements VisitChildren() and GetChildByName() by calling createChildren()
// only once, when/if needed, and storing the results.
//
// Children will be automatically sorted by their names, so visitor are always in a predictable and stable order.
type GrouperLazyChildren[T Descriptor] struct {
createChildren func() ([]T, error)
children []T
childByName map[string]T
}
func NewGrouperLazyChildren[T Descriptor](createChildren func() ([]T, error)) *GrouperLazyChildren[T] {
if createChildren == nil {
panic("createChildren == nil")
}
return &GrouperLazyChildren[T]{createChildren, nil, nil}
}
func (g *GrouperLazyChildren[T]) getChildren() (children []T, byName map[string]T, err error) {
if g.createChildren == nil {
return g.children, g.childByName, nil
}
children, err = g.createChildren()
if err != nil {
return nil, nil, err
}
g.createChildren = nil // avoid reloading and also free/GC any resources used by the loader function
g.children = children
g.childByName = make(map[string]T, len(children))
for _, child := range children {
childrenMutex.Lock()
g.childByName[child.Name()] = child
childrenMutex.Unlock()
}
slices.SortFunc(g.children, func(a, b T) int {
return strings.Compare(a.Name(), b.Name())
})
return g.children, g.childByName, nil
}
func (g *GrouperLazyChildren[T]) VisitChildren(visitor DescriptorVisitor) (finished bool, err error) {
children, _, err := g.getChildren()
if err != nil {
return false, err
}
for _, child := range children {
run, err := visitor(child)
if err != nil {
return false, err
}
if !run {
return false, nil
}
}
return true, nil
}
func (g *GrouperLazyChildren[T]) GetChildByName(name string) (child Descriptor, err error) {
_, childByName, err := g.getChildren()
if err != nil {
return nil, err
}
child, ok := childByName[name]
if !ok {
return nil, fmt.Errorf("child not found: %s", name)
}
return child, nil
}