...
1
16
17
18
19
20
21
22
23
24
25
26
27
28 package cpuset
29
30 import (
31 "bytes"
32 "fmt"
33 "reflect"
34 "sort"
35 "strconv"
36 "strings"
37 )
38
39
40 type CPUSet struct {
41 elems map[int]struct{}
42 }
43
44
45 func New(cpus ...int) CPUSet {
46 s := CPUSet{
47 elems: map[int]struct{}{},
48 }
49 for _, c := range cpus {
50 s.add(c)
51 }
52 return s
53 }
54
55
56
57 func (s CPUSet) add(elems ...int) {
58 for _, elem := range elems {
59 s.elems[elem] = struct{}{}
60 }
61 }
62
63
64 func (s CPUSet) Size() int {
65 return len(s.elems)
66 }
67
68
69 func (s CPUSet) IsEmpty() bool {
70 return s.Size() == 0
71 }
72
73
74 func (s CPUSet) Contains(cpu int) bool {
75 _, found := s.elems[cpu]
76 return found
77 }
78
79
80
81 func (s CPUSet) Equals(s2 CPUSet) bool {
82 return reflect.DeepEqual(s.elems, s2.elems)
83 }
84
85
86
87 func (s CPUSet) filter(predicate func(int) bool) CPUSet {
88 r := New()
89 for cpu := range s.elems {
90 if predicate(cpu) {
91 r.add(cpu)
92 }
93 }
94 return r
95 }
96
97
98 func (s CPUSet) IsSubsetOf(s2 CPUSet) bool {
99 result := true
100 for cpu := range s.elems {
101 if !s2.Contains(cpu) {
102 result = false
103 break
104 }
105 }
106 return result
107 }
108
109
110
111
112 func (s CPUSet) Union(s2 ...CPUSet) CPUSet {
113 r := New()
114 for cpu := range s.elems {
115 r.add(cpu)
116 }
117 for _, cs := range s2 {
118 for cpu := range cs.elems {
119 r.add(cpu)
120 }
121 }
122 return r
123 }
124
125
126
127
128 func (s CPUSet) Intersection(s2 CPUSet) CPUSet {
129 return s.filter(func(cpu int) bool { return s2.Contains(cpu) })
130 }
131
132
133
134
135 func (s CPUSet) Difference(s2 CPUSet) CPUSet {
136 return s.filter(func(cpu int) bool { return !s2.Contains(cpu) })
137 }
138
139
140
141 func (s CPUSet) List() []int {
142 result := s.UnsortedList()
143 sort.Ints(result)
144 return result
145 }
146
147
148
149 func (s CPUSet) UnsortedList() []int {
150 result := make([]int, 0, len(s.elems))
151 for cpu := range s.elems {
152 result = append(result, cpu)
153 }
154 return result
155 }
156
157
158
159
160
161 func (s CPUSet) String() string {
162 if s.IsEmpty() {
163 return ""
164 }
165
166 elems := s.List()
167
168 type rng struct {
169 start int
170 end int
171 }
172
173 ranges := []rng{{elems[0], elems[0]}}
174
175 for i := 1; i < len(elems); i++ {
176 lastRange := &ranges[len(ranges)-1]
177
178 if elems[i] == lastRange.end+1 {
179
180 lastRange.end = elems[i]
181 continue
182 }
183
184 ranges = append(ranges, rng{elems[i], elems[i]})
185 }
186
187
188 var result bytes.Buffer
189 for _, r := range ranges {
190 if r.start == r.end {
191 result.WriteString(strconv.Itoa(r.start))
192 } else {
193 result.WriteString(fmt.Sprintf("%d-%d", r.start, r.end))
194 }
195 result.WriteString(",")
196 }
197 return strings.TrimRight(result.String(), ",")
198 }
199
200
201
202
203 func Parse(s string) (CPUSet, error) {
204
205 if s == "" {
206 return New(), nil
207 }
208
209 result := New()
210
211
212
213 ranges := strings.Split(s, ",")
214
215 for _, r := range ranges {
216 boundaries := strings.SplitN(r, "-", 2)
217 if len(boundaries) == 1 {
218
219 elem, err := strconv.Atoi(boundaries[0])
220 if err != nil {
221 return New(), err
222 }
223 result.add(elem)
224 } else if len(boundaries) == 2 {
225
226 start, err := strconv.Atoi(boundaries[0])
227 if err != nil {
228 return New(), err
229 }
230 end, err := strconv.Atoi(boundaries[1])
231 if err != nil {
232 return New(), err
233 }
234 if start > end {
235 return New(), fmt.Errorf("invalid range %q (%d > %d)", r, start, end)
236 }
237
238
239
240
241 for e := start; e <= end; e++ {
242 result.add(e)
243 }
244 }
245 }
246 return result, nil
247 }
248
249
250 func (s CPUSet) Clone() CPUSet {
251 r := New()
252 for elem := range s.elems {
253 r.add(elem)
254 }
255 return r
256 }
257
View as plain text