com.google.protobuf.MessageSchema Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of protobuf-javalite Show documentation
Show all versions of protobuf-javalite Show documentation
Lite version of Protocol Buffers library. This version is optimized for code size, but does
not guarantee API/ABI stability.
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
package com.google.protobuf;
import static com.google.protobuf.ArrayDecoders.decodeBoolList;
import static com.google.protobuf.ArrayDecoders.decodeBytes;
import static com.google.protobuf.ArrayDecoders.decodeBytesList;
import static com.google.protobuf.ArrayDecoders.decodeDouble;
import static com.google.protobuf.ArrayDecoders.decodeDoubleList;
import static com.google.protobuf.ArrayDecoders.decodeExtensionOrUnknownField;
import static com.google.protobuf.ArrayDecoders.decodeFixed32;
import static com.google.protobuf.ArrayDecoders.decodeFixed32List;
import static com.google.protobuf.ArrayDecoders.decodeFixed64;
import static com.google.protobuf.ArrayDecoders.decodeFixed64List;
import static com.google.protobuf.ArrayDecoders.decodeFloat;
import static com.google.protobuf.ArrayDecoders.decodeFloatList;
import static com.google.protobuf.ArrayDecoders.decodeGroupList;
import static com.google.protobuf.ArrayDecoders.decodeMessageField;
import static com.google.protobuf.ArrayDecoders.decodeMessageList;
import static com.google.protobuf.ArrayDecoders.decodePackedBoolList;
import static com.google.protobuf.ArrayDecoders.decodePackedDoubleList;
import static com.google.protobuf.ArrayDecoders.decodePackedFixed32List;
import static com.google.protobuf.ArrayDecoders.decodePackedFixed64List;
import static com.google.protobuf.ArrayDecoders.decodePackedFloatList;
import static com.google.protobuf.ArrayDecoders.decodePackedSInt32List;
import static com.google.protobuf.ArrayDecoders.decodePackedSInt64List;
import static com.google.protobuf.ArrayDecoders.decodePackedVarint32List;
import static com.google.protobuf.ArrayDecoders.decodePackedVarint64List;
import static com.google.protobuf.ArrayDecoders.decodeSInt32List;
import static com.google.protobuf.ArrayDecoders.decodeSInt64List;
import static com.google.protobuf.ArrayDecoders.decodeString;
import static com.google.protobuf.ArrayDecoders.decodeStringList;
import static com.google.protobuf.ArrayDecoders.decodeStringListRequireUtf8;
import static com.google.protobuf.ArrayDecoders.decodeStringRequireUtf8;
import static com.google.protobuf.ArrayDecoders.decodeUnknownField;
import static com.google.protobuf.ArrayDecoders.decodeVarint32;
import static com.google.protobuf.ArrayDecoders.decodeVarint32List;
import static com.google.protobuf.ArrayDecoders.decodeVarint64;
import static com.google.protobuf.ArrayDecoders.decodeVarint64List;
import static com.google.protobuf.ArrayDecoders.mergeGroupField;
import static com.google.protobuf.ArrayDecoders.mergeMessageField;
import static com.google.protobuf.ArrayDecoders.skipField;
import com.google.protobuf.ArrayDecoders.Registers;
import com.google.protobuf.ByteString.CodedBuilder;
import com.google.protobuf.FieldSet.FieldDescriptorLite;
import com.google.protobuf.Internal.EnumVerifier;
import com.google.protobuf.Internal.ProtobufList;
import com.google.protobuf.MapEntryLite.Metadata;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/** Schema used for standard messages. */
@CheckReturnValue
final class MessageSchema implements Schema {
private static final int INTS_PER_FIELD = 3;
private static final int OFFSET_BITS = 20;
private static final int OFFSET_MASK = 0XFFFFF;
private static final int FIELD_TYPE_MASK = 0x0FF00000;
private static final int REQUIRED_MASK = 0x10000000;
private static final int ENFORCE_UTF8_MASK = 0x20000000;
private static final int LEGACY_ENUM_IS_CLOSED_MASK = 0x80000000;
private static final int NO_PRESENCE_SENTINEL = -1 & OFFSET_MASK;
private static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* Bit masks for field type extra feature bits encoded in Java gencode via
* GetExperimentalJavaFieldType in helpers.cc.
*/
private static final int REQUIRED_BIT = 0x100;
private static final int UTF8_CHECK_BIT = 0x200;
private static final int CHECK_INITIALIZED_BIT = 0x400;
private static final int LEGACY_ENUM_IS_CLOSED_BIT = 0x800;
private static final int HAS_HAS_BIT = 0x1000;
/** An offset applied to the field type ID for scalar fields that are a member of a oneof. */
static final int ONEOF_TYPE_OFFSET = 51 /* FieldType.MAP + 1 */;
/**
* Keep a direct reference to the unsafe object so we don't need to go through the UnsafeUtil
* wrapper for every call.
*/
private static final sun.misc.Unsafe UNSAFE = UnsafeUtil.getUnsafe();
/**
* Holds all information for accessing the message fields. The layout is as follows (field
* positions are relative to the offset of the start of the field in the buffer):
*
*
*
*
* buffer[i]
* [ 0 - 3] unused
* [ 4 - 31] field number
*
* buffer[i+1]
* [32 - 33] unused
* [34 - 34] whether UTF-8 enforcement should be applied to a string field.
* [35 - 35] whether the field is required
* [36 - 43] field type / for oneof: field type + {@link #ONEOF_TYPE_OFFSET}
* [44 - 63] field offset / oneof value field offset
*
* buffer[i+2]
* [64 - 69] unused
* [70 - 75] field presence mask shift (unused for oneof/repeated fields)
* [76 - 95] presence field offset / oneof case field offset / cached size field offset
*
*
* Offset refer to the field offsets returned by Unsafe.objectFieldOffset() for reflective access
* to corresponding field.
*
* Note that presence field offset can only use 20 bits - 1. All bits set to 1 is the sentinel
* value for non-presence. This is not validated at runtime, we simply assume message layouts will
* not exceed 1MB (assuming ~10 bytes per field, that implies 100k fields which should hit other
* javac limits first). This corresponds to a shared bitFieldN_, which must have the field
* presence mask shift applied to get the corresponding field's presence.
*/
private final int[] buffer;
/**
* Holds object references for fields. For each field entry in {@code buffer}, there are two
* corresponding entries in this array. The content is different from different field types:
*
*
* Map fields:
* objects[pos] = map default entry instance
* objects[pos + 1] = EnumVerifier if map value is enum, or message class reference if map
* value is message.
* Message fields:
* objects[pos] = null or cached message schema
* objects[pos + 1] = message class reference
* Enum fields:
* objects[pos] = null
* objects[pos + 1] = EnumVerifier
*
*/
private final Object[] objects;
private final int minFieldNumber;
private final int maxFieldNumber;
private final MessageLite defaultInstance;
private final boolean hasExtensions;
private final boolean lite;
private final ProtoSyntax syntax;
// TODO: Make both full-runtime and lite-runtime support cached field size.
private final boolean useCachedSizeField;
/** Represents [checkInitialized positions, map field positions, repeated field offsets]. */
private final int[] intArray;
/**
* Values at indices 0 -> checkInitializedCount in intArray are positions to check for
* initialization.
*/
private final int checkInitializedCount;
/**
* Values at indices checkInitializedCount -> repeatedFieldOffsetStart are map positions.
* Everything after that are repeated field offsets.
*/
private final int repeatedFieldOffsetStart;
private final NewInstanceSchema newInstanceSchema;
private final ListFieldSchema listFieldSchema;
private final UnknownFieldSchema, ?> unknownFieldSchema;
private final ExtensionSchema> extensionSchema;
private final MapFieldSchema mapFieldSchema;
private MessageSchema(
int[] buffer,
Object[] objects,
int minFieldNumber,
int maxFieldNumber,
MessageLite defaultInstance,
ProtoSyntax syntax,
boolean useCachedSizeField,
int[] intArray,
int checkInitialized,
int mapFieldPositions,
NewInstanceSchema newInstanceSchema,
ListFieldSchema listFieldSchema,
UnknownFieldSchema, ?> unknownFieldSchema,
ExtensionSchema> extensionSchema,
MapFieldSchema mapFieldSchema) {
this.buffer = buffer;
this.objects = objects;
this.minFieldNumber = minFieldNumber;
this.maxFieldNumber = maxFieldNumber;
this.lite = defaultInstance instanceof GeneratedMessageLite;
this.syntax = syntax;
this.hasExtensions = extensionSchema != null && extensionSchema.hasExtensions(defaultInstance);
this.useCachedSizeField = useCachedSizeField;
this.intArray = intArray;
this.checkInitializedCount = checkInitialized;
this.repeatedFieldOffsetStart = mapFieldPositions;
this.newInstanceSchema = newInstanceSchema;
this.listFieldSchema = listFieldSchema;
this.unknownFieldSchema = unknownFieldSchema;
this.extensionSchema = extensionSchema;
this.defaultInstance = defaultInstance;
this.mapFieldSchema = mapFieldSchema;
}
static MessageSchema newSchema(
Class messageClass,
MessageInfo messageInfo,
NewInstanceSchema newInstanceSchema,
ListFieldSchema listFieldSchema,
UnknownFieldSchema, ?> unknownFieldSchema,
ExtensionSchema> extensionSchema,
MapFieldSchema mapFieldSchema) {
if (messageInfo instanceof RawMessageInfo) {
return newSchemaForRawMessageInfo(
(RawMessageInfo) messageInfo,
newInstanceSchema,
listFieldSchema,
unknownFieldSchema,
extensionSchema,
mapFieldSchema);
} else {
return newSchemaForMessageInfo(
(StructuralMessageInfo) messageInfo,
newInstanceSchema,
listFieldSchema,
unknownFieldSchema,
extensionSchema,
mapFieldSchema);
}
}
static MessageSchema newSchemaForRawMessageInfo(
RawMessageInfo messageInfo,
NewInstanceSchema newInstanceSchema,
ListFieldSchema listFieldSchema,
UnknownFieldSchema, ?> unknownFieldSchema,
ExtensionSchema> extensionSchema,
MapFieldSchema mapFieldSchema) {
String info = messageInfo.getStringInfo();
final int length = info.length();
int i = 0;
int next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
final int unusedFlags = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
final int fieldCount = next;
final int oneofCount;
final int hasBitsCount;
final int minFieldNumber;
final int maxFieldNumber;
final int numEntries;
final int mapFieldCount;
final int repeatedFieldCount;
final int checkInitialized;
final int[] intArray;
int objectsPosition;
if (fieldCount == 0) {
oneofCount = 0;
hasBitsCount = 0;
minFieldNumber = 0;
maxFieldNumber = 0;
numEntries = 0;
mapFieldCount = 0;
repeatedFieldCount = 0;
checkInitialized = 0;
intArray = EMPTY_INT_ARRAY;
objectsPosition = 0;
} else {
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
oneofCount = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
hasBitsCount = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
minFieldNumber = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
maxFieldNumber = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
numEntries = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
mapFieldCount = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
repeatedFieldCount = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
checkInitialized = next;
intArray = new int[checkInitialized + mapFieldCount + repeatedFieldCount];
// Field objects are after a list of (oneof, oneofCase) pairs + a list of hasbits fields.
objectsPosition = oneofCount * 2 + hasBitsCount;
}
final sun.misc.Unsafe unsafe = UNSAFE;
final Object[] messageInfoObjects = messageInfo.getObjects();
int checkInitializedPosition = 0;
final Class> messageClass = messageInfo.getDefaultInstance().getClass();
int[] buffer = new int[numEntries * INTS_PER_FIELD];
Object[] objects = new Object[numEntries * 2];
int mapFieldIndex = checkInitialized;
int repeatedFieldIndex = checkInitialized + mapFieldCount;
int bufferIndex = 0;
while (i < length) {
final int fieldNumber;
final int fieldTypeWithExtraBits;
final int fieldType;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
fieldNumber = next;
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
fieldTypeWithExtraBits = next;
fieldType = fieldTypeWithExtraBits & 0xFF;
if ((fieldTypeWithExtraBits & CHECK_INITIALIZED_BIT) != 0) {
intArray[checkInitializedPosition++] = bufferIndex;
}
final int fieldOffset;
final int presenceMaskShift;
final int presenceFieldOffset;
// Oneof
if (fieldType >= ONEOF_TYPE_OFFSET) {
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
int oneofIndex = next;
final int oneofFieldType = fieldType - ONEOF_TYPE_OFFSET;
if (oneofFieldType == 9 /* FieldType.MESSAGE */
|| oneofFieldType == 17 /* FieldType.GROUP */) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++];
} else if (oneofFieldType == 12 /* FieldType.ENUM */) {
// TODO: Remove proto2 check once legacy gencode not setting this bit
// no longer needs to be supported.
if (messageInfo.getSyntax().equals(ProtoSyntax.PROTO2)
|| (fieldTypeWithExtraBits & LEGACY_ENUM_IS_CLOSED_BIT) != 0) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++];
}
}
final java.lang.reflect.Field oneofField;
int index = oneofIndex * 2;
Object o = messageInfoObjects[index];
if (o instanceof java.lang.reflect.Field) {
oneofField = (java.lang.reflect.Field) o;
} else {
oneofField = reflectField(messageClass, (String) o);
// Memoize java.lang.reflect.Field instances for oneof/hasbits fields, since they're
// potentially used for many Protobuf fields. Since there's a 1-1 mapping from the
// Protobuf field to the Java Field for non-oneofs, there's no benefit for memoizing
// those.
messageInfoObjects[index] = oneofField;
}
fieldOffset = (int) unsafe.objectFieldOffset(oneofField);
final java.lang.reflect.Field oneofCaseField;
index++;
o = messageInfoObjects[index];
if (o instanceof java.lang.reflect.Field) {
oneofCaseField = (java.lang.reflect.Field) o;
} else {
oneofCaseField = reflectField(messageClass, (String) o);
messageInfoObjects[index] = oneofCaseField;
}
presenceFieldOffset = (int) unsafe.objectFieldOffset(oneofCaseField);
presenceMaskShift = 0;
} else {
Field field = reflectField(messageClass, (String) messageInfoObjects[objectsPosition++]);
if (fieldType == 9 /* FieldType.MESSAGE */ || fieldType == 17 /* FieldType.GROUP */) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = field.getType();
} else if (fieldType == 27 /* FieldType.MESSAGE_LIST */
|| fieldType == 49 /* FieldType.GROUP_LIST */) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++];
} else if (fieldType == 12 /* FieldType.ENUM */
|| fieldType == 30 /* FieldType.ENUM_LIST */
|| fieldType == 44 /* FieldType.ENUM_LIST_PACKED */) {
// TODO: Remove proto2 check once legacy gencode not setting this bit
// no longer needs to be supported.
if (messageInfo.getSyntax() == ProtoSyntax.PROTO2
|| (fieldTypeWithExtraBits & LEGACY_ENUM_IS_CLOSED_BIT) != 0) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++];
}
} else if (fieldType == 50 /* FieldType.MAP */) {
intArray[mapFieldIndex++] = bufferIndex;
objects[bufferIndex / INTS_PER_FIELD * 2] = messageInfoObjects[objectsPosition++];
if ((fieldTypeWithExtraBits & LEGACY_ENUM_IS_CLOSED_BIT) != 0) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageInfoObjects[objectsPosition++];
}
}
fieldOffset = (int) unsafe.objectFieldOffset(field);
boolean hasHasBit = (fieldTypeWithExtraBits & HAS_HAS_BIT) != 0;
if (hasHasBit && fieldType <= 17 /* FieldType.GROUP */) {
next = info.charAt(i++);
if (next >= 0xD800) {
int result = next & 0x1FFF;
int shift = 13;
while ((next = info.charAt(i++)) >= 0xD800) {
result |= (next & 0x1FFF) << shift;
shift += 13;
}
next = result | (next << shift);
}
int hasBitsIndex = next;
final java.lang.reflect.Field hasBitsField;
int index = oneofCount * 2 + hasBitsIndex / 32;
Object o = messageInfoObjects[index];
if (o instanceof java.lang.reflect.Field) {
hasBitsField = (java.lang.reflect.Field) o;
} else {
hasBitsField = reflectField(messageClass, (String) o);
messageInfoObjects[index] = hasBitsField;
}
presenceFieldOffset = (int) unsafe.objectFieldOffset(hasBitsField);
presenceMaskShift = hasBitsIndex % 32;
} else {
presenceFieldOffset = NO_PRESENCE_SENTINEL;
presenceMaskShift = 0;
}
if (fieldType >= 18 && fieldType <= 49) {
// Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to
// 49 (GROUP_LIST).
intArray[repeatedFieldIndex++] = fieldOffset;
}
}
buffer[bufferIndex++] = fieldNumber;
buffer[bufferIndex++] =
((fieldTypeWithExtraBits & UTF8_CHECK_BIT) != 0 ? ENFORCE_UTF8_MASK : 0)
| ((fieldTypeWithExtraBits & REQUIRED_BIT) != 0 ? REQUIRED_MASK : 0)
| ((fieldTypeWithExtraBits & LEGACY_ENUM_IS_CLOSED_BIT) != 0
? LEGACY_ENUM_IS_CLOSED_MASK
: 0)
| (fieldType << OFFSET_BITS)
| fieldOffset;
buffer[bufferIndex++] = (presenceMaskShift << OFFSET_BITS) | presenceFieldOffset;
}
return new MessageSchema(
buffer,
objects,
minFieldNumber,
maxFieldNumber,
messageInfo.getDefaultInstance(),
messageInfo.getSyntax(),
/* useCachedSizeField= */ false,
intArray,
checkInitialized,
checkInitialized + mapFieldCount,
newInstanceSchema,
listFieldSchema,
unknownFieldSchema,
extensionSchema,
mapFieldSchema);
}
private static java.lang.reflect.Field reflectField(Class> messageClass, String fieldName) {
try {
return messageClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
// Some Samsung devices lie about what fields are present via the getDeclaredField API so
// we do the for loop properly that they seem to have messed up...
java.lang.reflect.Field[] fields = messageClass.getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
if (fieldName.equals(field.getName())) {
return field;
}
}
// If we make it here, the runtime still lies about what we know to be true at compile
// time. We throw to alert server monitoring for further remediation.
throw new RuntimeException(
"Field "
+ fieldName
+ " for "
+ messageClass.getName()
+ " not found. Known fields are "
+ Arrays.toString(fields));
}
}
static MessageSchema newSchemaForMessageInfo(
StructuralMessageInfo messageInfo,
NewInstanceSchema newInstanceSchema,
ListFieldSchema listFieldSchema,
UnknownFieldSchema, ?> unknownFieldSchema,
ExtensionSchema> extensionSchema,
MapFieldSchema mapFieldSchema) {
FieldInfo[] fis = messageInfo.getFields();
final int minFieldNumber;
final int maxFieldNumber;
if (fis.length == 0) {
minFieldNumber = 0;
maxFieldNumber = 0;
} else {
minFieldNumber = fis[0].getFieldNumber();
maxFieldNumber = fis[fis.length - 1].getFieldNumber();
}
final int numEntries = fis.length;
int[] buffer = new int[numEntries * INTS_PER_FIELD];
Object[] objects = new Object[numEntries * 2];
int mapFieldCount = 0;
int repeatedFieldCount = 0;
for (FieldInfo fi : fis) {
if (fi.getType() == FieldType.MAP) {
mapFieldCount++;
} else if (fi.getType().id() >= 18 && fi.getType().id() <= 49) {
// Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to
// 49 (GROUP_LIST).
repeatedFieldCount++;
}
}
int[] mapFieldPositions = mapFieldCount > 0 ? new int[mapFieldCount] : null;
int[] repeatedFieldOffsets = repeatedFieldCount > 0 ? new int[repeatedFieldCount] : null;
mapFieldCount = 0;
repeatedFieldCount = 0;
int[] checkInitialized = messageInfo.getCheckInitialized();
if (checkInitialized == null) {
checkInitialized = EMPTY_INT_ARRAY;
}
int checkInitializedIndex = 0;
// Fill in the manifest data from the descriptors.
int fieldIndex = 0;
for (int bufferIndex = 0; fieldIndex < fis.length; bufferIndex += INTS_PER_FIELD) {
final FieldInfo fi = fis[fieldIndex];
final int fieldNumber = fi.getFieldNumber();
// We found the entry for the next field. Store the entry in the manifest for
// this field and increment the field index.
storeFieldData(fi, buffer, bufferIndex, objects);
// Convert field number to index
if (checkInitializedIndex < checkInitialized.length
&& checkInitialized[checkInitializedIndex] == fieldNumber) {
checkInitialized[checkInitializedIndex++] = bufferIndex;
}
if (fi.getType() == FieldType.MAP) {
mapFieldPositions[mapFieldCount++] = bufferIndex;
} else if (fi.getType().id() >= 18 && fi.getType().id() <= 49) {
// Field types of repeated fields are in a consecutive range from 18 (DOUBLE_LIST) to
// 49 (GROUP_LIST).
repeatedFieldOffsets[repeatedFieldCount++] =
(int) UnsafeUtil.objectFieldOffset(fi.getField());
}
fieldIndex++;
}
if (mapFieldPositions == null) {
mapFieldPositions = EMPTY_INT_ARRAY;
}
if (repeatedFieldOffsets == null) {
repeatedFieldOffsets = EMPTY_INT_ARRAY;
}
int[] combined =
new int[checkInitialized.length + mapFieldPositions.length + repeatedFieldOffsets.length];
System.arraycopy(checkInitialized, 0, combined, 0, checkInitialized.length);
System.arraycopy(
mapFieldPositions, 0, combined, checkInitialized.length, mapFieldPositions.length);
System.arraycopy(
repeatedFieldOffsets,
0,
combined,
checkInitialized.length + mapFieldPositions.length,
repeatedFieldOffsets.length);
return new MessageSchema(
buffer,
objects,
minFieldNumber,
maxFieldNumber,
messageInfo.getDefaultInstance(),
messageInfo.getSyntax(),
/* useCachedSizeField= */ true,
combined,
checkInitialized.length,
checkInitialized.length + mapFieldPositions.length,
newInstanceSchema,
listFieldSchema,
unknownFieldSchema,
extensionSchema,
mapFieldSchema);
}
private static void storeFieldData(
FieldInfo fi, int[] buffer, int bufferIndex, Object[] objects) {
final int fieldOffset;
final int typeId;
final int presenceMaskShift;
final int presenceFieldOffset;
OneofInfo oneof = fi.getOneof();
if (oneof != null) {
typeId = fi.getType().id() + ONEOF_TYPE_OFFSET;
fieldOffset = (int) UnsafeUtil.objectFieldOffset(oneof.getValueField());
presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(oneof.getCaseField());
presenceMaskShift = 0;
} else {
FieldType type = fi.getType();
fieldOffset = (int) UnsafeUtil.objectFieldOffset(fi.getField());
typeId = type.id();
if (!type.isList() && !type.isMap()) {
Field presenceField = fi.getPresenceField();
if (presenceField == null) {
presenceFieldOffset = NO_PRESENCE_SENTINEL;
} else {
presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(presenceField);
}
presenceMaskShift = Integer.numberOfTrailingZeros(fi.getPresenceMask());
} else {
if (fi.getCachedSizeField() == null) {
presenceFieldOffset = 0;
presenceMaskShift = 0;
} else {
presenceFieldOffset = (int) UnsafeUtil.objectFieldOffset(fi.getCachedSizeField());
presenceMaskShift = 0;
}
}
}
buffer[bufferIndex] = fi.getFieldNumber();
buffer[bufferIndex + 1] =
(fi.isEnforceUtf8() ? ENFORCE_UTF8_MASK : 0)
| (fi.isRequired() ? REQUIRED_MASK : 0)
| (typeId << OFFSET_BITS)
| fieldOffset;
buffer[bufferIndex + 2] = (presenceMaskShift << OFFSET_BITS) | presenceFieldOffset;
Object messageFieldClass = fi.getMessageFieldClass();
if (fi.getMapDefaultEntry() != null) {
objects[bufferIndex / INTS_PER_FIELD * 2] = fi.getMapDefaultEntry();
if (messageFieldClass != null) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageFieldClass;
} else if (fi.getEnumVerifier() != null) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = fi.getEnumVerifier();
}
} else {
if (messageFieldClass != null) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = messageFieldClass;
} else if (fi.getEnumVerifier() != null) {
objects[bufferIndex / INTS_PER_FIELD * 2 + 1] = fi.getEnumVerifier();
}
}
}
@SuppressWarnings("unchecked")
@Override
public T newInstance() {
return (T) newInstanceSchema.newInstance(defaultInstance);
}
@Override
public boolean equals(T message, T other) {
final int bufferLength = buffer.length;
for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) {
if (!equals(message, other, pos)) {
return false;
}
}
Object messageUnknown = unknownFieldSchema.getFromMessage(message);
Object otherUnknown = unknownFieldSchema.getFromMessage(other);
if (!messageUnknown.equals(otherUnknown)) {
return false;
}
if (hasExtensions) {
FieldSet> messageExtensions = extensionSchema.getExtensions(message);
FieldSet> otherExtensions = extensionSchema.getExtensions(other);
return messageExtensions.equals(otherExtensions);
}
return true;
}
private boolean equals(T message, T other, int pos) {
final int typeAndOffset = typeAndOffsetAt(pos);
final long offset = offset(typeAndOffset);
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
return arePresentForEquals(message, other, pos)
&& Double.doubleToLongBits(UnsafeUtil.getDouble(message, offset))
== Double.doubleToLongBits(UnsafeUtil.getDouble(other, offset));
case 1: // FLOAT:
return arePresentForEquals(message, other, pos)
&& Float.floatToIntBits(UnsafeUtil.getFloat(message, offset))
== Float.floatToIntBits(UnsafeUtil.getFloat(other, offset));
case 2: // INT64:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset);
case 3: // UINT64:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset);
case 4: // INT32:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 5: // FIXED64:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset);
case 6: // FIXED32:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 7: // BOOL:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getBoolean(message, offset) == UnsafeUtil.getBoolean(other, offset);
case 8: // STRING:
return arePresentForEquals(message, other, pos)
&& SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 9: // MESSAGE:
return arePresentForEquals(message, other, pos)
&& SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 10: // BYTES:
return arePresentForEquals(message, other, pos)
&& SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 11: // UINT32:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 12: // ENUM:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 13: // SFIXED32:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 14: // SFIXED64:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset);
case 15: // SINT32:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getInt(message, offset) == UnsafeUtil.getInt(other, offset);
case 16: // SINT64:
return arePresentForEquals(message, other, pos)
&& UnsafeUtil.getLong(message, offset) == UnsafeUtil.getLong(other, offset);
case 17: // GROUP:
return arePresentForEquals(message, other, pos)
&& SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:
case 21: // UINT64_LIST:
case 22: // INT32_LIST:
case 23: // FIXED64_LIST:
case 24: // FIXED32_LIST:
case 25: // BOOL_LIST:
case 26: // STRING_LIST:
case 27: // MESSAGE_LIST:
case 28: // BYTES_LIST:
case 29: // UINT32_LIST:
case 30: // ENUM_LIST:
case 31: // SFIXED32_LIST:
case 32: // SFIXED64_LIST:
case 33: // SINT32_LIST:
case 34: // SINT64_LIST:
case 35: // DOUBLE_LIST_PACKED:
case 36: // FLOAT_LIST_PACKED:
case 37: // INT64_LIST_PACKED:
case 38: // UINT64_LIST_PACKED:
case 39: // INT32_LIST_PACKED:
case 40: // FIXED64_LIST_PACKED:
case 41: // FIXED32_LIST_PACKED:
case 42: // BOOL_LIST_PACKED:
case 43: // UINT32_LIST_PACKED:
case 44: // ENUM_LIST_PACKED:
case 45: // SFIXED32_LIST_PACKED:
case 46: // SFIXED64_LIST_PACKED:
case 47: // SINT32_LIST_PACKED:
case 48: // SINT64_LIST_PACKED:
case 49: // GROUP_LIST:
return SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 50: // MAP:
return SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
case 51: // ONEOF_DOUBLE:
case 52: // ONEOF_FLOAT:
case 53: // ONEOF_INT64:
case 54: // ONEOF_UINT64:
case 55: // ONEOF_INT32:
case 56: // ONEOF_FIXED64:
case 57: // ONEOF_FIXED32:
case 58: // ONEOF_BOOL:
case 59: // ONEOF_STRING:
case 60: // ONEOF_MESSAGE:
case 61: // ONEOF_BYTES:
case 62: // ONEOF_UINT32:
case 63: // ONEOF_ENUM:
case 64: // ONEOF_SFIXED32:
case 65: // ONEOF_SFIXED64:
case 66: // ONEOF_SINT32:
case 67: // ONEOF_SINT64:
case 68: // ONEOF_GROUP:
return isOneofCaseEqual(message, other, pos)
&& SchemaUtil.safeEquals(
UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(other, offset));
default:
// Assume it's an empty entry - just go to the next entry.
return true;
}
}
@Override
public int hashCode(T message) {
int hashCode = 0;
final int bufferLength = buffer.length;
for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) {
final int typeAndOffset = typeAndOffsetAt(pos);
final int entryNumber = numberAt(pos);
final long offset = offset(typeAndOffset);
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
hashCode =
(hashCode * 53)
+ Internal.hashLong(
Double.doubleToLongBits(UnsafeUtil.getDouble(message, offset)));
break;
case 1: // FLOAT:
hashCode = (hashCode * 53) + Float.floatToIntBits(UnsafeUtil.getFloat(message, offset));
break;
case 2: // INT64:
hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset));
break;
case 3: // UINT64:
hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset));
break;
case 4: // INT32:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 5: // FIXED64:
hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset));
break;
case 6: // FIXED32:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 7: // BOOL:
hashCode = (hashCode * 53) + Internal.hashBoolean(UnsafeUtil.getBoolean(message, offset));
break;
case 8: // STRING:
hashCode = (hashCode * 53) + ((String) UnsafeUtil.getObject(message, offset)).hashCode();
break;
case 9: // MESSAGE:
{
int protoHash = 37;
Object submessage = UnsafeUtil.getObject(message, offset);
if (submessage != null) {
protoHash = submessage.hashCode();
}
hashCode = (53 * hashCode) + protoHash;
break;
}
case 10: // BYTES:
hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode();
break;
case 11: // UINT32:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 12: // ENUM:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 13: // SFIXED32:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 14: // SFIXED64:
hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset));
break;
case 15: // SINT32:
hashCode = (hashCode * 53) + (UnsafeUtil.getInt(message, offset));
break;
case 16: // SINT64:
hashCode = (hashCode * 53) + Internal.hashLong(UnsafeUtil.getLong(message, offset));
break;
case 17: // GROUP:
{
int protoHash = 37;
Object submessage = UnsafeUtil.getObject(message, offset);
if (submessage != null) {
protoHash = submessage.hashCode();
}
hashCode = (53 * hashCode) + protoHash;
break;
}
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:
case 21: // UINT64_LIST:
case 22: // INT32_LIST:
case 23: // FIXED64_LIST:
case 24: // FIXED32_LIST:
case 25: // BOOL_LIST:
case 26: // STRING_LIST:
case 27: // MESSAGE_LIST:
case 28: // BYTES_LIST:
case 29: // UINT32_LIST:
case 30: // ENUM_LIST:
case 31: // SFIXED32_LIST:
case 32: // SFIXED64_LIST:
case 33: // SINT32_LIST:
case 34: // SINT64_LIST:
case 35: // DOUBLE_LIST_PACKED:
case 36: // FLOAT_LIST_PACKED:
case 37: // INT64_LIST_PACKED:
case 38: // UINT64_LIST_PACKED:
case 39: // INT32_LIST_PACKED:
case 40: // FIXED64_LIST_PACKED:
case 41: // FIXED32_LIST_PACKED:
case 42: // BOOL_LIST_PACKED:
case 43: // UINT32_LIST_PACKED:
case 44: // ENUM_LIST_PACKED:
case 45: // SFIXED32_LIST_PACKED:
case 46: // SFIXED64_LIST_PACKED:
case 47: // SINT32_LIST_PACKED:
case 48: // SINT64_LIST_PACKED:
case 49: // GROUP_LIST:
hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode();
break;
case 50: // MAP:
hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode();
break;
case 51: // ONEOF_DOUBLE:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode =
(hashCode * 53)
+ Internal.hashLong(Double.doubleToLongBits(oneofDoubleAt(message, offset)));
}
break;
case 52: // ONEOF_FLOAT:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Float.floatToIntBits(oneofFloatAt(message, offset));
}
break;
case 53: // ONEOF_INT64:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset));
}
break;
case 54: // ONEOF_UINT64:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset));
}
break;
case 55: // ONEOF_INT32:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 56: // ONEOF_FIXED64:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset));
}
break;
case 57: // ONEOF_FIXED32:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 58: // ONEOF_BOOL:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashBoolean(oneofBooleanAt(message, offset));
}
break;
case 59: // ONEOF_STRING:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode =
(hashCode * 53) + ((String) UnsafeUtil.getObject(message, offset)).hashCode();
}
break;
case 60: // ONEOF_MESSAGE:
if (isOneofPresent(message, entryNumber, pos)) {
Object submessage = UnsafeUtil.getObject(message, offset);
hashCode = (53 * hashCode) + submessage.hashCode();
}
break;
case 61: // ONEOF_BYTES:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + UnsafeUtil.getObject(message, offset).hashCode();
}
break;
case 62: // ONEOF_UINT32:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 63: // ONEOF_ENUM:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 64: // ONEOF_SFIXED32:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 65: // ONEOF_SFIXED64:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset));
}
break;
case 66: // ONEOF_SINT32:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + (oneofIntAt(message, offset));
}
break;
case 67: // ONEOF_SINT64:
if (isOneofPresent(message, entryNumber, pos)) {
hashCode = (hashCode * 53) + Internal.hashLong(oneofLongAt(message, offset));
}
break;
case 68: // ONEOF_GROUP:
if (isOneofPresent(message, entryNumber, pos)) {
Object submessage = UnsafeUtil.getObject(message, offset);
hashCode = (53 * hashCode) + submessage.hashCode();
}
break;
default:
// Assume it's an empty entry - just go to the next entry.
break;
}
}
hashCode = (hashCode * 53) + unknownFieldSchema.getFromMessage(message).hashCode();
if (hasExtensions) {
hashCode = (hashCode * 53) + extensionSchema.getExtensions(message).hashCode();
}
return hashCode;
}
@Override
public void mergeFrom(T message, T other) {
checkMutable(message);
if (other == null) {
throw new NullPointerException();
}
for (int i = 0; i < buffer.length; i += INTS_PER_FIELD) {
// A separate method allows for better JIT optimizations
mergeSingleField(message, other, i);
}
SchemaUtil.mergeUnknownFields(unknownFieldSchema, message, other);
if (hasExtensions) {
SchemaUtil.mergeExtensions(extensionSchema, message, other);
}
}
private void mergeSingleField(T message, T other, int pos) {
final int typeAndOffset = typeAndOffsetAt(pos);
final long offset = offset(typeAndOffset);
final int number = numberAt(pos);
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putDouble(message, offset, UnsafeUtil.getDouble(other, offset));
setFieldPresent(message, pos);
}
break;
case 1: // FLOAT:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putFloat(message, offset, UnsafeUtil.getFloat(other, offset));
setFieldPresent(message, pos);
}
break;
case 2: // INT64:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset));
setFieldPresent(message, pos);
}
break;
case 3: // UINT64:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset));
setFieldPresent(message, pos);
}
break;
case 4: // INT32:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 5: // FIXED64:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset));
setFieldPresent(message, pos);
}
break;
case 6: // FIXED32:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 7: // BOOL:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putBoolean(message, offset, UnsafeUtil.getBoolean(other, offset));
setFieldPresent(message, pos);
}
break;
case 8: // STRING:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset));
setFieldPresent(message, pos);
}
break;
case 9: // MESSAGE:
mergeMessage(message, other, pos);
break;
case 10: // BYTES:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset));
setFieldPresent(message, pos);
}
break;
case 11: // UINT32:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 12: // ENUM:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 13: // SFIXED32:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 14: // SFIXED64:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset));
setFieldPresent(message, pos);
}
break;
case 15: // SINT32:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putInt(message, offset, UnsafeUtil.getInt(other, offset));
setFieldPresent(message, pos);
}
break;
case 16: // SINT64:
if (isFieldPresent(other, pos)) {
UnsafeUtil.putLong(message, offset, UnsafeUtil.getLong(other, offset));
setFieldPresent(message, pos);
}
break;
case 17: // GROUP:
mergeMessage(message, other, pos);
break;
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:
case 21: // UINT64_LIST:
case 22: // INT32_LIST:
case 23: // FIXED64_LIST:
case 24: // FIXED32_LIST:
case 25: // BOOL_LIST:
case 26: // STRING_LIST:
case 27: // MESSAGE_LIST:
case 28: // BYTES_LIST:
case 29: // UINT32_LIST:
case 30: // ENUM_LIST:
case 31: // SFIXED32_LIST:
case 32: // SFIXED64_LIST:
case 33: // SINT32_LIST:
case 34: // SINT64_LIST:
case 35: // DOUBLE_LIST_PACKED:
case 36: // FLOAT_LIST_PACKED:
case 37: // INT64_LIST_PACKED:
case 38: // UINT64_LIST_PACKED:
case 39: // INT32_LIST_PACKED:
case 40: // FIXED64_LIST_PACKED:
case 41: // FIXED32_LIST_PACKED:
case 42: // BOOL_LIST_PACKED:
case 43: // UINT32_LIST_PACKED:
case 44: // ENUM_LIST_PACKED:
case 45: // SFIXED32_LIST_PACKED:
case 46: // SFIXED64_LIST_PACKED:
case 47: // SINT32_LIST_PACKED:
case 48: // SINT64_LIST_PACKED:
case 49: // GROUP_LIST:
listFieldSchema.mergeListsAt(message, other, offset);
break;
case 50: // MAP:
SchemaUtil.mergeMap(mapFieldSchema, message, other, offset);
break;
case 51: // ONEOF_DOUBLE:
case 52: // ONEOF_FLOAT:
case 53: // ONEOF_INT64:
case 54: // ONEOF_UINT64:
case 55: // ONEOF_INT32:
case 56: // ONEOF_FIXED64:
case 57: // ONEOF_FIXED32:
case 58: // ONEOF_BOOL:
case 59: // ONEOF_STRING:
if (isOneofPresent(other, number, pos)) {
UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset));
setOneofPresent(message, number, pos);
}
break;
case 60: // ONEOF_MESSAGE:
mergeOneofMessage(message, other, pos);
break;
case 61: // ONEOF_BYTES:
case 62: // ONEOF_UINT32:
case 63: // ONEOF_ENUM:
case 64: // ONEOF_SFIXED32:
case 65: // ONEOF_SFIXED64:
case 66: // ONEOF_SINT32:
case 67: // ONEOF_SINT64:
if (isOneofPresent(other, number, pos)) {
UnsafeUtil.putObject(message, offset, UnsafeUtil.getObject(other, offset));
setOneofPresent(message, number, pos);
}
break;
case 68: // ONEOF_GROUP:
mergeOneofMessage(message, other, pos);
break;
default:
break;
}
}
private void mergeMessage(T targetParent, T sourceParent, int pos) {
if (!isFieldPresent(sourceParent, pos)) {
return;
}
final int typeAndOffset = typeAndOffsetAt(pos);
final long offset = offset(typeAndOffset);
final Object source = UNSAFE.getObject(sourceParent, offset);
if (source == null) {
throw new IllegalStateException(
"Source subfield " + numberAt(pos) + " is present but null: " + sourceParent);
}
final Schema fieldSchema = getMessageFieldSchema(pos);
if (!isFieldPresent(targetParent, pos)) {
if (!isMutable(source)) {
// Can safely share source if it is immutable
UNSAFE.putObject(targetParent, offset, source);
} else {
// Make a safetey copy of source
final Object copyOfSource = fieldSchema.newInstance();
fieldSchema.mergeFrom(copyOfSource, source);
UNSAFE.putObject(targetParent, offset, copyOfSource);
}
setFieldPresent(targetParent, pos);
return;
}
// Sub-message is present, merge from source
Object target = UNSAFE.getObject(targetParent, offset);
if (!isMutable(target)) {
Object newInstance = fieldSchema.newInstance();
fieldSchema.mergeFrom(newInstance, target);
UNSAFE.putObject(targetParent, offset, newInstance);
target = newInstance;
}
fieldSchema.mergeFrom(target, source);
}
private void mergeOneofMessage(T targetParent, T sourceParent, int pos) {
int number = numberAt(pos);
if (!isOneofPresent(sourceParent, number, pos)) {
return;
}
long offset = offset(typeAndOffsetAt(pos));
final Object source = UNSAFE.getObject(sourceParent, offset);
if (source == null) {
throw new IllegalStateException(
"Source subfield " + numberAt(pos) + " is present but null: " + sourceParent);
}
final Schema fieldSchema = getMessageFieldSchema(pos);
if (!isOneofPresent(targetParent, number, pos)) {
if (!isMutable(source)) {
// Can safely share source if it is immutable
UNSAFE.putObject(targetParent, offset, source);
} else {
// Make a safety copy of theirs
final Object copyOfSource = fieldSchema.newInstance();
fieldSchema.mergeFrom(copyOfSource, source);
UNSAFE.putObject(targetParent, offset, copyOfSource);
}
setOneofPresent(targetParent, number, pos);
return;
}
// Sub-message is present, merge from source
Object target = UNSAFE.getObject(targetParent, offset);
if (!isMutable(target)) {
Object newInstance = fieldSchema.newInstance();
fieldSchema.mergeFrom(newInstance, target);
UNSAFE.putObject(targetParent, offset, newInstance);
target = newInstance;
}
fieldSchema.mergeFrom(target, source);
}
@Override
@SuppressWarnings("unchecked") // Field type checks guarantee type casts from Unsafe.
public int getSerializedSize(T message) {
int size = 0;
final sun.misc.Unsafe unsafe = UNSAFE;
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
int currentPresenceField = 0;
for (int i = 0; i < buffer.length; i += INTS_PER_FIELD) {
final int typeAndOffset = typeAndOffsetAt(i);
final int fieldType = type(typeAndOffset);
final int number = numberAt(i);
int presenceMask = 0;
int presenceMaskAndOffset = buffer[i + 2];
final int presenceOrCachedSizeFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
if (fieldType <= 17) {
// Performance optimization to cache the presence field which is shared for multiple
// fields.
// TODO: Improve caching for case when fields alternate between having and not
// having presence by caching presence field for last field with presence only.
if (presenceOrCachedSizeFieldOffset != currentPresenceFieldOffset) {
currentPresenceFieldOffset = presenceOrCachedSizeFieldOffset;
currentPresenceField =
currentPresenceFieldOffset == NO_PRESENCE_SENTINEL
? 0
: unsafe.getInt(message, (long) currentPresenceFieldOffset);
}
// Mask for presence bit of the current field from the shared presence field.
presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
}
final long offset = offset(typeAndOffset);
final int cachedSizeOffset =
fieldType >= FieldType.DOUBLE_LIST_PACKED.id()
&& fieldType <= FieldType.SINT64_LIST_PACKED.id()
? presenceOrCachedSizeFieldOffset
: 0;
switch (fieldType) {
case 0: // DOUBLE:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeDoubleSize(number, 0);
}
break;
case 1: // FLOAT:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeFloatSize(number, 0);
}
break;
case 2: // INT64:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeInt64Size(number, unsafe.getLong(message, offset));
}
break;
case 3: // UINT64:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeUInt64Size(number, unsafe.getLong(message, offset));
}
break;
case 4: // INT32:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeInt32Size(number, unsafe.getInt(message, offset));
}
break;
case 5: // FIXED64:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeFixed64Size(number, 0);
}
break;
case 6: // FIXED32:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeFixed32Size(number, 0);
}
break;
case 7: // BOOL:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeBoolSize(number, true);
}
break;
case 8: // STRING:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
Object value = unsafe.getObject(message, offset);
if (value instanceof ByteString) {
size += CodedOutputStream.computeBytesSize(number, (ByteString) value);
} else {
size += CodedOutputStream.computeStringSize(number, (String) value);
}
}
break;
case 9: // MESSAGE:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
Object value = unsafe.getObject(message, offset);
size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i));
}
break;
case 10: // BYTES:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
ByteString value = (ByteString) unsafe.getObject(message, offset);
size += CodedOutputStream.computeBytesSize(number, value);
}
break;
case 11: // UINT32:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeUInt32Size(number, unsafe.getInt(message, offset));
}
break;
case 12: // ENUM:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeEnumSize(number, unsafe.getInt(message, offset));
}
break;
case 13: // SFIXED32:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeSFixed32Size(number, 0);
}
break;
case 14: // SFIXED64:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeSFixed64Size(number, 0);
}
break;
case 15: // SINT32:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeSInt32Size(number, unsafe.getInt(message, offset));
}
break;
case 16: // SINT64:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size += CodedOutputStream.computeSInt64Size(number, unsafe.getLong(message, offset));
}
break;
case 17: // GROUP:
if (isFieldPresent(
message, i, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
size +=
CodedOutputStream.computeGroupSize(
number,
(MessageLite) unsafe.getObject(message, offset),
getMessageFieldSchema(i));
}
break;
case 18: // DOUBLE_LIST:
size +=
SchemaUtil.computeSizeFixed64List(
number, (List>) unsafe.getObject(message, offset), false);
break;
case 19: // FLOAT_LIST:
size +=
SchemaUtil.computeSizeFixed32List(
number, (List>) unsafe.getObject(message, offset), false);
break;
case 20: // INT64_LIST:
size +=
SchemaUtil.computeSizeInt64List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 21: // UINT64_LIST:
size +=
SchemaUtil.computeSizeUInt64List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 22: // INT32_LIST:
size +=
SchemaUtil.computeSizeInt32List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 23: // FIXED64_LIST:
size +=
SchemaUtil.computeSizeFixed64List(
number, (List>) unsafe.getObject(message, offset), false);
break;
case 24: // FIXED32_LIST:
size +=
SchemaUtil.computeSizeFixed32List(
number, (List>) unsafe.getObject(message, offset), false);
break;
case 25: // BOOL_LIST:
size +=
SchemaUtil.computeSizeBoolList(
number, (List>) unsafe.getObject(message, offset), false);
break;
case 26: // STRING_LIST:
size +=
SchemaUtil.computeSizeStringList(number, (List>) unsafe.getObject(message, offset));
break;
case 27: // MESSAGE_LIST:
size +=
SchemaUtil.computeSizeMessageList(
number, (List>) unsafe.getObject(message, offset), getMessageFieldSchema(i));
break;
case 28: // BYTES_LIST:
size +=
SchemaUtil.computeSizeByteStringList(
number, (List) unsafe.getObject(message, offset));
break;
case 29: // UINT32_LIST:
size +=
SchemaUtil.computeSizeUInt32List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 30: // ENUM_LIST:
size +=
SchemaUtil.computeSizeEnumList(
number, (List) unsafe.getObject(message, offset), false);
break;
case 31: // SFIXED32_LIST:
size +=
SchemaUtil.computeSizeFixed32List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 32: // SFIXED64_LIST:
size +=
SchemaUtil.computeSizeFixed64List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 33: // SINT32_LIST:
size +=
SchemaUtil.computeSizeSInt32List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 34: // SINT64_LIST:
size +=
SchemaUtil.computeSizeSInt64List(
number, (List) unsafe.getObject(message, offset), false);
break;
case 35:
{ // DOUBLE_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 36:
{ // FLOAT_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 37:
{ // INT64_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeInt64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 38:
{ // UINT64_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeUInt64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 39:
{ // INT32_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeInt32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 40:
{ // FIXED64_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 41:
{ // FIXED32_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 42:
{ // BOOL_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeBoolListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 43:
{ // UINT32_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeUInt32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 44:
{ // ENUM_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeEnumListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 45:
{ // SFIXED32_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 46:
{ // SFIXED64_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeFixed64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 47:
{ // SINT32_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeSInt32ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 48:
{ // SINT64_LIST_PACKED:
int fieldSize =
SchemaUtil.computeSizeSInt64ListNoTag(
(List) unsafe.getObject(message, offset));
if (fieldSize > 0) {
if (useCachedSizeField) {
unsafe.putInt(message, (long) cachedSizeOffset, fieldSize);
}
size +=
CodedOutputStream.computeTagSize(number)
+ CodedOutputStream.computeUInt32SizeNoTag(fieldSize)
+ fieldSize;
}
break;
}
case 49: // GROUP_LIST:
size +=
SchemaUtil.computeSizeGroupList(
number,
(List) unsafe.getObject(message, offset),
getMessageFieldSchema(i));
break;
case 50: // MAP:
// TODO: Use schema cache.
size +=
mapFieldSchema.getSerializedSize(
number, unsafe.getObject(message, offset), getMapFieldDefaultEntry(i));
break;
case 51: // ONEOF_DOUBLE:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeDoubleSize(number, 0);
}
break;
case 52: // ONEOF_FLOAT:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeFloatSize(number, 0);
}
break;
case 53: // ONEOF_INT64:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeInt64Size(number, oneofLongAt(message, offset));
}
break;
case 54: // ONEOF_UINT64:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeUInt64Size(number, oneofLongAt(message, offset));
}
break;
case 55: // ONEOF_INT32:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeInt32Size(number, oneofIntAt(message, offset));
}
break;
case 56: // ONEOF_FIXED64:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeFixed64Size(number, 0);
}
break;
case 57: // ONEOF_FIXED32:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeFixed32Size(number, 0);
}
break;
case 58: // ONEOF_BOOL:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeBoolSize(number, true);
}
break;
case 59: // ONEOF_STRING:
if (isOneofPresent(message, number, i)) {
Object value = unsafe.getObject(message, offset);
if (value instanceof ByteString) {
size += CodedOutputStream.computeBytesSize(number, (ByteString) value);
} else {
size += CodedOutputStream.computeStringSize(number, (String) value);
}
}
break;
case 60: // ONEOF_MESSAGE:
if (isOneofPresent(message, number, i)) {
Object value = unsafe.getObject(message, offset);
size += SchemaUtil.computeSizeMessage(number, value, getMessageFieldSchema(i));
}
break;
case 61: // ONEOF_BYTES:
if (isOneofPresent(message, number, i)) {
size +=
CodedOutputStream.computeBytesSize(
number, (ByteString) unsafe.getObject(message, offset));
}
break;
case 62: // ONEOF_UINT32:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeUInt32Size(number, oneofIntAt(message, offset));
}
break;
case 63: // ONEOF_ENUM:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeEnumSize(number, oneofIntAt(message, offset));
}
break;
case 64: // ONEOF_SFIXED32:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeSFixed32Size(number, 0);
}
break;
case 65: // ONEOF_SFIXED64:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeSFixed64Size(number, 0);
}
break;
case 66: // ONEOF_SINT32:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeSInt32Size(number, oneofIntAt(message, offset));
}
break;
case 67: // ONEOF_SINT64:
if (isOneofPresent(message, number, i)) {
size += CodedOutputStream.computeSInt64Size(number, oneofLongAt(message, offset));
}
break;
case 68: // ONEOF_GROUP:
if (isOneofPresent(message, number, i)) {
size +=
CodedOutputStream.computeGroupSize(
number,
(MessageLite) unsafe.getObject(message, offset),
getMessageFieldSchema(i));
}
break;
default:
// Assume it's an empty entry.
}
}
size += getUnknownFieldsSerializedSize(unknownFieldSchema, message);
if (hasExtensions) {
size += extensionSchema.getExtensions(message).getSerializedSize();
}
return size;
}
private int getUnknownFieldsSerializedSize(
UnknownFieldSchema schema, T message) {
UT unknowns = schema.getFromMessage(message);
return schema.getSerializedSize(unknowns);
}
@Override
// TODO: Consider serializing oneof fields last so that only one entry per
// oneof is actually serialized. This would mean that we would violate the serialization order
// contract. It should also be noted that Go currently does this.
public void writeTo(T message, Writer writer) throws IOException {
if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) {
writeFieldsInDescendingOrder(message, writer);
} else {
writeFieldsInAscendingOrder(message, writer);
}
}
@SuppressWarnings("unchecked")
private void writeFieldsInAscendingOrder(T message, Writer writer) throws IOException {
Iterator extends Map.Entry, ?>> extensionIterator = null;
Map.Entry nextExtension = null;
if (hasExtensions) {
FieldSet> extensions = extensionSchema.getExtensions(message);
if (!extensions.isEmpty()) {
extensionIterator = extensions.iterator();
nextExtension = extensionIterator.next();
}
}
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
int currentPresenceField = 0;
final int bufferLength = buffer.length;
final sun.misc.Unsafe unsafe = UNSAFE;
for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) {
final int typeAndOffset = typeAndOffsetAt(pos);
final int number = numberAt(pos);
final int fieldType = type(typeAndOffset);
int presenceMask = 0;
if (fieldType <= 17) {
int presenceMaskAndOffset = buffer[pos + 2];
final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
// Performance optimization to cache the presence field which is shared for multiple
// fields.
// TODO: Improve caching for case when fields alternate between having and not
// having presence by caching presence field for last field with presence only.
if (presenceFieldOffset != currentPresenceFieldOffset) {
currentPresenceFieldOffset = presenceFieldOffset;
currentPresenceField =
currentPresenceFieldOffset == NO_PRESENCE_SENTINEL
? 0
: unsafe.getInt(message, (long) presenceFieldOffset);
}
// Mask for presence bit of the current field from the shared presence field.
presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
}
// Write any extensions that need to be written before the current field.
while (nextExtension != null && extensionSchema.extensionNumber(nextExtension) <= number) {
extensionSchema.serializeExtension(writer, nextExtension);
nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null;
}
final long offset = offset(typeAndOffset);
switch (fieldType) {
case 0: // DOUBLE:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeDouble(number, doubleAt(message, offset));
}
break;
case 1: // FLOAT:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeFloat(number, floatAt(message, offset));
}
break;
case 2: // INT64:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeInt64(number, unsafe.getLong(message, offset));
}
break;
case 3: // UINT64:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeUInt64(number, unsafe.getLong(message, offset));
}
break;
case 4: // INT32:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeInt32(number, unsafe.getInt(message, offset));
}
break;
case 5: // FIXED64:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeFixed64(number, unsafe.getLong(message, offset));
}
break;
case 6: // FIXED32:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeFixed32(number, unsafe.getInt(message, offset));
}
break;
case 7: // BOOL:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeBool(number, booleanAt(message, offset));
}
break;
case 8: // STRING:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writeString(number, unsafe.getObject(message, offset), writer);
}
break;
case 9: // MESSAGE:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
Object value = unsafe.getObject(message, offset);
writer.writeMessage(number, value, getMessageFieldSchema(pos));
}
break;
case 10: // BYTES:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeBytes(number, (ByteString) unsafe.getObject(message, offset));
}
break;
case 11: // UINT32:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeUInt32(number, unsafe.getInt(message, offset));
}
break;
case 12: // ENUM:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeEnum(number, unsafe.getInt(message, offset));
}
break;
case 13: // SFIXED32:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeSFixed32(number, unsafe.getInt(message, offset));
}
break;
case 14: // SFIXED64:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeSFixed64(number, unsafe.getLong(message, offset));
}
break;
case 15: // SINT32:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeSInt32(number, unsafe.getInt(message, offset));
}
break;
case 16: // SINT64:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeSInt64(number, unsafe.getLong(message, offset));
}
break;
case 17: // GROUP:
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
writer.writeGroup(
number, unsafe.getObject(message, offset), getMessageFieldSchema(pos));
}
break;
case 18: // DOUBLE_LIST:
SchemaUtil.writeDoubleList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 19: // FLOAT_LIST:
SchemaUtil.writeFloatList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 20: // INT64_LIST:
SchemaUtil.writeInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 21: // UINT64_LIST:
SchemaUtil.writeUInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 22: // INT32_LIST:
SchemaUtil.writeInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 23: // FIXED64_LIST:
SchemaUtil.writeFixed64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 24: // FIXED32_LIST:
SchemaUtil.writeFixed32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 25: // BOOL_LIST:
SchemaUtil.writeBoolList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 26: // STRING_LIST:
SchemaUtil.writeStringList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer);
break;
case 27: // MESSAGE_LIST:
SchemaUtil.writeMessageList(
numberAt(pos),
(List>) unsafe.getObject(message, offset),
writer,
getMessageFieldSchema(pos));
break;
case 28: // BYTES_LIST:
SchemaUtil.writeBytesList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer);
break;
case 29: // UINT32_LIST:
SchemaUtil.writeUInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 30: // ENUM_LIST:
SchemaUtil.writeEnumList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 31: // SFIXED32_LIST:
SchemaUtil.writeSFixed32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 32: // SFIXED64_LIST:
SchemaUtil.writeSFixed64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 33: // SINT32_LIST:
SchemaUtil.writeSInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 34: // SINT64_LIST:
SchemaUtil.writeSInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, false);
break;
case 35: // DOUBLE_LIST_PACKED:
// TODO: Make use of cached field size to speed up serialization.
SchemaUtil.writeDoubleList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 36: // FLOAT_LIST_PACKED:
SchemaUtil.writeFloatList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 37: // INT64_LIST_PACKED:
SchemaUtil.writeInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 38: // UINT64_LIST_PACKED:
SchemaUtil.writeUInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 39: // INT32_LIST_PACKED:
SchemaUtil.writeInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 40: // FIXED64_LIST_PACKED:
SchemaUtil.writeFixed64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 41: // FIXED32_LIST_PACKED:
SchemaUtil.writeFixed32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 42: // BOOL_LIST_PACKED:
SchemaUtil.writeBoolList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 43: // UINT32_LIST_PACKED:
SchemaUtil.writeUInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 44: // ENUM_LIST_PACKED:
SchemaUtil.writeEnumList(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 45: // SFIXED32_LIST_PACKED:
SchemaUtil.writeSFixed32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 46: // SFIXED64_LIST_PACKED:
SchemaUtil.writeSFixed64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 47: // SINT32_LIST_PACKED:
SchemaUtil.writeSInt32List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 48: // SINT64_LIST_PACKED:
SchemaUtil.writeSInt64List(
numberAt(pos), (List) unsafe.getObject(message, offset), writer, true);
break;
case 49: // GROUP_LIST:
SchemaUtil.writeGroupList(
numberAt(pos),
(List>) unsafe.getObject(message, offset),
writer,
getMessageFieldSchema(pos));
break;
case 50: // MAP:
// TODO: Use schema cache.
writeMapHelper(writer, number, unsafe.getObject(message, offset), pos);
break;
case 51: // ONEOF_DOUBLE:
if (isOneofPresent(message, number, pos)) {
writer.writeDouble(number, oneofDoubleAt(message, offset));
}
break;
case 52: // ONEOF_FLOAT:
if (isOneofPresent(message, number, pos)) {
writer.writeFloat(number, oneofFloatAt(message, offset));
}
break;
case 53: // ONEOF_INT64:
if (isOneofPresent(message, number, pos)) {
writer.writeInt64(number, oneofLongAt(message, offset));
}
break;
case 54: // ONEOF_UINT64:
if (isOneofPresent(message, number, pos)) {
writer.writeUInt64(number, oneofLongAt(message, offset));
}
break;
case 55: // ONEOF_INT32:
if (isOneofPresent(message, number, pos)) {
writer.writeInt32(number, oneofIntAt(message, offset));
}
break;
case 56: // ONEOF_FIXED64:
if (isOneofPresent(message, number, pos)) {
writer.writeFixed64(number, oneofLongAt(message, offset));
}
break;
case 57: // ONEOF_FIXED32:
if (isOneofPresent(message, number, pos)) {
writer.writeFixed32(number, oneofIntAt(message, offset));
}
break;
case 58: // ONEOF_BOOL:
if (isOneofPresent(message, number, pos)) {
writer.writeBool(number, oneofBooleanAt(message, offset));
}
break;
case 59: // ONEOF_STRING:
if (isOneofPresent(message, number, pos)) {
writeString(number, unsafe.getObject(message, offset), writer);
}
break;
case 60: // ONEOF_MESSAGE:
if (isOneofPresent(message, number, pos)) {
Object value = unsafe.getObject(message, offset);
writer.writeMessage(number, value, getMessageFieldSchema(pos));
}
break;
case 61: // ONEOF_BYTES:
if (isOneofPresent(message, number, pos)) {
writer.writeBytes(number, (ByteString) unsafe.getObject(message, offset));
}
break;
case 62: // ONEOF_UINT32:
if (isOneofPresent(message, number, pos)) {
writer.writeUInt32(number, oneofIntAt(message, offset));
}
break;
case 63: // ONEOF_ENUM:
if (isOneofPresent(message, number, pos)) {
writer.writeEnum(number, oneofIntAt(message, offset));
}
break;
case 64: // ONEOF_SFIXED32:
if (isOneofPresent(message, number, pos)) {
writer.writeSFixed32(number, oneofIntAt(message, offset));
}
break;
case 65: // ONEOF_SFIXED64:
if (isOneofPresent(message, number, pos)) {
writer.writeSFixed64(number, oneofLongAt(message, offset));
}
break;
case 66: // ONEOF_SINT32:
if (isOneofPresent(message, number, pos)) {
writer.writeSInt32(number, oneofIntAt(message, offset));
}
break;
case 67: // ONEOF_SINT64:
if (isOneofPresent(message, number, pos)) {
writer.writeSInt64(number, oneofLongAt(message, offset));
}
break;
case 68: // ONEOF_GROUP:
if (isOneofPresent(message, number, pos)) {
writer.writeGroup(
number, unsafe.getObject(message, offset), getMessageFieldSchema(pos));
}
break;
default:
// Assume it's an empty entry - just go to the next entry.
break;
}
}
while (nextExtension != null) {
extensionSchema.serializeExtension(writer, nextExtension);
nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null;
}
writeUnknownInMessageTo(unknownFieldSchema, message, writer);
}
@SuppressWarnings("unchecked")
private void writeFieldsInDescendingOrder(T message, Writer writer) throws IOException {
writeUnknownInMessageTo(unknownFieldSchema, message, writer);
Iterator extends Map.Entry, ?>> extensionIterator = null;
Map.Entry nextExtension = null;
if (hasExtensions) {
FieldSet> extensions = extensionSchema.getExtensions(message);
if (!extensions.isEmpty()) {
extensionIterator = extensions.descendingIterator();
nextExtension = extensionIterator.next();
}
}
for (int pos = buffer.length - INTS_PER_FIELD; pos >= 0; pos -= INTS_PER_FIELD) {
final int typeAndOffset = typeAndOffsetAt(pos);
final int number = numberAt(pos);
// Write any extensions that need to be written before the current field.
while (nextExtension != null && extensionSchema.extensionNumber(nextExtension) > number) {
extensionSchema.serializeExtension(writer, nextExtension);
nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null;
}
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
if (isFieldPresent(message, pos)) {
writer.writeDouble(number, doubleAt(message, offset(typeAndOffset)));
}
break;
case 1: // FLOAT:
if (isFieldPresent(message, pos)) {
writer.writeFloat(number, floatAt(message, offset(typeAndOffset)));
}
break;
case 2: // INT64:
if (isFieldPresent(message, pos)) {
writer.writeInt64(number, longAt(message, offset(typeAndOffset)));
}
break;
case 3: // UINT64:
if (isFieldPresent(message, pos)) {
writer.writeUInt64(number, longAt(message, offset(typeAndOffset)));
}
break;
case 4: // INT32:
if (isFieldPresent(message, pos)) {
writer.writeInt32(number, intAt(message, offset(typeAndOffset)));
}
break;
case 5: // FIXED64:
if (isFieldPresent(message, pos)) {
writer.writeFixed64(number, longAt(message, offset(typeAndOffset)));
}
break;
case 6: // FIXED32:
if (isFieldPresent(message, pos)) {
writer.writeFixed32(number, intAt(message, offset(typeAndOffset)));
}
break;
case 7: // BOOL:
if (isFieldPresent(message, pos)) {
writer.writeBool(number, booleanAt(message, offset(typeAndOffset)));
}
break;
case 8: // STRING:
if (isFieldPresent(message, pos)) {
writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer);
}
break;
case 9: // MESSAGE:
if (isFieldPresent(message, pos)) {
Object value = UnsafeUtil.getObject(message, offset(typeAndOffset));
writer.writeMessage(number, value, getMessageFieldSchema(pos));
}
break;
case 10: // BYTES:
if (isFieldPresent(message, pos)) {
writer.writeBytes(
number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset)));
}
break;
case 11: // UINT32:
if (isFieldPresent(message, pos)) {
writer.writeUInt32(number, intAt(message, offset(typeAndOffset)));
}
break;
case 12: // ENUM:
if (isFieldPresent(message, pos)) {
writer.writeEnum(number, intAt(message, offset(typeAndOffset)));
}
break;
case 13: // SFIXED32:
if (isFieldPresent(message, pos)) {
writer.writeSFixed32(number, intAt(message, offset(typeAndOffset)));
}
break;
case 14: // SFIXED64:
if (isFieldPresent(message, pos)) {
writer.writeSFixed64(number, longAt(message, offset(typeAndOffset)));
}
break;
case 15: // SINT32:
if (isFieldPresent(message, pos)) {
writer.writeSInt32(number, intAt(message, offset(typeAndOffset)));
}
break;
case 16: // SINT64:
if (isFieldPresent(message, pos)) {
writer.writeSInt64(number, longAt(message, offset(typeAndOffset)));
}
break;
case 17: // GROUP:
if (isFieldPresent(message, pos)) {
writer.writeGroup(
number,
UnsafeUtil.getObject(message, offset(typeAndOffset)),
getMessageFieldSchema(pos));
}
break;
case 18: // DOUBLE_LIST:
SchemaUtil.writeDoubleList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 19: // FLOAT_LIST:
SchemaUtil.writeFloatList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 20: // INT64_LIST:
SchemaUtil.writeInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 21: // UINT64_LIST:
SchemaUtil.writeUInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 22: // INT32_LIST:
SchemaUtil.writeInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 23: // FIXED64_LIST:
SchemaUtil.writeFixed64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 24: // FIXED32_LIST:
SchemaUtil.writeFixed32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 25: // BOOL_LIST:
SchemaUtil.writeBoolList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 26: // STRING_LIST:
SchemaUtil.writeStringList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer);
break;
case 27: // MESSAGE_LIST:
SchemaUtil.writeMessageList(
numberAt(pos),
(List>) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
getMessageFieldSchema(pos));
break;
case 28: // BYTES_LIST:
SchemaUtil.writeBytesList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer);
break;
case 29: // UINT32_LIST:
SchemaUtil.writeUInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 30: // ENUM_LIST:
SchemaUtil.writeEnumList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 31: // SFIXED32_LIST:
SchemaUtil.writeSFixed32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 32: // SFIXED64_LIST:
SchemaUtil.writeSFixed64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 33: // SINT32_LIST:
SchemaUtil.writeSInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 34: // SINT64_LIST:
SchemaUtil.writeSInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
false);
break;
case 35: // DOUBLE_LIST_PACKED:
SchemaUtil.writeDoubleList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 36: // FLOAT_LIST_PACKED:
SchemaUtil.writeFloatList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 37: // INT64_LIST_PACKED:
SchemaUtil.writeInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 38: // UINT64_LIST_PACKED:
SchemaUtil.writeUInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 39: // INT32_LIST_PACKED:
SchemaUtil.writeInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 40: // FIXED64_LIST_PACKED:
SchemaUtil.writeFixed64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 41: // FIXED32_LIST_PACKED:
SchemaUtil.writeFixed32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 42: // BOOL_LIST_PACKED:
SchemaUtil.writeBoolList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 43: // UINT32_LIST_PACKED:
SchemaUtil.writeUInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 44: // ENUM_LIST_PACKED:
SchemaUtil.writeEnumList(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 45: // SFIXED32_LIST_PACKED:
SchemaUtil.writeSFixed32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 46: // SFIXED64_LIST_PACKED:
SchemaUtil.writeSFixed64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 47: // SINT32_LIST_PACKED:
SchemaUtil.writeSInt32List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 48: // SINT64_LIST_PACKED:
SchemaUtil.writeSInt64List(
numberAt(pos),
(List) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
true);
break;
case 49: // GROUP_LIST:
SchemaUtil.writeGroupList(
numberAt(pos),
(List>) UnsafeUtil.getObject(message, offset(typeAndOffset)),
writer,
getMessageFieldSchema(pos));
break;
case 50: // MAP:
// TODO: Use schema cache.
writeMapHelper(writer, number, UnsafeUtil.getObject(message, offset(typeAndOffset)), pos);
break;
case 51: // ONEOF_DOUBLE:
if (isOneofPresent(message, number, pos)) {
writer.writeDouble(number, oneofDoubleAt(message, offset(typeAndOffset)));
}
break;
case 52: // ONEOF_FLOAT:
if (isOneofPresent(message, number, pos)) {
writer.writeFloat(number, oneofFloatAt(message, offset(typeAndOffset)));
}
break;
case 53: // ONEOF_INT64:
if (isOneofPresent(message, number, pos)) {
writer.writeInt64(number, oneofLongAt(message, offset(typeAndOffset)));
}
break;
case 54: // ONEOF_UINT64:
if (isOneofPresent(message, number, pos)) {
writer.writeUInt64(number, oneofLongAt(message, offset(typeAndOffset)));
}
break;
case 55: // ONEOF_INT32:
if (isOneofPresent(message, number, pos)) {
writer.writeInt32(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 56: // ONEOF_FIXED64:
if (isOneofPresent(message, number, pos)) {
writer.writeFixed64(number, oneofLongAt(message, offset(typeAndOffset)));
}
break;
case 57: // ONEOF_FIXED32:
if (isOneofPresent(message, number, pos)) {
writer.writeFixed32(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 58: // ONEOF_BOOL:
if (isOneofPresent(message, number, pos)) {
writer.writeBool(number, oneofBooleanAt(message, offset(typeAndOffset)));
}
break;
case 59: // ONEOF_STRING:
if (isOneofPresent(message, number, pos)) {
writeString(number, UnsafeUtil.getObject(message, offset(typeAndOffset)), writer);
}
break;
case 60: // ONEOF_MESSAGE:
if (isOneofPresent(message, number, pos)) {
Object value = UnsafeUtil.getObject(message, offset(typeAndOffset));
writer.writeMessage(number, value, getMessageFieldSchema(pos));
}
break;
case 61: // ONEOF_BYTES:
if (isOneofPresent(message, number, pos)) {
writer.writeBytes(
number, (ByteString) UnsafeUtil.getObject(message, offset(typeAndOffset)));
}
break;
case 62: // ONEOF_UINT32:
if (isOneofPresent(message, number, pos)) {
writer.writeUInt32(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 63: // ONEOF_ENUM:
if (isOneofPresent(message, number, pos)) {
writer.writeEnum(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 64: // ONEOF_SFIXED32:
if (isOneofPresent(message, number, pos)) {
writer.writeSFixed32(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 65: // ONEOF_SFIXED64:
if (isOneofPresent(message, number, pos)) {
writer.writeSFixed64(number, oneofLongAt(message, offset(typeAndOffset)));
}
break;
case 66: // ONEOF_SINT32:
if (isOneofPresent(message, number, pos)) {
writer.writeSInt32(number, oneofIntAt(message, offset(typeAndOffset)));
}
break;
case 67: // ONEOF_SINT64:
if (isOneofPresent(message, number, pos)) {
writer.writeSInt64(number, oneofLongAt(message, offset(typeAndOffset)));
}
break;
case 68: // ONEOF_GROUP:
if (isOneofPresent(message, number, pos)) {
writer.writeGroup(
number,
UnsafeUtil.getObject(message, offset(typeAndOffset)),
getMessageFieldSchema(pos));
}
break;
default:
break;
}
}
while (nextExtension != null) {
extensionSchema.serializeExtension(writer, nextExtension);
nextExtension = extensionIterator.hasNext() ? extensionIterator.next() : null;
}
}
@SuppressWarnings("unchecked")
private void writeMapHelper(Writer writer, int number, Object mapField, int pos)
throws IOException {
if (mapField != null) {
writer.writeMap(
number,
(MapEntryLite.Metadata) mapFieldSchema.forMapMetadata(getMapFieldDefaultEntry(pos)),
(Map) mapFieldSchema.forMapData(mapField));
}
}
private void writeUnknownInMessageTo(
UnknownFieldSchema schema, T message, Writer writer) throws IOException {
schema.writeTo(schema.getFromMessage(message), writer);
}
@Override
public void mergeFrom(T message, Reader reader, ExtensionRegistryLite extensionRegistry)
throws IOException {
if (extensionRegistry == null) {
throw new NullPointerException();
}
checkMutable(message);
mergeFromHelper(unknownFieldSchema, extensionSchema, message, reader, extensionRegistry);
}
/**
* A helper method for wildcard capture of {@code unknownFieldSchema}. See:
* https://docs.oracle.com/javase/tutorial/java/generics/capture.html
*/
private > void mergeFromHelper(
UnknownFieldSchema unknownFieldSchema,
ExtensionSchema extensionSchema,
T message,
Reader reader,
ExtensionRegistryLite extensionRegistry)
throws IOException {
UB unknownFields = null;
FieldSet extensions = null;
try {
while (true) {
final int number = reader.getFieldNumber();
final int pos = positionForFieldNumber(number);
if (pos < 0) {
if (number == Reader.READ_DONE) {
return;
}
// Check if it's an extension.
Object extension =
!hasExtensions
? null
: extensionSchema.findExtensionByNumber(
extensionRegistry, defaultInstance, number);
if (extension != null) {
if (extensions == null) {
extensions = extensionSchema.getMutableExtensions(message);
}
unknownFields =
extensionSchema.parseExtension(
message,
reader,
extension,
extensionRegistry,
extensions,
unknownFields,
unknownFieldSchema);
continue;
}
if (unknownFieldSchema.shouldDiscardUnknownFields(reader)) {
if (reader.skipField()) {
continue;
}
} else {
if (unknownFields == null) {
unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
}
// Unknown field.
if (unknownFieldSchema.mergeOneFieldFrom(
unknownFields, reader, /* currentDepth= */ 0)) {
continue;
}
}
// Done reading.
return;
}
final int typeAndOffset = typeAndOffsetAt(pos);
try {
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
UnsafeUtil.putDouble(message, offset(typeAndOffset), reader.readDouble());
setFieldPresent(message, pos);
break;
case 1: // FLOAT:
UnsafeUtil.putFloat(message, offset(typeAndOffset), reader.readFloat());
setFieldPresent(message, pos);
break;
case 2: // INT64:
UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readInt64());
setFieldPresent(message, pos);
break;
case 3: // UINT64:
UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readUInt64());
setFieldPresent(message, pos);
break;
case 4: // INT32:
UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readInt32());
setFieldPresent(message, pos);
break;
case 5: // FIXED64:
UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readFixed64());
setFieldPresent(message, pos);
break;
case 6: // FIXED32:
UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readFixed32());
setFieldPresent(message, pos);
break;
case 7: // BOOL:
UnsafeUtil.putBoolean(message, offset(typeAndOffset), reader.readBool());
setFieldPresent(message, pos);
break;
case 8: // STRING:
readString(message, typeAndOffset, reader);
setFieldPresent(message, pos);
break;
case 9:
{ // MESSAGE:
final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos);
reader.mergeMessageField(
current, (Schema) getMessageFieldSchema(pos), extensionRegistry);
storeMessageField(message, pos, current);
break;
}
case 10: // BYTES:
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes());
setFieldPresent(message, pos);
break;
case 11: // UINT32:
UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readUInt32());
setFieldPresent(message, pos);
break;
case 12: // ENUM:
{
int enumValue = reader.readEnum();
EnumVerifier enumVerifier = getEnumFieldVerifier(pos);
if (enumVerifier == null || enumVerifier.isInRange(enumValue)) {
UnsafeUtil.putInt(message, offset(typeAndOffset), enumValue);
setFieldPresent(message, pos);
} else {
unknownFields =
SchemaUtil.storeUnknownEnum(
message, number, enumValue, unknownFields, unknownFieldSchema);
}
break;
}
case 13: // SFIXED32:
UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readSFixed32());
setFieldPresent(message, pos);
break;
case 14: // SFIXED64:
UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readSFixed64());
setFieldPresent(message, pos);
break;
case 15: // SINT32:
UnsafeUtil.putInt(message, offset(typeAndOffset), reader.readSInt32());
setFieldPresent(message, pos);
break;
case 16: // SINT64:
UnsafeUtil.putLong(message, offset(typeAndOffset), reader.readSInt64());
setFieldPresent(message, pos);
break;
case 17:
{ // GROUP:
final MessageLite current = (MessageLite) mutableMessageFieldForMerge(message, pos);
reader.mergeGroupField(
current, (Schema) getMessageFieldSchema(pos), extensionRegistry);
storeMessageField(message, pos, current);
break;
}
case 18: // DOUBLE_LIST:
reader.readDoubleList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 19: // FLOAT_LIST:
reader.readFloatList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 20: // INT64_LIST:
reader.readInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 21: // UINT64_LIST:
reader.readUInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 22: // INT32_LIST:
reader.readInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 23: // FIXED64_LIST:
reader.readFixed64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 24: // FIXED32_LIST:
reader.readFixed32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 25: // BOOL_LIST:
reader.readBoolList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 26: // STRING_LIST:
readStringList(message, typeAndOffset, reader);
break;
case 27:
{ // MESSAGE_LIST:
readMessageList(
message,
typeAndOffset,
reader,
(Schema) getMessageFieldSchema(pos),
extensionRegistry);
break;
}
case 28: // BYTES_LIST:
reader.readBytesList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 29: // UINT32_LIST:
reader.readUInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 30: // ENUM_LIST:
{
List enumList =
listFieldSchema.mutableListAt(message, offset(typeAndOffset));
reader.readEnumList(enumList);
unknownFields =
SchemaUtil.filterUnknownEnumList(
message,
number,
enumList,
getEnumFieldVerifier(pos),
unknownFields,
unknownFieldSchema);
break;
}
case 31: // SFIXED32_LIST:
reader.readSFixed32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 32: // SFIXED64_LIST:
reader.readSFixed64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 33: // SINT32_LIST:
reader.readSInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 34: // SINT64_LIST:
reader.readSInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 35: // DOUBLE_LIST_PACKED:
reader.readDoubleList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 36: // FLOAT_LIST_PACKED:
reader.readFloatList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 37: // INT64_LIST_PACKED:
reader.readInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 38: // UINT64_LIST_PACKED:
reader.readUInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 39: // INT32_LIST_PACKED:
reader.readInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 40: // FIXED64_LIST_PACKED:
reader.readFixed64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 41: // FIXED32_LIST_PACKED:
reader.readFixed32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 42: // BOOL_LIST_PACKED:
reader.readBoolList(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 43: // UINT32_LIST_PACKED:
reader.readUInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 44: // ENUM_LIST_PACKED:
{
List enumList =
listFieldSchema.mutableListAt(message, offset(typeAndOffset));
reader.readEnumList(enumList);
unknownFields =
SchemaUtil.filterUnknownEnumList(
message,
number,
enumList,
getEnumFieldVerifier(pos),
unknownFields,
unknownFieldSchema);
break;
}
case 45: // SFIXED32_LIST_PACKED:
reader.readSFixed32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 46: // SFIXED64_LIST_PACKED:
reader.readSFixed64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 47: // SINT32_LIST_PACKED:
reader.readSInt32List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 48: // SINT64_LIST_PACKED:
reader.readSInt64List(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
break;
case 49:
{ // GROUP_LIST:
readGroupList(
message,
offset(typeAndOffset),
reader,
(Schema) getMessageFieldSchema(pos),
extensionRegistry);
break;
}
case 50: // MAP:
mergeMap(message, pos, getMapFieldDefaultEntry(pos), extensionRegistry, reader);
break;
case 51: // ONEOF_DOUBLE:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Double.valueOf(reader.readDouble()));
setOneofPresent(message, number, pos);
break;
case 52: // ONEOF_FLOAT:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Float.valueOf(reader.readFloat()));
setOneofPresent(message, number, pos);
break;
case 53: // ONEOF_INT64:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Long.valueOf(reader.readInt64()));
setOneofPresent(message, number, pos);
break;
case 54: // ONEOF_UINT64:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Long.valueOf(reader.readUInt64()));
setOneofPresent(message, number, pos);
break;
case 55: // ONEOF_INT32:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Integer.valueOf(reader.readInt32()));
setOneofPresent(message, number, pos);
break;
case 56: // ONEOF_FIXED64:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Long.valueOf(reader.readFixed64()));
setOneofPresent(message, number, pos);
break;
case 57: // ONEOF_FIXED32:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Integer.valueOf(reader.readFixed32()));
setOneofPresent(message, number, pos);
break;
case 58: // ONEOF_BOOL:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Boolean.valueOf(reader.readBool()));
setOneofPresent(message, number, pos);
break;
case 59: // ONEOF_STRING:
readString(message, typeAndOffset, reader);
setOneofPresent(message, number, pos);
break;
case 60:
{ // ONEOF_MESSAGE:
final MessageLite current =
(MessageLite) mutableOneofMessageFieldForMerge(message, number, pos);
reader.mergeMessageField(
current, (Schema) getMessageFieldSchema(pos), extensionRegistry);
storeOneofMessageField(message, number, pos, current);
break;
}
case 61: // ONEOF_BYTES:
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes());
setOneofPresent(message, number, pos);
break;
case 62: // ONEOF_UINT32:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Integer.valueOf(reader.readUInt32()));
setOneofPresent(message, number, pos);
break;
case 63: // ONEOF_ENUM:
{
int enumValue = reader.readEnum();
EnumVerifier enumVerifier = getEnumFieldVerifier(pos);
if (enumVerifier == null || enumVerifier.isInRange(enumValue)) {
UnsafeUtil.putObject(message, offset(typeAndOffset), enumValue);
setOneofPresent(message, number, pos);
} else {
unknownFields =
SchemaUtil.storeUnknownEnum(
message, number, enumValue, unknownFields, unknownFieldSchema);
}
break;
}
case 64: // ONEOF_SFIXED32:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Integer.valueOf(reader.readSFixed32()));
setOneofPresent(message, number, pos);
break;
case 65: // ONEOF_SFIXED64:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Long.valueOf(reader.readSFixed64()));
setOneofPresent(message, number, pos);
break;
case 66: // ONEOF_SINT32:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Integer.valueOf(reader.readSInt32()));
setOneofPresent(message, number, pos);
break;
case 67: // ONEOF_SINT64:
UnsafeUtil.putObject(
message, offset(typeAndOffset), Long.valueOf(reader.readSInt64()));
setOneofPresent(message, number, pos);
break;
case 68:
{ // ONEOF_GROUP:
final MessageLite current =
(MessageLite) mutableOneofMessageFieldForMerge(message, number, pos);
reader.mergeGroupField(
current, (Schema) getMessageFieldSchema(pos), extensionRegistry);
storeOneofMessageField(message, number, pos, current);
break;
}
default:
// Assume we've landed on an empty entry. Treat it as an unknown field.
if (unknownFields == null) {
unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
}
if (!unknownFieldSchema.mergeOneFieldFrom(
unknownFields, reader, /* currentDepth= */ 0)) {
return;
}
break;
}
} catch (InvalidProtocolBufferException.InvalidWireTypeException e) {
// Treat fields with an invalid wire type as unknown fields
// (i.e. same as the default case).
if (unknownFieldSchema.shouldDiscardUnknownFields(reader)) {
if (!reader.skipField()) {
return;
}
} else {
if (unknownFields == null) {
unknownFields = unknownFieldSchema.getBuilderFromMessage(message);
}
if (!unknownFieldSchema.mergeOneFieldFrom(
unknownFields, reader, /* currentDepth= */ 0)) {
return;
}
}
}
}
} finally {
for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) {
unknownFields =
filterMapUnknownEnumValues(
message, intArray[i], unknownFields, unknownFieldSchema, message);
}
if (unknownFields != null) {
unknownFieldSchema.setBuilderToMessage(message, unknownFields);
}
}
}
@SuppressWarnings("ReferenceEquality")
static UnknownFieldSetLite getMutableUnknownFields(Object message) {
// TODO decide if we're keeping support for Full in schema classes and handle this
// better.
UnknownFieldSetLite unknownFields = ((GeneratedMessageLite) message).unknownFields;
if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) {
unknownFields = UnknownFieldSetLite.newInstance();
((GeneratedMessageLite) message).unknownFields = unknownFields;
}
return unknownFields;
}
/** Decodes a map entry key or value. Stores result in registers.object1. */
private int decodeMapEntryValue(
byte[] data,
int position,
int limit,
WireFormat.FieldType fieldType,
Class> messageType,
Registers registers)
throws IOException {
switch (fieldType) {
case BOOL:
position = decodeVarint64(data, position, registers);
registers.object1 = registers.long1 != 0;
break;
case BYTES:
position = decodeBytes(data, position, registers);
break;
case DOUBLE:
registers.object1 = decodeDouble(data, position);
position += 8;
break;
case FIXED32:
case SFIXED32:
registers.object1 = decodeFixed32(data, position);
position += 4;
break;
case FIXED64:
case SFIXED64:
registers.object1 = decodeFixed64(data, position);
position += 8;
break;
case FLOAT:
registers.object1 = decodeFloat(data, position);
position += 4;
break;
case ENUM:
case INT32:
case UINT32:
position = decodeVarint32(data, position, registers);
registers.object1 = registers.int1;
break;
case INT64:
case UINT64:
position = decodeVarint64(data, position, registers);
registers.object1 = registers.long1;
break;
case MESSAGE:
position =
decodeMessageField(
Protobuf.getInstance().schemaFor(messageType), data, position, limit, registers);
break;
case SINT32:
position = decodeVarint32(data, position, registers);
registers.object1 = CodedInputStream.decodeZigZag32(registers.int1);
break;
case SINT64:
position = decodeVarint64(data, position, registers);
registers.object1 = CodedInputStream.decodeZigZag64(registers.long1);
break;
case STRING:
position = decodeStringRequireUtf8(data, position, registers);
break;
default:
throw new RuntimeException("unsupported field type.");
}
return position;
}
/** Decodes a map entry. */
private int decodeMapEntry(
byte[] data,
int position,
int limit,
MapEntryLite.Metadata metadata,
Map target,
Registers registers)
throws IOException {
position = decodeVarint32(data, position, registers);
final int length = registers.int1;
if (length < 0 || length > limit - position) {
throw InvalidProtocolBufferException.truncatedMessage();
}
final int end = position + length;
K key = metadata.defaultKey;
V value = metadata.defaultValue;
while (position < end) {
int tag = data[position++];
if (tag < 0) {
position = decodeVarint32(tag, data, position, registers);
tag = registers.int1;
}
final int fieldNumber = tag >>> 3;
final int wireType = tag & 0x7;
switch (fieldNumber) {
case 1:
if (wireType == metadata.keyType.getWireType()) {
position =
decodeMapEntryValue(data, position, limit, metadata.keyType, null, registers);
key = (K) registers.object1;
continue;
}
break;
case 2:
if (wireType == metadata.valueType.getWireType()) {
position =
decodeMapEntryValue(
data,
position,
limit,
metadata.valueType,
metadata.defaultValue.getClass(),
registers);
value = (V) registers.object1;
continue;
}
break;
default:
break;
}
position = skipField(tag, data, position, limit, registers);
}
if (position != end) {
throw InvalidProtocolBufferException.parseFailure();
}
target.put(key, value);
return end;
}
@SuppressWarnings("ReferenceEquality")
private int parseRepeatedField(
T message,
byte[] data,
int position,
int limit,
int tag,
int number,
int wireType,
int bufferPosition,
long typeAndOffset,
int fieldType,
long fieldOffset,
Registers registers)
throws IOException {
ProtobufList> list = (ProtobufList>) UNSAFE.getObject(message, fieldOffset);
if (!list.isModifiable()) {
final int size = list.size();
list =
list.mutableCopyWithCapacity(
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
UNSAFE.putObject(message, fieldOffset, list);
}
switch (fieldType) {
case 18: // DOUBLE_LIST:
case 35: // DOUBLE_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedDoubleList(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_FIXED64) {
position = decodeDoubleList(tag, data, position, limit, list, registers);
}
break;
case 19: // FLOAT_LIST:
case 36: // FLOAT_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedFloatList(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_FIXED32) {
position = decodeFloatList(tag, data, position, limit, list, registers);
}
break;
case 20: // INT64_LIST:
case 21: // UINT64_LIST:
case 37: // INT64_LIST_PACKED:
case 38: // UINT64_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedVarint64List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64List(tag, data, position, limit, list, registers);
}
break;
case 22: // INT32_LIST:
case 29: // UINT32_LIST:
case 39: // INT32_LIST_PACKED:
case 43: // UINT32_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedVarint32List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32List(tag, data, position, limit, list, registers);
}
break;
case 23: // FIXED64_LIST:
case 32: // SFIXED64_LIST:
case 40: // FIXED64_LIST_PACKED:
case 46: // SFIXED64_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedFixed64List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_FIXED64) {
position = decodeFixed64List(tag, data, position, limit, list, registers);
}
break;
case 24: // FIXED32_LIST:
case 31: // SFIXED32_LIST:
case 41: // FIXED32_LIST_PACKED:
case 45: // SFIXED32_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedFixed32List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_FIXED32) {
position = decodeFixed32List(tag, data, position, limit, list, registers);
}
break;
case 25: // BOOL_LIST:
case 42: // BOOL_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedBoolList(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeBoolList(tag, data, position, limit, list, registers);
}
break;
case 26: // STRING_LIST:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
if ((typeAndOffset & ENFORCE_UTF8_MASK) == 0) {
position = decodeStringList(tag, data, position, limit, list, registers);
} else {
position = decodeStringListRequireUtf8(tag, data, position, limit, list, registers);
}
}
break;
case 27: // MESSAGE_LIST:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position =
decodeMessageList(
getMessageFieldSchema(bufferPosition),
tag,
data,
position,
limit,
list,
registers);
}
break;
case 28: // BYTES_LIST:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodeBytesList(tag, data, position, limit, list, registers);
}
break;
case 30: // ENUM_LIST:
case 44: // ENUM_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedVarint32List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32List(tag, data, position, limit, list, registers);
} else {
break;
}
SchemaUtil.filterUnknownEnumList(
message,
number,
(ProtobufList) list,
getEnumFieldVerifier(bufferPosition),
null,
(UnknownFieldSchema) unknownFieldSchema);
break;
case 33: // SINT32_LIST:
case 47: // SINT32_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedSInt32List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeSInt32List(tag, data, position, limit, list, registers);
}
break;
case 34: // SINT64_LIST:
case 48: // SINT64_LIST_PACKED:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodePackedSInt64List(data, position, list, registers);
} else if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeSInt64List(tag, data, position, limit, list, registers);
}
break;
case 49: // GROUP_LIST:
if (wireType == WireFormat.WIRETYPE_START_GROUP) {
position =
decodeGroupList(
getMessageFieldSchema(bufferPosition),
tag,
data,
position,
limit,
list,
registers);
}
break;
default:
break;
}
return position;
}
private int parseMapField(
T message,
byte[] data,
int position,
int limit,
int bufferPosition,
long fieldOffset,
Registers registers)
throws IOException {
final sun.misc.Unsafe unsafe = UNSAFE;
Object mapDefaultEntry = getMapFieldDefaultEntry(bufferPosition);
Object mapField = unsafe.getObject(message, fieldOffset);
if (mapFieldSchema.isImmutable(mapField)) {
Object oldMapField = mapField;
mapField = mapFieldSchema.newMapField(mapDefaultEntry);
mapFieldSchema.mergeFrom(mapField, oldMapField);
unsafe.putObject(message, fieldOffset, mapField);
}
return decodeMapEntry(
data,
position,
limit,
(Metadata) mapFieldSchema.forMapMetadata(mapDefaultEntry),
(Map) mapFieldSchema.forMutableMapData(mapField),
registers);
}
private int parseOneofField(
T message,
byte[] data,
int position,
int limit,
int tag,
int number,
int wireType,
int typeAndOffset,
int fieldType,
long fieldOffset,
int bufferPosition,
Registers registers)
throws IOException {
final sun.misc.Unsafe unsafe = UNSAFE;
final long oneofCaseOffset = buffer[bufferPosition + 2] & OFFSET_MASK;
switch (fieldType) {
case 51: // ONEOF_DOUBLE:
if (wireType == WireFormat.WIRETYPE_FIXED64) {
unsafe.putObject(message, fieldOffset, decodeDouble(data, position));
position += 8;
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 52: // ONEOF_FLOAT:
if (wireType == WireFormat.WIRETYPE_FIXED32) {
unsafe.putObject(message, fieldOffset, decodeFloat(data, position));
position += 4;
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 53: // ONEOF_INT64:
case 54: // ONEOF_UINT64:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
unsafe.putObject(message, fieldOffset, registers.long1);
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 55: // ONEOF_INT32:
case 62: // ONEOF_UINT32:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
unsafe.putObject(message, fieldOffset, registers.int1);
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 56: // ONEOF_FIXED64:
case 65: // ONEOF_SFIXED64:
if (wireType == WireFormat.WIRETYPE_FIXED64) {
unsafe.putObject(message, fieldOffset, decodeFixed64(data, position));
position += 8;
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 57: // ONEOF_FIXED32:
case 64: // ONEOF_SFIXED32:
if (wireType == WireFormat.WIRETYPE_FIXED32) {
unsafe.putObject(message, fieldOffset, decodeFixed32(data, position));
position += 4;
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 58: // ONEOF_BOOL:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
unsafe.putObject(message, fieldOffset, registers.long1 != 0);
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 59: // ONEOF_STRING:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodeVarint32(data, position, registers);
final int length = registers.int1;
if (length == 0) {
unsafe.putObject(message, fieldOffset, "");
} else {
if ((typeAndOffset & ENFORCE_UTF8_MASK) != 0
&& !Utf8.isValidUtf8(data, position, position + length)) {
throw InvalidProtocolBufferException.invalidUtf8();
}
final String value = new String(data, position, length, Internal.UTF_8);
unsafe.putObject(message, fieldOffset, value);
position += length;
}
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 60: // ONEOF_MESSAGE:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
final Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition);
position =
mergeMessageField(
current, getMessageFieldSchema(bufferPosition), data, position, limit, registers);
storeOneofMessageField(message, number, bufferPosition, current);
}
break;
case 61: // ONEOF_BYTES:
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodeBytes(data, position, registers);
unsafe.putObject(message, fieldOffset, registers.object1);
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 63: // ONEOF_ENUM:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
final int enumValue = registers.int1;
EnumVerifier enumVerifier = getEnumFieldVerifier(bufferPosition);
if (enumVerifier == null || enumVerifier.isInRange(enumValue)) {
unsafe.putObject(message, fieldOffset, enumValue);
unsafe.putInt(message, oneofCaseOffset, number);
} else {
// UnknownFieldSetLite requires varint to be represented as Long.
getMutableUnknownFields(message).storeField(tag, (long) enumValue);
}
}
break;
case 66: // ONEOF_SINT32:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
unsafe.putObject(message, fieldOffset, CodedInputStream.decodeZigZag32(registers.int1));
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 67: // ONEOF_SINT64:
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
unsafe.putObject(message, fieldOffset, CodedInputStream.decodeZigZag64(registers.long1));
unsafe.putInt(message, oneofCaseOffset, number);
}
break;
case 68: // ONEOF_GROUP:
if (wireType == WireFormat.WIRETYPE_START_GROUP) {
final Object current = mutableOneofMessageFieldForMerge(message, number, bufferPosition);
final int endTag = (tag & ~0x7) | WireFormat.WIRETYPE_END_GROUP;
position =
mergeGroupField(
current,
getMessageFieldSchema(bufferPosition),
data,
position,
limit,
endTag,
registers);
storeOneofMessageField(message, number, bufferPosition, current);
}
break;
default:
break;
}
return position;
}
private Schema getMessageFieldSchema(int pos) {
final int index = pos / INTS_PER_FIELD * 2;
Schema schema = (Schema) objects[index];
if (schema != null) {
return schema;
}
schema = Protobuf.getInstance().schemaFor((Class) objects[index + 1]);
objects[index] = schema;
return schema;
}
private Object getMapFieldDefaultEntry(int pos) {
return objects[pos / INTS_PER_FIELD * 2];
}
private EnumVerifier getEnumFieldVerifier(int pos) {
return (EnumVerifier) objects[pos / INTS_PER_FIELD * 2 + 1];
}
/**
* Parses a message and returns the position after the message/group. If it's parsing a
* LENGTH_PREFIXED message (endDelimited == 0), returns limit if parsing is successful; If it's
* parsing a DELIMITED message aka group (endDelimited != 0), parsing ends when a tag ==
* endDelimited is encountered and the position after that tag is returned.
*/
@CanIgnoreReturnValue
int parseMessage(
T message, byte[] data, int position, int limit, int endDelimited, Registers registers)
throws IOException {
checkMutable(message);
final sun.misc.Unsafe unsafe = UNSAFE;
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
int currentPresenceField = 0;
int tag = 0;
int oldNumber = -1;
int pos = 0;
while (position < limit) {
tag = data[position++];
if (tag < 0) {
position = decodeVarint32(tag, data, position, registers);
tag = registers.int1;
}
final int number = tag >>> 3;
final int wireType = tag & 0x7;
if (number > oldNumber) {
pos = positionForFieldNumber(number, pos / INTS_PER_FIELD);
} else {
pos = positionForFieldNumber(number);
}
oldNumber = number;
if (pos == -1) {
// need to reset
pos = 0;
} else {
final int typeAndOffset = buffer[pos + 1];
final int fieldType = type(typeAndOffset);
final long fieldOffset = offset(typeAndOffset);
if (fieldType <= 17) {
// Fields with explicit presence (i.e. optional) have has-bits.
final int presenceMaskAndOffset = buffer[pos + 2];
final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
// We cache the 32-bit presence integer value and only write it back when parsing a field
// using a different presence integer.
if (presenceFieldOffset != currentPresenceFieldOffset) {
if (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) {
unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField);
}
currentPresenceFieldOffset = presenceFieldOffset;
// For fields without presence, we unconditionally write and discard
// the data.
currentPresenceField =
presenceFieldOffset == NO_PRESENCE_SENTINEL
? 0
: unsafe.getInt(message, (long) presenceFieldOffset);
}
switch (fieldType) {
case 0: // DOUBLE
if (wireType == WireFormat.WIRETYPE_FIXED64) {
UnsafeUtil.putDouble(message, fieldOffset, decodeDouble(data, position));
position += 8;
currentPresenceField |= presenceMask;
continue;
}
break;
case 1: // FLOAT
if (wireType == WireFormat.WIRETYPE_FIXED32) {
UnsafeUtil.putFloat(message, fieldOffset, decodeFloat(data, position));
position += 4;
currentPresenceField |= presenceMask;
continue;
}
break;
case 2: // INT64
case 3: // UINT64
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
unsafe.putLong(message, fieldOffset, registers.long1);
currentPresenceField |= presenceMask;
continue;
}
break;
case 4: // INT32
case 11: // UINT32
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
unsafe.putInt(message, fieldOffset, registers.int1);
currentPresenceField |= presenceMask;
continue;
}
break;
case 5: // FIXED64
case 14: // SFIXED64
if (wireType == WireFormat.WIRETYPE_FIXED64) {
unsafe.putLong(message, fieldOffset, decodeFixed64(data, position));
position += 8;
currentPresenceField |= presenceMask;
continue;
}
break;
case 6: // FIXED32
case 13: // SFIXED32
if (wireType == WireFormat.WIRETYPE_FIXED32) {
unsafe.putInt(message, fieldOffset, decodeFixed32(data, position));
position += 4;
currentPresenceField |= presenceMask;
continue;
}
break;
case 7: // BOOL
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
UnsafeUtil.putBoolean(message, fieldOffset, registers.long1 != 0);
currentPresenceField |= presenceMask;
continue;
}
break;
case 8: // STRING
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
if (isEnforceUtf8(typeAndOffset)) {
position = decodeStringRequireUtf8(data, position, registers);
} else {
position = decodeString(data, position, registers);
}
unsafe.putObject(message, fieldOffset, registers.object1);
currentPresenceField |= presenceMask;
continue;
}
break;
case 9: // MESSAGE
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
final Object current = mutableMessageFieldForMerge(message, pos);
position =
mergeMessageField(
current, getMessageFieldSchema(pos), data, position, limit, registers);
storeMessageField(message, pos, current);
currentPresenceField |= presenceMask;
continue;
}
break;
case 10: // BYTES
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
position = decodeBytes(data, position, registers);
unsafe.putObject(message, fieldOffset, registers.object1);
currentPresenceField |= presenceMask;
continue;
}
break;
case 12: // ENUM
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
final int enumValue = registers.int1;
EnumVerifier enumVerifier = getEnumFieldVerifier(pos);
if (!isLegacyEnumIsClosed(typeAndOffset)
|| enumVerifier == null
|| enumVerifier.isInRange(enumValue)) {
// Parse open enums and in-range closed enums into their fields directly.
unsafe.putInt(message, fieldOffset, enumValue);
currentPresenceField |= presenceMask;
} else {
// Store out-of-range closed enums in unknown fields.
// UnknownFieldSetLite requires varint to be represented as Long.
getMutableUnknownFields(message).storeField(tag, (long) enumValue);
}
continue;
}
break;
case 15: // SINT32
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint32(data, position, registers);
unsafe.putInt(
message, fieldOffset, CodedInputStream.decodeZigZag32(registers.int1));
currentPresenceField |= presenceMask;
continue;
}
break;
case 16: // SINT64
if (wireType == WireFormat.WIRETYPE_VARINT) {
position = decodeVarint64(data, position, registers);
unsafe.putLong(
message, fieldOffset, CodedInputStream.decodeZigZag64(registers.long1));
currentPresenceField |= presenceMask;
continue;
}
break;
case 17: // GROUP
if (wireType == WireFormat.WIRETYPE_START_GROUP) {
final Object current = mutableMessageFieldForMerge(message, pos);
final int endTag = (number << 3) | WireFormat.WIRETYPE_END_GROUP;
position =
mergeGroupField(
current,
getMessageFieldSchema(pos),
data,
position,
limit,
endTag,
registers);
storeMessageField(message, pos, current);
currentPresenceField |= presenceMask;
continue;
}
break;
default:
break;
}
} else if (fieldType == 27) {
// Handle repeated message field.
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
ProtobufList> list = (ProtobufList>) unsafe.getObject(message, fieldOffset);
if (!list.isModifiable()) {
final int size = list.size();
list =
list.mutableCopyWithCapacity(
size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2);
unsafe.putObject(message, fieldOffset, list);
}
position =
decodeMessageList(
getMessageFieldSchema(pos), tag, data, position, limit, list, registers);
continue;
}
} else if (fieldType <= 49) {
// Handle all other repeated fields.
final int oldPosition = position;
position =
parseRepeatedField(
message,
data,
position,
limit,
tag,
number,
wireType,
pos,
typeAndOffset,
fieldType,
fieldOffset,
registers);
if (position != oldPosition) {
continue;
}
} else if (fieldType == 50) {
if (wireType == WireFormat.WIRETYPE_LENGTH_DELIMITED) {
final int oldPosition = position;
position = parseMapField(message, data, position, limit, pos, fieldOffset, registers);
if (position != oldPosition) {
continue;
}
}
} else {
final int oldPosition = position;
position =
parseOneofField(
message,
data,
position,
limit,
tag,
number,
wireType,
typeAndOffset,
fieldType,
fieldOffset,
pos,
registers);
if (position != oldPosition) {
continue;
}
}
}
if (tag == endDelimited && endDelimited != 0) {
break;
}
if (hasExtensions
&& registers.extensionRegistry != ExtensionRegistryLite.getEmptyRegistry()) {
position = decodeExtensionOrUnknownField(
tag, data, position, limit, message, defaultInstance,
(UnknownFieldSchema) unknownFieldSchema,
registers);
} else {
position = decodeUnknownField(
tag, data, position, limit, getMutableUnknownFields(message), registers);
}
}
if (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) {
unsafe.putInt(message, (long) currentPresenceFieldOffset, currentPresenceField);
}
UnknownFieldSetLite unknownFields = null;
for (int i = checkInitializedCount; i < repeatedFieldOffsetStart; i++) {
unknownFields =
filterMapUnknownEnumValues(
message,
intArray[i],
unknownFields,
(UnknownFieldSchema) unknownFieldSchema,
message);
}
if (unknownFields != null) {
((UnknownFieldSchema) unknownFieldSchema)
.setBuilderToMessage(message, unknownFields);
}
if (endDelimited == 0) {
if (position != limit) {
throw InvalidProtocolBufferException.parseFailure();
}
} else {
if (position > limit || tag != endDelimited) {
throw InvalidProtocolBufferException.parseFailure();
}
}
return position;
}
private Object mutableMessageFieldForMerge(T message, int pos) {
final Schema fieldSchema = getMessageFieldSchema(pos);
final long offset = offset(typeAndOffsetAt(pos));
// Field not present, create a new one
if (!isFieldPresent(message, pos)) {
return fieldSchema.newInstance();
}
// Field present, if mutable, ready to merge
final Object current = UNSAFE.getObject(message, offset);
if (isMutable(current)) {
return current;
}
// Field present but immutable, make a new mutable copy
final Object newMessage = fieldSchema.newInstance();
if (current != null) {
fieldSchema.mergeFrom(newMessage, current);
}
return newMessage;
}
private void storeMessageField(T message, int pos, Object field) {
UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field);
setFieldPresent(message, pos);
}
private Object mutableOneofMessageFieldForMerge(T message, int fieldNumber, int pos) {
final Schema fieldSchema = getMessageFieldSchema(pos);
// Field not present, create it and mark it present
if (!isOneofPresent(message, fieldNumber, pos)) {
return fieldSchema.newInstance();
}
// Field present, if mutable, ready to merge
final Object current = UNSAFE.getObject(message, offset(typeAndOffsetAt(pos)));
if (isMutable(current)) {
return current;
}
// Field present but immutable, make a new mutable copy
final Object newMessage = fieldSchema.newInstance();
if (current != null) {
fieldSchema.mergeFrom(newMessage, current);
}
return newMessage;
}
private void storeOneofMessageField(T message, int fieldNumber, int pos, Object field) {
UNSAFE.putObject(message, offset(typeAndOffsetAt(pos)), field);
setOneofPresent(message, fieldNumber, pos);
}
@Override
public void mergeFrom(T message, byte[] data, int position, int limit, Registers registers)
throws IOException {
parseMessage(message, data, position, limit, 0, registers);
}
@Override
public void makeImmutable(T message) {
if (!isMutable(message)) {
return;
}
// TODO decide if we're keeping support for Full in schema classes and handle this
// better.
if (message instanceof GeneratedMessageLite) {
GeneratedMessageLite, ?> generatedMessage = ((GeneratedMessageLite, ?>) message);
generatedMessage.clearMemoizedSerializedSize();
generatedMessage.clearMemoizedHashCode();
generatedMessage.markImmutable();
}
final int bufferLength = buffer.length;
for (int pos = 0; pos < bufferLength; pos += INTS_PER_FIELD) {
final int typeAndOffset = typeAndOffsetAt(pos);
final long offset = offset(typeAndOffset);
switch (type(typeAndOffset)) {
case 17: // GROUP
case 9: // MESSAGE
if (isFieldPresent(message, pos)) {
getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
}
break;
case 60: // ONEOF_MESSAGE
case 68: // ONEOF_GROUP
if (isOneofPresent(message, numberAt(pos), pos)) {
getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
}
break;
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:
case 21: // UINT64_LIST:
case 22: // INT32_LIST:
case 23: // FIXED64_LIST:
case 24: // FIXED32_LIST:
case 25: // BOOL_LIST:
case 26: // STRING_LIST:
case 27: // MESSAGE_LIST:
case 28: // BYTES_LIST:
case 29: // UINT32_LIST:
case 30: // ENUM_LIST:
case 31: // SFIXED32_LIST:
case 32: // SFIXED64_LIST:
case 33: // SINT32_LIST:
case 34: // SINT64_LIST:
case 35: // DOUBLE_LIST_PACKED:
case 36: // FLOAT_LIST_PACKED:
case 37: // INT64_LIST_PACKED:
case 38: // UINT64_LIST_PACKED:
case 39: // INT32_LIST_PACKED:
case 40: // FIXED64_LIST_PACKED:
case 41: // FIXED32_LIST_PACKED:
case 42: // BOOL_LIST_PACKED:
case 43: // UINT32_LIST_PACKED:
case 44: // ENUM_LIST_PACKED:
case 45: // SFIXED32_LIST_PACKED:
case 46: // SFIXED64_LIST_PACKED:
case 47: // SINT32_LIST_PACKED:
case 48: // SINT64_LIST_PACKED:
case 49: // GROUP_LIST:
listFieldSchema.makeImmutableListAt(message, offset);
break;
case 50: // MAP:
{
Object mapField = UNSAFE.getObject(message, offset);
if (mapField != null) {
UNSAFE.putObject(message, offset, mapFieldSchema.toImmutable(mapField));
}
}
break;
}
}
unknownFieldSchema.makeImmutable(message);
if (hasExtensions) {
extensionSchema.makeImmutable(message);
}
}
@SuppressWarnings("unchecked")
private final void mergeMap(
Object message,
int pos,
Object mapDefaultEntry,
ExtensionRegistryLite extensionRegistry,
Reader reader)
throws IOException {
long offset = offset(typeAndOffsetAt(pos));
Object mapField = UnsafeUtil.getObject(message, offset);
// TODO: Consider creating separate implementations for full and lite. In lite
// runtime map field will never be null but here we still need to check null because the
// code is shared by both full and lite. It might be better if full/lite uses different
// schema implementations.
if (mapField == null) {
mapField = mapFieldSchema.newMapField(mapDefaultEntry);
UnsafeUtil.putObject(message, offset, mapField);
} else if (mapFieldSchema.isImmutable(mapField)) {
Object oldMapField = mapField;
mapField = mapFieldSchema.newMapField(mapDefaultEntry);
mapFieldSchema.mergeFrom(mapField, oldMapField);
UnsafeUtil.putObject(message, offset, mapField);
}
reader.readMap(
(Map) mapFieldSchema.forMutableMapData(mapField),
(Metadata) mapFieldSchema.forMapMetadata(mapDefaultEntry),
extensionRegistry);
}
private UB filterMapUnknownEnumValues(
Object message,
int pos,
UB unknownFields,
UnknownFieldSchema unknownFieldSchema,
Object containerMessage) {
int fieldNumber = numberAt(pos);
long offset = offset(typeAndOffsetAt(pos));
Object mapField = UnsafeUtil.getObject(message, offset);
if (mapField == null) {
return unknownFields;
}
EnumVerifier enumVerifier = getEnumFieldVerifier(pos);
if (enumVerifier == null) {
return unknownFields;
}
Map, ?> mapData = mapFieldSchema.forMutableMapData(mapField);
// Filter unknown enum values.
unknownFields =
filterUnknownEnumMap(
pos,
fieldNumber,
mapData,
enumVerifier,
unknownFields,
unknownFieldSchema,
containerMessage);
return unknownFields;
}
@SuppressWarnings("unchecked")
private UB filterUnknownEnumMap(
int pos,
int number,
Map mapData,
EnumVerifier enumVerifier,
UB unknownFields,
UnknownFieldSchema unknownFieldSchema,
Object containerMessage) {
Metadata metadata =
(Metadata) mapFieldSchema.forMapMetadata(getMapFieldDefaultEntry(pos));
for (Iterator> it = mapData.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = it.next();
if (!enumVerifier.isInRange((Integer) entry.getValue())) {
if (unknownFields == null) {
unknownFields = unknownFieldSchema.getBuilderFromMessage(containerMessage);
}
int entrySize =
MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue());
CodedBuilder codedBuilder = ByteString.newCodedBuilder(entrySize);
CodedOutputStream codedOutput = codedBuilder.getCodedOutput();
try {
MapEntryLite.writeTo(codedOutput, metadata, entry.getKey(), entry.getValue());
} catch (IOException e) {
// Writing to ByteString CodedOutputStream should not throw IOException.
throw new RuntimeException(e);
}
unknownFieldSchema.addLengthDelimited(unknownFields, number, codedBuilder.build());
it.remove();
}
}
return unknownFields;
}
@Override
public final boolean isInitialized(T message) {
int currentPresenceFieldOffset = NO_PRESENCE_SENTINEL;
int currentPresenceField = 0;
for (int i = 0; i < checkInitializedCount; i++) {
final int pos = intArray[i];
final int number = numberAt(pos);
final int typeAndOffset = typeAndOffsetAt(pos);
int presenceMaskAndOffset = buffer[pos + 2];
final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
if (presenceFieldOffset != currentPresenceFieldOffset) {
currentPresenceFieldOffset = presenceFieldOffset;
if (currentPresenceFieldOffset != NO_PRESENCE_SENTINEL) {
currentPresenceField = UNSAFE.getInt(message, (long) presenceFieldOffset);
}
}
if (isRequired(typeAndOffset)) {
if (!isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)) {
return false;
}
// If a required message field is set but has no required fields of its own, we still
// proceed and check the message is initialized. It should be fairly cheap to check these
// messages but is worth documenting.
}
// Check nested message and groups.
switch (type(typeAndOffset)) {
case 9: // MESSAGE
case 17: // GROUP
if (isFieldPresent(
message, pos, currentPresenceFieldOffset, currentPresenceField, presenceMask)
&& !isInitialized(message, typeAndOffset, getMessageFieldSchema(pos))) {
return false;
}
break;
case 27: // MESSAGE_LIST
case 49: // GROUP_LIST
if (!isListInitialized(message, typeAndOffset, pos)) {
return false;
}
break;
case 60: // ONEOF_MESSAGE
case 68: // ONEOF_GROUP
if (isOneofPresent(message, number, pos)
&& !isInitialized(message, typeAndOffset, getMessageFieldSchema(pos))) {
return false;
}
break;
case 50: // MAP
if (!isMapInitialized(message, typeAndOffset, pos)) {
return false;
}
break;
default:
break;
}
}
if (hasExtensions) {
if (!extensionSchema.getExtensions(message).isInitialized()) {
return false;
}
}
return true;
}
private static boolean isInitialized(Object message, int typeAndOffset, Schema schema) {
Object nested = UnsafeUtil.getObject(message, offset(typeAndOffset));
return schema.isInitialized(nested);
}
private boolean isListInitialized(Object message, int typeAndOffset, int pos) {
@SuppressWarnings("unchecked")
List list = (List) UnsafeUtil.getObject(message, offset(typeAndOffset));
if (list.isEmpty()) {
return true;
}
Schema schema = getMessageFieldSchema(pos);
for (int i = 0; i < list.size(); i++) {
N nested = list.get(i);
if (!schema.isInitialized(nested)) {
return false;
}
}
return true;
}
private boolean isMapInitialized(T message, int typeAndOffset, int pos) {
Map, ?> map = mapFieldSchema.forMapData(UnsafeUtil.getObject(message, offset(typeAndOffset)));
if (map.isEmpty()) {
return true;
}
Object mapDefaultEntry = getMapFieldDefaultEntry(pos);
MapEntryLite.Metadata, ?> metadata = mapFieldSchema.forMapMetadata(mapDefaultEntry);
if (metadata.valueType.getJavaType() != WireFormat.JavaType.MESSAGE) {
return true;
}
// TODO: Use schema cache.
Schema schema = null;
for (Object nested : map.values()) {
if (schema == null) {
schema = Protobuf.getInstance().schemaFor(nested.getClass());
}
if (!schema.isInitialized(nested)) {
return false;
}
}
return true;
}
private void writeString(int fieldNumber, Object value, Writer writer) throws IOException {
if (value instanceof String) {
writer.writeString(fieldNumber, (String) value);
} else {
writer.writeBytes(fieldNumber, (ByteString) value);
}
}
private void readString(Object message, int typeAndOffset, Reader reader) throws IOException {
if (isEnforceUtf8(typeAndOffset)) {
// Enforce valid UTF-8 on the read.
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readStringRequireUtf8());
} else if (lite) {
// Lite messages use String fields to store strings. Read a string but do not
// enforce UTF-8
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readString());
} else {
// Full runtime messages use Objects to store either a String or ByteString. Read
// the string as a ByteString and do not enforce UTF-8.
UnsafeUtil.putObject(message, offset(typeAndOffset), reader.readBytes());
}
}
private void readStringList(Object message, int typeAndOffset, Reader reader) throws IOException {
if (isEnforceUtf8(typeAndOffset)) {
reader.readStringListRequireUtf8(
listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
} else {
reader.readStringList(listFieldSchema.mutableListAt(message, offset(typeAndOffset)));
}
}
private void readMessageList(
Object message,
int typeAndOffset,
Reader reader,
Schema schema,
ExtensionRegistryLite extensionRegistry)
throws IOException {
long offset = offset(typeAndOffset);
reader.readMessageList(
listFieldSchema.mutableListAt(message, offset), schema, extensionRegistry);
}
private void readGroupList(
Object message,
long offset,
Reader reader,
Schema schema,
ExtensionRegistryLite extensionRegistry)
throws IOException {
reader.readGroupList(
listFieldSchema.mutableListAt(message, offset), schema, extensionRegistry);
}
private int numberAt(int pos) {
return buffer[pos];
}
private int typeAndOffsetAt(int pos) {
return buffer[pos + 1];
}
private int presenceMaskAndOffsetAt(int pos) {
return buffer[pos + 2];
}
private static int type(int value) {
return (value & FIELD_TYPE_MASK) >>> OFFSET_BITS;
}
private static boolean isRequired(int value) {
return (value & REQUIRED_MASK) != 0;
}
private static boolean isEnforceUtf8(int value) {
return (value & ENFORCE_UTF8_MASK) != 0;
}
private static boolean isLegacyEnumIsClosed(int value) {
return (value & LEGACY_ENUM_IS_CLOSED_MASK) != 0;
}
private static long offset(int value) {
return value & OFFSET_MASK;
}
private static boolean isMutable(Object message) {
if (message == null) {
return false;
}
// TODO decide if we're keeping support for Full in schema classes and handle this
// better.
if (message instanceof GeneratedMessageLite, ?>) {
return ((GeneratedMessageLite, ?>) message).isMutable();
}
// For other types, we'll assume this is true because that's what was
// happening before we started checking.
return true;
}
private static void checkMutable(Object message) {
if (!isMutable(message)) {
throw new IllegalArgumentException("Mutating immutable message: " + message);
}
}
private static double doubleAt(T message, long offset) {
return UnsafeUtil.getDouble(message, offset);
}
private static float floatAt(T message, long offset) {
return UnsafeUtil.getFloat(message, offset);
}
private static int intAt(T message, long offset) {
return UnsafeUtil.getInt(message, offset);
}
private static long longAt(T message, long offset) {
return UnsafeUtil.getLong(message, offset);
}
private static boolean booleanAt(T message, long offset) {
return UnsafeUtil.getBoolean(message, offset);
}
private static double oneofDoubleAt(T message, long offset) {
return ((Double) UnsafeUtil.getObject(message, offset)).doubleValue();
}
private static float oneofFloatAt(T message, long offset) {
return ((Float) UnsafeUtil.getObject(message, offset)).floatValue();
}
private static int oneofIntAt(T message, long offset) {
return ((Integer) UnsafeUtil.getObject(message, offset)).intValue();
}
private static long oneofLongAt(T message, long offset) {
return ((Long) UnsafeUtil.getObject(message, offset)).longValue();
}
private static boolean oneofBooleanAt(T message, long offset) {
return ((Boolean) UnsafeUtil.getObject(message, offset)).booleanValue();
}
/** Returns true the field is present in both messages, or neither. */
private boolean arePresentForEquals(T message, T other, int pos) {
return isFieldPresent(message, pos) == isFieldPresent(other, pos);
}
private boolean isFieldPresent(
T message, int pos, int presenceFieldOffset, int presenceField, int presenceMask) {
if (presenceFieldOffset == NO_PRESENCE_SENTINEL) {
return isFieldPresent(message, pos);
} else {
return (presenceField & presenceMask) != 0;
}
}
private boolean isFieldPresent(T message, int pos) {
final int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos);
final long presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
if (presenceFieldOffset == NO_PRESENCE_SENTINEL) {
final int typeAndOffset = typeAndOffsetAt(pos);
final long offset = offset(typeAndOffset);
switch (type(typeAndOffset)) {
case 0: // DOUBLE:
return Double.doubleToRawLongBits(UnsafeUtil.getDouble(message, offset)) != 0L;
case 1: // FLOAT:
return Float.floatToRawIntBits(UnsafeUtil.getFloat(message, offset)) != 0;
case 2: // INT64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 3: // UINT64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 4: // INT32:
return UnsafeUtil.getInt(message, offset) != 0;
case 5: // FIXED64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 6: // FIXED32:
return UnsafeUtil.getInt(message, offset) != 0;
case 7: // BOOL:
return UnsafeUtil.getBoolean(message, offset);
case 8: // STRING:
Object value = UnsafeUtil.getObject(message, offset);
if (value instanceof String) {
return !((String) value).isEmpty();
} else if (value instanceof ByteString) {
return !ByteString.EMPTY.equals(value);
} else {
throw new IllegalArgumentException();
}
case 9: // MESSAGE:
return UnsafeUtil.getObject(message, offset) != null;
case 10: // BYTES:
return !ByteString.EMPTY.equals(UnsafeUtil.getObject(message, offset));
case 11: // UINT32:
return UnsafeUtil.getInt(message, offset) != 0;
case 12: // ENUM:
return UnsafeUtil.getInt(message, offset) != 0;
case 13: // SFIXED32:
return UnsafeUtil.getInt(message, offset) != 0;
case 14: // SFIXED64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 15: // SINT32:
return UnsafeUtil.getInt(message, offset) != 0;
case 16: // SINT64:
return UnsafeUtil.getLong(message, offset) != 0L;
case 17: // GROUP:
return UnsafeUtil.getObject(message, offset) != null;
default:
throw new IllegalArgumentException();
}
} else {
final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
return (UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) & presenceMask) != 0;
}
}
private void setFieldPresent(T message, int pos) {
int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos);
final long presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
if (presenceFieldOffset == NO_PRESENCE_SENTINEL) {
return;
}
final int presenceMask = 1 << (presenceMaskAndOffset >>> OFFSET_BITS);
UnsafeUtil.putInt(
message,
presenceFieldOffset,
UnsafeUtil.getInt(message, presenceFieldOffset) | presenceMask);
}
private boolean isOneofPresent(T message, int fieldNumber, int pos) {
int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos);
return UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK) == fieldNumber;
}
private boolean isOneofCaseEqual(T message, T other, int pos) {
int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos);
return UnsafeUtil.getInt(message, presenceMaskAndOffset & OFFSET_MASK)
== UnsafeUtil.getInt(other, presenceMaskAndOffset & OFFSET_MASK);
}
private void setOneofPresent(T message, int fieldNumber, int pos) {
int presenceMaskAndOffset = presenceMaskAndOffsetAt(pos);
UnsafeUtil.putInt(message, presenceMaskAndOffset & OFFSET_MASK, fieldNumber);
}
private int positionForFieldNumber(final int number) {
if (number >= minFieldNumber && number <= maxFieldNumber) {
return slowPositionForFieldNumber(number, 0);
}
return -1;
}
private int positionForFieldNumber(final int number, final int min) {
if (number >= minFieldNumber && number <= maxFieldNumber) {
return slowPositionForFieldNumber(number, min);
}
return -1;
}
private int slowPositionForFieldNumber(final int number, int min) {
int max = buffer.length / INTS_PER_FIELD - 1;
while (min <= max) {
// Find the midpoint address.
final int mid = (max + min) >>> 1;
final int pos = mid * INTS_PER_FIELD;
final int midFieldNumber = numberAt(pos);
if (number == midFieldNumber) {
// Found the field.
return pos;
}
if (number < midFieldNumber) {
// Search the lower half.
max = mid - 1;
} else {
// Search the upper half.
min = mid + 1;
}
}
return -1;
}
int getSchemaSize() {
return buffer.length * 3;
}
}