1
2
3
4
5 package spec
6
7 import (
8 "fmt"
9 "math"
10 "strings"
11 )
12
13
14
15 type Platform int8
16
17 const (
18 PlatformAMD64 Platform = iota
19 PlatformARM64
20 PlatformWASM
21
22 numPlatforms
23
24
25
26 PlatformAny Platform = -1
27 )
28
29 func (p Platform) String() string {
30 switch p {
31 case PlatformAMD64:
32 return "amd64"
33 case PlatformARM64:
34 return "arm64"
35 case PlatformWASM:
36 return "wasm"
37 case PlatformAny:
38 return "any"
39 }
40 return fmt.Sprintf("Platform(%d)", p)
41 }
42
43
44
45
46
47
48 type Variation[E EltOrMask] struct {
49 canon E
50 v variation[E]
51 }
52
53 type variation[E EltOrMask] interface {
54 permits(x E, plat Platform) bool
55 String() string
56 }
57
58 func (Variation[E]) elemBits() int {
59 return elemBits[E]()
60 }
61
62
63 func (v Variation[E]) Permits(x E, plat Platform) bool {
64 if v.v == nil {
65 return equalExact(x, v.canon)
66 }
67 return v.v.permits(x, plat)
68 }
69
70
71 func (v Variation[E]) Canon() E {
72 return v.canon
73 }
74
75
76 func (v Variation[E]) String() string {
77 if v.v == nil {
78 return fmt.Sprint(v.canon)
79 }
80 return v.v.String()
81 }
82
83
84 func exact[E EltOrMask](x E) Variation[E] {
85 return Variation[E]{canon: x}
86 }
87
88
89
90
91 func perPlatform[E EltOrMask](vals map[Platform]E) Variation[E] {
92 if len(vals) == 0 {
93 panic("perPlatform requires at least one platform value")
94 }
95 var pp perPlatformVar[E]
96 var canon E
97 haveCanon := false
98 for p := range numPlatforms {
99 if val, ok := vals[p]; ok {
100 pp.values[p] = val
101 pp.present |= 1 << p
102 if !haveCanon {
103 canon = val
104 haveCanon = true
105 }
106 }
107 }
108 if pp.present == 0 {
109 panic("perPlatform contains no recognized platforms")
110 }
111 return Variation[E]{canon: canon, v: pp}
112 }
113
114
115
116
117
118 func perPlatformDefault[E EltOrMask](def E, vals map[Platform]E) Variation[E] {
119 all := make(map[Platform]E, numPlatforms)
120 for p := range numPlatforms {
121 all[p] = def
122 }
123 for p, val := range vals {
124 all[p] = val
125 }
126 return perPlatform(all)
127 }
128
129 type perPlatformVar[E EltOrMask] struct {
130 values [numPlatforms]E
131 present uint8
132 }
133
134 func (pp perPlatformVar[E]) permits(x E, plat Platform) bool {
135 if plat == PlatformAny {
136 for p := range numPlatforms {
137 if pp.present&(1<<p) != 0 && equalExact(x, pp.values[p]) {
138 return true
139 }
140 }
141 return false
142 }
143 if plat < 0 || plat >= numPlatforms || pp.present&(1<<plat) == 0 {
144 return false
145 }
146 return equalExact(x, pp.values[plat])
147 }
148
149 func (pp perPlatformVar[E]) String() string {
150 var b strings.Builder
151 b.WriteByte('{')
152 for p := range numPlatforms {
153 if pp.present&(1<<p) != 0 {
154 if b.Len() > 1 {
155 b.WriteByte(' ')
156 }
157 fmt.Fprintf(&b, "%s:%v", p, pp.values[p])
158 }
159 }
160 b.WriteByte('}')
161 return b.String()
162 }
163
164
165 func ulps[E Floats](x E, n uint64) Variation[E] {
166 if n == 0 {
167 return exact(x)
168 }
169 return Variation[E]{canon: x, v: ulpsVar[E]{x: x, ulps: n}}
170 }
171
172 type ulpsVar[E Floats] struct {
173 x E
174 ulps uint64
175 }
176
177 func (u ulpsVar[E]) permits(got E, _ Platform) bool {
178 if equalExact(got, u.x) {
179 return true
180 }
181
182 got64, want64 := float64(got), float64(u.x)
183 if math.IsNaN(got64) || math.IsNaN(want64) ||
184 math.IsInf(got64, 0) || math.IsInf(want64, 0) ||
185 math.Signbit(got64) != math.Signbit(want64) {
186 return false
187 }
188
189
190
191
192
193 switch want := any(u.x).(type) {
194 case float32:
195 gb, wb := math.Float32bits(any(got).(float32)), math.Float32bits(want)
196 return uint64(max(gb, wb)-min(gb, wb)) <= u.ulps
197 case float64:
198 gb, wb := math.Float64bits(any(got).(float64)), math.Float64bits(want)
199 return max(gb, wb)-min(gb, wb) <= u.ulps
200 }
201 panic("unreachable")
202 }
203
204 func (u ulpsVar[E]) String() string {
205 return fmt.Sprintf("%v±%dulp", u.x, u.ulps)
206 }
207
208
209
210
211
212 func anyOf[E EltOrMask](vals ...E) Variation[E] {
213 if len(vals) == 0 {
214 panic("anyOf requires at least one value")
215 }
216 if len(vals) == 1 {
217 return exact(vals[0])
218 }
219 return Variation[E]{canon: vals[0], v: anyOfVar[E](vals)}
220 }
221
222 type anyOfVar[E EltOrMask] []E
223
224 func (a anyOfVar[E]) permits(x E, _ Platform) bool {
225 for _, v := range a {
226 if equalExact(x, v) {
227 return true
228 }
229 }
230 return false
231 }
232
233 func (a anyOfVar[E]) String() string {
234 var b strings.Builder
235 b.WriteByte('{')
236 for i, v := range a {
237 if i > 0 {
238 b.WriteByte('|')
239 }
240 fmt.Fprint(&b, v)
241 }
242 b.WriteByte('}')
243 return b.String()
244 }
245
246
247
248
249
250
251
252 func undef[E EltOrMask]() Variation[E] {
253 return Variation[E]{v: undefVar[E]{}}
254 }
255
256 type undefVar[E EltOrMask] struct{}
257
258 func (undefVar[E]) permits(_ E, _ Platform) bool { return true }
259 func (undefVar[E]) String() string { return "undef" }
260
261
262
263 func equalExact[E EltOrMask](got, want E) bool {
264 switch got := any(got).(type) {
265 case float32:
266 want := any(want).(float32)
267 if math.IsNaN(float64(got)) && math.IsNaN(float64(want)) {
268 return true
269 }
270 return math.Float32bits(got) == math.Float32bits(want)
271 case float64:
272 want := any(want).(float64)
273 if math.IsNaN(got) && math.IsNaN(want) {
274 return true
275 }
276 return math.Float64bits(got) == math.Float64bits(want)
277 }
278 return got == want
279 }
280
View as plain text