@@ -173,7 +173,7 @@ type Map struct {
173
173
order []int
174
174
}
175
175
176
- func (m * Map ) computeOrder () {
176
+ func (m * Map ) computeOrder () [] int {
177
177
if len (m .order ) != len (m .Items ) {
178
178
m .order = make ([]int , len (m .Items ))
179
179
for i := range m .order {
@@ -183,28 +183,67 @@ func (m *Map) computeOrder() {
183
183
return m.Items [m.order [i ]].Name < m.Items [m.order [j ]].Name
184
184
})
185
185
}
186
+ return m .order
186
187
}
187
188
188
189
// Less compares two maps lexically.
189
190
func (m * Map ) Less (rhs * Map ) bool {
190
- m .computeOrder ()
191
- rhs .computeOrder ()
191
+ var noAllocL , noAllocR [2 ]int
192
+ var morder , rorder []int
193
+
194
+ // For very short maps (<2 elements) this permits us to avoid
195
+ // allocating the order array. We could make this accomodate larger
196
+ // maps, but 2 items should be enough to cover most path element
197
+ // comparisons, and at some point there will be diminishing returns.
198
+ // This has a large effect on the path element deserialization test,
199
+ // because everything is sorted / compared, but only once.
200
+ switch len (m .Items ) {
201
+ case 0 :
202
+ morder = noAllocL [0 :0 ]
203
+ case 1 :
204
+ morder = noAllocL [0 :1 ]
205
+ case 2 :
206
+ morder = noAllocL [0 :2 ]
207
+ if m .Items [0 ].Name > m .Items [1 ].Name {
208
+ morder [0 ] = 1
209
+ } else {
210
+ morder [1 ] = 1
211
+ }
212
+ default :
213
+ morder = m .computeOrder ()
214
+ }
215
+
216
+ switch len (rhs .Items ) {
217
+ case 0 :
218
+ rorder = noAllocR [0 :0 ]
219
+ case 1 :
220
+ rorder = noAllocR [0 :1 ]
221
+ case 2 :
222
+ rorder = noAllocR [0 :2 ]
223
+ if rhs .Items [0 ].Name > rhs .Items [1 ].Name {
224
+ rorder [0 ] = 1
225
+ } else {
226
+ rorder [1 ] = 1
227
+ }
228
+ default :
229
+ rorder = rhs .computeOrder ()
230
+ }
192
231
193
232
i := 0
194
233
for {
195
- if i >= len (m . order ) && i >= len (rhs . order ) {
234
+ if i >= len (morder ) && i >= len (rorder ) {
196
235
// Maps are the same length and all items are equal.
197
236
return false
198
237
}
199
- if i >= len (m . order ) {
238
+ if i >= len (morder ) {
200
239
// LHS is shorter.
201
240
return true
202
241
}
203
- if i >= len (rhs . order ) {
242
+ if i >= len (rorder ) {
204
243
// RHS is shorter.
205
244
return false
206
245
}
207
- fa , fb := & m.Items [m. order [i ]], & rhs.Items [rhs. order [i ]]
246
+ fa , fb := & m.Items [morder [i ]], & rhs.Items [rorder [i ]]
208
247
if fa .Name != fb .Name {
209
248
// the map having the field name that sorts lexically less is "less"
210
249
return fa .Name < fb .Name
0 commit comments