All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.protobuf.MessageSchema Maven / Gradle / Ivy

Go to download

Core Protocol Buffers library. Protocol Buffers are a way of encoding structured data in an efficient yet extensible format.

The newest version!
// 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; // 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, 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.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(), /* 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 combinedLength = checkInitialized.length + mapFieldPositions.length + repeatedFieldOffsets.length; int[] combined; if (combinedLength > 0) { combined = new int[combinedLength]; 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); } else { combined = EMPTY_INT_ARRAY; } return new MessageSchema( buffer, objects, minFieldNumber, maxFieldNumber, messageInfo.getDefaultInstance(), /* 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> 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> 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 * 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy