proto/equal: reduce equal scalar value allocation

Instead of lifting values to interface and then do equality test,
compare scalar values with defined types to reduce allocation
from interface.

Change-Id: Ieb777fbd1a48c83d896d0ebe6ad605433f44c16c
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/253100
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Trust: Damien Neil <dneil@google.com>
Trust: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
Tzu-Chiao Yeh 2020-09-06 08:54:02 +08:00 committed by Joe Tsai
parent 53a58a916f
commit f62736dede
2 changed files with 94 additions and 12 deletions

View File

@ -111,18 +111,31 @@ func equalList(fd pref.FieldDescriptor, x, y pref.List) bool {
// equalValue compares two singular values.
func equalValue(fd pref.FieldDescriptor, x, y pref.Value) bool {
switch {
case fd.Message() != nil:
return equalMessage(x.Message(), y.Message())
case fd.Kind() == pref.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case fd.Kind() == pref.FloatKind, fd.Kind() == pref.DoubleKind:
switch fd.Kind() {
case pref.BoolKind:
return x.Bool() == y.Bool()
case pref.EnumKind:
return x.Enum() == y.Enum()
case pref.Int32Kind, pref.Sint32Kind,
pref.Int64Kind, pref.Sint64Kind,
pref.Sfixed32Kind, pref.Sfixed64Kind:
return x.Int() == y.Int()
case pref.Uint32Kind, pref.Uint64Kind,
pref.Fixed32Kind, pref.Fixed64Kind:
return x.Uint() == y.Uint()
case pref.FloatKind, pref.DoubleKind:
fx := x.Float()
fy := y.Float()
if math.IsNaN(fx) || math.IsNaN(fy) {
return math.IsNaN(fx) && math.IsNaN(fy)
}
return fx == fy
case pref.StringKind:
return x.String() == y.String()
case pref.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case pref.MessageKind, pref.GroupKind:
return equalMessage(x.Message(), y.Message())
default:
return x.Interface() == y.Interface()
}

View File

@ -41,18 +41,15 @@ func TestEqual(t *testing.T) {
x: new(testpb.TestAllTypes),
y: new(testpb.TestAllTypes),
eq: true,
},
{
}, {
x: (*testpb.TestAllTypes)(nil),
y: (*testpb.TestAllExtensions)(nil),
eq: false,
},
{
}, {
x: (*testpb.TestAllTypes)(nil),
y: new(testpb.TestAllExtensions),
eq: false,
},
{
}, {
x: new(testpb.TestAllTypes),
y: new(testpb.TestAllExtensions),
eq: false,
@ -113,6 +110,78 @@ func TestEqual(t *testing.T) {
}, {
x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_BAR.Enum()},
}, {
x: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
y: &testpb.TestAllTypes{OptionalInt32: proto.Int32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalInt64: proto.Int64(2)},
y: &testpb.TestAllTypes{OptionalInt64: proto.Int64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalUint32: proto.Uint32(2)},
y: &testpb.TestAllTypes{OptionalUint32: proto.Uint32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalUint64: proto.Uint64(2)},
y: &testpb.TestAllTypes{OptionalUint64: proto.Uint64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalSint32: proto.Int32(2)},
y: &testpb.TestAllTypes{OptionalSint32: proto.Int32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
y: &testpb.TestAllTypes{OptionalSint64: proto.Int64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(2)},
y: &testpb.TestAllTypes{OptionalFixed32: proto.Uint32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(2)},
y: &testpb.TestAllTypes{OptionalFixed64: proto.Uint64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(2)},
y: &testpb.TestAllTypes{OptionalSfixed32: proto.Int32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(2)},
y: &testpb.TestAllTypes{OptionalSfixed64: proto.Int64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalFloat: proto.Float32(2)},
y: &testpb.TestAllTypes{OptionalFloat: proto.Float32(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalDouble: proto.Float64(2)},
y: &testpb.TestAllTypes{OptionalDouble: proto.Float64(2)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalFloat: proto.Float32(float32(math.NaN()))},
y: &testpb.TestAllTypes{OptionalFloat: proto.Float32(float32(math.NaN()))},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalDouble: proto.Float64(float64(math.NaN()))},
y: &testpb.TestAllTypes{OptionalDouble: proto.Float64(float64(math.NaN()))},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalBool: proto.Bool(true)},
y: &testpb.TestAllTypes{OptionalBool: proto.Bool(true)},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalString: proto.String("abc")},
y: &testpb.TestAllTypes{OptionalString: proto.String("abc")},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalBytes: []byte("abc")},
y: &testpb.TestAllTypes{OptionalBytes: []byte("abc")},
eq: true,
}, {
x: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
y: &testpb.TestAllTypes{OptionalNestedEnum: testpb.TestAllTypes_FOO.Enum()},
eq: true,
},
// Proto2 presence.