コード例 #1
0
 private static void WriteRawLittleEndian32SlowPath(ref Span <byte> buffer, ref WriterInternalState state, uint value)
 {
     WriteRawByte(ref buffer, ref state, (byte)value);
     WriteRawByte(ref buffer, ref state, (byte)(value >> 8));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 16));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 24));
 }
コード例 #2
0
 public static void CheckNoSpaceLeft(ref WriterInternalState state)
 {
     if (GetSpaceLeft(ref state) != 0)
     {
         throw new InvalidOperationException("Did not write as much data as expected.");
     }
 }
コード例 #3
0
        /// <summary>
        /// Writes out part of an array of bytes.
        /// </summary>
        public static void WriteRawBytes(ref Span <byte> buffer, ref WriterInternalState state, ReadOnlySpan <byte> value)
        {
            if (buffer.Length - state.position >= value.Length)
            {
                // We have room in the current buffer.
                value.CopyTo(buffer.Slice(state.position, value.Length));
                state.position += value.Length;
            }
            else
            {
                // When writing to a CodedOutputStream backed by a Stream, we could avoid
                // copying the data twice (first copying to the current buffer and
                // and later writing from the current buffer to the underlying Stream)
                // in some circumstances by writing the data directly to the underlying Stream.
                // Current this is not being done to avoid specialcasing the code for
                // CodedOutputStream vs IBufferWriter<byte>.
                int bytesWritten = 0;
                while (buffer.Length - state.position < value.Length - bytesWritten)
                {
                    int length = buffer.Length - state.position;
                    value.Slice(bytesWritten, length).CopyTo(buffer.Slice(state.position, length));
                    bytesWritten   += length;
                    state.position += length;
                    WriteBufferHelper.RefreshBuffer(ref buffer, ref state);
                }

                // copy the remaining data
                int remainderLength = value.Length - bytesWritten;
                value.Slice(bytesWritten, remainderLength).CopyTo(buffer.Slice(state.position, remainderLength));
                state.position += remainderLength;
            }
        }
コード例 #4
0
 private static void WriteRawTagSlowPath(ref Span <byte> buffer, ref WriterInternalState state, byte b1, byte b2, byte b3, byte b4)
 {
     WriteRawByte(ref buffer, ref state, b1);
     WriteRawByte(ref buffer, ref state, b2);
     WriteRawByte(ref buffer, ref state, b3);
     WriteRawByte(ref buffer, ref state, b4);
 }
コード例 #5
0
        public static void WriteRawVarint64(ref Span <byte> buffer, ref WriterInternalState state, ulong value)
        {
            // Optimize for the common case of a single byte value
            if (value < 128 && state.position < buffer.Length)
            {
                buffer[state.position++] = (byte)value;
                return;
            }

            // Fast path when capacity is available
            while (state.position < buffer.Length)
            {
                if (value > 127)
                {
                    buffer[state.position++] = (byte)((value & 0x7F) | 0x80);
                    value >>= 7;
                }
                else
                {
                    buffer[state.position++] = (byte)value;
                    return;
                }
            }

            while (value > 127)
            {
                WriteRawByte(ref buffer, ref state, (byte)((value & 0x7F) | 0x80));
                value >>= 7;
            }

            WriteRawByte(ref buffer, ref state, (byte)value);
        }
コード例 #6
0
        private static void WriteRawByte(ref Span <byte> buffer, ref WriterInternalState state, byte value)
        {
            if (state.position == buffer.Length)
            {
                WriteBufferHelper.RefreshBuffer(ref buffer, ref state);
            }

            buffer[state.position++] = value;
        }
コード例 #7
0
 public static void WriteRawLittleEndian64SlowPath(ref Span <byte> buffer, ref WriterInternalState state, ulong value)
 {
     WriteRawByte(ref buffer, ref state, (byte)value);
     WriteRawByte(ref buffer, ref state, (byte)(value >> 8));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 16));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 24));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 32));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 40));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 48));
     WriteRawByte(ref buffer, ref state, (byte)(value >> 56));
 }
コード例 #8
0
 /// <summary>
 /// Writes the given two-byte tag directly to the stream.
 /// </summary>
 public static void WriteRawTag(ref Span <byte> buffer, ref WriterInternalState state, byte b1, byte b2)
 {
     if (state.position + 2 > buffer.Length)
     {
         WriteRawTagSlowPath(ref buffer, ref state, b1, b2);
     }
     else
     {
         buffer[state.position++] = b1;
         buffer[state.position++] = b2;
     }
 }
コード例 #9
0
 /// <summary>
 /// Writes an int32 field value, without a tag, to the stream.
 /// </summary>
 public static void WriteInt32(ref Span <byte> buffer, ref WriterInternalState state, int value)
 {
     if (value >= 0)
     {
         WriteRawVarint32(ref buffer, ref state, (uint)value);
     }
     else
     {
         // Must sign-extend.
         WriteRawVarint64(ref buffer, ref state, (ulong)value);
     }
 }
コード例 #10
0
 public static int GetSpaceLeft(ref WriterInternalState state)
 {
     if (state.writeBufferHelper.codedOutputStream?.InternalOutputStream == null && state.writeBufferHelper.bufferWriter == null)
     {
         return(state.limit - state.position);
     }
     else
     {
         throw new InvalidOperationException(
                   "SpaceLeft can only be called on CodedOutputStreams that are " +
                   "writing to a flat array or when writing to a single span.");
     }
 }
コード例 #11
0
        public static void WriteRawLittleEndian64(ref Span <byte> buffer, ref WriterInternalState state, ulong value)
        {
            const int length = sizeof(ulong);

            if (state.position + length > buffer.Length)
            {
                WriteRawLittleEndian64SlowPath(ref buffer, ref state, value);
            }
            else
            {
                BinaryPrimitives.WriteUInt64LittleEndian(buffer.Slice(state.position), value);
                state.position += length;
            }
        }
コード例 #12
0
 /// <summary>
 /// Writes the given five-byte tag directly to the stream.
 /// </summary>
 public static void WriteRawTag(ref Span <byte> buffer, ref WriterInternalState state, byte b1, byte b2, byte b3, byte b4, byte b5)
 {
     if (state.position + 5 > buffer.Length)
     {
         WriteRawTagSlowPath(ref buffer, ref state, b1, b2, b3, b4, b5);
     }
     else
     {
         buffer[state.position++] = b1;
         buffer[state.position++] = b2;
         buffer[state.position++] = b3;
         buffer[state.position++] = b4;
         buffer[state.position++] = b5;
     }
 }
コード例 #13
0
        /// <summary>
        /// Writes a string field value, without a tag, to the stream.
        /// The data is length-prefixed.
        /// </summary>
        public static void WriteString(ref Span <byte> buffer, ref WriterInternalState state, 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(ref buffer, ref state, length);
            if (buffer.Length - state.position >= length)
            {
                if (length == value.Length) // Must be all ASCII...
                {
                    for (int i = 0; i < length; i++)
                    {
                        buffer[state.position + i] = (byte)value[i];
                    }
                    state.position += length;
                }
                else
                {
#if NETSTANDARD1_1
                    // slowpath when Encoding.GetBytes(Char*, Int32, Byte*, Int32) is not available
                    byte[] bytes = Utf8Encoding.GetBytes(value);
                    WriteRawBytes(ref buffer, ref state, bytes);
#else
                    ReadOnlySpan <char> source = value.AsSpan();
                    int bytesUsed;
                    unsafe
                    {
                        fixed(char *sourceChars = &MemoryMarshal.GetReference(source))
                        fixed(byte *destinationBytes = &MemoryMarshal.GetReference(buffer.Slice(state.position)))
                        {
                            bytesUsed = Utf8Encoding.GetBytes(sourceChars, source.Length, destinationBytes, buffer.Length);
                        }
                    }
                    state.position += bytesUsed;
#endif
                }
            }
            else
            {
                // Opportunity for future optimization:
                // Large strings that don't fit into the current buffer segment
                // can probably be optimized by using Utf8Encoding.GetEncoder()
                // but more benchmarks would need to be added as evidence.
                byte[] bytes = Utf8Encoding.GetBytes(value);
                WriteRawBytes(ref buffer, ref state, bytes);
            }
        }
コード例 #14
0
        private static unsafe void WriteFloatSlowPath(ref Span <byte> buffer, ref WriterInternalState state, float value)
        {
            const int length = sizeof(float);

            // TODO(jtattermusch): deduplicate the code. Populating the span is the same as for the fastpath.
            Span <byte> floatSpan = stackalloc byte[length];

            Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(floatSpan), value);
            if (!BitConverter.IsLittleEndian)
            {
                floatSpan.Reverse();
            }

            WriteRawByte(ref buffer, ref state, floatSpan[0]);
            WriteRawByte(ref buffer, ref state, floatSpan[1]);
            WriteRawByte(ref buffer, ref state, floatSpan[2]);
            WriteRawByte(ref buffer, ref state, floatSpan[3]);
        }
コード例 #15
0
 public static void Flush(ref Span <byte> buffer, ref WriterInternalState state)
 {
     if (state.writeBufferHelper.codedOutputStream?.InternalOutputStream != null)
     {
         // because we're using coded output stream, we know that "buffer" and codedOutputStream.InternalBuffer are identical.
         state.writeBufferHelper.codedOutputStream.InternalOutputStream.Write(state.writeBufferHelper.codedOutputStream.InternalBuffer, 0, state.position);
         state.position = 0;
     }
     else if (state.writeBufferHelper.bufferWriter != null)
     {
         // calling Advance invalidates the current buffer and we must not continue writing to it,
         // so we set the current buffer to point to an empty Span. If any subsequent writes happen,
         // the first subsequent write will trigger refresing of the buffer.
         state.writeBufferHelper.bufferWriter.Advance(state.position);
         state.position = 0;
         state.limit    = 0;
         buffer         = default; // invalidate the current buffer
     }
 }
コード例 #16
0
        /// <summary>
        /// Writes a float field value, without a tag, to the stream.
        /// </summary>
        public static unsafe void WriteFloat(ref Span <byte> buffer, ref WriterInternalState state, float value)
        {
            const int length = sizeof(float);

            if (buffer.Length - state.position >= length)
            {
                // if there's enough space in the buffer, write the float directly into the buffer
                var floatSpan = buffer.Slice(state.position, length);
                Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(floatSpan), value);

                if (!BitConverter.IsLittleEndian)
                {
                    floatSpan.Reverse();
                }
                state.position += length;
            }
            else
            {
                WriteFloatSlowPath(ref buffer, ref state, value);
            }
        }
コード例 #17
0
 public static void RefreshBuffer(ref Span <byte> buffer, ref WriterInternalState state)
 {
     if (state.writeBufferHelper.codedOutputStream?.InternalOutputStream != null)
     {
         // because we're using coded output stream, we know that "buffer" and codedOutputStream.InternalBuffer are identical.
         state.writeBufferHelper.codedOutputStream.InternalOutputStream.Write(state.writeBufferHelper.codedOutputStream.InternalBuffer, 0, state.position);
         // reset position, limit stays the same because we are reusing the codedOutputStream's internal buffer.
         state.position = 0;
     }
     else if (state.writeBufferHelper.bufferWriter != null)
     {
         // commit the bytes and get a new buffer to write to.
         state.writeBufferHelper.bufferWriter.Advance(state.position);
         state.position = 0;
         buffer         = state.writeBufferHelper.bufferWriter.GetSpan();
         state.limit    = buffer.Length;
     }
     else
     {
         // We're writing to a single buffer.
         throw new CodedOutputStream.OutOfSpaceException();
     }
 }
コード例 #18
0
 /// <summary>
 /// Writes out part of an array of bytes.
 /// </summary>
 public static void WriteRawBytes(ref Span <byte> buffer, ref WriterInternalState state, byte[] value, int offset, int length)
 {
     WriteRawBytes(ref buffer, ref state, new ReadOnlySpan <byte>(value, offset, length));
 }
コード例 #19
0
 /// <summary>
 /// Writes a double field value, without a tag, to the stream.
 /// </summary>
 public static void WriteDouble(ref Span <byte> buffer, ref WriterInternalState state, double value)
 {
     WriteRawLittleEndian64(ref buffer, ref state, (ulong)BitConverter.DoubleToInt64Bits(value));
 }
コード例 #20
0
 /// <summary>
 /// Writes an sfixed64 value, without a tag, to the stream.
 /// </summary>
 public static void WriteSFixed64(ref Span <byte> buffer, ref WriterInternalState state, long value)
 {
     WriteRawLittleEndian64(ref buffer, ref state, (ulong)value);
 }
コード例 #21
0
 /// <summary>
 /// Writes the given single-byte tag directly to the stream.
 /// </summary>
 public static void WriteRawTag(ref Span <byte> buffer, ref WriterInternalState state, byte b1)
 {
     WriteRawByte(ref buffer, ref state, b1);
 }
コード例 #22
0
 /// <summary>
 /// Writes an already-encoded tag.
 /// </summary>
 public static void WriteTag(ref Span <byte> buffer, ref WriterInternalState state, uint tag)
 {
     WriteRawVarint32(ref buffer, ref state, tag);
 }
コード例 #23
0
 /// <summary>
 /// Encodes and writes a tag.
 /// </summary>
 public static void WriteTag(ref Span <byte> buffer, ref WriterInternalState state, int fieldNumber, WireFormat.WireType type)
 {
     WriteRawVarint32(ref buffer, ref state, WireFormat.MakeTag(fieldNumber, type));
 }
コード例 #24
0
 /// <summary>
 /// Writes a length (in bytes) for length-delimited data.
 /// </summary>
 /// <remarks>
 /// This method simply writes a rawint, but exists for clarity in calling code.
 /// </remarks>
 public static void WriteLength(ref Span <byte> buffer, ref WriterInternalState state, int length)
 {
     WriteRawVarint32(ref buffer, ref state, (uint)length);
 }
コード例 #25
0
 /// <summary>
 /// Writes out an array of bytes.
 /// </summary>
 public static void WriteRawBytes(ref Span <byte> buffer, ref WriterInternalState state, byte[] value)
 {
     WriteRawBytes(ref buffer, ref state, new ReadOnlySpan <byte>(value));
 }
コード例 #26
0
 /// <summary>
 /// Writes a uint32 value, without a tag, to the stream.
 /// </summary>
 public static void WriteUInt32(ref Span <byte> buffer, ref WriterInternalState state, uint value)
 {
     WriteRawVarint32(ref buffer, ref state, value);
 }
コード例 #27
0
 /// <summary>
 /// Writes an enum value, without a tag, to the stream.
 /// </summary>
 public static void WriteEnum(ref Span <byte> buffer, ref WriterInternalState state, int value)
 {
     WriteInt32(ref buffer, ref state, value);
 }
コード例 #28
0
 /// <summary>
 /// Writes an sfixed32 value, without a tag, to the stream.
 /// </summary>
 public static void WriteSFixed32(ref Span <byte> buffer, ref WriterInternalState state, int value)
 {
     WriteRawLittleEndian32(ref buffer, ref state, (uint)value);
 }
コード例 #29
0
 /// <summary>
 /// Write a byte string, without a tag, to the stream.
 /// The data is length-prefixed.
 /// </summary>
 public static void WriteBytes(ref Span <byte> buffer, ref WriterInternalState state, ByteString value)
 {
     WriteLength(ref buffer, ref state, value.Length);
     WriteRawBytes(ref buffer, ref state, value.Span);
 }
コード例 #30
0
 /// <summary>
 /// Writes an sint64 value, without a tag, to the stream.
 /// </summary>
 public static void WriteSInt64(ref Span <byte> buffer, ref WriterInternalState state, long value)
 {
     WriteRawVarint64(ref buffer, ref state, EncodeZigZag64(value));
 }