diff --git a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs index b9ff51521f..d64ef625d4 100644 --- a/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs +++ b/csharp/src/Google.Protobuf.Test/CodedOutputStreamTest.cs @@ -211,35 +211,35 @@ namespace Google.Protobuf [Test] public void EncodeZigZag32() { - Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag32(0)); - Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag32(-1)); - Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag32(1)); - Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag32(-2)); - Assert.AreEqual(0x7FFFFFFEu, CodedOutputStream.EncodeZigZag32(0x3FFFFFFF)); - Assert.AreEqual(0x7FFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0xC0000000))); - Assert.AreEqual(0xFFFFFFFEu, CodedOutputStream.EncodeZigZag32(0x7FFFFFFF)); - Assert.AreEqual(0xFFFFFFFFu, CodedOutputStream.EncodeZigZag32(unchecked((int) 0x80000000))); + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag32(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag32(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag32(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag32(-2)); + Assert.AreEqual(0x7FFFFFFEu, WritingPrimitives.EncodeZigZag32(0x3FFFFFFF)); + Assert.AreEqual(0x7FFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0xC0000000))); + Assert.AreEqual(0xFFFFFFFEu, WritingPrimitives.EncodeZigZag32(0x7FFFFFFF)); + Assert.AreEqual(0xFFFFFFFFu, WritingPrimitives.EncodeZigZag32(unchecked((int) 0x80000000))); } [Test] public void EncodeZigZag64() { - Assert.AreEqual(0u, CodedOutputStream.EncodeZigZag64(0)); - Assert.AreEqual(1u, CodedOutputStream.EncodeZigZag64(-1)); - Assert.AreEqual(2u, CodedOutputStream.EncodeZigZag64(1)); - Assert.AreEqual(3u, CodedOutputStream.EncodeZigZag64(-2)); + Assert.AreEqual(0u, WritingPrimitives.EncodeZigZag64(0)); + Assert.AreEqual(1u, WritingPrimitives.EncodeZigZag64(-1)); + Assert.AreEqual(2u, WritingPrimitives.EncodeZigZag64(1)); + Assert.AreEqual(3u, WritingPrimitives.EncodeZigZag64(-2)); Assert.AreEqual(0x000000007FFFFFFEuL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000003FFFFFFFUL))); Assert.AreEqual(0x000000007FFFFFFFuL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFFC0000000UL))); Assert.AreEqual(0x00000000FFFFFFFEuL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x000000007FFFFFFFUL))); Assert.AreEqual(0x00000000FFFFFFFFuL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0xFFFFFFFF80000000UL))); Assert.AreEqual(0xFFFFFFFFFFFFFFFEL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x7FFFFFFFFFFFFFFFUL))); Assert.AreEqual(0xFFFFFFFFFFFFFFFFL, - CodedOutputStream.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); + WritingPrimitives.EncodeZigZag64(unchecked((long) 0x8000000000000000UL))); } [Test] @@ -247,26 +247,26 @@ namespace Google.Protobuf { // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) // were chosen semi-randomly via keyboard bashing. - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(CodedOutputStream.EncodeZigZag32(-3612))); + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag32(WritingPrimitives.EncodeZigZag32(-3612))); } [Test] public void RoundTripZigZag64() { - Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(0))); - Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(1))); - Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-1))); - Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(14927))); - Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-3612))); + Assert.AreEqual(0, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(0))); + Assert.AreEqual(1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(1))); + Assert.AreEqual(-1, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-1))); + Assert.AreEqual(14927, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(14927))); + Assert.AreEqual(-3612, ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-3612))); Assert.AreEqual(856912304801416L, - ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(856912304801416L))); + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(856912304801416L))); Assert.AreEqual(-75123905439571256L, - ParsingPrimitives.DecodeZigZag64(CodedOutputStream.EncodeZigZag64(-75123905439571256L))); + ParsingPrimitives.DecodeZigZag64(WritingPrimitives.EncodeZigZag64(-75123905439571256L))); } [Test] diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs index ccf7520525..002fae3d0e 100644 --- a/csharp/src/Google.Protobuf/CodedOutputStream.cs +++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs @@ -263,9 +263,19 @@ namespace Google.Protobuf /// The value to write public void WriteMessage(IMessage value) { - // TOOD: implement.... - WriteLength(value.CalculateSize()); - value.WriteTo(this); + // TODO(jtattermusch): if the message doesn't implement IBufferMessage (and thus does not provide the InternalWriteTo method), + // what we're doing here works fine, but could be more efficient. + // For now, this inefficiency is fine, considering this is only a backward-compatibility scenario (and regenerating the code fixes it). + var span = new Span(buffer); + WriteContext.Initialize(ref span, ref state, out WriteContext ctx); + try + { + WritingPrimitivesMessages.WriteMessage(ref ctx, value); + } + finally + { + ctx.CopyStateTo(this); + } } /// @@ -274,8 +284,16 @@ namespace Google.Protobuf /// The value to write public void WriteGroup(IMessage value) { - // TODO: implement... - value.WriteTo(this); + var span = new Span(buffer); + WriteContext.Initialize(ref span, ref state, out WriteContext ctx); + try + { + WritingPrimitivesMessages.WriteGroup(ref ctx, value); + } + finally + { + ctx.CopyStateTo(this); + } } /// @@ -448,123 +466,49 @@ namespace Google.Protobuf } #endregion - //#region Underlying writing primitives - ///// - ///// Writes a 32 bit value as a varint. The fast route is taken when - ///// there's enough buffer space left to whizz through without checking - ///// for each byte; otherwise, we resort to calling WriteRawByte each time. - ///// - //internal void WriteRawVarint32(uint value) - //{ - // // Optimize for the common case of a single byte value - // if (value < 128 && position < limit) - // { - // buffer[position++] = (byte)value; - // return; - // } - - // while (value > 127 && position < limit) - // { - // buffer[position++] = (byte) ((value & 0x7F) | 0x80); - // value >>= 7; - // } - // while (value > 127) - // { - // WriteRawByte((byte) ((value & 0x7F) | 0x80)); - // value >>= 7; - // } - // if (position < limit) - // { - // buffer[position++] = (byte) value; - // } - // else - // { - // WriteRawByte((byte) value); - // } - //} - - //internal void WriteRawVarint64(ulong value) - //{ - // while (value > 127 && position < limit) - // { - // buffer[position++] = (byte) ((value & 0x7F) | 0x80); - // value >>= 7; - // } - // while (value > 127) - // { - // WriteRawByte((byte) ((value & 0x7F) | 0x80)); - // value >>= 7; - // } - // if (position < limit) - // { - // buffer[position++] = (byte) value; - // } - // else - // { - // WriteRawByte((byte) value); - // } - //} + #region Underlying writing primitives + + /// + /// Writes a 32 bit value as a varint. The fast route is taken when + /// there's enough buffer space left to whizz through without checking + /// for each byte; otherwise, we resort to calling WriteRawByte each time. + /// + internal void WriteRawVarint32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawVarint32(ref span, ref state, value); + } - //internal void WriteRawLittleEndian32(uint value) - //{ - // if (position + 4 > limit) - // { - // WriteRawByte((byte) value); - // WriteRawByte((byte) (value >> 8)); - // WriteRawByte((byte) (value >> 16)); - // WriteRawByte((byte) (value >> 24)); - // } - // else - // { - // buffer[position++] = ((byte) value); - // buffer[position++] = ((byte) (value >> 8)); - // buffer[position++] = ((byte) (value >> 16)); - // buffer[position++] = ((byte) (value >> 24)); - // } - //} + internal void WriteRawVarint64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawVarint64(ref span, ref state, value); + } - //internal void WriteRawLittleEndian64(ulong value) - //{ - // if (position + 8 > limit) - // { - // WriteRawByte((byte) value); - // WriteRawByte((byte) (value >> 8)); - // WriteRawByte((byte) (value >> 16)); - // WriteRawByte((byte) (value >> 24)); - // WriteRawByte((byte) (value >> 32)); - // WriteRawByte((byte) (value >> 40)); - // WriteRawByte((byte) (value >> 48)); - // WriteRawByte((byte) (value >> 56)); - // } - // else - // { - // buffer[position++] = ((byte) value); - // buffer[position++] = ((byte) (value >> 8)); - // buffer[position++] = ((byte) (value >> 16)); - // buffer[position++] = ((byte) (value >> 24)); - // buffer[position++] = ((byte) (value >> 32)); - // buffer[position++] = ((byte) (value >> 40)); - // buffer[position++] = ((byte) (value >> 48)); - // buffer[position++] = ((byte) (value >> 56)); - // } - //} + internal void WriteRawLittleEndian32(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawLittleEndian32(ref span, ref state, value); + } - //internal void WriteRawByte(byte value) - //{ - // if (position == limit) - // { - // RefreshBuffer(); - // } + internal void WriteRawLittleEndian64(ulong value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawLittleEndian64(ref span, ref state, value); + } - // buffer[position++] = value; - //} + internal void WriteRawByte(byte value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawByte(ref span, ref state, value); + } - //internal void WriteRawByte(uint value) - //{ - // WriteRawByte((byte) value); - //} + internal void WriteRawByte(uint value) + { + var span = new Span(buffer); + WritingPrimitives.WriteRawByte(ref span, ref state, value); + } - // TODO: get rid of this internal method /// /// Writes out an array of bytes. /// @@ -573,7 +517,6 @@ namespace Google.Protobuf WriteRawBytes(value, 0, value.Length); } - // TODO: get rid of this internal method /// /// Writes out part of an array of bytes. /// @@ -583,7 +526,7 @@ namespace Google.Protobuf WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length); } - //#endregion + #endregion ///// ///// Encode a 32-bit value with ZigZag encoding.