diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
index aa7932470b..2dec861483 100644
--- a/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.ComputeSize.cs
@@ -208,7 +208,7 @@ namespace Google.Protobuf
///
public static int ComputeSInt32Size(int value)
{
- return ComputeRawVarint32Size(EncodeZigZag32(value));
+ return ComputeRawVarint32Size(WritingPrimitives.EncodeZigZag32(value));
}
///
@@ -217,7 +217,7 @@ namespace Google.Protobuf
///
public static int ComputeSInt64Size(long value)
{
- return ComputeRawVarint64Size(EncodeZigZag64(value));
+ return ComputeRawVarint64Size(WritingPrimitives.EncodeZigZag64(value));
}
///
diff --git a/csharp/src/Google.Protobuf/CodedOutputStream.cs b/csharp/src/Google.Protobuf/CodedOutputStream.cs
index b348a523c1..ccf7520525 100644
--- a/csharp/src/Google.Protobuf/CodedOutputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedOutputStream.cs
@@ -67,8 +67,8 @@ namespace Google.Protobuf
private readonly bool leaveOpen;
private readonly byte[] buffer;
- private readonly int limit;
- private int position;
+ private WriterInternalState state;
+
private readonly Stream output;
#region Construction
@@ -90,8 +90,9 @@ namespace Google.Protobuf
{
this.output = null;
this.buffer = ProtoPreconditions.CheckNotNull(buffer, nameof(buffer));
- this.position = offset;
- this.limit = offset + length;
+ this.state.position = offset;
+ this.state.limit = offset + length;
+ WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper);
leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
}
@@ -99,8 +100,9 @@ namespace Google.Protobuf
{
this.output = ProtoPreconditions.CheckNotNull(output, nameof(output));
this.buffer = buffer;
- this.position = 0;
- this.limit = buffer.Length;
+ this.state.position = 0;
+ this.state.limit = buffer.Length;
+ WriteBufferHelper.Initialize(this, out this.state.writeBufferHelper);
this.leaveOpen = leaveOpen;
}
@@ -155,9 +157,9 @@ namespace Google.Protobuf
{
if (output != null)
{
- return output.Position + position;
+ return output.Position + state.position;
}
- return position;
+ return state.position;
}
}
@@ -169,7 +171,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteDouble(double value)
{
- WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
+ var span = new Span(buffer);
+ WritingPrimitives.WriteDouble(ref span, ref state, value);
}
///
@@ -178,23 +181,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteFloat(float value)
{
- byte[] rawBytes = BitConverter.GetBytes(value);
- if (!BitConverter.IsLittleEndian)
- {
- ByteArray.Reverse(rawBytes);
- }
-
- if (limit - position >= 4)
- {
- buffer[position++] = rawBytes[0];
- buffer[position++] = rawBytes[1];
- buffer[position++] = rawBytes[2];
- buffer[position++] = rawBytes[3];
- }
- else
- {
- WriteRawBytes(rawBytes, 0, 4);
- }
+ var span = new Span(buffer);
+ WritingPrimitives.WriteFloat(ref span, ref state, value);
}
///
@@ -203,7 +191,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteUInt64(ulong value)
{
- WriteRawVarint64(value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteUInt64(ref span, ref state, value);
}
///
@@ -212,7 +201,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteInt64(long value)
{
- WriteRawVarint64((ulong) value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteInt64(ref span, ref state, value);
}
///
@@ -221,15 +211,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteInt32(int value)
{
- if (value >= 0)
- {
- WriteRawVarint32((uint) value);
- }
- else
- {
- // Must sign-extend.
- WriteRawVarint64((ulong) value);
- }
+ var span = new Span(buffer);
+ WritingPrimitives.WriteInt32(ref span, ref state, value);
}
///
@@ -238,7 +221,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteFixed64(ulong value)
{
- WriteRawLittleEndian64(value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteFixed64(ref span, ref state, value);
}
///
@@ -247,7 +231,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteFixed32(uint value)
{
- WriteRawLittleEndian32(value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteFixed32(ref span, ref state, value);
}
///
@@ -256,7 +241,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteBool(bool value)
{
- WriteRawByte(value ? (byte) 1 : (byte) 0);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteBool(ref span, ref state, value);
}
///
@@ -266,30 +252,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteString(string value)
{
- // Optimise the case where we have enough space to write
- // the string directly to the buffer, which should be common.
- int length = Utf8Encoding.GetByteCount(value);
- WriteLength(length);
- if (limit - position >= length)
- {
- if (length == value.Length) // Must be all ASCII...
- {
- for (int i = 0; i < length; i++)
- {
- buffer[position + i] = (byte)value[i];
- }
- }
- else
- {
- Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);
- }
- position += length;
- }
- else
- {
- byte[] bytes = Utf8Encoding.GetBytes(value);
- WriteRawBytes(bytes);
- }
+ var span = new Span(buffer);
+ WritingPrimitives.WriteString(ref span, ref state, value);
}
///
@@ -299,6 +263,7 @@ namespace Google.Protobuf
/// The value to write
public void WriteMessage(IMessage value)
{
+ // TOOD: implement....
WriteLength(value.CalculateSize());
value.WriteTo(this);
}
@@ -309,6 +274,7 @@ namespace Google.Protobuf
/// The value to write
public void WriteGroup(IMessage value)
{
+ // TODO: implement...
value.WriteTo(this);
}
@@ -319,8 +285,9 @@ namespace Google.Protobuf
/// The value to write
public void WriteBytes(ByteString value)
{
- WriteLength(value.Length);
- value.WriteRawBytesTo(this);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteLength(ref span, ref state, value.Length);
+ WritingPrimitives.WriteBytes(ref span, ref state, value);
}
///
@@ -329,7 +296,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteUInt32(uint value)
{
- WriteRawVarint32(value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteUInt32(ref span, ref state, value);
}
///
@@ -338,7 +306,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteEnum(int value)
{
- WriteInt32(value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteEnum(ref span, ref state, value);
}
///
@@ -347,7 +316,8 @@ namespace Google.Protobuf
/// The value to write.
public void WriteSFixed32(int value)
{
- WriteRawLittleEndian32((uint) value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteSFixed32(ref span, ref state, value);
}
///
@@ -356,7 +326,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteSFixed64(long value)
{
- WriteRawLittleEndian64((ulong) value);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteSFixed64(ref span, ref state, value);
}
///
@@ -365,7 +336,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteSInt32(int value)
{
- WriteRawVarint32(EncodeZigZag32(value));
+ var span = new Span(buffer);
+ WritingPrimitives.WriteSInt32(ref span, ref state, value);
}
///
@@ -374,7 +346,8 @@ namespace Google.Protobuf
/// The value to write
public void WriteSInt64(long value)
{
- WriteRawVarint64(EncodeZigZag64(value));
+ var span = new Span(buffer);
+ WritingPrimitives.WriteSInt64(ref span, ref state, value);
}
///
@@ -386,7 +359,8 @@ namespace Google.Protobuf
/// Length value, in bytes.
public void WriteLength(int length)
{
- WriteRawVarint32((uint) length);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteLength(ref span, ref state, length);
}
#endregion
@@ -399,7 +373,8 @@ namespace Google.Protobuf
/// The wire format type of the tag to write
public void WriteTag(int fieldNumber, WireFormat.WireType type)
{
- WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
+ var span = new Span(buffer);
+ WritingPrimitives.WriteTag(ref span, ref state, fieldNumber, type);
}
///
@@ -408,7 +383,8 @@ namespace Google.Protobuf
/// The encoded tag
public void WriteTag(uint tag)
{
- WriteRawVarint32(tag);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteTag(ref span, ref state, tag);
}
///
@@ -417,7 +393,8 @@ namespace Google.Protobuf
/// The encoded tag
public void WriteRawTag(byte b1)
{
- WriteRawByte(b1);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawTag(ref span, ref state, b1);
}
///
@@ -427,8 +404,8 @@ namespace Google.Protobuf
/// The second byte of the encoded tag
public void WriteRawTag(byte b1, byte b2)
{
- WriteRawByte(b1);
- WriteRawByte(b2);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2);
}
///
@@ -439,9 +416,8 @@ namespace Google.Protobuf
/// The third byte of the encoded tag
public void WriteRawTag(byte b1, byte b2, byte b3)
{
- WriteRawByte(b1);
- WriteRawByte(b2);
- WriteRawByte(b3);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3);
}
///
@@ -453,10 +429,8 @@ namespace Google.Protobuf
/// The fourth byte of the encoded tag
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
{
- WriteRawByte(b1);
- WriteRawByte(b2);
- WriteRawByte(b3);
- WriteRawByte(b4);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4);
}
///
@@ -469,130 +443,128 @@ namespace Google.Protobuf
/// The fifth byte of the encoded tag
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
{
- WriteRawByte(b1);
- WriteRawByte(b2);
- WriteRawByte(b3);
- WriteRawByte(b4);
- WriteRawByte(b5);
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawTag(ref span, ref state, b1, b2, b3, b4, b5);
}
#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);
- }
- }
-
- 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 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 WriteRawByte(byte value)
- {
- if (position == limit)
- {
- RefreshBuffer();
- }
-
- buffer[position++] = value;
- }
-
- internal void WriteRawByte(uint value)
- {
- 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)
+ //{
+ // // 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);
+ // }
+ //}
+
+ //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 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 WriteRawByte(byte value)
+ //{
+ // if (position == limit)
+ // {
+ // RefreshBuffer();
+ // }
+
+ // buffer[position++] = value;
+ //}
+
+ //internal void WriteRawByte(uint value)
+ //{
+ // WriteRawByte((byte) value);
+ //}
+
+ // TODO: get rid of this internal method
///
/// Writes out an array of bytes.
///
@@ -601,89 +573,60 @@ namespace Google.Protobuf
WriteRawBytes(value, 0, value.Length);
}
+ // TODO: get rid of this internal method
///
/// Writes out part of an array of bytes.
///
internal void WriteRawBytes(byte[] value, int offset, int length)
{
- if (limit - position >= length)
- {
- ByteArray.Copy(value, offset, buffer, position, length);
- // We have room in the current buffer.
- position += length;
- }
- else
- {
- // Write extends past current buffer. Fill the rest of this buffer and
- // flush.
- int bytesWritten = limit - position;
- ByteArray.Copy(value, offset, buffer, position, bytesWritten);
- offset += bytesWritten;
- length -= bytesWritten;
- position = limit;
- RefreshBuffer();
-
- // Now deal with the rest.
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- if (length <= limit)
- {
- // Fits in new buffer.
- ByteArray.Copy(value, offset, buffer, 0, length);
- position = length;
- }
- else
- {
- // Write is very big. Let's do it all at once.
- output.Write(value, offset, length);
- }
- }
- }
-
- #endregion
-
- ///
- /// Encode a 32-bit value with ZigZag encoding.
- ///
- ///
- /// ZigZag encodes signed integers into values that can be efficiently
- /// encoded with varint. (Otherwise, negative values must be
- /// sign-extended to 64 bits to be varint encoded, thus always taking
- /// 10 bytes on the wire.)
- ///
- internal static uint EncodeZigZag32(int n)
- {
- // Note: the right-shift must be arithmetic
- return (uint) ((n << 1) ^ (n >> 31));
- }
-
- ///
- /// Encode a 64-bit value with ZigZag encoding.
- ///
- ///
- /// ZigZag encodes signed integers into values that can be efficiently
- /// encoded with varint. (Otherwise, negative values must be
- /// sign-extended to 64 bits to be varint encoded, thus always taking
- /// 10 bytes on the wire.)
- ///
- internal static ulong EncodeZigZag64(long n)
- {
- return (ulong) ((n << 1) ^ (n >> 63));
- }
-
- private void RefreshBuffer()
- {
- if (output == null)
- {
- // We're writing to a single buffer.
- throw new OutOfSpaceException();
- }
-
- // Since we have an output stream, this is our buffer
- // and buffer offset == 0
- output.Write(buffer, 0, position);
- position = 0;
- }
+ var span = new Span(buffer);
+ WritingPrimitives.WriteRawBytes(ref span, ref state, value, offset, length);
+ }
+
+ //#endregion
+
+ /////
+ ///// Encode a 32-bit value with ZigZag encoding.
+ /////
+ /////
+ ///// ZigZag encodes signed integers into values that can be efficiently
+ ///// encoded with varint. (Otherwise, negative values must be
+ ///// sign-extended to 64 bits to be varint encoded, thus always taking
+ ///// 10 bytes on the wire.)
+ /////
+ //internal static uint EncodeZigZag32(int n)
+ //{
+ // // Note: the right-shift must be arithmetic
+ // return (uint) ((n << 1) ^ (n >> 31));
+ //}
+
+ /////
+ ///// Encode a 64-bit value with ZigZag encoding.
+ /////
+ /////
+ ///// ZigZag encodes signed integers into values that can be efficiently
+ ///// encoded with varint. (Otherwise, negative values must be
+ ///// sign-extended to 64 bits to be varint encoded, thus always taking
+ ///// 10 bytes on the wire.)
+ /////
+ //internal static ulong EncodeZigZag64(long n)
+ //{
+ // return (ulong) ((n << 1) ^ (n >> 63));
+ //}
+
+ //private void RefreshBuffer()
+ //{
+ // if (output == null)
+ // {
+ // // We're writing to a single buffer.
+ // throw new OutOfSpaceException();
+ // }
+
+ // // Since we have an output stream, this is our buffer
+ // // and buffer offset == 0
+ // output.Write(buffer, 0, position);
+ // position = 0;
+ //}
///
/// Indicates that a CodedOutputStream wrapping a flat byte array
@@ -726,10 +669,13 @@ namespace Google.Protobuf
///
public void Flush()
{
- if (output != null)
+ var span = new Span(buffer);
+ state.writeBufferHelper.Flush(ref span, ref state);
+
+ /*if (output != null)
{
RefreshBuffer();
- }
+ }*/
}
///
@@ -756,7 +702,7 @@ namespace Google.Protobuf
{
if (output == null)
{
- return limit - position;
+ return state.limit - state.position;
}
else
{
@@ -770,5 +716,7 @@ namespace Google.Protobuf
internal byte[] InternalBuffer => buffer;
internal Stream InternalOutputStream => output;
+
+ internal ref WriterInternalState InternalState => ref state;
}
}
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
index 5c39aabafb..32f298a79b 100644
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
@@ -216,9 +216,9 @@ namespace Google.Protobuf.Collections
if (codec.PackedRepeatedField)
{
// Packed primitive type
- uint size = (uint)CalculatePackedDataSize(codec);
+ int size = CalculatePackedDataSize(codec);
output.WriteTag(tag);
- output.WriteRawVarint32(size);
+ output.WriteLength(size);
for (int i = 0; i < count; i++)
{
writer(output, array[i]);
diff --git a/csharp/src/Google.Protobuf/MessageExtensions.cs b/csharp/src/Google.Protobuf/MessageExtensions.cs
index 51e40915c8..e9a408c9e2 100644
--- a/csharp/src/Google.Protobuf/MessageExtensions.cs
+++ b/csharp/src/Google.Protobuf/MessageExtensions.cs
@@ -129,7 +129,7 @@ namespace Google.Protobuf
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(output, "output");
CodedOutputStream codedOutput = new CodedOutputStream(output);
- codedOutput.WriteRawVarint32((uint)message.CalculateSize());
+ codedOutput.WriteLength(message.CalculateSize());
message.WriteTo(codedOutput);
codedOutput.Flush();
}