// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package com.google.protobuf; import com.google.protobuf.FieldSet.FieldDescriptorLite; import com.google.protobuf.Internal.EnumLiteMap; import com.google.protobuf.Internal.EnumVerifier; import java.io.IOException; import java.lang.reflect.Field; import java.util.Iterator; import java.util.List; import java.util.RandomAccess; /** Helper methods used by schemas. */ @ExperimentalApi @CheckReturnValue final class SchemaUtil { private static final Class GENERATED_MESSAGE_CLASS = getGeneratedMessageClass(); private static final UnknownFieldSchema PROTO2_UNKNOWN_FIELD_SET_SCHEMA = getUnknownFieldSetSchema(false); private static final UnknownFieldSchema PROTO3_UNKNOWN_FIELD_SET_SCHEMA = getUnknownFieldSetSchema(true); private static final UnknownFieldSchema UNKNOWN_FIELD_SET_LITE_SCHEMA = new UnknownFieldSetLiteSchema(); private static final int DEFAULT_LOOK_UP_START_NUMBER = 40; private SchemaUtil() {} /** * Requires that the given message extend {@link com.google.protobuf.GeneratedMessageV3} or {@link * GeneratedMessageLite}. */ public static void requireGeneratedMessage(Class messageType) { // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle this // better. if (!GeneratedMessageLite.class.isAssignableFrom(messageType) && GENERATED_MESSAGE_CLASS != null && !GENERATED_MESSAGE_CLASS.isAssignableFrom(messageType)) { throw new IllegalArgumentException( "Message classes must extend GeneratedMessageV3 or GeneratedMessageLite"); } } public static void writeDouble(int fieldNumber, double value, Writer writer) throws IOException { if (Double.doubleToRawLongBits(value) != 0) { writer.writeDouble(fieldNumber, value); } } public static void writeFloat(int fieldNumber, float value, Writer writer) throws IOException { if (Float.floatToRawIntBits(value) != 0) { writer.writeFloat(fieldNumber, value); } } public static void writeInt64(int fieldNumber, long value, Writer writer) throws IOException { if (value != 0) { writer.writeInt64(fieldNumber, value); } } public static void writeUInt64(int fieldNumber, long value, Writer writer) throws IOException { if (value != 0) { writer.writeUInt64(fieldNumber, value); } } public static void writeSInt64(int fieldNumber, long value, Writer writer) throws IOException { if (value != 0) { writer.writeSInt64(fieldNumber, value); } } public static void writeFixed64(int fieldNumber, long value, Writer writer) throws IOException { if (value != 0) { writer.writeFixed64(fieldNumber, value); } } public static void writeSFixed64(int fieldNumber, long value, Writer writer) throws IOException { if (value != 0) { writer.writeSFixed64(fieldNumber, value); } } public static void writeInt32(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeInt32(fieldNumber, value); } } public static void writeUInt32(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeUInt32(fieldNumber, value); } } public static void writeSInt32(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeSInt32(fieldNumber, value); } } public static void writeFixed32(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeFixed32(fieldNumber, value); } } public static void writeSFixed32(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeSFixed32(fieldNumber, value); } } public static void writeEnum(int fieldNumber, int value, Writer writer) throws IOException { if (value != 0) { writer.writeEnum(fieldNumber, value); } } public static void writeBool(int fieldNumber, boolean value, Writer writer) throws IOException { if (value) { writer.writeBool(fieldNumber, true); } } public static void writeString(int fieldNumber, Object value, Writer writer) throws IOException { if (value instanceof String) { writeStringInternal(fieldNumber, (String) value, writer); } else { writeBytes(fieldNumber, (ByteString) value, writer); } } private static void writeStringInternal(int fieldNumber, String value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeString(fieldNumber, value); } } public static void writeBytes(int fieldNumber, ByteString value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeBytes(fieldNumber, value); } } public static void writeMessage(int fieldNumber, Object value, Writer writer) throws IOException { if (value != null) { writer.writeMessage(fieldNumber, value); } } public static void writeDoubleList( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeDoubleList(fieldNumber, value, packed); } } public static void writeFloatList( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeFloatList(fieldNumber, value, packed); } } public static void writeInt64List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeInt64List(fieldNumber, value, packed); } } public static void writeUInt64List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeUInt64List(fieldNumber, value, packed); } } public static void writeSInt64List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeSInt64List(fieldNumber, value, packed); } } public static void writeFixed64List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeFixed64List(fieldNumber, value, packed); } } public static void writeSFixed64List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeSFixed64List(fieldNumber, value, packed); } } public static void writeInt32List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeInt32List(fieldNumber, value, packed); } } public static void writeUInt32List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeUInt32List(fieldNumber, value, packed); } } public static void writeSInt32List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeSInt32List(fieldNumber, value, packed); } } public static void writeFixed32List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeFixed32List(fieldNumber, value, packed); } } public static void writeSFixed32List( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeSFixed32List(fieldNumber, value, packed); } } public static void writeEnumList( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeEnumList(fieldNumber, value, packed); } } public static void writeBoolList( int fieldNumber, List value, Writer writer, boolean packed) throws IOException { if (value != null && !value.isEmpty()) { writer.writeBoolList(fieldNumber, value, packed); } } public static void writeStringList(int fieldNumber, List value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeStringList(fieldNumber, value); } } public static void writeBytesList(int fieldNumber, List value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeBytesList(fieldNumber, value); } } public static void writeMessageList(int fieldNumber, List value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeMessageList(fieldNumber, value); } } public static void writeMessageList(int fieldNumber, List value, Writer writer, Schema schema) throws IOException { if (value != null && !value.isEmpty()) { writer.writeMessageList(fieldNumber, value, schema); } } public static void writeLazyFieldList(int fieldNumber, List value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { for (Object item : value) { ((LazyFieldLite) item).writeTo(writer, fieldNumber); } } } public static void writeGroupList(int fieldNumber, List value, Writer writer) throws IOException { if (value != null && !value.isEmpty()) { writer.writeGroupList(fieldNumber, value); } } public static void writeGroupList(int fieldNumber, List value, Writer writer, Schema schema) throws IOException { if (value != null && !value.isEmpty()) { writer.writeGroupList(fieldNumber, value, schema); } } static int computeSizeInt64ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof LongArrayList) { final LongArrayList primitiveList = (LongArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeInt64SizeNoTag(primitiveList.getLong(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeInt64SizeNoTag(list.get(i)); } } return size; } static int computeSizeInt64List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeInt64ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (list.size() * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeUInt64ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof LongArrayList) { final LongArrayList primitiveList = (LongArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeUInt64SizeNoTag(primitiveList.getLong(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeUInt64SizeNoTag(list.get(i)); } } return size; } static int computeSizeUInt64List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeUInt64ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeSInt64ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof LongArrayList) { final LongArrayList primitiveList = (LongArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeSInt64SizeNoTag(primitiveList.getLong(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeSInt64SizeNoTag(list.get(i)); } } return size; } static int computeSizeSInt64List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeSInt64ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeEnumListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof IntArrayList) { final IntArrayList primitiveList = (IntArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeEnumSizeNoTag(primitiveList.getInt(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeEnumSizeNoTag(list.get(i)); } } return size; } static int computeSizeEnumList(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeEnumListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeInt32ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof IntArrayList) { final IntArrayList primitiveList = (IntArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeInt32SizeNoTag(primitiveList.getInt(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeInt32SizeNoTag(list.get(i)); } } return size; } static int computeSizeInt32List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeInt32ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeUInt32ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof IntArrayList) { final IntArrayList primitiveList = (IntArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeUInt32SizeNoTag(primitiveList.getInt(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeUInt32SizeNoTag(list.get(i)); } } return size; } static int computeSizeUInt32List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeUInt32ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeSInt32ListNoTag(List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; if (list instanceof IntArrayList) { final IntArrayList primitiveList = (IntArrayList) list; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeSInt32SizeNoTag(primitiveList.getInt(i)); } } else { for (int i = 0; i < length; i++) { size += CodedOutputStream.computeSInt32SizeNoTag(list.get(i)); } } return size; } static int computeSizeSInt32List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } int size = computeSizeSInt32ListNoTag(list); if (packed) { return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(size); } else { return size + (length * CodedOutputStream.computeTagSize(fieldNumber)); } } static int computeSizeFixed32ListNoTag(List list) { return list.size() * WireFormat.FIXED32_SIZE; } static int computeSizeFixed32List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } if (packed) { int dataSize = length * WireFormat.FIXED32_SIZE; return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize); } else { return length * CodedOutputStream.computeFixed32Size(fieldNumber, 0); } } static int computeSizeFixed64ListNoTag(List list) { return list.size() * WireFormat.FIXED64_SIZE; } static int computeSizeFixed64List(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } if (packed) { final int dataSize = length * WireFormat.FIXED64_SIZE; return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(dataSize); } else { return length * CodedOutputStream.computeFixed64Size(fieldNumber, 0); } } static int computeSizeBoolListNoTag(List list) { // bools are 1 byte varints return list.size(); } static int computeSizeBoolList(int fieldNumber, List list, boolean packed) { final int length = list.size(); if (length == 0) { return 0; } if (packed) { // bools are 1 byte varints return CodedOutputStream.computeTagSize(fieldNumber) + CodedOutputStream.computeLengthDelimitedFieldSize(length); } else { return length * CodedOutputStream.computeBoolSize(fieldNumber, true); } } static int computeSizeStringList(int fieldNumber, List list) { final int length = list.size(); if (length == 0) { return 0; } int size = length * CodedOutputStream.computeTagSize(fieldNumber); if (list instanceof LazyStringList) { LazyStringList lazyList = ((LazyStringList) list); for (int i = 0; i < length; i++) { Object value = lazyList.getRaw(i); if (value instanceof ByteString) { size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value); } else { size += CodedOutputStream.computeStringSizeNoTag((String) value); } } } else { for (int i = 0; i < length; i++) { Object value = list.get(i); if (value instanceof ByteString) { size += CodedOutputStream.computeBytesSizeNoTag((ByteString) value); } else { size += CodedOutputStream.computeStringSizeNoTag((String) value); } } } return size; } static int computeSizeMessage(int fieldNumber, Object value, Schema schema) { if (value instanceof LazyFieldLite) { return CodedOutputStream.computeLazyFieldSize(fieldNumber, (LazyFieldLite) value); } else { return CodedOutputStream.computeMessageSize(fieldNumber, (MessageLite) value, schema); } } static int computeSizeMessageList(int fieldNumber, List list) { final int length = list.size(); if (length == 0) { return 0; } int size = length * CodedOutputStream.computeTagSize(fieldNumber); for (int i = 0; i < length; i++) { Object value = list.get(i); if (value instanceof LazyFieldLite) { size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value); } else { size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value); } } return size; } static int computeSizeMessageList(int fieldNumber, List list, Schema schema) { final int length = list.size(); if (length == 0) { return 0; } int size = length * CodedOutputStream.computeTagSize(fieldNumber); for (int i = 0; i < length; i++) { Object value = list.get(i); if (value instanceof LazyFieldLite) { size += CodedOutputStream.computeLazyFieldSizeNoTag((LazyFieldLite) value); } else { size += CodedOutputStream.computeMessageSizeNoTag((MessageLite) value, schema); } } return size; } static int computeSizeByteStringList(int fieldNumber, List list) { final int length = list.size(); if (length == 0) { return 0; } int size = length * CodedOutputStream.computeTagSize(fieldNumber); for (int i = 0; i < list.size(); i++) { size += CodedOutputStream.computeBytesSizeNoTag(list.get(i)); } return size; } static int computeSizeGroupList(int fieldNumber, List list) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i)); } return size; } static int computeSizeGroupList(int fieldNumber, List list, Schema schema) { final int length = list.size(); if (length == 0) { return 0; } int size = 0; for (int i = 0; i < length; i++) { size += CodedOutputStream.computeGroupSize(fieldNumber, list.get(i), schema); } return size; } /** * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method. * * @see #shouldUseTableSwitch(int, int, int) */ public static boolean shouldUseTableSwitch(FieldInfo[] fields) { // Determine whether to issue a tableswitch or a lookupswitch // instruction. if (fields.length == 0) { return false; } int lo = fields[0].getFieldNumber(); int hi = fields[fields.length - 1].getFieldNumber(); return shouldUseTableSwitch(lo, hi, fields.length); } /** * Determines whether to issue tableswitch or lookupswitch for the mergeFrom method. This is based * on the * logic in the JDK. * * @param lo the lowest fieldNumber contained within the message. * @param hi the highest fieldNumber contained within the message. * @param numFields the total number of fields in the message. * @return {@code true} if tableswitch should be used, rather than lookupswitch. */ public static boolean shouldUseTableSwitch(int lo, int hi, int numFields) { if (hi < DEFAULT_LOOK_UP_START_NUMBER) { return true; } long tableSpaceCost = ((long) hi - lo + 1); // words long tableTimeCost = 3; // comparisons long lookupSpaceCost = 3 + 2 * (long) numFields; long lookupTimeCost = 3 + (long) numFields; return tableSpaceCost + 3 * tableTimeCost <= lookupSpaceCost + 3 * lookupTimeCost; } public static UnknownFieldSchema proto2UnknownFieldSetSchema() { return PROTO2_UNKNOWN_FIELD_SET_SCHEMA; } public static UnknownFieldSchema proto3UnknownFieldSetSchema() { return PROTO3_UNKNOWN_FIELD_SET_SCHEMA; } public static UnknownFieldSchema unknownFieldSetLiteSchema() { return UNKNOWN_FIELD_SET_LITE_SCHEMA; } private static UnknownFieldSchema getUnknownFieldSetSchema(boolean proto3) { try { Class clz = getUnknownFieldSetSchemaClass(); if (clz == null) { return null; } return (UnknownFieldSchema) clz.getConstructor(boolean.class).newInstance(proto3); } catch (Throwable t) { return null; } } private static Class getGeneratedMessageClass() { try { // TODO(b/248560713) decide if we're keeping support for Full in schema classes and handle // this better. return Class.forName("com.google.protobuf.GeneratedMessageV3"); } catch (Throwable e) { return null; } } private static Class getUnknownFieldSetSchemaClass() { try { return Class.forName("com.google.protobuf.UnknownFieldSetSchema"); } catch (Throwable e) { return null; } } static Object getMapDefaultEntry(Class clazz, String name) { try { Class holder = Class.forName(clazz.getName() + "$" + toCamelCase(name, true) + "DefaultEntryHolder"); Field[] fields = holder.getDeclaredFields(); if (fields.length != 1) { throw new IllegalStateException( "Unable to look up map field default entry holder class for " + name + " in " + clazz.getName()); } return UnsafeUtil.getStaticObject(fields[0]); } catch (Throwable t) { throw new RuntimeException(t); } } static String toCamelCase(String name, boolean capNext) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); ++i) { char c = name.charAt(i); // Matches protoc field name function: if ('a' <= c && c <= 'z') { if (capNext) { sb.append((char) (c + ('A' - 'a'))); } else { sb.append(c); } capNext = false; } else if ('A' <= c && c <= 'Z') { if (i == 0 && !capNext) { // Force first letter to lower-case unless explicitly told to capitalize it. sb.append((char) (c - ('A' - 'a'))); } else { sb.append(c); } capNext = false; } else if ('0' <= c && c <= '9') { sb.append(c); capNext = true; } else { capNext = true; } } return sb.toString(); } /** Returns true if both are null or both are {@link Object#equals}. */ static boolean safeEquals(Object a, Object b) { return a == b || (a != null && a.equals(b)); } static void mergeMap(MapFieldSchema mapFieldSchema, T message, T o, long offset) { Object merged = mapFieldSchema.mergeFrom( UnsafeUtil.getObject(message, offset), UnsafeUtil.getObject(o, offset)); UnsafeUtil.putObject(message, offset, merged); } static > void mergeExtensions( ExtensionSchema schema, T message, T other) { FieldSet otherExtensions = schema.getExtensions(other); if (!otherExtensions.isEmpty()) { FieldSet messageExtensions = schema.getMutableExtensions(message); messageExtensions.mergeFrom(otherExtensions); } } static void mergeUnknownFields( UnknownFieldSchema schema, T message, T other) { UT messageUnknowns = schema.getFromMessage(message); UT otherUnknowns = schema.getFromMessage(other); UT merged = schema.merge(messageUnknowns, otherUnknowns); schema.setToMessage(message, merged); } /** Filters unrecognized enum values in a list. */ @CanIgnoreReturnValue static UB filterUnknownEnumList( Object containerMessage, int number, List enumList, EnumLiteMap enumMap, UB unknownFields, UnknownFieldSchema unknownFieldSchema) { if (enumMap == null) { return unknownFields; } // TODO(dweis): Specialize for IntArrayList to avoid boxing. if (enumList instanceof RandomAccess) { int writePos = 0; int size = enumList.size(); for (int readPos = 0; readPos < size; ++readPos) { int enumValue = enumList.get(readPos); if (enumMap.findValueByNumber(enumValue) != null) { if (readPos != writePos) { enumList.set(writePos, enumValue); } ++writePos; } else { unknownFields = storeUnknownEnum( containerMessage, number, enumValue, unknownFields, unknownFieldSchema); } } if (writePos != size) { enumList.subList(writePos, size).clear(); } } else { for (Iterator it = enumList.iterator(); it.hasNext(); ) { int enumValue = it.next(); if (enumMap.findValueByNumber(enumValue) == null) { unknownFields = storeUnknownEnum( containerMessage, number, enumValue, unknownFields, unknownFieldSchema); it.remove(); } } } return unknownFields; } /** Filters unrecognized enum values in a list. */ @CanIgnoreReturnValue static UB filterUnknownEnumList( Object containerMessage, int number, List enumList, EnumVerifier enumVerifier, UB unknownFields, UnknownFieldSchema unknownFieldSchema) { if (enumVerifier == null) { return unknownFields; } // TODO(dweis): Specialize for IntArrayList to avoid boxing. if (enumList instanceof RandomAccess) { int writePos = 0; int size = enumList.size(); for (int readPos = 0; readPos < size; ++readPos) { int enumValue = enumList.get(readPos); if (enumVerifier.isInRange(enumValue)) { if (readPos != writePos) { enumList.set(writePos, enumValue); } ++writePos; } else { unknownFields = storeUnknownEnum( containerMessage, number, enumValue, unknownFields, unknownFieldSchema); } } if (writePos != size) { enumList.subList(writePos, size).clear(); } } else { for (Iterator it = enumList.iterator(); it.hasNext(); ) { int enumValue = it.next(); if (!enumVerifier.isInRange(enumValue)) { unknownFields = storeUnknownEnum( containerMessage, number, enumValue, unknownFields, unknownFieldSchema); it.remove(); } } } return unknownFields; } /** Stores an unrecognized enum value as an unknown value. */ @CanIgnoreReturnValue static UB storeUnknownEnum( Object containerMessage, int number, int enumValue, UB unknownFields, UnknownFieldSchema unknownFieldSchema) { if (unknownFields == null) { unknownFields = unknownFieldSchema.getBuilderFromMessage(containerMessage); } unknownFieldSchema.addVarint(unknownFields, number, enumValue); return unknownFields; } }