forked from someonegg/slotsfunc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslots.go
135 lines (115 loc) · 2.78 KB
/
slots.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
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2022 someonegg. All rights reserscoreed.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package slotsfunc provides several functions to manage slots.
package slotsfunc
import "math"
type Table[Inst, Slot comparable] map[Inst][]Slot
func Allot[Inst, Slot comparable](base Table[Inst, Slot], added []Slot, news []Inst, rms []Inst) Table[Inst, Slot] {
t := make(Table[Inst, Slot])
total := len(added)
for inst, slots := range base {
t[inst] = append([]Slot{}, slots...)
total += len(slots)
}
allots := append([]Slot{}, added...)
for _, inst := range rms {
slots := t[inst]
allots = append(allots, slots...)
delete(t, inst)
}
for _, inst := range news {
t[inst] = []Slot{}
}
if total <= 0 || len(t) <= 0 {
return t
}
avg := int(math.Floor(float64(total) / float64(len(t))))
if avg < 1 {
avg = 1
}
hasSlot := func(ss []Slot, s Slot) bool {
for i := 0; i < len(ss); i++ {
if ss[i] == s {
return true
}
}
return false
}
evictRepeated := func(ss []Slot) {
for i := 0; i < len(ss); i++ {
if hasSlot(ss[i+1:], ss[i]) {
ss[i], ss[len(ss)-1] = ss[len(ss)-1], ss[i]
return
}
}
}
for need := len(news)*avg - len(allots); need > 0; {
noop := true
for inst, slots := range t {
if len(slots) > avg {
evictRepeated(slots)
allots = append(allots, slots[len(slots)-1])
t[inst] = slots[0 : len(slots)-1]
noop = false
if need--; need <= 0 {
break
}
}
}
if noop {
break
}
}
assign := func(new Slot, filter func(inst Inst, slots []Slot, new Slot) bool) bool {
for inst, slots := range t {
if filter(inst, slots, new) {
t[inst] = append(slots, new)
return true
}
}
return false
}
for _, allot := range allots {
if assign(allot, func(inst Inst, slots []Slot, new Slot) bool {
return len(slots) < avg && !hasSlot(slots, new)
}) {
continue
}
if assign(allot, func(inst Inst, slots []Slot, new Slot) bool {
return len(slots) == avg && !hasSlot(slots, new)
}) {
continue
}
if assign(allot, func(inst Inst, slots []Slot, new Slot) bool {
return len(slots) < avg
}) {
continue
}
if !assign(allot, func(inst Inst, slots []Slot, new Slot) bool {
return len(slots) == avg
}) {
panic("impossible")
}
}
return t
}
func Union[Inst, Slot comparable](a, b Table[Inst, Slot]) Table[Inst, Slot] {
t := make(Table[Inst, Slot])
for inst, slots := range a {
t[inst] = append([]Slot{}, slots...)
}
for inst, slots := range b {
t[inst] = append(t[inst], slots...)
}
return t
}
func Reverse[Inst, Slot comparable](t Table[Inst, Slot]) Table[Slot, Inst] {
r := make(Table[Slot, Inst])
for inst, slots := range t {
for _, slot := range slots {
r[slot] = append(r[slot], inst)
}
}
return r
}