-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqueue.go
124 lines (108 loc) · 2.08 KB
/
queue.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package di
import (
"fmt"
"sort"
"sync"
)
type providerDones struct {
dones map[*provider]struct{}
mu sync.RWMutex
}
func (p *providerDones) isDone(prov *provider) bool {
p.mu.RLock()
_, has := p.dones[prov]
p.mu.RUnlock()
return has
}
func (p *providerDones) markDone(prov *provider) {
p.mu.Lock()
if p.dones == nil {
p.dones = make(map[*provider]struct{})
}
p.dones[prov] = struct{}{}
p.mu.Unlock()
}
type queueNode struct {
provider *provider
weight int
parentDone bool
}
type queue struct {
deps dependencies
nodes []*queueNode
}
func (q *queue) search(p *provider) *queueNode {
for _, n := range q.nodes {
if n.provider == p {
return n
}
}
return nil
}
func (q *queue) append(p *provider) *queueNode {
n := &queueNode{
provider: p,
weight: 1,
}
q.nodes = append(q.nodes, n)
return n
}
func (q *queue) add(p *provider, context []string, dones *providerDones) (*queueNode, error) {
node := q.search(p)
if dones.isDone(p) {
return node, nil
}
if node != nil {
if node.parentDone {
return node, nil
}
context = append(context, p.name)
return nil, fmt.Errorf("cycle dependencies: %v", context)
}
context = append(context, p.name)
node = q.append(p)
var (
parent *queueNode
err error
)
for _, dep := range p.deps {
mod := q.deps.match(dep)
if mod == nil {
return nil, dep.notExistError(p.name)
}
parent, err = q.add(mod.Provider, context, dones)
if err != nil {
return nil, err
}
if parent != nil {
node.weight += parent.weight
}
}
node.parentDone = true
return node, nil
}
func (q *queue) Len() int {
return len(q.nodes)
}
func (q *queue) Less(i, j int) bool {
return q.nodes[i].weight < q.nodes[j].weight
}
func (q *queue) Swap(i, j int) {
q.nodes[i], q.nodes[j] = q.nodes[j], q.nodes[i]
}
func newQueue(providers []*provider, mods dependencies, dones *providerDones) ([]*queueNode, error) {
var (
queue = queue{
deps: mods,
}
err error
)
for _, p := range providers {
_, err = queue.add(p, nil, dones)
if err != nil {
return nil, err
}
}
sort.Sort(&queue)
return queue.nodes, nil
}