|
@@ -0,0 +1,2804 @@
|
|
|
|
+// 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.
|
|
|
|
+
|
|
|
|
+package com.google.protobuf;
|
|
|
|
+
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.FIXED32_SIZE;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.FIXED64_SIZE;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.MAX_VARINT32_SIZE;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.MAX_VARINT64_SIZE;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_END_GROUP;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_FIXED32;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_FIXED64;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_LENGTH_DELIMITED;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_START_GROUP;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.WIRETYPE_VARINT;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.encodeZigZag32;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.encodeZigZag64;
|
|
|
|
+import static com.google.protobuf.BinaryProtocolUtil.tagFor;
|
|
|
|
+import static com.google.protobuf.Internal.checkNotNull;
|
|
|
|
+
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.nio.ByteBuffer;
|
|
|
|
+import java.nio.ByteOrder;
|
|
|
|
+import java.util.ArrayDeque;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Queue;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * A protobuf writer that serializes messages in their binary form. Messages are serialized in
|
|
|
|
+ * reverse in order to avoid calculating the serialized size of each nested message. Since the
|
|
|
|
+ * message size is not known in advance, the writer employs a strategy of chunking and buffer
|
|
|
|
+ * chaining. Buffers are allocated as-needed by a provided {@link BufferAllocator}. Once writing is
|
|
|
|
+ * finished, the application can access the buffers in forward-writing order by calling {@link
|
|
|
|
+ * #complete()}.
|
|
|
|
+ *
|
|
|
|
+ * <p>Once {@link #complete()} has been called, the writer can not be reused for additional writes.
|
|
|
|
+ * The {@link #getTotalBytesWritten()} will continue to reflect the total of the write and will not
|
|
|
|
+ * be reset.
|
|
|
|
+ */
|
|
|
|
+@ExperimentalApi
|
|
|
|
+public abstract class BinaryWriter extends ByteOutput implements Writer {
|
|
|
|
+ public static final int DEFAULT_CHUNK_SIZE = 4096;
|
|
|
|
+
|
|
|
|
+ private final BufferAllocator alloc;
|
|
|
|
+ private final int chunkSize;
|
|
|
|
+
|
|
|
|
+ final ArrayDeque<AllocatedBuffer> buffers = new ArrayDeque<AllocatedBuffer>(4);
|
|
|
|
+ int totalDoneBytes;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@link
|
|
|
|
+ * #DEFAULT_CHUNK_SIZE} as necessary.
|
|
|
|
+ */
|
|
|
|
+ public static BinaryWriter newHeapInstance(BufferAllocator alloc) {
|
|
|
|
+ return newHeapInstance(alloc, DEFAULT_CHUNK_SIZE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates a new {@link BinaryWriter} that will allocate heap buffers of {@code chunkSize} as
|
|
|
|
+ * necessary.
|
|
|
|
+ */
|
|
|
|
+ public static BinaryWriter newHeapInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ return isUnsafeHeapSupported()
|
|
|
|
+ ? newUnsafeHeapInstance(alloc, chunkSize)
|
|
|
|
+ : newSafeHeapInstance(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@link
|
|
|
|
+ * #DEFAULT_CHUNK_SIZE} as necessary.
|
|
|
|
+ */
|
|
|
|
+ public static BinaryWriter newDirectInstance(BufferAllocator alloc) {
|
|
|
|
+ return newDirectInstance(alloc, DEFAULT_CHUNK_SIZE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates a new {@link BinaryWriter} that will allocate direct (i.e. non-heap) buffers of {@code
|
|
|
|
+ * chunkSize} as necessary.
|
|
|
|
+ */
|
|
|
|
+ public static BinaryWriter newDirectInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ return isUnsafeDirectSupported()
|
|
|
|
+ ? newUnsafeDirectInstance(alloc, chunkSize)
|
|
|
|
+ : newSafeDirectInstance(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean isUnsafeHeapSupported() {
|
|
|
|
+ return UnsafeHeapWriter.isSupported();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static boolean isUnsafeDirectSupported() {
|
|
|
|
+ return UnsafeDirectWriter.isSupported();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static BinaryWriter newSafeHeapInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ return new SafeHeapWriter(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static BinaryWriter newUnsafeHeapInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ if (!isUnsafeHeapSupported()) {
|
|
|
|
+ throw new UnsupportedOperationException("Unsafe operations not supported");
|
|
|
|
+ }
|
|
|
|
+ return new UnsafeHeapWriter(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static BinaryWriter newSafeDirectInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ return new SafeDirectWriter(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ static BinaryWriter newUnsafeDirectInstance(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ if (!isUnsafeDirectSupported()) {
|
|
|
|
+ throw new UnsupportedOperationException("Unsafe operations not supported");
|
|
|
|
+ }
|
|
|
|
+ return new UnsafeDirectWriter(alloc, chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Only allow subclassing for inner classes. */
|
|
|
|
+ private BinaryWriter(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ if (chunkSize <= 0) {
|
|
|
|
+ throw new IllegalArgumentException("chunkSize must be > 0");
|
|
|
|
+ }
|
|
|
|
+ this.alloc = checkNotNull(alloc, "alloc");
|
|
|
|
+ this.chunkSize = chunkSize;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Completes the write operation and returns a queue of {@link AllocatedBuffer} objects in
|
|
|
|
+ * forward-writing order. This method should only be called once.
|
|
|
|
+ *
|
|
|
|
+ * <p>After calling this method, the writer can not be reused. Create a new writer for future
|
|
|
|
+ * writes.
|
|
|
|
+ */
|
|
|
|
+ public final Queue<AllocatedBuffer> complete() {
|
|
|
|
+ finishCurrentBuffer();
|
|
|
|
+ return buffers;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSFixed32(int fieldNumber, int value) {
|
|
|
|
+ writeFixed32(fieldNumber, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeInt64(int fieldNumber, long value) {
|
|
|
|
+ writeUInt64(fieldNumber, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSFixed64(int fieldNumber, long value) {
|
|
|
|
+ writeFixed64(fieldNumber, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeFloat(int fieldNumber, float value) {
|
|
|
|
+ writeFixed32(fieldNumber, Float.floatToRawIntBits(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeDouble(int fieldNumber, double value) {
|
|
|
|
+ writeFixed64(fieldNumber, Double.doubleToRawLongBits(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeEnum(int fieldNumber, int value) {
|
|
|
|
+ writeInt32(fieldNumber, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeInt32List(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (list instanceof IntArrayList) {
|
|
|
|
+ writeInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeInt32List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeInt32(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeInt32(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeInt32(list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeInt32(fieldNumber, list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeFixed32List(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (list instanceof IntArrayList) {
|
|
|
|
+ writeFixed32List_Internal(fieldNumber, (IntArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeFixed32List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFixed32List_Internal(
|
|
|
|
+ int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFixed32List_Internal(int fieldNumber, IntArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(fieldNumber, list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeInt64List(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ writeUInt64List(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeUInt64List(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (list instanceof LongArrayList) {
|
|
|
|
+ writeUInt64List_Internal(fieldNumber, (LongArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeUInt64List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeUInt64List_Internal(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeVarint64(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeUInt64(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeUInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeVarint64(list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeUInt64(fieldNumber, list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeFixed64List(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (list instanceof LongArrayList) {
|
|
|
|
+ writeFixed64List_Internal(fieldNumber, (LongArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeFixed64List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFixed64List_Internal(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFixed64List_Internal(
|
|
|
|
+ int fieldNumber, LongArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(fieldNumber, list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeFloatList(int fieldNumber, List<Float> list, boolean packed) {
|
|
|
|
+ if (list instanceof FloatArrayList) {
|
|
|
|
+ writeFloatList_Internal(fieldNumber, (FloatArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeFloatList_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFloatList_Internal(int fieldNumber, List<Float> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(Float.floatToRawIntBits(list.get(i)));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFloat(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeFloatList_Internal(int fieldNumber, FloatArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed32(Float.floatToRawIntBits(list.getFloat(i)));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFloat(fieldNumber, list.getFloat(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeDoubleList(int fieldNumber, List<Double> list, boolean packed) {
|
|
|
|
+ if (list instanceof DoubleArrayList) {
|
|
|
|
+ writeDoubleList_Internal(fieldNumber, (DoubleArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeDoubleList_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeDoubleList_Internal(int fieldNumber, List<Double> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(Double.doubleToRawLongBits(list.get(i)));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeDouble(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeDoubleList_Internal(
|
|
|
|
+ int fieldNumber, DoubleArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * FIXED64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeFixed64(Double.doubleToRawLongBits(list.getDouble(i)));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeDouble(fieldNumber, list.getDouble(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeEnumList(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ writeInt32List(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeBoolList(int fieldNumber, List<Boolean> list, boolean packed) {
|
|
|
|
+ if (list instanceof BooleanArrayList) {
|
|
|
|
+ writeBoolList_Internal(fieldNumber, (BooleanArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeBoolList_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeBoolList_Internal(int fieldNumber, List<Boolean> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeBool(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeBool(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeBoolList_Internal(
|
|
|
|
+ int fieldNumber, BooleanArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + list.size());
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeBool(list.getBoolean(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeBool(fieldNumber, list.getBoolean(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeStringList(int fieldNumber, List<String> list) {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; i--) {
|
|
|
|
+ writeString(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeBytesList(int fieldNumber, List<ByteString> list) {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; i--) {
|
|
|
|
+ writeBytes(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeUInt32List(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (list instanceof IntArrayList) {
|
|
|
|
+ writeUInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeUInt32List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeUInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeVarint32(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeUInt32(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeUInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeVarint32(list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeUInt32(fieldNumber, list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSFixed32List(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ writeFixed32List(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSFixed64List(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ writeFixed64List(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSInt32List(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (list instanceof IntArrayList) {
|
|
|
|
+ writeSInt32List_Internal(fieldNumber, (IntArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeSInt32List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeSInt32List_Internal(int fieldNumber, List<Integer> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt32(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt32(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeSInt32List_Internal(int fieldNumber, IntArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT32_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt32(list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt32(fieldNumber, list.getInt(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeSInt64List(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (list instanceof LongArrayList) {
|
|
|
|
+ writeSInt64List_Internal(fieldNumber, (LongArrayList) list, packed);
|
|
|
|
+ } else {
|
|
|
|
+ writeSInt64List_Internal(fieldNumber, list, packed);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeSInt64List_Internal(int fieldNumber, List<Long> list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt64(list.get(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt64(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final void writeSInt64List_Internal(int fieldNumber, LongArrayList list, boolean packed) {
|
|
|
|
+ if (packed) {
|
|
|
|
+ requireSpace((MAX_VARINT32_SIZE * 2) + (list.size() * MAX_VARINT64_SIZE));
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt64(list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ } else {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; --i) {
|
|
|
|
+ writeSInt64(fieldNumber, list.getLong(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeMessageList(int fieldNumber, List<?> list) {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; i--) {
|
|
|
|
+ writeMessage(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final void writeGroupList(int fieldNumber, List<?> list) {
|
|
|
|
+ for (int i = list.size() - 1; i >= 0; i--) {
|
|
|
|
+ writeGroup(fieldNumber, list.get(i));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final AllocatedBuffer newHeapBuffer() {
|
|
|
|
+ return alloc.allocateHeapBuffer(chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final AllocatedBuffer newHeapBuffer(int capacity) {
|
|
|
|
+ return alloc.allocateHeapBuffer(Math.max(capacity, chunkSize));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final AllocatedBuffer newDirectBuffer() {
|
|
|
|
+ return alloc.allocateDirectBuffer(chunkSize);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final AllocatedBuffer newDirectBuffer(int capacity) {
|
|
|
|
+ return alloc.allocateDirectBuffer(Math.max(capacity, chunkSize));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the total number of bytes that have been written. This will not be reset by a call to
|
|
|
|
+ * {@link #complete()}.
|
|
|
|
+ */
|
|
|
|
+ public abstract int getTotalBytesWritten();
|
|
|
|
+
|
|
|
|
+ abstract void requireSpace(int size);
|
|
|
|
+
|
|
|
|
+ abstract void finishCurrentBuffer();
|
|
|
|
+
|
|
|
|
+ abstract void writeTag(int fieldNumber, byte wireType);
|
|
|
|
+
|
|
|
|
+ abstract void writeVarint32(int value);
|
|
|
|
+
|
|
|
|
+ abstract void writeInt32(int value);
|
|
|
|
+
|
|
|
|
+ abstract void writeSInt32(int value);
|
|
|
|
+
|
|
|
|
+ abstract void writeFixed32(int value);
|
|
|
|
+
|
|
|
|
+ abstract void writeVarint64(long value);
|
|
|
|
+
|
|
|
|
+ abstract void writeSInt64(long value);
|
|
|
|
+
|
|
|
|
+ abstract void writeFixed64(long value);
|
|
|
|
+
|
|
|
|
+ abstract void writeBool(boolean value);
|
|
|
|
+
|
|
|
|
+ abstract void writeString(String in);
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Not using the version in CodedOutputStream due to the fact that benchmarks have shown a
|
|
|
|
+ * performance improvement when returning a byte (rather than an int).
|
|
|
|
+ */
|
|
|
|
+ private static byte computeUInt64SizeNoTag(long value) {
|
|
|
|
+ // handle two popular special cases up front ...
|
|
|
|
+ if ((value & (~0L << 7)) == 0L) {
|
|
|
|
+ // Byte 1
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ if (value < 0L) {
|
|
|
|
+ // Byte 10
|
|
|
|
+ return 10;
|
|
|
|
+ }
|
|
|
|
+ // ... leaving us with 8 remaining, which we can divide and conquer
|
|
|
|
+ byte n = 2;
|
|
|
|
+ if ((value & (~0L << 35)) != 0L) {
|
|
|
|
+ // Byte 6-9
|
|
|
|
+ n += 4; // + (value >>> 63);
|
|
|
|
+ value >>>= 28;
|
|
|
|
+ }
|
|
|
|
+ if ((value & (~0L << 21)) != 0L) {
|
|
|
|
+ // Byte 4-5 or 8-9
|
|
|
|
+ n += 2;
|
|
|
|
+ value >>>= 14;
|
|
|
|
+ }
|
|
|
|
+ if ((value & (~0L << 14)) != 0L) {
|
|
|
|
+ // Byte 3 or 7
|
|
|
|
+ n += 1;
|
|
|
|
+ }
|
|
|
|
+ return n;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Writer that uses safe operations on target array. */
|
|
|
|
+ private static final class SafeHeapWriter extends BinaryWriter {
|
|
|
|
+ private AllocatedBuffer allocatedBuffer;
|
|
|
|
+ private byte[] buffer;
|
|
|
|
+ private int offset;
|
|
|
|
+ private int limit;
|
|
|
|
+ private int offsetMinusOne;
|
|
|
|
+ private int limitMinusOne;
|
|
|
|
+ private int pos;
|
|
|
|
+
|
|
|
|
+ SafeHeapWriter(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ super(alloc, chunkSize);
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void finishCurrentBuffer() {
|
|
|
|
+ if (allocatedBuffer != null) {
|
|
|
|
+ totalDoneBytes += bytesWrittenToCurrentBuffer();
|
|
|
|
+ allocatedBuffer.position((pos - allocatedBuffer.arrayOffset()) + 1);
|
|
|
|
+ allocatedBuffer = null;
|
|
|
|
+ pos = 0;
|
|
|
|
+ limitMinusOne = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer() {
|
|
|
|
+ nextBuffer(newHeapBuffer());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(int capacity) {
|
|
|
|
+ nextBuffer(newHeapBuffer(capacity));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(AllocatedBuffer allocatedBuffer) {
|
|
|
|
+ if (!allocatedBuffer.hasArray()) {
|
|
|
|
+ throw new RuntimeException("Allocator returned non-heap buffer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finishCurrentBuffer();
|
|
|
|
+
|
|
|
|
+ buffers.addFirst(allocatedBuffer);
|
|
|
|
+
|
|
|
|
+ this.allocatedBuffer = allocatedBuffer;
|
|
|
|
+ this.buffer = allocatedBuffer.array();
|
|
|
|
+ int arrayOffset = allocatedBuffer.arrayOffset();
|
|
|
|
+ this.limit = arrayOffset + allocatedBuffer.limit();
|
|
|
|
+ this.offset = arrayOffset + allocatedBuffer.position();
|
|
|
|
+ this.offsetMinusOne = offset - 1;
|
|
|
|
+ this.limitMinusOne = limit - 1;
|
|
|
|
+ this.pos = limitMinusOne;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getTotalBytesWritten() {
|
|
|
|
+ return totalDoneBytes + bytesWrittenToCurrentBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int bytesWrittenToCurrentBuffer() {
|
|
|
|
+ return limitMinusOne - pos;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int spaceLeft() {
|
|
|
|
+ return pos - offsetMinusOne;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeSInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
|
|
|
|
+ writeFixed32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED32);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeSInt64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
|
|
|
|
+ writeFixed64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED64);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBool(int fieldNumber, boolean value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + 1);
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeString(int fieldNumber, String value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ writeString(value);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(2 * MAX_VARINT32_SIZE);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBytes(int fieldNumber, ByteString value) {
|
|
|
|
+ try {
|
|
|
|
+ value.writeToReverse(this);
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ // Should never happen since the writer does not throw.
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value.size());
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeMessage(int fieldNumber, Object value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeGroup(int fieldNumber, Object value) {
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_END_GROUP);
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_START_GROUP);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeInt32(int value) {
|
|
|
|
+ if (value >= 0) {
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt32(int value) {
|
|
|
|
+ writeVarint32(encodeZigZag32(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt64(long value) {
|
|
|
|
+ writeVarint64(encodeZigZag64(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeBool(boolean value) {
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeTag(int fieldNumber, byte wireType) {
|
|
|
|
+ writeVarint32(tagFor(fieldNumber, wireType));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint32(int value) {
|
|
|
|
+ if ((value & (~0 << 7)) == 0) {
|
|
|
|
+ writeVarint32OneByte(value);
|
|
|
|
+ } else if ((value & (~0 << 14)) == 0) {
|
|
|
|
+ writeVarint32TwoBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 21)) == 0) {
|
|
|
|
+ writeVarint32ThreeBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 28)) == 0) {
|
|
|
|
+ writeVarint32FourBytes(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint32FiveBytes(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32OneByte(int value) {
|
|
|
|
+ buffer[pos--] = (byte) value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32TwoBytes(int value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 7);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32ThreeBytes(int value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 14);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FourBytes(int value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 21);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FiveBytes(int value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 28);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint64(long value) {
|
|
|
|
+ switch (computeUInt64SizeNoTag(value)) {
|
|
|
|
+ case 1:
|
|
|
|
+ writeVarint64OneByte(value);
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ writeVarint64TwoBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ writeVarint64ThreeBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 4:
|
|
|
|
+ writeVarint64FourBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 5:
|
|
|
|
+ writeVarint64FiveBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 6:
|
|
|
|
+ writeVarint64SixBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 7:
|
|
|
|
+ writeVarint64SevenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 8:
|
|
|
|
+ writeVarint64EightBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 9:
|
|
|
|
+ writeVarint64NineBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 10:
|
|
|
|
+ writeVarint64TenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64OneByte(long value) {
|
|
|
|
+ buffer[pos--] = (byte) value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TwoBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 7);
|
|
|
|
+ buffer[pos--] = (byte) (((int) value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64ThreeBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (((int) value) >>> 14);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FourBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 21);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FiveBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 28);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SixBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 35);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SevenBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 42);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64EightBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 49);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64NineBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 56);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TenBytes(long value) {
|
|
|
|
+ buffer[pos--] = (byte) (value >>> 63);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 56) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 49) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 42) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 35) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 28) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 21) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 14) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) (((value >>> 7) & 0x7F) | 0x80);
|
|
|
|
+ buffer[pos--] = (byte) ((value & 0x7F) | 0x80);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed32(int value) {
|
|
|
|
+ buffer[pos--] = (byte) ((value >> 24) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((value >> 16) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((value >> 8) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) (value & 0xFF);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed64(long value) {
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 56) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 48) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 40) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 32) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 24) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 16) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value >> 8) & 0xFF);
|
|
|
|
+ buffer[pos--] = (byte) ((int) (value) & 0xFF);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeString(String in) {
|
|
|
|
+ // Request enough space to write the ASCII string.
|
|
|
|
+ requireSpace(in.length());
|
|
|
|
+
|
|
|
|
+ // We know the buffer is big enough...
|
|
|
|
+ int i = in.length() - 1;
|
|
|
|
+ // Set pos to the start of the ASCII string.
|
|
|
|
+ pos -= i;
|
|
|
|
+ // Designed to take advantage of
|
|
|
|
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
|
|
|
+ for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
|
|
|
|
+ buffer[pos + i] = (byte) c;
|
|
|
|
+ }
|
|
|
|
+ if (i == -1) {
|
|
|
|
+ // Move pos past the String.
|
|
|
|
+ pos -= 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ pos += i;
|
|
|
|
+ for (char c; i >= 0; i--) {
|
|
|
|
+ c = in.charAt(i);
|
|
|
|
+ if (c < 0x80 && pos > offsetMinusOne) {
|
|
|
|
+ buffer[pos--] = (byte) c;
|
|
|
|
+ } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & c));
|
|
|
|
+ buffer[pos--] = (byte) ((0xF << 6) | (c >>> 6));
|
|
|
|
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
|
|
|
|
+ && pos > (offset + 1)) {
|
|
|
|
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & c));
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & (c >>> 6)));
|
|
|
|
+ buffer[pos--] = (byte) ((0xF << 5) | (c >>> 12));
|
|
|
|
+ } else if (pos > (offset + 2)) {
|
|
|
|
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
|
|
|
+ // four UTF-8 bytes
|
|
|
|
+ char high = 0;
|
|
|
|
+ if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
|
|
|
|
+ throw new Utf8.UnpairedSurrogateException(i - 1, i);
|
|
|
|
+ }
|
|
|
|
+ i--;
|
|
|
|
+ int codePoint = Character.toCodePoint(high, c);
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & codePoint));
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
|
|
|
|
+ buffer[pos--] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
|
|
|
|
+ buffer[pos--] = (byte) ((0xF << 4) | (codePoint >>> 18));
|
|
|
|
+ } else {
|
|
|
|
+ // Buffer is full - allocate a new one and revisit the current character.
|
|
|
|
+ requireSpace(i);
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte value) {
|
|
|
|
+ buffer[pos--] = value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ System.arraycopy(value, offset, buffer, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ System.arraycopy(value, offset, buffer, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ value.get(buffer, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ value.get(buffer, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void requireSpace(int size) {
|
|
|
|
+ if (spaceLeft() < size) {
|
|
|
|
+ nextBuffer(size);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Writer that uses unsafe operations on a target array. */
|
|
|
|
+ private static final class UnsafeHeapWriter extends BinaryWriter {
|
|
|
|
+ private AllocatedBuffer allocatedBuffer;
|
|
|
|
+ private byte[] buffer;
|
|
|
|
+ private long offset;
|
|
|
|
+ private long limit;
|
|
|
|
+ private long offsetMinusOne;
|
|
|
|
+ private long limitMinusOne;
|
|
|
|
+ private long pos;
|
|
|
|
+
|
|
|
|
+ UnsafeHeapWriter(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ super(alloc, chunkSize);
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Indicates whether the required unsafe operations are supported on this platform. */
|
|
|
|
+ static boolean isSupported() {
|
|
|
|
+ return UnsafeUtil.hasUnsafeArrayOperations();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void finishCurrentBuffer() {
|
|
|
|
+ if (allocatedBuffer != null) {
|
|
|
|
+ totalDoneBytes += bytesWrittenToCurrentBuffer();
|
|
|
|
+ allocatedBuffer.position((arrayPos() - allocatedBuffer.arrayOffset()) + 1);
|
|
|
|
+ allocatedBuffer = null;
|
|
|
|
+ pos = 0;
|
|
|
|
+ limitMinusOne = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int arrayPos() {
|
|
|
|
+ return (int) (pos - UnsafeUtil.getArrayBaseOffset());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer() {
|
|
|
|
+ nextBuffer(newHeapBuffer());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(int capacity) {
|
|
|
|
+ nextBuffer(newHeapBuffer(capacity));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(AllocatedBuffer allocatedBuffer) {
|
|
|
|
+ if (!allocatedBuffer.hasArray()) {
|
|
|
|
+ throw new RuntimeException("Allocator returned non-heap buffer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finishCurrentBuffer();
|
|
|
|
+ buffers.addFirst(allocatedBuffer);
|
|
|
|
+
|
|
|
|
+ this.allocatedBuffer = allocatedBuffer;
|
|
|
|
+ this.buffer = allocatedBuffer.array();
|
|
|
|
+ int arrayOffset = allocatedBuffer.arrayOffset();
|
|
|
|
+ long byteArrayOffset = UnsafeUtil.getArrayBaseOffset();
|
|
|
|
+ this.limit = byteArrayOffset + arrayOffset + allocatedBuffer.limit();
|
|
|
|
+ this.offset = byteArrayOffset + arrayOffset + allocatedBuffer.position();
|
|
|
|
+ this.offsetMinusOne = offset - 1;
|
|
|
|
+ this.limitMinusOne = limit - 1;
|
|
|
|
+ this.pos = limitMinusOne;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getTotalBytesWritten() {
|
|
|
|
+ return totalDoneBytes + bytesWrittenToCurrentBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int bytesWrittenToCurrentBuffer() {
|
|
|
|
+ return (int) (limitMinusOne - pos);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int spaceLeft() {
|
|
|
|
+ return (int) (pos - offsetMinusOne);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeSInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
|
|
|
|
+ writeFixed32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED32);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeSInt64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
|
|
|
|
+ writeFixed64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED64);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBool(int fieldNumber, boolean value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + 1);
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeString(int fieldNumber, String value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ writeString(value);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(2 * MAX_VARINT32_SIZE);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBytes(int fieldNumber, ByteString value) {
|
|
|
|
+ try {
|
|
|
|
+ value.writeToReverse(this);
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ // Should never happen since the writer does not throw.
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value.size());
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeMessage(int fieldNumber, Object value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeGroup(int fieldNumber, Object value) {
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_END_GROUP);
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_START_GROUP);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeInt32(int value) {
|
|
|
|
+ if (value >= 0) {
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt32(int value) {
|
|
|
|
+ writeVarint32(encodeZigZag32(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt64(long value) {
|
|
|
|
+ writeVarint64(encodeZigZag64(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeBool(boolean value) {
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeTag(int fieldNumber, byte wireType) {
|
|
|
|
+ writeVarint32(tagFor(fieldNumber, wireType));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint32(int value) {
|
|
|
|
+ if ((value & (~0 << 7)) == 0) {
|
|
|
|
+ writeVarint32OneByte(value);
|
|
|
|
+ } else if ((value & (~0 << 14)) == 0) {
|
|
|
|
+ writeVarint32TwoBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 21)) == 0) {
|
|
|
|
+ writeVarint32ThreeBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 28)) == 0) {
|
|
|
|
+ writeVarint32FourBytes(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint32FiveBytes(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32OneByte(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32TwoBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32ThreeBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 14));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FourBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FiveBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint64(long value) {
|
|
|
|
+ switch (computeUInt64SizeNoTag(value)) {
|
|
|
|
+ case 1:
|
|
|
|
+ writeVarint64OneByte(value);
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ writeVarint64TwoBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ writeVarint64ThreeBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 4:
|
|
|
|
+ writeVarint64FourBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 5:
|
|
|
|
+ writeVarint64FiveBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 6:
|
|
|
|
+ writeVarint64SixBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 7:
|
|
|
|
+ writeVarint64SevenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 8:
|
|
|
|
+ writeVarint64EightBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 9:
|
|
|
|
+ writeVarint64NineBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 10:
|
|
|
|
+ writeVarint64TenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64OneByte(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TwoBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 7));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64ThreeBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((int) value) >>> 14));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FourBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 21));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FiveBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 28));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SixBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 35));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SevenBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 42));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64EightBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 49));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64NineBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 56));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TenBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value >>> 63));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed32(int value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 24) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 16) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((value >> 8) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (value & 0xFF));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed64(long value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 56) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 48) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 40) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 32) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 24) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 16) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value >> 8) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((int) (value) & 0xFF));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeString(String in) {
|
|
|
|
+ // Request enough space to write the ASCII string.
|
|
|
|
+ requireSpace(in.length());
|
|
|
|
+
|
|
|
|
+ // We know the buffer is big enough...
|
|
|
|
+ int i = in.length() - 1;
|
|
|
|
+ // Set pos to the start of the ASCII string.
|
|
|
|
+ //pos -= i;
|
|
|
|
+ // Designed to take advantage of
|
|
|
|
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
|
|
|
+ for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) c);
|
|
|
|
+ }
|
|
|
|
+ if (i == -1) {
|
|
|
|
+ // Move pos past the String.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (char c; i >= 0; i--) {
|
|
|
|
+ c = in.charAt(i);
|
|
|
|
+ if (c < 0x80 && pos > offsetMinusOne) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) c);
|
|
|
|
+ } else if (c < 0x800 && pos > offset) { // 11 bits, two UTF-8 bytes
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 6) | (c >>> 6)));
|
|
|
|
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
|
|
|
|
+ && pos > offset + 1) {
|
|
|
|
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 5) | (c >>> 12)));
|
|
|
|
+ } else if (pos > offset + 2) {
|
|
|
|
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
|
|
|
+ // four UTF-8 bytes
|
|
|
|
+ final char high;
|
|
|
|
+ if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
|
|
|
|
+ throw new Utf8.UnpairedSurrogateException(i - 1, i);
|
|
|
|
+ }
|
|
|
|
+ i--;
|
|
|
|
+ int codePoint = Character.toCodePoint(high, c);
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & codePoint)));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
|
|
|
|
+ } else {
|
|
|
|
+ // Buffer is full - allocate a new one and revisit the current character.
|
|
|
|
+ requireSpace(i);
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte value) {
|
|
|
|
+ UnsafeUtil.putByte(buffer, pos--, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte[] value, int offset, int length) {
|
|
|
|
+ if (offset < 0 || offset + length > value.length) {
|
|
|
|
+ throw new ArrayIndexOutOfBoundsException(
|
|
|
|
+ String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length));
|
|
|
|
+ }
|
|
|
|
+ requireSpace(length);
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ System.arraycopy(value, offset, buffer, arrayPos() + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(byte[] value, int offset, int length) {
|
|
|
|
+ if (offset < 0 || offset + length > value.length) {
|
|
|
|
+ throw new ArrayIndexOutOfBoundsException(
|
|
|
|
+ String.format("value.length=%d, offset=%d, length=%d", value.length, offset, length));
|
|
|
|
+ }
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ System.arraycopy(value, offset, buffer, arrayPos() + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ requireSpace(length);
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ value.get(buffer, arrayPos() + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ value.get(buffer, arrayPos() + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void requireSpace(int size) {
|
|
|
|
+ if (spaceLeft() < size) {
|
|
|
|
+ nextBuffer(size);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Writer that uses safe operations on a target {@link ByteBuffer}. */
|
|
|
|
+ private static final class SafeDirectWriter extends BinaryWriter {
|
|
|
|
+ private ByteBuffer buffer;
|
|
|
|
+ private int limitMinusOne;
|
|
|
|
+ private int pos;
|
|
|
|
+
|
|
|
|
+ SafeDirectWriter(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ super(alloc, chunkSize);
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer() {
|
|
|
|
+ nextBuffer(newDirectBuffer());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(int capacity) {
|
|
|
|
+ nextBuffer(newDirectBuffer(capacity));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(AllocatedBuffer allocatedBuffer) {
|
|
|
|
+ if (!allocatedBuffer.hasNioBuffer()) {
|
|
|
|
+ throw new RuntimeException("Allocated buffer does not have NIO buffer");
|
|
|
|
+ }
|
|
|
|
+ ByteBuffer nioBuffer = allocatedBuffer.nioBuffer();
|
|
|
|
+ if (!nioBuffer.isDirect()) {
|
|
|
|
+ throw new RuntimeException("Allocator returned non-direct buffer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finishCurrentBuffer();
|
|
|
|
+ buffers.addFirst(allocatedBuffer);
|
|
|
|
+
|
|
|
|
+ buffer = nioBuffer;
|
|
|
|
+ buffer.limit(buffer.capacity());
|
|
|
|
+ buffer.position(0);
|
|
|
|
+ // Set byte order to little endian for fast writing of fixed 32/64.
|
|
|
|
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
|
|
+
|
|
|
|
+ limitMinusOne = buffer.limit() - 1;
|
|
|
|
+ pos = limitMinusOne;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getTotalBytesWritten() {
|
|
|
|
+ return totalDoneBytes + bytesWrittenToCurrentBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int bytesWrittenToCurrentBuffer() {
|
|
|
|
+ return limitMinusOne - pos;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int spaceLeft() {
|
|
|
|
+ return pos + 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void finishCurrentBuffer() {
|
|
|
|
+ if (buffer != null) {
|
|
|
|
+ totalDoneBytes += bytesWrittenToCurrentBuffer();
|
|
|
|
+ // Update the indices on the netty buffer.
|
|
|
|
+ buffer.position(pos + 1);
|
|
|
|
+ buffer = null;
|
|
|
|
+ pos = 0;
|
|
|
|
+ limitMinusOne = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeSInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
|
|
|
|
+ writeFixed32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED32);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeSInt64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
|
|
|
|
+ writeFixed64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED64);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBool(int fieldNumber, boolean value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + 1);
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeString(int fieldNumber, String value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ writeString(value);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(2 * MAX_VARINT32_SIZE);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBytes(int fieldNumber, ByteString value) {
|
|
|
|
+ try {
|
|
|
|
+ value.writeToReverse(this);
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ // Should never happen since the writer does not throw.
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value.size());
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeMessage(int fieldNumber, Object value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeGroup(int fieldNumber, Object value) {
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_END_GROUP);
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_START_GROUP);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeInt32(int value) {
|
|
|
|
+ if (value >= 0) {
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt32(int value) {
|
|
|
|
+ writeVarint32(encodeZigZag32(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt64(long value) {
|
|
|
|
+ writeVarint64(encodeZigZag64(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeBool(boolean value) {
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeTag(int fieldNumber, byte wireType) {
|
|
|
|
+ writeVarint32(tagFor(fieldNumber, wireType));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint32(int value) {
|
|
|
|
+ if ((value & (~0 << 7)) == 0) {
|
|
|
|
+ writeVarint32OneByte(value);
|
|
|
|
+ } else if ((value & (~0 << 14)) == 0) {
|
|
|
|
+ writeVarint32TwoBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 21)) == 0) {
|
|
|
|
+ writeVarint32ThreeBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 28)) == 0) {
|
|
|
|
+ writeVarint32FourBytes(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint32FiveBytes(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32OneByte(int value) {
|
|
|
|
+ buffer.put(pos--, (byte) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32TwoBytes(int value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 2;
|
|
|
|
+ buffer.putShort(pos + 1, (short) (((value & (0x7F << 7)) << 1) | ((value & 0x7F) | 0x80)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32ThreeBytes(int value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 3;
|
|
|
|
+ buffer.putInt(
|
|
|
|
+ pos,
|
|
|
|
+ ((value & (0x7F << 14)) << 10)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 9)
|
|
|
|
+ | ((value & 0x7F) | 0x80) << 8);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FourBytes(int value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 4;
|
|
|
|
+ buffer.putInt(
|
|
|
|
+ pos + 1,
|
|
|
|
+ ((value & (0x7F << 21)) << 3)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
|
|
|
|
+ | ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FiveBytes(int value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ buffer.put(pos--, (byte) (value >>> 28));
|
|
|
|
+ pos -= 4;
|
|
|
|
+ buffer.putInt(
|
|
|
|
+ pos + 1,
|
|
|
|
+ ((((value >>> 21) & 0x7F) | 0x80) << 24)
|
|
|
|
+ | ((((value >>> 14) & 0x7F) | 0x80) << 16)
|
|
|
|
+ | ((((value >>> 7) & 0x7F) | 0x80) << 8)
|
|
|
|
+ | ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint64(long value) {
|
|
|
|
+ switch (computeUInt64SizeNoTag(value)) {
|
|
|
|
+ case 1:
|
|
|
|
+ writeVarint64OneByte(value);
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ writeVarint64TwoBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ writeVarint64ThreeBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 4:
|
|
|
|
+ writeVarint64FourBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 5:
|
|
|
|
+ writeVarint64FiveBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 6:
|
|
|
|
+ writeVarint64SixBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 7:
|
|
|
|
+ writeVarint64SevenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 8:
|
|
|
|
+ writeVarint64EightBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 9:
|
|
|
|
+ writeVarint64NineBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 10:
|
|
|
|
+ writeVarint64TenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64OneByte(long value) {
|
|
|
|
+ writeVarint32OneByte((int) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TwoBytes(long value) {
|
|
|
|
+ writeVarint32TwoBytes((int) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64ThreeBytes(long value) {
|
|
|
|
+ writeVarint32ThreeBytes((int) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FourBytes(long value) {
|
|
|
|
+ writeVarint32FourBytes((int) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FiveBytes(long value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 5;
|
|
|
|
+ buffer.putLong(
|
|
|
|
+ pos - 2,
|
|
|
|
+ ((value & (0x7FL << 28)) << 28)
|
|
|
|
+ | (((value & (0x7F << 21)) | (0x80 << 21)) << 27)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 26)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 25)
|
|
|
|
+ | (((value & 0x7F) | 0x80)) << 24);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SixBytes(long value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 6;
|
|
|
|
+ buffer.putLong(
|
|
|
|
+ pos - 1,
|
|
|
|
+ ((value & (0x7FL << 35)) << 21)
|
|
|
|
+ | (((value & (0x7FL << 28)) | (0x80L << 28)) << 20)
|
|
|
|
+ | (((value & (0x7F << 21)) | (0x80 << 21)) << 19)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 18)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 17)
|
|
|
|
+ | (((value & 0x7F) | 0x80)) << 16);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SevenBytes(long value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 7;
|
|
|
|
+ buffer.putLong(
|
|
|
|
+ pos,
|
|
|
|
+ ((value & (0x7FL << 42)) << 14)
|
|
|
|
+ | (((value & (0x7FL << 35)) | (0x80L << 35)) << 13)
|
|
|
|
+ | (((value & (0x7FL << 28)) | (0x80L << 28)) << 12)
|
|
|
|
+ | (((value & (0x7F << 21)) | (0x80 << 21)) << 11)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 10)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 9)
|
|
|
|
+ | (((value & 0x7F) | 0x80)) << 8);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64EightBytes(long value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 8;
|
|
|
|
+ buffer.putLong(
|
|
|
|
+ pos + 1,
|
|
|
|
+ ((value & (0x7FL << 49)) << 7)
|
|
|
|
+ | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6)
|
|
|
|
+ | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5)
|
|
|
|
+ | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4)
|
|
|
|
+ | (((value & (0x7F << 21)) | (0x80 << 21)) << 3)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
|
|
|
|
+ | ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64EightBytesWithSign(long value) {
|
|
|
|
+ // Byte order is little-endian.
|
|
|
|
+ pos -= 8;
|
|
|
|
+ buffer.putLong(
|
|
|
|
+ pos + 1,
|
|
|
|
+ (((value & (0x7FL << 49)) | (0x80L << 49)) << 7)
|
|
|
|
+ | (((value & (0x7FL << 42)) | (0x80L << 42)) << 6)
|
|
|
|
+ | (((value & (0x7FL << 35)) | (0x80L << 35)) << 5)
|
|
|
|
+ | (((value & (0x7FL << 28)) | (0x80L << 28)) << 4)
|
|
|
|
+ | (((value & (0x7F << 21)) | (0x80 << 21)) << 3)
|
|
|
|
+ | (((value & (0x7F << 14)) | (0x80 << 14)) << 2)
|
|
|
|
+ | (((value & (0x7F << 7)) | (0x80 << 7)) << 1)
|
|
|
|
+ | ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64NineBytes(long value) {
|
|
|
|
+ buffer.put(pos--, (byte) (value >>> 56));
|
|
|
|
+ writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TenBytes(long value) {
|
|
|
|
+ buffer.put(pos--, (byte) (value >>> 63));
|
|
|
|
+ buffer.put(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
|
|
|
|
+ writeVarint64EightBytesWithSign(value & 0xFFFFFFFFFFFFFFL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed32(int value) {
|
|
|
|
+ pos -= 4;
|
|
|
|
+ buffer.putInt(pos + 1, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed64(long value) {
|
|
|
|
+ pos -= 8;
|
|
|
|
+ buffer.putLong(pos + 1, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeString(String in) {
|
|
|
|
+ // Request enough space to write the ASCII string.
|
|
|
|
+ requireSpace(in.length());
|
|
|
|
+
|
|
|
|
+ // We know the buffer is big enough...
|
|
|
|
+ int i = in.length() - 1;
|
|
|
|
+ pos -= i;
|
|
|
|
+ // Designed to take advantage of
|
|
|
|
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
|
|
|
+ for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
|
|
|
|
+ buffer.put(pos + i, (byte) c);
|
|
|
|
+ }
|
|
|
|
+ if (i == -1) {
|
|
|
|
+ // Move the position past the ASCII string.
|
|
|
|
+ pos -= 1;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ pos += i;
|
|
|
|
+ for (char c; i >= 0; i--) {
|
|
|
|
+ c = in.charAt(i);
|
|
|
|
+ if (c < 0x80 && pos >= 0) {
|
|
|
|
+ buffer.put(pos--, (byte) c);
|
|
|
|
+ } else if (c < 0x800 && pos > 0) { // 11 bits, two UTF-8 bytes
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ buffer.put(pos--, (byte) ((0xF << 6) | (c >>> 6)));
|
|
|
|
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && pos > 1) {
|
|
|
|
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
|
|
|
|
+ buffer.put(pos--, (byte) ((0xF << 5) | (c >>> 12)));
|
|
|
|
+ } else if (pos > 2) {
|
|
|
|
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
|
|
|
+ // four UTF-8 bytes
|
|
|
|
+ char high = 0;
|
|
|
|
+ if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
|
|
|
|
+ throw new Utf8.UnpairedSurrogateException(i - 1, i);
|
|
|
|
+ }
|
|
|
|
+ i--;
|
|
|
|
+ int codePoint = Character.toCodePoint(high, c);
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & codePoint)));
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
|
|
|
|
+ buffer.put(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
|
|
|
|
+ buffer.put(pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
|
|
|
|
+ } else {
|
|
|
|
+ // Buffer is full - allocate a new one and revisit the current character.
|
|
|
|
+ requireSpace(i);
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte value) {
|
|
|
|
+ buffer.put(pos--, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(pos + 1);
|
|
|
|
+ buffer.put(value, offset, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(pos + 1);
|
|
|
|
+ buffer.put(value, offset, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(pos + 1);
|
|
|
|
+ buffer.put(value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(pos + 1);
|
|
|
|
+ buffer.put(value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void requireSpace(int size) {
|
|
|
|
+ if (spaceLeft() < size) {
|
|
|
|
+ nextBuffer(size);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Writer that uses unsafe operations on a target {@link ByteBuffer}. */
|
|
|
|
+ private static final class UnsafeDirectWriter extends BinaryWriter {
|
|
|
|
+ private ByteBuffer buffer;
|
|
|
|
+ private long bufferOffset;
|
|
|
|
+ private long limitMinusOne;
|
|
|
|
+ private long pos;
|
|
|
|
+
|
|
|
|
+ UnsafeDirectWriter(BufferAllocator alloc, int chunkSize) {
|
|
|
|
+ super(alloc, chunkSize);
|
|
|
|
+ nextBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Indicates whether the required unsafe operations are supported on this platform. */
|
|
|
|
+ private static boolean isSupported() {
|
|
|
|
+ return UnsafeUtil.hasUnsafeByteBufferOperations();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer() {
|
|
|
|
+ nextBuffer(newDirectBuffer());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(int capacity) {
|
|
|
|
+ nextBuffer(newDirectBuffer(capacity));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void nextBuffer(AllocatedBuffer allocatedBuffer) {
|
|
|
|
+ if (!allocatedBuffer.hasNioBuffer()) {
|
|
|
|
+ throw new RuntimeException("Allocated buffer does not have NIO buffer");
|
|
|
|
+ }
|
|
|
|
+ ByteBuffer nioBuffer = allocatedBuffer.nioBuffer();
|
|
|
|
+ if (!nioBuffer.isDirect()) {
|
|
|
|
+ throw new RuntimeException("Allocator returned non-direct buffer");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finishCurrentBuffer();
|
|
|
|
+ buffers.addFirst(allocatedBuffer);
|
|
|
|
+
|
|
|
|
+ buffer = nioBuffer;
|
|
|
|
+ buffer.limit(buffer.capacity());
|
|
|
|
+ buffer.position(0);
|
|
|
|
+
|
|
|
|
+ bufferOffset = UnsafeUtil.addressOffset(buffer);
|
|
|
|
+ limitMinusOne = bufferOffset + (buffer.limit() - 1);
|
|
|
|
+ pos = limitMinusOne;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getTotalBytesWritten() {
|
|
|
|
+ return totalDoneBytes + bytesWrittenToCurrentBuffer();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int bytesWrittenToCurrentBuffer() {
|
|
|
|
+ return (int) (limitMinusOne - pos);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int spaceLeft() {
|
|
|
|
+ return bufferPos() + 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void finishCurrentBuffer() {
|
|
|
|
+ if (buffer != null) {
|
|
|
|
+ totalDoneBytes += bytesWrittenToCurrentBuffer();
|
|
|
|
+ // Update the indices on the netty buffer.
|
|
|
|
+ buffer.position(bufferPos() + 1);
|
|
|
|
+ buffer = null;
|
|
|
|
+ pos = 0;
|
|
|
|
+ limitMinusOne = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int bufferPos() {
|
|
|
|
+ return (int) (pos - bufferOffset);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeSInt32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed32(int fieldNumber, int value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED32_SIZE);
|
|
|
|
+ writeFixed32(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED32);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeUInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeSInt64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + MAX_VARINT64_SIZE);
|
|
|
|
+ writeSInt64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeFixed64(int fieldNumber, long value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + FIXED64_SIZE);
|
|
|
|
+ writeFixed64(value);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_FIXED64);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBool(int fieldNumber, boolean value) {
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE + 1);
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_VARINT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeString(int fieldNumber, String value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ writeString(value);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(2 * MAX_VARINT32_SIZE);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeBytes(int fieldNumber, ByteString value) {
|
|
|
|
+ try {
|
|
|
|
+ value.writeToReverse(this);
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ // Should never happen since the writer does not throw.
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(value.size());
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeMessage(int fieldNumber, Object value) {
|
|
|
|
+ int prevBytes = getTotalBytesWritten();
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ int length = getTotalBytesWritten() - prevBytes;
|
|
|
|
+ requireSpace(MAX_VARINT32_SIZE * 2);
|
|
|
|
+ writeVarint32(length);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeGroup(int fieldNumber, Object value) {
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_END_GROUP);
|
|
|
|
+ Protobuf.getInstance().writeTo(value, this);
|
|
|
|
+ writeTag(fieldNumber, WIRETYPE_START_GROUP);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeInt32(int value) {
|
|
|
|
+ if (value >= 0) {
|
|
|
|
+ writeVarint32(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint64(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt32(int value) {
|
|
|
|
+ writeVarint32(encodeZigZag32(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeSInt64(long value) {
|
|
|
|
+ writeVarint64(encodeZigZag64(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeBool(boolean value) {
|
|
|
|
+ write((byte) (value ? 1 : 0));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeTag(int fieldNumber, byte wireType) {
|
|
|
|
+ writeVarint32(tagFor(fieldNumber, wireType));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint32(int value) {
|
|
|
|
+ if ((value & (~0 << 7)) == 0) {
|
|
|
|
+ writeVarint32OneByte(value);
|
|
|
|
+ } else if ((value & (~0 << 14)) == 0) {
|
|
|
|
+ writeVarint32TwoBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 21)) == 0) {
|
|
|
|
+ writeVarint32ThreeBytes(value);
|
|
|
|
+ } else if ((value & (~0 << 28)) == 0) {
|
|
|
|
+ writeVarint32FourBytes(value);
|
|
|
|
+ } else {
|
|
|
|
+ writeVarint32FiveBytes(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32OneByte(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32TwoBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 7));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32ThreeBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 14));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FourBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 21));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint32FiveBytes(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 28));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeVarint64(long value) {
|
|
|
|
+ switch (computeUInt64SizeNoTag(value)) {
|
|
|
|
+ case 1:
|
|
|
|
+ writeVarint64OneByte(value);
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ writeVarint64TwoBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 3:
|
|
|
|
+ writeVarint64ThreeBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 4:
|
|
|
|
+ writeVarint64FourBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 5:
|
|
|
|
+ writeVarint64FiveBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 6:
|
|
|
|
+ writeVarint64SixBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 7:
|
|
|
|
+ writeVarint64SevenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 8:
|
|
|
|
+ writeVarint64EightBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 9:
|
|
|
|
+ writeVarint64NineBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ case 10:
|
|
|
|
+ writeVarint64TenBytes(value);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64OneByte(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TwoBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 7));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((int) value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64ThreeBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((int) value) >>> 14));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FourBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 21));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64FiveBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 28));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SixBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 35));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64SevenBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 42));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64EightBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 49));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64NineBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 56));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeVarint64TenBytes(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value >>> 63));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 56) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 49) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 42) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 35) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 28) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 21) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 14) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (((value >>> 7) & 0x7F) | 0x80));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value & 0x7F) | 0x80));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed32(int value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value >> 24) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value >> 16) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((value >> 8) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (value & 0xFF));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeFixed64(long value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 56) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 48) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 40) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 32) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 24) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 16) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value >> 8) & 0xFF));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((int) (value) & 0xFF));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void writeString(String in) {
|
|
|
|
+ // Request enough space to write the ASCII string.
|
|
|
|
+ requireSpace(in.length());
|
|
|
|
+
|
|
|
|
+ // We know the buffer is big enough...
|
|
|
|
+ int i = in.length() - 1;
|
|
|
|
+ // Designed to take advantage of
|
|
|
|
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
|
|
|
|
+ for (char c; i >= 0 && (c = in.charAt(i)) < 0x80; i--) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) c);
|
|
|
|
+ }
|
|
|
|
+ if (i == -1) {
|
|
|
|
+ // ASCII.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (char c; i >= 0; i--) {
|
|
|
|
+ c = in.charAt(i);
|
|
|
|
+ if (c < 0x80 && pos >= bufferOffset) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) c);
|
|
|
|
+ } else if (c < 0x800 && pos > bufferOffset) { // 11 bits, two UTF-8 bytes
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((0xF << 6) | (c >>> 6)));
|
|
|
|
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c)
|
|
|
|
+ && pos > bufferOffset + 1) {
|
|
|
|
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & c)));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (c >>> 6))));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((0xF << 5) | (c >>> 12)));
|
|
|
|
+ } else if (pos > bufferOffset + 2) {
|
|
|
|
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
|
|
|
|
+ // four UTF-8 bytes
|
|
|
|
+ final char high;
|
|
|
|
+ if (i == 0 || !Character.isSurrogatePair(high = in.charAt(i - 1), c)) {
|
|
|
|
+ throw new Utf8.UnpairedSurrogateException(i - 1, i);
|
|
|
|
+ }
|
|
|
|
+ i--;
|
|
|
|
+ int codePoint = Character.toCodePoint(high, c);
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & codePoint)));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
|
|
|
|
+ UnsafeUtil.putByte(pos--, (byte) ((0xF << 4) | (codePoint >>> 18)));
|
|
|
|
+ } else {
|
|
|
|
+ // Buffer is full - allocate a new one and revisit the current character.
|
|
|
|
+ requireSpace(i);
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte value) {
|
|
|
|
+ UnsafeUtil.putByte(pos--, value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(bufferPos() + 1);
|
|
|
|
+ buffer.put(value, offset, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(byte[] value, int offset, int length) {
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value, offset, length));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ buffer.position(bufferPos() + 1);
|
|
|
|
+ buffer.put(value, offset, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void write(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ nextBuffer(length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ long sourceOffset = UnsafeUtil.addressOffset(value);
|
|
|
|
+ long sourcePos = sourceOffset + value.position();
|
|
|
|
+ UnsafeUtil.copyMemory(sourcePos, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeLazy(ByteBuffer value) {
|
|
|
|
+ int length = value.remaining();
|
|
|
|
+ if (spaceLeft() < length) {
|
|
|
|
+ // We consider the value to be immutable (likely the internals of a ByteString). Just
|
|
|
|
+ // wrap it in a Netty buffer and add it to the output buffer.
|
|
|
|
+ totalDoneBytes += length;
|
|
|
|
+ buffers.addFirst(AllocatedBuffer.wrap(value));
|
|
|
|
+
|
|
|
|
+ // Advance the writer to the next buffer.
|
|
|
|
+ // TODO(nathanmittler): Consider slicing if space available above some threshold.
|
|
|
|
+ nextBuffer();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos -= length;
|
|
|
|
+ long sourceOffset = UnsafeUtil.addressOffset(value);
|
|
|
|
+ long sourcePos = sourceOffset + value.position();
|
|
|
|
+ UnsafeUtil.copyMemory(sourcePos, pos + 1, length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void requireSpace(int size) {
|
|
|
|
+ if (spaceLeft() < size) {
|
|
|
|
+ nextBuffer(size);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|