Skip to content

Commit f20e696

Browse files
committed
fmtsort: make it work under Go 1.11
It's not possible to make it work correctly in the face of NaNs without MapRange, but we do the best we can.
1 parent dc93391 commit f20e696

File tree

5 files changed

+75
-31
lines changed

5 files changed

+75
-31
lines changed

fmtsort/export_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ import "reflect"
99
func Compare(a, b reflect.Value) int {
1010
return compare(a, b)
1111
}
12+
13+
const BrokenNaNs = brokenNaNs

fmtsort/mapelem.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// +build go1.12
2+
3+
package fmtsort
4+
5+
import "reflect"
6+
7+
const brokenNaNs = false
8+
9+
func mapElems(mapValue reflect.Value) ([]reflect.Value, []reflect.Value) {
10+
key := make([]reflect.Value, mapValue.Len())
11+
value := make([]reflect.Value, len(key))
12+
iter := mapValue.MapRange()
13+
for i := 0; iter.Next(); i++ {
14+
key[i] = iter.Key()
15+
value[i] = iter.Value()
16+
}
17+
return key, value
18+
}

fmtsort/mapelem_1.11.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// +build !go1.12
2+
3+
package fmtsort
4+
5+
import "reflect"
6+
7+
const brokenNaNs = true
8+
9+
func mapElems(mapValue reflect.Value) ([]reflect.Value, []reflect.Value) {
10+
key := mapValue.MapKeys()
11+
value := make([]reflect.Value, len(key))
12+
for i, k := range key {
13+
v := mapValue.MapIndex(k)
14+
if !v.IsValid() {
15+
// Note: we can't retrieve the value, probably because
16+
// the key is NaN, so just do the best we can and
17+
// add a zero value of the correct type in that case.
18+
v = reflect.Zero(mapValue.Type().Elem())
19+
}
20+
value[i] = v
21+
}
22+
return key, value
23+
}

fmtsort/sort.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,7 @@ func Sort(mapValue reflect.Value) *SortedMap {
5353
if mapValue.Type().Kind() != reflect.Map {
5454
return nil
5555
}
56-
key := make([]reflect.Value, mapValue.Len())
57-
value := make([]reflect.Value, len(key))
58-
iter := mapValue.MapRange()
59-
for i := 0; iter.Next(); i++ {
60-
key[i] = iter.Key()
61-
value[i] = iter.Value()
62-
}
56+
key, value := mapElems(mapValue)
6357
sorted := &SortedMap{
6458
Key: key,
6559
Value: value,

fmtsort/sort_test.go

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,50 +82,53 @@ func TestCompare(t *testing.T) {
8282
}
8383

8484
type sortTest struct {
85-
data interface{} // Always a map.
86-
print string // Printed result using our custom printer.
85+
data interface{} // Always a map.
86+
print string // Printed result using our custom printer.
87+
printBrokenNaNs string // Printed result when NaN support is broken (pre Go1.12).
8788
}
8889

8990
var sortTests = []sortTest{
9091
{
91-
map[int]string{7: "bar", -3: "foo"},
92-
"-3:foo 7:bar",
92+
data: map[int]string{7: "bar", -3: "foo"},
93+
print: "-3:foo 7:bar",
9394
},
9495
{
95-
map[uint8]string{7: "bar", 3: "foo"},
96-
"3:foo 7:bar",
96+
data: map[uint8]string{7: "bar", 3: "foo"},
97+
print: "3:foo 7:bar",
9798
},
9899
{
99-
map[string]string{"7": "bar", "3": "foo"},
100-
"3:foo 7:bar",
100+
data: map[string]string{"7": "bar", "3": "foo"},
101+
print: "3:foo 7:bar",
101102
},
102103
{
103-
map[float64]string{7: "bar", -3: "foo", math.NaN(): "nan", math.Inf(0): "inf"},
104-
"NaN:nan -3:foo 7:bar +Inf:inf",
104+
data: map[float64]string{7: "bar", -3: "foo", math.NaN(): "nan", math.Inf(0): "inf"},
105+
print: "NaN:nan -3:foo 7:bar +Inf:inf",
106+
printBrokenNaNs: "NaN: -3:foo 7:bar +Inf:inf",
105107
},
106108
{
107-
map[complex128]string{7 + 2i: "bar2", 7 + 1i: "bar", -3: "foo", complex(math.NaN(), 0i): "nan", complex(math.Inf(0), 0i): "inf"},
108-
"(NaN+0i):nan (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
109+
data: map[complex128]string{7 + 2i: "bar2", 7 + 1i: "bar", -3: "foo", complex(math.NaN(), 0i): "nan", complex(math.Inf(0), 0i): "inf"},
110+
print: "(NaN+0i):nan (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
111+
printBrokenNaNs: "(NaN+0i): (-3+0i):foo (7+1i):bar (7+2i):bar2 (+Inf+0i):inf",
109112
},
110113
{
111-
map[bool]string{true: "true", false: "false"},
112-
"false:false true:true",
114+
data: map[bool]string{true: "true", false: "false"},
115+
print: "false:false true:true",
113116
},
114117
{
115-
chanMap(),
116-
"CHAN0:0 CHAN1:1 CHAN2:2",
118+
data: chanMap(),
119+
print: "CHAN0:0 CHAN1:1 CHAN2:2",
117120
},
118121
{
119-
pointerMap(),
120-
"PTR0:0 PTR1:1 PTR2:2",
122+
data: pointerMap(),
123+
print: "PTR0:0 PTR1:1 PTR2:2",
121124
},
122125
{
123-
map[toy]string{toy{7, 2}: "72", toy{7, 1}: "71", toy{3, 4}: "34"},
124-
"{3 4}:34 {7 1}:71 {7 2}:72",
126+
data: map[toy]string{toy{7, 2}: "72", toy{7, 1}: "71", toy{3, 4}: "34"},
127+
print: "{3 4}:34 {7 1}:71 {7 2}:72",
125128
},
126129
{
127-
map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
128-
"[3 4]:34 [7 1]:71 [7 2]:72",
130+
data: map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
131+
print: "[3 4]:34 [7 1]:71 [7 2]:72",
129132
},
130133
}
131134

@@ -202,8 +205,12 @@ type toy struct {
202205
func TestOrder(t *testing.T) {
203206
for _, test := range sortTests {
204207
got := sprint(test.data)
205-
if got != test.print {
206-
t.Errorf("%s: got %q, want %q", reflect.TypeOf(test.data), got, test.print)
208+
want := test.print
209+
if fmtsort.BrokenNaNs && test.printBrokenNaNs != "" {
210+
want = test.printBrokenNaNs
211+
}
212+
if got != want {
213+
t.Errorf("%s: got %q, want %q", reflect.TypeOf(test.data), got, want)
207214
}
208215
}
209216
}

0 commit comments

Comments
 (0)