Commit cd32aae3 authored by Yilun Chong's avatar Yilun Chong

Merge branch 'master' of https://github.com/google/protobuf into JavaCaliper

parents 75523ec0 426cf6f3
......@@ -72,6 +72,7 @@ cc_library(
"src/google/protobuf/extension_set.cc",
"src/google/protobuf/generated_message_table_driven_lite.cc",
"src/google/protobuf/generated_message_util.cc",
"src/google/protobuf/implicit_weak_message.cc",
"src/google/protobuf/io/coded_stream.cc",
"src/google/protobuf/io/zero_copy_stream.cc",
"src/google/protobuf/io/zero_copy_stream_impl_lite.cc",
......@@ -734,6 +735,7 @@ py_proto_library(
":python_srcs",
"//external:six",
],
py_extra_srcs = glob(["python/**/__init__.py"]),
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
)
......
......@@ -84,6 +84,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs \
csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs \
csharp/src/Google.Protobuf.Test/Collections/MapFieldTest.cs \
csharp/src/Google.Protobuf.Test/Collections/ProtobufEqualityComparersTest.cs \
csharp/src/Google.Protobuf.Test/Collections/RepeatedFieldTest.cs \
csharp/src/Google.Protobuf.Test/Compatibility/PropertyInfoExtensionsTest.cs \
csharp/src/Google.Protobuf.Test/Compatibility/StreamExtensionsTest.cs \
......@@ -104,6 +105,7 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.Test/Reflection/TypeRegistryTest.cs \
csharp/src/Google.Protobuf.Test/SampleEnum.cs \
csharp/src/Google.Protobuf.Test/SampleMessages.cs \
csharp/src/Google.Protobuf.Test/SampleNaNs.cs \
csharp/src/Google.Protobuf.Test/TestCornerCases.cs \
csharp/src/Google.Protobuf.Test/TestProtos/ForeignMessagePartial.cs \
csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs \
......@@ -119,13 +121,16 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf.Test/WellKnownTypes/FieldMaskTest.cs \
csharp/src/Google.Protobuf.Test/WellKnownTypes/TimestampTest.cs \
csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs \
csharp/src/Google.Protobuf.Test/UnknownFieldSetTest.cs \
csharp/src/Google.Protobuf.sln \
csharp/src/Google.Protobuf/ByteArray.cs \
csharp/src/Google.Protobuf/ByteString.cs \
csharp/src/Google.Protobuf/CodedInputStream.cs \
csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs \
csharp/src/Google.Protobuf/CodedOutputStream.cs \
csharp/src/Google.Protobuf/Collections/Lists.cs \
csharp/src/Google.Protobuf/Collections/MapField.cs \
csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs \
csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs \
csharp/src/Google.Protobuf/Collections/RepeatedField.cs \
csharp/src/Google.Protobuf/Compatibility/PropertyInfoExtensions.cs \
......@@ -193,7 +198,9 @@ csharp_EXTRA_DIST= \
csharp/src/Google.Protobuf/WellKnownTypes/ValuePartial.cs \
csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs \
csharp/src/Google.Protobuf/WellKnownTypes/WrappersPartial.cs \
csharp/src/Google.Protobuf/WireFormat.cs
csharp/src/Google.Protobuf/WireFormat.cs \
csharp/src/Google.Protobuf/UnknownField.cs \
csharp/src/Google.Protobuf/UnknownFieldSet.cs
java_EXTRA_DIST= \
java/README.md \
......
......@@ -53,6 +53,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_ref
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_table_driven.h" include\google\protobuf\generated_message_table_driven.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h" include\google\protobuf\io\gzip_stream.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\printer.h" include\google\protobuf\io\printer.h
......
Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
......@@ -638,7 +638,7 @@ namespace Google.Protobuf
}
[Test]
public void IgnoreUnknownFields_RealDataStillRead()
public void DiscardUnknownFields_RealDataStillRead()
{
var message = SampleMessages.CreateFullTestAllTypes();
var stream = new MemoryStream();
......@@ -652,16 +652,18 @@ namespace Google.Protobuf
stream.Position = 0;
var parsed = TestAllTypes.Parser.ParseFrom(stream);
Assert.AreEqual(message, parsed);
// TODO(jieluo): Add test back after DiscardUnknownFields is supported
// Assert.AreEqual(message, parsed);
}
[Test]
public void IgnoreUnknownFields_AllTypes()
public void DiscardUnknownFields_AllTypes()
{
// Simple way of ensuring we can skip all kinds of fields.
var data = SampleMessages.CreateFullTestAllTypes().ToByteArray();
var empty = Empty.Parser.ParseFrom(data);
Assert.AreEqual(new Empty(), empty);
// TODO(jieluo): Add test back after DiscardUnknownField is supported.
// Assert.AreEqual(new Empty(), empty);
}
// This was originally seen as a conformance test failure.
......@@ -720,4 +722,4 @@ namespace Google.Protobuf
Assert.AreEqual("{ \"c\": 31 }", writer.ToString());
}
}
}
\ No newline at end of file
}
......@@ -377,3 +377,4 @@ service TestService {
message BarRequest {}
message BarResponse {}
message TestEmptyMessage {}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: addressbook.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: addressbook.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -49,6 +51,7 @@ namespace Google.Protobuf.Examples.AddressBook {
/// </summary>
public sealed partial class Person : pb::IMessage<Person> {
private static readonly pb::MessageParser<Person> _parser = new pb::MessageParser<Person>(() => new Person());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<Person> Parser { get { return _parser; } }
......@@ -76,6 +79,7 @@ namespace Google.Protobuf.Examples.AddressBook {
email_ = other.email_;
phones_ = other.phones_.Clone();
LastUpdated = other.lastUpdated_ != null ? other.LastUpdated.Clone() : null;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -158,7 +162,7 @@ namespace Google.Protobuf.Examples.AddressBook {
if (Email != other.Email) return false;
if(!phones_.Equals(other.phones_)) return false;
if (!object.Equals(LastUpdated, other.LastUpdated)) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -169,6 +173,9 @@ namespace Google.Protobuf.Examples.AddressBook {
if (Email.Length != 0) hash ^= Email.GetHashCode();
hash ^= phones_.GetHashCode();
if (lastUpdated_ != null) hash ^= LastUpdated.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -196,6 +203,9 @@ namespace Google.Protobuf.Examples.AddressBook {
output.WriteRawTag(42);
output.WriteMessage(LastUpdated);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -214,6 +224,9 @@ namespace Google.Protobuf.Examples.AddressBook {
if (lastUpdated_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(LastUpdated);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -238,6 +251,7 @@ namespace Google.Protobuf.Examples.AddressBook {
}
LastUpdated.MergeFrom(other.LastUpdated);
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -246,7 +260,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
Name = input.ReadString();
......@@ -287,6 +301,7 @@ namespace Google.Protobuf.Examples.AddressBook {
public sealed partial class PhoneNumber : pb::IMessage<PhoneNumber> {
private static readonly pb::MessageParser<PhoneNumber> _parser = new pb::MessageParser<PhoneNumber>(() => new PhoneNumber());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<PhoneNumber> Parser { get { return _parser; } }
......@@ -311,6 +326,7 @@ namespace Google.Protobuf.Examples.AddressBook {
public PhoneNumber(PhoneNumber other) : this() {
number_ = other.number_;
type_ = other.type_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -355,7 +371,7 @@ namespace Google.Protobuf.Examples.AddressBook {
}
if (Number != other.Number) return false;
if (Type != other.Type) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -363,6 +379,9 @@ namespace Google.Protobuf.Examples.AddressBook {
int hash = 1;
if (Number.Length != 0) hash ^= Number.GetHashCode();
if (Type != 0) hash ^= Type.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -381,6 +400,9 @@ namespace Google.Protobuf.Examples.AddressBook {
output.WriteRawTag(16);
output.WriteEnum((int) Type);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -392,6 +414,9 @@ namespace Google.Protobuf.Examples.AddressBook {
if (Type != 0) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -406,6 +431,7 @@ namespace Google.Protobuf.Examples.AddressBook {
if (other.Type != 0) {
Type = other.Type;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -414,7 +440,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
Number = input.ReadString();
......@@ -440,6 +466,7 @@ namespace Google.Protobuf.Examples.AddressBook {
/// </summary>
public sealed partial class AddressBook : pb::IMessage<AddressBook> {
private static readonly pb::MessageParser<AddressBook> _parser = new pb::MessageParser<AddressBook>(() => new AddressBook());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<AddressBook> Parser { get { return _parser; } }
......@@ -463,6 +490,7 @@ namespace Google.Protobuf.Examples.AddressBook {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public AddressBook(AddressBook other) : this() {
people_ = other.people_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -494,13 +522,16 @@ namespace Google.Protobuf.Examples.AddressBook {
return true;
}
if(!people_.Equals(other.people_)) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= people_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -512,12 +543,18 @@ namespace Google.Protobuf.Examples.AddressBook {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
people_.WriteTo(output, _repeated_people_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += people_.CalculateSize(_repeated_people_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -527,6 +564,7 @@ namespace Google.Protobuf.Examples.AddressBook {
return;
}
people_.Add(other.people_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -535,7 +573,7 @@ namespace Google.Protobuf.Examples.AddressBook {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
people_.AddEntriesFrom(input, _repeated_people_codec);
......
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: conformance.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: conformance.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -62,6 +64,7 @@ namespace Conformance {
/// </summary>
public sealed partial class ConformanceRequest : pb::IMessage<ConformanceRequest> {
private static readonly pb::MessageParser<ConformanceRequest> _parser = new pb::MessageParser<ConformanceRequest>(() => new ConformanceRequest());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<ConformanceRequest> Parser { get { return _parser; } }
......@@ -95,6 +98,7 @@ namespace Conformance {
break;
}
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -191,7 +195,7 @@ namespace Conformance {
if (RequestedOutputFormat != other.RequestedOutputFormat) return false;
if (MessageType != other.MessageType) return false;
if (PayloadCase != other.PayloadCase) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -202,6 +206,9 @@ namespace Conformance {
if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode();
if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
hash ^= (int) payloadCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -228,6 +235,9 @@ namespace Conformance {
output.WriteRawTag(34);
output.WriteString(MessageType);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -245,6 +255,9 @@ namespace Conformance {
if (MessageType.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageType);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -268,6 +281,7 @@ namespace Conformance {
break;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -276,7 +290,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
ProtobufPayload = input.ReadBytes();
......@@ -305,6 +319,7 @@ namespace Conformance {
/// </summary>
public sealed partial class ConformanceResponse : pb::IMessage<ConformanceResponse> {
private static readonly pb::MessageParser<ConformanceResponse> _parser = new pb::MessageParser<ConformanceResponse>(() => new ConformanceResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<ConformanceResponse> Parser { get { return _parser; } }
......@@ -348,6 +363,7 @@ namespace Conformance {
break;
}
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -493,7 +509,7 @@ namespace Conformance {
if (JsonPayload != other.JsonPayload) return false;
if (Skipped != other.Skipped) return false;
if (ResultCase != other.ResultCase) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -506,6 +522,9 @@ namespace Conformance {
if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
if (resultCase_ == ResultOneofCase.Skipped) hash ^= Skipped.GetHashCode();
hash ^= (int) resultCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -540,6 +559,9 @@ namespace Conformance {
output.WriteRawTag(50);
output.WriteString(SerializeError);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -563,6 +585,9 @@ namespace Conformance {
if (resultCase_ == ResultOneofCase.Skipped) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Skipped);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -592,6 +617,7 @@ namespace Conformance {
break;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -600,7 +626,7 @@ namespace Conformance {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
ParseError = input.ReadString();
......
......@@ -540,6 +540,49 @@ namespace Google.Protobuf.Collections
Assert.Throws<ArgumentException>(() => map.ToString());
}
[Test]
public void NaNValuesComparedBitwise()
{
var map1 = new MapField<string, double>
{
{ "x", SampleNaNs.Regular },
{ "y", SampleNaNs.SignallingFlipped }
};
var map2 = new MapField<string, double>
{
{ "x", SampleNaNs.Regular },
{ "y", SampleNaNs.PayloadFlipped }
};
var map3 = new MapField<string, double>
{
{ "x", SampleNaNs.Regular },
{ "y", SampleNaNs.SignallingFlipped }
};
EqualityTester.AssertInequality(map1, map2);
EqualityTester.AssertEquality(map1, map3);
Assert.True(map1.Values.Contains(SampleNaNs.SignallingFlipped));
Assert.False(map2.Values.Contains(SampleNaNs.SignallingFlipped));
}
// This wouldn't usually happen, as protos can't use doubles as map keys,
// but let's be consistent.
[Test]
public void NaNKeysComparedBitwise()
{
var map = new MapField<double, string>
{
{ SampleNaNs.Regular, "x" },
{ SampleNaNs.SignallingFlipped, "y" }
};
Assert.AreEqual("x", map[SampleNaNs.Regular]);
Assert.AreEqual("y", map[SampleNaNs.SignallingFlipped]);
string ignored;
Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out ignored));
}
#if !NET35
[Test]
public void IDictionaryKeys_Equals_IReadOnlyDictionaryKeys()
......
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2017 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System.Collections.Generic;
using System.Linq;
using static Google.Protobuf.Collections.ProtobufEqualityComparers;
namespace Google.Protobuf.Collections
{
public class ProtobufEqualityComparersTest
{
private static readonly double[] doubles =
{
0,
1,
1.5,
-1.5,
double.PositiveInfinity,
double.NegativeInfinity,
// Three different types of NaN...
SampleNaNs.Regular,
SampleNaNs.SignallingFlipped,
SampleNaNs.PayloadFlipped
};
[Test]
public void GetEqualityComparer_Default()
{
// It's more pain than it's worth to try to parameterize these tests.
Assert.AreSame(EqualityComparer<object>.Default, GetEqualityComparer<object>());
Assert.AreSame(EqualityComparer<string>.Default, GetEqualityComparer<string>());
Assert.AreSame(EqualityComparer<int>.Default, GetEqualityComparer<int>());
Assert.AreSame(EqualityComparer<int?>.Default, GetEqualityComparer<int?>());
}
[Test]
public void GetEqualityComparer_NotDefault()
{
// It's more pain than it's worth to try to parameterize these tests.
Assert.AreSame(BitwiseDoubleEqualityComparer, GetEqualityComparer<double>());
Assert.AreSame(BitwiseSingleEqualityComparer, GetEqualityComparer<float>());
Assert.AreSame(BitwiseNullableDoubleEqualityComparer, GetEqualityComparer<double?>());
Assert.AreSame(BitwiseNullableSingleEqualityComparer, GetEqualityComparer<float?>());
}
[Test]
public void DoubleComparisons()
{
ValidateEqualityComparer(BitwiseDoubleEqualityComparer, doubles);
}
[Test]
public void NullableDoubleComparisons()
{
ValidateEqualityComparer(BitwiseNullableDoubleEqualityComparer, doubles.Select(d => (double?) d).Concat(new double?[] { null }));
}
[Test]
public void SingleComparisons()
{
ValidateEqualityComparer(BitwiseSingleEqualityComparer, doubles.Select(d => (float) d));
}
[Test]
public void NullableSingleComparisons()
{
ValidateEqualityComparer(BitwiseNullableSingleEqualityComparer, doubles.Select(d => (float?) d).Concat(new float?[] { null }));
}
private static void ValidateEqualityComparer<T>(EqualityComparer<T> comparer, IEnumerable<T> values)
{
var array = values.ToArray();
// Each value should be equal to itself, but not to any other value.
for (int i = 0; i < array.Length; i++)
{
for (int j = 0; j < array.Length; j++)
{
if (i == j)
{
Assert.IsTrue(comparer.Equals(array[i], array[j]),
"{0} should be equal to itself", array[i], array[j]);
}
else
{
Assert.IsFalse(comparer.Equals(array[i], array[j]),
"{0} and {1} should not be equal", array[i], array[j]);
Assert.AreNotEqual(comparer.GetHashCode(array[i]), comparer.GetHashCode(array[j]),
"Hash codes for {0} and {1} should not be equal", array[i], array[j]);
}
}
}
}
}
}
......@@ -742,5 +742,18 @@ namespace Google.Protobuf.Collections
var text = list.ToString();
Assert.AreEqual(text, "[ { \"foo\": 20 } ]", message.ToString());
}
[Test]
public void NaNValuesComparedBitwise()
{
var list1 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.SignallingFlipped };
var list2 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.PayloadFlipped };
var list3 = new RepeatedField<double> { SampleNaNs.Regular, SampleNaNs.SignallingFlipped };
EqualityTester.AssertInequality(list1, list2);
EqualityTester.AssertEquality(list1, list3);
Assert.True(list1.Contains(SampleNaNs.SignallingFlipped));
Assert.False(list2.Contains(SampleNaNs.SignallingFlipped));
}
}
}
......@@ -638,7 +638,7 @@ namespace Google.Protobuf
}
[Test]
public void IgnoreUnknownFields_RealDataStillRead()
public void DiscardUnknownFields_RealDataStillRead()
{
var message = SampleMessages.CreateFullTestAllTypes();
var stream = new MemoryStream();
......@@ -652,16 +652,18 @@ namespace Google.Protobuf
stream.Position = 0;
var parsed = TestAllTypes.Parser.ParseFrom(stream);
Assert.AreEqual(message, parsed);
// TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
// Assert.AreEqual(message, parsed);
}
[Test]
public void IgnoreUnknownFields_AllTypes()
public void DiscardUnknownFields_AllTypes()
{
// Simple way of ensuring we can skip all kinds of fields.
var data = SampleMessages.CreateFullTestAllTypes().ToByteArray();
var empty = Empty.Parser.ParseFrom(data);
Assert.AreEqual(new Empty(), empty);
// TODO(jieluo): Add test back when DiscardUnknownFields API is supported.
// Assert.AreNotEqual(new Empty(), empty);
}
// This was originally seen as a conformance test failure.
......@@ -719,5 +721,16 @@ namespace Google.Protobuf
JsonFormatter.Default.Format(message, writer);
Assert.AreEqual("{ \"c\": 31 }", writer.ToString());
}
[Test]
public void NaNComparisons()
{
var message1 = new TestAllTypes { SingleDouble = SampleNaNs.Regular };
var message2 = new TestAllTypes { SingleDouble = SampleNaNs.PayloadFlipped };
var message3 = new TestAllTypes { SingleDouble = SampleNaNs.Regular };
EqualityTester.AssertInequality(message1, message2);
EqualityTester.AssertEquality(message1, message3);
}
}
}
\ No newline at end of file
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2017 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
namespace Google.Protobuf
{
/// <summary>
/// Samples of different not-a-number values, for testing equality comparisons.
/// </summary>
public static class SampleNaNs
{
public static double Regular { get; } = double.NaN;
// Signalling bit is inverted compared with double.NaN. Doesn't really matter
// whether that makes it quiet or signalling - it's different.
public static double SignallingFlipped { get; } =
BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(double.NaN) ^ -0x8000_0000_0000_0000L);
// A bit in the middle of the mantissa is flipped; this difference is preserved when casting to float.
public static double PayloadFlipped { get; } =
BitConverter.Int64BitsToDouble(BitConverter.DoubleToInt64Bits(double.NaN) ^ 0x1_0000_0000L);
}
}
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: unittest_import_proto3.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: unittest_import_proto3.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -50,6 +52,7 @@ namespace Google.Protobuf.TestProtos {
#region Messages
public sealed partial class ImportMessage : pb::IMessage<ImportMessage> {
private static readonly pb::MessageParser<ImportMessage> _parser = new pb::MessageParser<ImportMessage>(() => new ImportMessage());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<ImportMessage> Parser { get { return _parser; } }
......@@ -73,6 +76,7 @@ namespace Google.Protobuf.TestProtos {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public ImportMessage(ImportMessage other) : this() {
d_ = other.d_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -105,13 +109,16 @@ namespace Google.Protobuf.TestProtos {
return true;
}
if (D != other.D) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (D != 0) hash ^= D.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -126,6 +133,9 @@ namespace Google.Protobuf.TestProtos {
output.WriteRawTag(8);
output.WriteInt32(D);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -134,6 +144,9 @@ namespace Google.Protobuf.TestProtos {
if (D != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(D);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -145,6 +158,7 @@ namespace Google.Protobuf.TestProtos {
if (other.D != 0) {
D = other.D;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -153,7 +167,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
D = input.ReadInt32();
......
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: unittest_import_public_proto3.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: unittest_import_public_proto3.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -38,6 +40,7 @@ namespace Google.Protobuf.TestProtos {
#region Messages
public sealed partial class PublicImportMessage : pb::IMessage<PublicImportMessage> {
private static readonly pb::MessageParser<PublicImportMessage> _parser = new pb::MessageParser<PublicImportMessage>(() => new PublicImportMessage());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<PublicImportMessage> Parser { get { return _parser; } }
......@@ -61,6 +64,7 @@ namespace Google.Protobuf.TestProtos {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public PublicImportMessage(PublicImportMessage other) : this() {
e_ = other.e_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -93,13 +97,16 @@ namespace Google.Protobuf.TestProtos {
return true;
}
if (E != other.E) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
if (E != 0) hash ^= E.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -114,6 +121,9 @@ namespace Google.Protobuf.TestProtos {
output.WriteRawTag(8);
output.WriteInt32(E);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -122,6 +132,9 @@ namespace Google.Protobuf.TestProtos {
if (E != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(E);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -133,6 +146,7 @@ namespace Google.Protobuf.TestProtos {
if (other.E != 0) {
E = other.E;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -141,7 +155,7 @@ namespace Google.Protobuf.TestProtos {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
E = input.ReadInt32();
......
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
namespace Google.Protobuf
{
public class UnknownFieldSetTest
{
[Test]
public void EmptyUnknownFieldSet()
{
UnknownFieldSet unknownFields = new UnknownFieldSet();
Assert.AreEqual(0, unknownFields.CalculateSize());
}
[Test]
public void MergeUnknownFieldSet()
{
UnknownFieldSet unknownFields = new UnknownFieldSet();
UnknownField field = new UnknownField();
field.AddFixed32(123);
unknownFields.AddOrReplaceField(1, field);
UnknownFieldSet otherUnknownFields = new UnknownFieldSet();
Assert.IsFalse(otherUnknownFields.HasField(1));
UnknownFieldSet.MergeFrom(otherUnknownFields, unknownFields);
Assert.IsTrue(otherUnknownFields.HasField(1));
}
[Test]
public void TestMergeCodedInput()
{
var message = SampleMessages.CreateFullTestAllTypes();
var emptyMessage = new TestEmptyMessage();
emptyMessage.MergeFrom(message.ToByteArray());
Assert.AreEqual(message.CalculateSize(), emptyMessage.CalculateSize());
Assert.AreEqual(message.ToByteArray(), emptyMessage.ToByteArray());
var newMessage = new TestAllTypes();
newMessage.MergeFrom(emptyMessage.ToByteArray());
Assert.AreEqual(message, newMessage);
Assert.AreEqual(message.CalculateSize(), newMessage.CalculateSize());
}
[Test]
public void TestMergeMessage()
{
var message = SampleMessages.CreateFullTestAllTypes();
var emptyMessage = new TestEmptyMessage();
var otherEmptyMessage = new TestEmptyMessage();
emptyMessage.MergeFrom(message.ToByteArray());
otherEmptyMessage.MergeFrom(emptyMessage);
Assert.AreEqual(message.CalculateSize(), otherEmptyMessage.CalculateSize());
Assert.AreEqual(message.ToByteArray(), otherEmptyMessage.ToByteArray());
}
[Test]
public void TestEquals()
{
var message = SampleMessages.CreateFullTestAllTypes();
var emptyMessage = new TestEmptyMessage();
var otherEmptyMessage = new TestEmptyMessage();
Assert.AreEqual(emptyMessage, otherEmptyMessage);
emptyMessage.MergeFrom(message.ToByteArray());
Assert.AreNotEqual(emptyMessage.CalculateSize(),
otherEmptyMessage.CalculateSize());
Assert.AreNotEqual(emptyMessage, otherEmptyMessage);
}
[Test]
public void TestHashCode()
{
var message = SampleMessages.CreateFullTestAllTypes();
var emptyMessage = new TestEmptyMessage();
int hashCode = emptyMessage.GetHashCode();
emptyMessage.MergeFrom(message.ToByteArray());
Assert.AreNotEqual(hashCode, emptyMessage.GetHashCode());
}
[Test]
public void TestClone()
{
var emptyMessage = new TestEmptyMessage();
var otherEmptyMessage = new TestEmptyMessage();
otherEmptyMessage = emptyMessage.Clone();
Assert.AreEqual(emptyMessage.CalculateSize(), otherEmptyMessage.CalculateSize());
Assert.AreEqual(emptyMessage.ToByteArray(), otherEmptyMessage.ToByteArray());
var message = SampleMessages.CreateFullTestAllTypes();
emptyMessage.MergeFrom(message.ToByteArray());
otherEmptyMessage = emptyMessage.Clone();
Assert.AreEqual(message.CalculateSize(), otherEmptyMessage.CalculateSize());
Assert.AreEqual(message.ToByteArray(), otherEmptyMessage.ToByteArray());
}
}
}
......@@ -417,5 +417,16 @@ namespace Google.Protobuf.WellKnownTypes
TestWellKnownTypes.Descriptor.Fields[TestWellKnownTypes.StringFieldFieldNumber].Accessor.Clear(message);
Assert.IsNull(message.StringField);
}
[Test]
public void NaNComparisons()
{
var message1 = new TestWellKnownTypes { DoubleField = SampleNaNs.Regular };
var message2 = new TestWellKnownTypes { DoubleField = SampleNaNs.PayloadFlipped };
var message3 = new TestWellKnownTypes { DoubleField = SampleNaNs.Regular };
EqualityTester.AssertInequality(message1, message2);
EqualityTester.AssertEquality(message1, message3);
}
}
}
......@@ -424,7 +424,10 @@ namespace Google.Protobuf
}
}
private void SkipGroup(uint startGroupTag)
/// <summary>
/// Skip a group.
/// </summary>
internal void SkipGroup(uint startGroupTag)
{
// Note: Currently we expect this to be the way that groups are read. We could put the recursion
// depth changes into the ReadTag method instead, potentially...
......@@ -1270,7 +1273,6 @@ namespace Google.Protobuf
}
}
}
#endregion
}
}
\ No newline at end of file
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2017 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Google.Protobuf.Collections
{
/// <summary>
/// Utility to compare if two Lists are the same, and the hash code
/// of a List.
/// </summary>
public static class Lists
{
/// <summary>
/// Checks if two lists are equal.
/// </summary>
public static bool Equals<T>(List<T> left, List<T> right)
{
if (left == right)
{
return true;
}
if (left == null || right == null)
{
return false;
}
if (left.Count != right.Count)
{
return false;
}
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < left.Count; i++)
{
if (!comparer.Equals(left[i], right[i]))
{
return false;
}
}
return true;
}
/// <summary>
/// Gets the list's hash code.
/// </summary>
public static int GetHashCode<T>(List<T> list)
{
if (list == null)
{
return 0;
}
int hash = 31;
foreach (T element in list)
{
hash = hash * 29 + element.GetHashCode();
}
return hash;
}
}
}
\ No newline at end of file
......@@ -71,9 +71,12 @@ namespace Google.Protobuf.Collections
, IReadOnlyDictionary<TKey, TValue>
#endif
{
private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();
private static readonly EqualityComparer<TKey> KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TKey>();
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(KeyEqualityComparer);
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
/// <summary>
......@@ -131,11 +134,8 @@ namespace Google.Protobuf.Collections
return map.ContainsKey(key);
}
private bool ContainsValue(TValue value)
{
var comparer = EqualityComparer<TValue>.Default;
return list.Any(pair => comparer.Equals(pair.Value, value));
}
private bool ContainsValue(TValue value) =>
list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value));
/// <summary>
/// Removes the entry identified by the given key from the map.
......@@ -293,8 +293,7 @@ namespace Google.Protobuf.Collections
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
TValue value;
return TryGetValue(item.Key, out value)
&& EqualityComparer<TValue>.Default.Equals(item.Value, value);
return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value);
}
/// <summary>
......@@ -363,11 +362,12 @@ namespace Google.Protobuf.Collections
/// </returns>
public override int GetHashCode()
{
var valueComparer = EqualityComparer<TValue>.Default;
var keyComparer = KeyEqualityComparer;
var valueComparer = ValueEqualityComparer;
int hash = 0;
foreach (var pair in list)
{
hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value);
hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value);
}
return hash;
}
......@@ -394,7 +394,7 @@ namespace Google.Protobuf.Collections
{
return false;
}
var valueComparer = EqualityComparer<TValue>.Default;
var valueComparer = ValueEqualityComparer;
foreach (var pair in this)
{
TValue value;
......
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2017 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
namespace Google.Protobuf.Collections
{
/// <summary>
/// Provides a central place to implement equality comparisons, primarily for bitwise float/double equality.
/// </summary>
public static class ProtobufEqualityComparers
{
/// <summary>
/// Returns an equality comparer for <typeparamref name="T"/> suitable for Protobuf equality comparisons.
/// This is usually just the default equality comparer for the type, but floating point numbers are compared
/// bitwise.
/// </summary>
/// <typeparam name="T">The type of equality comparer to return.</typeparam>
/// <returns>The equality comparer.</returns>
public static EqualityComparer<T> GetEqualityComparer<T>()
{
return typeof(T) == typeof(double) ? (EqualityComparer<T>) (object) BitwiseDoubleEqualityComparer
: typeof(T) == typeof(float) ? (EqualityComparer<T>) (object) BitwiseSingleEqualityComparer
: typeof(T) == typeof(double?) ? (EqualityComparer<T>) (object) BitwiseNullableDoubleEqualityComparer
: typeof(T) == typeof(float?) ? (EqualityComparer<T>) (object) BitwiseNullableSingleEqualityComparer
: EqualityComparer<T>.Default;
}
/// <summary>
/// Returns an equality comparer suitable for comparing 64-bit floating point values, by bitwise comparison.
/// (NaN values are considered equal, but only when they have the same representation.)
/// </summary>
public static EqualityComparer<double> BitwiseDoubleEqualityComparer { get; } = new BitwiseDoubleEqualityComparerImpl();
/// <summary>
/// Returns an equality comparer suitable for comparing 32-bit floating point values, by bitwise comparison.
/// (NaN values are considered equal, but only when they have the same representation.)
/// </summary>
public static EqualityComparer<float> BitwiseSingleEqualityComparer { get; } = new BitwiseSingleEqualityComparerImpl();
/// <summary>
/// Returns an equality comparer suitable for comparing nullable 64-bit floating point values, by bitwise comparison.
/// (NaN values are considered equal, but only when they have the same representation.)
/// </summary>
public static EqualityComparer<double?> BitwiseNullableDoubleEqualityComparer { get; } = new BitwiseNullableDoubleEqualityComparerImpl();
/// <summary>
/// Returns an equality comparer suitable for comparing nullable 32-bit floating point values, by bitwise comparison.
/// (NaN values are considered equal, but only when they have the same representation.)
/// </summary>
public static EqualityComparer<float?> BitwiseNullableSingleEqualityComparer { get; } = new BitwiseNullableSingleEqualityComparerImpl();
private class BitwiseDoubleEqualityComparerImpl : EqualityComparer<double>
{
public override bool Equals(double x, double y) =>
BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y);
public override int GetHashCode(double obj) =>
BitConverter.DoubleToInt64Bits(obj).GetHashCode();
}
private class BitwiseSingleEqualityComparerImpl : EqualityComparer<float>
{
// Just promote values to double and use BitConverter.DoubleToInt64Bits,
// as there's no BitConverter.SingleToInt32Bits, unfortunately.
public override bool Equals(float x, float y) =>
BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y);
public override int GetHashCode(float obj) =>
BitConverter.DoubleToInt64Bits(obj).GetHashCode();
}
private class BitwiseNullableDoubleEqualityComparerImpl : EqualityComparer<double?>
{
public override bool Equals(double? x, double? y) =>
x == null && y == null ? true
: x == null || y == null ? false
: BitwiseDoubleEqualityComparer.Equals(x.Value, y.Value);
// The hash code for null is just a constant which is at least *unlikely* to be used
// elsewhere. (Compared with 0, say.)
public override int GetHashCode(double? obj) =>
obj == null ? 293864 : BitwiseDoubleEqualityComparer.GetHashCode(obj.Value);
}
private class BitwiseNullableSingleEqualityComparerImpl : EqualityComparer<float?>
{
public override bool Equals(float? x, float? y) =>
x == null && y == null ? true
: x == null || y == null ? false
: BitwiseSingleEqualityComparer.Equals(x.Value, y.Value);
// The hash code for null is just a constant which is at least *unlikely* to be used
// elsewhere. (Compared with 0, say.)
public override int GetHashCode(float? obj) =>
obj == null ? 293864 : BitwiseSingleEqualityComparer.GetHashCode(obj.Value);
}
}
}
......@@ -51,6 +51,7 @@ namespace Google.Protobuf.Collections
, IReadOnlyList<T>
#endif
{
private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
private static readonly T[] EmptyArray = new T[0];
private const int MinArraySize = 8;
......@@ -434,7 +435,7 @@ namespace Google.Protobuf.Collections
{
return false;
}
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
EqualityComparer<T> comparer = EqualityComparer;
for (int i = 0; i < count; i++)
{
if (!comparer.Equals(array[i], other.array[i]))
......@@ -454,7 +455,7 @@ namespace Google.Protobuf.Collections
public int IndexOf(T item)
{
ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
EqualityComparer<T> comparer = EqualityComparer;
for (int i = 0; i < count; i++)
{
if (comparer.Equals(array[i], item))
......
......@@ -30,6 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using Google.Protobuf.Collections;
using Google.Protobuf.Compatibility;
using Google.Protobuf.WellKnownTypes;
using System;
......@@ -346,6 +347,7 @@ namespace Google.Protobuf
/// </remarks>
public sealed class FieldCodec<T>
{
private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
private static readonly T DefaultDefault;
// Only non-nullable value types support packing. This is the simplest way of detecting that.
private static readonly bool TypeSupportsPacking = default(T) != null;
......@@ -469,6 +471,6 @@ namespace Google.Protobuf
/// </summary>
public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(value, DefaultValue);
private bool IsDefault(T value) => EqualityComparer.Equals(value, DefaultValue);
}
}
This diff is collapsed.
This diff is collapsed.
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -119,6 +121,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// </summary>
public sealed partial class Any : pb::IMessage<Any> {
private static readonly pb::MessageParser<Any> _parser = new pb::MessageParser<Any>(() => new Any());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<Any> Parser { get { return _parser; } }
......@@ -143,6 +146,7 @@ namespace Google.Protobuf.WellKnownTypes {
public Any(Any other) : this() {
typeUrl_ = other.typeUrl_;
value_ = other.value_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -218,7 +222,7 @@ namespace Google.Protobuf.WellKnownTypes {
}
if (TypeUrl != other.TypeUrl) return false;
if (Value != other.Value) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -226,6 +230,9 @@ namespace Google.Protobuf.WellKnownTypes {
int hash = 1;
if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
if (Value.Length != 0) hash ^= Value.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -244,6 +251,9 @@ namespace Google.Protobuf.WellKnownTypes {
output.WriteRawTag(18);
output.WriteBytes(Value);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -255,6 +265,9 @@ namespace Google.Protobuf.WellKnownTypes {
if (Value.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -269,6 +282,7 @@ namespace Google.Protobuf.WellKnownTypes {
if (other.Value.Length != 0) {
Value = other.Value;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -277,7 +291,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
TypeUrl = input.ReadString();
......
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/duration.proto
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/duration.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
......@@ -100,6 +102,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// </summary>
public sealed partial class Duration : pb::IMessage<Duration> {
private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<Duration> Parser { get { return _parser; } }
......@@ -124,6 +127,7 @@ namespace Google.Protobuf.WellKnownTypes {
public Duration(Duration other) : this() {
seconds_ = other.seconds_;
nanos_ = other.nanos_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -181,7 +185,7 @@ namespace Google.Protobuf.WellKnownTypes {
}
if (Seconds != other.Seconds) return false;
if (Nanos != other.Nanos) return false;
return true;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -189,6 +193,9 @@ namespace Google.Protobuf.WellKnownTypes {
int hash = 1;
if (Seconds != 0L) hash ^= Seconds.GetHashCode();
if (Nanos != 0) hash ^= Nanos.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
......@@ -207,6 +214,9 @@ namespace Google.Protobuf.WellKnownTypes {
output.WriteRawTag(16);
output.WriteInt32(Nanos);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -218,6 +228,9 @@ namespace Google.Protobuf.WellKnownTypes {
if (Nanos != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
......@@ -232,6 +245,7 @@ namespace Google.Protobuf.WellKnownTypes {
if (other.Nanos != 0) {
Nanos = other.Nanos;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
......@@ -240,7 +254,7 @@ namespace Google.Protobuf.WellKnownTypes {
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
Seconds = input.ReadInt64();
......
......@@ -115,7 +115,9 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
* {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
* seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
* are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
* is required, though only UTC (as indicated by "Z") is presently supported.
* is required. A proto3 JSON serializer should always use UTC (as indicated by
* "Z") when printing the Timestamp type and a proto3 JSON parser should be
* able to accept both UTC and other timezones (as indicated by an offset).
*
* For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
* 01:30 UTC on January 15, 2017.
......
......@@ -16,10 +16,6 @@ install it as you would any other gem:
$ gem install [--prerelease] google-protobuf
The `--pre` flag is necessary if we have not yet made a non-alpha/beta release
of the Ruby extension; it allows `gem` to consider these "pre-release"
alpha/beta versions.
Once the gem is installed, you may or may not need `protoc`. If you write your
message type descriptions directly in the Ruby DSL, you do not need it.
However, if you wish to generate the Ruby DSL from a `.proto` file, you will
......
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: google/protobuf/any.proto
#ifndef PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
#define PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
#ifndef PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
#define PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
#include <string>
......@@ -329,4 +329,4 @@ inline void Any::set_allocated_value(::std::string* value) {
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_google_2fprotobuf_2fany_2eproto__INCLUDED
#endif // PROTOBUF_google_2fprotobuf_2fany_2eproto_INCLUDED
This diff is collapsed.
......@@ -104,8 +104,10 @@ void ReflectionClassGenerator::Generate(io::Printer* printer) {
void ReflectionClassGenerator::WriteIntroduction(io::Printer* printer) {
printer->Print(
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"// source: $file_name$\n"
"// <auto-generated>\n"
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"// source: $file_name$\n"
"// </auto-generated>\n"
"#pragma warning disable 1591, 0612, 3021\n"
"#region Designer generated code\n"
"\n"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment