diff --git a/.gitignore b/.gitignore index 6508eccb18..38755c96ae 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ src/.libs .dirstamp +any_test.pb.* map*unittest.pb.* unittest*.pb.* cpp_test*.pb.* diff --git a/Android.mk b/Android.mk index 18bdd0911f..bbd15740a9 100644 --- a/Android.mk +++ b/Android.mk @@ -90,14 +90,20 @@ COMPILER_SRC_FILES := \ src/google/protobuf/compiler/cpp/cpp_string_field.cc \ src/google/protobuf/compiler/java/java_enum.cc \ src/google/protobuf/compiler/java/java_enum_field.cc \ + src/google/protobuf/compiler/java/java_enum_field_lite.cc \ src/google/protobuf/compiler/java/java_extension.cc \ src/google/protobuf/compiler/java/java_field.cc \ src/google/protobuf/compiler/java/java_file.cc \ src/google/protobuf/compiler/java/java_generator.cc \ src/google/protobuf/compiler/java/java_helpers.cc \ src/google/protobuf/compiler/java/java_message.cc \ + src/google/protobuf/compiler/java/java_message_lite.cc \ + src/google/protobuf/compiler/java/java_message_builder.cc \ + src/google/protobuf/compiler/java/java_message_builder_lite.cc \ src/google/protobuf/compiler/java/java_message_field.cc \ + src/google/protobuf/compiler/java/java_message_field_lite.cc \ src/google/protobuf/compiler/java/java_primitive_field.cc \ + src/google/protobuf/compiler/java/java_primitive_field_lite.cc \ src/google/protobuf/compiler/java/java_service.cc \ src/google/protobuf/compiler/javamicro/javamicro_enum.cc \ src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc \ diff --git a/Makefile.am b/Makefile.am index 45d44f5c51..645c924b14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,28 +43,34 @@ java_EXTRA_DIST= \ java/src/main/java/com/google/protobuf/AbstractMessage.java \ java/src/main/java/com/google/protobuf/AbstractMessageLite.java \ java/src/main/java/com/google/protobuf/AbstractParser.java \ + java/src/main/java/com/google/protobuf/AbstractProtobufList.java \ java/src/main/java/com/google/protobuf/BlockingRpcChannel.java \ java/src/main/java/com/google/protobuf/BlockingService.java \ java/src/main/java/com/google/protobuf/BoundedByteString.java \ + java/src/main/java/com/google/protobuf/BooleanArrayList.java \ java/src/main/java/com/google/protobuf/ByteString.java \ java/src/main/java/com/google/protobuf/CodedInputStream.java \ java/src/main/java/com/google/protobuf/CodedOutputStream.java \ java/src/main/java/com/google/protobuf/Descriptors.java \ + java/src/main/java/com/google/protobuf/DoubleArrayList.java \ java/src/main/java/com/google/protobuf/DynamicMessage.java \ java/src/main/java/com/google/protobuf/Extension.java \ java/src/main/java/com/google/protobuf/ExtensionLite.java \ java/src/main/java/com/google/protobuf/ExtensionRegistry.java \ java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \ java/src/main/java/com/google/protobuf/FieldSet.java \ + java/src/main/java/com/google/protobuf/FloatArrayList.java \ java/src/main/java/com/google/protobuf/GeneratedMessage.java \ java/src/main/java/com/google/protobuf/GeneratedMessageLite.java \ java/src/main/java/com/google/protobuf/Internal.java \ + java/src/main/java/com/google/protobuf/IntArrayList.java \ java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \ java/src/main/java/com/google/protobuf/LazyField.java \ java/src/main/java/com/google/protobuf/LazyFieldLite.java \ java/src/main/java/com/google/protobuf/LazyStringArrayList.java \ java/src/main/java/com/google/protobuf/LazyStringList.java \ java/src/main/java/com/google/protobuf/LiteralByteString.java \ + java/src/main/java/com/google/protobuf/LongArrayList.java \ java/src/main/java/com/google/protobuf/MapEntry.java \ java/src/main/java/com/google/protobuf/MapEntryLite.java \ java/src/main/java/com/google/protobuf/MapField.java \ @@ -74,7 +80,9 @@ java_EXTRA_DIST= \ java/src/main/java/com/google/protobuf/MessageLiteOrBuilder.java \ java/src/main/java/com/google/protobuf/MessageOrBuilder.java \ java/src/main/java/com/google/protobuf/MessageReflection.java \ + java/src/main/java/com/google/protobuf/MutabilityOracle.java \ java/src/main/java/com/google/protobuf/Parser.java \ + java/src/main/java/com/google/protobuf/ProtobufArrayList.java \ java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \ java/src/main/java/com/google/protobuf/ProtocolStringList.java \ java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java \ @@ -96,16 +104,20 @@ java_EXTRA_DIST= \ java/src/main/java/com/google/protobuf/WireFormat.java \ java/src/test/java/com/google/protobuf/AbstractMessageTest.java \ java/src/test/java/com/google/protobuf/BoundedByteStringTest.java \ + java/src/test/java/com/google/protobuf/BooleanArrayListTest.java \ java/src/test/java/com/google/protobuf/ByteStringTest.java \ java/src/test/java/com/google/protobuf/CheckUtf8Test.java \ java/src/test/java/com/google/protobuf/CodedInputStreamTest.java \ java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java \ java/src/test/java/com/google/protobuf/DeprecatedFieldTest.java \ java/src/test/java/com/google/protobuf/DescriptorsTest.java \ + java/src/test/java/com/google/protobuf/DoubleArrayListTest.java \ java/src/test/java/com/google/protobuf/DynamicMessageTest.java \ java/src/test/java/com/google/protobuf/FieldPresenceTest.java \ + java/src/test/java/com/google/protobuf/FloatArrayListTest.java \ java/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java \ java/src/test/java/com/google/protobuf/GeneratedMessageTest.java \ + java/src/test/java/com/google/protobuf/IntArrayListTest.java \ java/src/test/java/com/google/protobuf/IsValidUtf8Test.java \ java/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java \ java/src/test/java/com/google/protobuf/LazyFieldLiteTest.java \ @@ -116,12 +128,14 @@ java_EXTRA_DIST= \ java/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java \ java/src/test/java/com/google/protobuf/LiteralByteStringTest.java \ java/src/test/java/com/google/protobuf/LiteTest.java \ + java/src/test/java/com/google/protobuf/LongArrayListTest.java \ java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java \ java/src/test/java/com/google/protobuf/MapForProto2Test.java \ java/src/test/java/com/google/protobuf/MapTest.java \ java/src/test/java/com/google/protobuf/MessageTest.java \ java/src/test/java/com/google/protobuf/NestedBuildersTest.java \ java/src/test/java/com/google/protobuf/ParserTest.java \ + java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java \ java/src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java \ java/src/test/java/com/google/protobuf/RopeByteStringSubstringTest.java \ java/src/test/java/com/google/protobuf/RopeByteStringTest.java \ diff --git a/conformance/conformance.proto b/conformance/conformance.proto index 7b67689851..39eafdbb7c 100644 --- a/conformance/conformance.proto +++ b/conformance/conformance.proto @@ -71,7 +71,7 @@ message ConformanceRequest { } // Which format should the testee serialize its message to? - optional RequestedOutput requested_output = 3; + RequestedOutput requested_output = 3; } // Represents a single test case's output. @@ -103,8 +103,8 @@ message ConformanceResponse { // forms. message TestAllTypes { message NestedMessage { - optional int32 a = 1; - optional TestAllTypes corecursive = 2; + int32 a = 1; + TestAllTypes corecursive = 2; } enum NestedEnum { @@ -115,36 +115,32 @@ message TestAllTypes { } // Singular - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional group OptionalGroup = 16 { - optional int32 a = 17; - } - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessage optional_foreign_message = 19; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnum optional_foreign_enum = 22; - - optional string optional_string_piece = 24 [ctype=STRING_PIECE]; - optional string optional_cord = 25 [ctype=CORD]; - - optional TestAllTypes recursive_message = 27; + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; + + TestAllTypes recursive_message = 27; // Repeated repeated int32 repeated_int32 = 31; @@ -163,10 +159,6 @@ message TestAllTypes { repeated string repeated_string = 44; repeated bytes repeated_bytes = 45; - repeated group RepeatedGroup = 46 { - optional int32 a = 47; - } - repeated NestedMessage repeated_nested_message = 48; repeated ForeignMessage repeated_foreign_message = 49; @@ -206,7 +198,7 @@ message TestAllTypes { } message ForeignMessage { - optional int32 c = 1; + int32 c = 1; } enum ForeignEnum { diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc index 61029e44f8..857f215296 100644 --- a/conformance/conformance_test.cc +++ b/conformance/conformance_test.cc @@ -295,6 +295,7 @@ void ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, failures_ = 0; for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) { + if (i == FieldDescriptor::TYPE_GROUP) continue; TestPrematureEOFForType(static_cast(i)); } diff --git a/editors/proto.vim b/editors/proto.vim index 23085a28d8..7f1aeb730a 100644 --- a/editors/proto.vim +++ b/editors/proto.vim @@ -57,7 +57,7 @@ syn keyword pbSyntax syntax import option syn keyword pbStructure package message group oneof syn keyword pbRepeat optional required repeated syn keyword pbDefault default -syn keyword pbExtend extend extensions to max +syn keyword pbExtend extend extensions to max reserved syn keyword pbRPC service rpc returns syn keyword pbType int32 int64 uint32 uint64 sint32 sint64 diff --git a/editors/protobuf-mode.el b/editors/protobuf-mode.el index 09aecc9394..f615a0afbc 100644 --- a/editors/protobuf-mode.el +++ b/editors/protobuf-mode.el @@ -106,7 +106,7 @@ ;; cc-mode. So, we approximate as best we can. (c-lang-defconst c-type-list-kwds - protobuf '("extensions" "to")) + protobuf '("extensions" "to" "reserved")) (c-lang-defconst c-typeless-decl-kwds protobuf '("extend" "rpc" "option" "returns")) diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh index 27d293a2e5..89449e109b 100755 --- a/generate_descriptor_proto.sh +++ b/generate_descriptor_proto.sh @@ -43,8 +43,11 @@ declare -a RUNTIME_PROTO_FILES=(\ google/protobuf/wrappers.proto) CORE_PROTO_IS_CORRECT=0 +PROCESS_ROUND=1 +echo "Updating descriptor protos..." while [ $CORE_PROTO_IS_CORRECT -ne 1 ] do + echo "Round $PROCESS_ROUND" CORE_PROTO_IS_CORRECT=1 for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do BASE_NAME=${PROTO_FILE%.*} @@ -86,5 +89,7 @@ do done rm google/protobuf/compiler/plugin.pb.h.tmp rm google/protobuf/compiler/plugin.pb.cc.tmp + + PROCESS_ROUND=$((PROCESS_ROUND + 1)) done cd .. diff --git a/java/pom.xml b/java/pom.xml index 3eb7a70315..9f2701138a 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -134,6 +134,7 @@ + target/generated-test-sources @@ -227,25 +228,33 @@ **/AbstractMessageLite.java **/AbstractParser.java + **/AbstractProtobufList.java **/BoundedByteString.java + **/BooleanArrayList.java **/ByteString.java **/CodedInputStream.java **/CodedOutputStream.java + **/DoublerrayList.java **/ExtensionLite.java **/ExtensionRegistryLite.java **/FieldSet.java + **/FloatArrayList.java **/GeneratedMessageLite.java + **/IntArrayList.java **/Internal.java **/InvalidProtocolBufferException.java **/LazyFieldLite.java **/LazyStringArrayList.java **/LazyStringList.java **/LiteralByteString.java + **/LongArrayList.java **/MapEntryLite.java **/MapFieldLite.java **/MessageLite.java **/MessageLiteOrBuilder.java + **/MutabilityOracle.java **/Parser.java + **/ProtobufArrayList.java **/ProtocolStringList.java **/RopeByteString.java **/SmallSortedMap.java @@ -257,8 +266,14 @@ **/*Lite.java + **/BooleanArrayListTest.java + **/DoubleArrayListTest.java + **/FloatArrayListTest.java + **/IntArrayListTest.java **/LazyMessageLiteTest.java **/LiteTest.java + **/LongArrayListTest.java + **/ProtobufArrayListTest.java **/UnknownFieldSetLiteTest.java diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java index aac4fa7729..12384983e3 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java @@ -31,8 +31,8 @@ package com.google.protobuf; import java.io.FilterInputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; @@ -109,6 +109,11 @@ public abstract class AbstractMessageLite implements MessageLite { } } + protected static void addAll(final Iterable values, + final Collection list) { + Builder.addAll(values, list); + } + /** * A partial implementation of the {@link Message.Builder} interface which * implements as many methods of that interface as possible in terms of @@ -320,12 +325,15 @@ public abstract class AbstractMessageLite implements MessageLite { * Adds the {@code values} to the {@code list}. This is a helper method * used by generated code. Users should ignore it. * - * @throws NullPointerException if any of the elements of {@code values} is - * null. When that happens, some elements of {@code values} may have already - * been added to the result {@code list}. + * @throws NullPointerException if {@code values} or any of the elements of + * {@code values} is null. When that happens, some elements of + * {@code values} may have already been added to the result {@code list}. */ protected static void addAll(final Iterable values, final Collection list) { + if (values == null) { + throw new NullPointerException(); + } if (values instanceof LazyStringList) { // For StringOrByteStringLists, check the underlying elements to avoid // forcing conversions of ByteStrings to Strings. diff --git a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java new file mode 100644 index 0000000000..bb6446b2a2 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java @@ -0,0 +1,136 @@ +// 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.Internal.ProtobufList; + +import java.util.AbstractList; +import java.util.Collection; + +/** + * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate + * methods are check if the list is mutable before proceeding. Subclasses must invoke + * {@link #ensureIsMutable()} manually when overriding those methods. + */ +abstract class AbstractProtobufList extends AbstractList implements ProtobufList { + + /** + * Whether or not this list is modifiable. + */ + private boolean isMutable; + + /** + * Constructs a mutable list by default. + */ + AbstractProtobufList() { + isMutable = true; + } + + @Override + public boolean add(E e) { + ensureIsMutable(); + return super.add(e); + } + + @Override + public void add(int index, E element) { + ensureIsMutable(); + super.add(index, element); + } + + @Override + public boolean addAll(Collection c) { + ensureIsMutable(); + return super.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + ensureIsMutable(); + return super.addAll(index, c); + } + + @Override + public void clear() { + ensureIsMutable(); + super.clear(); + } + + @Override + public boolean isModifiable() { + return isMutable; + } + + @Override + public final void makeImmutable() { + isMutable = false; + } + + @Override + public E remove(int index) { + ensureIsMutable(); + return super.remove(index); + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + return super.remove(o); + } + + @Override + public boolean removeAll(Collection c) { + ensureIsMutable(); + return super.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + ensureIsMutable(); + return super.retainAll(c); + } + + @Override + public E set(int index, E element) { + ensureIsMutable(); + return super.set(index, element); + } + + /** + * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are + * responsible for invoking this method on mutate operations. + */ + protected void ensureIsMutable() { + if (!isMutable) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/src/main/java/com/google/protobuf/BooleanArrayList.java new file mode 100644 index 0000000000..45492d2fe7 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/BooleanArrayList.java @@ -0,0 +1,244 @@ +// 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.Internal.BooleanList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An implementation of {@link BooleanList} on top of a primitive array. + * + * @author dweis@google.com (Daniel Weis) + */ +final class BooleanArrayList + extends AbstractProtobufList implements BooleanList, RandomAccess { + + private static final int DEFAULT_CAPACITY = 10; + + private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + public static BooleanArrayList emptyList() { + return EMPTY_LIST; + } + + /** + * The backing store for the list. + */ + private boolean[] array; + + /** + * The size of the list distinct from the length of the array. That is, it is the number of + * elements set in the list. + */ + private int size; + + /** + * Constructs a new mutable {@code BooleanArrayList}. + */ + BooleanArrayList() { + array = new boolean[DEFAULT_CAPACITY]; + size = 0; + } + + /** + * Constructs a new mutable {@code BooleanArrayList} containing the same elements as + * {@code other}. + */ + BooleanArrayList(List other) { + if (other instanceof BooleanArrayList) { + BooleanArrayList list = (BooleanArrayList) other; + array = list.array.clone(); + size = list.size; + } else { + size = other.size(); + array = new boolean[size]; + for (int i = 0; i < size; i++) { + array[i] = other.get(i); + } + } + } + + @Override + public Boolean get(int index) { + return getBoolean(index); + } + + @Override + public boolean getBoolean(int index) { + ensureIndexInRange(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public Boolean set(int index, Boolean element) { + return setBoolean(index, element); + } + + @Override + public boolean setBoolean(int index, boolean element) { + ensureIsMutable(); + ensureIndexInRange(index); + boolean previousValue = array[index]; + array[index] = element; + return previousValue; + } + + @Override + public void add(int index, Boolean element) { + addBoolean(index, element); + } + + /** + * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. + */ + @Override + public void addBoolean(boolean element) { + addBoolean(size, element); + } + + /** + * Like {@link #add(int, Boolean)} but more efficient in that it doesn't box the element. + */ + private void addBoolean(int index, boolean element) { + ensureIsMutable(); + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + + if (size < array.length) { + // Shift everything over to make room + System.arraycopy(array, index, array, index + 1, size - index); + } else { + // Resize to 1.5x the size + int length = ((size * 3) / 2) + 1; + boolean[] newArray = new boolean[length]; + + // Copy the first part directly + System.arraycopy(array, 0, newArray, 0, index); + + // Copy the rest shifted over by one to make room + System.arraycopy(array, index, newArray, index + 1, size - index); + array = newArray; + } + + array[index] = element; + size++; + modCount++; + } + + @Override + public boolean addAll(Collection collection) { + ensureIsMutable(); + + if (collection == null) { + throw new NullPointerException(); + } + + // We specialize when adding another BooleanArrayList to avoid boxing elements. + if (!(collection instanceof BooleanArrayList)) { + return super.addAll(collection); + } + + BooleanArrayList list = (BooleanArrayList) collection; + if (list.size == 0) { + return false; + } + + int overflow = Integer.MAX_VALUE - size; + if (overflow < list.size) { + // We can't actually represent a list this large. + throw new OutOfMemoryError(); + } + + int newSize = size + list.size; + if (newSize > array.length) { + array = Arrays.copyOf(array, newSize); + } + + System.arraycopy(list.array, 0, array, size, list.size); + size = newSize; + modCount++; + return true; + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + for (int i = 0; i < size; i++) { + if (o.equals(array[i])) { + System.arraycopy(array, i + 1, array, i, size - i); + size--; + modCount++; + return true; + } + } + return false; + } + + @Override + public Boolean remove(int index) { + ensureIsMutable(); + ensureIndexInRange(index); + boolean value = array[index]; + System.arraycopy(array, index + 1, array, index, size - index); + size--; + modCount++; + return value; + } + + /** + * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an + * {@link IndexOutOfBoundsException} if it is not. + * + * @param index the index to verify is in range + */ + private void ensureIndexInRange(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + } + + private String makeOutOfBoundsExceptionMessage(int index) { + return "Index:" + index + ", Size:" + size; + } +} diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index b60bd36b01..3658410cd6 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -644,6 +644,30 @@ public final class Descriptors { return false; } + /** Determines if the given field number is reserved. */ + public boolean isReservedNumber(final int number) { + for (final DescriptorProto.ReservedRange range : + proto.getReservedRangeList()) { + if (range.getStart() <= number && number < range.getEnd()) { + return true; + } + } + return false; + } + + /** Determines if the given field name is reserved. */ + public boolean isReservedName(final String name) { + if (name == null) { + throw new NullPointerException(); + } + for (final String reservedName : proto.getReservedNameList()) { + if (reservedName.equals(name)) { + return true; + } + } + return false; + } + /** * Indicates whether the message can be extended. That is, whether it has * any "extensions x to y" ranges declared on it. @@ -917,9 +941,18 @@ public final class Descriptors { return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED; } - /** Does this field have the {@code [packed = true]} option? */ + /** Does this field have the {@code [packed = true]} option or is this field + * packable in proto3 and not explicitly setted to unpacked? + */ public boolean isPacked() { - return getOptions().getPacked(); + if (!isPackable()) { + return false; + } + if (getFile().getSyntax() == FileDescriptor.Syntax.PROTO2) { + return getOptions().getPacked(); + } else { + return !getOptions().hasPacked() || getOptions().getPacked(); + } } /** Can this field be packed? i.e. is it a repeated primitive field? */ @@ -2317,6 +2350,11 @@ public final class Descriptors { public int getFieldCount() { return fieldCount; } + /** Get a list of this message type's fields. */ + public List getFields() { + return Collections.unmodifiableList(Arrays.asList(fields)); + } + public FieldDescriptor getField(int index) { return fields[index]; } diff --git a/java/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/src/main/java/com/google/protobuf/DoubleArrayList.java new file mode 100644 index 0000000000..90ebe109d6 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/DoubleArrayList.java @@ -0,0 +1,243 @@ +// 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.Internal.DoubleList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An implementation of {@link DoubleList} on top of a primitive array. + * + * @author dweis@google.com (Daniel Weis) + */ +final class DoubleArrayList + extends AbstractProtobufList implements DoubleList, RandomAccess { + + private static final int DEFAULT_CAPACITY = 10; + + private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + public static DoubleArrayList emptyList() { + return EMPTY_LIST; + } + + /** + * The backing store for the list. + */ + private double[] array; + + /** + * The size of the list distinct from the length of the array. That is, it is the number of + * elements set in the list. + */ + private int size; + + /** + * Constructs a new mutable {@code DoubleArrayList}. + */ + DoubleArrayList() { + array = new double[DEFAULT_CAPACITY]; + size = 0; + } + + /** + * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}. + */ + DoubleArrayList(List other) { + if (other instanceof DoubleArrayList) { + DoubleArrayList list = (DoubleArrayList) other; + array = list.array.clone(); + size = list.size; + } else { + size = other.size(); + array = new double[size]; + for (int i = 0; i < size; i++) { + array[i] = other.get(i); + } + } + } + + @Override + public Double get(int index) { + return getDouble(index); + } + + @Override + public double getDouble(int index) { + ensureIndexInRange(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public Double set(int index, Double element) { + return setDouble(index, element); + } + + @Override + public double setDouble(int index, double element) { + ensureIsMutable(); + ensureIndexInRange(index); + double previousValue = array[index]; + array[index] = element; + return previousValue; + } + + @Override + public void add(int index, Double element) { + addDouble(index, element); + } + + /** + * Like {@link #add(Double)} but more efficient in that it doesn't box the element. + */ + @Override + public void addDouble(double element) { + addDouble(size, element); + } + + /** + * Like {@link #add(int, Double)} but more efficient in that it doesn't box the element. + */ + private void addDouble(int index, double element) { + ensureIsMutable(); + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + + if (size < array.length) { + // Shift everything over to make room + System.arraycopy(array, index, array, index + 1, size - index); + } else { + // Resize to 1.5x the size + int length = ((size * 3) / 2) + 1; + double[] newArray = new double[length]; + + // Copy the first part directly + System.arraycopy(array, 0, newArray, 0, index); + + // Copy the rest shifted over by one to make room + System.arraycopy(array, index, newArray, index + 1, size - index); + array = newArray; + } + + array[index] = element; + size++; + modCount++; + } + + @Override + public boolean addAll(Collection collection) { + ensureIsMutable(); + + if (collection == null) { + throw new NullPointerException(); + } + + // We specialize when adding another DoubleArrayList to avoid boxing elements. + if (!(collection instanceof DoubleArrayList)) { + return super.addAll(collection); + } + + DoubleArrayList list = (DoubleArrayList) collection; + if (list.size == 0) { + return false; + } + + int overflow = Integer.MAX_VALUE - size; + if (overflow < list.size) { + // We can't actually represent a list this large. + throw new OutOfMemoryError(); + } + + int newSize = size + list.size; + if (newSize > array.length) { + array = Arrays.copyOf(array, newSize); + } + + System.arraycopy(list.array, 0, array, size, list.size); + size = newSize; + modCount++; + return true; + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + for (int i = 0; i < size; i++) { + if (o.equals(array[i])) { + System.arraycopy(array, i + 1, array, i, size - i); + size--; + modCount++; + return true; + } + } + return false; + } + + @Override + public Double remove(int index) { + ensureIsMutable(); + ensureIndexInRange(index); + double value = array[index]; + System.arraycopy(array, index + 1, array, index, size - index); + size--; + modCount++; + return value; + } + + /** + * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an + * {@link IndexOutOfBoundsException} if it is not. + * + * @param index the index to verify is in range + */ + private void ensureIndexInRange(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + } + + private String makeOutOfBoundsExceptionMessage(int index) { + return "Index:" + index + ", Size:" + size; + } +} diff --git a/java/src/main/java/com/google/protobuf/FloatArrayList.java b/java/src/main/java/com/google/protobuf/FloatArrayList.java new file mode 100644 index 0000000000..293eaff68c --- /dev/null +++ b/java/src/main/java/com/google/protobuf/FloatArrayList.java @@ -0,0 +1,242 @@ +// 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.Internal.FloatList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An implementation of {@link FloatList} on top of a primitive array. + * + * @author dweis@google.com (Daniel Weis) + */ +final class FloatArrayList extends AbstractProtobufList implements FloatList, RandomAccess { + + private static final int DEFAULT_CAPACITY = 10; + + private static final FloatArrayList EMPTY_LIST = new FloatArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + public static FloatArrayList emptyList() { + return EMPTY_LIST; + } + + /** + * The backing store for the list. + */ + private float[] array; + + /** + * The size of the list distinct from the length of the array. That is, it is the number of + * elements set in the list. + */ + private int size; + + /** + * Constructs a new mutable {@code FloatArrayList}. + */ + FloatArrayList() { + array = new float[DEFAULT_CAPACITY]; + size = 0; + } + + /** + * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}. + */ + FloatArrayList(List other) { + if (other instanceof FloatArrayList) { + FloatArrayList list = (FloatArrayList) other; + array = list.array.clone(); + size = list.size; + } else { + size = other.size(); + array = new float[size]; + for (int i = 0; i < size; i++) { + array[i] = other.get(i); + } + } + } + + @Override + public Float get(int index) { + return getFloat(index); + } + + @Override + public float getFloat(int index) { + ensureIndexInRange(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public Float set(int index, Float element) { + return setFloat(index, element); + } + + @Override + public float setFloat(int index, float element) { + ensureIsMutable(); + ensureIndexInRange(index); + float previousValue = array[index]; + array[index] = element; + return previousValue; + } + + @Override + public void add(int index, Float element) { + addFloat(index, element); + } + + /** + * Like {@link #add(Float)} but more efficient in that it doesn't box the element. + */ + @Override + public void addFloat(float element) { + addFloat(size, element); + } + + /** + * Like {@link #add(int, Float)} but more efficient in that it doesn't box the element. + */ + private void addFloat(int index, float element) { + ensureIsMutable(); + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + + if (size < array.length) { + // Shift everything over to make room + System.arraycopy(array, index, array, index + 1, size - index); + } else { + // Resize to 1.5x the size + int length = ((size * 3) / 2) + 1; + float[] newArray = new float[length]; + + // Copy the first part directly + System.arraycopy(array, 0, newArray, 0, index); + + // Copy the rest shifted over by one to make room + System.arraycopy(array, index, newArray, index + 1, size - index); + array = newArray; + } + + array[index] = element; + size++; + modCount++; + } + + @Override + public boolean addAll(Collection collection) { + ensureIsMutable(); + + if (collection == null) { + throw new NullPointerException(); + } + + // We specialize when adding another FloatArrayList to avoid boxing elements. + if (!(collection instanceof FloatArrayList)) { + return super.addAll(collection); + } + + FloatArrayList list = (FloatArrayList) collection; + if (list.size == 0) { + return false; + } + + int overflow = Integer.MAX_VALUE - size; + if (overflow < list.size) { + // We can't actually represent a list this large. + throw new OutOfMemoryError(); + } + + int newSize = size + list.size; + if (newSize > array.length) { + array = Arrays.copyOf(array, newSize); + } + + System.arraycopy(list.array, 0, array, size, list.size); + size = newSize; + modCount++; + return true; + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + for (int i = 0; i < size; i++) { + if (o.equals(array[i])) { + System.arraycopy(array, i + 1, array, i, size - i); + size--; + modCount++; + return true; + } + } + return false; + } + + @Override + public Float remove(int index) { + ensureIsMutable(); + ensureIndexInRange(index); + float value = array[index]; + System.arraycopy(array, index + 1, array, index, size - index); + size--; + modCount++; + return value; + } + + /** + * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an + * {@link IndexOutOfBoundsException} if it is not. + * + * @param index the index to verify is in range + */ + private void ensureIndexInRange(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + } + + private String makeOutOfBoundsExceptionMessage(int index) { + return "Index:" + index + ", Size:" + size; + } +} diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 6839c9dd9e..bd6bc463dd 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -30,6 +30,12 @@ package com.google.protobuf; +import com.google.protobuf.Internal.BooleanList; +import com.google.protobuf.Internal.DoubleList; +import com.google.protobuf.Internal.FloatList; +import com.google.protobuf.Internal.IntList; +import com.google.protobuf.Internal.LongList; +import com.google.protobuf.Internal.ProtobufList; import com.google.protobuf.WireFormat.FieldType; import java.io.IOException; @@ -76,7 +82,11 @@ public abstract class GeneratedMessageLite< private static final long serialVersionUID = 1L; /** For use by generated code only. */ - protected UnknownFieldSetLite unknownFields; + protected UnknownFieldSetLite unknownFields = + UnknownFieldSetLite.getDefaultInstance(); + + /** For use by generated code only. */ + protected int memoizedSerializedSize = -1; @SuppressWarnings("unchecked") // Guaranteed by runtime. public final Parser getParserForType() { @@ -109,10 +119,67 @@ public abstract class GeneratedMessageLite< return unknownFields.mergeFieldFrom(tag, input); } - // The default behavior. If a message has required fields in its subtree, the - // generated code will override. - public boolean isInitialized() { - return true; + public final boolean isInitialized() { + return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null; + } + + public final BuilderType toBuilder() { + BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); + builder.mergeFrom((MessageType) this); + return builder; + } + + /** + * Defines which method path to invoke in {@link GeneratedMessageLite + * #dynamicMethod(MethodToInvoke, Object...)}. + *

+ * For use by generated code only. + */ + public static enum MethodToInvoke { + IS_INITIALIZED, + PARSE_PARTIAL_FROM, + MERGE_FROM, + MAKE_IMMUTABLE, + NEW_INSTANCE, + NEW_BUILDER; + } + + /** + * A method that implements different types of operations described in {@link MethodToInvoke}. + * Theses different kinds of operations are required to implement message-level operations for + * builders in the runtime. This method bundles those operations to reduce the generated methods + * count. + *

    + *
  • {@code PARSE_PARTIAL_FROM} is parameterized with an {@link CodedInputStream} and + * {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the + * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the + * implementation wraps it in a RuntimeException + *
  • {@code NEW_INSTANCE} returns a new instance of the protocol buffer + *
  • {@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to + * memoize. It returns {@code null} for false and the default instance for true. We optionally + * memoize to support the Builder case, where memoization is not desired. + *
  • {@code NEW_BUILDER} returns a {@code BuilderType} instance. + *
  • {@code MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from + * that instance into this instance. + *
  • {@code MAKE_IMMUTABLE} sets all internal fields to an immutable state. + *
+ * This method, plus the implementation of the Builder, enables the Builder class to be proguarded + * away entirely on Android. + *

+ * For use by generated code only. + */ + protected abstract Object dynamicMethod( + MethodToInvoke method, + Object... args); + + /** + * Merge some unknown fields into the {@link UnknownFieldSetLite} for this + * message. + * + *

For use by generated code only. + */ + protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) { + this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields); } @SuppressWarnings("unchecked") @@ -122,24 +189,37 @@ public abstract class GeneratedMessageLite< extends AbstractMessageLite.Builder { private final MessageType defaultInstance; - - /** For use by generated code only. */ - protected UnknownFieldSetLite unknownFields = - UnknownFieldSetLite.getDefaultInstance(); + protected MessageType instance; + protected boolean isBuilt; protected Builder(MessageType defaultInstance) { this.defaultInstance = defaultInstance; + this.instance = (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); + isBuilt = false; } - // The default behavior. If a message has required fields in its subtree, - // the generated code will override. - public boolean isInitialized() { - return true; + /** + * Called before any method that would mutate the builder to ensure that it correctly copies + * any state before the write happens to preserve immutability guarantees. + */ + protected void copyOnWrite() { + if (isBuilt) { + MessageType newInstance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); + newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance); + instance = newInstance; + isBuilt = false; + } + } + + //@Override (Java 1.6 override semantics, but we must support 1.5) + public final boolean isInitialized() { + return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */); } //@Override (Java 1.6 override semantics, but we must support 1.5) - public BuilderType clear() { - unknownFields = UnknownFieldSetLite.getDefaultInstance(); + public final BuilderType clear() { + // No need to copy on write since we're dropping the instance anyways. + instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); return (BuilderType) this; } @@ -151,8 +231,12 @@ public abstract class GeneratedMessageLite< return builder; } - /** All subclasses implement this. */ - public abstract MessageType buildPartial(); + //@Override (Java 1.6 override semantics, but we must support 1.5) + public MessageType buildPartial() { + instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); + isBuilt = true; + return instance; + } //@Override (Java 1.6 override semantics, but we must support 1.5) public final MessageType build() { @@ -162,9 +246,13 @@ public abstract class GeneratedMessageLite< } return result; } - + /** All subclasses implement this. */ - public abstract BuilderType mergeFrom(MessageType message); + public BuilderType mergeFrom(MessageType message) { + copyOnWrite(); + instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message); + return (BuilderType) this; + } public MessageType getDefaultInstanceForType() { return defaultInstance; @@ -181,18 +269,6 @@ public abstract class GeneratedMessageLite< int tag) throws IOException { return unknownFields.mergeFieldFrom(tag, input); } - - /** - * Merge some unknown fields into the {@link UnknownFieldSetLite} for this - * message. - * - *

For use by generated code only. - */ - protected final BuilderType mergeUnknownFields( - final UnknownFieldSetLite unknownFields) { - this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields); - return (BuilderType) this; - } public BuilderType mergeFrom( com.google.protobuf.CodedInputStream input, @@ -259,19 +335,13 @@ public abstract class GeneratedMessageLite< */ protected FieldSet extensions = FieldSet.newFieldSet(); - // -1 => not memoized, 0 => false, 1 => true. - private byte memoizedIsInitialized = -1; - - // The default behavior. If a message has required fields in its subtree, - // the generated code will override. - public boolean isInitialized() { - if (memoizedIsInitialized == -1) { - memoizedIsInitialized = (byte) (extensions.isInitialized() ? 1 : 0); + protected final void mergeExtensionFields(final MessageType other) { + if (extensions.isImmutable()) { + extensions = extensions.clone(); } - - return memoizedIsInitialized == 1; + extensions.mergeFrom(((ExtendableMessage) other).extensions); } - + private void verifyExtensionContainingType( final GeneratedExtension extension) { if (extension.getContainingTypeDefaultInstance() != @@ -420,46 +490,38 @@ public abstract class GeneratedMessageLite< implements ExtendableMessageOrBuilder { protected ExtendableBuilder(MessageType defaultInstance) { super(defaultInstance); - } - - private FieldSet extensions = FieldSet.emptySet(); - private boolean extensionsIsMutable; - - // The default behavior. If a message has required fields in its subtree, - // the generated code will override. - public boolean isInitialized() { - return extensions.isInitialized(); + + // TODO(dweis): This is kind of an unnecessary clone since we construct a + // new instance in the parent constructor which makes the extensions + // immutable. This extra allocation shouldn't matter in practice + // though. + instance.extensions = instance.extensions.clone(); } // For immutable message conversion. void internalSetExtensionSet(FieldSet extensions) { - this.extensions = extensions; + copyOnWrite(); + instance.extensions = extensions; } - @Override - public BuilderType clear() { - extensions.clear(); - extensionsIsMutable = false; - return super.clear(); + // @Override (Java 1.6 override semantics, but we must support 1.5) + protected void copyOnWrite() { + if (!isBuilt) { + return; + } + + super.copyOnWrite(); + instance.extensions = instance.extensions.clone(); } - private void ensureExtensionsIsMutable() { - if (!extensionsIsMutable) { - extensions = extensions.clone(); - extensionsIsMutable = true; + // @Override (Java 1.6 override semantics, but we must support 1.5) + public final MessageType buildPartial() { + if (isBuilt) { + return instance; } - } - /** - * Called by the build code path to create a copy of the extensions for - * building the message. - *

- * For use by generated code only. - */ - protected final FieldSet buildExtensions() { - extensions.makeImmutable(); - extensionsIsMutable = false; - return extensions; + instance.extensions.makeImmutable(); + return super.buildPartial(); } private void verifyExtensionContainingType( @@ -477,22 +539,14 @@ public abstract class GeneratedMessageLite< //@Override (Java 1.6 override semantics, but we must support 1.5) public final boolean hasExtension( final ExtensionLite extension) { - GeneratedExtension extensionLite = - checkIsLite(extension); - - verifyExtensionContainingType(extensionLite); - return extensions.hasField(extensionLite.descriptor); + return instance.hasExtension(extension); } /** Get the number of elements in a repeated extension. */ //@Override (Java 1.6 override semantics, but we must support 1.5) public final int getExtensionCount( final ExtensionLite> extension) { - GeneratedExtension> extensionLite = - checkIsLite(extension); - - verifyExtensionContainingType(extensionLite); - return extensions.getRepeatedFieldCount(extensionLite.descriptor); + return instance.getExtensionCount(extension); } /** Get the value of an extension. */ @@ -500,16 +554,7 @@ public abstract class GeneratedMessageLite< @SuppressWarnings("unchecked") public final Type getExtension( final ExtensionLite extension) { - GeneratedExtension extensionLite = - checkIsLite(extension); - - verifyExtensionContainingType(extensionLite); - final Object value = extensions.getField(extensionLite.descriptor); - if (value == null) { - return extensionLite.defaultValue; - } else { - return (Type) extensionLite.fromFieldSetType(value); - } + return instance.getExtension(extension); } /** Get one element of a repeated extension. */ @@ -518,12 +563,7 @@ public abstract class GeneratedMessageLite< public final Type getExtension( final ExtensionLite> extension, final int index) { - GeneratedExtension> extensionLite = - checkIsLite(extension); - - verifyExtensionContainingType(extensionLite); - return (Type) extensionLite.singularFromFieldSetType( - extensions.getRepeatedField(extensionLite.descriptor, index)); + return instance.getExtension(extension, index); } // This is implemented here only to work around an apparent bug in the @@ -542,9 +582,8 @@ public abstract class GeneratedMessageLite< checkIsLite(extension); verifyExtensionContainingType(extensionLite); - ensureExtensionsIsMutable(); - extensions.setField(extensionLite.descriptor, - extensionLite.toFieldSetType(value)); + copyOnWrite(); + instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value)); return (BuilderType) this; } @@ -556,9 +595,9 @@ public abstract class GeneratedMessageLite< checkIsLite(extension); verifyExtensionContainingType(extensionLite); - ensureExtensionsIsMutable(); - extensions.setRepeatedField(extensionLite.descriptor, index, - extensionLite.singularToFieldSetType(value)); + copyOnWrite(); + instance.extensions.setRepeatedField( + extensionLite.descriptor, index, extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } @@ -570,9 +609,9 @@ public abstract class GeneratedMessageLite< checkIsLite(extension); verifyExtensionContainingType(extensionLite); - ensureExtensionsIsMutable(); - extensions.addRepeatedField(extensionLite.descriptor, - extensionLite.singularToFieldSetType(value)); + copyOnWrite(); + instance.extensions.addRepeatedField( + extensionLite.descriptor, extensionLite.singularToFieldSetType(value)); return (BuilderType) this; } @@ -582,20 +621,10 @@ public abstract class GeneratedMessageLite< GeneratedExtension extensionLite = checkIsLite(extension); verifyExtensionContainingType(extensionLite); - ensureExtensionsIsMutable(); - extensions.clearField(extensionLite.descriptor); + copyOnWrite(); + instance.extensions.clearField(extensionLite.descriptor); return (BuilderType) this; } - - /** Called by subclasses to check if all extensions are initialized. */ - protected boolean extensionsAreInitialized() { - return extensions.isInitialized(); - } - - protected final void mergeExtensionFields(final MessageType other) { - ensureExtensionsIsMutable(); - extensions.mergeFrom(((ExtendableMessage) other).extensions); - } } //----------------------------------------------------------------- @@ -1113,4 +1142,133 @@ public abstract class GeneratedMessageLite< return (BuilderType) defaultInstance.toBuilder(); } } + + /** + * A static helper method for checking if a message is initialized, optionally memoizing. + *

+ * For use by generated code only. + */ + protected static final > boolean isInitialized( + T message, boolean shouldMemoize) { + return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null; + } + + protected static final > void makeImmutable(T message) { + message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); + } + + /** + * A static helper method for parsing a partial from input using the extension registry and the + * instance. + */ + static > T parsePartialFrom( + T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + return (T) instance.dynamicMethod( + MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry); + } catch (RuntimeException e) { + if (e.getCause() instanceof InvalidProtocolBufferException) { + throw (InvalidProtocolBufferException) e.getCause(); + } + throw e; + } + } + + /** + * A {@link Parser} implementation that delegates to the default instance. + *

+ * For use by generated code only. + */ + protected static class DefaultInstanceBasedParser> + extends AbstractParser { + + private T defaultInstance; + + public DefaultInstanceBasedParser(T defaultInstance) { + this.defaultInstance = defaultInstance; + } + + @Override + public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry); + } + } + + protected static IntList newIntList() { + return new IntArrayList(); + } + + protected static IntList newIntList(List toCopy) { + return new IntArrayList(toCopy); + } + + protected static IntList emptyIntList() { + return IntArrayList.emptyList(); + } + + protected static LongList newLongList() { + return new LongArrayList(); + } + + protected static LongList newLongList(List toCopy) { + return new LongArrayList(toCopy); + } + + protected static LongList emptyLongList() { + return LongArrayList.emptyList(); + } + + protected static FloatList newFloatList() { + return new FloatArrayList(); + } + + protected static FloatList newFloatList(List toCopy) { + return new FloatArrayList(toCopy); + } + + protected static FloatList emptyFloatList() { + return FloatArrayList.emptyList(); + } + + protected static DoubleList newDoubleList() { + return new DoubleArrayList(); + } + + protected static DoubleList newDoubleList(List toCopy) { + return new DoubleArrayList(toCopy); + } + + protected static DoubleList emptyDoubleList() { + return DoubleArrayList.emptyList(); + } + + protected static BooleanList newBooleanList() { + return new BooleanArrayList(); + } + + protected static BooleanList newBooleanList(List toCopy) { + return new BooleanArrayList(toCopy); + } + + protected static BooleanList emptyBooleanList() { + return BooleanArrayList.emptyList(); + } + + protected static ProtobufList newProtobufList() { + return new ProtobufArrayList(); + } + + protected static ProtobufList newProtobufList(List toCopy) { + return new ProtobufArrayList(toCopy); + } + + protected static ProtobufList emptyProtobufList() { + return ProtobufArrayList.emptyList(); + } + + protected static LazyStringArrayList emptyLazyStringArrayList() { + return LazyStringArrayList.emptyList(); + } } diff --git a/java/src/main/java/com/google/protobuf/IntArrayList.java b/java/src/main/java/com/google/protobuf/IntArrayList.java new file mode 100644 index 0000000000..f7609cc9f0 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/IntArrayList.java @@ -0,0 +1,242 @@ +// 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.Internal.IntList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An implementation of {@link IntList} on top of a primitive array. + * + * @author dweis@google.com (Daniel Weis) + */ +final class IntArrayList extends AbstractProtobufList implements IntList, RandomAccess { + + private static final int DEFAULT_CAPACITY = 10; + + private static final IntArrayList EMPTY_LIST = new IntArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + public static IntArrayList emptyList() { + return EMPTY_LIST; + } + + /** + * The backing store for the list. + */ + private int[] array; + + /** + * The size of the list distinct from the length of the array. That is, it is the number of + * elements set in the list. + */ + private int size; + + /** + * Constructs a new mutable {@code IntArrayList}. + */ + IntArrayList() { + array = new int[DEFAULT_CAPACITY]; + size = 0; + } + + /** + * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}. + */ + IntArrayList(List other) { + if (other instanceof IntArrayList) { + IntArrayList list = (IntArrayList) other; + array = list.array.clone(); + size = list.size; + } else { + size = other.size(); + array = new int[size]; + for (int i = 0; i < size; i++) { + array[i] = other.get(i); + } + } + } + + @Override + public Integer get(int index) { + return getInt(index); + } + + @Override + public int getInt(int index) { + ensureIndexInRange(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public Integer set(int index, Integer element) { + return setInt(index, element); + } + + @Override + public int setInt(int index, int element) { + ensureIsMutable(); + ensureIndexInRange(index); + int previousValue = array[index]; + array[index] = element; + return previousValue; + } + + @Override + public void add(int index, Integer element) { + addInt(index, element); + } + + /** + * Like {@link #add(Integer)} but more efficient in that it doesn't box the element. + */ + @Override + public void addInt(int element) { + addInt(size, element); + } + + /** + * Like {@link #add(int, Integer)} but more efficient in that it doesn't box the element. + */ + private void addInt(int index, int element) { + ensureIsMutable(); + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + + if (size < array.length) { + // Shift everything over to make room + System.arraycopy(array, index, array, index + 1, size - index); + } else { + // Resize to 1.5x the size + int length = ((size * 3) / 2) + 1; + int[] newArray = new int[length]; + + // Copy the first part directly + System.arraycopy(array, 0, newArray, 0, index); + + // Copy the rest shifted over by one to make room + System.arraycopy(array, index, newArray, index + 1, size - index); + array = newArray; + } + + array[index] = element; + size++; + modCount++; + } + + @Override + public boolean addAll(Collection collection) { + ensureIsMutable(); + + if (collection == null) { + throw new NullPointerException(); + } + + // We specialize when adding another IntArrayList to avoid boxing elements. + if (!(collection instanceof IntArrayList)) { + return super.addAll(collection); + } + + IntArrayList list = (IntArrayList) collection; + if (list.size == 0) { + return false; + } + + int overflow = Integer.MAX_VALUE - size; + if (overflow < list.size) { + // We can't actually represent a list this large. + throw new OutOfMemoryError(); + } + + int newSize = size + list.size; + if (newSize > array.length) { + array = Arrays.copyOf(array, newSize); + } + + System.arraycopy(list.array, 0, array, size, list.size); + size = newSize; + modCount++; + return true; + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + for (int i = 0; i < size; i++) { + if (o.equals(array[i])) { + System.arraycopy(array, i + 1, array, i, size - i); + size--; + modCount++; + return true; + } + } + return false; + } + + @Override + public Integer remove(int index) { + ensureIsMutable(); + ensureIndexInRange(index); + int value = array[index]; + System.arraycopy(array, index + 1, array, index, size - index); + size--; + modCount++; + return value; + } + + /** + * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an + * {@link IndexOutOfBoundsException} if it is not. + * + * @param index the index to verify is in range + */ + private void ensureIndexInRange(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + } + + private String makeOutOfBoundsExceptionMessage(int index) { + return "Index:" + index + ", Size:" + size; + } +} diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java index 74bf44c05b..20054b7917 100644 --- a/java/src/main/java/com/google/protobuf/Internal.java +++ b/java/src/main/java/com/google/protobuf/Internal.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.AbstractList; @@ -532,4 +533,132 @@ public class Internal { } } } + + /** + * Extends {@link List} to add the capability to make the list immutable and inspect if it is + * modifiable. + */ + public static interface ProtobufList extends List { + + /** + * Makes this list immutable. All subsequent modifications will throw an + * {@link UnsupportedOperationException}. + */ + void makeImmutable(); + + /** + * Returns whether this list can be modified via the publicly accessible {@link List} methods. + */ + boolean isModifiable(); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Integers if + * possible. Does not support null elements. + */ + public static interface IntList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + int getInt(int index); + + /** + * Like {@link #add(Integer)} but more efficient in that it doesn't box the element. + */ + void addInt(int element); + + /** + * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element. + */ + int setInt(int index, int element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Booleans if + * possible. Does not support null elements. + */ + public static interface BooleanList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + boolean getBoolean(int index); + + /** + * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. + */ + void addBoolean(boolean element); + + /** + * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element. + */ + boolean setBoolean(int index, boolean element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Longs if + * possible. Does not support null elements. + */ + public static interface LongList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + long getLong(int index); + + /** + * Like {@link #add(Long)} but more efficient in that it doesn't box the element. + */ + void addLong(long element); + + /** + * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element. + */ + long setLong(int index, long element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Doubles if + * possible. Does not support null elements. + */ + public static interface DoubleList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + double getDouble(int index); + + /** + * Like {@link #add(Double)} but more efficient in that it doesn't box the element. + */ + void addDouble(double element); + + /** + * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element. + */ + double setDouble(int index, double element); + } + + /** + * A {@link java.util.List} implementation that avoids boxing the elements into Floats if + * possible. Does not support null elements. + */ + public static interface FloatList extends ProtobufList { + + /** + * Like {@link #get(int)} but more efficient in that it doesn't box the returned value. + */ + float getFloat(int index); + + /** + * Like {@link #add(Float)} but more efficient in that it doesn't box the element. + */ + void addFloat(float element); + + /** + * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element. + */ + float setFloat(int index, float element); + } } diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java index 2d40a51fcf..a2997e1cb6 100644 --- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -62,11 +62,20 @@ import java.util.RandomAccess; * * @author jonp@google.com (Jon Perlow) */ -public class LazyStringArrayList extends AbstractList +public class LazyStringArrayList extends AbstractProtobufList implements LazyStringList, RandomAccess { + + private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + static LazyStringArrayList emptyList() { + return EMPTY_LIST; + } - public static final LazyStringList EMPTY = - new LazyStringArrayList().getUnmodifiableView(); + // For compatibility with older runtimes. + public static final LazyStringList EMPTY = EMPTY_LIST; private final List list; @@ -116,12 +125,26 @@ public class LazyStringArrayList extends AbstractList @Override public String set(int index, String s) { + ensureIsMutable(); Object o = list.set(index, s); return asString(o); } @Override public void add(int index, String element) { + ensureIsMutable(); + list.add(index, element); + modCount++; + } + + private void add(int index, ByteString element) { + ensureIsMutable(); + list.add(index, element); + modCount++; + } + + private void add(int index, byte[] element) { + ensureIsMutable(); list.add(index, element); modCount++; } @@ -137,6 +160,7 @@ public class LazyStringArrayList extends AbstractList @Override public boolean addAll(int index, Collection c) { + ensureIsMutable(); // When copying from another LazyStringList, directly copy the underlying // elements rather than forcing each element to be decoded to a String. Collection collection = c instanceof LazyStringList @@ -148,6 +172,7 @@ public class LazyStringArrayList extends AbstractList // @Override public boolean addAllByteString(Collection values) { + ensureIsMutable(); boolean ret = list.addAll(values); modCount++; return ret; @@ -155,6 +180,7 @@ public class LazyStringArrayList extends AbstractList // @Override public boolean addAllByteArray(Collection c) { + ensureIsMutable(); boolean ret = list.addAll(c); modCount++; return ret; @@ -162,6 +188,7 @@ public class LazyStringArrayList extends AbstractList @Override public String remove(int index) { + ensureIsMutable(); Object o = list.remove(index); modCount++; return asString(o); @@ -169,18 +196,21 @@ public class LazyStringArrayList extends AbstractList @Override public void clear() { + ensureIsMutable(); list.clear(); modCount++; } // @Override public void add(ByteString element) { + ensureIsMutable(); list.add(element); modCount++; } // @Override public void add(byte[] element) { + ensureIsMutable(); list.add(element); modCount++; } @@ -207,14 +237,23 @@ public class LazyStringArrayList extends AbstractList // @Override public void set(int index, ByteString s) { - list.set(index, s); + setAndReturn(index, s); + } + + private Object setAndReturn(int index, ByteString s) { + ensureIsMutable(); + return list.set(index, s); } // @Override public void set(int index, byte[] s) { - list.set(index, s); + setAndReturn(index, s); + } + + private Object setAndReturn(int index, byte[] s) { + ensureIsMutable(); + return list.set(index, s); } - private static String asString(Object o) { if (o instanceof String) { @@ -253,6 +292,7 @@ public class LazyStringArrayList extends AbstractList // @Override public void mergeFrom(LazyStringList other) { + ensureIsMutable(); for (Object o : other.getUnderlyingElements()) { if (o instanceof byte[]) { byte[] b = (byte[]) o; @@ -267,20 +307,15 @@ public class LazyStringArrayList extends AbstractList private static class ByteArrayListView extends AbstractList implements RandomAccess { - private final List list; + private final LazyStringArrayList list; - ByteArrayListView(List list) { + ByteArrayListView(LazyStringArrayList list) { this.list = list; } @Override public byte[] get(int index) { - Object o = list.get(index); - byte[] b = asByteArray(o); - if (b != o) { - list.set(index, b); - } - return b; + return list.getByteArray(index); } @Override @@ -290,7 +325,7 @@ public class LazyStringArrayList extends AbstractList @Override public byte[] set(int index, byte[] s) { - Object o = list.set(index, s); + Object o = list.setAndReturn(index, s); modCount++; return asByteArray(o); } @@ -311,25 +346,20 @@ public class LazyStringArrayList extends AbstractList // @Override public List asByteArrayList() { - return new ByteArrayListView(list); + return new ByteArrayListView(this); } private static class ByteStringListView extends AbstractList implements RandomAccess { - private final List list; + private final LazyStringArrayList list; - ByteStringListView(List list) { + ByteStringListView(LazyStringArrayList list) { this.list = list; } @Override public ByteString get(int index) { - Object o = list.get(index); - ByteString b = asByteString(o); - if (b != o) { - list.set(index, b); - } - return b; + return list.getByteString(index); } @Override @@ -339,7 +369,7 @@ public class LazyStringArrayList extends AbstractList @Override public ByteString set(int index, ByteString s) { - Object o = list.set(index, s); + Object o = list.setAndReturn(index, s); modCount++; return asByteString(o); } @@ -360,12 +390,15 @@ public class LazyStringArrayList extends AbstractList // @Override public List asByteStringList() { - return new ByteStringListView(list); + return new ByteStringListView(this); } // @Override public LazyStringList getUnmodifiableView() { - return new UnmodifiableLazyStringList(this); + if (isModifiable()) { + return new UnmodifiableLazyStringList(this); + } + return this; } } diff --git a/java/src/main/java/com/google/protobuf/LongArrayList.java b/java/src/main/java/com/google/protobuf/LongArrayList.java new file mode 100644 index 0000000000..298617ff8d --- /dev/null +++ b/java/src/main/java/com/google/protobuf/LongArrayList.java @@ -0,0 +1,242 @@ +// 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.Internal.LongList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An implementation of {@link LongList} on top of a primitive array. + * + * @author dweis@google.com (Daniel Weis) + */ +final class LongArrayList extends AbstractProtobufList implements LongList, RandomAccess { + + private static final int DEFAULT_CAPACITY = 10; + + private static final LongArrayList EMPTY_LIST = new LongArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + public static LongArrayList emptyList() { + return EMPTY_LIST; + } + + /** + * The backing store for the list. + */ + private long[] array; + + /** + * The size of the list distinct from the length of the array. That is, it is the number of + * elements set in the list. + */ + private int size; + + /** + * Constructs a new mutable {@code LongArrayList}. + */ + LongArrayList() { + array = new long[DEFAULT_CAPACITY]; + size = 0; + } + + /** + * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}. + */ + LongArrayList(List other) { + if (other instanceof LongArrayList) { + LongArrayList list = (LongArrayList) other; + array = list.array.clone(); + size = list.size; + } else { + size = other.size(); + array = new long[size]; + for (int i = 0; i < size; i++) { + array[i] = other.get(i); + } + } + } + + @Override + public Long get(int index) { + return getLong(index); + } + + @Override + public long getLong(int index) { + ensureIndexInRange(index); + return array[index]; + } + + @Override + public int size() { + return size; + } + + @Override + public Long set(int index, Long element) { + return setLong(index, element); + } + + @Override + public long setLong(int index, long element) { + ensureIsMutable(); + ensureIndexInRange(index); + long previousValue = array[index]; + array[index] = element; + return previousValue; + } + + @Override + public void add(int index, Long element) { + addLong(index, element); + } + + /** + * Like {@link #add(Long)} but more efficient in that it doesn't box the element. + */ + @Override + public void addLong(long element) { + addLong(size, element); + } + + /** + * Like {@link #add(int, Long)} but more efficient in that it doesn't box the element. + */ + private void addLong(int index, long element) { + ensureIsMutable(); + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + + if (size < array.length) { + // Shift everything over to make room + System.arraycopy(array, index, array, index + 1, size - index); + } else { + // Resize to 1.5x the size + int length = ((size * 3) / 2) + 1; + long[] newArray = new long[length]; + + // Copy the first part directly + System.arraycopy(array, 0, newArray, 0, index); + + // Copy the rest shifted over by one to make room + System.arraycopy(array, index, newArray, index + 1, size - index); + array = newArray; + } + + array[index] = element; + size++; + modCount++; + } + + @Override + public boolean addAll(Collection collection) { + ensureIsMutable(); + + if (collection == null) { + throw new NullPointerException(); + } + + // We specialize when adding another LongArrayList to avoid boxing elements. + if (!(collection instanceof LongArrayList)) { + return super.addAll(collection); + } + + LongArrayList list = (LongArrayList) collection; + if (list.size == 0) { + return false; + } + + int overflow = Integer.MAX_VALUE - size; + if (overflow < list.size) { + // We can't actually represent a list this large. + throw new OutOfMemoryError(); + } + + int newSize = size + list.size; + if (newSize > array.length) { + array = Arrays.copyOf(array, newSize); + } + + System.arraycopy(list.array, 0, array, size, list.size); + size = newSize; + modCount++; + return true; + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + for (int i = 0; i < size; i++) { + if (o.equals(array[i])) { + System.arraycopy(array, i + 1, array, i, size - i); + size--; + modCount++; + return true; + } + } + return false; + } + + @Override + public Long remove(int index) { + ensureIsMutable(); + ensureIndexInRange(index); + long value = array[index]; + System.arraycopy(array, index + 1, array, index, size - index); + size--; + modCount++; + return value; + } + + /** + * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an + * {@link IndexOutOfBoundsException} if it is not. + * + * @param index the index to verify is in range + */ + private void ensureIndexInRange(int index) { + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index)); + } + } + + private String makeOutOfBoundsExceptionMessage(int index) { + return "Index:" + index + ", Size:" + size; + } +} diff --git a/java/src/main/java/com/google/protobuf/MapField.java b/java/src/main/java/com/google/protobuf/MapField.java index 82906d375c..b290993ca1 100644 --- a/java/src/main/java/com/google/protobuf/MapField.java +++ b/java/src/main/java/com/google/protobuf/MapField.java @@ -30,9 +30,11 @@ package com.google.protobuf; +import com.google.protobuf.MapFieldLite.MutatabilityAwareMap; + import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -51,7 +53,7 @@ import java.util.Map; * and getList() concurrently in multiple threads. If write-access is needed, * all access must be synchronized. */ -public class MapField { +public class MapField implements MutabilityOracle { /** * Indicates where the data of this map field is currently stored. * @@ -72,8 +74,9 @@ public class MapField { */ private enum StorageMode {MAP, LIST, BOTH} + private volatile boolean isMutable; private volatile StorageMode mode; - private Map mapData; + private MutatabilityAwareMap mapData; private List listData; // Convert between a map entry Message and a key-value pair. @@ -110,20 +113,19 @@ public class MapField { private MapField( Converter converter, StorageMode mode, - Map mapData, - List listData) { + Map mapData) { this.converter = converter; + this.isMutable = true; this.mode = mode; - this.mapData = mapData; - this.listData = listData; + this.mapData = new MutatabilityAwareMap(this, mapData); + this.listData = null; } private MapField( MapEntry defaultEntry, StorageMode mode, - Map mapData, - List listData) { - this(new ImmutableMessageConverter(defaultEntry), mode, mapData, listData); + Map mapData) { + this(new ImmutableMessageConverter(defaultEntry), mode, mapData); } @@ -131,14 +133,14 @@ public class MapField { public static MapField emptyMapField( MapEntry defaultEntry) { return new MapField( - defaultEntry, StorageMode.MAP, Collections.emptyMap(), null); + defaultEntry, StorageMode.MAP, Collections.emptyMap()); } /** Creates a new mutable empty MapField. */ public static MapField newMapField(MapEntry defaultEntry) { return new MapField( - defaultEntry, StorageMode.MAP, new HashMap(), null); + defaultEntry, StorageMode.MAP, new LinkedHashMap()); } @@ -151,7 +153,7 @@ public class MapField { converter.convertMessageToKeyAndValue(message, map); } - private List convertMapToList(Map mapData) { + private List convertMapToList(MutatabilityAwareMap mapData) { List listData = new ArrayList(); for (Map.Entry entry : mapData.entrySet()) { listData.add( @@ -161,12 +163,12 @@ public class MapField { return listData; } - private Map convertListToMap(List listData) { - Map mapData = new HashMap(); + private MutatabilityAwareMap convertListToMap(List listData) { + Map mapData = new LinkedHashMap(); for (Message item : listData) { convertMessageToKeyAndValue(item, mapData); } - return mapData; + return new MutatabilityAwareMap(this, mapData); } /** Returns the content of this MapField as a read-only Map. */ @@ -199,7 +201,7 @@ public class MapField { } public void clear() { - mapData = new HashMap(); + mapData = new MutatabilityAwareMap(this, new LinkedHashMap()); mode = StorageMode.MAP; } @@ -221,7 +223,7 @@ public class MapField { /** Returns a deep copy of this MapField. */ public MapField copy() { return new MapField( - converter, StorageMode.MAP, MapFieldLite.copy(getMap()), null); + converter, StorageMode.MAP, MapFieldLite.copy(getMap())); } /** Gets the content of this MapField as a read-only List. */ @@ -256,4 +258,29 @@ public class MapField { Message getMapEntryMessageDefaultInstance() { return converter.getMessageDefaultInstance(); } + + /** + * Makes this list immutable. All subsequent modifications will throw an + * {@link UnsupportedOperationException}. + */ + public void makeImmutable() { + isMutable = false; + } + + /** + * Returns whether this field can be modified. + */ + public boolean isMutable() { + return isMutable; + } + + /* (non-Javadoc) + * @see com.google.protobuf.MutabilityOracle#ensureMutable() + */ + @Override + public void ensureMutable() { + if (!isMutable()) { + throw new UnsupportedOperationException(); + } + } } diff --git a/java/src/main/java/com/google/protobuf/MapFieldLite.java b/java/src/main/java/com/google/protobuf/MapFieldLite.java index 7f94c690b0..c17fa7b1db 100644 --- a/java/src/main/java/com/google/protobuf/MapFieldLite.java +++ b/java/src/main/java/com/google/protobuf/MapFieldLite.java @@ -31,9 +31,12 @@ package com.google.protobuf; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; -import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; /** * Internal representation of map fields in generated lite-runtime messages. @@ -41,16 +44,21 @@ import java.util.Map; * This class is a protobuf implementation detail. Users shouldn't use this * class directly. */ -public class MapFieldLite { - private Map mapData; +public class MapFieldLite implements MutabilityOracle { + private MutatabilityAwareMap mapData; + private boolean isMutable; private MapFieldLite(Map mapData) { - this.mapData = mapData; + this.mapData = new MutatabilityAwareMap(this, mapData); + this.isMutable = true; } @SuppressWarnings({"rawtypes", "unchecked"}) private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite(Collections.emptyMap()); + static { + EMPTY_MAP_FIELD.makeImmutable(); + } /** Returns an singleton immutable empty MapFieldLite instance. */ @SuppressWarnings({"unchecked", "cast"}) @@ -60,7 +68,7 @@ public class MapFieldLite { /** Creates a new MapFieldLite instance. */ public static MapFieldLite newMapField() { - return new MapFieldLite(new HashMap()); + return new MapFieldLite(new LinkedHashMap()); } /** Gets the content of this MapField as a read-only Map. */ @@ -168,7 +176,7 @@ public class MapFieldLite { */ @SuppressWarnings("unchecked") static Map copy(Map map) { - Map result = new HashMap(); + Map result = new LinkedHashMap(); for (Map.Entry entry : map.entrySet()) { result.put(entry.getKey(), (V) copy(entry.getValue())); } @@ -179,4 +187,360 @@ public class MapFieldLite { public MapFieldLite copy() { return new MapFieldLite(copy(mapData)); } + + /** + * Makes this field immutable. All subsequent modifications will throw an + * {@link UnsupportedOperationException}. + */ + public void makeImmutable() { + isMutable = false; + } + + /** + * Returns whether this field can be modified. + */ + public boolean isMutable() { + return isMutable; + } + + @Override + public void ensureMutable() { + if (!isMutable()) { + throw new UnsupportedOperationException(); + } + } + + /** + * An internal map that checks for mutability before delegating. + */ + static class MutatabilityAwareMap implements Map { + private final MutabilityOracle mutabilityOracle; + private final Map delegate; + + MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map delegate) { + this.mutabilityOracle = mutabilityOracle; + this.delegate = delegate; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return delegate.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate.containsValue(value); + } + + @Override + public V get(Object key) { + return delegate.get(key); + } + + @Override + public V put(K key, V value) { + mutabilityOracle.ensureMutable(); + return delegate.put(key, value); + } + + @Override + public V remove(Object key) { + mutabilityOracle.ensureMutable(); + return delegate.remove(key); + } + + @Override + public void putAll(Map m) { + mutabilityOracle.ensureMutable(); + delegate.putAll(m); + } + + @Override + public void clear() { + mutabilityOracle.ensureMutable(); + delegate.clear(); + } + + @Override + public Set keySet() { + return new MutatabilityAwareSet(mutabilityOracle, delegate.keySet()); + } + + @Override + public Collection values() { + return new MutatabilityAwareCollection(mutabilityOracle, delegate.values()); + } + + @Override + public Set> entrySet() { + return new MutatabilityAwareSet>(mutabilityOracle, delegate.entrySet()); + } + + @Override + public boolean equals(Object o) { + return delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } + + /** + * An internal collection that checks for mutability before delegating. + */ + private static class MutatabilityAwareCollection implements Collection { + private final MutabilityOracle mutabilityOracle; + private final Collection delegate; + + MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection delegate) { + this.mutabilityOracle = mutabilityOracle; + this.delegate = delegate; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return new MutatabilityAwareIterator(mutabilityOracle, delegate.iterator()); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(E e) { + // Unsupported operation in the delegate. + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + mutabilityOracle.ensureMutable(); + return delegate.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + // Unsupported operation in the delegate. + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection c) { + mutabilityOracle.ensureMutable(); + return delegate.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + mutabilityOracle.ensureMutable(); + return delegate.retainAll(c); + } + + @Override + public void clear() { + mutabilityOracle.ensureMutable(); + delegate.clear(); + } + + @Override + public boolean equals(Object o) { + return delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } + + /** + * An internal set that checks for mutability before delegating. + */ + private static class MutatabilityAwareSet implements Set { + private final MutabilityOracle mutabilityOracle; + private final Set delegate; + + MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set delegate) { + this.mutabilityOracle = mutabilityOracle; + this.delegate = delegate; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return new MutatabilityAwareIterator(mutabilityOracle, delegate.iterator()); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(E e) { + mutabilityOracle.ensureMutable(); + return delegate.add(e); + } + + @Override + public boolean remove(Object o) { + mutabilityOracle.ensureMutable(); + return delegate.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + mutabilityOracle.ensureMutable(); + return delegate.addAll(c); + } + + @Override + public boolean retainAll(Collection c) { + mutabilityOracle.ensureMutable(); + return delegate.retainAll(c); + } + + @Override + public boolean removeAll(Collection c) { + mutabilityOracle.ensureMutable(); + return delegate.removeAll(c); + } + + @Override + public void clear() { + mutabilityOracle.ensureMutable(); + delegate.clear(); + } + + @Override + public boolean equals(Object o) { + return delegate.equals(o); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } + + /** + * An internal iterator that checks for mutability before delegating. + */ + private static class MutatabilityAwareIterator implements Iterator { + private final MutabilityOracle mutabilityOracle; + private final Iterator delegate; + + MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator delegate) { + this.mutabilityOracle = mutabilityOracle; + this.delegate = delegate; + } + + @Override + public boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public E next() { + return delegate.next(); + } + + @Override + public void remove() { + mutabilityOracle.ensureMutable(); + delegate.remove(); + } + + @Override + public boolean equals(Object obj) { + return delegate.equals(obj); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + } } diff --git a/java/src/main/java/com/google/protobuf/MutabilityOracle.java b/java/src/main/java/com/google/protobuf/MutabilityOracle.java new file mode 100644 index 0000000000..82b723c95d --- /dev/null +++ b/java/src/main/java/com/google/protobuf/MutabilityOracle.java @@ -0,0 +1,48 @@ +// 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; + +/** + * Verifies that an object is mutable, throwing if not. + */ +interface MutabilityOracle { + static final MutabilityOracle IMMUTABLE = new MutabilityOracle() { + @Override + public void ensureMutable() { + throw new UnsupportedOperationException(); + } + }; + + /** + * Throws an {@link UnsupportedOperationException} if not mutable. + */ + void ensureMutable(); +} diff --git a/java/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/src/main/java/com/google/protobuf/ProtobufArrayList.java new file mode 100644 index 0000000000..759368c9b6 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/ProtobufArrayList.java @@ -0,0 +1,95 @@ +// 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.Internal.ProtobufList; + +import java.util.ArrayList; +import java.util.List; + +/** + * Implements {@link ProtobufList} for non-primitive and {@link String} types. + */ +class ProtobufArrayList extends AbstractProtobufList { + + private static final ProtobufArrayList EMPTY_LIST = new ProtobufArrayList(); + static { + EMPTY_LIST.makeImmutable(); + } + + @SuppressWarnings("unchecked") // Guaranteed safe by runtime. + public static ProtobufArrayList emptyList() { + return (ProtobufArrayList) EMPTY_LIST; + } + + private final List list; + + ProtobufArrayList() { + list = new ArrayList(); + } + + ProtobufArrayList(List toCopy) { + list = new ArrayList(toCopy); + } + + @Override + public void add(int index, E element) { + ensureIsMutable(); + list.add(index, element); + modCount++; + } + + @Override + public E get(int index) { + return list.get(index); + } + + @Override + public E remove(int index) { + ensureIsMutable(); + E toReturn = list.remove(index); + modCount++; + return toReturn; + } + + @Override + public E set(int index, E element) { + ensureIsMutable(); + E toReturn = list.set(index, element); + modCount++; + return toReturn; + } + + @Override + public int size() { + return list.size(); + } +} diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java index dd2b4600b0..a79ce559b2 100644 --- a/java/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/src/main/java/com/google/protobuf/TextFormat.java @@ -1725,7 +1725,7 @@ public final class TextFormat { * {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with * "\x") are also recognized. */ - static ByteString unescapeBytes(final CharSequence charString) + public static ByteString unescapeBytes(final CharSequence charString) throws InvalidEscapeSequenceException { // First convert the Java character sequence to UTF-8 bytes. ByteString input = ByteString.copyFromUtf8(charString.toString()); @@ -1808,7 +1808,7 @@ public final class TextFormat { * Thrown by {@link TextFormat#unescapeBytes} and * {@link TextFormat#unescapeText} when an invalid escape sequence is seen. */ - static class InvalidEscapeSequenceException extends IOException { + public static class InvalidEscapeSequenceException extends IOException { private static final long serialVersionUID = -8164033650142593304L; InvalidEscapeSequenceException(final String description) { diff --git a/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java new file mode 100644 index 0000000000..df89c26394 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/BooleanArrayListTest.java @@ -0,0 +1,473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * Tests for {@link BooleanArrayList}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class BooleanArrayListTest extends TestCase { + + private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true); + private static final BooleanArrayList TERTIARY_LIST = + newImmutableBooleanArrayList(true, true, false); + + private BooleanArrayList list; + + @Override + protected void setUp() throws Exception { + list = new BooleanArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(BooleanArrayList.emptyList()); + } + + public void testMakeImmutable() { + list.addBoolean(true); + list.addBoolean(false); + list.addBoolean(true); + list.addBoolean(true); + list.makeImmutable(); + assertImmutable(list); + } + + public void testCopyConstructor() { + BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new BooleanArrayList(BooleanArrayList.emptyList()); + assertEquals(BooleanArrayList.emptyList(), copy); + + copy = new BooleanArrayList(asList(false, false, true)); + assertEquals(asList(false, false, true), copy); + + copy = new BooleanArrayList(Collections.emptyList()); + assertEquals(BooleanArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(true, false, false, true)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(true, (boolean) list.get(0)); + assertEquals(true, (boolean) iterator.next()); + list.set(0, true); + assertEquals(false, (boolean) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, false); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testGet() { + assertEquals(true, (boolean) TERTIARY_LIST.get(0)); + assertEquals(true, (boolean) TERTIARY_LIST.get(1)); + assertEquals(false, (boolean) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testGetInt() { + assertEquals(true, TERTIARY_LIST.getBoolean(0)); + assertEquals(true, TERTIARY_LIST.getBoolean(1)); + assertEquals(false, TERTIARY_LIST.getBoolean(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSize() { + assertEquals(0, BooleanArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.addBoolean(true); + list.addBoolean(false); + list.addBoolean(false); + list.addBoolean(false); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(true); + assertEquals(4, list.size()); + } + + public void testSet() { + list.addBoolean(false); + list.addBoolean(false); + + assertEquals(false, (boolean) list.set(0, true)); + assertEquals(true, list.getBoolean(0)); + + assertEquals(false, (boolean) list.set(1, false)); + assertEquals(false, list.getBoolean(1)); + + try { + list.set(-1, true); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, false); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSetInt() { + list.addBoolean(true); + list.addBoolean(true); + + assertEquals(true, list.setBoolean(0, false)); + assertEquals(false, list.getBoolean(0)); + + assertEquals(true, list.setBoolean(1, false)); + assertEquals(false, list.getBoolean(1)); + + try { + list.setBoolean(-1, false); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.setBoolean(2, true); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(true)); + assertEquals(asList(true), list); + + assertTrue(list.add(false)); + list.add(0, false); + assertEquals(asList(false, true, false), list); + + list.add(0, false); + list.add(0, true); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(true); + } + assertEquals(asList(true, false, false, true, false, true, true, true, true, true, true), list); + + try { + list.add(-1, false); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, true); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddInt() { + assertEquals(0, list.size()); + + list.addBoolean(true); + assertEquals(asList(true), list); + + list.addBoolean(false); + assertEquals(asList(true, false), list); + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(false))); + assertEquals(1, list.size()); + assertEquals(false, (boolean) list.get(0)); + assertEquals(false, list.getBoolean(0)); + + assertTrue(list.addAll(asList(true, false, false, false, true))); + assertEquals(asList(false, true, false, false, false, true), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(false, true, false, false, false, true, true, true, false), list); + + assertFalse(list.addAll(Collections.emptyList())); + assertFalse(list.addAll(BooleanArrayList.emptyList())); + } + + public void testRemove() { + list.addAll(TERTIARY_LIST); + assertEquals(true, (boolean) list.remove(0)); + assertEquals(asList(true, false), list); + + assertTrue(list.remove(Boolean.TRUE)); + assertEquals(asList(false), list); + + assertFalse(list.remove(Boolean.TRUE)); + assertEquals(asList(false), list); + + assertEquals(false, (boolean) list.remove(0)); + assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + private void assertImmutable(BooleanArrayList list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(false); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, true); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(false)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new BooleanArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(true)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addBoolean(true); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, true); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.setBoolean(0, false); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static BooleanArrayList newImmutableBooleanArrayList(boolean... elements) { + BooleanArrayList list = new BooleanArrayList(); + for (boolean element : elements) { + list.addBoolean(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java index 6cfa18d543..edd7fc4625 100644 --- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -56,6 +56,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestExtremeDefaultValues; import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges; import protobuf_unittest.UnittestProto.TestRequired; +import protobuf_unittest.UnittestProto.TestReservedFields; import protobuf_unittest.UnittestProto.TestService; import junit.framework.TestCase; @@ -687,6 +688,9 @@ public class DescriptorsTest extends TestCase { assertEquals(4, oneofDescriptor.getFieldCount()); assertSame(oneofDescriptor.getField(1), field); + + assertEquals(4, oneofDescriptor.getFields().size()); + assertEquals(oneofDescriptor.getFields().get(1), field); } public void testMessageDescriptorExtensions() throws Exception { @@ -702,6 +706,19 @@ public class DescriptorsTest extends TestCase { assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)); } + public void testReservedFields() { + Descriptor d = TestReservedFields.getDescriptor(); + assertTrue(d.isReservedNumber(2)); + assertFalse(d.isReservedNumber(8)); + assertTrue(d.isReservedNumber(9)); + assertTrue(d.isReservedNumber(10)); + assertTrue(d.isReservedNumber(11)); + assertFalse(d.isReservedNumber(12)); + assertFalse(d.isReservedName("foo")); + assertTrue(d.isReservedName("bar")); + assertTrue(d.isReservedName("baz")); + } + public void testToString() { assertEquals("protobuf_unittest.TestAllTypes.optional_uint64", UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber( diff --git a/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java new file mode 100644 index 0000000000..e7a73d706a --- /dev/null +++ b/java/src/test/java/com/google/protobuf/DoubleArrayListTest.java @@ -0,0 +1,473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * Tests for {@link DoubleArrayList}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class DoubleArrayListTest extends TestCase { + + private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1); + private static final DoubleArrayList TERTIARY_LIST = + newImmutableDoubleArrayList(1, 2, 3); + + private DoubleArrayList list; + + @Override + protected void setUp() throws Exception { + list = new DoubleArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(DoubleArrayList.emptyList()); + } + + public void testMakeImmutable() { + list.addDouble(2); + list.addDouble(4); + list.addDouble(6); + list.addDouble(8); + list.makeImmutable(); + assertImmutable(list); + } + + public void testCopyConstructor() { + DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new DoubleArrayList(DoubleArrayList.emptyList()); + assertEquals(DoubleArrayList.emptyList(), copy); + + copy = new DoubleArrayList(asList(1D, 2D, 3D)); + assertEquals(asList(1D, 2D, 3D), copy); + + copy = new DoubleArrayList(Collections.emptyList()); + assertEquals(DoubleArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(1D, 2D, 3D, 4D)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(1D, (double) list.get(0)); + assertEquals(1D, (double) iterator.next()); + list.set(0, 1D); + assertEquals(2D, (double) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, 0D); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testGet() { + assertEquals(1D, (double) TERTIARY_LIST.get(0)); + assertEquals(2D, (double) TERTIARY_LIST.get(1)); + assertEquals(3D, (double) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testGetInt() { + assertEquals(1D, TERTIARY_LIST.getDouble(0)); + assertEquals(2D, TERTIARY_LIST.getDouble(1)); + assertEquals(3D, TERTIARY_LIST.getDouble(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSize() { + assertEquals(0, DoubleArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.addDouble(2); + list.addDouble(4); + list.addDouble(6); + list.addDouble(8); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(16D); + assertEquals(4, list.size()); + } + + public void testSet() { + list.addDouble(2); + list.addDouble(4); + + assertEquals(2D, (double) list.set(0, 0D)); + assertEquals(0D, list.getDouble(0)); + + assertEquals(4D, (double) list.set(1, 0D)); + assertEquals(0D, list.getDouble(1)); + + try { + list.set(-1, 0D); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, 0D); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSetInt() { + list.addDouble(2); + list.addDouble(4); + + assertEquals(2D, list.setDouble(0, 0)); + assertEquals(0D, list.getDouble(0)); + + assertEquals(4D, list.setDouble(1, 0)); + assertEquals(0D, list.getDouble(1)); + + try { + list.setDouble(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.setDouble(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(2D)); + assertEquals(asList(2D), list); + + assertTrue(list.add(3D)); + list.add(0, 4D); + assertEquals(asList(4D, 2D, 3D), list); + + list.add(0, 1D); + list.add(0, 0D); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(Double.valueOf(5 + i)); + } + assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list); + + try { + list.add(-1, 5D); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, 5D); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddInt() { + assertEquals(0, list.size()); + + list.addDouble(2); + assertEquals(asList(2D), list); + + list.addDouble(3); + assertEquals(asList(2D, 3D), list); + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(1D))); + assertEquals(1, list.size()); + assertEquals(1D, (double) list.get(0)); + assertEquals(1D, list.getDouble(0)); + + assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D))); + assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list); + + assertFalse(list.addAll(Collections.emptyList())); + assertFalse(list.addAll(DoubleArrayList.emptyList())); + } + + public void testRemove() { + list.addAll(TERTIARY_LIST); + assertEquals(1D, (double) list.remove(0)); + assertEquals(asList(2D, 3D), list); + + assertTrue(list.remove(Double.valueOf(3))); + assertEquals(asList(2D), list); + + assertFalse(list.remove(Double.valueOf(3))); + assertEquals(asList(2D), list); + + assertEquals(2D, (double) list.remove(0)); + assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + private void assertImmutable(DoubleArrayList list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(1D); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, 1D); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(1D)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new DoubleArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(1D)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addDouble(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, 0D); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.setDouble(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static DoubleArrayList newImmutableDoubleArrayList(double... elements) { + DoubleArrayList list = new DoubleArrayList(); + for (double element : elements) { + list.addDouble(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/src/test/java/com/google/protobuf/FloatArrayListTest.java new file mode 100644 index 0000000000..8f3e93dc10 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/FloatArrayListTest.java @@ -0,0 +1,473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * Tests for {@link FloatArrayList}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class FloatArrayListTest extends TestCase { + + private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1); + private static final FloatArrayList TERTIARY_LIST = + newImmutableFloatArrayList(1, 2, 3); + + private FloatArrayList list; + + @Override + protected void setUp() throws Exception { + list = new FloatArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(FloatArrayList.emptyList()); + } + + public void testMakeImmutable() { + list.addFloat(2); + list.addFloat(4); + list.addFloat(6); + list.addFloat(8); + list.makeImmutable(); + assertImmutable(list); + } + + public void testCopyConstructor() { + FloatArrayList copy = new FloatArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new FloatArrayList(FloatArrayList.emptyList()); + assertEquals(FloatArrayList.emptyList(), copy); + + copy = new FloatArrayList(asList(1F, 2F, 3F)); + assertEquals(asList(1F, 2F, 3F), copy); + + copy = new FloatArrayList(Collections.emptyList()); + assertEquals(FloatArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(1F, 2F, 3F, 4F)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(1F, (float) list.get(0)); + assertEquals(1F, (float) iterator.next()); + list.set(0, 1F); + assertEquals(2F, (float) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, 0F); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testGet() { + assertEquals(1F, (float) TERTIARY_LIST.get(0)); + assertEquals(2F, (float) TERTIARY_LIST.get(1)); + assertEquals(3F, (float) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testGetFloat() { + assertEquals(1F, TERTIARY_LIST.getFloat(0)); + assertEquals(2F, TERTIARY_LIST.getFloat(1)); + assertEquals(3F, TERTIARY_LIST.getFloat(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSize() { + assertEquals(0, FloatArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.addFloat(2); + list.addFloat(4); + list.addFloat(6); + list.addFloat(8); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(16F); + assertEquals(4, list.size()); + } + + public void testSet() { + list.addFloat(2); + list.addFloat(4); + + assertEquals(2F, (float) list.set(0, 0F)); + assertEquals(0F, list.getFloat(0)); + + assertEquals(4F, (float) list.set(1, 0F)); + assertEquals(0F, list.getFloat(1)); + + try { + list.set(-1, 0F); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, 0F); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSetFloat() { + list.addFloat(2); + list.addFloat(4); + + assertEquals(2F, list.setFloat(0, 0)); + assertEquals(0F, list.getFloat(0)); + + assertEquals(4F, list.setFloat(1, 0)); + assertEquals(0F, list.getFloat(1)); + + try { + list.setFloat(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.setFloat(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(2F)); + assertEquals(asList(2F), list); + + assertTrue(list.add(3F)); + list.add(0, 4F); + assertEquals(asList(4F, 2F, 3F), list); + + list.add(0, 1F); + list.add(0, 0F); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(Float.valueOf(5 + i)); + } + assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list); + + try { + list.add(-1, 5F); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, 5F); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddFloat() { + assertEquals(0, list.size()); + + list.addFloat(2); + assertEquals(asList(2F), list); + + list.addFloat(3); + assertEquals(asList(2F, 3F), list); + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(1F))); + assertEquals(1, list.size()); + assertEquals(1F, (float) list.get(0)); + assertEquals(1F, list.getFloat(0)); + + assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F))); + assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list); + + assertFalse(list.addAll(Collections.emptyList())); + assertFalse(list.addAll(FloatArrayList.emptyList())); + } + + public void testRemove() { + list.addAll(TERTIARY_LIST); + assertEquals(1F, (float) list.remove(0)); + assertEquals(asList(2F, 3F), list); + + assertTrue(list.remove(Float.valueOf(3))); + assertEquals(asList(2F), list); + + assertFalse(list.remove(Float.valueOf(3))); + assertEquals(asList(2F), list); + + assertEquals(2F, (float) list.remove(0)); + assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + private void assertImmutable(FloatArrayList list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(1F); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, 1F); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(1F)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new FloatArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(1F)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addFloat(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, 0F); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.setFloat(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static FloatArrayList newImmutableFloatArrayList(int... elements) { + FloatArrayList list = new FloatArrayList(); + for (int element : elements) { + list.addFloat(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/src/test/java/com/google/protobuf/IntArrayListTest.java new file mode 100644 index 0000000000..3733eb3056 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/IntArrayListTest.java @@ -0,0 +1,473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * Tests for {@link IntArrayList}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class IntArrayListTest extends TestCase { + + private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1); + private static final IntArrayList TERTIARY_LIST = + newImmutableIntArrayList(1, 2, 3); + + private IntArrayList list; + + @Override + protected void setUp() throws Exception { + list = new IntArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(IntArrayList.emptyList(), IntArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(IntArrayList.emptyList()); + } + + public void testMakeImmutable() { + list.addInt(2); + list.addInt(4); + list.addInt(6); + list.addInt(8); + list.makeImmutable(); + assertImmutable(list); + } + + public void testCopyConstructor() { + IntArrayList copy = new IntArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new IntArrayList(IntArrayList.emptyList()); + assertEquals(IntArrayList.emptyList(), copy); + + copy = new IntArrayList(asList(1, 2, 3)); + assertEquals(asList(1, 2, 3), copy); + + copy = new IntArrayList(Collections.emptyList()); + assertEquals(IntArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(1, 2, 3, 4)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(1, (int) list.get(0)); + assertEquals(1, (int) iterator.next()); + list.set(0, 1); + assertEquals(2, (int) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, 0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testGet() { + assertEquals(1, (int) TERTIARY_LIST.get(0)); + assertEquals(2, (int) TERTIARY_LIST.get(1)); + assertEquals(3, (int) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testGetInt() { + assertEquals(1, TERTIARY_LIST.getInt(0)); + assertEquals(2, TERTIARY_LIST.getInt(1)); + assertEquals(3, TERTIARY_LIST.getInt(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSize() { + assertEquals(0, IntArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.addInt(2); + list.addInt(4); + list.addInt(6); + list.addInt(8); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(16); + assertEquals(4, list.size()); + } + + public void testSet() { + list.addInt(2); + list.addInt(4); + + assertEquals(2, (int) list.set(0, 0)); + assertEquals(0, list.getInt(0)); + + assertEquals(4, (int) list.set(1, 0)); + assertEquals(0, list.getInt(1)); + + try { + list.set(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSetInt() { + list.addInt(2); + list.addInt(4); + + assertEquals(2, list.setInt(0, 0)); + assertEquals(0, list.getInt(0)); + + assertEquals(4, list.setInt(1, 0)); + assertEquals(0, list.getInt(1)); + + try { + list.setInt(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.setInt(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(2)); + assertEquals(asList(2), list); + + assertTrue(list.add(3)); + list.add(0, 4); + assertEquals(asList(4, 2, 3), list); + + list.add(0, 1); + list.add(0, 0); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(5 + i); + } + assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list); + + try { + list.add(-1, 5); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, 5); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddInt() { + assertEquals(0, list.size()); + + list.addInt(2); + assertEquals(asList(2), list); + + list.addInt(3); + assertEquals(asList(2, 3), list); + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(1))); + assertEquals(1, list.size()); + assertEquals(1, (int) list.get(0)); + assertEquals(1, list.getInt(0)); + + assertTrue(list.addAll(asList(2, 3, 4, 5, 6))); + assertEquals(asList(1, 2, 3, 4, 5, 6), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list); + + assertFalse(list.addAll(Collections.emptyList())); + assertFalse(list.addAll(IntArrayList.emptyList())); + } + + public void testRemove() { + list.addAll(TERTIARY_LIST); + assertEquals(1, (int) list.remove(0)); + assertEquals(asList(2, 3), list); + + assertTrue(list.remove(Integer.valueOf(3))); + assertEquals(asList(2), list); + + assertFalse(list.remove(Integer.valueOf(3))); + assertEquals(asList(2), list); + + assertEquals(2, (int) list.remove(0)); + assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + private void assertImmutable(IntArrayList list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, 1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new IntArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addInt(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.setInt(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static IntArrayList newImmutableIntArrayList(int... elements) { + IntArrayList list = new IntArrayList(); + for (int element : elements) { + list.addInt(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java index f3012b9631..0f42ac5060 100644 --- a/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java +++ b/java/src/test/java/com/google/protobuf/LazyStringArrayListTest.java @@ -30,9 +30,13 @@ package com.google.protobuf; +import static java.util.Arrays.asList; + import junit.framework.TestCase; import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Iterator; import java.util.List; /** @@ -171,4 +175,188 @@ public class LazyStringArrayListTest extends TestCase { assertSame(BYTE_STRING_B, list2.getByteString(1)); assertSame(BYTE_STRING_C, list2.getByteString(2)); } + + public void testModificationWithIteration() { + LazyStringArrayList list = new LazyStringArrayList(); + list.addAll(asList(STRING_A, STRING_B, STRING_C)); + Iterator iterator = list.iterator(); + assertEquals(3, list.size()); + assertEquals(STRING_A, list.get(0)); + assertEquals(STRING_A, iterator.next()); + + // Does not structurally modify. + iterator = list.iterator(); + list.set(0, STRING_B); + iterator.next(); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, STRING_C); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testMakeImmutable() { + LazyStringArrayList list = new LazyStringArrayList(); + list.add(STRING_A); + list.add(STRING_B); + list.add(STRING_C); + list.makeImmutable(); + assertGenericListImmutable(list, STRING_A); + + // LazyStringArrayList has extra methods not covered in the generic + // assertion. + + try { + list.add(BYTE_STRING_A.toByteArray()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(BYTE_STRING_A); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAllByteArray(asList(BYTE_STRING_A.toByteArray())); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAllByteString(asList(BYTE_STRING_A)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.mergeFrom(new LazyStringArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, BYTE_STRING_A.toByteArray()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, BYTE_STRING_A); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + public void testImmutabilityPropagation() { + LazyStringArrayList list = new LazyStringArrayList(); + list.add(STRING_A); + list.makeImmutable(); + + assertGenericListImmutable(list.asByteStringList(), BYTE_STRING_A); + + // Arrays use reference equality so need to retrieve the underlying value + // to properly test deep immutability. + List byteArrayList = list.asByteArrayList(); + assertGenericListImmutable(byteArrayList, byteArrayList.get(0)); + } + + private static void assertGenericListImmutable(List list, T value) { + try { + list.add(value); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, value); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(asList(value)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, asList(value)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(value); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(asList(value)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(asList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(asList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, value); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } } diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java index 4d8037fcbc..8c3b5e5c72 100644 --- a/java/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/src/test/java/com/google/protobuf/LiteTest.java @@ -30,9 +30,18 @@ package com.google.protobuf; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + import com.google.protobuf.UnittestLite; -import com.google.protobuf.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.ForeignEnumLite; +import com.google.protobuf.UnittestLite.ForeignMessageLite; import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage; +import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase; +import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup; +import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup; import com.google.protobuf.UnittestLite.TestNestedExtensionLite; import junit.framework.TestCase; @@ -149,13 +158,1302 @@ public class LiteTest extends TestCase { public void testClone() { TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder() .setOptionalInt32(123); - assertEquals( - expected.getOptionalInt32(), expected.clone().getOptionalInt32()); + assertEquals( + expected.getOptionalInt32(), expected.clone().getOptionalInt32()); - TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder() - .setExtension(UnittestLite.optionalInt32ExtensionLite, 123); - assertEquals( - expected2.getExtension(UnittestLite.optionalInt32ExtensionLite), - expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite)); + TestAllExtensionsLite.Builder expected2 = TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 123); + assertEquals( + expected2.getExtension(UnittestLite.optionalInt32ExtensionLite), + expected2.clone().getExtension(UnittestLite.optionalInt32ExtensionLite)); + } + + public void testAddAll() { + try { + TestAllTypesLite.newBuilder() + .addAllRepeatedBytes(null); + fail(); + } catch (NullPointerException e) { + // expected. + } + } + + public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { + // Since builders are implemented as a thin wrapper around a message + // instance, we attempt to verify that we can't cause the builder to modify + // a produced message. + + TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder(); + TestAllTypesLite message = builder.build(); + TestAllTypesLite messageAfterBuild; + builder.setOptionalBool(true); + assertEquals(false, message.getOptionalBool()); + assertEquals(true, builder.getOptionalBool()); + messageAfterBuild = builder.build(); + assertEquals(true, messageAfterBuild.getOptionalBool()); + assertEquals(false, message.getOptionalBool()); + builder.clearOptionalBool(); + assertEquals(false, builder.getOptionalBool()); + assertEquals(true, messageAfterBuild.getOptionalBool()); + + message = builder.build(); + builder.setOptionalBytes(ByteString.copyFromUtf8("hi")); + assertEquals(ByteString.EMPTY, message.getOptionalBytes()); + assertEquals(ByteString.copyFromUtf8("hi"), builder.getOptionalBytes()); + messageAfterBuild = builder.build(); + assertEquals( + ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes()); + assertEquals(ByteString.EMPTY, message.getOptionalBytes()); + builder.clearOptionalBytes(); + assertEquals(ByteString.EMPTY, builder.getOptionalBytes()); + assertEquals( + ByteString.copyFromUtf8("hi"), messageAfterBuild.getOptionalBytes()); + + message = builder.build(); + builder.setOptionalCord("hi"); + assertEquals("", message.getOptionalCord()); + assertEquals("hi", builder.getOptionalCord()); + messageAfterBuild = builder.build(); + assertEquals("hi", messageAfterBuild.getOptionalCord()); + assertEquals("", message.getOptionalCord()); + builder.clearOptionalCord(); + assertEquals("", builder.getOptionalCord()); + assertEquals("hi", messageAfterBuild.getOptionalCord()); + + message = builder.build(); + builder.setOptionalCordBytes(ByteString.copyFromUtf8("no")); + assertEquals(ByteString.EMPTY, message.getOptionalCordBytes()); + assertEquals(ByteString.copyFromUtf8("no"), builder.getOptionalCordBytes()); + messageAfterBuild = builder.build(); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalCordBytes()); + assertEquals(ByteString.EMPTY, message.getOptionalCordBytes()); + builder.clearOptionalCord(); + assertEquals(ByteString.EMPTY, builder.getOptionalCordBytes()); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalCordBytes()); + + message = builder.build(); + builder.setOptionalDouble(1); + assertEquals(0D, message.getOptionalDouble()); + assertEquals(1D, builder.getOptionalDouble()); + messageAfterBuild = builder.build(); + assertEquals(1D, messageAfterBuild.getOptionalDouble()); + assertEquals(0D, message.getOptionalDouble()); + builder.clearOptionalDouble(); + assertEquals(0D, builder.getOptionalDouble()); + assertEquals(1D, messageAfterBuild.getOptionalDouble()); + + message = builder.build(); + builder.setOptionalFixed32(1); + assertEquals(0, message.getOptionalFixed32()); + assertEquals(1, builder.getOptionalFixed32()); + messageAfterBuild = builder.build(); + assertEquals(1, messageAfterBuild.getOptionalFixed32()); + assertEquals(0, message.getOptionalFixed32()); + builder.clearOptionalFixed32(); + assertEquals(0, builder.getOptionalFixed32()); + assertEquals(1, messageAfterBuild.getOptionalFixed32()); + + message = builder.build(); + builder.setOptionalFixed64(1); + assertEquals(0L, message.getOptionalFixed64()); + assertEquals(1L, builder.getOptionalFixed64()); + messageAfterBuild = builder.build(); + assertEquals(1L, messageAfterBuild.getOptionalFixed64()); + assertEquals(0L, message.getOptionalFixed64()); + builder.clearOptionalFixed64(); + assertEquals(0L, builder.getOptionalFixed64()); + assertEquals(1L, messageAfterBuild.getOptionalFixed64()); + + message = builder.build(); + builder.setOptionalFloat(1); + assertEquals(0F, message.getOptionalFloat()); + assertEquals(1F, builder.getOptionalFloat()); + messageAfterBuild = builder.build(); + assertEquals(1F, messageAfterBuild.getOptionalFloat()); + assertEquals(0F, message.getOptionalFloat()); + builder.clearOptionalFloat(); + assertEquals(0F, builder.getOptionalFloat()); + assertEquals(1F, messageAfterBuild.getOptionalFloat()); + + message = builder.build(); + builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum()); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_BAR, builder.getOptionalForeignEnum()); + messageAfterBuild = builder.build(); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_BAR, + messageAfterBuild.getOptionalForeignEnum()); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_FOO, message.getOptionalForeignEnum()); + builder.clearOptionalForeignEnum(); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_FOO, builder.getOptionalForeignEnum()); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_BAR, + messageAfterBuild.getOptionalForeignEnum()); + + message = builder.build(); + ForeignMessageLite foreignMessage = ForeignMessageLite.newBuilder() + .setC(1) + .build(); + builder.setOptionalForeignMessage(foreignMessage); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + message.getOptionalForeignMessage()); + assertEquals(foreignMessage, builder.getOptionalForeignMessage()); + messageAfterBuild = builder.build(); + assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage()); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + message.getOptionalForeignMessage()); + builder.clearOptionalForeignMessage(); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + builder.getOptionalForeignMessage()); + assertEquals(foreignMessage, messageAfterBuild.getOptionalForeignMessage()); + + message = builder.build(); + ForeignMessageLite.Builder foreignMessageBuilder = + ForeignMessageLite.newBuilder() + .setC(3); + builder.setOptionalForeignMessage(foreignMessageBuilder); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + message.getOptionalForeignMessage()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on foreignMessage. + assertEquals(3, builder.getOptionalForeignMessage().getC()); + messageAfterBuild = builder.build(); + assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC()); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + message.getOptionalForeignMessage()); + builder.clearOptionalForeignMessage(); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + builder.getOptionalForeignMessage()); + assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC()); + + message = builder.build(); + OptionalGroup optionalGroup = OptionalGroup.newBuilder() + .setA(1) + .build(); + builder.setOptionalGroup(optionalGroup); + assertEquals( + OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); + assertEquals(optionalGroup, builder.getOptionalGroup()); + messageAfterBuild = builder.build(); + assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup()); + assertEquals( + OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); + builder.clearOptionalGroup(); + assertEquals( + OptionalGroup.getDefaultInstance(), builder.getOptionalGroup()); + assertEquals(optionalGroup, messageAfterBuild.getOptionalGroup()); + + message = builder.build(); + OptionalGroup.Builder optionalGroupBuilder = OptionalGroup.newBuilder() + .setA(3); + builder.setOptionalGroup(optionalGroupBuilder); + assertEquals( + OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on optionalGroup. + assertEquals(3, builder.getOptionalGroup().getA()); + messageAfterBuild = builder.build(); + assertEquals(3, messageAfterBuild.getOptionalGroup().getA()); + assertEquals( + OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); + builder.clearOptionalGroup(); + assertEquals( + OptionalGroup.getDefaultInstance(), builder.getOptionalGroup()); + assertEquals(3, messageAfterBuild.getOptionalGroup().getA()); + + message = builder.build(); + builder.setOptionalInt32(1); + assertEquals(0, message.getOptionalInt32()); + assertEquals(1, builder.getOptionalInt32()); + messageAfterBuild = builder.build(); + assertEquals(1, messageAfterBuild.getOptionalInt32()); + assertEquals(0, message.getOptionalInt32()); + builder.clearOptionalInt32(); + assertEquals(0, builder.getOptionalInt32()); + assertEquals(1, messageAfterBuild.getOptionalInt32()); + + message = builder.build(); + builder.setOptionalInt64(1); + assertEquals(0L, message.getOptionalInt64()); + assertEquals(1L, builder.getOptionalInt64()); + messageAfterBuild = builder.build(); + assertEquals(1L, messageAfterBuild.getOptionalInt64()); + assertEquals(0L, message.getOptionalInt64()); + builder.clearOptionalInt64(); + assertEquals(0L, builder.getOptionalInt64()); + assertEquals(1L, messageAfterBuild.getOptionalInt64()); + + message = builder.build(); + NestedMessage nestedMessage = NestedMessage.newBuilder() + .setBb(1) + .build(); + builder.setOptionalLazyMessage(nestedMessage); + assertEquals( + NestedMessage.getDefaultInstance(), + message.getOptionalLazyMessage()); + assertEquals(nestedMessage, builder.getOptionalLazyMessage()); + messageAfterBuild = builder.build(); + assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage()); + assertEquals( + NestedMessage.getDefaultInstance(), + message.getOptionalLazyMessage()); + builder.clearOptionalLazyMessage(); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage()); + assertEquals(nestedMessage, messageAfterBuild.getOptionalLazyMessage()); + + message = builder.build(); + NestedMessage.Builder nestedMessageBuilder = + NestedMessage.newBuilder() + .setBb(3); + builder.setOptionalLazyMessage(nestedMessageBuilder); + assertEquals( + NestedMessage.getDefaultInstance(), + message.getOptionalLazyMessage()); + // LITE_RUNTIME doesn't implement equals so we compare on a property. + assertEquals(3, builder.getOptionalLazyMessage().getBb()); + messageAfterBuild = builder.build(); + assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb()); + assertEquals( + NestedMessage.getDefaultInstance(), + message.getOptionalLazyMessage()); + builder.clearOptionalLazyMessage(); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage()); + assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb()); + + message = builder.build(); + builder.setOptionalSfixed32(1); + assertEquals(0, message.getOptionalSfixed32()); + assertEquals(1, builder.getOptionalSfixed32()); + messageAfterBuild = builder.build(); + assertEquals(1, messageAfterBuild.getOptionalSfixed32()); + assertEquals(0, message.getOptionalSfixed32()); + builder.clearOptionalSfixed32(); + assertEquals(0, builder.getOptionalSfixed32()); + assertEquals(1, messageAfterBuild.getOptionalSfixed32()); + + message = builder.build(); + builder.setOptionalSfixed64(1); + assertEquals(0L, message.getOptionalSfixed64()); + assertEquals(1L, builder.getOptionalSfixed64()); + messageAfterBuild = builder.build(); + assertEquals(1L, messageAfterBuild.getOptionalSfixed64()); + assertEquals(0L, message.getOptionalSfixed64()); + builder.clearOptionalSfixed64(); + assertEquals(0L, builder.getOptionalSfixed64()); + assertEquals(1L, messageAfterBuild.getOptionalSfixed64()); + + message = builder.build(); + builder.setOptionalSint32(1); + assertEquals(0, message.getOptionalSint32()); + assertEquals(1, builder.getOptionalSint32()); + messageAfterBuild = builder.build(); + assertEquals(1, messageAfterBuild.getOptionalSint32()); + builder.clearOptionalSint32(); + assertEquals(0, builder.getOptionalSint32()); + assertEquals(1, messageAfterBuild.getOptionalSint32()); + + message = builder.build(); + builder.setOptionalSint64(1); + assertEquals(0L, message.getOptionalSint64()); + assertEquals(1L, builder.getOptionalSint64()); + messageAfterBuild = builder.build(); + assertEquals(1L, messageAfterBuild.getOptionalSint64()); + assertEquals(0L, message.getOptionalSint64()); + builder.clearOptionalSint64(); + assertEquals(0L, builder.getOptionalSint64()); + assertEquals(1L, messageAfterBuild.getOptionalSint64()); + + message = builder.build(); + builder.setOptionalString("hi"); + assertEquals("", message.getOptionalString()); + assertEquals("hi", builder.getOptionalString()); + messageAfterBuild = builder.build(); + assertEquals("hi", messageAfterBuild.getOptionalString()); + assertEquals("", message.getOptionalString()); + builder.clearOptionalString(); + assertEquals("", builder.getOptionalString()); + assertEquals("hi", messageAfterBuild.getOptionalString()); + + message = builder.build(); + builder.setOptionalStringBytes(ByteString.copyFromUtf8("no")); + assertEquals(ByteString.EMPTY, message.getOptionalStringBytes()); + assertEquals( + ByteString.copyFromUtf8("no"), builder.getOptionalStringBytes()); + messageAfterBuild = builder.build(); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalStringBytes()); + assertEquals(ByteString.EMPTY, message.getOptionalStringBytes()); + builder.clearOptionalString(); + assertEquals(ByteString.EMPTY, builder.getOptionalStringBytes()); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalStringBytes()); + + message = builder.build(); + builder.setOptionalStringPiece("hi"); + assertEquals("", message.getOptionalStringPiece()); + assertEquals("hi", builder.getOptionalStringPiece()); + messageAfterBuild = builder.build(); + assertEquals("hi", messageAfterBuild.getOptionalStringPiece()); + assertEquals("", message.getOptionalStringPiece()); + builder.clearOptionalStringPiece(); + assertEquals("", builder.getOptionalStringPiece()); + assertEquals("hi", messageAfterBuild.getOptionalStringPiece()); + + message = builder.build(); + builder.setOptionalStringPieceBytes(ByteString.copyFromUtf8("no")); + assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes()); + assertEquals( + ByteString.copyFromUtf8("no"), builder.getOptionalStringPieceBytes()); + messageAfterBuild = builder.build(); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalStringPieceBytes()); + assertEquals(ByteString.EMPTY, message.getOptionalStringPieceBytes()); + builder.clearOptionalStringPiece(); + assertEquals(ByteString.EMPTY, builder.getOptionalStringPieceBytes()); + assertEquals( + ByteString.copyFromUtf8("no"), + messageAfterBuild.getOptionalStringPieceBytes()); + + message = builder.build(); + builder.setOptionalUint32(1); + assertEquals(0, message.getOptionalUint32()); + assertEquals(1, builder.getOptionalUint32()); + messageAfterBuild = builder.build(); + assertEquals(1, messageAfterBuild.getOptionalUint32()); + assertEquals(0, message.getOptionalUint32()); + builder.clearOptionalUint32(); + assertEquals(0, builder.getOptionalUint32()); + assertEquals(1, messageAfterBuild.getOptionalUint32()); + + message = builder.build(); + builder.setOptionalUint64(1); + assertEquals(0L, message.getOptionalUint64()); + assertEquals(1L, builder.getOptionalUint64()); + messageAfterBuild = builder.build(); + assertEquals(1L, messageAfterBuild.getOptionalUint64()); + assertEquals(0L, message.getOptionalUint64()); + builder.clearOptionalUint64(); + assertEquals(0L, builder.getOptionalUint64()); + assertEquals(1L, messageAfterBuild.getOptionalUint64()); + + message = builder.build(); + builder.addAllRepeatedBool(singletonList(true)); + assertEquals(emptyList(), message.getRepeatedBoolList()); + assertEquals(singletonList(true), builder.getRepeatedBoolList()); + assertEquals(emptyList(), message.getRepeatedBoolList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedBool(); + assertEquals(emptyList(), builder.getRepeatedBoolList()); + assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList()); + + message = builder.build(); + builder.addAllRepeatedBytes(singletonList(ByteString.copyFromUtf8("hi"))); + assertEquals(emptyList(), message.getRepeatedBytesList()); + assertEquals( + singletonList(ByteString.copyFromUtf8("hi")), + builder.getRepeatedBytesList()); + assertEquals(emptyList(), message.getRepeatedBytesList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedBytes(); + assertEquals(emptyList(), builder.getRepeatedBytesList()); + assertEquals( + singletonList(ByteString.copyFromUtf8("hi")), + messageAfterBuild.getRepeatedBytesList()); + + message = builder.build(); + builder.addAllRepeatedCord(singletonList("hi")); + assertEquals(emptyList(), message.getRepeatedCordList()); + assertEquals(singletonList("hi"), builder.getRepeatedCordList()); + assertEquals(emptyList(), message.getRepeatedCordList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedCord(); + assertEquals(emptyList(), builder.getRepeatedCordList()); + assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList()); + + message = builder.build(); + builder.addAllRepeatedDouble(singletonList(1D)); + assertEquals(emptyList(), message.getRepeatedDoubleList()); + assertEquals(singletonList(1D), builder.getRepeatedDoubleList()); + assertEquals(emptyList(), message.getRepeatedDoubleList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedDouble(); + assertEquals(emptyList(), builder.getRepeatedDoubleList()); + assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList()); + + message = builder.build(); + builder.addAllRepeatedFixed32(singletonList(1)); + assertEquals(emptyList(), message.getRepeatedFixed32List()); + assertEquals(singletonList(1), builder.getRepeatedFixed32List()); + assertEquals(emptyList(), message.getRepeatedFixed32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFixed32(); + assertEquals(emptyList(), builder.getRepeatedFixed32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List()); + + message = builder.build(); + builder.addAllRepeatedFixed64(singletonList(1L)); + assertEquals(emptyList(), message.getRepeatedFixed64List()); + assertEquals(singletonList(1L), builder.getRepeatedFixed64List()); + assertEquals(emptyList(), message.getRepeatedFixed64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFixed64(); + assertEquals(emptyList(), builder.getRepeatedFixed64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List()); + + message = builder.build(); + builder.addAllRepeatedFloat(singletonList(1F)); + assertEquals(emptyList(), message.getRepeatedFloatList()); + assertEquals(singletonList(1F), builder.getRepeatedFloatList()); + assertEquals(emptyList(), message.getRepeatedFloatList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFloat(); + assertEquals(emptyList(), builder.getRepeatedFloatList()); + assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList()); + + message = builder.build(); + builder.addAllRepeatedForeignEnum( + singletonList(ForeignEnumLite.FOREIGN_LITE_BAR)); + assertEquals(emptyList(), message.getRepeatedForeignEnumList()); + assertEquals( + singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), + builder.getRepeatedForeignEnumList()); + assertEquals(emptyList(), message.getRepeatedForeignEnumList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedForeignEnum(); + assertEquals(emptyList(), builder.getRepeatedForeignEnumList()); + assertEquals( + singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), + messageAfterBuild.getRepeatedForeignEnumList()); + + message = builder.build(); + builder.addAllRepeatedForeignMessage(singletonList(foreignMessage)); + assertEquals(emptyList(), message.getRepeatedForeignMessageList()); + assertEquals( + singletonList(foreignMessage), builder.getRepeatedForeignMessageList()); + assertEquals(emptyList(), message.getRepeatedForeignMessageList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedForeignMessage(); + assertEquals(emptyList(), builder.getRepeatedForeignMessageList()); + assertEquals( + singletonList(foreignMessage), + messageAfterBuild.getRepeatedForeignMessageList()); + + message = builder.build(); + builder.addAllRepeatedGroup( + singletonList(RepeatedGroup.getDefaultInstance())); + assertEquals(emptyList(), message.getRepeatedGroupList()); + assertEquals( + singletonList(RepeatedGroup.getDefaultInstance()), + builder.getRepeatedGroupList()); + assertEquals(emptyList(), message.getRepeatedGroupList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedGroup(); + assertEquals(emptyList(), builder.getRepeatedGroupList()); + assertEquals( + singletonList(RepeatedGroup.getDefaultInstance()), + messageAfterBuild.getRepeatedGroupList()); + + message = builder.build(); + builder.addAllRepeatedInt32(singletonList(1)); + assertEquals(emptyList(), message.getRepeatedInt32List()); + assertEquals(singletonList(1), builder.getRepeatedInt32List()); + assertEquals(emptyList(), message.getRepeatedInt32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedInt32(); + assertEquals(emptyList(), builder.getRepeatedInt32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List()); + + message = builder.build(); + builder.addAllRepeatedInt64(singletonList(1L)); + assertEquals(emptyList(), message.getRepeatedInt64List()); + assertEquals(singletonList(1L), builder.getRepeatedInt64List()); + assertEquals(emptyList(), message.getRepeatedInt64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedInt64(); + assertEquals(emptyList(), builder.getRepeatedInt64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List()); + + message = builder.build(); + builder.addAllRepeatedLazyMessage(singletonList(nestedMessage)); + assertEquals(emptyList(), message.getRepeatedLazyMessageList()); + assertEquals( + singletonList(nestedMessage), builder.getRepeatedLazyMessageList()); + assertEquals(emptyList(), message.getRepeatedLazyMessageList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedLazyMessage(); + assertEquals(emptyList(), builder.getRepeatedLazyMessageList()); + assertEquals( + singletonList(nestedMessage), + messageAfterBuild.getRepeatedLazyMessageList()); + + message = builder.build(); + builder.addAllRepeatedSfixed32(singletonList(1)); + assertEquals(emptyList(), message.getRepeatedSfixed32List()); + assertEquals(singletonList(1), builder.getRepeatedSfixed32List()); + assertEquals(emptyList(), message.getRepeatedSfixed32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSfixed32(); + assertEquals(emptyList(), builder.getRepeatedSfixed32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List()); + + message = builder.build(); + builder.addAllRepeatedSfixed64(singletonList(1L)); + assertEquals(emptyList(), message.getRepeatedSfixed64List()); + assertEquals(singletonList(1L), builder.getRepeatedSfixed64List()); + assertEquals(emptyList(), message.getRepeatedSfixed64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSfixed64(); + assertEquals(emptyList(), builder.getRepeatedSfixed64List()); + assertEquals( + singletonList(1L), messageAfterBuild.getRepeatedSfixed64List()); + + message = builder.build(); + builder.addAllRepeatedSint32(singletonList(1)); + assertEquals(emptyList(), message.getRepeatedSint32List()); + assertEquals(singletonList(1), builder.getRepeatedSint32List()); + assertEquals(emptyList(), message.getRepeatedSint32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSint32(); + assertEquals(emptyList(), builder.getRepeatedSint32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List()); + + message = builder.build(); + builder.addAllRepeatedSint64(singletonList(1L)); + assertEquals(emptyList(), message.getRepeatedSint64List()); + assertEquals(singletonList(1L), builder.getRepeatedSint64List()); + assertEquals(emptyList(), message.getRepeatedSint64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSint64(); + assertEquals(emptyList(), builder.getRepeatedSint64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List()); + + message = builder.build(); + builder.addAllRepeatedString(singletonList("hi")); + assertEquals(emptyList(), message.getRepeatedStringList()); + assertEquals(singletonList("hi"), builder.getRepeatedStringList()); + assertEquals(emptyList(), message.getRepeatedStringList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedString(); + assertEquals(emptyList(), builder.getRepeatedStringList()); + assertEquals( + singletonList("hi"), messageAfterBuild.getRepeatedStringList()); + + message = builder.build(); + builder.addAllRepeatedStringPiece(singletonList("hi")); + assertEquals(emptyList(), message.getRepeatedStringPieceList()); + assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList()); + assertEquals(emptyList(), message.getRepeatedStringPieceList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedStringPiece(); + assertEquals(emptyList(), builder.getRepeatedStringPieceList()); + assertEquals( + singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList()); + + message = builder.build(); + builder.addAllRepeatedUint32(singletonList(1)); + assertEquals(emptyList(), message.getRepeatedUint32List()); + assertEquals(singletonList(1), builder.getRepeatedUint32List()); + assertEquals(emptyList(), message.getRepeatedUint32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedUint32(); + assertEquals(emptyList(), builder.getRepeatedUint32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List()); + + message = builder.build(); + builder.addAllRepeatedUint64(singletonList(1L)); + assertEquals(emptyList(), message.getRepeatedUint64List()); + assertEquals(singletonList(1L), builder.getRepeatedUint64List()); + assertEquals(emptyList(), message.getRepeatedUint64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedUint64(); + assertEquals(emptyList(), builder.getRepeatedUint64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List()); + + message = builder.build(); + builder.addRepeatedBool(true); + assertEquals(emptyList(), message.getRepeatedBoolList()); + assertEquals(singletonList(true), builder.getRepeatedBoolList()); + assertEquals(emptyList(), message.getRepeatedBoolList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedBool(); + assertEquals(emptyList(), builder.getRepeatedBoolList()); + assertEquals(singletonList(true), messageAfterBuild.getRepeatedBoolList()); + + message = builder.build(); + builder.addRepeatedBytes(ByteString.copyFromUtf8("hi")); + assertEquals(emptyList(), message.getRepeatedBytesList()); + assertEquals( + singletonList(ByteString.copyFromUtf8("hi")), + builder.getRepeatedBytesList()); + assertEquals(emptyList(), message.getRepeatedBytesList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedBytes(); + assertEquals(emptyList(), builder.getRepeatedBytesList()); + assertEquals( + singletonList(ByteString.copyFromUtf8("hi")), + messageAfterBuild.getRepeatedBytesList()); + + message = builder.build(); + builder.addRepeatedCord("hi"); + assertEquals(emptyList(), message.getRepeatedCordList()); + assertEquals(singletonList("hi"), builder.getRepeatedCordList()); + assertEquals(emptyList(), message.getRepeatedCordList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedCord(); + assertEquals(emptyList(), builder.getRepeatedCordList()); + assertEquals(singletonList("hi"), messageAfterBuild.getRepeatedCordList()); + + message = builder.build(); + builder.addRepeatedDouble(1D); + assertEquals(emptyList(), message.getRepeatedDoubleList()); + assertEquals(singletonList(1D), builder.getRepeatedDoubleList()); + assertEquals(emptyList(), message.getRepeatedDoubleList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedDouble(); + assertEquals(emptyList(), builder.getRepeatedDoubleList()); + assertEquals(singletonList(1D), messageAfterBuild.getRepeatedDoubleList()); + + message = builder.build(); + builder.addRepeatedFixed32(1); + assertEquals(emptyList(), message.getRepeatedFixed32List()); + assertEquals(singletonList(1), builder.getRepeatedFixed32List()); + assertEquals(emptyList(), message.getRepeatedFixed32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFixed32(); + assertEquals(emptyList(), builder.getRepeatedFixed32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedFixed32List()); + + message = builder.build(); + builder.addRepeatedFixed64(1L); + assertEquals(emptyList(), message.getRepeatedFixed64List()); + assertEquals(singletonList(1L), builder.getRepeatedFixed64List()); + assertEquals(emptyList(), message.getRepeatedFixed64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFixed64(); + assertEquals(emptyList(), builder.getRepeatedFixed64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedFixed64List()); + + message = builder.build(); + builder.addRepeatedFloat(1F); + assertEquals(emptyList(), message.getRepeatedFloatList()); + assertEquals(singletonList(1F), builder.getRepeatedFloatList()); + assertEquals(emptyList(), message.getRepeatedFloatList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedFloat(); + assertEquals(emptyList(), builder.getRepeatedFloatList()); + assertEquals(singletonList(1F), messageAfterBuild.getRepeatedFloatList()); + + message = builder.build(); + builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR); + assertEquals(emptyList(), message.getRepeatedForeignEnumList()); + assertEquals( + singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), + builder.getRepeatedForeignEnumList()); + assertEquals(emptyList(), message.getRepeatedForeignEnumList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedForeignEnum(); + assertEquals(emptyList(), builder.getRepeatedForeignEnumList()); + assertEquals( + singletonList(ForeignEnumLite.FOREIGN_LITE_BAR), + messageAfterBuild.getRepeatedForeignEnumList()); + + message = builder.build(); + builder.addRepeatedForeignMessage(foreignMessage); + assertEquals(emptyList(), message.getRepeatedForeignMessageList()); + assertEquals( + singletonList(foreignMessage), builder.getRepeatedForeignMessageList()); + assertEquals(emptyList(), message.getRepeatedForeignMessageList()); + messageAfterBuild = builder.build(); + builder.removeRepeatedForeignMessage(0); + assertEquals(emptyList(), builder.getRepeatedForeignMessageList()); + assertEquals( + singletonList(foreignMessage), + messageAfterBuild.getRepeatedForeignMessageList()); + + message = builder.build(); + builder.addRepeatedGroup(RepeatedGroup.getDefaultInstance()); + assertEquals(emptyList(), message.getRepeatedGroupList()); + assertEquals( + singletonList(RepeatedGroup.getDefaultInstance()), + builder.getRepeatedGroupList()); + assertEquals(emptyList(), message.getRepeatedGroupList()); + messageAfterBuild = builder.build(); + builder.removeRepeatedGroup(0); + assertEquals(emptyList(), builder.getRepeatedGroupList()); + assertEquals( + singletonList(RepeatedGroup.getDefaultInstance()), + messageAfterBuild.getRepeatedGroupList()); + + message = builder.build(); + builder.addRepeatedInt32(1); + assertEquals(emptyList(), message.getRepeatedInt32List()); + assertEquals(singletonList(1), builder.getRepeatedInt32List()); + assertEquals(emptyList(), message.getRepeatedInt32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedInt32(); + assertEquals(emptyList(), builder.getRepeatedInt32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedInt32List()); + + message = builder.build(); + builder.addRepeatedInt64(1L); + assertEquals(emptyList(), message.getRepeatedInt64List()); + assertEquals(singletonList(1L), builder.getRepeatedInt64List()); + assertEquals(emptyList(), message.getRepeatedInt64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedInt64(); + assertEquals(emptyList(), builder.getRepeatedInt64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedInt64List()); + + message = builder.build(); + builder.addRepeatedLazyMessage(nestedMessage); + assertEquals(emptyList(), message.getRepeatedLazyMessageList()); + assertEquals( + singletonList(nestedMessage), builder.getRepeatedLazyMessageList()); + assertEquals(emptyList(), message.getRepeatedLazyMessageList()); + messageAfterBuild = builder.build(); + builder.removeRepeatedLazyMessage(0); + assertEquals(emptyList(), builder.getRepeatedLazyMessageList()); + assertEquals( + singletonList(nestedMessage), + messageAfterBuild.getRepeatedLazyMessageList()); + + message = builder.build(); + builder.addRepeatedSfixed32(1); + assertEquals(emptyList(), message.getRepeatedSfixed32List()); + assertEquals(singletonList(1), builder.getRepeatedSfixed32List()); + assertEquals(emptyList(), message.getRepeatedSfixed32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSfixed32(); + assertEquals(emptyList(), builder.getRepeatedSfixed32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedSfixed32List()); + + message = builder.build(); + builder.addRepeatedSfixed64(1L); + assertEquals(emptyList(), message.getRepeatedSfixed64List()); + assertEquals(singletonList(1L), builder.getRepeatedSfixed64List()); + assertEquals(emptyList(), message.getRepeatedSfixed64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSfixed64(); + assertEquals(emptyList(), builder.getRepeatedSfixed64List()); + assertEquals( + singletonList(1L), messageAfterBuild.getRepeatedSfixed64List()); + + message = builder.build(); + builder.addRepeatedSint32(1); + assertEquals(emptyList(), message.getRepeatedSint32List()); + assertEquals(singletonList(1), builder.getRepeatedSint32List()); + assertEquals(emptyList(), message.getRepeatedSint32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSint32(); + assertEquals(emptyList(), builder.getRepeatedSint32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedSint32List()); + + message = builder.build(); + builder.addRepeatedSint64(1L); + assertEquals(emptyList(), message.getRepeatedSint64List()); + assertEquals(singletonList(1L), builder.getRepeatedSint64List()); + assertEquals(emptyList(), message.getRepeatedSint64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedSint64(); + assertEquals(emptyList(), builder.getRepeatedSint64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedSint64List()); + + message = builder.build(); + builder.addRepeatedString("hi"); + assertEquals(emptyList(), message.getRepeatedStringList()); + assertEquals(singletonList("hi"), builder.getRepeatedStringList()); + assertEquals(emptyList(), message.getRepeatedStringList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedString(); + assertEquals(emptyList(), builder.getRepeatedStringList()); + assertEquals( + singletonList("hi"), messageAfterBuild.getRepeatedStringList()); + + message = builder.build(); + builder.addRepeatedStringPiece("hi"); + assertEquals(emptyList(), message.getRepeatedStringPieceList()); + assertEquals(singletonList("hi"), builder.getRepeatedStringPieceList()); + assertEquals(emptyList(), message.getRepeatedStringPieceList()); + messageAfterBuild = builder.build(); + builder.clearRepeatedStringPiece(); + assertEquals(emptyList(), builder.getRepeatedStringPieceList()); + assertEquals( + singletonList("hi"), messageAfterBuild.getRepeatedStringPieceList()); + + message = builder.build(); + builder.addRepeatedUint32(1); + assertEquals(emptyList(), message.getRepeatedUint32List()); + assertEquals(singletonList(1), builder.getRepeatedUint32List()); + assertEquals(emptyList(), message.getRepeatedUint32List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedUint32(); + assertEquals(emptyList(), builder.getRepeatedUint32List()); + assertEquals(singletonList(1), messageAfterBuild.getRepeatedUint32List()); + + message = builder.build(); + builder.addRepeatedUint64(1L); + assertEquals(emptyList(), message.getRepeatedUint64List()); + assertEquals(singletonList(1L), builder.getRepeatedUint64List()); + assertEquals(emptyList(), message.getRepeatedUint64List()); + messageAfterBuild = builder.build(); + builder.clearRepeatedUint64(); + assertEquals(emptyList(), builder.getRepeatedUint64List()); + assertEquals(singletonList(1L), messageAfterBuild.getRepeatedUint64List()); + + message = builder.build(); + builder.addRepeatedBool(true); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedBoolCount()); + builder.setRepeatedBool(0, false); + assertEquals(true, messageAfterBuild.getRepeatedBool(0)); + assertEquals(false, builder.getRepeatedBool(0)); + builder.clearRepeatedBool(); + + message = builder.build(); + builder.addRepeatedBytes(ByteString.copyFromUtf8("hi")); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedBytesCount()); + builder.setRepeatedBytes(0, ByteString.EMPTY); + assertEquals( + ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedBytes(0)); + assertEquals(ByteString.EMPTY, builder.getRepeatedBytes(0)); + builder.clearRepeatedBytes(); + + message = builder.build(); + builder.addRepeatedCord("hi"); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedCordCount()); + builder.setRepeatedCord(0, ""); + assertEquals("hi", messageAfterBuild.getRepeatedCord(0)); + assertEquals("", builder.getRepeatedCord(0)); + builder.clearRepeatedCord(); + message = builder.build(); + + builder.addRepeatedCordBytes(ByteString.copyFromUtf8("hi")); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedCordCount()); + builder.setRepeatedCord(0, ""); + assertEquals( + ByteString.copyFromUtf8("hi"), messageAfterBuild.getRepeatedCordBytes(0)); + assertEquals(ByteString.EMPTY, builder.getRepeatedCordBytes(0)); + builder.clearRepeatedCord(); + + message = builder.build(); + builder.addRepeatedDouble(1D); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedDoubleCount()); + builder.setRepeatedDouble(0, 0D); + assertEquals(1D, messageAfterBuild.getRepeatedDouble(0)); + assertEquals(0D, builder.getRepeatedDouble(0)); + builder.clearRepeatedDouble(); + + message = builder.build(); + builder.addRepeatedFixed32(1); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedFixed32Count()); + builder.setRepeatedFixed32(0, 0); + assertEquals(1, messageAfterBuild.getRepeatedFixed32(0)); + assertEquals(0, builder.getRepeatedFixed32(0)); + builder.clearRepeatedFixed32(); + + message = builder.build(); + builder.addRepeatedFixed64(1L); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedFixed64Count()); + builder.setRepeatedFixed64(0, 0L); + assertEquals(1L, messageAfterBuild.getRepeatedFixed64(0)); + assertEquals(0L, builder.getRepeatedFixed64(0)); + builder.clearRepeatedFixed64(); + + message = builder.build(); + builder.addRepeatedFloat(1F); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedFloatCount()); + builder.setRepeatedFloat(0, 0F); + assertEquals(1F, messageAfterBuild.getRepeatedFloat(0)); + assertEquals(0F, builder.getRepeatedFloat(0)); + builder.clearRepeatedFloat(); + + message = builder.build(); + builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedForeignEnumCount()); + builder.setRepeatedForeignEnum(0, ForeignEnumLite.FOREIGN_LITE_FOO); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_BAR, + messageAfterBuild.getRepeatedForeignEnum(0)); + assertEquals( + ForeignEnumLite.FOREIGN_LITE_FOO, builder.getRepeatedForeignEnum(0)); + builder.clearRepeatedForeignEnum(); + + message = builder.build(); + builder.addRepeatedForeignMessage(foreignMessage); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedForeignMessageCount()); + builder.setRepeatedForeignMessage( + 0, ForeignMessageLite.getDefaultInstance()); + assertEquals( + foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0)); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + builder.getRepeatedForeignMessage(0)); + builder.clearRepeatedForeignMessage(); + + message = builder.build(); + builder.addRepeatedForeignMessage(foreignMessageBuilder); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedForeignMessageCount()); + builder.setRepeatedForeignMessage( + 0, ForeignMessageLite.getDefaultInstance()); + // LITE_RUNTIME doesn't implement equals so we compare on a property. + assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC()); + assertEquals( + ForeignMessageLite.getDefaultInstance(), + builder.getRepeatedForeignMessage(0)); + builder.clearRepeatedForeignMessage(); + + message = builder.build(); + builder.addRepeatedForeignMessage(0, foreignMessage); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedForeignMessageCount()); + builder.setRepeatedForeignMessage(0, foreignMessageBuilder); + assertEquals( + foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0)); + // LITE_RUNTIME doesn't implement equals so we compare on a property. + assertEquals(3, builder.getRepeatedForeignMessage(0).getC()); + builder.clearRepeatedForeignMessage(); + + message = builder.build(); + RepeatedGroup repeatedGroup = RepeatedGroup.newBuilder() + .setA(1) + .build(); + builder.addRepeatedGroup(repeatedGroup); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedGroupCount()); + builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); + assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0)); + assertEquals( + RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); + builder.clearRepeatedGroup(); + + message = builder.build(); + builder.addRepeatedGroup(0, repeatedGroup); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedGroupCount()); + builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); + assertEquals(repeatedGroup, messageAfterBuild.getRepeatedGroup(0)); + assertEquals( + RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); + builder.clearRepeatedGroup(); + + message = builder.build(); + RepeatedGroup.Builder repeatedGroupBuilder = RepeatedGroup.newBuilder() + .setA(3); + builder.addRepeatedGroup(repeatedGroupBuilder); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedGroupCount()); + builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on repeatedGroup. + assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA()); + assertEquals( + RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); + builder.clearRepeatedGroup(); + + message = builder.build(); + builder.addRepeatedGroup(0, repeatedGroupBuilder); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedGroupCount()); + builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on repeatedGroup. + assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA()); + assertEquals( + RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); + builder.clearRepeatedGroup(); + + message = builder.build(); + builder.addRepeatedInt32(1); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedInt32Count()); + builder.setRepeatedInt32(0, 0); + assertEquals(1, messageAfterBuild.getRepeatedInt32(0)); + assertEquals(0, builder.getRepeatedInt32(0)); + builder.clearRepeatedInt32(); + + message = builder.build(); + builder.addRepeatedInt64(1L); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedInt64Count()); + builder.setRepeatedInt64(0, 0L); + assertEquals(1L, messageAfterBuild.getRepeatedInt64(0)); + assertEquals(0L, builder.getRepeatedInt64(0)); + builder.clearRepeatedInt64(); + + message = builder.build(); + builder.addRepeatedLazyMessage(nestedMessage); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedLazyMessageCount()); + builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); + assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0)); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); + builder.clearRepeatedLazyMessage(); + + message = builder.build(); + builder.addRepeatedLazyMessage(0, nestedMessage); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedLazyMessageCount()); + builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); + assertEquals(nestedMessage, messageAfterBuild.getRepeatedLazyMessage(0)); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); + builder.clearRepeatedLazyMessage(); + + message = builder.build(); + builder.addRepeatedLazyMessage(nestedMessageBuilder); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedLazyMessageCount()); + builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on repeatedGroup. + assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb()); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); + builder.clearRepeatedLazyMessage(); + + message = builder.build(); + builder.addRepeatedLazyMessage(0, nestedMessageBuilder); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedLazyMessageCount()); + builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); + // LITE_RUNTIME doesn't implement equals so we compare on a property and + // ensure the property isn't set on repeatedGroup. + assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb()); + assertEquals( + NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); + builder.clearRepeatedLazyMessage(); + + message = builder.build(); + builder.addRepeatedSfixed32(1); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedSfixed32Count()); + builder.setRepeatedSfixed32(0, 0); + assertEquals(1, messageAfterBuild.getRepeatedSfixed32(0)); + assertEquals(0, builder.getRepeatedSfixed32(0)); + builder.clearRepeatedSfixed32(); + + message = builder.build(); + builder.addRepeatedSfixed64(1L); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedSfixed64Count()); + builder.setRepeatedSfixed64(0, 0L); + assertEquals(1L, messageAfterBuild.getRepeatedSfixed64(0)); + assertEquals(0L, builder.getRepeatedSfixed64(0)); + builder.clearRepeatedSfixed64(); + + message = builder.build(); + builder.addRepeatedSint32(1); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedSint32Count()); + builder.setRepeatedSint32(0, 0); + assertEquals(1, messageAfterBuild.getRepeatedSint32(0)); + assertEquals(0, builder.getRepeatedSint32(0)); + builder.clearRepeatedSint32(); + + message = builder.build(); + builder.addRepeatedSint64(1L); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedSint64Count()); + builder.setRepeatedSint64(0, 0L); + assertEquals(1L, messageAfterBuild.getRepeatedSint64(0)); + assertEquals(0L, builder.getRepeatedSint64(0)); + builder.clearRepeatedSint64(); + + message = builder.build(); + builder.addRepeatedString("hi"); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedStringCount()); + builder.setRepeatedString(0, ""); + assertEquals("hi", messageAfterBuild.getRepeatedString(0)); + assertEquals("", builder.getRepeatedString(0)); + builder.clearRepeatedString(); + + message = builder.build(); + builder.addRepeatedStringBytes(ByteString.copyFromUtf8("hi")); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedStringCount()); + builder.setRepeatedString(0, ""); + assertEquals( + ByteString.copyFromUtf8("hi"), + messageAfterBuild.getRepeatedStringBytes(0)); + assertEquals(ByteString.EMPTY, builder.getRepeatedStringBytes(0)); + builder.clearRepeatedString(); + + message = builder.build(); + builder.addRepeatedStringPiece("hi"); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedStringPieceCount()); + builder.setRepeatedStringPiece(0, ""); + assertEquals("hi", messageAfterBuild.getRepeatedStringPiece(0)); + assertEquals("", builder.getRepeatedStringPiece(0)); + builder.clearRepeatedStringPiece(); + + message = builder.build(); + builder.addRepeatedStringPieceBytes(ByteString.copyFromUtf8("hi")); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedStringPieceCount()); + builder.setRepeatedStringPiece(0, ""); + assertEquals( + ByteString.copyFromUtf8("hi"), + messageAfterBuild.getRepeatedStringPieceBytes(0)); + assertEquals(ByteString.EMPTY, builder.getRepeatedStringPieceBytes(0)); + builder.clearRepeatedStringPiece(); + + message = builder.build(); + builder.addRepeatedUint32(1); + messageAfterBuild = builder.build(); + assertEquals(0, message.getRepeatedUint32Count()); + builder.setRepeatedUint32(0, 0); + assertEquals(1, messageAfterBuild.getRepeatedUint32(0)); + assertEquals(0, builder.getRepeatedUint32(0)); + builder.clearRepeatedUint32(); + + message = builder.build(); + builder.addRepeatedUint64(1L); + messageAfterBuild = builder.build(); + assertEquals(0L, message.getRepeatedUint64Count()); + builder.setRepeatedUint64(0, 0L); + assertEquals(1L, messageAfterBuild.getRepeatedUint64(0)); + assertEquals(0L, builder.getRepeatedUint64(0)); + builder.clearRepeatedUint64(); + + message = builder.build(); + assertEquals(0, message.getSerializedSize()); + builder.mergeFrom(TestAllTypesLite.newBuilder() + .setOptionalBool(true) + .build()); + assertEquals(0, message.getSerializedSize()); + assertEquals(true, builder.build().getOptionalBool()); + builder.clearOptionalBool(); + + message = builder.build(); + assertEquals(0, message.getSerializedSize()); + builder.mergeFrom(TestAllTypesLite.newBuilder() + .setOptionalBool(true) + .build()); + assertEquals(0, message.getSerializedSize()); + assertEquals(true, builder.build().getOptionalBool()); + builder.clear(); + assertEquals(0, builder.build().getSerializedSize()); + + message = builder.build(); + assertEquals(0, message.getSerializedSize()); + builder.mergeOptionalForeignMessage(foreignMessage); + assertEquals(0, message.getSerializedSize()); + assertEquals( + foreignMessage.getC(), + builder.build().getOptionalForeignMessage().getC()); + builder.clearOptionalForeignMessage(); + + message = builder.build(); + assertEquals(0, message.getSerializedSize()); + builder.mergeOptionalLazyMessage(nestedMessage); + assertEquals(0, message.getSerializedSize()); + assertEquals( + nestedMessage.getBb(), + builder.build().getOptionalLazyMessage().getBb()); + builder.clearOptionalLazyMessage(); + + message = builder.build(); + builder.setOneofString("hi"); + assertEquals( + OneofFieldCase.ONEOFFIELD_NOT_SET, message.getOneofFieldCase()); + assertEquals(OneofFieldCase.ONEOF_STRING, builder.getOneofFieldCase()); + assertEquals("hi", builder.getOneofString()); + messageAfterBuild = builder.build(); + assertEquals( + OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase()); + assertEquals("hi", messageAfterBuild.getOneofString()); + builder.setOneofUint32(1); + assertEquals( + OneofFieldCase.ONEOF_STRING, messageAfterBuild.getOneofFieldCase()); + assertEquals("hi", messageAfterBuild.getOneofString()); + assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase()); + assertEquals(1, builder.getOneofUint32()); + + TestAllExtensionsLite.Builder extendableMessageBuilder = + TestAllExtensionsLite.newBuilder(); + TestAllExtensionsLite extendableMessage = extendableMessageBuilder.build(); + extendableMessageBuilder.setExtension( + UnittestLite.optionalInt32ExtensionLite, 1); + assertFalse(extendableMessage.hasExtension( + UnittestLite.optionalInt32ExtensionLite)); + extendableMessage = extendableMessageBuilder.build(); + assertEquals( + 1, (int) extendableMessageBuilder.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + assertEquals( + 1, (int) extendableMessage.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + extendableMessageBuilder.setExtension( + UnittestLite.optionalInt32ExtensionLite, 3); + assertEquals( + 3, (int) extendableMessageBuilder.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + assertEquals( + 1, (int) extendableMessage.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + extendableMessage = extendableMessageBuilder.build(); + assertEquals( + 3, (int) extendableMessageBuilder.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + assertEquals( + 3, (int) extendableMessage.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + + // No extension registry, so it should be in unknown fields. + extendableMessage = + TestAllExtensionsLite.parseFrom(extendableMessage.toByteArray()); + assertFalse(extendableMessage.hasExtension( + UnittestLite.optionalInt32ExtensionLite)); + + extendableMessageBuilder = extendableMessage.toBuilder(); + extendableMessageBuilder.mergeFrom(TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalFixed32ExtensionLite, 11) + .build()); + + extendableMessage = extendableMessageBuilder.build(); + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + UnittestLite.registerAllExtensions(registry); + extendableMessage = TestAllExtensionsLite.parseFrom( + extendableMessage.toByteArray(), registry); + + // The unknown field was preserved. + assertEquals( + 3, (int) extendableMessage.getExtension( + UnittestLite.optionalInt32ExtensionLite)); + assertEquals( + 11, (int) extendableMessage.getExtension( + UnittestLite.optionalFixed32ExtensionLite)); } } diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java index 7b201a9deb..958b6a7ecd 100644 --- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java +++ b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java @@ -307,7 +307,8 @@ public class LiteralByteStringTest extends TestCase { public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{ assertSame(classUnderTest + " must be the same string references", - ByteString.EMPTY.toString(Internal.UTF_8), new LiteralByteString(new byte[]{}).toString(Internal.UTF_8)); + ByteString.EMPTY.toString(Internal.UTF_8), + new LiteralByteString(new byte[]{}).toString(Internal.UTF_8)); } public void testToString_raisesException() throws UnsupportedEncodingException{ diff --git a/java/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/src/test/java/com/google/protobuf/LongArrayListTest.java new file mode 100644 index 0000000000..3a52ec7faa --- /dev/null +++ b/java/src/test/java/com/google/protobuf/LongArrayListTest.java @@ -0,0 +1,473 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; + +/** + * Tests for {@link LongArrayList}. + * + * @author dweis@google.com (Daniel Weis) + */ +public class LongArrayListTest extends TestCase { + + private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1); + private static final LongArrayList TERTIARY_LIST = + newImmutableLongArrayList(1, 2, 3); + + private LongArrayList list; + + @Override + protected void setUp() throws Exception { + list = new LongArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(LongArrayList.emptyList(), LongArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(LongArrayList.emptyList()); + } + + public void testMakeImmutable() { + list.addLong(2); + list.addLong(4); + list.addLong(6); + list.addLong(8); + list.makeImmutable(); + assertImmutable(list); + } + + public void testCopyConstructor() { + LongArrayList copy = new LongArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new LongArrayList(LongArrayList.emptyList()); + assertEquals(LongArrayList.emptyList(), copy); + + copy = new LongArrayList(asList(1L, 2L, 3L)); + assertEquals(asList(1L, 2L, 3L), copy); + + copy = new LongArrayList(Collections.emptyList()); + assertEquals(LongArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(1L, 2L, 3L, 4L)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(1, (long) list.get(0)); + assertEquals(1, (long) iterator.next()); + list.set(0, 1L); + assertEquals(2, (long) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, 0L); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testGet() { + assertEquals(1, (long) TERTIARY_LIST.get(0)); + assertEquals(2, (long) TERTIARY_LIST.get(1)); + assertEquals(3, (long) TERTIARY_LIST.get(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testGetLong() { + assertEquals(1, TERTIARY_LIST.getLong(0)); + assertEquals(2, TERTIARY_LIST.getLong(1)); + assertEquals(3, TERTIARY_LIST.getLong(2)); + + try { + TERTIARY_LIST.get(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + TERTIARY_LIST.get(3); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSize() { + assertEquals(0, LongArrayList.emptyList().size()); + assertEquals(1, UNARY_LIST.size()); + assertEquals(3, TERTIARY_LIST.size()); + + list.addLong(2); + list.addLong(4); + list.addLong(6); + list.addLong(8); + assertEquals(4, list.size()); + + list.remove(0); + assertEquals(3, list.size()); + + list.add(16L); + assertEquals(4, list.size()); + } + + public void testSet() { + list.addLong(2); + list.addLong(4); + + assertEquals(2, (long) list.set(0, 0L)); + assertEquals(0, list.getLong(0)); + + assertEquals(4, (long) list.set(1, 0L)); + assertEquals(0, list.getLong(1)); + + try { + list.set(-1, 0L); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.set(2, 0L); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testSetLong() { + list.addLong(2); + list.addLong(4); + + assertEquals(2, list.setLong(0, 0)); + assertEquals(0, list.getLong(0)); + + assertEquals(4, list.setLong(1, 0)); + assertEquals(0, list.getLong(1)); + + try { + list.setLong(-1, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.setLong(2, 0); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAdd() { + assertEquals(0, list.size()); + + assertTrue(list.add(2L)); + assertEquals(asList(2L), list); + + assertTrue(list.add(3L)); + list.add(0, 4L); + assertEquals(asList(4L, 2L, 3L), list); + + list.add(0, 1L); + list.add(0, 0L); + // Force a resize by getting up to 11 elements. + for (int i = 0; i < 6; i++) { + list.add(Long.valueOf(5 + i)); + } + assertEquals(asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L), list); + + try { + list.add(-1, 5L); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.add(4, 5L); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + public void testAddLong() { + assertEquals(0, list.size()); + + list.addLong(2); + assertEquals(asList(2L), list); + + list.addLong(3); + assertEquals(asList(2L, 3L), list); + } + + public void testAddAll() { + assertEquals(0, list.size()); + + assertTrue(list.addAll(Collections.singleton(1L))); + assertEquals(1, list.size()); + assertEquals(1, (long) list.get(0)); + assertEquals(1, list.getLong(0)); + + assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L))); + assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list); + + assertTrue(list.addAll(TERTIARY_LIST)); + assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list); + + assertFalse(list.addAll(Collections.emptyList())); + assertFalse(list.addAll(LongArrayList.emptyList())); + } + + public void testRemove() { + list.addAll(TERTIARY_LIST); + assertEquals(1, (long) list.remove(0)); + assertEquals(asList(2L, 3L), list); + + assertTrue(list.remove(3L)); + assertEquals(asList(2L), list); + + assertFalse(list.remove(3L)); + assertEquals(asList(2L), list); + + assertEquals(2, (long) list.remove(0)); + assertEquals(asList(), list); + + try { + list.remove(-1); + fail(); + } catch (IndexOutOfBoundsException e) { + // expected + } + + try { + list.remove(0); + } catch (IndexOutOfBoundsException e) { + // expected + } + } + + private void assertImmutable(LongArrayList list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(1L); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, 1L); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(1L)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new LongArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(1L)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addLong(0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, 0L); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.setLong(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static LongArrayList newImmutableLongArrayList(long... elements) { + LongArrayList list = new LongArrayList(); + for (long element : elements) { + list.addLong(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java index 22dbeb769a..6cff689ffa 100644 --- a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java +++ b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java @@ -36,6 +36,11 @@ import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue; import junit.framework.TestCase; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + /** * Unit tests for map fields. */ @@ -170,6 +175,140 @@ public class MapForProto2LiteTest extends TestCase { assertEquals(0, message.getStringToInt32Field().size()); } + public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { + // Since builders are implemented as a thin wrapper around a message + // instance, we attempt to verify that we can't cause the builder to modify + // a produced message. + + TestMap.Builder builder = TestMap.newBuilder(); + TestMap message = builder.build(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertTrue(message.getInt32ToInt32Field().isEmpty()); + message = builder.build(); + try { + intMap.put(2, 3); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + builder.getMutableInt32ToInt32Field().put(2, 3); + assertEquals(newMap(1, 2), message.getInt32ToInt32Field()); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + } + + public void testMutableMapLifecycle() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.put(2, 3); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + builder.getMutableInt32ToInt32Field().put(2, 3); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + + Map enumMap = builder.getMutableInt32ToEnumField(); + enumMap.put(1, TestMap.EnumValue.BAR); + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); + try { + enumMap.put(2, TestMap.EnumValue.FOO); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); + assertEquals( + newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), + builder.getInt32ToEnumField()); + + Map stringMap = builder.getMutableInt32ToStringField(); + stringMap.put(1, "1"); + assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); + try { + stringMap.put(2, "2"); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); + builder.getMutableInt32ToStringField().put(2, "2"); + assertEquals( + newMap(1, "1", 2, "2"), + builder.getInt32ToStringField()); + + Map messageMap = builder.getMutableInt32ToMessageField(); + messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.build().getInt32ToMessageField()); + try { + messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance()); + assertEquals( + newMap(1, TestMap.MessageValue.getDefaultInstance(), + 2, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + } + + public void testMutableMapLifecycle_collections() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.remove(2); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.keySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), intMap); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + } + public void testGettersAndSetters() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); TestMap message = builder.build(); @@ -274,4 +413,26 @@ public class MapForProto2LiteTest extends TestCase { assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); } + + public void testIterationOrder() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + assertEquals(Arrays.asList("1", "2", "3"), + new ArrayList(message.getStringToInt32Field().keySet())); + } + + private static Map newMap(K key1, V value1) { + Map map = new HashMap(); + map.put(key1, value1); + return map; + } + + private static Map newMap(K key1, V value1, K key2, V value2) { + Map map = new HashMap(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } } diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/src/test/java/com/google/protobuf/MapForProto2Test.java index 78cba1b4f0..7e984040f6 100644 --- a/java/src/test/java/com/google/protobuf/MapForProto2Test.java +++ b/java/src/test/java/com/google/protobuf/MapForProto2Test.java @@ -40,6 +40,7 @@ import map_test.MapForProto2TestProto.TestUnknownEnumValue; import junit.framework.TestCase; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -177,6 +178,116 @@ public class MapForProto2Test extends TestCase { assertEquals(0, message.getInt32ToMessageField().size()); assertEquals(0, message.getStringToInt32Field().size()); } + + public void testMutableMapLifecycle() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.put(2, 3); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + builder.getMutableInt32ToInt32Field().put(2, 3); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + + Map enumMap = builder.getMutableInt32ToEnumField(); + enumMap.put(1, TestMap.EnumValue.BAR); + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); + try { + enumMap.put(2, TestMap.EnumValue.FOO); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); + assertEquals( + newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), + builder.getInt32ToEnumField()); + + Map stringMap = builder.getMutableInt32ToStringField(); + stringMap.put(1, "1"); + assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); + try { + stringMap.put(2, "2"); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); + builder.getMutableInt32ToStringField().put(2, "2"); + assertEquals( + newMap(1, "1", 2, "2"), + builder.getInt32ToStringField()); + + Map messageMap = builder.getMutableInt32ToMessageField(); + messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.build().getInt32ToMessageField()); + try { + messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance()); + assertEquals( + newMap(1, TestMap.MessageValue.getDefaultInstance(), + 2, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + } + + public void testMutableMapLifecycle_collections() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.remove(2); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.keySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), intMap); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + } public void testGettersAndSetters() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); @@ -513,4 +624,41 @@ public class MapForProto2Test extends TestCase { assertEquals(2, message.getRecursiveMapField().get(1).getValue()); assertEquals(4, message.getRecursiveMapField().get(3).getValue()); } + + public void testIterationOrder() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + assertEquals(Arrays.asList("1", "2", "3"), + new ArrayList(message.getStringToInt32Field().keySet())); + } + + // Regression test for b/20494788 + public void testMapInitializationOrder() throws Exception { + assertEquals("RedactAllTypes", map_test.RedactAllTypes + .getDefaultInstance().getDescriptorForType().getName()); + + map_test.Message1.Builder builder = + map_test.Message1.newBuilder(); + builder.getMutableMapField().put("key", true); + map_test.Message1 message = builder.build(); + Message mapEntry = (Message) message.getRepeatedField( + message.getDescriptorForType().findFieldByName("map_field"), 0); + assertEquals(2, mapEntry.getAllFields().size()); + } + + private static Map newMap(K key1, V value1) { + Map map = new HashMap(); + map.put(key1, value1); + return map; + } + + private static Map newMap(K key1, V value1, K key2, V value2) { + Map map = new HashMap(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } } + diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java index b8e67b7cea..0509be152b 100644 --- a/java/src/test/java/com/google/protobuf/MapTest.java +++ b/java/src/test/java/com/google/protobuf/MapTest.java @@ -41,6 +41,7 @@ import map_test.MapTestProto.TestOnChangeEventPropagation; import junit.framework.TestCase; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -178,7 +179,117 @@ public class MapTest extends TestCase { assertEquals(0, message.getInt32ToMessageField().size()); assertEquals(0, message.getStringToInt32Field().size()); } + + public void testMutableMapLifecycle() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.put(2, 3); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + builder.getMutableInt32ToInt32Field().put(2, 3); + assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field()); + + Map enumMap = builder.getMutableInt32ToEnumField(); + enumMap.put(1, TestMap.EnumValue.BAR); + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField()); + try { + enumMap.put(2, TestMap.EnumValue.FOO); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField()); + builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO); + assertEquals( + newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO), + builder.getInt32ToEnumField()); + + Map stringMap = builder.getMutableInt32ToStringField(); + stringMap.put(1, "1"); + assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField()); + try { + stringMap.put(2, "2"); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, "1"), builder.getInt32ToStringField()); + builder.getMutableInt32ToStringField().put(2, "2"); + assertEquals( + newMap(1, "1", 2, "2"), + builder.getInt32ToStringField()); + + Map messageMap = builder.getMutableInt32ToMessageField(); + messageMap.put(1, TestMap.MessageValue.getDefaultInstance()); + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.build().getInt32ToMessageField()); + try { + messageMap.put(2, TestMap.MessageValue.getDefaultInstance()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance()); + assertEquals( + newMap(1, TestMap.MessageValue.getDefaultInstance(), + 2, TestMap.MessageValue.getDefaultInstance()), + builder.getInt32ToMessageField()); + } + public void testMutableMapLifecycle_collections() { + TestMap.Builder builder = TestMap.newBuilder(); + Map intMap = builder.getMutableInt32ToInt32Field(); + intMap.put(1, 2); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + try { + intMap.remove(2); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.entrySet().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.keySet().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + try { + intMap.values().iterator().remove(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + assertEquals(newMap(1, 2), intMap); + assertEquals(newMap(1, 2), builder.getInt32ToInt32Field()); + assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field()); + } + public void testGettersAndSetters() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); TestMap message = builder.build(); @@ -611,4 +722,26 @@ public class MapTest extends TestCase { assertEquals(data.get(entry.getKey()) + 1, entry.getValue().intValue()); } } + + public void testIterationOrder() throws Exception { + TestMap.Builder builder = TestMap.newBuilder(); + setMapValues(builder); + TestMap message = builder.build(); + + assertEquals(Arrays.asList("1", "2", "3"), + new ArrayList(message.getStringToInt32Field().keySet())); + } + + private static Map newMap(K key1, V value1) { + Map map = new HashMap(); + map.put(key1, value1); + return map; + } + + private static Map newMap(K key1, V value1, K key2, V value2) { + Map map = new HashMap(); + map.put(key1, value1); + map.put(key2, value2); + return map; + } } diff --git a/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java new file mode 100644 index 0000000000..f9f5e9c769 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/ProtobufArrayListTest.java @@ -0,0 +1,303 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package com.google.protobuf; + +import static java.util.Arrays.asList; + +import junit.framework.TestCase; + +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; + +/** + * Tests for {@link ProtobufArrayList}. + */ +public class ProtobufArrayListTest extends TestCase { + + private static final ProtobufArrayList UNARY_LIST = newImmutableProtoArrayList(1); + private static final ProtobufArrayList TERTIARY_LIST = + newImmutableProtoArrayList(1, 2, 3); + + private ProtobufArrayList list; + + @Override + protected void setUp() throws Exception { + list = new ProtobufArrayList(); + } + + public void testEmptyListReturnsSameInstance() { + assertSame(ProtobufArrayList.emptyList(), ProtobufArrayList.emptyList()); + } + + public void testEmptyListIsImmutable() { + assertImmutable(ProtobufArrayList.emptyList()); + } + + public void testCopyConstructor() { + ProtobufArrayList copy = new ProtobufArrayList(TERTIARY_LIST); + assertEquals(TERTIARY_LIST, copy); + + copy = new ProtobufArrayList(IntArrayList.emptyList()); + assertEquals(ProtobufArrayList.emptyList(), copy); + + copy = new ProtobufArrayList(asList(1, 2, 3)); + assertEquals(asList(1, 2, 3), copy); + + copy = new ProtobufArrayList(Collections.emptyList()); + assertEquals(ProtobufArrayList.emptyList(), copy); + } + + public void testModificationWithIteration() { + list.addAll(asList(1, 2, 3, 4)); + Iterator iterator = list.iterator(); + assertEquals(4, list.size()); + assertEquals(1, (int) list.get(0)); + assertEquals(1, (int) iterator.next()); + + list.remove(0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.set(0, 1); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + + iterator = list.iterator(); + list.add(0, 0); + try { + iterator.next(); + fail(); + } catch (ConcurrentModificationException e) { + // expected + } + } + + public void testMakeImmutable() { + list.add(2); + list.add(4); + list.add(6); + list.add(8); + list.makeImmutable(); + assertImmutable(list); + } + + public void testRemove() { + list.add(2); + list.add(4); + list.add(6); + + list.remove(1); + assertEquals(asList(2, 6), list); + + list.remove(1); + assertEquals(asList(2), list); + + list.remove(0); + assertEquals(asList(), list); + } + + public void testGet() { + list.add(2); + list.add(6); + + assertEquals(2, (int) list.get(0)); + assertEquals(6, (int) list.get(1)); + } + + public void testSet() { + list.add(2); + list.add(6); + + list.set(0, 1); + assertEquals(1, (int) list.get(0)); + list.set(1, 2); + assertEquals(2, (int) list.get(1)); + } + + private void assertImmutable(List list) { + if (list.contains(1)) { + throw new RuntimeException("Cannot test the immutability of lists that contain 1."); + } + + try { + list.add(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.add(0, 1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(Collections.singletonList(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(new ProtobufArrayList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.addAll(0, Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.clear(); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(1); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.remove(new Object()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.removeAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.emptyList()); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(Collections.singleton(1)); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.retainAll(UNARY_LIST); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + + try { + list.set(0, 0); + fail(); + } catch (UnsupportedOperationException e) { + // expected + } + } + + private static ProtobufArrayList newImmutableProtoArrayList(int... elements) { + ProtobufArrayList list = new ProtobufArrayList(); + for (int element : elements) { + list.add(element); + } + list.makeImmutable(); + return list; + } +} diff --git a/java/src/test/java/com/google/protobuf/field_presence_test.proto b/java/src/test/java/com/google/protobuf/field_presence_test.proto index 8d8ea8ef83..8f3ca8c610 100644 --- a/java/src/test/java/com/google/protobuf/field_presence_test.proto +++ b/java/src/test/java/com/google/protobuf/field_presence_test.proto @@ -45,15 +45,15 @@ message TestAllTypes { BAZ = 2; } message NestedMessage { - optional int32 value = 1; + int32 value = 1; } - optional int32 optional_int32 = 1; - optional string optional_string = 2; - optional bytes optional_bytes = 3; - optional NestedEnum optional_nested_enum = 4; - optional NestedMessage optional_nested_message = 5; - optional protobuf_unittest.TestRequired optional_proto2_message = 6; + int32 optional_int32 = 1; + string optional_string = 2; + bytes optional_bytes = 3; + NestedEnum optional_nested_enum = 4; + NestedMessage optional_nested_message = 5; + protobuf_unittest.TestRequired optional_proto2_message = 6; oneof oneof_field { int32 oneof_int32 = 11; @@ -75,12 +75,12 @@ message TestAllTypes { } message TestOptionalFieldsOnly { - optional int32 optional_int32 = 1; - optional string optional_string = 2; - optional bytes optional_bytes = 3; - optional TestAllTypes.NestedEnum optional_nested_enum = 4; - optional TestAllTypes.NestedMessage optional_nested_message = 5; - optional protobuf_unittest.TestRequired optional_proto2_message = 6; + int32 optional_int32 = 1; + string optional_string = 2; + bytes optional_bytes = 3; + TestAllTypes.NestedEnum optional_nested_enum = 4; + TestAllTypes.NestedMessage optional_nested_message = 5; + protobuf_unittest.TestRequired optional_proto2_message = 6; } message TestRepeatedFieldsOnly { diff --git a/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto b/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto new file mode 100644 index 0000000000..b02ac599a5 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/map_initialization_order_test.proto @@ -0,0 +1,61 @@ +// 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. + +// Regression test for a map initilaization order bug. The bug only manifests +// when: +// 1. A message contains map fields and is also extendable. +// 2. There is a file-level extension defined in the same file referencing +// the above message as the extension type. +// 3. The program executes in the following order: +// a. getDescriptor() is called on another message in the same file. +// b. use protobuf reflection to access the map field. +// The symptom is a NullPointerException being thrown. +syntax = "proto2"; + +package map_test; + +option java_package = "map_test"; +option java_outer_classname = "MapInitializationOrderTest"; +option java_multiple_files = true; + +// Mirrors the structure of +// javatests/com/google/cloud/common/logging/logging_test.proto. + +message Message1 { + map map_field = 1; + extensions 1000 to max; +} + +extend Message1 { + optional Message1 recursive_extension = 1001; +} + +message RedactAllTypes { +} diff --git a/java/src/test/java/com/google/protobuf/map_test.proto b/java/src/test/java/com/google/protobuf/map_test.proto index bf692c2216..2f7709be99 100644 --- a/java/src/test/java/com/google/protobuf/map_test.proto +++ b/java/src/test/java/com/google/protobuf/map_test.proto @@ -39,7 +39,7 @@ option java_generate_equals_and_hash = true; message TestMap { message MessageValue { - optional int32 value = 1; + int32 value = 1; } enum EnumValue { FOO = 0; @@ -60,5 +60,5 @@ message TestMap { // propagate the onChange event and mark its parent dirty when a change // is made to a map field. message TestOnChangeEventPropagation { - optional TestMap optional_message = 1; + TestMap optional_message = 1; } diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py index f7a58ca064..970b1a8844 100755 --- a/python/google/protobuf/descriptor.py +++ b/python/google/protobuf/descriptor.py @@ -245,9 +245,6 @@ class Descriptor(_NestedDescriptorBase): is_extendable: Does this type define any extension ranges? - options: (descriptor_pb2.MessageOptions) Protocol message options or None - to use default message options. - oneofs: (list of OneofDescriptor) The list of descriptors for oneof fields in this message. oneofs_by_name: (dict str -> OneofDescriptor) Same objects as in |oneofs|, @@ -265,7 +262,7 @@ class Descriptor(_NestedDescriptorBase): file=None, serialized_start=None, serialized_end=None, syntax=None): _message.Message._CheckCalledFromGeneratedFile() - return _message.Message._GetMessageDescriptor(full_name) + return _message.default_pool.FindMessageTypeByName(full_name) # NOTE(tmarek): The file argument redefining a builtin is nothing we can # fix right now since we don't know how many clients already rely on the @@ -495,9 +492,9 @@ class FieldDescriptor(DescriptorBase): has_default_value=True, containing_oneof=None): _message.Message._CheckCalledFromGeneratedFile() if is_extension: - return _message.Message._GetExtensionDescriptor(full_name) + return _message.default_pool.FindExtensionByName(full_name) else: - return _message.Message._GetFieldDescriptor(full_name) + return _message.default_pool.FindFieldByName(full_name) def __init__(self, name, full_name, index, number, type, cpp_type, label, default_value, message_type, enum_type, containing_type, @@ -528,14 +525,9 @@ class FieldDescriptor(DescriptorBase): self.containing_oneof = containing_oneof if api_implementation.Type() == 'cpp': if is_extension: - # pylint: disable=protected-access - self._cdescriptor = ( - _message.Message._GetExtensionDescriptor(full_name)) - # pylint: enable=protected-access + self._cdescriptor = _message.default_pool.FindExtensionByName(full_name) else: - # pylint: disable=protected-access - self._cdescriptor = _message.Message._GetFieldDescriptor(full_name) - # pylint: enable=protected-access + self._cdescriptor = _message.default_pool.FindFieldByName(full_name) else: self._cdescriptor = None @@ -592,7 +584,7 @@ class EnumDescriptor(_NestedDescriptorBase): containing_type=None, options=None, file=None, serialized_start=None, serialized_end=None): _message.Message._CheckCalledFromGeneratedFile() - return _message.Message._GetEnumDescriptor(full_name) + return _message.default_pool.FindEnumTypeByName(full_name) def __init__(self, name, full_name, filename, values, containing_type=None, options=None, file=None, @@ -677,7 +669,7 @@ class OneofDescriptor(object): def __new__(cls, name, full_name, index, containing_type, fields): _message.Message._CheckCalledFromGeneratedFile() - return _message.Message._GetOneofDescriptor(full_name) + return _message.default_pool.FindOneofByName(full_name) def __init__(self, name, full_name, index, containing_type, fields): """Arguments are as described in the attribute description above.""" @@ -788,12 +780,8 @@ class FileDescriptor(DescriptorBase): dependencies=None, syntax=None): # FileDescriptor() is called from various places, not only from generated # files, to register dynamic proto files and messages. - # TODO(amauryfa): Expose BuildFile() as a public function and make this - # constructor an implementation detail. if serialized_pb: - # pylint: disable=protected-access2 - return _message.Message._BuildFile(serialized_pb) - # pylint: enable=protected-access + return _message.default_pool.AddSerializedFile(serialized_pb) else: return super(FileDescriptor, cls).__new__(cls) @@ -814,9 +802,7 @@ class FileDescriptor(DescriptorBase): if (api_implementation.Type() == 'cpp' and self.serialized_pb is not None): - # pylint: disable=protected-access - _message.Message._BuildFile(self.serialized_pb) - # pylint: enable=protected-access + _message.default_pool.AddSerializedFile(self.serialized_pb) def CopyToProto(self, proto): """Copies this to a descriptor_pb2.FileDescriptorProto. @@ -864,10 +850,10 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True, file_descriptor_proto = descriptor_pb2.FileDescriptorProto() file_descriptor_proto.message_type.add().MergeFrom(desc_proto) - # Generate a random name for this proto file to prevent conflicts with - # any imported ones. We need to specify a file name so BuildFile accepts - # our FileDescriptorProto, but it is not important what that file name - # is actually set to. + # Generate a random name for this proto file to prevent conflicts with any + # imported ones. We need to specify a file name so the descriptor pool + # accepts our FileDescriptorProto, but it is not important what that file + # name is actually set to. proto_name = str(uuid.uuid4()) if package: @@ -877,10 +863,8 @@ def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True, else: file_descriptor_proto.name = proto_name + '.proto' - # pylint: disable=protected-access - result = _message.Message._BuildFile( - file_descriptor_proto.SerializeToString()) - # pylint: enable=protected-access + _message.default_pool.Add(file_descriptor_proto) + result = _message.default_pool.FindFileByName(file_descriptor_proto.name) if _USE_C_DESCRIPTORS: return result.message_types_by_name[desc_proto.name] diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py index 7e7701f80d..1244ba7c28 100644 --- a/python/google/protobuf/descriptor_pool.py +++ b/python/google/protobuf/descriptor_pool.py @@ -113,6 +113,20 @@ class DescriptorPool(object): self._internal_db.Add(file_desc_proto) + def AddSerializedFile(self, serialized_file_desc_proto): + """Adds the FileDescriptorProto and its types to this pool. + + Args: + serialized_file_desc_proto: A bytes string, serialization of the + FileDescriptorProto to add. + """ + + # pylint: disable=g-import-not-at-top + from google.protobuf import descriptor_pb2 + file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString( + serialized_file_desc_proto) + self.Add(file_desc_proto) + def AddDescriptor(self, desc): """Adds a Descriptor to the pool, non-recursively. @@ -320,17 +334,17 @@ class DescriptorPool(object): file_descriptor, None, scope)) for index, extension_proto in enumerate(file_proto.extension): - extension_desc = self.MakeFieldDescriptor( + extension_desc = self._MakeFieldDescriptor( extension_proto, file_proto.package, index, is_extension=True) extension_desc.containing_type = self._GetTypeFromScope( file_descriptor.package, extension_proto.extendee, scope) - self.SetFieldType(extension_proto, extension_desc, + self._SetFieldType(extension_proto, extension_desc, file_descriptor.package, scope) file_descriptor.extensions_by_name[extension_desc.name] = ( extension_desc) for desc_proto in file_proto.message_type: - self.SetAllFieldTypes(file_proto.package, desc_proto, scope) + self._SetAllFieldTypes(file_proto.package, desc_proto, scope) if file_proto.package: desc_proto_prefix = _PrefixWithDot(file_proto.package) @@ -381,10 +395,11 @@ class DescriptorPool(object): enums = [ self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope) for enum in desc_proto.enum_type] - fields = [self.MakeFieldDescriptor(field, desc_name, index) + fields = [self._MakeFieldDescriptor(field, desc_name, index) for index, field in enumerate(desc_proto.field)] extensions = [ - self.MakeFieldDescriptor(extension, desc_name, index, is_extension=True) + self._MakeFieldDescriptor(extension, desc_name, index, + is_extension=True) for index, extension in enumerate(desc_proto.extension)] oneofs = [ descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)), @@ -464,8 +479,8 @@ class DescriptorPool(object): self._enum_descriptors[enum_name] = desc return desc - def MakeFieldDescriptor(self, field_proto, message_name, index, - is_extension=False): + def _MakeFieldDescriptor(self, field_proto, message_name, index, + is_extension=False): """Creates a field descriptor from a FieldDescriptorProto. For message and enum type fields, this method will do a look up @@ -506,7 +521,7 @@ class DescriptorPool(object): extension_scope=None, options=field_proto.options) - def SetAllFieldTypes(self, package, desc_proto, scope): + def _SetAllFieldTypes(self, package, desc_proto, scope): """Sets all the descriptor's fields's types. This method also sets the containing types on any extensions. @@ -527,18 +542,18 @@ class DescriptorPool(object): nested_package = '.'.join([package, desc_proto.name]) for field_proto, field_desc in zip(desc_proto.field, main_desc.fields): - self.SetFieldType(field_proto, field_desc, nested_package, scope) + self._SetFieldType(field_proto, field_desc, nested_package, scope) for extension_proto, extension_desc in ( zip(desc_proto.extension, main_desc.extensions)): extension_desc.containing_type = self._GetTypeFromScope( nested_package, extension_proto.extendee, scope) - self.SetFieldType(extension_proto, extension_desc, nested_package, scope) + self._SetFieldType(extension_proto, extension_desc, nested_package, scope) for nested_type in desc_proto.nested_type: - self.SetAllFieldTypes(nested_package, nested_type, scope) + self._SetAllFieldTypes(nested_package, nested_type, scope) - def SetFieldType(self, field_proto, field_desc, package, scope): + def _SetFieldType(self, field_proto, field_desc, package, scope): """Sets the field's type, cpp_type, message_type and enum_type. Args: diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py index d976f9e14b..72c2fa01bc 100755 --- a/python/google/protobuf/internal/containers.py +++ b/python/google/protobuf/internal/containers.py @@ -41,6 +41,146 @@ are: __author__ = 'petar@google.com (Petar Petrov)' +import sys + +if sys.version_info[0] < 3: + # We would use collections.MutableMapping all the time, but in Python 2 it + # doesn't define __slots__. This causes two significant problems: + # + # 1. we can't disallow arbitrary attribute assignment, even if our derived + # classes *do* define __slots__. + # + # 2. we can't safely derive a C type from it without __slots__ defined (the + # interpreter expects to find a dict at tp_dictoffset, which we can't + # robustly provide. And we don't want an instance dict anyway. + # + # So this is the Python 2.7 definition of Mapping/MutableMapping functions + # verbatim, except that: + # 1. We declare __slots__. + # 2. We don't declare this as a virtual base class. The classes defined + # in collections are the interesting base classes, not us. + # + # Note: deriving from object is critical. It is the only thing that makes + # this a true type, allowing us to derive from it in C++ cleanly and making + # __slots__ properly disallow arbitrary element assignment. + from collections import Mapping as _Mapping + + class Mapping(object): + __slots__ = () + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + def __contains__(self, key): + try: + self[key] + except KeyError: + return False + else: + return True + + def iterkeys(self): + return iter(self) + + def itervalues(self): + for key in self: + yield self[key] + + def iteritems(self): + for key in self: + yield (key, self[key]) + + def keys(self): + return list(self) + + def items(self): + return [(key, self[key]) for key in self] + + def values(self): + return [self[key] for key in self] + + # Mappings are not hashable by default, but subclasses can change this + __hash__ = None + + def __eq__(self, other): + if not isinstance(other, _Mapping): + return NotImplemented + return dict(self.items()) == dict(other.items()) + + def __ne__(self, other): + return not (self == other) + + class MutableMapping(Mapping): + __slots__ = () + + __marker = object() + + def pop(self, key, default=__marker): + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def popitem(self): + try: + key = next(iter(self)) + except StopIteration: + raise KeyError + value = self[key] + del self[key] + return key, value + + def clear(self): + try: + while True: + self.popitem() + except KeyError: + pass + + def update(*args, **kwds): + if len(args) > 2: + raise TypeError("update() takes at most 2 positional " + "arguments ({} given)".format(len(args))) + elif not args: + raise TypeError("update() takes at least 1 argument (0 given)") + self = args[0] + other = args[1] if len(args) >= 2 else () + + if isinstance(other, Mapping): + for key in other: + self[key] = other[key] + elif hasattr(other, "keys"): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + def setdefault(self, key, default=None): + try: + return self[key] + except KeyError: + self[key] = default + return default + + _Mapping.register(Mapping) + +else: + # In Python 3 we can just use MutableMapping directly, because it defines + # __slots__. + from collections import MutableMapping + + class BaseContainer(object): """Base container class.""" @@ -286,3 +426,160 @@ class RepeatedCompositeFieldContainer(BaseContainer): raise TypeError('Can only compare repeated composite fields against ' 'other repeated composite fields.') return self._values == other._values + + +class ScalarMap(MutableMapping): + + """Simple, type-checked, dict-like container for holding repeated scalars.""" + + # Disallows assignment to other attributes. + __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener'] + + def __init__(self, message_listener, key_checker, value_checker): + """ + Args: + message_listener: A MessageListener implementation. + The ScalarMap will call this object's Modified() method when it + is modified. + key_checker: A type_checkers.ValueChecker instance to run on keys + inserted into this container. + value_checker: A type_checkers.ValueChecker instance to run on values + inserted into this container. + """ + self._message_listener = message_listener + self._key_checker = key_checker + self._value_checker = value_checker + self._values = {} + + def __getitem__(self, key): + try: + return self._values[key] + except KeyError: + key = self._key_checker.CheckValue(key) + val = self._value_checker.DefaultValue() + self._values[key] = val + return val + + def __contains__(self, item): + return item in self._values + + # We need to override this explicitly, because our defaultdict-like behavior + # will make the default implementation (from our base class) always insert + # the key. + def get(self, key, default=None): + if key in self: + return self[key] + else: + return default + + def __setitem__(self, key, value): + checked_key = self._key_checker.CheckValue(key) + checked_value = self._value_checker.CheckValue(value) + self._values[checked_key] = checked_value + self._message_listener.Modified() + + def __delitem__(self, key): + del self._values[key] + self._message_listener.Modified() + + def __len__(self): + return len(self._values) + + def __iter__(self): + return iter(self._values) + + def MergeFrom(self, other): + self._values.update(other._values) + self._message_listener.Modified() + + # This is defined in the abstract base, but we can do it much more cheaply. + def clear(self): + self._values.clear() + self._message_listener.Modified() + + +class MessageMap(MutableMapping): + + """Simple, type-checked, dict-like container for with submessage values.""" + + # Disallows assignment to other attributes. + __slots__ = ['_key_checker', '_values', '_message_listener', + '_message_descriptor'] + + def __init__(self, message_listener, message_descriptor, key_checker): + """ + Args: + message_listener: A MessageListener implementation. + The ScalarMap will call this object's Modified() method when it + is modified. + key_checker: A type_checkers.ValueChecker instance to run on keys + inserted into this container. + value_checker: A type_checkers.ValueChecker instance to run on values + inserted into this container. + """ + self._message_listener = message_listener + self._message_descriptor = message_descriptor + self._key_checker = key_checker + self._values = {} + + def __getitem__(self, key): + try: + return self._values[key] + except KeyError: + key = self._key_checker.CheckValue(key) + new_element = self._message_descriptor._concrete_class() + new_element._SetListener(self._message_listener) + self._values[key] = new_element + self._message_listener.Modified() + + return new_element + + def get_or_create(self, key): + """get_or_create() is an alias for getitem (ie. map[key]). + + Args: + key: The key to get or create in the map. + + This is useful in cases where you want to be explicit that the call is + mutating the map. This can avoid lint errors for statements like this + that otherwise would appear to be pointless statements: + + msg.my_map[key] + """ + return self[key] + + # We need to override this explicitly, because our defaultdict-like behavior + # will make the default implementation (from our base class) always insert + # the key. + def get(self, key, default=None): + if key in self: + return self[key] + else: + return default + + def __contains__(self, item): + return item in self._values + + def __setitem__(self, key, value): + raise ValueError('May not set values directly, call my_map[key].foo = 5') + + def __delitem__(self, key): + del self._values[key] + self._message_listener.Modified() + + def __len__(self): + return len(self._values) + + def __iter__(self): + return iter(self._values) + + def MergeFrom(self, other): + for key in other: + self[key].MergeFrom(other[key]) + # self._message_listener.Modified() not required here, because + # mutations to submessages already propagate. + + # This is defined in the abstract base, but we can do it much more cheaply. + def clear(self): + self._values.clear() + self._message_listener.Modified() diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py index 0f500606f3..3837eaea39 100755 --- a/python/google/protobuf/internal/decoder.py +++ b/python/google/protobuf/internal/decoder.py @@ -732,6 +732,50 @@ def MessageSetItemDecoder(extensions_by_number): return DecodeItem +# -------------------------------------------------------------------- + +def MapDecoder(field_descriptor, new_default, is_message_map): + """Returns a decoder for a map field.""" + + key = field_descriptor + tag_bytes = encoder.TagBytes(field_descriptor.number, + wire_format.WIRETYPE_LENGTH_DELIMITED) + tag_len = len(tag_bytes) + local_DecodeVarint = _DecodeVarint + # Can't read _concrete_class yet; might not be initialized. + message_type = field_descriptor.message_type + + def DecodeMap(buffer, pos, end, message, field_dict): + submsg = message_type._concrete_class() + value = field_dict.get(key) + if value is None: + value = field_dict.setdefault(key, new_default(message)) + while 1: + # Read length. + (size, pos) = local_DecodeVarint(buffer, pos) + new_pos = pos + size + if new_pos > end: + raise _DecodeError('Truncated message.') + # Read sub-message. + submsg.Clear() + if submsg._InternalParse(buffer, pos, new_pos) != new_pos: + # The only reason _InternalParse would return early is if it + # encountered an end-group tag. + raise _DecodeError('Unexpected end-group tag.') + + if is_message_map: + value[submsg.key].MergeFrom(submsg.value) + else: + value[submsg.key] = submsg.value + + # Predict that the next tag is another copy of the same repeated field. + pos = new_pos + tag_len + if buffer[new_pos:pos] != tag_bytes or new_pos == end: + # Prediction failed. Return. + return new_pos + + return DecodeMap + # -------------------------------------------------------------------- # Optimization is not as heavy here because calls to SkipField() are rare, # except for handling end-group tags. diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py index 56fe14e9a5..8416e1575d 100644 --- a/python/google/protobuf/internal/descriptor_database_test.py +++ b/python/google/protobuf/internal/descriptor_database_test.py @@ -35,7 +35,6 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import unittest - from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test2_pb2 from google.protobuf import descriptor_database diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index 7d145f42dd..d159cc6257 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -37,6 +37,7 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import os import unittest +import unittest from google.protobuf import unittest_pb2 from google.protobuf import descriptor_pb2 from google.protobuf.internal import api_implementation @@ -226,6 +227,13 @@ class DescriptorPoolTest(unittest.TestCase): db.Add(self.factory_test2_fd) self.testFindMessageTypeByName() + def testAddSerializedFile(self): + db = descriptor_database.DescriptorDatabase() + self.pool = descriptor_pool.DescriptorPool(db) + self.pool.AddSerializedFile(self.factory_test1_fd.SerializeToString()) + self.pool.AddSerializedFile(self.factory_test2_fd.SerializeToString()) + self.testFindMessageTypeByName() + def testComplexNesting(self): test1_desc = descriptor_pb2.FileDescriptorProto.FromString( descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb) @@ -510,6 +518,43 @@ class AddDescriptorTest(unittest.TestCase): 'protobuf_unittest.TestAllTypes') +@unittest.skipIf( + api_implementation.Type() != 'cpp', + 'default_pool is only supported by the C++ implementation') +class DefaultPoolTest(unittest.TestCase): + + def testFindMethods(self): + # pylint: disable=g-import-not-at-top + from google.protobuf.pyext import _message + pool = _message.default_pool + self.assertIs( + pool.FindFileByName('google/protobuf/unittest.proto'), + unittest_pb2.DESCRIPTOR) + self.assertIs( + pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'), + unittest_pb2.TestAllTypes.DESCRIPTOR) + self.assertIs( + pool.FindFieldByName('protobuf_unittest.TestAllTypes.optional_int32'), + unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32']) + self.assertIs( + pool.FindExtensionByName('protobuf_unittest.optional_int32_extension'), + unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension']) + self.assertIs( + pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'), + unittest_pb2.ForeignEnum.DESCRIPTOR) + self.assertIs( + pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'), + unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field']) + + def testAddFileDescriptor(self): + # pylint: disable=g-import-not-at-top + from google.protobuf.pyext import _message + pool = _message.default_pool + file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') + pool.Add(file_desc) + pool.AddSerializedFile(file_desc.SerializeToString()) + + TEST1_FILE = ProtoFile( 'google/protobuf/internal/descriptor_pool_test1.proto', 'google.protobuf.python.internal', diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index 335caee6e0..26866f3a05 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -35,8 +35,8 @@ __author__ = 'robinson@google.com (Will Robinson)' import sys -import unittest +import unittest from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_pb2 diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py index 38a5138aea..752f4eabc2 100755 --- a/python/google/protobuf/internal/encoder.py +++ b/python/google/protobuf/internal/encoder.py @@ -314,7 +314,7 @@ def MessageSizer(field_number, is_repeated, is_packed): # -------------------------------------------------------------------- -# MessageSet is special. +# MessageSet is special: it needs custom logic to compute its size properly. def MessageSetItemSizer(field_number): @@ -339,6 +339,32 @@ def MessageSetItemSizer(field_number): return FieldSize +# -------------------------------------------------------------------- +# Map is special: it needs custom logic to compute its size properly. + + +def MapSizer(field_descriptor): + """Returns a sizer for a map field.""" + + # Can't look at field_descriptor.message_type._concrete_class because it may + # not have been initialized yet. + message_type = field_descriptor.message_type + message_sizer = MessageSizer(field_descriptor.number, False, False) + + def FieldSize(map_value): + total = 0 + for key in map_value: + value = map_value[key] + # It's wasteful to create the messages and throw them away one second + # later since we'll do the same for the actual encode. But there's not an + # obvious way to avoid this within the current design without tons of code + # duplication. + entry_msg = message_type._concrete_class(key=key, value=value) + total += message_sizer(entry_msg) + return total + + return FieldSize + # ==================================================================== # Encoders! @@ -786,3 +812,30 @@ def MessageSetItemEncoder(field_number): return write(end_bytes) return EncodeField + + +# -------------------------------------------------------------------- +# As before, Map is special. + + +def MapEncoder(field_descriptor): + """Encoder for extensions of MessageSet. + + Maps always have a wire format like this: + message MapEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapEntry map = N; + """ + # Can't look at field_descriptor.message_type._concrete_class because it may + # not have been initialized yet. + message_type = field_descriptor.message_type + encode_message = MessageEncoder(field_descriptor.number, False, False) + + def EncodeField(write, value): + for key in value: + entry_msg = message_type._concrete_class(key=key, value=value[key]) + encode_message(write, entry_msg) + + return EncodeField diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index ccc5860bfd..5c07cbe6b1 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -42,7 +42,6 @@ further ensures that we can use Python protocol message objects as we expect. __author__ = 'robinson@google.com (Will Robinson)' import unittest - from google.protobuf.internal import test_bad_identifiers_pb2 from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 626c3fc96d..b8694f96df 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -35,7 +35,6 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import unittest - from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test2_pb2 diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 4ecaa1c73c..320ff0d27b 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -50,7 +50,9 @@ import pickle import sys import unittest +import unittest from google.protobuf.internal import _parameterized +from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf.internal import api_implementation @@ -125,10 +127,17 @@ class MessageTest(unittest.TestCase): self.assertEqual(unpickled_message, golden_message) def testPositiveInfinity(self, message_module): - golden_data = (b'\x5D\x00\x00\x80\x7F' - b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F' - b'\xCD\x02\x00\x00\x80\x7F' - b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F') + if message_module is unittest_pb2: + golden_data = (b'\x5D\x00\x00\x80\x7F' + b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F' + b'\xCD\x02\x00\x00\x80\x7F' + b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\x7F') + else: + golden_data = (b'\x5D\x00\x00\x80\x7F' + b'\x61\x00\x00\x00\x00\x00\x00\xF0\x7F' + b'\xCA\x02\x04\x00\x00\x80\x7F' + b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\x7F') + golden_message = message_module.TestAllTypes() golden_message.ParseFromString(golden_data) self.assertTrue(IsPosInf(golden_message.optional_float)) @@ -138,10 +147,17 @@ class MessageTest(unittest.TestCase): self.assertEqual(golden_data, golden_message.SerializeToString()) def testNegativeInfinity(self, message_module): - golden_data = (b'\x5D\x00\x00\x80\xFF' - b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF' - b'\xCD\x02\x00\x00\x80\xFF' - b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF') + if message_module is unittest_pb2: + golden_data = (b'\x5D\x00\x00\x80\xFF' + b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF' + b'\xCD\x02\x00\x00\x80\xFF' + b'\xD1\x02\x00\x00\x00\x00\x00\x00\xF0\xFF') + else: + golden_data = (b'\x5D\x00\x00\x80\xFF' + b'\x61\x00\x00\x00\x00\x00\x00\xF0\xFF' + b'\xCA\x02\x04\x00\x00\x80\xFF' + b'\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xF0\xFF') + golden_message = message_module.TestAllTypes() golden_message.ParseFromString(golden_data) self.assertTrue(IsNegInf(golden_message.optional_float)) @@ -1034,64 +1050,132 @@ class Proto2Test(unittest.TestCase): self.assertEqual(len(parsing_merge.Extensions[ unittest_pb2.TestParsingMerge.repeated_ext]), 3) + def testPythonicInit(self): + message = unittest_pb2.TestAllTypes( + optional_int32=100, + optional_fixed32=200, + optional_float=300.5, + optional_bytes=b'x', + optionalgroup={'a': 400}, + optional_nested_message={'bb': 500}, + optional_nested_enum='BAZ', + repeatedgroup=[{'a': 600}, + {'a': 700}], + repeated_nested_enum=['FOO', unittest_pb2.TestAllTypes.BAR], + default_int32=800, + oneof_string='y') + self.assertTrue(isinstance(message, unittest_pb2.TestAllTypes)) + self.assertEqual(100, message.optional_int32) + self.assertEqual(200, message.optional_fixed32) + self.assertEqual(300.5, message.optional_float) + self.assertEqual(b'x', message.optional_bytes) + self.assertEqual(400, message.optionalgroup.a) + self.assertTrue(isinstance(message.optional_nested_message, + unittest_pb2.TestAllTypes.NestedMessage)) + self.assertEqual(500, message.optional_nested_message.bb) + self.assertEqual(unittest_pb2.TestAllTypes.BAZ, + message.optional_nested_enum) + self.assertEqual(2, len(message.repeatedgroup)) + self.assertEqual(600, message.repeatedgroup[0].a) + self.assertEqual(700, message.repeatedgroup[1].a) + self.assertEqual(2, len(message.repeated_nested_enum)) + self.assertEqual(unittest_pb2.TestAllTypes.FOO, + message.repeated_nested_enum[0]) + self.assertEqual(unittest_pb2.TestAllTypes.BAR, + message.repeated_nested_enum[1]) + self.assertEqual(800, message.default_int32) + self.assertEqual('y', message.oneof_string) + self.assertFalse(message.HasField('optional_int64')) + self.assertEqual(0, len(message.repeated_float)) + self.assertEqual(42, message.default_int64) + + message = unittest_pb2.TestAllTypes(optional_nested_enum=u'BAZ') + self.assertEqual(unittest_pb2.TestAllTypes.BAZ, + message.optional_nested_enum) + + with self.assertRaises(ValueError): + unittest_pb2.TestAllTypes( + optional_nested_message={'INVALID_NESTED_FIELD': 17}) + + with self.assertRaises(TypeError): + unittest_pb2.TestAllTypes( + optional_nested_message={'bb': 'INVALID_VALUE_TYPE'}) + + with self.assertRaises(ValueError): + unittest_pb2.TestAllTypes(optional_nested_enum='INVALID_LABEL') + + with self.assertRaises(ValueError): + unittest_pb2.TestAllTypes(repeated_nested_enum='FOO') + # Class to test proto3-only features/behavior (updated field presence & enums) class Proto3Test(unittest.TestCase): + # Utility method for comparing equality with a map. + def assertMapIterEquals(self, map_iter, dict_value): + # Avoid mutating caller's copy. + dict_value = dict(dict_value) + + for k, v in map_iter: + self.assertEqual(v, dict_value[k]) + del dict_value[k] + + self.assertEqual({}, dict_value) + def testFieldPresence(self): message = unittest_proto3_arena_pb2.TestAllTypes() # We can't test presence of non-repeated, non-submessage fields. with self.assertRaises(ValueError): - message.HasField("optional_int32") + message.HasField('optional_int32') with self.assertRaises(ValueError): - message.HasField("optional_float") + message.HasField('optional_float') with self.assertRaises(ValueError): - message.HasField("optional_string") + message.HasField('optional_string') with self.assertRaises(ValueError): - message.HasField("optional_bool") + message.HasField('optional_bool') # But we can still test presence of submessage fields. - self.assertFalse(message.HasField("optional_nested_message")) + self.assertFalse(message.HasField('optional_nested_message')) # As with proto2, we can't test presence of fields that don't exist, or # repeated fields. with self.assertRaises(ValueError): - message.HasField("field_doesnt_exist") + message.HasField('field_doesnt_exist') with self.assertRaises(ValueError): - message.HasField("repeated_int32") + message.HasField('repeated_int32') with self.assertRaises(ValueError): - message.HasField("repeated_nested_message") + message.HasField('repeated_nested_message') # Fields should default to their type-specific default. self.assertEqual(0, message.optional_int32) self.assertEqual(0, message.optional_float) - self.assertEqual("", message.optional_string) + self.assertEqual('', message.optional_string) self.assertEqual(False, message.optional_bool) self.assertEqual(0, message.optional_nested_message.bb) # Setting a submessage should still return proper presence information. message.optional_nested_message.bb = 0 - self.assertTrue(message.HasField("optional_nested_message")) + self.assertTrue(message.HasField('optional_nested_message')) # Set the fields to non-default values. message.optional_int32 = 5 message.optional_float = 1.1 - message.optional_string = "abc" + message.optional_string = 'abc' message.optional_bool = True message.optional_nested_message.bb = 15 # Clearing the fields unsets them and resets their value to default. - message.ClearField("optional_int32") - message.ClearField("optional_float") - message.ClearField("optional_string") - message.ClearField("optional_bool") - message.ClearField("optional_nested_message") + message.ClearField('optional_int32') + message.ClearField('optional_float') + message.ClearField('optional_string') + message.ClearField('optional_bool') + message.ClearField('optional_nested_message') self.assertEqual(0, message.optional_int32) self.assertEqual(0, message.optional_float) - self.assertEqual("", message.optional_string) + self.assertEqual('', message.optional_string) self.assertEqual(False, message.optional_bool) self.assertEqual(0, message.optional_nested_message.bb) @@ -1113,6 +1197,393 @@ class Proto3Test(unittest.TestCase): self.assertEqual(1234567, m2.optional_nested_enum) self.assertEqual(7654321, m2.repeated_nested_enum[0]) + # Map isn't really a proto3-only feature. But there is no proto2 equivalent + # of google/protobuf/map_unittest.proto right now, so it's not easy to + # test both with the same test like we do for the other proto2/proto3 tests. + # (google/protobuf/map_protobuf_unittest.proto is very different in the set + # of messages and fields it contains). + def testScalarMapDefaults(self): + msg = map_unittest_pb2.TestMap() + + # Scalars start out unset. + self.assertFalse(-123 in msg.map_int32_int32) + self.assertFalse(-2**33 in msg.map_int64_int64) + self.assertFalse(123 in msg.map_uint32_uint32) + self.assertFalse(2**33 in msg.map_uint64_uint64) + self.assertFalse('abc' in msg.map_string_string) + self.assertFalse(888 in msg.map_int32_enum) + + # Accessing an unset key returns the default. + self.assertEqual(0, msg.map_int32_int32[-123]) + self.assertEqual(0, msg.map_int64_int64[-2**33]) + self.assertEqual(0, msg.map_uint32_uint32[123]) + self.assertEqual(0, msg.map_uint64_uint64[2**33]) + self.assertEqual('', msg.map_string_string['abc']) + self.assertEqual(0, msg.map_int32_enum[888]) + + # It also sets the value in the map + self.assertTrue(-123 in msg.map_int32_int32) + self.assertTrue(-2**33 in msg.map_int64_int64) + self.assertTrue(123 in msg.map_uint32_uint32) + self.assertTrue(2**33 in msg.map_uint64_uint64) + self.assertTrue('abc' in msg.map_string_string) + self.assertTrue(888 in msg.map_int32_enum) + + self.assertTrue(isinstance(msg.map_string_string['abc'], unicode)) + + # Accessing an unset key still throws TypeError of the type of the key + # is incorrect. + with self.assertRaises(TypeError): + msg.map_string_string[123] + + self.assertFalse(123 in msg.map_string_string) + + def testMapGet(self): + # Need to test that get() properly returns the default, even though the dict + # has defaultdict-like semantics. + msg = map_unittest_pb2.TestMap() + + self.assertIsNone(msg.map_int32_int32.get(5)) + self.assertEquals(10, msg.map_int32_int32.get(5, 10)) + self.assertIsNone(msg.map_int32_int32.get(5)) + + msg.map_int32_int32[5] = 15 + self.assertEquals(15, msg.map_int32_int32.get(5)) + + self.assertIsNone(msg.map_int32_foreign_message.get(5)) + self.assertEquals(10, msg.map_int32_foreign_message.get(5, 10)) + + submsg = msg.map_int32_foreign_message[5] + self.assertIs(submsg, msg.map_int32_foreign_message.get(5)) + + def testScalarMap(self): + msg = map_unittest_pb2.TestMap() + + self.assertEqual(0, len(msg.map_int32_int32)) + self.assertFalse(5 in msg.map_int32_int32) + + msg.map_int32_int32[-123] = -456 + msg.map_int64_int64[-2**33] = -2**34 + msg.map_uint32_uint32[123] = 456 + msg.map_uint64_uint64[2**33] = 2**34 + msg.map_string_string['abc'] = '123' + msg.map_int32_enum[888] = 2 + + self.assertEqual([], msg.FindInitializationErrors()) + + self.assertEqual(1, len(msg.map_string_string)) + + # Bad key. + with self.assertRaises(TypeError): + msg.map_string_string[123] = '123' + + # Verify that trying to assign a bad key doesn't actually add a member to + # the map. + self.assertEqual(1, len(msg.map_string_string)) + + # Bad value. + with self.assertRaises(TypeError): + msg.map_string_string['123'] = 123 + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMap() + msg2.ParseFromString(serialized) + + # Bad key. + with self.assertRaises(TypeError): + msg2.map_string_string[123] = '123' + + # Bad value. + with self.assertRaises(TypeError): + msg2.map_string_string['123'] = 123 + + self.assertEqual(-456, msg2.map_int32_int32[-123]) + self.assertEqual(-2**34, msg2.map_int64_int64[-2**33]) + self.assertEqual(456, msg2.map_uint32_uint32[123]) + self.assertEqual(2**34, msg2.map_uint64_uint64[2**33]) + self.assertEqual('123', msg2.map_string_string['abc']) + self.assertEqual(2, msg2.map_int32_enum[888]) + + def testStringUnicodeConversionInMap(self): + msg = map_unittest_pb2.TestMap() + + unicode_obj = u'\u1234' + bytes_obj = unicode_obj.encode('utf8') + + msg.map_string_string[bytes_obj] = bytes_obj + + (key, value) = msg.map_string_string.items()[0] + + self.assertEqual(key, unicode_obj) + self.assertEqual(value, unicode_obj) + + self.assertTrue(isinstance(key, unicode)) + self.assertTrue(isinstance(value, unicode)) + + def testMessageMap(self): + msg = map_unittest_pb2.TestMap() + + self.assertEqual(0, len(msg.map_int32_foreign_message)) + self.assertFalse(5 in msg.map_int32_foreign_message) + + msg.map_int32_foreign_message[123] + # get_or_create() is an alias for getitem. + msg.map_int32_foreign_message.get_or_create(-456) + + self.assertEqual(2, len(msg.map_int32_foreign_message)) + self.assertIn(123, msg.map_int32_foreign_message) + self.assertIn(-456, msg.map_int32_foreign_message) + self.assertEqual(2, len(msg.map_int32_foreign_message)) + + # Bad key. + with self.assertRaises(TypeError): + msg.map_int32_foreign_message['123'] + + # Can't assign directly to submessage. + with self.assertRaises(ValueError): + msg.map_int32_foreign_message[999] = msg.map_int32_foreign_message[123] + + # Verify that trying to assign a bad key doesn't actually add a member to + # the map. + self.assertEqual(2, len(msg.map_int32_foreign_message)) + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMap() + msg2.ParseFromString(serialized) + + self.assertEqual(2, len(msg2.map_int32_foreign_message)) + self.assertIn(123, msg2.map_int32_foreign_message) + self.assertIn(-456, msg2.map_int32_foreign_message) + self.assertEqual(2, len(msg2.map_int32_foreign_message)) + + def testMergeFrom(self): + msg = map_unittest_pb2.TestMap() + msg.map_int32_int32[12] = 34 + msg.map_int32_int32[56] = 78 + msg.map_int64_int64[22] = 33 + msg.map_int32_foreign_message[111].c = 5 + msg.map_int32_foreign_message[222].c = 10 + + msg2 = map_unittest_pb2.TestMap() + msg2.map_int32_int32[12] = 55 + msg2.map_int64_int64[88] = 99 + msg2.map_int32_foreign_message[222].c = 15 + + msg2.MergeFrom(msg) + + self.assertEqual(34, msg2.map_int32_int32[12]) + self.assertEqual(78, msg2.map_int32_int32[56]) + self.assertEqual(33, msg2.map_int64_int64[22]) + self.assertEqual(99, msg2.map_int64_int64[88]) + self.assertEqual(5, msg2.map_int32_foreign_message[111].c) + self.assertEqual(10, msg2.map_int32_foreign_message[222].c) + + # Verify that there is only one entry per key, even though the MergeFrom + # may have internally created multiple entries for a single key in the + # list representation. + as_dict = {} + for key in msg2.map_int32_foreign_message: + self.assertFalse(key in as_dict) + as_dict[key] = msg2.map_int32_foreign_message[key].c + + self.assertEqual({111: 5, 222: 10}, as_dict) + + # Special case: test that delete of item really removes the item, even if + # there might have physically been duplicate keys due to the previous merge. + # This is only a special case for the C++ implementation which stores the + # map as an array. + del msg2.map_int32_int32[12] + self.assertFalse(12 in msg2.map_int32_int32) + + del msg2.map_int32_foreign_message[222] + self.assertFalse(222 in msg2.map_int32_foreign_message) + + def testIntegerMapWithLongs(self): + msg = map_unittest_pb2.TestMap() + msg.map_int32_int32[long(-123)] = long(-456) + msg.map_int64_int64[long(-2**33)] = long(-2**34) + msg.map_uint32_uint32[long(123)] = long(456) + msg.map_uint64_uint64[long(2**33)] = long(2**34) + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMap() + msg2.ParseFromString(serialized) + + self.assertEqual(-456, msg2.map_int32_int32[-123]) + self.assertEqual(-2**34, msg2.map_int64_int64[-2**33]) + self.assertEqual(456, msg2.map_uint32_uint32[123]) + self.assertEqual(2**34, msg2.map_uint64_uint64[2**33]) + + def testMapAssignmentCausesPresence(self): + msg = map_unittest_pb2.TestMapSubmessage() + msg.test_map.map_int32_int32[123] = 456 + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMapSubmessage() + msg2.ParseFromString(serialized) + + self.assertEqual(msg, msg2) + + # Now test that various mutations of the map properly invalidate the + # cached size of the submessage. + msg.test_map.map_int32_int32[888] = 999 + serialized = msg.SerializeToString() + msg2.ParseFromString(serialized) + self.assertEqual(msg, msg2) + + msg.test_map.map_int32_int32.clear() + serialized = msg.SerializeToString() + msg2.ParseFromString(serialized) + self.assertEqual(msg, msg2) + + def testMapAssignmentCausesPresenceForSubmessages(self): + msg = map_unittest_pb2.TestMapSubmessage() + msg.test_map.map_int32_foreign_message[123].c = 5 + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMapSubmessage() + msg2.ParseFromString(serialized) + + self.assertEqual(msg, msg2) + + # Now test that various mutations of the map properly invalidate the + # cached size of the submessage. + msg.test_map.map_int32_foreign_message[888].c = 7 + serialized = msg.SerializeToString() + msg2.ParseFromString(serialized) + self.assertEqual(msg, msg2) + + msg.test_map.map_int32_foreign_message[888].MergeFrom( + msg.test_map.map_int32_foreign_message[123]) + serialized = msg.SerializeToString() + msg2.ParseFromString(serialized) + self.assertEqual(msg, msg2) + + msg.test_map.map_int32_foreign_message.clear() + serialized = msg.SerializeToString() + msg2.ParseFromString(serialized) + self.assertEqual(msg, msg2) + + def testModifyMapWhileIterating(self): + msg = map_unittest_pb2.TestMap() + + string_string_iter = iter(msg.map_string_string) + int32_foreign_iter = iter(msg.map_int32_foreign_message) + + msg.map_string_string['abc'] = '123' + msg.map_int32_foreign_message[5].c = 5 + + with self.assertRaises(RuntimeError): + for key in string_string_iter: + pass + + with self.assertRaises(RuntimeError): + for key in int32_foreign_iter: + pass + + def testSubmessageMap(self): + msg = map_unittest_pb2.TestMap() + + submsg = msg.map_int32_foreign_message[111] + self.assertIs(submsg, msg.map_int32_foreign_message[111]) + self.assertTrue(isinstance(submsg, unittest_pb2.ForeignMessage)) + + submsg.c = 5 + + serialized = msg.SerializeToString() + msg2 = map_unittest_pb2.TestMap() + msg2.ParseFromString(serialized) + + self.assertEqual(5, msg2.map_int32_foreign_message[111].c) + + # Doesn't allow direct submessage assignment. + with self.assertRaises(ValueError): + msg.map_int32_foreign_message[88] = unittest_pb2.ForeignMessage() + + def testMapIteration(self): + msg = map_unittest_pb2.TestMap() + + for k, v in msg.map_int32_int32.iteritems(): + # Should not be reached. + self.assertTrue(False) + + msg.map_int32_int32[2] = 4 + msg.map_int32_int32[3] = 6 + msg.map_int32_int32[4] = 8 + self.assertEqual(3, len(msg.map_int32_int32)) + + matching_dict = {2: 4, 3: 6, 4: 8} + self.assertMapIterEquals(msg.map_int32_int32.iteritems(), matching_dict) + + def testMapIterationClearMessage(self): + # Iterator needs to work even if message and map are deleted. + msg = map_unittest_pb2.TestMap() + + msg.map_int32_int32[2] = 4 + msg.map_int32_int32[3] = 6 + msg.map_int32_int32[4] = 8 + + it = msg.map_int32_int32.iteritems() + del msg + + matching_dict = {2: 4, 3: 6, 4: 8} + self.assertMapIterEquals(it, matching_dict) + + def testMapConstruction(self): + msg = map_unittest_pb2.TestMap(map_int32_int32={1: 2, 3: 4}) + self.assertEqual(2, msg.map_int32_int32[1]) + self.assertEqual(4, msg.map_int32_int32[3]) + + msg = map_unittest_pb2.TestMap( + map_int32_foreign_message={3: unittest_pb2.ForeignMessage(c=5)}) + self.assertEqual(5, msg.map_int32_foreign_message[3].c) + + def testMapValidAfterFieldCleared(self): + # Map needs to work even if field is cleared. + # For the C++ implementation this tests the correctness of + # ScalarMapContainer::Release() + msg = map_unittest_pb2.TestMap() + map = msg.map_int32_int32 + + map[2] = 4 + map[3] = 6 + map[4] = 8 + + msg.ClearField('map_int32_int32') + matching_dict = {2: 4, 3: 6, 4: 8} + self.assertMapIterEquals(map.iteritems(), matching_dict) + + def testMapIterValidAfterFieldCleared(self): + # Map iterator needs to work even if field is cleared. + # For the C++ implementation this tests the correctness of + # ScalarMapContainer::Release() + msg = map_unittest_pb2.TestMap() + + msg.map_int32_int32[2] = 4 + msg.map_int32_int32[3] = 6 + msg.map_int32_int32[4] = 8 + + it = msg.map_int32_int32.iteritems() + + msg.ClearField('map_int32_int32') + matching_dict = {2: 4, 3: 6, 4: 8} + self.assertMapIterEquals(it, matching_dict) + + def testMapDelete(self): + msg = map_unittest_pb2.TestMap() + + self.assertEqual(0, len(msg.map_int32_int32)) + + msg.map_int32_int32[4] = 6 + self.assertEqual(1, len(msg.map_int32_int32)) + + with self.assertRaises(KeyError): + del msg.map_int32_int32[88] + + del msg.map_int32_int32[4] + self.assertEqual(0, len(msg.map_int32_int32)) + + class ValidTypeNamesTest(unittest.TestCase): diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py index b1e57f3549..edaf3fa358 100644 --- a/python/google/protobuf/internal/proto_builder_test.py +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -32,6 +32,7 @@ """Tests for google.protobuf.proto_builder.""" +import collections import unittest from google.protobuf import descriptor_pb2 @@ -43,10 +44,11 @@ from google.protobuf import text_format class ProtoBuilderTest(unittest.TestCase): def setUp(self): - self._fields = { - 'foo': descriptor_pb2.FieldDescriptorProto.TYPE_INT64, - 'bar': descriptor_pb2.FieldDescriptorProto.TYPE_STRING, - } + self.ordered_fields = collections.OrderedDict([ + ('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64), + ('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING), + ]) + self._fields = dict(self.ordered_fields) def testMakeSimpleProtoClass(self): """Test that we can create a proto class.""" @@ -59,6 +61,17 @@ class ProtoBuilderTest(unittest.TestCase): self.assertMultiLineEqual( 'bar: "asdf"\nfoo: 12345\n', text_format.MessageToString(proto)) + def testOrderedFields(self): + """Test that the field order is maintained when given an OrderedDict.""" + proto_cls = proto_builder.MakeSimpleProtoClass( + self.ordered_fields, + full_name='net.proto2.python.public.proto_builder_test.OrderedTest') + proto = proto_cls() + proto.foo = 12345 + proto.bar = 'asdf' + self.assertMultiLineEqual( + 'foo: 12345\nbar: "asdf"\n', text_format.MessageToString(proto)) + def testMakeSameProtoClassTwice(self): """Test that the DescriptorPool is used.""" pool = descriptor_pool.DescriptorPool() diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py index 54f584ae8a..ca9f76753b 100755 --- a/python/google/protobuf/internal/python_message.py +++ b/python/google/protobuf/internal/python_message.py @@ -61,9 +61,11 @@ if sys.version_info[0] < 3: except ImportError: from StringIO import StringIO as BytesIO import copy_reg as copyreg + _basestring = basestring else: from io import BytesIO import copyreg + _basestring = str import struct import weakref @@ -77,6 +79,7 @@ from google.protobuf.internal import type_checkers from google.protobuf.internal import wire_format from google.protobuf import descriptor as descriptor_mod from google.protobuf import message as message_mod +from google.protobuf import symbol_database from google.protobuf import text_format _FieldDescriptor = descriptor_mod.FieldDescriptor @@ -101,6 +104,7 @@ def InitMessage(descriptor, cls): for field in descriptor.fields: _AttachFieldHelpers(cls, field) + descriptor._concrete_class = cls # pylint: disable=protected-access _AddEnumValues(descriptor, cls) _AddInitMethod(descriptor, cls) _AddPropertiesForFields(descriptor, cls) @@ -198,12 +202,37 @@ def _IsMessageSetExtension(field): field.label == _FieldDescriptor.LABEL_OPTIONAL) +def _IsMapField(field): + return (field.type == _FieldDescriptor.TYPE_MESSAGE and + field.message_type.has_options and + field.message_type.GetOptions().map_entry) + + +def _IsMessageMapField(field): + value_type = field.message_type.fields_by_name["value"] + return value_type.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE + + def _AttachFieldHelpers(cls, field_descriptor): is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED) - is_packed = (field_descriptor.has_options and - field_descriptor.GetOptions().packed) - - if _IsMessageSetExtension(field_descriptor): + is_packable = (is_repeated and + wire_format.IsTypePackable(field_descriptor.type)) + if not is_packable: + is_packed = False + elif field_descriptor.containing_type.syntax == "proto2": + is_packed = (field_descriptor.has_options and + field_descriptor.GetOptions().packed) + else: + has_packed_false = (field_descriptor.has_options and + field_descriptor.GetOptions().HasField("packed") and + field_descriptor.GetOptions().packed == False) + is_packed = not has_packed_false + is_map_entry = _IsMapField(field_descriptor) + + if is_map_entry: + field_encoder = encoder.MapEncoder(field_descriptor) + sizer = encoder.MapSizer(field_descriptor) + elif _IsMessageSetExtension(field_descriptor): field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number) sizer = encoder.MessageSetItemSizer(field_descriptor.number) else: @@ -228,9 +257,16 @@ def _AttachFieldHelpers(cls, field_descriptor): if field_descriptor.containing_oneof is not None: oneof_descriptor = field_descriptor - field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( - field_descriptor.number, is_repeated, is_packed, - field_descriptor, field_descriptor._default_constructor) + if is_map_entry: + is_message_map = _IsMessageMapField(field_descriptor) + + field_decoder = decoder.MapDecoder( + field_descriptor, _GetInitializeDefaultForMap(field_descriptor), + is_message_map) + else: + field_decoder = type_checkers.TYPE_TO_DECODER[decode_type]( + field_descriptor.number, is_repeated, is_packed, + field_descriptor, field_descriptor._default_constructor) cls._decoders_by_tag[tag_bytes] = (field_decoder, oneof_descriptor) @@ -265,6 +301,26 @@ def _AddEnumValues(descriptor, cls): setattr(cls, enum_value.name, enum_value.number) +def _GetInitializeDefaultForMap(field): + if field.label != _FieldDescriptor.LABEL_REPEATED: + raise ValueError('map_entry set on non-repeated field %s' % ( + field.name)) + fields_by_name = field.message_type.fields_by_name + key_checker = type_checkers.GetTypeChecker(fields_by_name['key']) + + value_field = fields_by_name['value'] + if _IsMessageMapField(field): + def MakeMessageMapDefault(message): + return containers.MessageMap( + message._listener_for_children, value_field.message_type, key_checker) + return MakeMessageMapDefault + else: + value_checker = type_checkers.GetTypeChecker(value_field) + def MakePrimitiveMapDefault(message): + return containers.ScalarMap( + message._listener_for_children, key_checker, value_checker) + return MakePrimitiveMapDefault + def _DefaultValueConstructorForField(field): """Returns a function which returns a default value for a field. @@ -279,6 +335,9 @@ def _DefaultValueConstructorForField(field): value may refer back to |message| via a weak reference. """ + if _IsMapField(field): + return _GetInitializeDefaultForMap(field) + if field.label == _FieldDescriptor.LABEL_REPEATED: if field.has_default_value and field.default_value != []: raise ValueError('Repeated field default value not empty list: %s' % ( @@ -329,7 +388,22 @@ def _ReraiseTypeErrorWithFieldName(message_name, field_name): def _AddInitMethod(message_descriptor, cls): """Adds an __init__ method to cls.""" - fields = message_descriptor.fields + + def _GetIntegerEnumValue(enum_type, value): + """Convert a string or integer enum value to an integer. + + If the value is a string, it is converted to the enum value in + enum_type with the same name. If the value is not a string, it's + returned as-is. (No conversion or bounds-checking is done.) + """ + if isinstance(value, _basestring): + try: + return enum_type.values_by_name[value].number + except KeyError: + raise ValueError('Enum type %s: unknown label "%s"' % ( + enum_type.full_name, value)) + return value + def init(self, **kwargs): self._cached_byte_size = 0 self._cached_byte_size_dirty = len(kwargs) > 0 @@ -352,19 +426,37 @@ def _AddInitMethod(message_descriptor, cls): if field.label == _FieldDescriptor.LABEL_REPEATED: copy = field._default_constructor(self) if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: # Composite - for val in field_value: - copy.add().MergeFrom(val) + if _IsMapField(field): + if _IsMessageMapField(field): + for key in field_value: + copy[key].MergeFrom(field_value[key]) + else: + copy.update(field_value) + else: + for val in field_value: + if isinstance(val, dict): + copy.add(**val) + else: + copy.add().MergeFrom(val) else: # Scalar + if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: + field_value = [_GetIntegerEnumValue(field.enum_type, val) + for val in field_value] copy.extend(field_value) self._fields[field] = copy elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: copy = field._default_constructor(self) + new_val = field_value + if isinstance(field_value, dict): + new_val = field.message_type._concrete_class(**field_value) try: - copy.MergeFrom(field_value) + copy.MergeFrom(new_val) except TypeError: _ReraiseTypeErrorWithFieldName(message_descriptor.name, field_name) self._fields[field] = copy else: + if field.cpp_type == _FieldDescriptor.CPPTYPE_ENUM: + field_value = _GetIntegerEnumValue(field.enum_type, field_value) try: setattr(self, field_name, field_value) except TypeError: @@ -758,6 +850,26 @@ def _AddHasExtensionMethod(cls): return extension_handle in self._fields cls.HasExtension = HasExtension +def _UnpackAny(msg): + type_url = msg.type_url + db = symbol_database.Default() + + if not type_url: + return None + + # TODO(haberman): For now we just strip the hostname. Better logic will be + # required. + type_name = type_url.split("/")[-1] + descriptor = db.pool.FindMessageTypeByName(type_name) + + if descriptor is None: + return None + + message_class = db.GetPrototype(descriptor) + message = message_class() + + message.ParseFromString(msg.value) + return message def _AddEqualsMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" @@ -769,6 +881,12 @@ def _AddEqualsMethod(message_descriptor, cls): if self is other: return True + if self.DESCRIPTOR.full_name == "google.protobuf.Any": + any_a = _UnpackAny(self) + any_b = _UnpackAny(other) + if any_a and any_b: + return any_a == any_b + if not self.ListFields() == other.ListFields(): return False @@ -961,6 +1079,9 @@ def _AddIsInitializedMethod(message_descriptor, cls): for field, value in list(self._fields.items()): # dict can change size! if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE: if field.label == _FieldDescriptor.LABEL_REPEATED: + if (field.message_type.has_options and + field.message_type.GetOptions().map_entry): + continue for element in value: if not element.IsInitialized(): if errors is not None: @@ -996,16 +1117,26 @@ def _AddIsInitializedMethod(message_descriptor, cls): else: name = field.name - if field.label == _FieldDescriptor.LABEL_REPEATED: + if _IsMapField(field): + if _IsMessageMapField(field): + for key in value: + element = value[key] + prefix = "%s[%d]." % (name, key) + sub_errors = element.FindInitializationErrors() + errors += [prefix + error for error in sub_errors] + else: + # ScalarMaps can't have any initialization errors. + pass + elif field.label == _FieldDescriptor.LABEL_REPEATED: for i in xrange(len(value)): element = value[i] prefix = "%s[%d]." % (name, i) sub_errors = element.FindInitializationErrors() - errors += [ prefix + error for error in sub_errors ] + errors += [prefix + error for error in sub_errors] else: prefix = name + "." sub_errors = value.FindInitializationErrors() - errors += [ prefix + error for error in sub_errors ] + errors += [prefix + error for error in sub_errors] return errors diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index ae79c78b8e..4eca4989ea 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -39,8 +39,8 @@ import copy import gc import operator import struct -import unittest +import unittest from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 @@ -1798,8 +1798,8 @@ class ReflectionTest(unittest.TestCase): def testBadArguments(self): # Some of these assertions used to segfault. from google.protobuf.pyext import _message - self.assertRaises(TypeError, _message.Message._GetFieldDescriptor, 3) - self.assertRaises(TypeError, _message.Message._GetExtensionDescriptor, 42) + self.assertRaises(TypeError, _message.default_pool.FindFieldByName, 3) + self.assertRaises(TypeError, _message.default_pool.FindExtensionByName, 42) self.assertRaises(TypeError, unittest_pb2.TestAllTypes().__getattribute__, 42) diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py index de462124fe..9967255a19 100755 --- a/python/google/protobuf/internal/service_reflection_test.py +++ b/python/google/protobuf/internal/service_reflection_test.py @@ -35,7 +35,6 @@ __author__ = 'petar@google.com (Petar Petrov)' import unittest - from google.protobuf import unittest_pb2 from google.protobuf import service_reflection from google.protobuf import service @@ -81,7 +80,7 @@ class FooUnitTest(unittest.TestCase): self.assertEqual('Method Bar not implemented.', rpc_controller.failure_message) self.assertEqual(None, self.callback_response) - + class MyServiceImpl(unittest_pb2.TestService): def Foo(self, rpc_controller, request, done): self.foo_called = True diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py index c888aff717..80b83bc2ad 100644 --- a/python/google/protobuf/internal/symbol_database_test.py +++ b/python/google/protobuf/internal/symbol_database_test.py @@ -33,7 +33,6 @@ """Tests for google.protobuf.symbol_database.""" import unittest - from google.protobuf import unittest_pb2 from google.protobuf import symbol_database diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py index d84e383619..0cbdbad918 100755 --- a/python/google/protobuf/internal/test_util.py +++ b/python/google/protobuf/internal/test_util.py @@ -75,7 +75,8 @@ def SetAllNonLazyFields(message): message.optional_string = u'115' message.optional_bytes = b'116' - message.optionalgroup.a = 117 + if IsProto2(message): + message.optionalgroup.a = 117 message.optional_nested_message.bb = 118 message.optional_foreign_message.c = 119 message.optional_import_message.d = 120 @@ -109,7 +110,8 @@ def SetAllNonLazyFields(message): message.repeated_string.append(u'215') message.repeated_bytes.append(b'216') - message.repeatedgroup.add().a = 217 + if IsProto2(message): + message.repeatedgroup.add().a = 217 message.repeated_nested_message.add().bb = 218 message.repeated_foreign_message.add().c = 219 message.repeated_import_message.add().d = 220 @@ -140,7 +142,8 @@ def SetAllNonLazyFields(message): message.repeated_string.append(u'315') message.repeated_bytes.append(b'316') - message.repeatedgroup.add().a = 317 + if IsProto2(message): + message.repeatedgroup.add().a = 317 message.repeated_nested_message.add().bb = 318 message.repeated_foreign_message.add().c = 319 message.repeated_import_message.add().d = 320 @@ -396,7 +399,8 @@ def ExpectAllFieldsSet(test_case, message): test_case.assertTrue(message.HasField('optional_string')) test_case.assertTrue(message.HasField('optional_bytes')) - test_case.assertTrue(message.HasField('optionalgroup')) + if IsProto2(message): + test_case.assertTrue(message.HasField('optionalgroup')) test_case.assertTrue(message.HasField('optional_nested_message')) test_case.assertTrue(message.HasField('optional_foreign_message')) test_case.assertTrue(message.HasField('optional_import_message')) @@ -430,7 +434,8 @@ def ExpectAllFieldsSet(test_case, message): test_case.assertEqual('115', message.optional_string) test_case.assertEqual(b'116', message.optional_bytes) - test_case.assertEqual(117, message.optionalgroup.a) + if IsProto2(message): + test_case.assertEqual(117, message.optionalgroup.a) test_case.assertEqual(118, message.optional_nested_message.bb) test_case.assertEqual(119, message.optional_foreign_message.c) test_case.assertEqual(120, message.optional_import_message.d) @@ -463,7 +468,8 @@ def ExpectAllFieldsSet(test_case, message): test_case.assertEqual(2, len(message.repeated_string)) test_case.assertEqual(2, len(message.repeated_bytes)) - test_case.assertEqual(2, len(message.repeatedgroup)) + if IsProto2(message): + test_case.assertEqual(2, len(message.repeatedgroup)) test_case.assertEqual(2, len(message.repeated_nested_message)) test_case.assertEqual(2, len(message.repeated_foreign_message)) test_case.assertEqual(2, len(message.repeated_import_message)) @@ -491,7 +497,8 @@ def ExpectAllFieldsSet(test_case, message): test_case.assertEqual('215', message.repeated_string[0]) test_case.assertEqual(b'216', message.repeated_bytes[0]) - test_case.assertEqual(217, message.repeatedgroup[0].a) + if IsProto2(message): + test_case.assertEqual(217, message.repeatedgroup[0].a) test_case.assertEqual(218, message.repeated_nested_message[0].bb) test_case.assertEqual(219, message.repeated_foreign_message[0].c) test_case.assertEqual(220, message.repeated_import_message[0].d) @@ -521,7 +528,8 @@ def ExpectAllFieldsSet(test_case, message): test_case.assertEqual('315', message.repeated_string[1]) test_case.assertEqual(b'316', message.repeated_bytes[1]) - test_case.assertEqual(317, message.repeatedgroup[1].a) + if IsProto2(message): + test_case.assertEqual(317, message.repeatedgroup[1].a) test_case.assertEqual(318, message.repeated_nested_message[1].bb) test_case.assertEqual(319, message.repeated_foreign_message[1].c) test_case.assertEqual(320, message.repeated_import_message[1].d) diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py index 27896b9417..5df13b7896 100755 --- a/python/google/protobuf/internal/text_encoding_test.py +++ b/python/google/protobuf/internal/text_encoding_test.py @@ -33,7 +33,6 @@ """Tests for google.protobuf.text_encoding.""" import unittest - from google.protobuf import text_encoding TEST_VALUES = [ diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index bf7e06eef3..06bd1ee558 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -37,8 +37,10 @@ __author__ = 'kenton@google.com (Kenton Varda)' import re import unittest +import unittest from google.protobuf.internal import _parameterized +from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 @@ -309,31 +311,6 @@ class TextFormatTest(TextFormatBase): r'"unknown_field".'), text_format.Parse, text, message) - def testParseGroupNotClosed(self, message_module): - message = message_module.TestAllTypes() - text = 'RepeatedGroup: <' - self.assertRaisesRegexp( - text_format.ParseError, '1:16 : Expected ">".', - text_format.Parse, text, message) - - text = 'RepeatedGroup: {' - self.assertRaisesRegexp( - text_format.ParseError, '1:16 : Expected "}".', - text_format.Parse, text, message) - - def testParseEmptyGroup(self, message_module): - message = message_module.TestAllTypes() - text = 'OptionalGroup: {}' - text_format.Parse(text, message) - self.assertTrue(message.HasField('optionalgroup')) - - message.Clear() - - message = message_module.TestAllTypes() - text = 'OptionalGroup: <>' - text_format.Parse(text, message) - self.assertTrue(message.HasField('optionalgroup')) - def testParseBadEnumValue(self, message_module): message = message_module.TestAllTypes() text = 'optional_nested_enum: BARR' @@ -408,6 +385,14 @@ class TextFormatTest(TextFormatBase): # Ideally the schemas would be made more similar so these tests could pass. class OnlyWorksWithProto2RightNowTests(TextFormatBase): + def testPrintAllFieldsPointy(self, message_module): + message = unittest_pb2.TestAllTypes() + test_util.SetAllFields(message) + self.CompareToGoldenFile( + self.RemoveRedundantZeros( + text_format.MessageToString(message, pointy_brackets=True)), + 'text_format_unittest_data_pointy_oneof.txt') + def testParseGolden(self): golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) parsed_message = unittest_pb2.TestAllTypes() @@ -471,8 +456,49 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): test_util.SetAllFields(message) self.assertEquals(message, parsed_message) + def testPrintMap(self): + message = map_unittest_pb2.TestMap() -# Tests of proto2-only features (MessageSet and extensions). + message.map_int32_int32[-123] = -456 + message.map_int64_int64[-2**33] = -2**34 + message.map_uint32_uint32[123] = 456 + message.map_uint64_uint64[2**33] = 2**34 + message.map_string_string["abc"] = "123" + message.map_int32_foreign_message[111].c = 5 + + # Maps are serialized to text format using their underlying repeated + # representation. + self.CompareToGoldenText( + text_format.MessageToString(message), + 'map_int32_int32 {\n' + ' key: -123\n' + ' value: -456\n' + '}\n' + 'map_int64_int64 {\n' + ' key: -8589934592\n' + ' value: -17179869184\n' + '}\n' + 'map_uint32_uint32 {\n' + ' key: 123\n' + ' value: 456\n' + '}\n' + 'map_uint64_uint64 {\n' + ' key: 8589934592\n' + ' value: 17179869184\n' + '}\n' + 'map_string_string {\n' + ' key: "abc"\n' + ' value: "123"\n' + '}\n' + 'map_int32_foreign_message {\n' + ' key: 111\n' + ' value {\n' + ' c: 5\n' + ' }\n' + '}\n') + + +# Tests of proto2-only features (MessageSet, extensions, etc.). class Proto2Tests(TextFormatBase): def testPrintMessageSet(self): @@ -620,6 +646,69 @@ class Proto2Tests(TextFormatBase): 'have multiple "optional_int32" fields.'), text_format.Parse, text, message) + def testParseGroupNotClosed(self): + message = unittest_pb2.TestAllTypes() + text = 'RepeatedGroup: <' + self.assertRaisesRegexp( + text_format.ParseError, '1:16 : Expected ">".', + text_format.Parse, text, message) + text = 'RepeatedGroup: {' + self.assertRaisesRegexp( + text_format.ParseError, '1:16 : Expected "}".', + text_format.Parse, text, message) + + def testParseEmptyGroup(self): + message = unittest_pb2.TestAllTypes() + text = 'OptionalGroup: {}' + text_format.Parse(text, message) + self.assertTrue(message.HasField('optionalgroup')) + + message.Clear() + + message = unittest_pb2.TestAllTypes() + text = 'OptionalGroup: <>' + text_format.Parse(text, message) + self.assertTrue(message.HasField('optionalgroup')) + + # Maps aren't really proto2-only, but our test schema only has maps for + # proto2. + def testParseMap(self): + text = ('map_int32_int32 {\n' + ' key: -123\n' + ' value: -456\n' + '}\n' + 'map_int64_int64 {\n' + ' key: -8589934592\n' + ' value: -17179869184\n' + '}\n' + 'map_uint32_uint32 {\n' + ' key: 123\n' + ' value: 456\n' + '}\n' + 'map_uint64_uint64 {\n' + ' key: 8589934592\n' + ' value: 17179869184\n' + '}\n' + 'map_string_string {\n' + ' key: "abc"\n' + ' value: "123"\n' + '}\n' + 'map_int32_foreign_message {\n' + ' key: 111\n' + ' value {\n' + ' c: 5\n' + ' }\n' + '}\n') + message = map_unittest_pb2.TestMap() + text_format.Parse(text, message) + + self.assertEqual(-456, message.map_int32_int32[-123]) + self.assertEqual(-2**34, message.map_int64_int64[-2**33]) + self.assertEqual(456, message.map_uint32_uint32[123]) + self.assertEqual(2**34, message.map_uint64_uint64[2**33]) + self.assertEqual("123", message.map_string_string["abc"]) + self.assertEqual(5, message.map_int32_foreign_message[111].c) + class TokenizerTest(unittest.TestCase): diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py index 76c056c4b8..f20e526a06 100755 --- a/python/google/protobuf/internal/type_checkers.py +++ b/python/google/protobuf/internal/type_checkers.py @@ -129,6 +129,9 @@ class IntValueChecker(object): proposed_value = self._TYPE(proposed_value) return proposed_value + def DefaultValue(self): + return 0 + class EnumValueChecker(object): @@ -146,6 +149,9 @@ class EnumValueChecker(object): raise ValueError('Unknown enum value: %d' % proposed_value) return proposed_value + def DefaultValue(self): + return self._enum_type.values[0].number + class UnicodeValueChecker(object): @@ -171,6 +177,9 @@ class UnicodeValueChecker(object): (proposed_value)) return proposed_value + def DefaultValue(self): + return u"" + class Int32ValueChecker(IntValueChecker): # We're sure to use ints instead of longs here since comparison may be more diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 9337ae8a92..1b81ae79bf 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -36,7 +36,6 @@ __author__ = 'bohdank@google.com (Bohdan Koval)' import unittest - from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py index 5cd7fcb9e5..78dc11670f 100755 --- a/python/google/protobuf/internal/wire_format_test.py +++ b/python/google/protobuf/internal/wire_format_test.py @@ -35,7 +35,6 @@ __author__ = 'robinson@google.com (Will Robinson)' import unittest - from google.protobuf import message from google.protobuf.internal import wire_format diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py index 1fa28f1afe..7489cf63ab 100644 --- a/python/google/protobuf/proto_builder.py +++ b/python/google/protobuf/proto_builder.py @@ -30,6 +30,7 @@ """Dynamic Protobuf class creator.""" +import collections import hashlib import os @@ -59,7 +60,9 @@ def MakeSimpleProtoClass(fields, full_name, pool=None): Note: this doesn't validate field names! Args: - fields: dict of {name: field_type} mappings for each field in the proto. + fields: dict of {name: field_type} mappings for each field in the proto. If + this is an OrderedDict the order will be maintained, otherwise the + fields will be sorted by name. full_name: str, the fully-qualified name of the proto type. pool: optional DescriptorPool instance. Returns: @@ -73,12 +76,19 @@ def MakeSimpleProtoClass(fields, full_name, pool=None): # The factory's DescriptorPool doesn't know about this class yet. pass + # Get a list of (name, field_type) tuples from the fields dict. If fields was + # an OrderedDict we keep the order, but otherwise we sort the field to ensure + # consistent ordering. + field_items = fields.items() + if not isinstance(fields, collections.OrderedDict): + field_items = sorted(field_items) + # Use a consistent file name that is unlikely to conflict with any imported # proto files. fields_hash = hashlib.sha1() - for f_name, f_type in sorted(fields.items()): - fields_hash.update(f_name.encode('utf8')) - fields_hash.update(str(f_type).encode('utf8')) + for f_name, f_type in field_items: + fields_hash.update(f_name.encode('utf-8')) + fields_hash.update(str(f_type).encode('utf-8')) proto_file_name = fields_hash.hexdigest() + '.proto' package, name = full_name.rsplit('.', 1) @@ -87,7 +97,7 @@ def MakeSimpleProtoClass(fields, full_name, pool=None): file_proto.package = package desc_proto = file_proto.message_type.add() desc_proto.name = name - for f_number, (f_name, f_type) in enumerate(sorted(fields.items()), 1): + for f_number, (f_name, f_type) in enumerate(field_items, 1): field_proto = desc_proto.field.add() field_proto.name = f_name field_proto.number = f_number diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index e77d0bb97e..2160757b3b 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -43,8 +43,6 @@ #include #include -#define C(str) const_cast(str) - #if PY_MAJOR_VERSION >= 3 #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_Check PyUnicode_Check @@ -257,8 +255,14 @@ namespace descriptor { // Creates or retrieve a Python descriptor of the specified type. // Objects are interned: the same descriptor will return the same object if it // was kept alive. +// 'was_created' is an optional pointer to a bool, and is set to true if a new +// object was allocated. // Always return a new reference. -PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor) { +PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor, + bool* was_created) { + if (was_created) { + *was_created = false; + } if (descriptor == NULL) { PyErr_BadInternalCall(); return NULL; @@ -283,6 +287,9 @@ PyObject* NewInternedDescriptor(PyTypeObject* type, const void* descriptor) { GetDescriptorPool()->interned_descriptors->insert( std::make_pair(descriptor, reinterpret_cast(py_descriptor))); + if (was_created) { + *was_created = true; + } return reinterpret_cast(py_descriptor); } @@ -298,9 +305,7 @@ static PyGetSetDef Getters[] = { PyTypeObject PyBaseDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - "google.protobuf.internal._message." - "DescriptorBase", // tp_name + FULL_MODULE_NAME ".DescriptorBase", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize (destructor)Dealloc, // tp_dealloc @@ -357,7 +362,7 @@ static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) { } static PyObject* GetFile(PyBaseDescriptor *self, void *closure) { - return PyFileDescriptor_New(_GetDescriptor(self)->file()); + return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file()); } static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { @@ -367,17 +372,6 @@ static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { return concrete_class; } -static int SetConcreteClass(PyBaseDescriptor *self, PyObject *value, - void *closure) { - // This attribute is also set from reflection.py. Check that it's actually a - // no-op. - if (value != cdescriptor_pool::GetMessageClass( - GetDescriptorPool(), _GetDescriptor(self))) { - PyErr_SetString(PyExc_AttributeError, "Cannot change _concrete_class"); - } - return 0; -} - static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) { return NewMessageFieldsByName(_GetDescriptor(self)); } @@ -452,7 +446,7 @@ static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { const Descriptor* containing_type = _GetDescriptor(self)->containing_type(); if (containing_type) { - return PyMessageDescriptor_New(containing_type); + return PyMessageDescriptor_FromDescriptor(containing_type); } else { Py_RETURN_NONE; } @@ -515,29 +509,34 @@ static PyObject* GetSyntax(PyBaseDescriptor *self, void *closure) { } static PyGetSetDef Getters[] = { - { C("name"), (getter)GetName, NULL, "Last name", NULL}, - { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, - { C("_concrete_class"), (getter)GetConcreteClass, (setter)SetConcreteClass, "concrete class", NULL}, - { C("file"), (getter)GetFile, NULL, "File descriptor", NULL}, - - { C("fields"), (getter)GetFieldsSeq, NULL, "Fields sequence", NULL}, - { C("fields_by_name"), (getter)GetFieldsByName, NULL, "Fields by name", NULL}, - { C("fields_by_number"), (getter)GetFieldsByNumber, NULL, "Fields by number", NULL}, - { C("nested_types"), (getter)GetNestedTypesSeq, NULL, "Nested types sequence", NULL}, - { C("nested_types_by_name"), (getter)GetNestedTypesByName, NULL, "Nested types by name", NULL}, - { C("extensions"), (getter)GetExtensions, NULL, "Extensions Sequence", NULL}, - { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL}, - { C("extension_ranges"), (getter)GetExtensionRanges, NULL, "Extension ranges", NULL}, - { C("enum_types"), (getter)GetEnumsSeq, NULL, "Enum sequence", NULL}, - { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enum types by name", NULL}, - { C("enum_values_by_name"), (getter)GetEnumValuesByName, NULL, "Enum values by name", NULL}, - { C("oneofs_by_name"), (getter)GetOneofsByName, NULL, "Oneofs by name", NULL}, - { C("oneofs"), (getter)GetOneofsSeq, NULL, "Oneofs by name", NULL}, - { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL}, - { C("is_extendable"), (getter)IsExtendable, (setter)NULL, NULL, NULL}, - { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL}, - { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL}, - { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL}, + { "name", (getter)GetName, NULL, "Last name"}, + { "full_name", (getter)GetFullName, NULL, "Full name"}, + { "_concrete_class", (getter)GetConcreteClass, NULL, "concrete class"}, + { "file", (getter)GetFile, NULL, "File descriptor"}, + + { "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"}, + { "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"}, + { "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"}, + { "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"}, + { "nested_types_by_name", (getter)GetNestedTypesByName, NULL, + "Nested types by name"}, + { "extensions", (getter)GetExtensions, NULL, "Extensions Sequence"}, + { "extensions_by_name", (getter)GetExtensionsByName, NULL, + "Extensions by name"}, + { "extension_ranges", (getter)GetExtensionRanges, NULL, "Extension ranges"}, + { "enum_types", (getter)GetEnumsSeq, NULL, "Enum sequence"}, + { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, + "Enum types by name"}, + { "enum_values_by_name", (getter)GetEnumValuesByName, NULL, + "Enum values by name"}, + { "oneofs_by_name", (getter)GetOneofsByName, NULL, "Oneofs by name"}, + { "oneofs", (getter)GetOneofsSeq, NULL, "Oneofs by name"}, + { "containing_type", (getter)GetContainingType, (setter)SetContainingType, + "Containing type"}, + { "is_extendable", (getter)IsExtendable, (setter)NULL}, + { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, + { "_options", (getter)NULL, (setter)SetOptions, "Options"}, + { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"}, {NULL} }; @@ -552,9 +551,7 @@ static PyMethodDef Methods[] = { PyTypeObject PyMessageDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - C("google.protobuf.internal._message." - "MessageDescriptor"), // tp_name + FULL_MODULE_NAME ".MessageDescriptor", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize 0, // tp_dealloc @@ -573,7 +570,7 @@ PyTypeObject PyMessageDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A Message Descriptor"), // tp_doc + "A Message Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -586,10 +583,10 @@ PyTypeObject PyMessageDescriptor_Type = { &descriptor::PyBaseDescriptor_Type, // tp_base }; -PyObject* PyMessageDescriptor_New( +PyObject* PyMessageDescriptor_FromDescriptor( const Descriptor* message_descriptor) { return descriptor::NewInternedDescriptor( - &PyMessageDescriptor_Type, message_descriptor); + &PyMessageDescriptor_Type, message_descriptor, NULL); } const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj) { @@ -715,7 +712,7 @@ static PyObject* GetCDescriptor(PyObject *self, void *closure) { static PyObject *GetEnumType(PyBaseDescriptor *self, void *closure) { const EnumDescriptor* enum_type = _GetDescriptor(self)->enum_type(); if (enum_type) { - return PyEnumDescriptor_New(enum_type); + return PyEnumDescriptor_FromDescriptor(enum_type); } else { Py_RETURN_NONE; } @@ -728,7 +725,7 @@ static int SetEnumType(PyBaseDescriptor *self, PyObject *value, void *closure) { static PyObject *GetMessageType(PyBaseDescriptor *self, void *closure) { const Descriptor* message_type = _GetDescriptor(self)->message_type(); if (message_type) { - return PyMessageDescriptor_New(message_type); + return PyMessageDescriptor_FromDescriptor(message_type); } else { Py_RETURN_NONE; } @@ -743,7 +740,7 @@ static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { const Descriptor* containing_type = _GetDescriptor(self)->containing_type(); if (containing_type) { - return PyMessageDescriptor_New(containing_type); + return PyMessageDescriptor_FromDescriptor(containing_type); } else { Py_RETURN_NONE; } @@ -758,7 +755,7 @@ static PyObject* GetExtensionScope(PyBaseDescriptor *self, void *closure) { const Descriptor* extension_scope = _GetDescriptor(self)->extension_scope(); if (extension_scope) { - return PyMessageDescriptor_New(extension_scope); + return PyMessageDescriptor_FromDescriptor(extension_scope); } else { Py_RETURN_NONE; } @@ -768,7 +765,7 @@ static PyObject* GetContainingOneof(PyBaseDescriptor *self, void *closure) { const OneofDescriptor* containing_oneof = _GetDescriptor(self)->containing_oneof(); if (containing_oneof) { - return PyOneofDescriptor_New(containing_oneof); + return PyOneofDescriptor_FromDescriptor(containing_oneof); } else { Py_RETURN_NONE; } @@ -803,26 +800,30 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value, static PyGetSetDef Getters[] = { - { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, - { C("name"), (getter)GetName, NULL, "Unqualified name", NULL}, - { C("type"), (getter)GetType, NULL, "C++ Type", NULL}, - { C("cpp_type"), (getter)GetCppType, NULL, "C++ Type", NULL}, - { C("label"), (getter)GetLabel, NULL, "Label", NULL}, - { C("number"), (getter)GetNumber, NULL, "Number", NULL}, - { C("index"), (getter)GetIndex, NULL, "Index", NULL}, - { C("default_value"), (getter)GetDefaultValue, NULL, "Default Value", NULL}, - { C("has_default_value"), (getter)HasDefaultValue, NULL, NULL, NULL}, - { C("is_extension"), (getter)IsExtension, NULL, "ID", NULL}, - { C("id"), (getter)GetID, NULL, "ID", NULL}, - { C("_cdescriptor"), (getter)GetCDescriptor, NULL, "HAACK REMOVE ME", NULL}, - - { C("message_type"), (getter)GetMessageType, (setter)SetMessageType, "Message type", NULL}, - { C("enum_type"), (getter)GetEnumType, (setter)SetEnumType, "Enum type", NULL}, - { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL}, - { C("extension_scope"), (getter)GetExtensionScope, (setter)NULL, "Extension scope", NULL}, - { C("containing_oneof"), (getter)GetContainingOneof, (setter)SetContainingOneof, "Containing oneof", NULL}, - { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL}, - { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL}, + { "full_name", (getter)GetFullName, NULL, "Full name"}, + { "name", (getter)GetName, NULL, "Unqualified name"}, + { "type", (getter)GetType, NULL, "C++ Type"}, + { "cpp_type", (getter)GetCppType, NULL, "C++ Type"}, + { "label", (getter)GetLabel, NULL, "Label"}, + { "number", (getter)GetNumber, NULL, "Number"}, + { "index", (getter)GetIndex, NULL, "Index"}, + { "default_value", (getter)GetDefaultValue, NULL, "Default Value"}, + { "has_default_value", (getter)HasDefaultValue}, + { "is_extension", (getter)IsExtension, NULL, "ID"}, + { "id", (getter)GetID, NULL, "ID"}, + { "_cdescriptor", (getter)GetCDescriptor, NULL, "HAACK REMOVE ME"}, + + { "message_type", (getter)GetMessageType, (setter)SetMessageType, + "Message type"}, + { "enum_type", (getter)GetEnumType, (setter)SetEnumType, "Enum type"}, + { "containing_type", (getter)GetContainingType, (setter)SetContainingType, + "Containing type"}, + { "extension_scope", (getter)GetExtensionScope, (setter)NULL, + "Extension scope"}, + { "containing_oneof", (getter)GetContainingOneof, (setter)SetContainingOneof, + "Containing oneof"}, + { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, + { "_options", (getter)NULL, (setter)SetOptions, "Options"}, {NULL} }; @@ -835,8 +836,7 @@ static PyMethodDef Methods[] = { PyTypeObject PyFieldDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - C("google.protobuf.internal." - "_message.FieldDescriptor"), // tp_name + FULL_MODULE_NAME ".FieldDescriptor", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize 0, // tp_dealloc @@ -855,7 +855,7 @@ PyTypeObject PyFieldDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A Field Descriptor"), // tp_doc + "A Field Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -868,10 +868,10 @@ PyTypeObject PyFieldDescriptor_Type = { &descriptor::PyBaseDescriptor_Type, // tp_base }; -PyObject* PyFieldDescriptor_New( +PyObject* PyFieldDescriptor_FromDescriptor( const FieldDescriptor* field_descriptor) { return descriptor::NewInternedDescriptor( - &PyFieldDescriptor_Type, field_descriptor); + &PyFieldDescriptor_Type, field_descriptor, NULL); } const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj) { @@ -900,7 +900,7 @@ static PyObject* GetName(PyBaseDescriptor *self, void *closure) { } static PyObject* GetFile(PyBaseDescriptor *self, void *closure) { - return PyFileDescriptor_New(_GetDescriptor(self)->file()); + return PyFileDescriptor_FromDescriptor(_GetDescriptor(self)->file()); } static PyObject* GetEnumvaluesByName(PyBaseDescriptor* self, void *closure) { @@ -919,7 +919,7 @@ static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { const Descriptor* containing_type = _GetDescriptor(self)->containing_type(); if (containing_type) { - return PyMessageDescriptor_New(containing_type); + return PyMessageDescriptor_FromDescriptor(containing_type); } else { Py_RETURN_NONE; } @@ -964,16 +964,19 @@ static PyMethodDef Methods[] = { }; static PyGetSetDef Getters[] = { - { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, - { C("name"), (getter)GetName, NULL, "last name", NULL}, - { C("file"), (getter)GetFile, NULL, "File descriptor", NULL}, - { C("values"), (getter)GetEnumvaluesSeq, NULL, "values", NULL}, - { C("values_by_name"), (getter)GetEnumvaluesByName, NULL, "Enumvalues by name", NULL}, - { C("values_by_number"), (getter)GetEnumvaluesByNumber, NULL, "Enumvalues by number", NULL}, - - { C("containing_type"), (getter)GetContainingType, (setter)SetContainingType, "Containing type", NULL}, - { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL}, - { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL}, + { "full_name", (getter)GetFullName, NULL, "Full name"}, + { "name", (getter)GetName, NULL, "last name"}, + { "file", (getter)GetFile, NULL, "File descriptor"}, + { "values", (getter)GetEnumvaluesSeq, NULL, "values"}, + { "values_by_name", (getter)GetEnumvaluesByName, NULL, + "Enum values by name"}, + { "values_by_number", (getter)GetEnumvaluesByNumber, NULL, + "Enum values by number"}, + + { "containing_type", (getter)GetContainingType, (setter)SetContainingType, + "Containing type"}, + { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, + { "_options", (getter)NULL, (setter)SetOptions, "Options"}, {NULL} }; @@ -981,9 +984,7 @@ static PyGetSetDef Getters[] = { PyTypeObject PyEnumDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - C("google.protobuf.internal._message." - "EnumDescriptor"), // tp_name + FULL_MODULE_NAME ".EnumDescriptor", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize 0, // tp_dealloc @@ -1002,7 +1003,7 @@ PyTypeObject PyEnumDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A Enum Descriptor"), // tp_doc + "A Enum Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -1015,10 +1016,10 @@ PyTypeObject PyEnumDescriptor_Type = { &descriptor::PyBaseDescriptor_Type, // tp_base }; -PyObject* PyEnumDescriptor_New( +PyObject* PyEnumDescriptor_FromDescriptor( const EnumDescriptor* enum_descriptor) { return descriptor::NewInternedDescriptor( - &PyEnumDescriptor_Type, enum_descriptor); + &PyEnumDescriptor_Type, enum_descriptor, NULL); } namespace enumvalue_descriptor { @@ -1042,7 +1043,7 @@ static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) { } static PyObject* GetType(PyBaseDescriptor *self, void *closure) { - return PyEnumDescriptor_New(_GetDescriptor(self)->type()); + return PyEnumDescriptor_FromDescriptor(_GetDescriptor(self)->type()); } static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) { @@ -1069,13 +1070,13 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value, static PyGetSetDef Getters[] = { - { C("name"), (getter)GetName, NULL, "name", NULL}, - { C("number"), (getter)GetNumber, NULL, "number", NULL}, - { C("index"), (getter)GetIndex, NULL, "index", NULL}, - { C("type"), (getter)GetType, NULL, "index", NULL}, + { "name", (getter)GetName, NULL, "name"}, + { "number", (getter)GetNumber, NULL, "number"}, + { "index", (getter)GetIndex, NULL, "index"}, + { "type", (getter)GetType, NULL, "index"}, - { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL}, - { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL}, + { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, + { "_options", (getter)NULL, (setter)SetOptions, "Options"}, {NULL} }; @@ -1088,8 +1089,7 @@ static PyMethodDef Methods[] = { PyTypeObject PyEnumValueDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - C("google.protobuf.internal." - "_message.EnumValueDescriptor"), // tp_name + FULL_MODULE_NAME ".EnumValueDescriptor", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize 0, // tp_dealloc @@ -1108,7 +1108,7 @@ PyTypeObject PyEnumValueDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A EnumValue Descriptor"), // tp_doc + "A EnumValue Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -1121,10 +1121,10 @@ PyTypeObject PyEnumValueDescriptor_Type = { &descriptor::PyBaseDescriptor_Type, // tp_base }; -PyObject* PyEnumValueDescriptor_New( +PyObject* PyEnumValueDescriptor_FromDescriptor( const EnumValueDescriptor* enumvalue_descriptor) { return descriptor::NewInternedDescriptor( - &PyEnumValueDescriptor_Type, enumvalue_descriptor); + &PyEnumValueDescriptor_Type, enumvalue_descriptor, NULL); } namespace file_descriptor { @@ -1218,18 +1218,20 @@ static PyObject* CopyToProto(PyFileDescriptor *self, PyObject *target) { } static PyGetSetDef Getters[] = { - { C("name"), (getter)GetName, NULL, "name", NULL}, - { C("package"), (getter)GetPackage, NULL, "package", NULL}, - { C("serialized_pb"), (getter)GetSerializedPb, NULL, NULL, NULL}, - { C("message_types_by_name"), (getter)GetMessageTypesByName, NULL, "Messages by name", NULL}, - { C("enum_types_by_name"), (getter)GetEnumTypesByName, NULL, "Enums by name", NULL}, - { C("extensions_by_name"), (getter)GetExtensionsByName, NULL, "Extensions by name", NULL}, - { C("dependencies"), (getter)GetDependencies, NULL, "Dependencies", NULL}, - { C("public_dependencies"), (getter)GetPublicDependencies, NULL, "Dependencies", NULL}, - - { C("has_options"), (getter)GetHasOptions, (setter)SetHasOptions, "Has Options", NULL}, - { C("_options"), (getter)NULL, (setter)SetOptions, "Options", NULL}, - { C("syntax"), (getter)GetSyntax, (setter)NULL, "Syntax", NULL}, + { "name", (getter)GetName, NULL, "name"}, + { "package", (getter)GetPackage, NULL, "package"}, + { "serialized_pb", (getter)GetSerializedPb}, + { "message_types_by_name", (getter)GetMessageTypesByName, NULL, + "Messages by name"}, + { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"}, + { "extensions_by_name", (getter)GetExtensionsByName, NULL, + "Extensions by name"}, + { "dependencies", (getter)GetDependencies, NULL, "Dependencies"}, + { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"}, + + { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"}, + { "_options", (getter)NULL, (setter)SetOptions, "Options"}, + { "syntax", (getter)GetSyntax, (setter)NULL, "Syntax"}, {NULL} }; @@ -1243,11 +1245,10 @@ static PyMethodDef Methods[] = { PyTypeObject PyFileDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - C("google.protobuf.internal." - "_message.FileDescriptor"), // tp_name + FULL_MODULE_NAME ".FileDescriptor", // tp_name sizeof(PyFileDescriptor), // tp_basicsize 0, // tp_itemsize - (destructor)file_descriptor::Dealloc, // tp_dealloc + (destructor)file_descriptor::Dealloc, // tp_dealloc 0, // tp_print 0, // tp_getattr 0, // tp_setattr @@ -1263,7 +1264,7 @@ PyTypeObject PyFileDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A File Descriptor"), // tp_doc + "A File Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -1284,23 +1285,28 @@ PyTypeObject PyFileDescriptor_Type = { PyObject_Del, // tp_free }; -PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor) { - return descriptor::NewInternedDescriptor( - &PyFileDescriptor_Type, file_descriptor); +PyObject* PyFileDescriptor_FromDescriptor( + const FileDescriptor* file_descriptor) { + return PyFileDescriptor_FromDescriptorWithSerializedPb(file_descriptor, + NULL); } -PyObject* PyFileDescriptor_NewWithPb( +PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( const FileDescriptor* file_descriptor, PyObject *serialized_pb) { - PyObject* py_descriptor = PyFileDescriptor_New(file_descriptor); + bool was_created; + PyObject* py_descriptor = descriptor::NewInternedDescriptor( + &PyFileDescriptor_Type, file_descriptor, &was_created); if (py_descriptor == NULL) { return NULL; } - if (serialized_pb != NULL) { + if (was_created) { PyFileDescriptor* cfile_descriptor = reinterpret_cast(py_descriptor); Py_XINCREF(serialized_pb); cfile_descriptor->serialized_pb = serialized_pb; } + // TODO(amauryfa): In the case of a cached object, check that serialized_pb + // is the same as before. return py_descriptor; } @@ -1333,19 +1339,19 @@ static PyObject* GetContainingType(PyBaseDescriptor *self, void *closure) { const Descriptor* containing_type = _GetDescriptor(self)->containing_type(); if (containing_type) { - return PyMessageDescriptor_New(containing_type); + return PyMessageDescriptor_FromDescriptor(containing_type); } else { Py_RETURN_NONE; } } static PyGetSetDef Getters[] = { - { C("name"), (getter)GetName, NULL, "Name", NULL}, - { C("full_name"), (getter)GetFullName, NULL, "Full name", NULL}, - { C("index"), (getter)GetIndex, NULL, "Index", NULL}, + { "name", (getter)GetName, NULL, "Name"}, + { "full_name", (getter)GetFullName, NULL, "Full name"}, + { "index", (getter)GetIndex, NULL, "Index"}, - { C("containing_type"), (getter)GetContainingType, NULL, "Containing type", NULL}, - { C("fields"), (getter)GetFields, NULL, "Fields", NULL}, + { "containing_type", (getter)GetContainingType, NULL, "Containing type"}, + { "fields", (getter)GetFields, NULL, "Fields"}, {NULL} }; @@ -1353,8 +1359,7 @@ static PyGetSetDef Getters[] = { PyTypeObject PyOneofDescriptor_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - C("google.protobuf.internal." - "_message.OneofDescriptor"), // tp_name + FULL_MODULE_NAME ".OneofDescriptor", // tp_name sizeof(PyBaseDescriptor), // tp_basicsize 0, // tp_itemsize 0, // tp_dealloc @@ -1373,7 +1378,7 @@ PyTypeObject PyOneofDescriptor_Type = { 0, // tp_setattro 0, // tp_as_buffer Py_TPFLAGS_DEFAULT, // tp_flags - C("A Oneof Descriptor"), // tp_doc + "A Oneof Descriptor", // tp_doc 0, // tp_traverse 0, // tp_clear 0, // tp_richcompare @@ -1386,10 +1391,10 @@ PyTypeObject PyOneofDescriptor_Type = { &descriptor::PyBaseDescriptor_Type, // tp_base }; -PyObject* PyOneofDescriptor_New( +PyObject* PyOneofDescriptor_FromDescriptor( const OneofDescriptor* oneof_descriptor) { return descriptor::NewInternedDescriptor( - &PyOneofDescriptor_Type, oneof_descriptor); + &PyOneofDescriptor_Type, oneof_descriptor, NULL); } // Add a enum values to a type dictionary. diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h index ba6e72987c..b2550406c3 100644 --- a/python/google/protobuf/pyext/descriptor.h +++ b/python/google/protobuf/pyext/descriptor.h @@ -48,21 +48,24 @@ extern PyTypeObject PyEnumValueDescriptor_Type; extern PyTypeObject PyFileDescriptor_Type; extern PyTypeObject PyOneofDescriptor_Type; -// Return a new reference to a Descriptor object. +// Wraps a Descriptor in a Python object. // The C++ pointer is usually borrowed from the global DescriptorPool. // In any case, it must stay alive as long as the Python object. -PyObject* PyMessageDescriptor_New(const Descriptor* descriptor); -PyObject* PyFieldDescriptor_New(const FieldDescriptor* descriptor); -PyObject* PyEnumDescriptor_New(const EnumDescriptor* descriptor); -PyObject* PyEnumValueDescriptor_New(const EnumValueDescriptor* descriptor); -PyObject* PyOneofDescriptor_New(const OneofDescriptor* descriptor); -PyObject* PyFileDescriptor_New(const FileDescriptor* file_descriptor); +// Returns a new reference. +PyObject* PyMessageDescriptor_FromDescriptor(const Descriptor* descriptor); +PyObject* PyFieldDescriptor_FromDescriptor(const FieldDescriptor* descriptor); +PyObject* PyEnumDescriptor_FromDescriptor(const EnumDescriptor* descriptor); +PyObject* PyEnumValueDescriptor_FromDescriptor( + const EnumValueDescriptor* descriptor); +PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor); +PyObject* PyFileDescriptor_FromDescriptor( + const FileDescriptor* file_descriptor); // Alternate constructor of PyFileDescriptor, used when we already have a // serialized FileDescriptorProto that can be cached. // Returns a new reference. -PyObject* PyFileDescriptor_NewWithPb(const FileDescriptor* file_descriptor, - PyObject* serialized_pb); +PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb( + const FileDescriptor* file_descriptor, PyObject* serialized_pb); // Return the C++ descriptor pointer. // This function checks the parameter type; on error, return NULL with a Python diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc index 06edebf806..92e11e3122 100644 --- a/python/google/protobuf/pyext/descriptor_containers.cc +++ b/python/google/protobuf/pyext/descriptor_containers.cc @@ -898,7 +898,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFieldDescriptor_New(item); + return PyFieldDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -956,7 +956,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyMessageDescriptor_New(item); + return PyMessageDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1006,7 +1006,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyEnumDescriptor_New(item); + return PyEnumDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1082,7 +1082,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyEnumValueDescriptor_New(item); + return PyEnumValueDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1124,7 +1124,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFieldDescriptor_New(item); + return PyFieldDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1174,7 +1174,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyOneofDescriptor_New(item); + return PyOneofDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1238,7 +1238,7 @@ static ItemDescriptor GetByNumber(PyContainer* self, int number) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyEnumValueDescriptor_New(item); + return PyEnumValueDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1302,7 +1302,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFieldDescriptor_New(item); + return PyFieldDescriptor_FromDescriptor(item); } static int GetItemIndex(ItemDescriptor item) { @@ -1354,7 +1354,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyMessageDescriptor_New(item); + return PyMessageDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1400,7 +1400,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyEnumDescriptor_New(item); + return PyEnumDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1446,7 +1446,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFieldDescriptor_New(item); + return PyFieldDescriptor_FromDescriptor(item); } static const string& GetItemName(ItemDescriptor item) { @@ -1488,7 +1488,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFileDescriptor_New(item); + return PyFileDescriptor_FromDescriptor(item); } static DescriptorContainerDef ContainerDef = { @@ -1522,7 +1522,7 @@ static ItemDescriptor GetByIndex(PyContainer* self, int index) { } static PyObject* NewObjectFromItem(ItemDescriptor item) { - return PyFileDescriptor_New(item); + return PyFileDescriptor_FromDescriptor(item); } static DescriptorContainerDef ContainerDef = { diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h index d81537deca..8fbdaff9d3 100644 --- a/python/google/protobuf/pyext/descriptor_containers.h +++ b/python/google/protobuf/pyext/descriptor_containers.h @@ -28,6 +28,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ +#define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ + // Mappings and Sequences of descriptors. // They implement containers like fields_by_name, EnumDescriptor.values... // See descriptor_containers.cc for more description. @@ -92,4 +95,6 @@ PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor); } // namespace python } // namespace protobuf + } // namespace google +#endif // GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_CONTAINERS_H__ diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc index bc3077bc84..ecd9084720 100644 --- a/python/google/protobuf/pyext/descriptor_pool.cc +++ b/python/google/protobuf/pyext/descriptor_pool.cc @@ -35,10 +35,9 @@ #include #include #include +#include #include -#define C(str) const_cast(str) - #if PY_MAJOR_VERSION >= 3 #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #if PY_VERSION_HEX < 0x03030000 @@ -108,11 +107,11 @@ PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) { self->pool->FindMessageTypeByName(string(name, name_size)); if (message_descriptor == NULL) { - PyErr_Format(PyExc_TypeError, "Couldn't find message %.200s", name); + PyErr_Format(PyExc_KeyError, "Couldn't find message %.200s", name); return NULL; } - return PyMessageDescriptor_New(message_descriptor); + return PyMessageDescriptor_FromDescriptor(message_descriptor); } // Add a message class to our database. @@ -158,6 +157,24 @@ PyObject *GetMessageClass(PyDescriptorPool* self, } } +PyObject* FindFileByName(PyDescriptorPool* self, PyObject* arg) { + Py_ssize_t name_size; + char* name; + if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) { + return NULL; + } + + const FileDescriptor* file_descriptor = + self->pool->FindFileByName(string(name, name_size)); + if (file_descriptor == NULL) { + PyErr_Format(PyExc_KeyError, "Couldn't find file %.200s", + name); + return NULL; + } + + return PyFileDescriptor_FromDescriptor(file_descriptor); +} + PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) { Py_ssize_t name_size; char* name; @@ -168,12 +185,12 @@ PyObject* FindFieldByName(PyDescriptorPool* self, PyObject* arg) { const FieldDescriptor* field_descriptor = self->pool->FindFieldByName(string(name, name_size)); if (field_descriptor == NULL) { - PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", + PyErr_Format(PyExc_KeyError, "Couldn't find field %.200s", name); return NULL; } - return PyFieldDescriptor_New(field_descriptor); + return PyFieldDescriptor_FromDescriptor(field_descriptor); } PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) { @@ -186,11 +203,11 @@ PyObject* FindExtensionByName(PyDescriptorPool* self, PyObject* arg) { const FieldDescriptor* field_descriptor = self->pool->FindExtensionByName(string(name, name_size)); if (field_descriptor == NULL) { - PyErr_Format(PyExc_TypeError, "Couldn't find field %.200s", name); + PyErr_Format(PyExc_KeyError, "Couldn't find extension field %.200s", name); return NULL; } - return PyFieldDescriptor_New(field_descriptor); + return PyFieldDescriptor_FromDescriptor(field_descriptor); } PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) { @@ -203,11 +220,11 @@ PyObject* FindEnumTypeByName(PyDescriptorPool* self, PyObject* arg) { const EnumDescriptor* enum_descriptor = self->pool->FindEnumTypeByName(string(name, name_size)); if (enum_descriptor == NULL) { - PyErr_Format(PyExc_TypeError, "Couldn't find enum %.200s", name); + PyErr_Format(PyExc_KeyError, "Couldn't find enum %.200s", name); return NULL; } - return PyEnumDescriptor_New(enum_descriptor); + return PyEnumDescriptor_FromDescriptor(enum_descriptor); } PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) { @@ -220,70 +237,13 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) { const OneofDescriptor* oneof_descriptor = self->pool->FindOneofByName(string(name, name_size)); if (oneof_descriptor == NULL) { - PyErr_Format(PyExc_TypeError, "Couldn't find oneof %.200s", name); + PyErr_Format(PyExc_KeyError, "Couldn't find oneof %.200s", name); return NULL; } - return PyOneofDescriptor_New(oneof_descriptor); + return PyOneofDescriptor_FromDescriptor(oneof_descriptor); } -static PyMethodDef Methods[] = { - { C("FindFieldByName"), - (PyCFunction)FindFieldByName, - METH_O, - C("Searches for a field descriptor by full name.") }, - { C("FindExtensionByName"), - (PyCFunction)FindExtensionByName, - METH_O, - C("Searches for extension descriptor by full name.") }, - {NULL} -}; - -} // namespace cdescriptor_pool - -PyTypeObject PyDescriptorPool_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - C("google.protobuf.internal." - "_message.DescriptorPool"), // tp_name - sizeof(PyDescriptorPool), // tp_basicsize - 0, // tp_itemsize - (destructor)cdescriptor_pool::Dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - C("A Descriptor Pool"), // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - cdescriptor_pool::Methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - 0, // tp_alloc - 0, // tp_new - PyObject_Del, // tp_free -}; - // The code below loads new Descriptors from a serialized FileDescriptorProto. @@ -301,6 +261,7 @@ class BuildFileErrorCollector : public DescriptorPool::ErrorCollector { if (!had_errors) { error_message += ("Invalid proto descriptor for file \"" + filename + "\":\n"); + had_errors = true; } // As this only happens on failure and will result in the program not // running at all, no effort is made to optimize this string manipulation. @@ -311,7 +272,7 @@ class BuildFileErrorCollector : public DescriptorPool::ErrorCollector { bool had_errors; }; -PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) { +PyObject* AddSerializedFile(PyDescriptorPool* self, PyObject* serialized_pb) { char* message_type; Py_ssize_t message_len; @@ -330,13 +291,14 @@ PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) { const FileDescriptor* generated_file = DescriptorPool::generated_pool()->FindFileByName(file_proto.name()); if (generated_file != NULL) { - return PyFileDescriptor_NewWithPb(generated_file, serialized_pb); + return PyFileDescriptor_FromDescriptorWithSerializedPb( + generated_file, serialized_pb); } BuildFileErrorCollector error_collector; const FileDescriptor* descriptor = - GetDescriptorPool()->pool->BuildFileCollectingErrors(file_proto, - &error_collector); + self->pool->BuildFileCollectingErrors(file_proto, + &error_collector); if (descriptor == NULL) { PyErr_Format(PyExc_TypeError, "Couldn't build proto file into descriptor pool!\n%s", @@ -344,9 +306,84 @@ PyObject* Python_BuildFile(PyObject* ignored, PyObject* serialized_pb) { return NULL; } - return PyFileDescriptor_NewWithPb(descriptor, serialized_pb); + return PyFileDescriptor_FromDescriptorWithSerializedPb( + descriptor, serialized_pb); +} + +PyObject* Add(PyDescriptorPool* self, PyObject* file_descriptor_proto) { + ScopedPyObjectPtr serialized_pb( + PyObject_CallMethod(file_descriptor_proto, "SerializeToString", NULL)); + if (serialized_pb == NULL) { + return NULL; + } + return AddSerializedFile(self, serialized_pb); } +static PyMethodDef Methods[] = { + { "Add", (PyCFunction)Add, METH_O, + "Adds the FileDescriptorProto and its types to this pool." }, + { "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O, + "Adds a serialized FileDescriptorProto to this pool." }, + + { "FindFileByName", (PyCFunction)FindFileByName, METH_O, + "Searches for a file descriptor by its .proto name." }, + { "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O, + "Searches for a message descriptor by full name." }, + { "FindFieldByName", (PyCFunction)FindFieldByName, METH_O, + "Searches for a field descriptor by full name." }, + { "FindExtensionByName", (PyCFunction)FindExtensionByName, METH_O, + "Searches for extension descriptor by full name." }, + { "FindEnumTypeByName", (PyCFunction)FindEnumTypeByName, METH_O, + "Searches for enum type descriptor by full name." }, + { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O, + "Searches for oneof descriptor by full name." }, + {NULL} +}; + +} // namespace cdescriptor_pool + +PyTypeObject PyDescriptorPool_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".DescriptorPool", // tp_name + sizeof(PyDescriptorPool), // tp_basicsize + 0, // tp_itemsize + (destructor)cdescriptor_pool::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "A Descriptor Pool", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + cdescriptor_pool::Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + 0, // tp_new + PyObject_Del, // tp_free +}; + static PyDescriptorPool* global_cdescriptor_pool = NULL; bool InitDescriptorPool() { diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h index 4e494b8941..efb1abeb0e 100644 --- a/python/google/protobuf/pyext/descriptor_pool.h +++ b/python/google/protobuf/pyext/descriptor_pool.h @@ -95,6 +95,8 @@ const Descriptor* FindMessageTypeByName(PyDescriptorPool* self, const Descriptor* RegisterMessageClass( PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor); +// The function below are also exposed as methods of the DescriptorPool type. + // Retrieves the Python class registered with the given message descriptor. // // Returns a *borrowed* reference if found, otherwise returns NULL with an @@ -134,12 +136,8 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg); } // namespace cdescriptor_pool -// Implement the Python "_BuildFile" method, it takes a serialized -// FileDescriptorProto, and adds it to the C++ DescriptorPool. -// It returns a new FileDescriptor object, or NULL when an exception is raised. -PyObject* Python_BuildFile(PyObject* ignored, PyObject* args); - // Retrieve the global descriptor pool owned by the _message module. +// Returns a *borrowed* reference. PyDescriptorPool* GetDescriptorPool(); // Initialize objects used by this module. diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc index 8e38fc42f7..b8d18f8d92 100644 --- a/python/google/protobuf/pyext/extension_dict.cc +++ b/python/google/protobuf/pyext/extension_dict.cc @@ -51,16 +51,6 @@ namespace python { namespace extension_dict { -// TODO(tibell): Always use self->message for clarity, just like in -// RepeatedCompositeContainer. -static Message* GetMessage(ExtensionDict* self) { - if (self->parent != NULL) { - return self->parent->message; - } else { - return self->message; - } -} - PyObject* len(ExtensionDict* self) { #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(PyDict_Size(self->values)); @@ -89,7 +79,7 @@ int ReleaseExtension(ExtensionDict* self, } } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (cmessage::ReleaseSubMessage( - GetMessage(self), descriptor, + self->parent, descriptor, reinterpret_cast(extension)) < 0) { return -1; } @@ -109,7 +99,7 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { if (descriptor->label() != FieldDescriptor::LABEL_REPEATED && descriptor->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { - return cmessage::InternalGetScalar(self->parent, descriptor); + return cmessage::InternalGetScalar(self->parent->message, descriptor); } PyObject* value = PyDict_GetItem(self->values, key); @@ -266,8 +256,7 @@ static PyMethodDef Methods[] = { PyTypeObject ExtensionDict_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "google.protobuf.internal." - "cpp._message.ExtensionDict", // tp_name + FULL_MODULE_NAME ".ExtensionDict", // tp_name sizeof(ExtensionDict), // tp_basicsize 0, // tp_itemsize (destructor)extension_dict::dealloc, // tp_dealloc diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index a2b357b25c..a4843e8d3d 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -59,6 +59,8 @@ #include #include #include +#include +#include #include #include @@ -93,9 +95,9 @@ static const FieldDescriptor* GetFieldDescriptor( static const Descriptor* GetMessageDescriptor(PyTypeObject* cls); static string GetMessageName(CMessage* self); int InternalReleaseFieldByDescriptor( + CMessage* self, const FieldDescriptor* field_descriptor, - PyObject* composite_field, - Message* parent_message); + PyObject* composite_field); } // namespace cmessage // --------------------------------------------------------------------- @@ -127,10 +129,29 @@ static int VisitCompositeField(const FieldDescriptor* descriptor, Visitor visitor) { if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - RepeatedCompositeContainer* container = - reinterpret_cast(child); - if (visitor.VisitRepeatedCompositeContainer(container) == -1) - return -1; + if (descriptor->is_map()) { + const Descriptor* entry_type = descriptor->message_type(); + const FieldDescriptor* value_type = + entry_type->FindFieldByName("value"); + if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + MessageMapContainer* container = + reinterpret_cast(child); + if (visitor.VisitMessageMapContainer(container) == -1) { + return -1; + } + } else { + ScalarMapContainer* container = + reinterpret_cast(child); + if (visitor.VisitScalarMapContainer(container) == -1) { + return -1; + } + } + } else { + RepeatedCompositeContainer* container = + reinterpret_cast(child); + if (visitor.VisitRepeatedCompositeContainer(container) == -1) + return -1; + } } else { RepeatedScalarContainer* container = reinterpret_cast(child); @@ -444,7 +465,7 @@ static int MaybeReleaseOverlappingOneofField( } if (InternalReleaseFieldByDescriptor( - existing_field, child_message, message) < 0) { + cmessage, existing_field, child_message) < 0) { return -1; } return PyDict_DelItemString(cmessage->composite_fields, field_name); @@ -483,6 +504,16 @@ struct FixupMessageReference : public ChildVisitor { return 0; } + int VisitScalarMapContainer(ScalarMapContainer* container) { + container->message = message_; + return 0; + } + + int VisitMessageMapContainer(MessageMapContainer* container) { + container->message = message_; + return 0; + } + private: Message* message_; }; @@ -500,6 +531,9 @@ int AssureWritable(CMessage* self) { self->message->GetDescriptor()); self->message = prototype->New(); self->owner.reset(self->message); + // Cascade the new owner to eventual children: even if this message is + // empty, some submessages or repeated containers might exist already. + SetOwner(self, self->owner); } else { // Otherwise, we need a mutable child message. if (AssureWritable(self->parent) == -1) @@ -520,8 +554,9 @@ int AssureWritable(CMessage* self) { // When a CMessage is made writable its Message pointer is updated // to point to a new mutable Message. When that happens we need to // update any references to the old, read-only CMessage. There are - // three places such references occur: RepeatedScalarContainer, - // RepeatedCompositeContainer, and ExtensionDict. + // five places such references occur: RepeatedScalarContainer, + // RepeatedCompositeContainer, ScalarMapContainer, MessageMapContainer, + // and ExtensionDict. if (self->extensions != NULL) self->extensions->message = self->message; if (ForEachCompositeField(self, FixupMessageReference(self->message)) == -1) @@ -583,15 +618,43 @@ const FieldDescriptor* GetExtensionDescriptor(PyObject* extension) { return PyFieldDescriptor_AsDescriptor(extension); } +// If value is a string, convert it into an enum value based on the labels in +// descriptor, otherwise simply return value. Always returns a new reference. +static PyObject* GetIntegerEnumValue(const FieldDescriptor& descriptor, + PyObject* value) { + if (PyString_Check(value) || PyUnicode_Check(value)) { + const EnumDescriptor* enum_descriptor = descriptor.enum_type(); + if (enum_descriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "not an enum field"); + return NULL; + } + char* enum_label; + Py_ssize_t size; + if (PyString_AsStringAndSize(value, &enum_label, &size) < 0) { + return NULL; + } + const EnumValueDescriptor* enum_value_descriptor = + enum_descriptor->FindValueByName(string(enum_label, size)); + if (enum_value_descriptor == NULL) { + PyErr_SetString(PyExc_ValueError, "unknown enum label"); + return NULL; + } + return PyInt_FromLong(enum_value_descriptor->number()); + } + Py_INCREF(value); + return value; +} + // If cmessage_list is not NULL, this function releases values into the // container CMessages instead of just removing. Repeated composite container // needs to do this to make sure CMessages stay alive if they're still // referenced after deletion. Repeated scalar container doesn't need to worry. int InternalDeleteRepeatedField( - Message* message, + CMessage* self, const FieldDescriptor* field_descriptor, PyObject* slice, PyObject* cmessage_list) { + Message* message = self->message; Py_ssize_t length, from, to, step, slice_length; const Reflection* reflection = message->GetReflection(); int min, max; @@ -665,7 +728,7 @@ int InternalDeleteRepeatedField( CMessage* last_cmessage = reinterpret_cast( PyList_GET_ITEM(cmessage_list, PyList_GET_SIZE(cmessage_list) - 1)); repeated_composite_container::ReleaseLastTo( - field_descriptor, message, last_cmessage); + self, field_descriptor, last_cmessage); if (PySequence_DelItem(cmessage_list, -1) < 0) { return -1; } @@ -696,16 +759,90 @@ int InitAttributes(CMessage* self, PyObject* kwargs) { PyString_AsString(name)); return -1; } - if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { + if (descriptor->is_map()) { + ScopedPyObjectPtr map(GetAttr(self, name)); + const FieldDescriptor* value_descriptor = + descriptor->message_type()->FindFieldByName("value"); + if (value_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + Py_ssize_t map_pos = 0; + PyObject* map_key; + PyObject* map_value; + while (PyDict_Next(value, &map_pos, &map_key, &map_value)) { + ScopedPyObjectPtr function_return; + function_return.reset(PyObject_GetItem(map.get(), map_key)); + if (function_return.get() == NULL) { + return -1; + } + ScopedPyObjectPtr ok(PyObject_CallMethod( + function_return.get(), "MergeFrom", "O", map_value)); + if (ok.get() == NULL) { + return -1; + } + } + } else { + ScopedPyObjectPtr function_return; + function_return.reset( + PyObject_CallMethod(map.get(), "update", "O", value)); + if (function_return.get() == NULL) { + return -1; + } + } + } else if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { ScopedPyObjectPtr container(GetAttr(self, name)); if (container == NULL) { return -1; } if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (repeated_composite_container::Extend( - reinterpret_cast(container.get()), - value) - == NULL) { + RepeatedCompositeContainer* rc_container = + reinterpret_cast(container.get()); + ScopedPyObjectPtr iter(PyObject_GetIter(value)); + if (iter == NULL) { + PyErr_SetString(PyExc_TypeError, "Value must be iterable"); + return -1; + } + ScopedPyObjectPtr next; + while ((next.reset(PyIter_Next(iter))) != NULL) { + PyObject* kwargs = (PyDict_Check(next) ? next.get() : NULL); + ScopedPyObjectPtr new_msg( + repeated_composite_container::Add(rc_container, NULL, kwargs)); + if (new_msg == NULL) { + return -1; + } + if (kwargs == NULL) { + // next was not a dict, it's a message we need to merge + ScopedPyObjectPtr merged( + MergeFrom(reinterpret_cast(new_msg.get()), next)); + if (merged == NULL) { + return -1; + } + } + } + if (PyErr_Occurred()) { + // Check to see how PyIter_Next() exited. + return -1; + } + } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + RepeatedScalarContainer* rs_container = + reinterpret_cast(container.get()); + ScopedPyObjectPtr iter(PyObject_GetIter(value)); + if (iter == NULL) { + PyErr_SetString(PyExc_TypeError, "Value must be iterable"); + return -1; + } + ScopedPyObjectPtr next; + while ((next.reset(PyIter_Next(iter))) != NULL) { + ScopedPyObjectPtr enum_value(GetIntegerEnumValue(*descriptor, next)); + if (enum_value == NULL) { + return -1; + } + ScopedPyObjectPtr new_msg( + repeated_scalar_container::Append(rs_container, enum_value)); + if (new_msg == NULL) { + return -1; + } + } + if (PyErr_Occurred()) { + // Check to see how PyIter_Next() exited. return -1; } } else { @@ -721,12 +858,26 @@ int InitAttributes(CMessage* self, PyObject* kwargs) { if (message == NULL) { return -1; } - if (MergeFrom(reinterpret_cast(message.get()), - value) == NULL) { - return -1; + CMessage* cmessage = reinterpret_cast(message.get()); + if (PyDict_Check(value)) { + if (InitAttributes(cmessage, value) < 0) { + return -1; + } + } else { + ScopedPyObjectPtr merged(MergeFrom(cmessage, value)); + if (merged == NULL) { + return -1; + } } } else { - if (SetAttr(self, name, value) < 0) { + ScopedPyObjectPtr new_val; + if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + new_val.reset(GetIntegerEnumValue(*descriptor, value)); + if (new_val == NULL) { + return -1; + } + } + if (SetAttr(self, name, (new_val == NULL) ? value : new_val) < 0) { return -1; } } @@ -789,7 +940,6 @@ static PyObject* New(PyTypeObject* type, } self->message = default_message->New(); self->owner.reset(self->message); - return reinterpret_cast(self); } @@ -830,6 +980,16 @@ struct ClearWeakReferences : public ChildVisitor { return 0; } + int VisitScalarMapContainer(ScalarMapContainer* container) { + container->parent = NULL; + return 0; + } + + int VisitMessageMapContainer(MessageMapContainer* container) { + container->parent = NULL; + return 0; + } + int VisitCMessage(CMessage* cmessage, const FieldDescriptor* field_descriptor) { cmessage->parent = NULL; @@ -1064,6 +1224,16 @@ struct SetOwnerVisitor : public ChildVisitor { return 0; } + int VisitScalarMapContainer(ScalarMapContainer* container) { + scalar_map_container::SetOwner(container, new_owner_); + return 0; + } + + int VisitMessageMapContainer(MessageMapContainer* container) { + message_map_container::SetOwner(container, new_owner_); + return 0; + } + int VisitCMessage(CMessage* cmessage, const FieldDescriptor* field_descriptor) { return SetOwner(cmessage, new_owner_); @@ -1084,11 +1254,11 @@ int SetOwner(CMessage* self, const shared_ptr& new_owner) { // Releases the message specified by 'field' and returns the // pointer. If the field does not exist a new message is created using // 'descriptor'. The caller takes ownership of the returned pointer. -Message* ReleaseMessage(Message* message, +Message* ReleaseMessage(CMessage* self, const Descriptor* descriptor, const FieldDescriptor* field_descriptor) { - Message* released_message = message->GetReflection()->ReleaseMessage( - message, field_descriptor, message_factory); + Message* released_message = self->message->GetReflection()->ReleaseMessage( + self->message, field_descriptor, message_factory); // ReleaseMessage will return NULL which differs from // child_cmessage->message, if the field does not exist. In this case, // the latter points to the default instance via a const_cast<>, so we @@ -1102,12 +1272,12 @@ Message* ReleaseMessage(Message* message, return released_message; } -int ReleaseSubMessage(Message* message, +int ReleaseSubMessage(CMessage* self, const FieldDescriptor* field_descriptor, CMessage* child_cmessage) { // Release the Message shared_ptr released_message(ReleaseMessage( - message, child_cmessage->message->GetDescriptor(), field_descriptor)); + self, child_cmessage->message->GetDescriptor(), field_descriptor)); child_cmessage->message = released_message.get(); child_cmessage->owner.swap(released_message); child_cmessage->parent = NULL; @@ -1119,8 +1289,8 @@ int ReleaseSubMessage(Message* message, struct ReleaseChild : public ChildVisitor { // message must outlive this object. - explicit ReleaseChild(Message* parent_message) : - parent_message_(parent_message) {} + explicit ReleaseChild(CMessage* parent) : + parent_(parent) {} int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) { return repeated_composite_container::Release( @@ -1132,23 +1302,33 @@ struct ReleaseChild : public ChildVisitor { reinterpret_cast(container)); } + int VisitScalarMapContainer(ScalarMapContainer* container) { + return scalar_map_container::Release( + reinterpret_cast(container)); + } + + int VisitMessageMapContainer(MessageMapContainer* container) { + return message_map_container::Release( + reinterpret_cast(container)); + } + int VisitCMessage(CMessage* cmessage, const FieldDescriptor* field_descriptor) { - return ReleaseSubMessage(parent_message_, field_descriptor, + return ReleaseSubMessage(parent_, field_descriptor, reinterpret_cast(cmessage)); } - Message* parent_message_; + CMessage* parent_; }; int InternalReleaseFieldByDescriptor( + CMessage* self, const FieldDescriptor* field_descriptor, - PyObject* composite_field, - Message* parent_message) { + PyObject* composite_field) { return VisitCompositeField( field_descriptor, composite_field, - ReleaseChild(parent_message)); + ReleaseChild(self)); } PyObject* ClearFieldByDescriptor( @@ -1200,8 +1380,8 @@ PyObject* ClearField(CMessage* self, PyObject* arg) { // Only release the field if there's a possibility that there are // references to it. if (composite_field != NULL) { - if (InternalReleaseFieldByDescriptor(field_descriptor, - composite_field, message) < 0) { + if (InternalReleaseFieldByDescriptor(self, field_descriptor, + composite_field) < 0) { return NULL; } PyDict_DelItem(self->composite_fields, arg); @@ -1219,7 +1399,7 @@ PyObject* ClearField(CMessage* self, PyObject* arg) { PyObject* Clear(CMessage* self) { AssureWritable(self); - if (ForEachCompositeField(self, ReleaseChild(self->message)) == -1) + if (ForEachCompositeField(self, ReleaseChild(self)) == -1) return NULL; // The old ExtensionDict still aliases this CMessage, but all its @@ -1582,7 +1762,8 @@ static PyObject* ListFields(CMessage* self) { } if (fields[i]->is_extension()) { - ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(fields[i])); + ScopedPyObjectPtr extension_field( + PyFieldDescriptor_FromDescriptor(fields[i])); if (extension_field == NULL) { return NULL; } @@ -1616,7 +1797,8 @@ static PyObject* ListFields(CMessage* self) { PyErr_SetString(PyExc_ValueError, "bad string"); return NULL; } - ScopedPyObjectPtr field_descriptor(PyFieldDescriptor_New(fields[i])); + ScopedPyObjectPtr field_descriptor( + PyFieldDescriptor_FromDescriptor(fields[i])); if (field_descriptor == NULL) { return NULL; } @@ -1683,10 +1865,8 @@ static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) { } } -PyObject* InternalGetScalar( - CMessage* self, - const FieldDescriptor* field_descriptor) { - Message* message = self->message; +PyObject* InternalGetScalar(const Message* message, + const FieldDescriptor* field_descriptor) { const Reflection* reflection = message->GetReflection(); if (!CheckFieldBelongsToMessage(field_descriptor, message)) { @@ -1739,12 +1919,12 @@ PyObject* InternalGetScalar( if (!message->GetReflection()->SupportsUnknownEnumValues() && !message->GetReflection()->HasField(*message, field_descriptor)) { // Look for the value in the unknown fields. - UnknownFieldSet* unknown_field_set = - message->GetReflection()->MutableUnknownFields(message); - for (int i = 0; i < unknown_field_set->field_count(); ++i) { - if (unknown_field_set->field(i).number() == + const UnknownFieldSet& unknown_field_set = + message->GetReflection()->GetUnknownFields(*message); + for (int i = 0; i < unknown_field_set.field_count(); ++i) { + if (unknown_field_set.field(i).number() == field_descriptor->number()) { - result = PyInt_FromLong(unknown_field_set->field(i).varint()); + result = PyInt_FromLong(unknown_field_set.field(i).varint()); break; } } @@ -1793,21 +1973,16 @@ PyObject* InternalGetSubMessage( return reinterpret_cast(cmsg); } -int InternalSetScalar( - CMessage* self, +int InternalSetNonOneofScalar( + Message* message, const FieldDescriptor* field_descriptor, PyObject* arg) { - Message* message = self->message; const Reflection* reflection = message->GetReflection(); if (!CheckFieldBelongsToMessage(field_descriptor, message)) { return -1; } - if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) { - return -1; - } - switch (field_descriptor->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: { GOOGLE_CHECK_GET_INT32(arg, value, -1); @@ -1878,6 +2053,21 @@ int InternalSetScalar( return 0; } +int InternalSetScalar( + CMessage* self, + const FieldDescriptor* field_descriptor, + PyObject* arg) { + if (!CheckFieldBelongsToMessage(field_descriptor, self->message)) { + return -1; + } + + if (MaybeReleaseOverlappingOneofField(self, field_descriptor) < 0) { + return -1; + } + + return InternalSetNonOneofScalar(self->message, field_descriptor, arg); +} + PyObject* FromString(PyTypeObject* cls, PyObject* serialized) { PyObject* py_cmsg = PyObject_CallObject( reinterpret_cast(cls), NULL); @@ -1955,7 +2145,8 @@ static PyObject* AddDescriptors(PyObject* cls, PyObject* descriptor) { // which was built previously. for (int i = 0; i < message_descriptor->enum_type_count(); ++i) { const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i); - ScopedPyObjectPtr enum_type(PyEnumDescriptor_New(enum_descriptor)); + ScopedPyObjectPtr enum_type( + PyEnumDescriptor_FromDescriptor(enum_descriptor)); if (enum_type == NULL) { return NULL; } @@ -1993,7 +2184,7 @@ static PyObject* AddDescriptors(PyObject* cls, PyObject* descriptor) { // which was defined previously. for (int i = 0; i < message_descriptor->extension_count(); ++i) { const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i); - ScopedPyObjectPtr extension_field(PyFieldDescriptor_New(field)); + ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); if (extension_field == NULL) { return NULL; } @@ -2097,26 +2288,6 @@ PyObject* SetState(CMessage* self, PyObject* state) { } // CMessage static methods: -PyObject* _GetMessageDescriptor(PyObject* unused, PyObject* arg) { - return cdescriptor_pool::FindMessageByName(GetDescriptorPool(), arg); -} - -PyObject* _GetFieldDescriptor(PyObject* unused, PyObject* arg) { - return cdescriptor_pool::FindFieldByName(GetDescriptorPool(), arg); -} - -PyObject* _GetExtensionDescriptor(PyObject* unused, PyObject* arg) { - return cdescriptor_pool::FindExtensionByName(GetDescriptorPool(), arg); -} - -PyObject* _GetEnumDescriptor(PyObject* unused, PyObject* arg) { - return cdescriptor_pool::FindEnumTypeByName(GetDescriptorPool(), arg); -} - -PyObject* _GetOneofDescriptor(PyObject* unused, PyObject* arg) { - return cdescriptor_pool::FindOneofByName(GetDescriptorPool(), arg); -} - PyObject* _CheckCalledFromGeneratedFile(PyObject* unused, PyObject* unused_arg) { if (!_CalledFromGeneratedFile(1)) { @@ -2188,21 +2359,6 @@ static PyMethodDef Methods[] = { "or None if no field is set." }, // Static Methods. - { "_BuildFile", (PyCFunction)Python_BuildFile, METH_O | METH_STATIC, - "Registers a new protocol buffer file in the global C++ descriptor pool." }, - { "_GetMessageDescriptor", (PyCFunction)_GetMessageDescriptor, - METH_O | METH_STATIC, "Finds a message descriptor in the message pool." }, - { "_GetFieldDescriptor", (PyCFunction)_GetFieldDescriptor, - METH_O | METH_STATIC, "Finds a field descriptor in the message pool." }, - { "_GetExtensionDescriptor", (PyCFunction)_GetExtensionDescriptor, - METH_O | METH_STATIC, - "Finds a extension descriptor in the message pool." }, - { "_GetEnumDescriptor", (PyCFunction)_GetEnumDescriptor, - METH_O | METH_STATIC, - "Finds an enum descriptor in the message pool." }, - { "_GetOneofDescriptor", (PyCFunction)_GetOneofDescriptor, - METH_O | METH_STATIC, - "Finds an oneof descriptor in the message pool." }, { "_CheckCalledFromGeneratedFile", (PyCFunction)_CheckCalledFromGeneratedFile, METH_NOARGS | METH_STATIC, "Raises TypeError if the caller is not in a _pb2.py file."}, @@ -2234,6 +2390,31 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { reinterpret_cast(self), name); } + if (field_descriptor->is_map()) { + PyObject* py_container = NULL; + const Descriptor* entry_type = field_descriptor->message_type(); + const FieldDescriptor* value_type = entry_type->FindFieldByName("value"); + if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + PyObject* value_class = cdescriptor_pool::GetMessageClass( + GetDescriptorPool(), value_type->message_type()); + if (value_class == NULL) { + return NULL; + } + py_container = message_map_container::NewContainer(self, field_descriptor, + value_class); + } else { + py_container = scalar_map_container::NewContainer(self, field_descriptor); + } + if (py_container == NULL) { + return NULL; + } + if (!SetCompositeField(self, name, py_container)) { + Py_DECREF(py_container); + return NULL; + } + return py_container; + } + if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { PyObject* py_container = NULL; if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { @@ -2267,7 +2448,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { return sub_message; } - return InternalGetScalar(self, field_descriptor); + return InternalGetScalar(self->message, field_descriptor); } int SetAttr(CMessage* self, PyObject* name, PyObject* value) { @@ -2304,9 +2485,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { PyTypeObject CMessage_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - "google.protobuf.pyext._message." - "CMessage", // tp_name + FULL_MODULE_NAME ".CMessage", // tp_name sizeof(CMessage), // tp_basicsize 0, // tp_itemsize (destructor)cmessage::Dealloc, // tp_dealloc @@ -2401,7 +2580,7 @@ void InitGlobals() { k_extensions_by_name = PyString_FromString("_extensions_by_name"); k_extensions_by_number = PyString_FromString("_extensions_by_number"); - message_factory = new DynamicMessageFactory(GetDescriptorPool()->pool); + message_factory = new DynamicMessageFactory(); message_factory->SetDelegateToGeneratedFactory(true); } @@ -2469,6 +2648,61 @@ bool InitProto2MessageModule(PyObject *m) { reinterpret_cast( &RepeatedCompositeContainer_Type)); + // ScalarMapContainer_Type derives from our MutableMapping type. + PyObject* containers = + PyImport_ImportModule("google.protobuf.internal.containers"); + if (containers == NULL) { + return false; + } + + PyObject* mutable_mapping = + PyObject_GetAttrString(containers, "MutableMapping"); + Py_DECREF(containers); + + if (mutable_mapping == NULL) { + return false; + } + + if (!PyObject_TypeCheck(mutable_mapping, &PyType_Type)) { + Py_DECREF(mutable_mapping); + return false; + } + + ScalarMapContainer_Type.tp_base = + reinterpret_cast(mutable_mapping); + + if (PyType_Ready(&ScalarMapContainer_Type) < 0) { + return false; + } + + PyModule_AddObject(m, "ScalarMapContainer", + reinterpret_cast(&ScalarMapContainer_Type)); + + if (PyType_Ready(&ScalarMapIterator_Type) < 0) { + return false; + } + + PyModule_AddObject(m, "ScalarMapIterator", + reinterpret_cast(&ScalarMapIterator_Type)); + + Py_INCREF(mutable_mapping); + MessageMapContainer_Type.tp_base = + reinterpret_cast(mutable_mapping); + + if (PyType_Ready(&MessageMapContainer_Type) < 0) { + return false; + } + + PyModule_AddObject(m, "MessageMapContainer", + reinterpret_cast(&MessageMapContainer_Type)); + + if (PyType_Ready(&MessageMapIterator_Type) < 0) { + return false; + } + + PyModule_AddObject(m, "MessageMapIterator", + reinterpret_cast(&MessageMapIterator_Type)); + ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&ExtensionDict_Type) < 0) { return false; @@ -2478,6 +2712,12 @@ bool InitProto2MessageModule(PyObject *m) { m, "ExtensionDict", reinterpret_cast(&ExtensionDict_Type)); + // Expose the DescriptorPool used to hold all descriptors added from generated + // pb2.py files. + Py_INCREF(GetDescriptorPool()); // PyModule_AddObject steals a reference. + PyModule_AddObject( + m, "default_pool", reinterpret_cast(GetDescriptorPool())); + // This implementation provides full Descriptor types, we advertise it so that // descriptor.py can use them in replacement of the Python classes. PyModule_AddIntConstant(m, "_USE_C_DESCRIPTORS", 1); diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index 2f2da79517..7360b20774 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -120,7 +120,7 @@ CMessage* NewEmptyMessage(PyObject* type, const Descriptor* descriptor); // A new message will be created if this is a read-only default instance. // // Corresponds to reflection api method ReleaseMessage. -int ReleaseSubMessage(Message* message, +int ReleaseSubMessage(CMessage* self, const FieldDescriptor* field_descriptor, CMessage* child_cmessage); @@ -144,7 +144,7 @@ PyObject* InternalGetSubMessage( // by slice will be removed from cmessage_list by this function. // // Corresponds to reflection api method RemoveLast. -int InternalDeleteRepeatedField(Message* message, +int InternalDeleteRepeatedField(CMessage* self, const FieldDescriptor* field_descriptor, PyObject* slice, PyObject* cmessage_list); @@ -153,10 +153,15 @@ int InternalSetScalar(CMessage* self, const FieldDescriptor* field_descriptor, PyObject* value); +// Sets the specified scalar value to the message. Requires it is not a Oneof. +int InternalSetNonOneofScalar(Message* message, + const FieldDescriptor* field_descriptor, + PyObject* arg); + // Retrieves the specified scalar value from the message. // // Returns a new python reference. -PyObject* InternalGetScalar(CMessage* self, +PyObject* InternalGetScalar(const Message* message, const FieldDescriptor* field_descriptor); // Clears the message, removing all contained data. Extension dictionary and @@ -279,7 +284,7 @@ extern PyObject* kint64min_py; extern PyObject* kint64max_py; extern PyObject* kuint64max_py; -#define C(str) const_cast(str) +#define FULL_MODULE_NAME "google.protobuf.pyext._message" void FormatTypeError(PyObject* arg, char* expected_types); template diff --git a/python/google/protobuf/pyext/message_map_container.cc b/python/google/protobuf/pyext/message_map_container.cc new file mode 100644 index 0000000000..ab8d8fb9f0 --- /dev/null +++ b/python/google/protobuf/pyext/message_map_container.cc @@ -0,0 +1,540 @@ +// 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. + +// Author: haberman@google.com (Josh Haberman) + +#include + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace python { + +struct MessageMapIterator { + PyObject_HEAD; + + // This dict contains the full contents of what we want to iterate over. + // There's no way to avoid building this, because the list representation + // (which is canonical) can contain duplicate keys. So at the very least we + // need a set that lets us skip duplicate keys. And at the point that we're + // doing that, we might as well just build the actual dict we're iterating + // over and use dict's built-in iterator. + PyObject* dict; + + // An iterator on dict. + PyObject* iter; + + // A pointer back to the container, so we can notice changes to the version. + MessageMapContainer* container; + + // The version of the map when we took the iterator to it. + // + // We store this so that if the map is modified during iteration we can throw + // an error. + uint64 version; +}; + +static MessageMapIterator* GetIter(PyObject* obj) { + return reinterpret_cast(obj); +} + +namespace message_map_container { + +static MessageMapContainer* GetMap(PyObject* obj) { + return reinterpret_cast(obj); +} + +// The private constructor of MessageMapContainer objects. +PyObject* NewContainer(CMessage* parent, + const google::protobuf::FieldDescriptor* parent_field_descriptor, + PyObject* concrete_class) { + if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { + return NULL; + } + + PyObject* obj = PyType_GenericAlloc(&MessageMapContainer_Type, 0); + if (obj == NULL) { + return PyErr_Format(PyExc_RuntimeError, + "Could not allocate new container."); + } + + MessageMapContainer* self = GetMap(obj); + + self->message = parent->message; + self->parent = parent; + self->parent_field_descriptor = parent_field_descriptor; + self->owner = parent->owner; + self->version = 0; + + self->key_field_descriptor = + parent_field_descriptor->message_type()->FindFieldByName("key"); + self->value_field_descriptor = + parent_field_descriptor->message_type()->FindFieldByName("value"); + + self->message_dict = PyDict_New(); + if (self->message_dict == NULL) { + return PyErr_Format(PyExc_RuntimeError, + "Could not allocate message dict."); + } + + Py_INCREF(concrete_class); + self->subclass_init = concrete_class; + + if (self->key_field_descriptor == NULL || + self->value_field_descriptor == NULL) { + Py_DECREF(obj); + return PyErr_Format(PyExc_KeyError, + "Map entry descriptor did not have key/value fields"); + } + + return obj; +} + +// Initializes the underlying Message object of "to" so it becomes a new parent +// repeated scalar, and copies all the values from "from" to it. A child scalar +// container can be released by passing it as both from and to (e.g. making it +// the recipient of the new parent message and copying the values from itself). +static int InitializeAndCopyToParentContainer( + MessageMapContainer* from, + MessageMapContainer* to) { + // For now we require from == to, re-evaluate if we want to support deep copy + // as in repeated_composite_container.cc. + GOOGLE_DCHECK(from == to); + Message* old_message = from->message; + Message* new_message = old_message->New(); + to->parent = NULL; + to->parent_field_descriptor = from->parent_field_descriptor; + to->message = new_message; + to->owner.reset(new_message); + + vector fields; + fields.push_back(from->parent_field_descriptor); + old_message->GetReflection()->SwapFields(old_message, new_message, fields); + return 0; +} + +static PyObject* GetCMessage(MessageMapContainer* self, Message* entry) { + // Get or create the CMessage object corresponding to this message. + Message* message = entry->GetReflection()->MutableMessage( + entry, self->value_field_descriptor); + ScopedPyObjectPtr key(PyLong_FromVoidPtr(message)); + PyObject* ret = PyDict_GetItem(self->message_dict, key); + + if (ret == NULL) { + CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, + message->GetDescriptor()); + ret = reinterpret_cast(cmsg); + + if (cmsg == NULL) { + return NULL; + } + cmsg->owner = self->owner; + cmsg->message = message; + cmsg->parent = self->parent; + + if (PyDict_SetItem(self->message_dict, key, ret) < 0) { + Py_DECREF(ret); + return NULL; + } + } else { + Py_INCREF(ret); + } + + return ret; +} + +int Release(MessageMapContainer* self) { + InitializeAndCopyToParentContainer(self, self); + return 0; +} + +void SetOwner(MessageMapContainer* self, + const shared_ptr& new_owner) { + self->owner = new_owner; +} + +Py_ssize_t Length(PyObject* _self) { + MessageMapContainer* self = GetMap(_self); + google::protobuf::Message* message = self->message; + return message->GetReflection()->FieldSize(*message, + self->parent_field_descriptor); +} + +int MapKeyMatches(MessageMapContainer* self, const Message* entry, + PyObject* key) { + // TODO(haberman): do we need more strict type checking? + ScopedPyObjectPtr entry_key( + cmessage::InternalGetScalar(entry, self->key_field_descriptor)); + int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ); + return ret; +} + +int SetItem(PyObject *_self, PyObject *key, PyObject *v) { + if (v) { + PyErr_Format(PyExc_ValueError, + "Direct assignment of submessage not allowed"); + return -1; + } + + // Now we know that this is a delete, not a set. + + MessageMapContainer* self = GetMap(_self); + cmessage::AssureWritable(self->parent); + + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. We need to search from the end because the underlying + // representation can have duplicates if a user calls MergeFrom(); the last + // one needs to win. + // + // TODO(haberman): add lookup API to Reflection API. + bool found = false; + for (int i = size - 1; i >= 0; i--) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, entry, key); + if (matches < 0) return -1; + if (matches) { + found = true; + if (i != size - 1) { + reflection->SwapElements(message, self->parent_field_descriptor, i, + size - 1); + } + reflection->RemoveLast(message, self->parent_field_descriptor); + + // Can't exit now, the repeated field representation of maps allows + // duplicate keys, and we have to be sure to remove all of them. + } + } + + if (!found) { + PyErr_Format(PyExc_KeyError, "Key not present in map"); + return -1; + } + + self->version++; + + return 0; +} + +PyObject* GetIterator(PyObject *_self) { + MessageMapContainer* self = GetMap(_self); + + ScopedPyObjectPtr obj(PyType_GenericAlloc(&MessageMapIterator_Type, 0)); + if (obj == NULL) { + return PyErr_Format(PyExc_KeyError, "Could not allocate iterator"); + } + + MessageMapIterator* iter = GetIter(obj); + + Py_INCREF(self); + iter->container = self; + iter->version = self->version; + iter->dict = PyDict_New(); + if (iter->dict == NULL) { + return PyErr_Format(PyExc_RuntimeError, + "Could not allocate dict for iterator."); + } + + // Build the entire map into a dict right now. Start from the beginning so + // that later entries win in the case of duplicates. + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. We need to search from the end because the underlying + // representation can have duplicates if a user calls MergeFrom(); the last + // one needs to win. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = size - 1; i >= 0; i--) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + ScopedPyObjectPtr key( + cmessage::InternalGetScalar(entry, self->key_field_descriptor)); + if (PyDict_SetItem(iter->dict, key.get(), GetCMessage(self, entry)) < 0) { + return PyErr_Format(PyExc_RuntimeError, + "SetItem failed in iterator construction."); + } + } + + iter->iter = PyObject_GetIter(iter->dict); + + return obj.release(); +} + +PyObject* GetItem(PyObject* _self, PyObject* key) { + MessageMapContainer* self = GetMap(_self); + cmessage::AssureWritable(self->parent); + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. We need to search from the end because the underlying + // representation can have duplicates if a user calls MergeFrom(); the last + // one needs to win. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = size - 1; i >= 0; i--) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, entry, key); + if (matches < 0) return NULL; + if (matches) { + return GetCMessage(self, entry); + } + } + + // Key is not already present; insert a new entry. + Message* entry = + reflection->AddMessage(message, self->parent_field_descriptor); + + self->version++; + + if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor, + key) < 0) { + reflection->RemoveLast(message, self->parent_field_descriptor); + return NULL; + } + + return GetCMessage(self, entry); +} + +PyObject* Contains(PyObject* _self, PyObject* key) { + MessageMapContainer* self = GetMap(_self); + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = 0; i < size; i++) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, entry, key); + if (matches < 0) return NULL; + if (matches) { + Py_RETURN_TRUE; + } + } + + Py_RETURN_FALSE; +} + +PyObject* Clear(PyObject* _self) { + MessageMapContainer* self = GetMap(_self); + cmessage::AssureWritable(self->parent); + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + self->version++; + reflection->ClearField(message, self->parent_field_descriptor); + + Py_RETURN_NONE; +} + +PyObject* Get(PyObject* self, PyObject* args) { + PyObject* key; + PyObject* default_value = NULL; + if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) { + return NULL; + } + + ScopedPyObjectPtr is_present(Contains(self, key)); + if (is_present.get() == NULL) { + return NULL; + } + + if (PyObject_IsTrue(is_present.get())) { + return GetItem(self, key); + } else { + if (default_value != NULL) { + Py_INCREF(default_value); + return default_value; + } else { + Py_RETURN_NONE; + } + } +} + +static PyMappingMethods MpMethods = { + Length, // mp_length + GetItem, // mp_subscript + SetItem, // mp_ass_subscript +}; + +static void Dealloc(PyObject* _self) { + MessageMapContainer* self = GetMap(_self); + self->owner.reset(); + Py_DECREF(self->message_dict); + Py_TYPE(_self)->tp_free(_self); +} + +static PyMethodDef Methods[] = { + { "__contains__", (PyCFunction)Contains, METH_O, + "Tests whether the map contains this element."}, + { "clear", (PyCFunction)Clear, METH_NOARGS, + "Removes all elements from the map."}, + { "get", Get, METH_VARARGS, + "Gets the value for the given key if present, or otherwise a default" }, + { "get_or_create", GetItem, METH_O, + "Alias for getitem, useful to make explicit that the map is mutated." }, + /* + { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, + "Makes a deep copy of the class." }, + { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, + "Outputs picklable representation of the repeated field." }, + */ + {NULL, NULL}, +}; + +} // namespace message_map_container + +namespace message_map_iterator { + +static void Dealloc(PyObject* _self) { + MessageMapIterator* self = GetIter(_self); + Py_DECREF(self->dict); + Py_DECREF(self->iter); + Py_DECREF(self->container); + Py_TYPE(_self)->tp_free(_self); +} + +PyObject* IterNext(PyObject* _self) { + MessageMapIterator* self = GetIter(_self); + + // This won't catch mutations to the map performed by MergeFrom(); no easy way + // to address that. + if (self->version != self->container->version) { + return PyErr_Format(PyExc_RuntimeError, + "Map modified during iteration."); + } + + return PyIter_Next(self->iter); +} + +} // namespace message_map_iterator + +PyTypeObject MessageMapContainer_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".MessageMapContainer", // tp_name + sizeof(MessageMapContainer), // tp_basicsize + 0, // tp_itemsize + message_map_container::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &message_map_container::MpMethods, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "A map container for message", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + message_map_container::GetIterator, // tp_iter + 0, // tp_iternext + message_map_container::Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init +}; + +PyTypeObject MessageMapIterator_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".MessageMapIterator", // tp_name + sizeof(MessageMapIterator), // tp_basicsize + 0, // tp_itemsize + message_map_iterator::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "A scalar map iterator", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + PyObject_SelfIter, // tp_iter + message_map_iterator::IterNext, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init +}; + +} // namespace python +} // namespace protobuf +} // namespace google diff --git a/python/google/protobuf/pyext/message_map_container.h b/python/google/protobuf/pyext/message_map_container.h new file mode 100644 index 0000000000..4ca0aecca4 --- /dev/null +++ b/python/google/protobuf/pyext/message_map_container.h @@ -0,0 +1,117 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__ +#define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__ + +#include + +#include +#ifndef _SHARED_PTR_H +#include +#endif + +#include + +namespace google { +namespace protobuf { + +class Message; + +using internal::shared_ptr; + +namespace python { + +struct CMessage; + +struct MessageMapContainer { + PyObject_HEAD; + + // This is the top-level C++ Message object that owns the whole + // proto tree. Every Python MessageMapContainer holds a + // reference to it in order to keep it alive as long as there's a + // Python object that references any part of the tree. + shared_ptr owner; + + // Pointer to the C++ Message that contains this container. The + // MessageMapContainer does not own this pointer. + Message* message; + + // Weak reference to a parent CMessage object (i.e. may be NULL.) + // + // Used to make sure all ancestors are also mutable when first + // modifying the container. + CMessage* parent; + + // Pointer to the parent's descriptor that describes this + // field. Used together with the parent's message when making a + // default message instance mutable. + // The pointer is owned by the global DescriptorPool. + const FieldDescriptor* parent_field_descriptor; + const FieldDescriptor* key_field_descriptor; + const FieldDescriptor* value_field_descriptor; + + // A callable that is used to create new child messages. + PyObject* subclass_init; + + // A dict mapping Message* -> CMessage. + PyObject* message_dict; + + // We bump this whenever we perform a mutation, to invalidate existing + // iterators. + uint64 version; +}; + +extern PyTypeObject MessageMapContainer_Type; +extern PyTypeObject MessageMapIterator_Type; + +namespace message_map_container { + +// Builds a MessageMapContainer object, from a parent message and a +// field descriptor. +extern PyObject* NewContainer(CMessage* parent, + const FieldDescriptor* parent_field_descriptor, + PyObject* concrete_class); + +// Releases the messages in the container to a new message. +// +// Returns 0 on success, -1 on failure. +int Release(MessageMapContainer* self); + +// Set the owner field of self and any children of self. +void SetOwner(MessageMapContainer* self, + const shared_ptr& new_owner); + +} // namespace message_map_container +} // namespace python +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_MAP_CONTAINER_H__ diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc index 0fe98e73ef..86b75d0f7c 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.cc +++ b/python/google/protobuf/pyext/repeated_composite_container.cc @@ -367,8 +367,8 @@ int AssignSubscript(RepeatedCompositeContainer* self, } // Delete from the underlying Message, if any. - if (self->message != NULL) { - if (cmessage::InternalDeleteRepeatedField(self->message, + if (self->parent != NULL) { + if (cmessage::InternalDeleteRepeatedField(self->parent, self->parent_field_descriptor, slice, self->child_messages) < 0) { @@ -572,47 +572,35 @@ static PyObject* Pop(RepeatedCompositeContainer* self, return item; } -// The caller takes ownership of the returned Message. -Message* ReleaseLast(const FieldDescriptor* field, - const Descriptor* type, - Message* message) { +// Release field of parent message and transfer the ownership to target. +void ReleaseLastTo(CMessage* parent, + const FieldDescriptor* field, + CMessage* target) { + GOOGLE_CHECK_NOTNULL(parent); GOOGLE_CHECK_NOTNULL(field); - GOOGLE_CHECK_NOTNULL(type); - GOOGLE_CHECK_NOTNULL(message); + GOOGLE_CHECK_NOTNULL(target); - Message* released_message = message->GetReflection()->ReleaseLast( - message, field); + shared_ptr released_message( + parent->message->GetReflection()->ReleaseLast(parent->message, field)); // TODO(tibell): Deal with proto1. // ReleaseMessage will return NULL which differs from // child_cmessage->message, if the field does not exist. In this case, // the latter points to the default instance via a const_cast<>, so we // have to reset it to a new mutable object since we are taking ownership. - if (released_message == NULL) { + if (released_message.get() == NULL) { const Message* prototype = - cmessage::GetMessageFactory()->GetPrototype(type); + cmessage::GetMessageFactory()->GetPrototype( + target->message->GetDescriptor()); GOOGLE_CHECK_NOTNULL(prototype); - return prototype->New(); - } else { - return released_message; + released_message.reset(prototype->New()); } -} -// Release field of message and transfer the ownership to cmessage. -void ReleaseLastTo(const FieldDescriptor* field, - Message* message, - CMessage* cmessage) { - GOOGLE_CHECK_NOTNULL(field); - GOOGLE_CHECK_NOTNULL(message); - GOOGLE_CHECK_NOTNULL(cmessage); - - shared_ptr released_message( - ReleaseLast(field, cmessage->message->GetDescriptor(), message)); - cmessage->parent = NULL; - cmessage->parent_field_descriptor = NULL; - cmessage->message = released_message.get(); - cmessage->read_only = false; - cmessage::SetOwner(cmessage, released_message); + target->parent = NULL; + target->parent_field_descriptor = NULL; + target->message = released_message.get(); + target->read_only = false; + cmessage::SetOwner(target, released_message); } // Called to release a container using @@ -635,7 +623,7 @@ int Release(RepeatedCompositeContainer* self) { for (Py_ssize_t i = size - 1; i >= 0; --i) { CMessage* child_cmessage = reinterpret_cast( PyList_GET_ITEM(self->child_messages, i)); - ReleaseLastTo(field, message, child_cmessage); + ReleaseLastTo(self->parent, field, child_cmessage); } // Detach from containing message. @@ -732,9 +720,7 @@ static PyMethodDef Methods[] = { PyTypeObject RepeatedCompositeContainer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - "google.protobuf.pyext._message." - "RepeatedCompositeContainer", // tp_name + FULL_MODULE_NAME ".RepeatedCompositeContainer", // tp_name sizeof(RepeatedCompositeContainer), // tp_basicsize 0, // tp_itemsize (destructor)repeated_composite_container::Dealloc, // tp_dealloc diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index ce7cee0fac..e0f2136021 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -161,13 +161,13 @@ int SetOwner(RepeatedCompositeContainer* self, const shared_ptr& new_owner); // Removes the last element of the repeated message field 'field' on -// the Message 'message', and transfers the ownership of the released -// Message to 'cmessage'. +// the Message 'parent', and transfers the ownership of the released +// Message to 'target'. // // Corresponds to reflection api method ReleaseMessage. -void ReleaseLastTo(const FieldDescriptor* field, - Message* message, - CMessage* cmessage); +void ReleaseLastTo(CMessage* parent, + const FieldDescriptor* field, + CMessage* target); } // namespace repeated_composite_container } // namespace python diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc index 110a4c8584..fd19683604 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.cc +++ b/python/google/protobuf/pyext/repeated_scalar_container.cc @@ -102,7 +102,7 @@ static int AssignItem(RepeatedScalarContainer* self, if (arg == NULL) { ScopedPyObjectPtr py_index(PyLong_FromLong(index)); - return cmessage::InternalDeleteRepeatedField(message, field_descriptor, + return cmessage::InternalDeleteRepeatedField(self->parent, field_descriptor, py_index, NULL); } @@ -470,7 +470,7 @@ static int AssSubscript(RepeatedScalarContainer* self, if (value == NULL) { return cmessage::InternalDeleteRepeatedField( - message, field_descriptor, slice, NULL); + self->parent, field_descriptor, slice, NULL); } if (!create_list) { @@ -769,9 +769,7 @@ static PyMethodDef Methods[] = { PyTypeObject RepeatedScalarContainer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - // Keep the fully qualified _message symbol in a line for opensource. - "google.protobuf.pyext._message." - "RepeatedScalarContainer", // tp_name + FULL_MODULE_NAME ".RepeatedScalarContainer", // tp_name sizeof(RepeatedScalarContainer), // tp_basicsize 0, // tp_itemsize (destructor)repeated_scalar_container::Dealloc, // tp_dealloc diff --git a/python/google/protobuf/pyext/scalar_map_container.cc b/python/google/protobuf/pyext/scalar_map_container.cc new file mode 100644 index 0000000000..6f731d2715 --- /dev/null +++ b/python/google/protobuf/pyext/scalar_map_container.cc @@ -0,0 +1,514 @@ +// 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. + +// Author: haberman@google.com (Josh Haberman) + +#include + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace python { + +struct ScalarMapIterator { + PyObject_HEAD; + + // This dict contains the full contents of what we want to iterate over. + // There's no way to avoid building this, because the list representation + // (which is canonical) can contain duplicate keys. So at the very least we + // need a set that lets us skip duplicate keys. And at the point that we're + // doing that, we might as well just build the actual dict we're iterating + // over and use dict's built-in iterator. + PyObject* dict; + + // An iterator on dict. + PyObject* iter; + + // A pointer back to the container, so we can notice changes to the version. + ScalarMapContainer* container; + + // The version of the map when we took the iterator to it. + // + // We store this so that if the map is modified during iteration we can throw + // an error. + uint64 version; +}; + +static ScalarMapIterator* GetIter(PyObject* obj) { + return reinterpret_cast(obj); +} + +namespace scalar_map_container { + +static ScalarMapContainer* GetMap(PyObject* obj) { + return reinterpret_cast(obj); +} + +// The private constructor of ScalarMapContainer objects. +PyObject *NewContainer( + CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor) { + if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { + return NULL; + } + + ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapContainer_Type, 0)); + if (obj.get() == NULL) { + return PyErr_Format(PyExc_RuntimeError, + "Could not allocate new container."); + } + + ScalarMapContainer* self = GetMap(obj); + + self->message = parent->message; + self->parent = parent; + self->parent_field_descriptor = parent_field_descriptor; + self->owner = parent->owner; + self->version = 0; + + self->key_field_descriptor = + parent_field_descriptor->message_type()->FindFieldByName("key"); + self->value_field_descriptor = + parent_field_descriptor->message_type()->FindFieldByName("value"); + + if (self->key_field_descriptor == NULL || + self->value_field_descriptor == NULL) { + return PyErr_Format(PyExc_KeyError, + "Map entry descriptor did not have key/value fields"); + } + + return obj.release(); +} + +// Initializes the underlying Message object of "to" so it becomes a new parent +// repeated scalar, and copies all the values from "from" to it. A child scalar +// container can be released by passing it as both from and to (e.g. making it +// the recipient of the new parent message and copying the values from itself). +static int InitializeAndCopyToParentContainer( + ScalarMapContainer* from, + ScalarMapContainer* to) { + // For now we require from == to, re-evaluate if we want to support deep copy + // as in repeated_scalar_container.cc. + GOOGLE_DCHECK(from == to); + Message* old_message = from->message; + Message* new_message = old_message->New(); + to->parent = NULL; + to->parent_field_descriptor = from->parent_field_descriptor; + to->message = new_message; + to->owner.reset(new_message); + + vector fields; + fields.push_back(from->parent_field_descriptor); + old_message->GetReflection()->SwapFields(old_message, new_message, fields); + return 0; +} + +int Release(ScalarMapContainer* self) { + return InitializeAndCopyToParentContainer(self, self); +} + +void SetOwner(ScalarMapContainer* self, + const shared_ptr& new_owner) { + self->owner = new_owner; +} + +Py_ssize_t Length(PyObject* _self) { + ScalarMapContainer* self = GetMap(_self); + google::protobuf::Message* message = self->message; + return message->GetReflection()->FieldSize(*message, + self->parent_field_descriptor); +} + +int MapKeyMatches(ScalarMapContainer* self, const Message* entry, + PyObject* key) { + // TODO(haberman): do we need more strict type checking? + ScopedPyObjectPtr entry_key( + cmessage::InternalGetScalar(entry, self->key_field_descriptor)); + int ret = PyObject_RichCompareBool(key, entry_key, Py_EQ); + return ret; +} + +PyObject* GetItem(PyObject* _self, PyObject* key) { + ScalarMapContainer* self = GetMap(_self); + + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = size - 1; i >= 0; i--) { + const Message& entry = reflection->GetRepeatedMessage( + *message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, &entry, key); + if (matches < 0) return NULL; + if (matches) { + return cmessage::InternalGetScalar(&entry, self->value_field_descriptor); + } + } + + // Need to add a new entry. + Message* entry = + reflection->AddMessage(message, self->parent_field_descriptor); + PyObject* ret = NULL; + + if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor, + key) >= 0) { + ret = cmessage::InternalGetScalar(entry, self->value_field_descriptor); + } + + self->version++; + + // If there was a type error above, it set the Python exception. + return ret; +} + +int SetItem(PyObject *_self, PyObject *key, PyObject *v) { + ScalarMapContainer* self = GetMap(_self); + cmessage::AssureWritable(self->parent); + + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + self->version++; + + if (v) { + // Set item. + // + // Right now the Reflection API doesn't support map lookup, so we implement + // it via linear search. + // + // TODO(haberman): add lookup API to Reflection API. + for (int i = size - 1; i >= 0; i--) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, entry, key); + if (matches < 0) return -1; + if (matches) { + return cmessage::InternalSetNonOneofScalar( + entry, self->value_field_descriptor, v); + } + } + + // Key is not already present; insert a new entry. + Message* entry = + reflection->AddMessage(message, self->parent_field_descriptor); + + if (cmessage::InternalSetNonOneofScalar(entry, self->key_field_descriptor, + key) < 0 || + cmessage::InternalSetNonOneofScalar(entry, self->value_field_descriptor, + v) < 0) { + reflection->RemoveLast(message, self->parent_field_descriptor); + return -1; + } + + return 0; + } else { + bool found = false; + for (int i = size - 1; i >= 0; i--) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, entry, key); + if (matches < 0) return -1; + if (matches) { + found = true; + if (i != size - 1) { + reflection->SwapElements(message, self->parent_field_descriptor, i, + size - 1); + } + reflection->RemoveLast(message, self->parent_field_descriptor); + + // Can't exit now, the repeated field representation of maps allows + // duplicate keys, and we have to be sure to remove all of them. + } + } + + if (found) { + return 0; + } else { + PyErr_Format(PyExc_KeyError, "Key not present in map"); + return -1; + } + } +} + +PyObject* GetIterator(PyObject *_self) { + ScalarMapContainer* self = GetMap(_self); + + ScopedPyObjectPtr obj(PyType_GenericAlloc(&ScalarMapIterator_Type, 0)); + if (obj == NULL) { + return PyErr_Format(PyExc_KeyError, "Could not allocate iterator"); + } + + ScalarMapIterator* iter = GetIter(obj.get()); + + Py_INCREF(self); + iter->container = self; + iter->version = self->version; + iter->dict = PyDict_New(); + if (iter->dict == NULL) { + return PyErr_Format(PyExc_RuntimeError, + "Could not allocate dict for iterator."); + } + + // Build the entire map into a dict right now. Start from the beginning so + // that later entries win in the case of duplicates. + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. We need to search from the end because the underlying + // representation can have duplicates if a user calls MergeFrom(); the last + // one needs to win. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = + reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = 0; i < size; i++) { + Message* entry = reflection->MutableRepeatedMessage( + message, self->parent_field_descriptor, i); + ScopedPyObjectPtr key( + cmessage::InternalGetScalar(entry, self->key_field_descriptor)); + ScopedPyObjectPtr val( + cmessage::InternalGetScalar(entry, self->value_field_descriptor)); + if (PyDict_SetItem(iter->dict, key.get(), val.get()) < 0) { + return PyErr_Format(PyExc_RuntimeError, + "SetItem failed in iterator construction."); + } + } + + + iter->iter = PyObject_GetIter(iter->dict); + + + return obj.release(); +} + +PyObject* Clear(PyObject* _self) { + ScalarMapContainer* self = GetMap(_self); + cmessage::AssureWritable(self->parent); + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + reflection->ClearField(message, self->parent_field_descriptor); + + Py_RETURN_NONE; +} + +PyObject* Contains(PyObject* _self, PyObject* key) { + ScalarMapContainer* self = GetMap(_self); + + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + + // Right now the Reflection API doesn't support map lookup, so we implement it + // via linear search. + // + // TODO(haberman): add lookup API to Reflection API. + size_t size = reflection->FieldSize(*message, self->parent_field_descriptor); + for (int i = size - 1; i >= 0; i--) { + const Message& entry = reflection->GetRepeatedMessage( + *message, self->parent_field_descriptor, i); + int matches = MapKeyMatches(self, &entry, key); + if (matches < 0) return NULL; + if (matches) { + Py_RETURN_TRUE; + } + } + + Py_RETURN_FALSE; +} + +PyObject* Get(PyObject* self, PyObject* args) { + PyObject* key; + PyObject* default_value = NULL; + if (PyArg_ParseTuple(args, "O|O", &key, &default_value) < 0) { + return NULL; + } + + ScopedPyObjectPtr is_present(Contains(self, key)); + if (is_present.get() == NULL) { + return NULL; + } + + if (PyObject_IsTrue(is_present.get())) { + return GetItem(self, key); + } else { + if (default_value != NULL) { + Py_INCREF(default_value); + return default_value; + } else { + Py_RETURN_NONE; + } + } +} + +static PyMappingMethods MpMethods = { + Length, // mp_length + GetItem, // mp_subscript + SetItem, // mp_ass_subscript +}; + +static void Dealloc(PyObject* _self) { + ScalarMapContainer* self = GetMap(_self); + self->owner.reset(); + Py_TYPE(_self)->tp_free(_self); +} + +static PyMethodDef Methods[] = { + { "__contains__", Contains, METH_O, + "Tests whether a key is a member of the map." }, + { "clear", (PyCFunction)Clear, METH_NOARGS, + "Removes all elements from the map." }, + { "get", Get, METH_VARARGS, + "Gets the value for the given key if present, or otherwise a default" }, + /* + { "__deepcopy__", (PyCFunction)DeepCopy, METH_VARARGS, + "Makes a deep copy of the class." }, + { "__reduce__", (PyCFunction)Reduce, METH_NOARGS, + "Outputs picklable representation of the repeated field." }, + */ + {NULL, NULL}, +}; + +} // namespace scalar_map_container + +namespace scalar_map_iterator { + +static void Dealloc(PyObject* _self) { + ScalarMapIterator* self = GetIter(_self); + Py_DECREF(self->dict); + Py_DECREF(self->iter); + Py_DECREF(self->container); + Py_TYPE(_self)->tp_free(_self); +} + +PyObject* IterNext(PyObject* _self) { + ScalarMapIterator* self = GetIter(_self); + + // This won't catch mutations to the map performed by MergeFrom(); no easy way + // to address that. + if (self->version != self->container->version) { + return PyErr_Format(PyExc_RuntimeError, + "Map modified during iteration."); + } + + return PyIter_Next(self->iter); +} + +} // namespace scalar_map_iterator + +PyTypeObject ScalarMapContainer_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".ScalarMapContainer", // tp_name + sizeof(ScalarMapContainer), // tp_basicsize + 0, // tp_itemsize + scalar_map_container::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + &scalar_map_container::MpMethods, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "A scalar map container", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + scalar_map_container::GetIterator, // tp_iter + 0, // tp_iternext + scalar_map_container::Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init +}; + +PyTypeObject ScalarMapIterator_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".ScalarMapIterator", // tp_name + sizeof(ScalarMapIterator), // tp_basicsize + 0, // tp_itemsize + scalar_map_iterator::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "A scalar map iterator", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + PyObject_SelfIter, // tp_iter + scalar_map_iterator::IterNext, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init +}; + +} // namespace python +} // namespace protobuf +} // namespace google diff --git a/python/google/protobuf/pyext/scalar_map_container.h b/python/google/protobuf/pyext/scalar_map_container.h new file mode 100644 index 0000000000..254e6e9874 --- /dev/null +++ b/python/google/protobuf/pyext/scalar_map_container.h @@ -0,0 +1,110 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__ +#define GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__ + +#include + +#include +#ifndef _SHARED_PTR_H +#include +#endif + +#include + +namespace google { +namespace protobuf { + +class Message; + +using internal::shared_ptr; + +namespace python { + +struct CMessage; + +struct ScalarMapContainer { + PyObject_HEAD; + + // This is the top-level C++ Message object that owns the whole + // proto tree. Every Python ScalarMapContainer holds a + // reference to it in order to keep it alive as long as there's a + // Python object that references any part of the tree. + shared_ptr owner; + + // Pointer to the C++ Message that contains this container. The + // ScalarMapContainer does not own this pointer. + Message* message; + + // Weak reference to a parent CMessage object (i.e. may be NULL.) + // + // Used to make sure all ancestors are also mutable when first + // modifying the container. + CMessage* parent; + + // Pointer to the parent's descriptor that describes this + // field. Used together with the parent's message when making a + // default message instance mutable. + // The pointer is owned by the global DescriptorPool. + const FieldDescriptor* parent_field_descriptor; + const FieldDescriptor* key_field_descriptor; + const FieldDescriptor* value_field_descriptor; + + // We bump this whenever we perform a mutation, to invalidate existing + // iterators. + uint64 version; +}; + +extern PyTypeObject ScalarMapContainer_Type; +extern PyTypeObject ScalarMapIterator_Type; + +namespace scalar_map_container { + +// Builds a ScalarMapContainer object, from a parent message and a +// field descriptor. +extern PyObject *NewContainer( + CMessage* parent, const FieldDescriptor* parent_field_descriptor); + +// Releases the messages in the container to a new message. +// +// Returns 0 on success, -1 on failure. +int Release(ScalarMapContainer* self); + +// Set the owner field of self and any children of self. +void SetOwner(ScalarMapContainer* self, + const shared_ptr& new_owner); + +} // namespace scalar_map_container +} // namespace python +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_PYTHON_CPP_SCALAR_MAP_CONTAINER_H__ diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py index 55e653a0fc..82fca66198 100755 --- a/python/google/protobuf/reflection.py +++ b/python/google/protobuf/reflection.py @@ -144,7 +144,6 @@ class GeneratedProtocolMessageType(type): _InitMessage(descriptor, cls) superclass = super(GeneratedProtocolMessageType, cls) superclass.__init__(name, bases, dictionary) - setattr(descriptor, '_concrete_class', cls) def ParseMessage(descriptor, byte_str): diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index a47ce3e32e..8cbd68222e 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -100,6 +100,10 @@ def MessageToString(message, as_utf8=False, as_one_line=False, return result.rstrip() return result +def _IsMapEntry(field): + return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and + field.message_type.has_options and + field.message_type.GetOptions().map_entry) def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, use_index_order=False, @@ -108,7 +112,19 @@ def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False, if use_index_order: fields.sort(key=lambda x: x[0].index) for field, value in fields: - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if _IsMapEntry(field): + for key in value: + # This is slow for maps with submessage entires because it copies the + # entire tree. Unfortunately this would take significant refactoring + # of this file to work around. + # + # TODO(haberman): refactor and optimize if this becomes an issue. + entry_submsg = field.message_type._concrete_class( + key=key, value=value[key]) + PrintField(field, entry_submsg, out, indent, as_utf8, as_one_line, + pointy_brackets=pointy_brackets, + use_index_order=use_index_order, float_format=float_format) + elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: for element in value: PrintField(field, element, out, indent, as_utf8, as_one_line, pointy_brackets=pointy_brackets, @@ -367,6 +383,7 @@ def _MergeField(tokenizer, message, allow_multiple_scalars): message_descriptor.full_name, name)) if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + is_map_entry = _IsMapEntry(field) tokenizer.TryConsume(':') if tokenizer.TryConsume('<'): @@ -378,6 +395,8 @@ def _MergeField(tokenizer, message, allow_multiple_scalars): if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: if field.is_extension: sub_message = message.Extensions[field].add() + elif is_map_entry: + sub_message = field.message_type._concrete_class() else: sub_message = getattr(message, field.name).add() else: @@ -391,6 +410,14 @@ def _MergeField(tokenizer, message, allow_multiple_scalars): if tokenizer.AtEnd(): raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token)) _MergeField(tokenizer, sub_message, allow_multiple_scalars) + + if is_map_entry: + value_cpptype = field.message_type.fields_by_name['value'].cpp_type + if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + value = getattr(message, field.name)[sub_message.key] + value.MergeFrom(sub_message.value) + else: + getattr(message, field.name)[sub_message.key] = sub_message.value else: _MergeScalarField(tokenizer, message, field, allow_multiple_scalars) @@ -701,13 +728,16 @@ class _Tokenizer(object): String literals (whether bytes or text) can come in multiple adjacent tokens which are automatically concatenated, like in C or Python. This method only consumes one token. + + Raises: + ParseError: When the wrong format data is found. """ text = self.token if len(text) < 1 or text[0] not in ('\'', '"'): - raise self._ParseError('Expected string but found: "%r"' % text) + raise self._ParseError('Expected string but found: %r' % (text,)) if len(text) < 2 or text[-1] != text[0]: - raise self._ParseError('String missing ending quote.') + raise self._ParseError('String missing ending quote: %r' % (text,)) try: result = text_encoding.CUnescape(text[1:-1]) diff --git a/python/setup.py b/python/setup.py index a1365fba57..5c321f509a 100755 --- a/python/setup.py +++ b/python/setup.py @@ -91,6 +91,7 @@ def GenerateUnittestProtos(): if not os.path.exists("../.git"): return + generate_proto("../src/google/protobuf/map_unittest.proto") generate_proto("../src/google/protobuf/unittest.proto") generate_proto("../src/google/protobuf/unittest_custom_options.proto") generate_proto("../src/google/protobuf/unittest_import.proto") diff --git a/ruby/tests/generated_code.proto b/ruby/tests/generated_code.proto index b1d6323243..42d82a6bac 100644 --- a/ruby/tests/generated_code.proto +++ b/ruby/tests/generated_code.proto @@ -3,17 +3,17 @@ syntax = "proto3"; package A.B.C; message TestMessage { - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional bool optional_bool = 5; - optional double optional_double = 6; - optional float optional_float = 7; - optional string optional_string = 8; - optional bytes optional_bytes = 9; - optional TestEnum optional_enum = 10; - optional TestMessage optional_msg = 11; + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + bool optional_bool = 5; + double optional_double = 6; + float optional_float = 7; + string optional_string = 8; + bytes optional_bytes = 9; + TestEnum optional_enum = 10; + TestMessage optional_msg = 11; repeated int32 repeated_int32 = 21; repeated int64 repeated_int64 = 22; @@ -53,10 +53,10 @@ message TestMessage { map map_string_bool = 70; message NestedMessage { - optional int32 foo = 1; + int32 foo = 1; } - optional NestedMessage nested_message = 80; + NestedMessage nested_message = 80; } enum TestEnum { diff --git a/src/Makefile.am b/src/Makefile.am index fd10b789fd..2ecf6028f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -88,6 +88,7 @@ nobase_include_HEADERS = \ google/protobuf/stubs/type_traits.h \ google/protobuf/any.pb.h \ google/protobuf/api.pb.h \ + google/protobuf/any.h \ google/protobuf/arena.h \ google/protobuf/arenastring.h \ google/protobuf/descriptor_database.h \ @@ -186,6 +187,7 @@ libprotobuf_la_SOURCES = \ $(libprotobuf_lite_la_SOURCES) \ google/protobuf/any.pb.cc \ google/protobuf/api.pb.cc \ + google/protobuf/any.cc \ google/protobuf/descriptor.cc \ google/protobuf/descriptor_database.cc \ google/protobuf/descriptor.pb.cc \ @@ -264,6 +266,8 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_enum.cc \ google/protobuf/compiler/java/java_enum_field.cc \ google/protobuf/compiler/java/java_enum_field.h \ + google/protobuf/compiler/java/java_enum_field_lite.cc \ + google/protobuf/compiler/java/java_enum_field_lite.h \ google/protobuf/compiler/java/java_enum.h \ google/protobuf/compiler/java/java_extension.cc \ google/protobuf/compiler/java/java_extension.h \ @@ -278,22 +282,38 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_helpers.h \ google/protobuf/compiler/java/java_lazy_message_field.cc \ google/protobuf/compiler/java/java_lazy_message_field.h \ + google/protobuf/compiler/java/java_lazy_message_field_lite.cc\ + google/protobuf/compiler/java/java_lazy_message_field_lite.h \ google/protobuf/compiler/java/java_map_field.cc \ google/protobuf/compiler/java/java_map_field.h \ + google/protobuf/compiler/java/java_map_field_lite.cc \ + google/protobuf/compiler/java/java_map_field_lite.h \ google/protobuf/compiler/java/java_message.cc \ + google/protobuf/compiler/java/java_message_lite.cc \ + google/protobuf/compiler/java/java_message_builder.cc \ + google/protobuf/compiler/java/java_message_builder_lite.cc \ google/protobuf/compiler/java/java_message_field.cc \ google/protobuf/compiler/java/java_message_field.h \ + google/protobuf/compiler/java/java_message_field_lite.cc \ + google/protobuf/compiler/java/java_message_field_lite.h \ google/protobuf/compiler/java/java_message.h \ + google/protobuf/compiler/java/java_message_lite.h \ + google/protobuf/compiler/java/java_message_builder.h \ + google/protobuf/compiler/java/java_message_builder_lite.h \ google/protobuf/compiler/java/java_name_resolver.cc \ google/protobuf/compiler/java/java_name_resolver.h \ google/protobuf/compiler/java/java_primitive_field.cc \ google/protobuf/compiler/java/java_primitive_field.h \ + google/protobuf/compiler/java/java_primitive_field_lite.cc \ + google/protobuf/compiler/java/java_primitive_field_lite.h \ google/protobuf/compiler/java/java_shared_code_generator.cc \ google/protobuf/compiler/java/java_shared_code_generator.h \ google/protobuf/compiler/java/java_service.cc \ google/protobuf/compiler/java/java_service.h \ google/protobuf/compiler/java/java_string_field.cc \ google/protobuf/compiler/java/java_string_field.h \ + google/protobuf/compiler/java/java_string_field_lite.cc \ + google/protobuf/compiler/java/java_string_field_lite.h \ google/protobuf/compiler/java/java_doc_comment.cc \ google/protobuf/compiler/java/java_doc_comment.h \ google/protobuf/compiler/javanano/javanano_enum.cc \ @@ -381,6 +401,7 @@ protoc_SOURCES = google/protobuf/compiler/main.cc # Tests ============================================================== protoc_inputs = \ + google/protobuf/any_test.proto \ google/protobuf/map_lite_unittest.proto \ google/protobuf/map_proto2_unittest.proto \ google/protobuf/map_unittest.proto \ @@ -419,6 +440,7 @@ EXTRA_DIST = \ google/protobuf/testdata/golden_message_proto3 \ google/protobuf/testdata/golden_packed_fields_message \ google/protobuf/testdata/bad_utf8_string \ + google/protobuf/testdata/map_test_data.txt \ google/protobuf/testdata/text_format_unittest_data.txt \ google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt \ google/protobuf/testdata/text_format_unittest_data_pointy.txt \ @@ -443,6 +465,8 @@ protoc_lite_outputs = \ protoc_outputs = \ $(protoc_lite_outputs) \ + google/protobuf/any_test.pb.cc \ + google/protobuf/any_test.pb.h \ google/protobuf/map_proto2_unittest.pb.cc \ google/protobuf/map_proto2_unittest.pb.h \ google/protobuf/map_unittest.pb.cc \ @@ -543,6 +567,7 @@ protobuf_test_SOURCES = \ google/protobuf/stubs/stringprintf_unittest.cc \ google/protobuf/stubs/template_util_unittest.cc \ google/protobuf/stubs/type_traits_unittest.cc \ + google/protobuf/any_test.cc \ google/protobuf/arenastring_unittest.cc \ google/protobuf/arena_unittest.cc \ google/protobuf/descriptor_database_unittest.cc \ @@ -604,6 +629,8 @@ nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs) protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS) protobuf_lite_test_SOURCES = \ + google/protobuf/arena_test_util.cc \ + google/protobuf/arena_test_util.h \ google/protobuf/lite_unittest.cc \ google/protobuf/map_lite_test_util.cc \ google/protobuf/map_lite_test_util.h \ diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc new file mode 100644 index 0000000000..c66fdfadec --- /dev/null +++ b/src/google/protobuf/any.cc @@ -0,0 +1,100 @@ +// 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. + +#include + +namespace google { +namespace protobuf { +namespace internal { + +namespace { +string GetTypeUrl(const Descriptor* message) { + return string(kTypeGoogleApisComPrefix) + message->full_name(); +} + +} // namespace + +const char kAnyFullTypeName[] = "google.protobuf.Any"; +const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/"; + +AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) + : type_url_(type_url), value_(value) { +} + +void AnyMetadata::PackFrom(const Message& message) { + type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(), + GetTypeUrl(message.GetDescriptor())); + message.SerializeToString(value_->MutableNoArena( + &::google::protobuf::internal::GetEmptyStringAlreadyInited())); +} + +bool AnyMetadata::UnpackTo(Message* message) const { + if (!InternalIs(message->GetDescriptor())) { + return false; + } + return message->ParseFromString( + value_->GetNoArena(&::google::protobuf::internal::GetEmptyString())); +} + +bool AnyMetadata::InternalIs(const Descriptor* descriptor) const { + return type_url_->GetNoArena( + &::google::protobuf::internal::GetEmptyString()) == + GetTypeUrl(descriptor); +} + +bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { + const int prefix_len = strlen(kTypeGoogleApisComPrefix); + if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) { + full_type_name->assign(type_url.data() + prefix_len, + type_url.size() - prefix_len); + return true; + } + return true; +} + + +bool GetAnyFieldDescriptors(const Message& message, + const FieldDescriptor** type_url_field, + const FieldDescriptor** value_field) { + const Descriptor* descriptor = message.GetDescriptor(); + if (descriptor->full_name() != kAnyFullTypeName) { + return false; + } + *type_url_field = descriptor->FindFieldByNumber(1); + *value_field = descriptor->FindFieldByNumber(2); + return (*type_url_field != NULL && + (*type_url_field)->type() == FieldDescriptor::TYPE_STRING && + *value_field != NULL && + (*value_field)->type() == FieldDescriptor::TYPE_BYTES); +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h new file mode 100644 index 0000000000..757b45aa22 --- /dev/null +++ b/src/google/protobuf/any.h @@ -0,0 +1,90 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_ANY_H__ +#define GOOGLE_PROTOBUF_ANY_H__ + +#include + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace internal { + +// Helper class used to implement google::protobuf::Any. +class AnyMetadata { + typedef ArenaStringPtr UrlType; + typedef ArenaStringPtr ValueType; + public: + // AnyMetadata does not take ownership of "type_url" and "value". + AnyMetadata(UrlType* type_url, ValueType* value); + + void PackFrom(const Message& message); + + bool UnpackTo(Message* message) const; + + template + bool Is() const { + return InternalIs(T::default_instance().GetDescriptor()); + } + + private: + bool InternalIs(const Descriptor* message) const; + + UrlType* type_url_; + ValueType* value_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AnyMetadata); +}; + +extern const char kAnyFullTypeName[]; // "google.protobuf.Any". +extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/". + +// Get the proto type name from Any::type_url value. For example, passing +// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in +// *full_type_name. Returns false if type_url does not start with +// "type.googleapis.com". +bool ParseAnyTypeUrl(const string& type_url, string* full_type_name); + +// See if message is of type google.protobuf.Any, if so, return the descriptors +// for "type_url" and "value" fields. +bool GetAnyFieldDescriptors(const Message& message, + const FieldDescriptor** type_url_field, + const FieldDescriptor** value_field); + +} // namespace internal +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_ANY_H__ diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index 75cc875445..2c492b048e 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -111,13 +111,21 @@ static void MergeFromFail(int line) { // =================================================================== +void Any::PackFrom(const ::google::protobuf::Message& message) { + _any_metadata_.PackFrom(message); +} + +bool Any::UnpackTo(::google::protobuf::Message* message) const { + return _any_metadata_.UnpackTo(message); +} + #ifndef _MSC_VER const int Any::kTypeUrlFieldNumber; const int Any::kValueFieldNumber; #endif // !_MSC_VER Any::Any() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL), _any_metadata_(&type_url_, &value_) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Any) } @@ -128,7 +136,8 @@ void Any::InitAsDefaultInstance() { Any::Any(const Any& from) : ::google::protobuf::Message(), - _internal_metadata_(NULL) { + _internal_metadata_(NULL), + _any_metadata_(&type_url_, &value_) { SharedCtor(); MergeFrom(from); // @@protoc_insertion_point(copy_constructor:google.protobuf.Any) @@ -316,9 +325,9 @@ int Any::ByteSize() const { void Any::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Any* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Any* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -378,7 +387,7 @@ void Any::InternalSwap(Any* other) { // Any // optional string type_url = 1; - void Any::clear_type_url() { +void Any::clear_type_url() { type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Any::type_url() const { @@ -421,7 +430,7 @@ void Any::InternalSwap(Any* other) { } // optional bytes value = 2; - void Any::clear_value() { +void Any::clear_value() { value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Any::value() const { diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index b2c238c11b..c324c4afc8 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -27,6 +27,7 @@ #include #include #include +#include "google/protobuf/any.h" // @@protoc_insertion_point(includes) namespace google { @@ -56,6 +57,14 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const Any& default_instance(); + // implements Any ----------------------------------------------- + + void PackFrom(const ::google::protobuf::Message& message); + bool UnpackTo(::google::protobuf::Message* message) const; + template bool Is() const { + return _any_metadata_.Is(); + } + void Swap(Any* other); // implements Message ---------------------------------------------- @@ -127,6 +136,7 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message { ::google::protobuf::internal::ArenaStringPtr type_url_; ::google::protobuf::internal::ArenaStringPtr value_; mutable int _cached_size_; + ::google::protobuf::internal::AnyMetadata _any_metadata_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fany_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fany_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fany_2eproto(); diff --git a/src/google/protobuf/any_test.cc b/src/google/protobuf/any_test.cc new file mode 100644 index 0000000000..1bfaa63d87 --- /dev/null +++ b/src/google/protobuf/any_test.cc @@ -0,0 +1,89 @@ +// 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. + +#include +#include + +namespace google { +namespace protobuf { +namespace { + +TEST(AnyTest, TestPackAndUnpack) { + protobuf_unittest::TestAny submessage; + submessage.set_int32_value(12345); + protobuf_unittest::TestAny message; + message.mutable_any_value()->PackFrom(submessage); + + string data = message.SerializeAsString(); + + ASSERT_TRUE(message.ParseFromString(data)); + EXPECT_TRUE(message.has_any_value()); + ASSERT_TRUE(message.any_value().UnpackTo(&submessage)); + EXPECT_EQ(12345, submessage.int32_value()); +} + +TEST(AnyTest, TestPackAndUnpackAny) { + // We can pack a Any message inside another Any message. + protobuf_unittest::TestAny submessage; + submessage.set_int32_value(12345); + google::protobuf::Any any; + any.PackFrom(submessage); + protobuf_unittest::TestAny message; + message.mutable_any_value()->PackFrom(any); + + string data = message.SerializeAsString(); + + ASSERT_TRUE(message.ParseFromString(data)); + EXPECT_TRUE(message.has_any_value()); + ASSERT_TRUE(message.any_value().UnpackTo(&any)); + ASSERT_TRUE(any.UnpackTo(&submessage)); + EXPECT_EQ(12345, submessage.int32_value()); +} + +TEST(AnyTest, TestIs) { + protobuf_unittest::TestAny submessage; + submessage.set_int32_value(12345); + google::protobuf::Any any; + any.PackFrom(submessage); + ASSERT_TRUE(any.ParseFromString(any.SerializeAsString())); + EXPECT_TRUE(any.Is()); + EXPECT_FALSE(any.Is()); + + protobuf_unittest::TestAny message; + message.mutable_any_value()->PackFrom(any); + ASSERT_TRUE(message.ParseFromString(message.SerializeAsString())); + EXPECT_FALSE(message.any_value().Is()); + EXPECT_TRUE(message.any_value().Is()); +} + +} // namespace +} // namespace protobuf + +} // namespace google diff --git a/src/google/protobuf/any_test.proto b/src/google/protobuf/any_test.proto new file mode 100644 index 0000000000..0c5b30ba3e --- /dev/null +++ b/src/google/protobuf/any_test.proto @@ -0,0 +1,41 @@ +// 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. + +syntax = "proto3"; + +package protobuf_unittest; + +import "google/protobuf/any.proto"; + +message TestAny { + int32 int32_value = 1; + google.protobuf.Any any_value = 2; + repeated google.protobuf.Any repeated_any_value = 3; +} diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index b34ce803ca..434320dc9d 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -162,7 +162,7 @@ const int Api::kSourceContextFieldNumber; #endif // !_MSC_VER Api::Api() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Api) } @@ -230,7 +230,7 @@ Api* Api::New(::google::protobuf::Arena* arena) const { void Api::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; methods_.Clear(); options_.Clear(); @@ -266,26 +266,31 @@ bool Api::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_methods: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_methods: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_methods())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_methods; - if (input->ExpectTag(26)) goto parse_options; + if (input->ExpectTag(18)) goto parse_loop_methods; + if (input->ExpectTag(26)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.Option options = 3; case 3: { if (tag == 26) { - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(26)) goto parse_options; + if (input->ExpectTag(26)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(34)) goto parse_version; break; } @@ -483,9 +488,9 @@ int Api::ByteSize() const { void Api::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Api* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Api* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -553,7 +558,7 @@ void Api::InternalSwap(Api* other) { // Api // optional string name = 1; - void Api::clear_name() { +void Api::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Api::name() const { @@ -596,10 +601,10 @@ void Api::InternalSwap(Api* other) { } // repeated .google.protobuf.Method methods = 2; - int Api::methods_size() const { +int Api::methods_size() const { return methods_.size(); } - void Api::clear_methods() { +void Api::clear_methods() { methods_.Clear(); } const ::google::protobuf::Method& Api::methods(int index) const { @@ -626,10 +631,10 @@ Api::mutable_methods() { } // repeated .google.protobuf.Option options = 3; - int Api::options_size() const { +int Api::options_size() const { return options_.size(); } - void Api::clear_options() { +void Api::clear_options() { options_.Clear(); } const ::google::protobuf::Option& Api::options(int index) const { @@ -656,7 +661,7 @@ Api::mutable_options() { } // optional string version = 4; - void Api::clear_version() { +void Api::clear_version() { version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Api::version() const { @@ -699,11 +704,11 @@ Api::mutable_options() { } // optional .google.protobuf.SourceContext source_context = 5; - bool Api::has_source_context() const { +bool Api::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } - void Api::clear_source_context() { - if (source_context_ != NULL) delete source_context_; +void Api::clear_source_context() { + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } const ::google::protobuf::SourceContext& Api::source_context() const { @@ -749,7 +754,7 @@ const int Method::kOptionsFieldNumber; #endif // !_MSC_VER Method::Method() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Method) } @@ -929,12 +934,15 @@ bool Method::MergePartialFromCodedStream( case 6: { if (tag == 50) { parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(50)) goto parse_options; + if (input->ExpectTag(50)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -1119,9 +1127,9 @@ int Method::ByteSize() const { void Method::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Method* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Method* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1196,7 +1204,7 @@ void Method::InternalSwap(Method* other) { // Method // optional string name = 1; - void Method::clear_name() { +void Method::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Method::name() const { @@ -1239,7 +1247,7 @@ void Method::InternalSwap(Method* other) { } // optional string request_type_url = 2; - void Method::clear_request_type_url() { +void Method::clear_request_type_url() { request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Method::request_type_url() const { @@ -1282,7 +1290,7 @@ void Method::InternalSwap(Method* other) { } // optional bool request_streaming = 3; - void Method::clear_request_streaming() { +void Method::clear_request_streaming() { request_streaming_ = false; } bool Method::request_streaming() const { @@ -1296,7 +1304,7 @@ void Method::InternalSwap(Method* other) { } // optional string response_type_url = 4; - void Method::clear_response_type_url() { +void Method::clear_response_type_url() { response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Method::response_type_url() const { @@ -1339,7 +1347,7 @@ void Method::InternalSwap(Method* other) { } // optional bool response_streaming = 5; - void Method::clear_response_streaming() { +void Method::clear_response_streaming() { response_streaming_ = false; } bool Method::response_streaming() const { @@ -1353,10 +1361,10 @@ void Method::InternalSwap(Method* other) { } // repeated .google.protobuf.Option options = 6; - int Method::options_size() const { +int Method::options_size() const { return options_.size(); } - void Method::clear_options() { +void Method::clear_options() { options_.Clear(); } const ::google::protobuf::Option& Method::options(int index) const { diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index f459af0ffe..985adc5d5d 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -466,7 +466,7 @@ inline bool Api::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } inline void Api::clear_source_context() { - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } inline const ::google::protobuf::SourceContext& Api::source_context() const { @@ -690,6 +690,8 @@ Method::mutable_options() { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index f7059d2601..9600964516 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -29,7 +29,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include #ifdef ADDRESS_SANITIZER #include @@ -155,10 +154,16 @@ void Arena::AddListNode(void* elem, void (*cleanup)(void*)) { reinterpret_cast(node))); } -void* Arena::AllocateAligned(size_t n) { +void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) { // Align n to next multiple of 8 (from Hacker's Delight, Chapter 3.) n = (n + 7) & -8; + // Monitor allocation if needed. + if (GOOGLE_PREDICT_FALSE(hooks_cookie_ != NULL) && + options_.on_arena_allocation != NULL) { + options_.on_arena_allocation(allocated, n, hooks_cookie_); + } + // If this thread already owns a block in this arena then try to use that. // This fast path optimizes the case where multiple threads allocate from the // same arena. diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index b48bef925a..4adcd677da 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -28,12 +28,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// This header is logically internal, but is made public because it is used -// from protocol-compiler-generated code, which may reside in other components. - #ifndef GOOGLE_PROTOBUF_ARENA_H__ #define GOOGLE_PROTOBUF_ARENA_H__ +#if __cplusplus >= 201103L +#include +#endif #include #include @@ -113,10 +113,13 @@ struct ArenaOptions { void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used); void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used); - // type_name is promised to be a static string - its lifetime extends to - // match program's lifetime. - void (*on_arena_allocation)(const char* type_name, uint64 alloc_size, - Arena* arena, void* cookie); + // type_info is promised to be static - its lifetime extends to + // match program's lifetime (It is given by typeid operator). + // Note: typeid(void) will be passed as allocated_type every time we + // intentionally want to avoid monitoring an allocation. (i.e. internal + // allocations for managing the arena) + void (*on_arena_allocation)(const std::type_info* allocated_type, + uint64 alloc_size, void* cookie); ArenaOptions() : start_block_size(kDefaultStartBlockSize), @@ -137,6 +140,14 @@ struct ArenaOptions { static const size_t kDefaultMaxBlockSize = 8192; }; +// Support for non-RTTI environments. (The metrics hooks API uses type +// information.) +#ifndef GOOGLE_PROTOBUF_NO_RTTI +#define RTTI_TYPE_ID(type) (&typeid(type)) +#else +#define RTTI_TYPE_ID(type) (NULL) +#endif + // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation // with new/delete, and improves performance by aggregating allocations into // larger blocks and freeing allocations all at once. Protocol messages are @@ -146,6 +157,44 @@ struct ArenaOptions { // This is a thread-safe implementation: multiple threads may allocate from the // arena concurrently. Destruction is not thread-safe and the destructing // thread must synchronize with users of the arena first. +// +// An arena provides two allocation interfaces: CreateMessage, which works +// for arena-enabled proto2 message types as well as other types that satisfy +// the appropriate protocol (described below), and Create, which works for +// any arbitrary type T. CreateMessage is better when the type T supports it, +// because this interface (i) passes the arena pointer to the created object so +// that its sub-objects and internal allocations can use the arena too, and (ii) +// elides the object's destructor call when possible. Create does not place +// any special requirements on the type T, and will invoke the object's +// destructor when the arena is destroyed. +// +// The arena message allocation protocol, required by CreateMessage, is as +// follows: +// +// - The type T must have (at least) two constructors: a constructor with no +// arguments, called when a T is allocated on the heap; and a constructor with +// a google::protobuf::Arena* argument, called when a T is allocated on an arena. If the +// second constructor is called with a NULL arena pointer, it must be +// equivalent to invoking the first (no-argument) constructor. +// +// - The type T must have a particular type trait: a nested type +// |InternalArenaConstructable_|. This is usually a typedef to |void|. If no +// such type trait exists, then the instantiation CreateMessage will fail +// to compile. +// +// - The type T *may* have the type trait |DestructorSkippable_|. If this type +// trait is present in the type, then its destructor will not be called if and +// only if it was passed a non-NULL arena pointer. If this type trait is not +// present on the type, then its destructor is always called when the +// containing arena is destroyed. +// +// - One- and two-user-argument forms of CreateMessage() also exist that +// forward these constructor arguments to T's constructor: for example, +// CreateMessage(Arena*, arg1, arg2) forwards to a constructor T(Arena*, +// arg1, arg2). +// +// This protocol is implemented by all arena-enabled proto2 message classes as +// well as RepeatedPtrField. class LIBPROTOBUF_EXPORT Arena { public: // Arena constructor taking custom options. See ArenaOptions below for @@ -172,8 +221,10 @@ class LIBPROTOBUF_EXPORT Arena { // compilation error will occur. // // RepeatedField and RepeatedPtrField may also be instantiated directly on an - // arena with this method: they act as "arena-capable message types" for the - // purposes of the Arena API. + // arena with this method. + // + // This function also accepts any type T that satisfies the arena message + // allocation protocol, documented above. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* CreateMessage(::google::protobuf::Arena* arena) { if (arena == NULL) { @@ -183,17 +234,55 @@ class LIBPROTOBUF_EXPORT Arena { } } + // One-argument form of CreateMessage. This is useful for constructing objects + // that implement the arena message construction protocol described above but + // take additional constructor arguments. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* CreateMessage(::google::protobuf::Arena* arena, const Arg& arg) { + if (arena == NULL) { + return new T(NULL, arg); + } else { + return arena->CreateMessageInternal(static_cast(0), + arg); + } + } + + // Two-argument form of CreateMessage. This is useful for constructing objects + // that implement the arena message construction protocol described above but + // take additional constructor arguments. + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static T* CreateMessage(::google::protobuf::Arena* arena, + const Arg1& arg1, + const Arg2& arg2) { + if (arena == NULL) { + return new T(NULL, arg1, arg2); + } else { + return arena->CreateMessageInternal(static_cast(0), + arg1, arg2); + } + } + // API to create any objects on the arena. Note that only the object will // be created on the arena; the underlying ptrs (in case of a proto2 message) // will be still heap allocated. Proto messages should usually be allocated // with CreateMessage() instead. + // + // Note that even if T satisfies the arena message construction protocol + // (InternalArenaConstructable_ trait and optional DestructorSkippable_ + // trait), as described above, this function does not follow the protocol; + // instead, it treats T as a black-box type, just as if it did not have these + // traits. Specifically, T's constructor arguments will always be only those + // passed to Create() -- no additional arena pointer is implicitly added. + // Furthermore, the destructor will always be called at arena destruction time + // (unless the destructor is trivial). Hence, from T's point of view, it is as + // if the object were allocated on the heap (except that the underlying memory + // is obtained from the arena). template GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena) { if (arena == NULL) { return new T(); } else { - return arena->CreateInternal( - SkipDeleteList(static_cast(0))); + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value); } } @@ -203,7 +292,7 @@ class LIBPROTOBUF_EXPORT Arena { if (arena == NULL) { return new T(arg); } else { - return arena->CreateInternal(SkipDeleteList(static_cast(0)), + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, arg); } } @@ -214,9 +303,8 @@ class LIBPROTOBUF_EXPORT Arena { if (arena == NULL) { return new T(arg1, arg2); } else { - return arena->CreateInternal(SkipDeleteList(static_cast(0)), - arg1, - arg2); + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2); } } @@ -229,10 +317,8 @@ class LIBPROTOBUF_EXPORT Arena { if (arena == NULL) { return new T(arg1, arg2, arg3); } else { - return arena->CreateInternal(SkipDeleteList(static_cast(0)), - arg1, - arg2, - arg3); + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3); } } @@ -246,20 +332,95 @@ class LIBPROTOBUF_EXPORT Arena { if (arena == NULL) { return new T(arg1, arg2, arg3, arg4); } else { - return arena->CreateInternal(SkipDeleteList(static_cast(0)), - arg1, - arg2, - arg3, - arg4); + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3, arg4); } } - // Create an array of object type T on the arena. Type T must have a trivial - // constructor, as it will not be invoked when created on the arena. + // Version of the above with five constructor arguments for the created + // object. + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena, + const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, + const Arg5& arg5) { + if (arena == NULL) { + return new T(arg1, arg2, arg3, arg4, arg5); + } else { + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3, arg4, arg5); + } + } + + // Version of the above with six constructor arguments for the created + // object. + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena, + const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, + const Arg5& arg5, const Arg6& arg6) { + if (arena == NULL) { + return new T(arg1, arg2, arg3, arg4, arg5, arg6); + } else { + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3, arg4, arg5, arg6); + } + } + + // Version of the above with seven constructor arguments for the created + // object. + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena, + const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, + const Arg5& arg5, const Arg6& arg6, + const Arg7& arg7) { + if (arena == NULL) { + return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } else { + return arena->CreateInternal(google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + } + + // Version of the above with eight constructor arguments for the created + // object. + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena, + const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, + const Arg5& arg5, const Arg6& arg6, + const Arg7& arg7, const Arg8& arg8) { + if (arena == NULL) { + return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } else { + return arena->CreateInternal( + google::protobuf::internal::has_trivial_destructor::value, + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + } + + // Create an array of object type T on the arena *without* invoking the + // constructor of T. If `arena` is null, then the return value should be freed + // with `delete[] x;` (or `::operator delete[](x);`). + // To ensure safe uses, this function checks at compile time + // (when compiled as C++11) that T is trivially default-constructible and + // trivially destructible. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) { +#if __cplusplus >= 201103L + static_assert(std::is_trivially_default_constructible::value, + "CreateArray requires a trivially constructible type"); + static_assert(std::is_trivially_destructible::value, + "CreateArray requires a trivially destructible type"); +#endif if (arena == NULL) { - return new T[num_elements]; + return static_cast(::operator new[](num_elements * sizeof(T))); } else { return arena->CreateInternalRawArray(num_elements); } @@ -374,27 +535,26 @@ class LIBPROTOBUF_EXPORT Arena { // wrap them in static functions. static ThreadCache& thread_cache(); #elif defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) - // Android ndk does not support __thread keyword so we use a custom thread + // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread // local storage class we implemented. - // iOS also does not support the __thread keyword. + // iOS also does not support the GOOGLE_THREAD_LOCAL keyword. static ThreadCache& thread_cache(); #else static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_; static ThreadCache& thread_cache() { return thread_cache_; } #endif - // SFINAE for skipping addition to delete list for a Type. This is mainly to - // skip proto2/proto1 message objects with cc_enable_arenas=true from being - // part of the delete list. Also, note, compiler will optimize out the branch - // in CreateInternal. - // + // SFINAE for skipping addition to delete list for a message type when created + // with CreateMessage. This is mainly to skip proto2/proto1 message objects + // with cc_enable_arenas=true from being part of the delete list. Also, note, + // compiler will optimize out the branch in CreateInternal. template static inline bool SkipDeleteList(typename T::DestructorSkippable_*) { return true; } - // For non message objects, we skip addition to delete list if the object has - // a trivial destructor. + // For message objects that don't have the DestructorSkippable_ trait, we + // always add to the delete list. template static inline bool SkipDeleteList(...) { return google::protobuf::internal::has_trivial_destructor::value; @@ -419,14 +579,15 @@ class LIBPROTOBUF_EXPORT Arena { // Just allocate the required size for the given type assuming the // type has a trivial constructor. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternalRawArray(uint32 num_elements) { - return static_cast(AllocateAligned(sizeof(T) * num_elements)); + inline T* CreateInternalRawArray(size_t num_elements) { + return static_cast( + AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements)); } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal( bool skip_explicit_ownership) { - T* t = new (AllocateAligned(sizeof(T))) T(); + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); } @@ -436,7 +597,7 @@ class LIBPROTOBUF_EXPORT Arena { template GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal( bool skip_explicit_ownership, const Arg& arg) { - T* t = new (AllocateAligned(sizeof(T))) T(arg); + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); } @@ -446,7 +607,7 @@ class LIBPROTOBUF_EXPORT Arena { template GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal( bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) { - T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2); + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); } @@ -458,7 +619,8 @@ class LIBPROTOBUF_EXPORT Arena { const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { - T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3); + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); } @@ -472,7 +634,79 @@ class LIBPROTOBUF_EXPORT Arena { const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { - T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, arg4); + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3, arg4); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5) { + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3, arg4, arg5); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6) { + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3, arg4, arg5, arg6); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7) { + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3, arg4, arg5, arg6, arg7); + if (!skip_explicit_ownership) { + AddListNode(t, &internal::arena_destruct_object); + } + return t; + } + + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7, + const Arg8& arg8) { + T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) + T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); } @@ -485,6 +719,20 @@ class LIBPROTOBUF_EXPORT Arena { this); } + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg& arg) { + return CreateInternal(SkipDeleteList(static_cast(0)), + this, arg); + } + + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg1& arg1, const Arg2& arg2) { + return CreateInternal(SkipDeleteList(static_cast(0)), + this, arg1, arg2); + } + // CreateInArenaStorage is used to implement map field. Without it, // google::protobuf::Map need to call generated message's protected arena constructor, // which needs to declare google::protobuf::Map as friend of generated message. @@ -536,8 +784,15 @@ class LIBPROTOBUF_EXPORT Arena { return NULL; } + // Allocate and also optionally call on_arena_allocation callback with the + // allocated type info when the hooks are in place in ArenaOptions and + // the cookie is not null. + void* AllocateAligned(const std::type_info* allocated, size_t n); - void* AllocateAligned(size_t size); + // Allocate an internal allocation, avoiding optional typed monitoring. + GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline void* AllocateAligned(size_t n) { + return AllocateAligned(NULL, n); + } void Init(); @@ -596,6 +851,9 @@ class LIBPROTOBUF_EXPORT Arena { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena); }; +// Defined above for supporting environments without RTTI. +#undef RTTI_TYPE_ID + template const typename Arena::is_arena_constructable::type Arena::is_arena_constructable::value = diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py index f390df3681..87a69b2afd 100644 --- a/src/google/protobuf/arena_nc_test.py +++ b/src/google/protobuf/arena_nc_test.py @@ -35,6 +35,7 @@ import unittest from google3.testing.pybase import fake_target_util +import unittest class ArenaNcTest(unittest.TestCase): diff --git a/src/google/protobuf/arena_test_util.h b/src/google/protobuf/arena_test_util.h index 7db7a90e71..690cc706ee 100644 --- a/src/google/protobuf/arena_test_util.h +++ b/src/google/protobuf/arena_test_util.h @@ -31,6 +31,7 @@ #ifndef GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__ #define GOOGLE_PROTOBUF_ARENA_TEST_UTIL_H__ + namespace google { namespace protobuf { namespace internal { diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index d9b198e0a8..873e85ae1a 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -39,6 +39,7 @@ #include #endif #include +#include #include #include @@ -47,11 +48,14 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -125,6 +129,29 @@ class MustBeConstructedWithOneThroughFour { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughFour); }; +// A class that takes eight different types as constructor arguments. +class MustBeConstructedWithOneThroughEight { + public: + MustBeConstructedWithOneThroughEight( + int one, const char* two, const string& three, + const PleaseDontCopyMe* four, int five, const char* six, + const string& seven, const string& eight) + : one_(one), two_(two), three_(three), four_(four), five_(five), + six_(six), seven_(seven), eight_(eight) {} + + int one_; + const char* const two_; + string three_; + const PleaseDontCopyMe* four_; + int five_; + const char* const six_; + string seven_; + string eight_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MustBeConstructedWithOneThroughEight); +}; + } // namespace TEST(ArenaTest, ArenaConstructable) { @@ -156,7 +183,7 @@ TEST(ArenaTest, BasicCreate) { EXPECT_EQ(2, notifier.GetCount()); } -TEST(ArenaTest, CreateWithManyConstructorArguments) { +TEST(ArenaTest, CreateWithFourConstructorArguments) { Arena arena; const string three("3"); const PleaseDontCopyMe four(4); @@ -170,6 +197,26 @@ TEST(ArenaTest, CreateWithManyConstructorArguments) { ASSERT_EQ(4, new_object->four_->value()); } +TEST(ArenaTest, CreateWithEightConstructorArguments) { + Arena arena; + const string three("3"); + const PleaseDontCopyMe four(4); + const string seven("7"); + const string eight("8"); + const MustBeConstructedWithOneThroughEight* new_object = + Arena::Create( + &arena, 1, "2", three, &four, 5, "6", seven, eight); + EXPECT_TRUE(new_object != NULL); + ASSERT_EQ(1, new_object->one_); + ASSERT_STREQ("2", new_object->two_); + ASSERT_EQ("3", new_object->three_); + ASSERT_EQ(4, new_object->four_->value()); + ASSERT_EQ(5, new_object->five_); + ASSERT_STREQ("6", new_object->six_); + ASSERT_EQ("7", new_object->seven_); + ASSERT_EQ("8", new_object->eight_); +} + TEST(ArenaTest, InitialBlockTooSmall) { // Construct a small (64 byte) initial block of memory to be used by the // arena allocator; then, allocate an object which will not fit in the @@ -1113,6 +1160,19 @@ TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) { EXPECT_EQ(NULL, Arena::GetArena(const_pointer_to_message)); } +TEST(ArenaTest, UnsafeSetAllocatedOnArena) { + ::google::protobuf::Arena arena; + TestAllTypes* message = Arena::CreateMessage(&arena); + EXPECT_FALSE(message->has_optional_string()); + + string owned_string = "test with long enough content to heap-allocate"; + message->unsafe_arena_set_allocated_optional_string(&owned_string); + EXPECT_TRUE(message->has_optional_string()); + + message->unsafe_arena_set_allocated_optional_string(NULL); + EXPECT_FALSE(message->has_optional_string()); +} + // A helper utility class to only contain static hook functions, some // counters to be used to verify the counters have been called and a cookie // value to be verified. @@ -1124,6 +1184,13 @@ class ArenaHooksTestUtil { return static_cast(cookie); } + static void on_allocation(const std::type_info* /*unused*/, uint64 alloc_size, + void* cookie) { + ++num_allocations; + int cookie_value = *static_cast(cookie); + EXPECT_EQ(kCookieValue, cookie_value); + } + static void on_reset(::google::protobuf::Arena* arena, void* cookie, uint64 space_used) { ++num_reset; @@ -1141,10 +1208,12 @@ class ArenaHooksTestUtil { static const int kCookieValue = 999; static uint32 num_init; + static uint32 num_allocations; static uint32 num_reset; static uint32 num_destruct; }; uint32 ArenaHooksTestUtil::num_init = 0; +uint32 ArenaHooksTestUtil::num_allocations = 0; uint32 ArenaHooksTestUtil::num_reset = 0; uint32 ArenaHooksTestUtil::num_destruct = 0; const int ArenaHooksTestUtil::kCookieValue; @@ -1153,6 +1222,7 @@ const int ArenaHooksTestUtil::kCookieValue; TEST(ArenaTest, ArenaHooksSanity) { ::google::protobuf::ArenaOptions options; options.on_arena_init = ArenaHooksTestUtil::on_init; + options.on_arena_allocation = ArenaHooksTestUtil::on_allocation; options.on_arena_reset = ArenaHooksTestUtil::on_reset; options.on_arena_destruction = ArenaHooksTestUtil::on_destruction; @@ -1160,6 +1230,9 @@ TEST(ArenaTest, ArenaHooksSanity) { { ::google::protobuf::Arena arena(options); EXPECT_EQ(1, ArenaHooksTestUtil::num_init); + EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations); + ::google::protobuf::Arena::Create(&arena); + EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations); arena.Reset(); arena.Reset(); diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index 321a8ccd25..b989f15132 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -79,6 +79,37 @@ class LIBPROTOC_EXPORT CodeGenerator { GeneratorContext* generator_context, string* error) const = 0; + // Generates code for all given proto files, generating one or more files in + // the given output directory. + // + // This method should be called instead of |Generate()| when + // |HasGenerateAll()| returns |true|. It is used to emulate legacy semantics + // when more than one `.proto` file is specified on one compiler invocation. + // + // WARNING: Please do not use unless legacy semantics force the code generator + // to produce a single output file for all input files, or otherwise require + // an examination of all input files first. The canonical code generator + // design produces one output file per input .proto file, and we do not wish + // to encourage alternate designs. + // + // A parameter is given as passed on the command line, as in |Generate()| + // above. + // + // Returns true if successful. Otherwise, sets *error to a description of + // the problem (e.g. "invalid parameter") and returns false. + virtual bool GenerateAll(const vector& files, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + *error = "Unimplemented GenerateAll() method."; + return false; + } + + // Returns true if the code generator expects to receive all FileDescriptors + // at once (via |GenerateAll()|), rather than one at a time (via + // |Generate()|). This is required to implement legacy semantics. + virtual bool HasGenerateAll() const { return false; } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); }; diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 567238aed1..291fb05473 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -898,12 +898,14 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { return PARSE_ARGUMENT_FAIL; } if (mode_ != MODE_COMPILE && !dependency_out_name_.empty()) { - cerr << "Can only use --dependency_out=FILE when generating code." << endl; + std::cerr << "Can only use --dependency_out=FILE when generating code." + << std::endl; return PARSE_ARGUMENT_FAIL; } if (!dependency_out_name_.empty() && input_files_.size() > 1) { - cerr << "Can only process one input file when using --dependency_out=FILE." - << endl; + std::cerr + << "Can only process one input file when using --dependency_out=FILE." + << std::endl; return PARSE_ARGUMENT_FAIL; } if (imports_in_descriptor_set_ && descriptor_set_name_.empty()) { @@ -1054,11 +1056,11 @@ CommandLineInterface::InterpretArgument(const string& name, } else if (name == "--dependency_out") { if (!dependency_out_name_.empty()) { - cerr << name << " may only be passed once." << endl; + std::cerr << name << " may only be passed once." << std::endl; return PARSE_ARGUMENT_FAIL; } if (value.empty()) { - cerr << name << " requires a non-empty value." << endl; + std::cerr << name << " requires a non-empty value." << std::endl; return PARSE_ARGUMENT_FAIL; } dependency_out_name_ = value; @@ -1272,7 +1274,8 @@ void CommandLineInterface::PrintHelpText() { " defined in the given proto files. Groups share\n" " the same field number space with the parent \n" " message. Extension ranges are counted as \n" -" occupied fields numbers." << std::endl; +" occupied fields numbers." + << std::endl; if (!plugin_prefix_.empty()) { std::cerr << " --plugin=EXECUTABLE Specifies a plugin executable to use.\n" @@ -1327,13 +1330,23 @@ bool CommandLineInterface::GenerateOutput( } parameters.append(generator_parameters_[output_directive.name]); } - for (int i = 0; i < parsed_files.size(); i++) { - if (!output_directive.generator->Generate(parsed_files[i], parameters, - generator_context, &error)) { - // Generator returned an error. - std::cerr << output_directive.name << ": " << parsed_files[i]->name() - << ": " << error << std::endl; - return false; + if (output_directive.generator->HasGenerateAll()) { + if (!output_directive.generator->GenerateAll( + parsed_files, parameters, generator_context, &error)) { + // Generator returned an error. + std::cerr << output_directive.name << ": " + << ": " << error << std::endl; + return false; + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + if (!output_directive.generator->Generate(parsed_files[i], parameters, + generator_context, &error)) { + // Generator returned an error. + std::cerr << output_directive.name << ": " << parsed_files[i]->name() + << ": " << error << std::endl; + return false; + } } } } @@ -1403,7 +1416,8 @@ bool CommandLineInterface::GenerateDependencyManifestFile( printer.Print(" $disk_file$", "disk_file", disk_file); if (i < file_set.file_size() - 1) printer.Print("\\\n"); } else { - cerr << "Unable to identify path for file " << virtual_file << endl; + std::cerr << "Unable to identify path for file " << virtual_file + << std::endl; return false; } } @@ -1673,6 +1687,10 @@ void GatherOccupiedFieldRanges(const Descriptor* descriptor, ranges->insert(FieldRange(descriptor->extension_range(i)->start, descriptor->extension_range(i)->end)); } + for (int i = 0; i < descriptor->reserved_range_count(); ++i) { + ranges->insert(FieldRange(descriptor->reserved_range(i)->start, + descriptor->reserved_range(i)->end)); + } // Handle the nested messages/groups in declaration order to make it // post-order strict. for (int i = 0; i < descriptor->nested_type_count(); ++i) { diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index e284c7915b..23d67e2b8d 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -115,10 +115,15 @@ class CommandLineInterfaceTest : public testing::Test { // Create a subdirectory within temp_directory_. void CreateTempDir(const string& name); +#ifdef PROTOBUF_OPENSOURCE // Change working directory to temp directory. void SwitchToTempDirectory() { File::ChangeWorkingDirectory(temp_directory_); } +#else // !PROTOBUF_OPENSOURCE + // TODO(teboring): Figure out how to change and get working directory in + // google3. +#endif // !PROTOBUF_OPENSOURCE void SetInputsAreProtoPathRelative(bool enable) { cli_.SetInputsAreProtoPathRelative(enable); @@ -986,6 +991,7 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileGivenTwoInputs) { "Can only process one input file when using --dependency_out=FILE.\n"); } +#ifdef PROTOBUF_OPENSOURCE TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" @@ -1011,6 +1017,10 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFile) { File::ChangeWorkingDirectory(current_working_directory); } +#else // !PROTOBUF_OPENSOURCE +// TODO(teboring): Figure out how to change and get working directory in +// google3. +#endif // !PROTOBUF_OPENSOURCE TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { CreateTempFile("foo.proto", diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 3eb20ab136..70d3a60061 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -70,12 +70,23 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} +void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) { + if (!options_.proto_h) { + return; + } + map vars; + vars["classname"] = classname_; + printer->Print(vars, "enum $classname$ : int;\n"); + printer->Print(vars, "bool $classname$_IsValid(int value);\n"); +} + void EnumGenerator::GenerateDefinition(io::Printer* printer) { map vars; vars["classname"] = classname_; vars["short_name"] = descriptor_->name(); + vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); - printer->Print(vars, "enum $classname$ {\n"); + printer->Print(vars, "enum $enumbase$ {\n"); printer->Indent(); const EnumValueDescriptor* min_value = descriptor_->value(0); @@ -90,7 +101,6 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["prefix"] = (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; - if (i > 0) printer->Print(",\n"); printer->Print(vars, "$prefix$$name$ = $number$"); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 1ebd7cf7a4..3e930856bd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -60,6 +60,12 @@ class EnumGenerator { // Header stuff. + // Generate header code to forward-declare the enum. This is for use when + // generating other .proto.h files. This code should be placed within the + // enum's package namespace, but NOT within any class, even for nested + // enums. + void GenerateForwardDeclaration(io::Printer* printer); + // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for // nested enums. diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 749897032e..965327b188 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -242,7 +242,7 @@ void RepeatedEnumFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField $name$_;\n"); - if (descriptor_->options().packed() + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); @@ -352,7 +352,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { - if (!descriptor_->options().packed()) { + if (!descriptor_->is_packed()) { // This path is rarely executed, so we use a non-inlined implementation. if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { printer->Print(variables_, @@ -419,7 +419,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -432,7 +432,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" " this->$name$(i), output);\n"); @@ -446,7 +446,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -460,7 +460,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" " this->$name$(i), target);\n"); @@ -484,7 +484,7 @@ GenerateByteSize(io::Printer* printer) const { " this->$name$(i));\n" "}\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index cd2b6b75be..1d7f823300 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -82,12 +82,38 @@ class FieldGenerator { // implementation is empty. virtual void GenerateStaticMembers(io::Printer* /*printer*/) const {} + // Generate prototypes for accessors that will manipulate imported + // messages inline. These are for .proto.h headers. + // + // In .proto.h mode, the headers of imports are not #included. However, + // functions that manipulate the imported message types need access to + // the class definition of the imported message, meaning that the headers + // must be #included. To get around this, functions that manipulate + // imported message objects are defined as dependent functions in a base + // template class. By making them dependent template functions, the + // function templates will not be instantiated until they are called, so + // we can defer to those translation units to #include the necessary + // generated headers. + // + // See: + // http://en.cppreference.com/w/cpp/language/class_template#Implicit_instantiation + // + // Most field types don't need this, so the default implementation is empty. + virtual void GenerateDependentAccessorDeclarations( + io::Printer* printer) const {} + // Generate prototypes for all of the accessor functions related to this // field. These are placed inside the class definition. virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; + // Generate inline definitions of depenent accessor functions for this field. + // These are placed inside the header after all class definitions. + virtual void GenerateDependentInlineAccessorDefinitions( + io::Printer* printer) const {} + // Generate inline definitions of accessor functions for this field. // These are placed inside the header after all class definitions. + // In non-.proto.h mode, this generates dependent accessor functions as well. virtual void GenerateInlineAccessorDefinitions( io::Printer* printer, bool is_inline) const = 0; diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index a98c7d92e4..b997a51af9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -94,113 +94,10 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} void FileGenerator::GenerateHeader(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); - - // Generate top of header. - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" - "#define PROTOBUF_$filename_identifier$__INCLUDED\n" - "\n" - "#include \n" - "\n", - "filename", file_->name(), - "filename_identifier", filename_identifier); - - - printer->Print( - "#include \n" - "\n"); - - // Verify the protobuf library header version is compatible with the protoc - // version before going any further. - printer->Print( - "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" - "#error This file was generated by a newer version of protoc which is\n" - "#error incompatible with your Protocol Buffer headers. Please update\n" - "#error your headers.\n" - "#endif\n" - "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" - "#error This file was generated by an older version of protoc which is\n" - "#error incompatible with your Protocol Buffer headers. Please\n" - "#error regenerate this file with a newer version of protoc.\n" - "#endif\n" - "\n", - "min_header_version", - SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), - "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); - - // OK, it's now safe to #include other files. - printer->Print( - "#include \n" - "#include \n" - "#include \n"); - if (UseUnknownFieldSet(file_)) { - printer->Print( - "#include \n"); - } - if (file_->message_type_count() > 0) { - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include \n"); - } else { - printer->Print( - "#include \n"); - } - } - printer->Print( - "#include \n" - "#include \n"); - if (HasMapFields(file_)) { - printer->Print( - "#include \n"); - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include \n"); - } else { - printer->Print( - "#include \n"); - } - } - - if (HasEnumDefinitions(file_)) { - if (HasDescriptorMethods(file_)) { - printer->Print( - "#include \n"); - } else { - printer->Print( - "#include \n"); - } - } - - if (HasGenericServices(file_)) { - printer->Print( - "#include \n"); - } - - if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { - printer->Print( - "#include \n"); - } - - - set public_import_names; - for (int i = 0; i < file_->public_dependency_count(); i++) { - public_import_names.insert(file_->public_dependency(i)->name()); - } - - for (int i = 0; i < file_->dependency_count(); i++) { - const string& name = file_->dependency(i)->name(); - bool public_import = (public_import_names.count(name) != 0); + GenerateTopHeaderGuard(printer); - - printer->Print( - "#include \"$dependency$.pb.h\"$iwyu$\n", - "dependency", StripProto(name), - "iwyu", (public_import) ? " // IWYU pragma: export" : ""); - } + GenerateLibraryIncludes(printer); + GenerateDependencyIncludes(printer); printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -210,132 +107,44 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Open namespace. GenerateNamespaceOpeners(printer); - // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile - // functions, so that we can declare them to be friends of each class. - printer->Print( - "\n" - "// Internal implementation detail -- do not call these.\n" - "void $dllexport_decl$$adddescriptorsname$();\n", - "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "dllexport_decl", - options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); - - printer->Print( - // Note that we don't put dllexport_decl on these because they are only - // called by the .pb.cc file in which they are defined. - "void $assigndescriptorsname$();\n" - "void $shutdownfilename$();\n" - "\n", - "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), - "shutdownfilename", GlobalShutdownFileName(file_->name())); - - // Generate forward declarations of classes. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateForwardDeclaration(printer); - } + GenerateGlobalStateFunctionDeclarations(printer); + GenerateMessageForwardDeclarations(printer); printer->Print("\n"); - // Generate enum definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateEnumDefinitions(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { - enum_generators_[i]->GenerateDefinition(printer); - } + GenerateEnumDefinitions(printer); printer->Print(kThickSeparator); printer->Print("\n"); - // Generate class definitions. - for (int i = 0; i < file_->message_type_count(); i++) { - if (i > 0) { - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - message_generators_[i]->GenerateClassDefinition(printer); - } + GenerateMessageDefinitions(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); - if (HasGenericServices(file_)) { - // Generate service definitions. - for (int i = 0; i < file_->service_count(); i++) { - if (i > 0) { - printer->Print("\n"); - printer->Print(kThinSeparator); - printer->Print("\n"); - } - service_generators_[i]->GenerateDeclarations(printer); - } - - printer->Print("\n"); - printer->Print(kThickSeparator); - printer->Print("\n"); - } + GenerateServiceDefinitions(printer); - // Declare extension identifiers. - for (int i = 0; i < file_->extension_count(); i++) { - extension_generators_[i]->GenerateDeclaration(printer); - } + GenerateExtensionIdentifiers(printer); printer->Print("\n"); printer->Print(kThickSeparator); printer->Print("\n"); - printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - // Generate class inline methods. - for (int i = 0; i < file_->message_type_count(); i++) { - if (i > 0) { - printer->Print(kThinSeparator); - printer->Print("\n"); - } - message_generators_[i]->GenerateInlineMethods(printer, - /* is_inline = */ true); - } - printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateInlineFunctionDefinitions(printer); // Close up namespace. GenerateNamespaceClosers(printer); - // Emit GetEnumDescriptor specializations into google::protobuf namespace: - if (HasEnumDefinitions(file_)) { - // The SWIG conditional is to avoid a null-pointer dereference - // (bug 1984964) in swig-1.3.21 resulting from the following syntax: - // namespace X { void Y(); } - // which appears in GetEnumDescriptor() specializations. - printer->Print( - "\n" - "#ifndef SWIG\n" - "namespace google {\nnamespace protobuf {\n" - "\n"); - for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - for (int i = 0; i < file_->enum_type_count(); i++) { - enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); - } - printer->Print( - "\n" - "} // namespace protobuf\n} // namespace google\n" - "#endif // SWIG\n"); - } + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); printer->Print( "\n" "// @@protoc_insertion_point(global_scope)\n" "\n"); - printer->Print( - "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", - "filename_identifier", filename_identifier); + GenerateBottomHeaderGuard(printer); } void FileGenerator::GenerateSource(io::Printer* printer) { @@ -707,6 +516,294 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { } } +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { + string filename_identifier = FilenameIdentifier(file_->name()); + // Generate top of header. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" + "#define PROTOBUF_$filename_identifier$__INCLUDED\n" + "\n" + "#include \n" + "\n", + "filename", file_->name(), + "filename_identifier", filename_identifier); +} + +void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) { + string filename_identifier = FilenameIdentifier(file_->name()); + printer->Print( + "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", + "filename_identifier", filename_identifier); +} + +void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { + + printer->Print( + "#include \n" + "\n"); + + // Verify the protobuf library header version is compatible with the protoc + // version before going any further. + printer->Print( + "#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" + "#error This file was generated by a newer version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please update\n" + "#error your headers.\n" + "#endif\n" + "#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" + "#error This file was generated by an older version of protoc which is\n" + "#error incompatible with your Protocol Buffer headers. Please\n" + "#error regenerate this file with a newer version of protoc.\n" + "#endif\n" + "\n", + "min_header_version", + SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), + "protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); + + // OK, it's now safe to #include other files. + printer->Print( + "#include \n" + "#include \n" + "#include \n"); + if (UseUnknownFieldSet(file_)) { + printer->Print( + "#include \n"); + } + if (file_->message_type_count() > 0) { + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include \n"); + } else { + printer->Print( + "#include \n"); + } + } + printer->Print( + "#include \n" + "#include \n"); + if (HasMapFields(file_)) { + printer->Print( + "#include \n"); + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include \n"); + } else { + printer->Print( + "#include \n"); + } + } + + if (HasEnumDefinitions(file_)) { + if (HasDescriptorMethods(file_)) { + printer->Print( + "#include \n"); + } else { + printer->Print( + "#include \n"); + } + } + + if (HasGenericServices(file_)) { + printer->Print( + "#include \n"); + } + + if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + printer->Print( + "#include \n"); + } + + + if (IsAnyMessage(file_)) { + printer->Print( + "#include \"google/protobuf/any.h\"\n"); + } +} + +void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { + set public_import_names; + for (int i = 0; i < file_->public_dependency_count(); i++) { + public_import_names.insert(file_->public_dependency(i)->name()); + } + + for (int i = 0; i < file_->dependency_count(); i++) { + const string& name = file_->dependency(i)->name(); + bool public_import = (public_import_names.count(name) != 0); + + + printer->Print( + "#include \"$dependency$.pb.h\"$iwyu$\n", + "dependency", StripProto(name), + "iwyu", (public_import) ? " // IWYU pragma: export" : ""); + } +} + +void FileGenerator::GenerateGlobalStateFunctionDeclarations( + io::Printer* printer) { + // Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile + // functions, so that we can declare them to be friends of each class. + printer->Print( + "\n" + "// Internal implementation detail -- do not call these.\n" + "void $dllexport_decl$$adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), + "dllexport_decl", + options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " "); + + printer->Print( + // Note that we don't put dllexport_decl on these because they are only + // called by the .pb.cc file in which they are defined. + "void $assigndescriptorsname$();\n" + "void $shutdownfilename$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), + "shutdownfilename", GlobalShutdownFileName(file_->name())); +} + +void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateMessageForwardDeclaration(printer); + } +} + +void FileGenerator::GenerateMessageDefinitions(io::Printer* printer) { + // Generate class definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + message_generators_[i]->GenerateClassDefinition(printer); + } +} + +void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { + // Generate enum definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateEnumDefinitions(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateDefinition(printer); + } +} + +void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { + if (HasGenericServices(file_)) { + // Generate service definitions. + for (int i = 0; i < file_->service_count(); i++) { + if (i > 0) { + printer->Print("\n"); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + service_generators_[i]->GenerateDeclarations(printer); + } + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + } +} + +void FileGenerator::GenerateExtensionIdentifiers(io::Printer* printer) { + // Declare extension identifiers. + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateDeclaration(printer); + } +} + +void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { + // An aside about inline functions in .proto.h mode: + // + // The PROTOBUF_INLINE_NOT_IN_HEADERS symbol controls conditionally + // moving much of the inline functions to the .pb.cc file, which can be a + // significant performance benefit for compilation time, at the expense + // of non-inline function calls. + // + // However, in .proto.h mode, the definition of the internal dependent + // base class must remain in the header, and can never be out-lined. The + // dependent base class also needs access to has-bit manipuation + // functions, so the has-bit functions must be unconditionally inlined in + // proto_h mode. + // + // This gives us three flavors of functions: + // + // 1. Functions on the message not used by the internal dependent base + // class: in .proto.h mode, only some functions are defined on the + // message class; others are defined on the dependent base class. + // These are guarded and can be out-lined. These are generated by + // GenerateInlineMethods, and include has_* bit functions in + // non-proto_h mode. + // + // 2. Functions on the internal dependent base class: these functions + // are dependent on a template parameter, so they always need to + // remain in the header. + // + // 3. Functions on the message that are used by the dependent base: the + // dependent base class down casts itself to the message + // implementation class to access these functions (the has_* bit + // manipulation functions). Unlike #1, these functions must + // unconditionally remain in the header. These are emitted by + // GenerateDependentInlineMethods, even though they are not actually + // dependent. + + printer->Print("#if !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + // Generate class inline methods. + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print(kThinSeparator); + printer->Print("\n"); + } + message_generators_[i]->GenerateInlineMethods(printer, + /* is_inline = */ true); + } + printer->Print("#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS\n"); + + for (int i = 0; i < file_->message_type_count(); i++) { + if (i > 0) { + printer->Print(kThinSeparator); + printer->Print("\n"); + } + // Methods of the dependent base class must always be inline in the header. + message_generators_[i]->GenerateDependentInlineMethods(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); +} + +void FileGenerator::GenerateProto2NamespaceEnumSpecializations( + io::Printer* printer) { + // Emit GetEnumDescriptor specializations into google::protobuf namespace: + if (HasEnumDefinitions(file_)) { + // The SWIG conditional is to avoid a null-pointer dereference + // (bug 1984964) in swig-1.3.21 resulting from the following syntax: + // namespace X { void Y(); } + // which appears in GetEnumDescriptor() specializations. + printer->Print( + "\n" + "#ifndef SWIG\n" + "namespace google {\nnamespace protobuf {\n" + "\n"); + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); + } + printer->Print( + "\n" + "} // namespace protobuf\n} // namespace google\n" + "#endif // SWIG\n"); + } +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 0e06547d03..e68f67bb53 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -80,6 +80,35 @@ class FileGenerator { void GenerateNamespaceOpeners(io::Printer* printer); void GenerateNamespaceClosers(io::Printer* printer); + // Generates top or bottom of a header file. + void GenerateTopHeaderGuard(io::Printer* printer); + void GenerateBottomHeaderGuard(io::Printer* printer); + + // Generates #include directives. + void GenerateLibraryIncludes(io::Printer* printer); + void GenerateDependencyIncludes(io::Printer* printer); + + // Generates a couple of different pieces before definitions: + void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); + + // Generates types for classes. + void GenerateMessageForwardDeclarations(io::Printer* printer); + void GenerateMessageDefinitions(io::Printer* printer); + + // Generates enum definitions. + void GenerateEnumDefinitions(io::Printer* printer); + + // Generates generic service definitions. + void GenerateServiceDefinitions(io::Printer* printer); + + // Generates extension identifiers. + void GenerateExtensionIdentifiers(io::Printer* printer); + + // Generates inline function defintions. + void GenerateInlineFunctionDefinitions(io::Printer* printer); + + void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); + const FileDescriptor* file_; google::protobuf::scoped_array > message_generators_; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index c999b93f8e..9941637200 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -82,6 +82,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, // } // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or // __declspec(dllimport) depending on what is being compiled. + // Options file_options; for (int i = 0; i < options.size(); i++) { diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 4e7155c33c..0f3688d030 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -51,6 +51,9 @@ namespace cpp { namespace { +static const char kAnyMessageName[] = "Any"; +static const char kAnyProtoFile[] = "google/protobuf/any.proto"; + string DotsToUnderscores(const string& name) { return StringReplace(name, ".", "_", true); } @@ -162,6 +165,10 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } +string DependentBaseClassTemplateName(const Descriptor* descriptor) { + return ClassName(descriptor, false) + "_InternalBase"; +} + string SuperClassName(const Descriptor* descriptor) { return HasDescriptorMethods(descriptor->file()) ? "::google::protobuf::Message" : "::google::protobuf::MessageLite"; @@ -200,6 +207,47 @@ string FieldConstantName(const FieldDescriptor *field) { return result; } +bool IsFieldDependent(const FieldDescriptor* field) { + if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + return false; + } + if (field->containing_oneof() != NULL) { + // Oneof fields will always be dependent. + // + // This is a unique case for field codegen. Field generators are + // responsible for generating all the field-specific accessor + // functions, except for the clear_*() function; instead, field + // generators produce inline clearing code. + // + // For non-oneof fields, the Message class uses the inline clearing + // code to define the field's clear_*() function, as well as in the + // destructor. For oneof fields, the Message class generates a much + // more complicated clear_*() function, which clears only the oneof + // member that is set, in addition to clearing methods for each of the + // oneof members individually. + // + // Since oneofs do not have their own generator class, the Message code + // generation logic would be significantly complicated in order to + // split dependent and non-dependent manipulation logic based on + // whether the oneof truly needs to be dependent; so, for oneof fields, + // we just assume it (and its constituents) should be manipulated by a + // dependent base class function. + // + // This is less precise than how dependent message-typed fields are + // handled, but the cost is limited to only the generated code for the + // oneof field, which seems like an acceptable tradeoff. + return true; + } + if (field->file() == field->message_type()->file()) { + return false; + } + return true; +} + +string DependentTypeName(const FieldDescriptor* field) { + return "InternalBase_" + field->name() + "_T"; +} + string FieldMessageTypeName(const FieldDescriptor* field) { // Note: The Google-internal version of Protocol Buffers uses this function // as a hook point for hacks to support legacy code. @@ -360,7 +408,7 @@ string FilenameIdentifier(const string& filename) { } else { // Not alphanumeric. To avoid any possibility of name conflicts we // use the hex code for the character. - StrAppend(&result, "_", ToHex(static_cast(filename[i]))); + StrAppend(&result, "_", strings::Hex(static_cast(filename[i]))); } } return result; @@ -521,6 +569,15 @@ FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) { } +bool IsAnyMessage(const FileDescriptor* descriptor) { + return descriptor->name() == kAnyProtoFile; +} + +bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->name() == kAnyMessageName && + descriptor->file()->name() == kAnyProtoFile; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 284fa2c1a5..4bbf830345 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -66,6 +66,10 @@ extern const char kThinSeparator[]; string ClassName(const Descriptor* descriptor, bool qualified); string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +// Name of the CRTP class template (for use with proto_h). +// This is a class name, like "ProtoName_InternalBase". +string DependentBaseClassTemplateName(const Descriptor* descriptor); + string SuperClassName(const Descriptor* descriptor); // Get the (unqualified) name that should be used for this field in C++ code. @@ -88,6 +92,20 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { field->extension_scope() : field->containing_type(); } +// Returns true if the given 'field_descriptor' has a message type that is +// a dependency of the file where the field is defined (i.e., the field +// type is defined in a different file than the message holding the field). +// +// This only applies to Message-typed fields. Enum-typed fields may refer +// to an enum in a dependency; however, enums are specified and +// forward-declared with an enum-base, so the definition is not required to +// manipulate the field value. +bool IsFieldDependent(const FieldDescriptor* field_descriptor); + +// Returns the name that should be used for forcing dependent lookup from a +// dependent base class. +string DependentTypeName(const FieldDescriptor* field); + // Returns the fully-qualified type name field->message_type(). Usually this // is just ClassName(field->message_type(), true); string FieldMessageTypeName(const FieldDescriptor* field); @@ -242,6 +260,9 @@ inline bool SupportsArenas(const FieldDescriptor* field) { return SupportsArenas(field->file()); } +bool IsAnyMessage(const FileDescriptor* descriptor); +bool IsAnyMessage(const Descriptor* descriptor); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 8c38db2b36..0ff0d27c3a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -244,7 +244,8 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n"); + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { @@ -277,7 +278,8 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n"); + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { @@ -312,7 +314,8 @@ GenerateByteSize(io::Printer* printer) const { "{\n" " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n" " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = $name$().begin(); it != $name$().end(); ++it) {\n"); + " it = this->$name$().begin();\n" + " it != this->$name$().end(); ++it) {\n"); // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 98929b1e90..212fe2e1b7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -64,10 +64,15 @@ using internal::WireFormatLite; namespace { -void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { - // Print the field's proto-syntax definition as a comment. We don't want to - // print group bodies so we cut off after the first line. - string def = field->DebugString(); +template +void PrintFieldComment(io::Printer* printer, const T* field) { + // Print the field's (or oneof's) proto-syntax definition as a comment. + // We don't want to print group bodies so we cut off after the first + // line. + DebugStringOptions options; + options.elide_group_body = true; + options.elide_oneof_body = true; + string def = field->DebugStringWithOptions(options); printer->Print("// $def$\n", "def", def.substr(0, def.find_first_of('\n'))); } @@ -280,6 +285,10 @@ void OptimizePadding(vector* fields) { } } +string MessageTypeProtoName(const FieldDescriptor* field) { + return field->message_type()->full_name(); +} + // Emits an if-statement with a condition that evaluates to true if |field| is // considered non-default (will be sent over the wire), for message types // without true field presence. Should only be called if @@ -379,7 +388,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, enum_generators_( new google::protobuf::scoped_ptr[descriptor->enum_type_count()]), extension_generators_(new google::protobuf::scoped_ptr< - ExtensionGenerator>[descriptor->extension_count()]) { + ExtensionGenerator>[descriptor->extension_count()]), + use_dependent_base_(false) { for (int i = 0; i < descriptor->nested_type_count(); i++) { nested_generators_[i].reset( @@ -401,13 +411,16 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, if (descriptor->field(i)->is_required()) { ++num_required_fields_; } + if (options.proto_h && IsFieldDependent(descriptor->field(i))) { + use_dependent_base_ = true; + } } } MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -GenerateForwardDeclaration(io::Printer* printer) { +GenerateMessageForwardDeclaration(io::Printer* printer) { printer->Print("class $classname$;\n", "classname", classname_); @@ -416,7 +429,17 @@ GenerateForwardDeclaration(io::Printer* printer) { // message cannot be a top level class, we just need to avoid calling // GenerateForwardDeclaration here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateForwardDeclaration(printer); + nested_generators_[i]->GenerateMessageForwardDeclaration(printer); + } +} + +void MessageGenerator:: +GenerateEnumForwardDeclaration(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateEnumForwardDeclaration(printer); + } + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + enum_generators_[i]->GenerateForwardDeclaration(printer); } } @@ -441,6 +464,35 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { } } +void MessageGenerator:: +GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + map vars; + SetCommonFieldVariables(field, &vars, options_); + + if (use_dependent_base_ && IsFieldDependent(field)) { + // If the message is dependent, the inline clear_*() method will need + // to delete the message type, so it must be in the dependent base + // class. (See also GenerateFieldAccessorDeclarations.) + printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + } + // Generate type-specific accessor declarations. + field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); + printer->Print("\n"); + } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + const OneofDescriptor* oneof = descriptor_->oneof_decl(i); + PrintFieldComment(printer, oneof); + printer->Print( + "void clear_$oneof_name$();\n", + "oneof_name", oneof->name()); + } +} + void MessageGenerator:: GenerateFieldAccessorDeclarations(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { @@ -452,6 +504,19 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); + bool dependent_field = use_dependent_base_ && IsFieldDependent(field); + if (dependent_field) { + // If this field is dependent, the dependent base class determines + // the message type from the derived class (which is a template + // parameter). This typedef is for that: + printer->Print( + "private:\n" + "typedef $field_type$ $dependent_type$;\n" + "public:\n", + "field_type", FieldMessageTypeName(field), + "dependent_type", DependentTypeName(field)); + } + if (field->is_repeated()) { printer->Print(vars, "int $name$_size() const$deprecation$;\n"); } else if (HasHasMethod(field)) { @@ -463,7 +528,11 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { "public:\n"); } - printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + if (!dependent_field) { + // If this field is dependent, then its clear_() method is in the + // depenent base class. (See also GenerateDependentAccessorDeclarations.) + printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + } printer->Print(vars, "static const int $constant_name$ = $number$;\n"); // Generate type-specific accessor declarations. @@ -489,6 +558,188 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } } +void MessageGenerator:: +GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { + if (!use_dependent_base_) return; + + printer->Print("// $classname$\n\n", "classname", + DependentBaseClassTemplateName(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + PrintFieldComment(printer, field); + + // These functions are not really dependent: they are part of the + // (non-dependent) derived class. However, they need to live outside + // any #ifdef guards, so we treat them as if they were dependent. + // + // See the comment in FileGenerator::GenerateInlineFunctionDefinitions + // for a more complete explanation. + if (use_dependent_base_ && IsFieldDependent(field)) { + map vars; + SetCommonFieldVariables(field, &vars, options_); + vars["inline"] = "inline "; + if (field->containing_oneof()) { + vars["field_name"] = UnderscoresToCamelCase(field->name(), true); + vars["oneof_name"] = field->containing_oneof()->name(); + vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); + GenerateOneofMemberHasBits(field, vars, printer); + } else if (!field->is_repeated()) { + // There will be no header guard, so this always has to be inline. + GenerateSingularFieldHasBits(field, vars, printer); + } + // vars needed for clear_(), which is in the dependent base: + // (See also GenerateDependentFieldAccessorDeclarations.) + vars["tmpl"] = "template\n"; + vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + ""; + vars["this_message"] = "reinterpret_cast(this)->"; + vars["this_const_message"] = "reinterpret_cast(this)->"; + GenerateFieldClear(field, vars, printer); + } + + // Generate type-specific accessors. + field_generators_.get(field) + .GenerateDependentInlineAccessorDefinitions(printer); + + printer->Print("\n"); + } + + // Generate has_$name$() and clear_has_$name$() functions for oneofs + // Similar to other has-bits, these must always be in the header if we + // are using a dependent base class. + GenerateOneofHasBits(printer, true /* is_inline */); +} + +void MessageGenerator:: +GenerateSingularFieldHasBits(const FieldDescriptor* field, + map vars, + io::Printer* printer) { + if (HasFieldPresence(descriptor_->file())) { + // N.B.: without field presence, we do not use has-bits or generate + // has_$name$() methods. + vars["has_array_index"] = SimpleItoa(field->index() / 32); + vars["has_mask"] = StrCat(strings::Hex(1u << (field->index() % 32), + strings::Hex::ZERO_PAD_8)); + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" + "}\n" + "$inline$" + "void $classname$::set_has_$name$() {\n" + " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" + "}\n" + "$inline$" + "void $classname$::clear_has_$name$() {\n" + " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" + "}\n"); + } else { + // Message fields have a has_$name$() method. + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + bool is_lazy = false; + if (is_lazy) { + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return !$name$_.IsCleared();\n" + "}\n"); + } else { + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return !_is_default_instance_ && $name$_ != NULL;\n" + "}\n"); + } + } + } +} + +void MessageGenerator:: +GenerateOneofHasBits(io::Printer* printer, bool is_inline) { + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + map vars; + vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + vars["cap_oneof_name"] = + ToUpper(descriptor_->oneof_decl(i)->name()); + vars["classname"] = classname_; + vars["inline"] = (is_inline ? "inline " : ""); + printer->Print( + vars, + "$inline$" + "bool $classname$::has_$oneof_name$() const {\n" + " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" + "}\n" + "$inline$" + "void $classname$::clear_has_$oneof_name$() {\n" + " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" + "}\n"); + } +} + +void MessageGenerator:: +GenerateOneofMemberHasBits(const FieldDescriptor* field, + const map& vars, + io::Printer* printer) { + // Singular field in a oneof + // N.B.: Without field presence, we do not use has-bits or generate + // has_$name$() methods, but oneofs still have set_has_$name$(). + // Oneofs also have has_$name$() but only as a private helper + // method, so that generated code is slightly cleaner (vs. comparing + // _oneof_case_[index] against a constant everywhere). + printer->Print(vars, + "$inline$" + "bool $classname$::has_$name$() const {\n" + " return $oneof_name$_case() == k$field_name$;\n" + "}\n"); + printer->Print(vars, + "$inline$" + "void $classname$::set_has_$name$() {\n" + " _oneof_case_[$oneof_index$] = k$field_name$;\n" + "}\n"); +} + +void MessageGenerator:: +GenerateFieldClear(const FieldDescriptor* field, + const map& vars, + io::Printer* printer) { + // Generate clear_$name$() (See GenerateFieldAccessorDeclarations and + // GenerateDependentFieldAccessorDeclarations, $dependent_classname$ is + // set by the Generate*Definitions functions.) + printer->Print(vars, + "$tmpl$" + "$inline$" + "void $dependent_classname$::clear_$name$() {\n"); + + printer->Indent(); + + if (field->containing_oneof()) { + // Clear this field only if it is the active field in this oneof, + // otherwise ignore + printer->Print(vars, + "if ($this_message$has_$name$()) {\n"); + printer->Indent(); + field_generators_.get(field).GenerateClearingCode(printer); + printer->Print(vars, + "$this_message$clear_has_$oneof_name$();\n"); + printer->Outdent(); + printer->Print("}\n"); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + if (HasFieldPresence(descriptor_->file())) { + if (!field->is_repeated()) { + printer->Print(vars, + "$this_message$clear_has_$name$();\n"); + } + } + } + + printer->Outdent(); + printer->Print("}\n"); +} + void MessageGenerator:: GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { printer->Print("// $classname$\n\n", "classname", classname_); @@ -500,101 +751,37 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { map vars; SetCommonFieldVariables(field, &vars, options_); - vars["inline"] = is_inline ? "inline" : ""; + vars["inline"] = is_inline ? "inline " : ""; // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { printer->Print(vars, - "$inline$ int $classname$::$name$_size() const {\n" + "$inline$" + "int $classname$::$name$_size() const {\n" " return $name$_.size();\n" "}\n"); } else if (field->containing_oneof()) { - // Singular field in a oneof - // N.B.: Without field presence, we do not use has-bits or generate - // has_$name$() methods, but oneofs still have set_has_$name$(). - // Oneofs also have has_$name$() but only as a private helper - // method, so that generated code is slightly cleaner (vs. comparing - // _oneof_case_[index] against a constant everywhere). vars["field_name"] = UnderscoresToCamelCase(field->name(), true); vars["oneof_name"] = field->containing_oneof()->name(); vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index()); - printer->Print(vars, - "$inline$ bool $classname$::has_$name$() const {\n" - " return $oneof_name$_case() == k$field_name$;\n" - "}\n"); - printer->Print(vars, - "$inline$ void $classname$::set_has_$name$() {\n" - " _oneof_case_[$oneof_index$] = k$field_name$;\n" - "}\n"); + if (!use_dependent_base_ || !IsFieldDependent(field)) { + GenerateOneofMemberHasBits(field, vars, printer); + } } else { // Singular field. - if (HasFieldPresence(descriptor_->file())) { - // N.B.: without field presence, we do not use has-bits or generate - // has_$name$() methods. - char buffer[kFastToBufferSize]; - vars["has_array_index"] = SimpleItoa(field->index() / 32); - vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), - buffer); - printer->Print(vars, - "$inline$ bool $classname$::has_$name$() const {\n" - " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n" - "}\n" - "$inline$ void $classname$::set_has_$name$() {\n" - " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n" - "}\n" - "$inline$ void $classname$::clear_has_$name$() {\n" - " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n" - "}\n" - ); - } else { - // Message fields have a has_$name$() method. - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - bool is_lazy = false; - if (is_lazy) { - printer->Print(vars, - "$inline$ bool $classname$::has_$name$() const {\n" - " return !$name$_.IsCleared();\n" - "}\n"); - } else { - printer->Print(vars, - "$inline$ bool $classname$::has_$name$() const {\n" - " return !_is_default_instance_ && $name$_ != NULL;\n" - "}\n"); - } - } + if (!use_dependent_base_ || !IsFieldDependent(field)) { + GenerateSingularFieldHasBits(field, vars, printer); } } - // Generate clear_$name$() - printer->Print(vars, - "$inline$ void $classname$::clear_$name$() {\n"); - - printer->Indent(); - - if (field->containing_oneof()) { - // Clear this field only if it is the active field in this oneof, - // otherwise ignore - printer->Print(vars, - "if (has_$name$()) {\n"); - printer->Indent(); - field_generators_.get(field).GenerateClearingCode(printer); - printer->Print(vars, - "clear_has_$oneof_name$();\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - field_generators_.get(field).GenerateClearingCode(printer); - if (HasFieldPresence(descriptor_->file())) { - if (!field->is_repeated()) { - printer->Print(vars, - "clear_has_$name$();\n"); - } - } + if (!use_dependent_base_ || !IsFieldDependent(field)) { + vars["tmpl"] = ""; + vars["dependent_classname"] = vars["classname"]; + vars["this_message"] = ""; + vars["this_const_message"] = ""; + GenerateFieldClear(field, vars, printer); } - printer->Outdent(); - printer->Print("}\n"); - // Generate type-specific accessors. field_generators_.get(field).GenerateInlineAccessorDefinitions(printer, is_inline); @@ -602,23 +789,11 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { printer->Print("\n"); } - // Generate has_$name$() and clear_has_$name$() functions for oneofs - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - map vars; - vars["oneof_name"] = descriptor_->oneof_decl(i)->name(); - vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); - vars["cap_oneof_name"] = - ToUpper(descriptor_->oneof_decl(i)->name()); - vars["classname"] = classname_; - vars["inline"] = is_inline ? "inline" : ""; - printer->Print( - vars, - "$inline$ bool $classname$::has_$oneof_name$() const {\n" - " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" - "}\n" - "$inline$ void $classname$::clear_has_$oneof_name$() {\n" - " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" - "}\n"); + if (!use_dependent_base_) { + // Generate has_$name$() and clear_has_$name$() functions for oneofs + // If we aren't using a dependent base, they can be with the other functions + // that are #ifdef-guarded. + GenerateOneofHasBits(printer, is_inline); } } @@ -647,6 +822,34 @@ static bool CanClearByZeroing(const FieldDescriptor* field) { } } +void MessageGenerator:: +GenerateDependentBaseClassDefinition(io::Printer* printer) { + if (!use_dependent_base_) { + return; + } + + map vars; + vars["classname"] = DependentBaseClassTemplateName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_); + + printer->Print(vars, + "template \n" + "class $classname$ : public $superclass$ {\n" + " public:\n"); + printer->Indent(); + + printer->Print(vars, + "$classname$() {}\n" + "virtual ~$classname$() {}\n" + "\n"); + + // Generate dependent accessor methods for all fields. + GenerateDependentFieldAccessorDeclarations(printer); + + printer->Outdent(); + printer->Print("};\n"); +} + void MessageGenerator:: GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -660,6 +863,11 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print("\n"); } + if (use_dependent_base_) { + GenerateDependentBaseClassDefinition(printer); + printer->Print("\n"); + } + map vars; vars["classname"] = classname_; vars["field_count"] = SimpleItoa(descriptor_->field_count()); @@ -669,11 +877,18 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = options_.dllexport_decl + " "; } - vars["superclass"] = SuperClassName(descriptor_); - + if (use_dependent_base_) { + vars["superclass"] = + DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; + } else { + vars["superclass"] = SuperClassName(descriptor_); + } printer->Print(vars, - "class $dllexport$$classname$ : public $superclass$ {\n" - " public:\n"); + "class $dllexport$$classname$ : public $superclass$ {\n"); + if (use_dependent_base_) { + printer->Print(vars, " friend class $superclass$;\n"); + } + printer->Print(" public:\n"); printer->Indent(); printer->Print(vars, @@ -782,6 +997,19 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(vars, "void UnsafeArenaSwap($classname$* other);\n"); } + + if (IsAnyMessage(descriptor_)) { + printer->Print(vars, + "// implements Any -----------------------------------------------\n" + "\n" + "void PackFrom(const ::google::protobuf::Message& message);\n" + "bool UnpackTo(::google::protobuf::Message* message) const;\n" + "template bool Is() const {\n" + " return _any_metadata_.Is();\n" + "}\n" + "\n"); + } + printer->Print(vars, "void Swap($classname$* other);\n" "\n" @@ -973,11 +1201,18 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); + if (use_dependent_base_) { + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); + } else { + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "void clear_$oneof_name$();\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); + } } if (HasGeneratedMethods(descriptor_->file()) && @@ -1139,6 +1374,12 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } + // Generate _any_metadata_ for the Any type. + if (IsAnyMessage(descriptor_)) { + printer->Print(vars, + "::google::protobuf::internal::AnyMetadata _any_metadata_;\n"); + } + // Declare AddDescriptors(), BuildDescriptors(), and ShutdownFile() as // friends so that they can access private static variables like // default_instance_ and reflection_. @@ -1171,6 +1412,21 @@ GenerateClassDefinition(io::Printer* printer) { GOOGLE_DCHECK(!need_to_emit_cached_size); } +void MessageGenerator:: +GenerateDependentInlineMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // map entry message doesn't need inline methods. Since map entry message + // cannot be a top level class, we just need to avoid calling + // GenerateInlineMethods here. + if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; + nested_generators_[i]->GenerateDependentInlineMethods(printer); + printer->Print(kThinSeparator); + printer->Print("\n"); + } + + GenerateDependentFieldAccessorDefinitions(printer); +} + void MessageGenerator:: GenerateInlineMethods(io::Printer* printer, bool is_inline) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -1196,7 +1452,8 @@ GenerateInlineMethods(io::Printer* printer, bool is_inline) { vars["inline"] = is_inline ? "inline " : ""; printer->Print( vars, - "$inline$$class_name$::$camel_oneof_name$Case $class_name$::" + "$inline$" + "$class_name$::$camel_oneof_name$Case $class_name$::" "$oneof_name$_case() const {\n" " return $class_name$::$camel_oneof_name$Case(" "_oneof_case_[$oneof_index$]);\n" @@ -1494,6 +1751,19 @@ GenerateShutdownCode(io::Printer* printer) { void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { + if (IsAnyMessage(descriptor_)) { + printer->Print( + "void $classname$::PackFrom(const ::google::protobuf::Message& message) {\n" + " _any_metadata_.PackFrom(message);\n" + "}\n" + "\n" + "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" + " return _any_metadata_.UnpackTo(message);\n" + "}\n" + "\n", + "classname", classname_); + } + for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators_[i]->GenerateMethods(printer); } @@ -1767,7 +2037,7 @@ GenerateArenaDestructorCode(io::Printer* printer) { if (need_registration) { printer->Print( "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" - " if (arena != NULL) {" + " if (arena != NULL) {\n" " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" " }\n" "}\n", @@ -1782,18 +2052,23 @@ GenerateArenaDestructorCode(io::Printer* printer) { void MessageGenerator:: GenerateStructors(io::Printer* printer) { - string superclass = SuperClassName(descriptor_); - string initializer_with_arena; - if (UseUnknownFieldSet(descriptor_->file())) { - initializer_with_arena = "_internal_metadata_(arena)"; + string superclass; + if (use_dependent_base_) { + superclass = + DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - initializer_with_arena = "_arena_ptr_(arena)"; + superclass = SuperClassName(descriptor_); } + string initializer_with_arena = superclass + "()"; + if (descriptor_->extension_range_count() > 0) { - initializer_with_arena = string("\n _extensions_(arena)") + - (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena; + initializer_with_arena += ",\n _extensions_(arena)"; + } + + if (UseUnknownFieldSet(descriptor_->file())) { + initializer_with_arena += ",\n _internal_metadata_(arena)"; } else { - initializer_with_arena = "\n " + initializer_with_arena; + initializer_with_arena += ",\n _arena_ptr_(arena)"; } // Initialize member variables with arena constructor. @@ -1804,16 +2079,21 @@ GenerateStructors(io::Printer* printer) { FieldName(descriptor_->field(i)) + string("_(arena)"); } } - initializer_with_arena = superclass + "()" + - (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena; + + if (IsAnyMessage(descriptor_)) { + initializer_with_arena += ",\n _any_metadata_(&type_url, &value_)"; + } string initializer_null; initializer_null = (UseUnknownFieldSet(descriptor_->file()) ? - ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)"); + ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)"); + if (IsAnyMessage(descriptor_)) { + initializer_null += ", _any_metadata_(&type_url_, &value_)"; + } printer->Print( "$classname$::$classname$()\n" - " : $superclass$() $initializer$ {\n" + " : $superclass$()$initializer$ {\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", @@ -1894,10 +2174,14 @@ GenerateStructors(io::Printer* printer) { "full_name", descriptor_->full_name()); if (UseUnknownFieldSet(descriptor_->file())) { printer->Print( - ",\n _internal_metadata_(NULL) {\n"); + ",\n _internal_metadata_(NULL)"); } else if (!UseUnknownFieldSet(descriptor_->file())) { - printer->Print(",\n _arena_ptr_(NULL) {\n"); + printer->Print(",\n _arena_ptr_(NULL)"); } + if (IsAnyMessage(descriptor_)) { + printer->Print(",\n _any_metadata_(&type_url_, &value_)"); + } + printer->Print(" {\n"); printer->Print( " SharedCtor();\n" " MergeFrom(from);\n" @@ -2124,7 +2408,11 @@ GenerateClear(io::Printer* printer) { have_enclosing_if = true; } - field_generators_.get(field).GenerateClearingCode(printer); + if (use_dependent_base_ && IsFieldDependent(field)) { + printer->Print("clear_$name$();\n", "name", fieldname); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + } if (have_enclosing_if) { printer->Outdent(); @@ -2147,7 +2435,11 @@ GenerateClear(io::Printer* printer) { const FieldDescriptor* field = descriptor_->field(i); if (field->is_repeated()) { - field_generators_.get(field).GenerateClearingCode(printer); + if (use_dependent_base_ && IsFieldDependent(field)) { + printer->Print("clear_$name$();\n", "name", FieldName(field)); + } else { + field_generators_.get(field).GenerateClearingCode(printer); + } } } @@ -2184,19 +2476,38 @@ void MessageGenerator:: GenerateOneofClear(io::Printer* printer) { // Generated function clears the active field and union case (e.g. foo_case_). for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "void $classname$::clear_$oneofname$() {\n", - "classname", classname_, - "oneofname", descriptor_->oneof_decl(i)->name()); + map oneof_vars; + oneof_vars["classname"] = classname_; + oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); + string message_class; + + if (use_dependent_base_) { + oneof_vars["tmpl"] = "template\n"; + oneof_vars["inline"] = "inline "; + oneof_vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + ""; + oneof_vars["this_message"] = "reinterpret_cast(this)->"; + message_class = "T::"; + } else { + oneof_vars["tmpl"] = ""; + oneof_vars["inline"] = ""; + oneof_vars["dependent_classname"] = classname_; + oneof_vars["this_message"] = ""; + } + + printer->Print(oneof_vars, + "$tmpl$" + "$inline$" + "void $dependent_classname$::clear_$oneofname$() {\n"); printer->Indent(); - printer->Print( - "switch($oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); + printer->Print(oneof_vars, + "switch($this_message$$oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "case k$field_name$: {\n", + "case $message_class$k$field_name$: {\n", + "message_class", message_class, "field_name", UnderscoresToCamelCase(field->name(), true)); printer->Indent(); // We clear only allocated objects in oneofs @@ -2213,16 +2524,20 @@ GenerateOneofClear(io::Printer* printer) { "}\n"); } printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" + "case $message_class$$cap_oneof_name$_NOT_SET: {\n" " break;\n" "}\n", + "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n" - "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", + "$this_message$_oneof_case_[$oneof_index$] = " + "$message_class$$cap_oneof_name$_NOT_SET;\n", + "this_message", oneof_vars["this_message"], "oneof_index", SimpleItoa(i), + "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); @@ -2333,9 +2648,9 @@ GenerateMergeFrom(io::Printer* printer) { // system, as the GOOGLE_CHECK above ensured that we have the same descriptor // for each message. printer->Print( - "const $classname$* source =\n" - " ::google::protobuf::internal::dynamic_cast_if_available(\n" - " &from);\n" + "const $classname$* source = \n" + " ::google::protobuf::internal::DynamicCastToGenerated(\n" + " &from);\n" "if (source == NULL) {\n" " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" "} else {\n" @@ -2585,8 +2900,24 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Indent(); + // Find repeated messages and groups now, to simplify what follows. + hash_set fields_with_parse_loop; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = ordered_fields[i]; + if (field->is_repeated() && + (field->type() == FieldDescriptor::TYPE_MESSAGE || + field->type() == FieldDescriptor::TYPE_GROUP)) { + fields_with_parse_loop.insert(i); + } + } + + // need_label is true if we generated "goto parse_$name$" while handling the + // previous field. + bool need_label = false; for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = ordered_fields[i]; + const bool loops = fields_with_parse_loop.count(i) > 0; + const bool next_field_loops = fields_with_parse_loop.count(i + 1) > 0; PrintFieldComment(printer, field); @@ -2600,9 +2931,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("if (tag == $commontag$) {\n", "commontag", SimpleItoa(WireFormat::MakeTag(field))); - if (i > 0 || (field->is_repeated() && !field->options().packed())) { + if (need_label || + (field->is_repeated() && !field->options().packed() && !loops)) { + printer->Print( + " parse_$name$:\n", + "name", field->name()); + } + if (loops) { printer->Print( - " parse_$name$:\n", + " DO_(input->IncrementRecursionDepth());\n" + " parse_loop_$name$:\n", "name", field->name()); } @@ -2644,26 +2982,53 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. - if (field->is_repeated() && !field->options().packed()) { - // Expect repeats of this field. + // For non-packed repeated fields, expect the same tag again. + if (loops) { + printer->Print( + "if (input->ExpectTag($tag$)) goto parse_loop_$name$;\n", + "tag", SimpleItoa(WireFormat::MakeTag(field)), + "name", field->name()); + } else if (field->is_repeated() && !field->options().packed()) { printer->Print( "if (input->ExpectTag($tag$)) goto parse_$name$;\n", "tag", SimpleItoa(WireFormat::MakeTag(field)), "name", field->name()); } - if (i + 1 < descriptor_->field_count()) { - // Expect the next field in order. - const FieldDescriptor* next_field = ordered_fields[i + 1]; - printer->Print( - "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", - "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), - "next_name", next_field->name()); - } else { - // Expect EOF. - // TODO(kenton): Expect group end-tag? + // Have we emitted "if (input->ExpectTag($next_tag$)) ..." yet? + bool emitted_goto_next_tag = false; + + // For repeated messages/groups, we need to decrement recursion depth, + // unless the next tag is also for a repeated message/group. + if (loops) { + if (next_field_loops) { + const FieldDescriptor* next_field = ordered_fields[i + 1]; + printer->Print( + "if (input->ExpectTag($next_tag$)) goto parse_loop_$next_name$;\n", + "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), + "next_name", next_field->name()); + emitted_goto_next_tag = true; + } printer->Print( - "if (input->ExpectAtEnd()) goto success;\n"); + "input->UnsafeDecrementRecursionDepth();\n"); + } + + // If there are more fields, expect the next one. + need_label = false; + if (!emitted_goto_next_tag) { + if (i + 1 == descriptor_->field_count()) { + // Expect EOF. + // TODO(kenton): Expect group end-tag? + printer->Print( + "if (input->ExpectAtEnd()) goto success;\n"); + } else { + const FieldDescriptor* next_field = ordered_fields[i + 1]; + printer->Print( + "if (input->ExpectTag($next_tag$)) goto parse_$next_name$;\n", + "next_tag", SimpleItoa(WireFormat::MakeTag(next_field)), + "next_name", next_field->name()); + need_label = true; + } } printer->Print( @@ -2999,9 +3364,7 @@ static string ConditionalToCheckBitmasks(const vector& masks) { vector parts; for (int i = 0; i < masks.size(); i++) { if (masks[i] == 0) continue; - char buffer[kFastToBufferSize]; - FastHex32ToBuffer(masks[i], buffer); - string m = StrCat("0x", buffer); + string m = StrCat("0x", strings::Hex(masks[i], strings::Hex::ZERO_PAD_8)); // Each xor evaluates to 0 if the expected bits are present. parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")")); } @@ -3293,11 +3656,10 @@ GenerateIsInitialized(io::Printer* printer) { } if (mask != 0) { - char buffer[kFastToBufferSize]; printer->Print( "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n", "i", SimpleItoa(i), - "mask", FastHex32ToBuffer(mask, buffer)); + "mask", StrCat(strings::Hex(mask, strings::Hex::ZERO_PAD_8))); } } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index ea96581df9..23dad10c1d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -67,7 +67,8 @@ class MessageGenerator { // Header stuff. // Generate foward declarations for this class and all its nested types. - void GenerateForwardDeclaration(io::Printer* printer); + void GenerateMessageForwardDeclaration(io::Printer* printer); + void GenerateEnumForwardDeclaration(io::Printer* printer); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). @@ -84,6 +85,9 @@ class MessageGenerator { // file). void GenerateInlineMethods(io::Printer* printer, bool is_inline); + // Dependent methods are always inline. + void GenerateDependentInlineMethods(io::Printer* printer); + // Source file stuff. // Generate code which declares all the global descriptor pointers which @@ -115,7 +119,10 @@ class MessageGenerator { private: // Generate declarations and definitions of accessors for fields. + void GenerateDependentBaseClassDefinition(io::Printer* printer); + void GenerateDependentFieldAccessorDeclarations(io::Printer* printer); void GenerateFieldAccessorDeclarations(io::Printer* printer); + void GenerateDependentFieldAccessorDefinitions(io::Printer* printer); void GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline); // Generate the field offsets array. @@ -158,6 +165,21 @@ class MessageGenerator { bool unbounded); + // Generates has_foo() functions and variables for singular field has-bits. + void GenerateSingularFieldHasBits(const FieldDescriptor* field, + map vars, + io::Printer* printer); + // Generates has_foo() functions and variables for oneof field has-bits. + void GenerateOneofHasBits(io::Printer* printer, bool is_inline); + // Generates has_foo_bar() functions for oneof members. + void GenerateOneofMemberHasBits(const FieldDescriptor* field, + const map& vars, + io::Printer* printer); + // Generates the clear_foo() method for a field. + void GenerateFieldClear(const FieldDescriptor* field, + const map& vars, + io::Printer* printer); + const Descriptor* descriptor_; string classname_; Options options_; @@ -168,6 +190,7 @@ class MessageGenerator { google::protobuf::scoped_array > extension_generators_; int num_required_fields_; bool uses_string_; + bool use_dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 467b6bf6e3..ba318d10bc 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -72,7 +72,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MessageFieldGenerator:: MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -83,6 +84,10 @@ GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "$type$* $name$_;\n"); } +void MessageFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { +} + void MessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { @@ -144,6 +149,8 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " return temp;\n" "}\n"); if (SupportsArenas(descriptor_->message_type())) { + // NOTE: the same logic is mirrored in weak_message_field.cc. Any + // arena-related semantics changes should be made in both places. printer->Print(variables_, "void $classname$::_slow_set_allocated_$name$(\n" " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n" @@ -180,6 +187,10 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( } } +void MessageFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { @@ -294,7 +305,7 @@ GenerateClearingCode(io::Printer* printer) const { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. printer->Print(variables_, - "if ($name$_ != NULL) delete $name$_;\n" + "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n" "$name$_ = NULL;\n"); } else { printer->Print(variables_, @@ -365,6 +376,10 @@ MessageOneofFieldGenerator(const FieldDescriptor* descriptor, MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} +void MessageOneofFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { @@ -559,6 +574,10 @@ GeneratePrivateMembers(io::Printer* printer) const { "::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n"); } +void RepeatedMessageFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { +} + void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, @@ -572,6 +591,10 @@ GenerateAccessorDeclarations(io::Printer* printer) const { " mutable_$name$()$deprecation$;\n"); } +void RepeatedMessageFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +} + void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { @@ -627,11 +650,13 @@ void RepeatedMessageFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadMessageNoVirtualNoRecursionDepth(\n" " input, add_$name$()));\n"); } else { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" + "DO_(::google::protobuf::internal::WireFormatLite::" + "ReadGroupNoVirtualNoRecursionDepth(\n" " $number$, input, add_$name$()));\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index c1704fc1ae..9ddf964395 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -52,7 +52,9 @@ class MessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; @@ -67,6 +69,7 @@ class MessageFieldGenerator : public FieldGenerator { protected: const FieldDescriptor* descriptor_; + const bool dependent_field_; map variables_; private: @@ -80,6 +83,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {} @@ -99,7 +103,9 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const; + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateAccessorDeclarations(io::Printer* printer) const; + void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; void GenerateClearingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 0c99cff187..4463f20060 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -41,12 +41,13 @@ namespace protobuf { namespace compiler { namespace cpp { -// Generator options: +// Generator options (see generator.cc for a description of each): struct Options { - Options() : safe_boundary_check(false) { + Options() : safe_boundary_check(false), proto_h(false) { } string dllexport_decl; bool safe_boundary_check; + bool proto_h; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 329eae32f3..9f929d378b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -262,7 +262,7 @@ RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); - if (descriptor->options().packed()) { + if (descriptor->is_packed()) { variables_["packed_reader"] = "ReadPackedPrimitive"; variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; } else { @@ -277,7 +277,7 @@ void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); - if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -364,7 +364,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -377,7 +377,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" " this->$name$(i), output);\n"); @@ -391,7 +391,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" @@ -405,7 +405,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::\n" " Write$declared_type$NoTagToArray(this->$name$(i), target);\n"); @@ -435,7 +435,7 @@ GenerateByteSize(io::Printer* printer) const { "data_size = $fixed_size$ * this->$name$_size();\n"); } - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 1a1bcd3d2e..1a3896a15b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -226,7 +226,6 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " } else {\n" " $clear_hasbit$\n" " }\n" - " $set_hasbit$\n" " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" " $name$, GetArenaNoVirtual());\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto index 9f63155b41..4e25b2ea8f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto +++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto @@ -131,23 +131,23 @@ message TestConflictingSymbolNamesExtension { // NO_PROTO3 } // NO_PROTO3 } // NO_PROTO3 -message TestConflictingEnumNames { - enum NestedConflictingEnum { - and = 1; - class = 2; - int = 3; - typedef = 4; - XOR = 5; - } - - optional NestedConflictingEnum conflicting_enum = 1; -} - -enum ConflictingEnum { - NOT_EQ = 1; - volatile = 2; - return = 3; -} +message TestConflictingEnumNames { // NO_PROTO3 + enum NestedConflictingEnum { // NO_PROTO3 + and = 1; // NO_PROTO3 + class = 2; // NO_PROTO3 + int = 3; // NO_PROTO3 + typedef = 4; // NO_PROTO3 + XOR = 5; // NO_PROTO3 + } // NO_PROTO3 + + optional NestedConflictingEnum conflicting_enum = 1; // NO_PROTO3 +} // NO_PROTO3 + +enum ConflictingEnum { // NO_PROTO3 + NOT_EQ = 1; // NO_PROTO3 + volatile = 2; // NO_PROTO3 + return = 3; // NO_PROTO3 +} // NO_PROTO3 message DummyMessage {} diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 9d14a924f0..b11fb21af2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -941,6 +941,22 @@ TEST(GeneratedMessageTest, ExtensionConstantValues) { EXPECT_EQ(unittest::kRepeatedNestedEnumExtensionFieldNumber, 51); } +TEST(GeneratedMessageTest, ParseFromTruncated) { + const string long_string = string(128, 'q'); + FileDescriptorProto p; + p.add_extension()->set_name(long_string); + const string msg = p.SerializeAsString(); + int successful_count = 0; + for (int i = 0; i <= msg.size(); i++) { + if (p.ParseFromArray(msg.c_str(), i)) { + ++successful_count; + } + } + // We don't really care about how often we succeeded. + // As long as we didn't crash, we're happy. + EXPECT_GE(successful_count, 1); +} + // =================================================================== TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) { diff --git a/src/google/protobuf/compiler/cpp/test_large_enum_value.proto b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto new file mode 100644 index 0000000000..cb6ca1b151 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/test_large_enum_value.proto @@ -0,0 +1,43 @@ +// 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. + +// Test that proto2 compiler can generate valid code when the enum value +// is INT_MAX. Note that this is a compile-only test and this proto is not +// referenced in any C++ code. +syntax = "proto2"; + +package protobuf_unittest; + +message TestLargeEnumValue { + enum EnumWithLargeValue { + VALUE_1 = 1; + VALUE_MAX = 0x7fffffff; + } +} diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 71a2ba4bd8..39318a192a 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -67,7 +67,13 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_number"] = SimpleItoa( descriptor->default_value_enum()->number()); - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + if (descriptor->is_packed()) { + (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag( + descriptor->number(), + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + } else { + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + } (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported @@ -641,7 +647,7 @@ GenerateMembers(io::Printer* printer) const { "}\n"); } - if (descriptor_->options().packed() && + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); @@ -884,7 +890,7 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (get$capitalized_name$List().size() > 0) {\n" " output.writeRawVarint32($tag$);\n" @@ -915,7 +921,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { "}\n"); printer->Print( "size += dataSize;\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (!get$capitalized_name$List().isEmpty()) {" " size += $tag_size$;\n" @@ -928,7 +934,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } // cache the data size for packed fields. - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc new file mode 100644 index 0000000000..697a07a733 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -0,0 +1,967 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +void SetEnumVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->enum_type()); + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->enum_type()); + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_number"] = SimpleItoa( + descriptor->default_value_enum()->number()); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + + (*variables)["default"] + ".getNumber()"; + } + + // For repeated builders, the underlying list tracks mutability state. + (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()"; + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); + + if (SupportUnknownEnumValue(descriptor->file())) { + (*variables)["unknown"] = (*variables)["type"] + ".UNRECOGNIZED"; + } else { + (*variables)["unknown"] = (*variables)["default"]; + } +} + +} // namespace + +// =================================================================== + +ImmutableEnumFieldLiteGenerator:: +ImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {} + +int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const { + return 1; +} + +int ImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value();\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private int $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return $name$_;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " $type$ result = $type$.valueOf($name$_);\n" + " return result == null ? $unknown$ : result;\n" + "}\n"); + + // Generate private setters for the builder to proxy into. + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$Value(int value) {\n" + " $set_has_field_bit_message$" + " $name$_ = value;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $set_has_field_bit_message$\n" + " $name$_ = value.getNumber();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n" + " $name$_ = $default_number$;\n" + "}\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return instance.get$capitalized_name$Value();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(int value);\n" + " return this;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for enums +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default_number$;\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "if (other.$name$_ != $default_number$) {\n" + " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" + "}\n"); + } else { + GOOGLE_LOG(FATAL) << "Can't reach here."; + } +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + // noop for scalars +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$set_has_field_bit_message$\n" + "$name$_ = rawValue;\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_has_field_bit_message$\n" + " $name$_ = rawValue;\n" + "}\n"); + } +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for enums +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.writeEnum($number$, $name$_);\n" + "}\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSize($number$, $name$_);\n" + "}\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && $name$_ == other.$name$_;\n"); +} + +void ImmutableEnumFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + $name$_;\n"); +} + +string ImmutableEnumFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +// =================================================================== + +ImmutableEnumOneofFieldLiteGenerator:: +ImmutableEnumOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableEnumFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableEnumOneofFieldLiteGenerator:: +~ImmutableEnumOneofFieldLiteGenerator() {} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " if ($has_oneof_case_message$) {\n" + " return (java.lang.Integer) $oneof_name$_;\n" + " }\n" + " return $default_number$;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " return $default$;\n" + "}\n"); + + // Generate private setters for the builder to proxy into. + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$Value(int value) {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value.getNumber();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value() {\n" + " return instance.get$capitalized_name$Value();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(value);\n" + " return this;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); + } else { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); + } +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = rawValue;\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = rawValue;\n" + "}\n"); + } +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeEnum($number$, ((java.lang.Integer) $oneof_name$_));\n" + "}\n"); +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSize($number$, ((java.lang.Integer) $oneof_name$_));\n" + "}\n"); +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "result = result && get$capitalized_name$Value()\n" + " == other.get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); + } +} + +void ImmutableEnumOneofFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$Value();\n"); + } else { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().getNumber();\n"); + } +} + +// =================================================================== + +RepeatedImmutableEnumFieldLiteGenerator:: +RepeatedImmutableEnumFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableEnumFieldLiteGenerator:: +~RepeatedImmutableEnumFieldLiteGenerator() {} + +int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableEnumFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List\n" + "get$capitalized_name$ValueList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Value(int index);\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + // TODO(dweis): Switch to IntList? + "private com.google.protobuf.Internal.ProtobufList<\n" + " java.lang.Integer> $name$_;\n" + "private static final com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$> $name$_converter_ =\n" + " new com.google.protobuf.Internal.ListAdapter.Converter<\n" + " java.lang.Integer, $type$>() {\n" + " public $type$ convert(java.lang.Integer from) {\n" + " $type$ result = $type$.valueOf(from);\n" + " return result == null ? $unknown$ : result;\n" + " }\n" + " };\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" + " return new com.google.protobuf.Internal.ListAdapter<\n" + " java.lang.Integer, $type$>($name$_, $name$_converter_);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return $name$_converter_.convert($name$_.get(index));\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List\n" + "get$capitalized_name$ValueList() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + } + + if (descriptor_->options().packed() && + HasGeneratedMethods(descriptor_->containing_type())) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } + + // Generate private setters for the builder to proxy into. + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$is_mutable$) {\n" + " $name$_ = newProtobufList($name$_);\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value.getNumber());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value.getNumber());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for ($type$ value : values) {\n" + " $name$_.add(value.getNumber());\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = emptyProtobufList();\n" + "}\n"); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$Value(\n" + " int index, int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$Value(int value) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$Value(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (int value : values) {\n" + " $name$_.add(value);\n" + " }\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" + " return instance.get$capitalized_name$List();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List\n" + "get$capitalized_name$ValueList() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$ValueList());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Value(int index) {\n" + " return instance.get$capitalized_name$Value(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Value(\n" + " int index, int value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Value(index, value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$Value(int value) {\n" + " instance.add$capitalized_name$Value(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$Value(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$Value(values);\n" + " return this;\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for enums +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = emptyProtobufList();\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.makeImmutable();\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + // Read and store the enum + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "if (!$is_mutable$) {\n" + " $name$_ = newProtobufList();\n" + "}\n" + "$name$_.add(rawValue);\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.valueOf(rawValue);\n" + "if (value == null) {\n"); + if (PreserveUnknownFields(descriptor_->containing_type())) { + printer->Print(variables_, + " unknownFields.mergeVarintField($number$, rawValue);\n"); + } + printer->Print(variables_, + "} else {\n" + " if (!$is_mutable$) {\n" + " $name$_ = newProtobufList();\n" + " }\n" + " $name$_.add(rawValue);\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Wrap GenerateParsingCode's contents with a while loop. + + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + + GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_mutable$) {\n" + " $name$_.makeImmutable();\n" + "}\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n" + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeEnumNoTag($name$_.get(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeEnum($number$, $name$_.get(i));\n" + "}\n"); + } +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .computeEnumSizeNoTag($name$_.get(i));\n" + "}\n"); + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeRawVarint32Size(dataSize);\n" + "}"); + } else { + printer->Print(variables_, + "size += $tag_size$ * $name$_.size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && $name$_.equals(other.$name$_);\n"); +} + +void RepeatedImmutableEnumFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + $name$_.hashCode();\n" + "}\n"); +} + +string RepeatedImmutableEnumFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->enum_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h new file mode 100644 index 0000000000..2c41c3e4cd --- /dev/null +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h @@ -0,0 +1,159 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableEnumFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableEnumFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + protected: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumFieldLiteGenerator); +}; + +class ImmutableEnumOneofFieldLiteGenerator + : public ImmutableEnumFieldLiteGenerator { + public: + ImmutableEnumOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableEnumOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableEnumOneofFieldLiteGenerator); +}; + +class RepeatedImmutableEnumFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableEnumFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableEnumFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableEnumFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index af9978e287..3f0fa11fe3 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -42,12 +42,18 @@ #include #include #include +#include #include #include +#include #include +#include #include +#include #include +#include #include +#include #include #include #include @@ -133,6 +139,79 @@ ImmutableFieldGenerator* MakeImmutableGenerator( } } +ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( + const FieldDescriptor* field, int messageBitIndex, int builderBitIndex, + Context* context) { + if (field->is_repeated()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsMapEntry(field->message_type())) { + return new ImmutableMapFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + if (IsLazy(field)) { + return new RepeatedImmutableLazyMessageFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new RepeatedImmutableMessageFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } + case JAVATYPE_ENUM: + return new RepeatedImmutableEnumFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new RepeatedImmutableStringFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new RepeatedImmutablePrimitiveFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + if (field->containing_oneof()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsLazy(field)) { + return new ImmutableLazyMessageOneofFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new ImmutableMessageOneofFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new ImmutableEnumOneofFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringOneofFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new ImmutablePrimitiveOneofFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } else { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + if (IsLazy(field)) { + return new ImmutableLazyMessageFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } else { + return new ImmutableMessageFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + case JAVATYPE_ENUM: + return new ImmutableEnumFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + case JAVATYPE_STRING: + return new ImmutableStringFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + default: + return new ImmutablePrimitiveFieldLiteGenerator( + field, messageBitIndex, builderBitIndex, context); + } + } + } +} + static inline void ReportUnexpectedPackedFieldsCall(io::Printer* printer) { // Reaching here indicates a bug. Cases are: @@ -153,6 +232,13 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { ReportUnexpectedPackedFieldsCall(printer); } +ImmutableFieldLiteGenerator::~ImmutableFieldLiteGenerator() {} + +void ImmutableFieldLiteGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + ReportUnexpectedPackedFieldsCall(printer); +} + // =================================================================== template <> @@ -178,6 +264,28 @@ FieldGeneratorMap::FieldGeneratorMap( template<> FieldGeneratorMap::~FieldGeneratorMap() {} +template <> +FieldGeneratorMap::FieldGeneratorMap( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), + field_generators_(new google::protobuf::scoped_ptr< + ImmutableFieldLiteGenerator>[descriptor->field_count()]) { + // Construct all the FieldGenerators and assign them bit indices for their + // bit fields. + int messageBitIndex = 0; + int builderBitIndex = 0; + for (int i = 0; i < descriptor->field_count(); i++) { + ImmutableFieldLiteGenerator* generator = MakeImmutableLiteGenerator( + descriptor->field(i), messageBitIndex, builderBitIndex, context); + field_generators_[i].reset(generator); + messageBitIndex += generator->GetNumBitsForMessage(); + builderBitIndex += generator->GetNumBitsForBuilder(); + } +} + +template<> +FieldGeneratorMap::~FieldGeneratorMap() {} + void SetCommonFieldVariables(const FieldDescriptor* descriptor, const FieldGeneratorInfo* info, diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 1cf360c111..00f3c601e8 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -83,7 +83,6 @@ class ImmutableFieldGenerator { virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer) const = 0; - virtual void GenerateStaticInitializationCode(io::Printer* printer) const {} virtual void GenerateEqualsCode(io::Printer* printer) const = 0; virtual void GenerateHashCode(io::Printer* printer) const = 0; @@ -94,6 +93,37 @@ class ImmutableFieldGenerator { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldGenerator); }; +class ImmutableFieldLiteGenerator { + public: + ImmutableFieldLiteGenerator() {} + virtual ~ImmutableFieldLiteGenerator(); + + virtual int GetNumBitsForMessage() const = 0; + virtual int GetNumBitsForBuilder() const = 0; + virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0; + virtual void GenerateMembers(io::Printer* printer) const = 0; + virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) + const = 0; + virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; + virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0; + virtual void GenerateSerializationCode(io::Printer* printer) const = 0; + virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; + virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer) + const = 0; + + virtual void GenerateEqualsCode(io::Printer* printer) const = 0; + virtual void GenerateHashCode(io::Printer* printer) const = 0; + + virtual string GetBoxedType() const = 0; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableFieldLiteGenerator); +}; + // Convenience class which constructs FieldGenerators for a Descriptor. template diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 4a1f452988..68b47ee1cb 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -35,10 +35,10 @@ #include #include -#include #ifndef _SHARED_PTR_H #include #endif +#include #include #include @@ -153,6 +153,12 @@ void CollectExtensions(const FileDescriptorProto& file_proto, } } +// Compare two field descriptors, returning true if the first should come +// before the second. +bool CompareFieldsByName(const FieldDescriptor *a, const FieldDescriptor *b) { + return a->full_name() < b->full_name(); +} + // Our static initialization methods can become very, very large. // So large that if we aren't careful we end up blowing the JVM's // 64K bytes of bytecode/method. Fortunately, since these static @@ -166,7 +172,6 @@ void MaybeRestartJavaMethod(io::Printer* printer, int *method_num, const char *chain_statement, const char *method_decl) { - // The goal here is to stay under 64K bytes of jvm bytecode/method, // since otherwise we hit a hardcoded limit in the jvm and javac will // then fail with the error "code too large". This limit lets our @@ -184,6 +189,7 @@ void MaybeRestartJavaMethod(io::Printer* printer, } } + } // namespace FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc index 2d1437f08d..92ef851b8d 100644 --- a/src/google/protobuf/compiler/java/java_generator_factory.cc +++ b/src/google/protobuf/compiler/java/java_generator_factory.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include namespace google { @@ -57,7 +58,12 @@ ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {} MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator( const Descriptor* descriptor) const { - return new ImmutableMessageGenerator(descriptor, context_); + if (descriptor->file()->options().optimize_for() == + FileOptions::LITE_RUNTIME) { + return new ImmutableMessageLiteGenerator(descriptor, context_); + } else { + return new ImmutableMessageGenerator(descriptor, context_); + } } ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 62efbefa17..96d2545f31 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -196,12 +196,6 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { FileOptions::LITE_RUNTIME; } -inline bool HasNestedBuilders(const Descriptor* descriptor) { - // The proto-lite version doesn't support nested builders. - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; -} - // Should we generate generic services for this file? inline bool HasGenericServices(const FileDescriptor *file) { return file->service_count() > 0 && @@ -330,6 +324,10 @@ inline bool IsMapEntry(const Descriptor* descriptor) { return descriptor->options().map_entry(); } +inline bool IsMapField(const FieldDescriptor* descriptor) { + return descriptor->is_map(); +} + inline bool PreserveUnknownFields(const Descriptor* descriptor) { return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc index 6e29a40bf8..0de8cbe529 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc +++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc @@ -72,14 +72,12 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n" - "}\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" - " return $name$_;\n" - "}\n"); - } + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " return $name$_;\n" + "}\n"); } void ImmutableLazyMessageFieldGenerator:: @@ -92,14 +90,12 @@ GenerateBuilderMembers(io::Printer* printer) const { "private com.google.protobuf.LazyFieldLite $name$_ =\n" " new com.google.protobuf.LazyFieldLite();\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, - // If this builder is non-null, it is used and the other fields are - // ignored. - "private com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" - "\n"); - } + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); // The comments above the methods below are based on a hypothetical // field of type "Field" called "Field". @@ -179,39 +175,37 @@ GenerateBuilderMembers(io::Printer* printer) const { "$clear_has_field_bit_builder$;\n" "return this;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" - " $set_has_field_bit_builder$;\n" - " $on_changed$\n" - " return get$capitalized_name$FieldBuilder().getBuilder();\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" - " if ($name$Builder_ != null) {\n" - " return $name$Builder_.getMessageOrBuilder();\n" - " } else {\n" - " return $name$_;\n" - " }\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "private com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> \n" - " get$capitalized_name$FieldBuilder() {\n" - " if ($name$Builder_ == null) {\n" - " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder>(\n" - " $name$_,\n" - " getParentForChildren(),\n" - " isClean());\n" - " $name$_ = null;\n" - " }\n" - " return $name$Builder_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" + " $set_has_field_bit_builder$;\n" + " $on_changed$\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " return $name$_;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); } @@ -538,14 +532,12 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n" "\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, - // If this builder is non-null, it is used and the other fields are - // ignored. - "private com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" - "\n"); - } + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" + "\n"); // The comments above the methods below are based on a hypothetical // repeated field of type "Field" called "RepeatedField". @@ -723,70 +715,68 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" - " int index) {\n" - " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" - " int index) {\n" - " if ($name$Builder_ == null) {\n" - " return $name$_.get(index);" - " } else {\n" - " return $name$Builder_.getMessageOrBuilder(index);\n" - " }\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " if ($name$Builder_ == null) {\n" + " return $name$_.get(index);" + " } else {\n" + " return $name$Builder_.getMessageOrBuilder(index);\n" + " }\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public java.util.List \n" - " get$capitalized_name$OrBuilderList() {\n" - " if ($name$Builder_ != null) {\n" - " return $name$Builder_.getMessageOrBuilderList();\n" - " } else {\n" - " return java.util.Collections.unmodifiableList($name$_);\n" - " }\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List \n" + " get$capitalized_name$OrBuilderList() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilderList();\n" + " } else {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + " }\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" - " return get$capitalized_name$FieldBuilder().addBuilder(\n" - " $type$.getDefaultInstance());\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" - " int index) {\n" - " return get$capitalized_name$FieldBuilder().addBuilder(\n" - " index, $type$.getDefaultInstance());\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public java.util.List<$type$.Builder> \n" - " get$capitalized_name$BuilderList() {\n" - " return get$capitalized_name$FieldBuilder().getBuilderList();\n" - "}\n" - "private com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> \n" - " get$capitalized_name$FieldBuilder() {\n" - " if ($name$Builder_ == null) {\n" - " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder>(\n" - " $name$_,\n" - " $get_mutable_bit_builder$,\n" - " getParentForChildren(),\n" - " isClean());\n" - " $name$_ = null;\n" - " }\n" - " return $name$Builder_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " index, $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$.Builder> \n" + " get$capitalized_name$BuilderList() {\n" + " return get$capitalized_name$FieldBuilder().getBuilderList();\n" + "}\n" + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " $get_mutable_bit_builder$,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); } void RepeatedImmutableLazyMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc new file mode 100644 index 0000000000..283ba1d3bb --- /dev/null +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc @@ -0,0 +1,708 @@ +// 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. + +// Author: niwasaki@google.com (Naoki Iwasaki) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableLazyMessageFieldLiteGenerator:: +ImmutableLazyMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableMessageFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { +} + +ImmutableLazyMessageFieldLiteGenerator:: +~ImmutableLazyMessageFieldLiteGenerator() {} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.LazyFieldLite $name$_ =\n" + " new com.google.protobuf.LazyFieldLite();\n"); + + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return ($type$) $name$_.getValue($type$.getDefaultInstance());\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $name$_.setValue(value);\n" + " $set_has_field_bit_message$;\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " $name$_.setValue(builderForValue.build());\n" + " $set_has_field_bit_message$;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void merge$capitalized_name$($type$ value) {\n" + " if ($get_has_field_bit_message$ &&\n" + " !$name$_.containsDefaultInstance()) {\n" + " $name$_.setValue(\n" + " $type$.newBuilder(\n" + " get$capitalized_name$()).mergeFrom(value).buildPartial());\n" + " } else {\n" + " $name$_.setValue(value);\n" + " }\n" + " $set_has_field_bit_message$;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_.clear();\n" + " $clear_has_field_bit_message$;\n" + "}\n"); +} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_.clear();\n"); +} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " $name$_.merge(other.$name$_);\n" + " $set_has_field_bit_message$;\n" + "}\n"); +} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.setByteString(input.readBytes(), extensionRegistry);\n"); + printer->Print(variables_, + "$set_has_field_bit_message$;\n"); +} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + // Do not de-serialize lazy fields. + printer->Print(variables_, + "if ($get_has_field_bit_message$) {\n" + " output.writeBytes($number$, $name$_.toByteString());\n" + "}\n"); +} + +void ImmutableLazyMessageFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has_field_bit_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, $name$_);\n" + "}\n"); +} + +// =================================================================== + +ImmutableLazyMessageOneofFieldLiteGenerator:: +ImmutableLazyMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableLazyMessageFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); + variables_["lazy_type"] = "com.google.protobuf.LazyFieldLite"; +} + +ImmutableLazyMessageOneofFieldLiteGenerator:: +~ImmutableLazyMessageOneofFieldLiteGenerator() {} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) (($lazy_type$) $oneof_name$_).getValue(\n" + " $type$.getDefaultInstance());\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + " }\n" + " (($lazy_type$) $oneof_name$_).setValue(value);\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + " }\n" + " (($lazy_type$) $oneof_name$_).setValue(builderForValue.build());\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void merge$capitalized_name$($type$ value) {\n" + " if ($has_oneof_case_message$ &&\n" + " !(($lazy_type$) $oneof_name$_).containsDefaultInstance()) {\n" + " (($lazy_type$) $oneof_name$_).setValue(\n" + " $type$.newBuilder(\n" + " get$capitalized_name$()).mergeFrom(value).buildPartial());\n" + " } else {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + " $set_oneof_case_message$;\n" + " }\n" + " (($lazy_type$) $oneof_name$_).setValue(value);\n" + " }\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + "}\n" + "(($lazy_type$) $oneof_name$_).merge(\n" + " ($lazy_type$) other.$oneof_name$_);\n" + "$set_oneof_case_message$;\n"); +} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = new $lazy_type$();\n" + "}\n" + "(($lazy_type$) $oneof_name$_).setByteString(\n" + " input.readBytes(), extensionRegistry);\n" + "$set_oneof_case_message$;\n"); +} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + // Do not de-serialize lazy fields. + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeBytes(\n" + " $number$, (($lazy_type$) $oneof_name$_).toByteString());\n" + "}\n"); +} + +void ImmutableLazyMessageOneofFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, ($lazy_type$) $oneof_name$_);\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableLazyMessageFieldLiteGenerator:: +RepeatedImmutableLazyMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : RepeatedImmutableMessageFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { +} + + +RepeatedImmutableLazyMessageFieldLiteGenerator:: +~RepeatedImmutableLazyMessageFieldLiteGenerator() {} + +void RepeatedImmutableLazyMessageFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.Internal.ProtobufList<\n" + " com.google.protobuf.LazyFieldLite> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$>\n" + " get$capitalized_name$List() {\n" + " java.util.List<$type$> list =\n" + " new java.util.ArrayList<$type$>($name$_.size());\n" + " for (com.google.protobuf.LazyFieldLite lf : $name$_) {\n" + " list.add(($type$) lf.getValue($type$.getDefaultInstance()));\n" + " }\n" + // TODO(dweis): Make this list immutable? + " return list;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List\n" + " get$capitalized_name$OrBuilderList() {\n" + " return get$capitalized_name$List();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return ($type$)\n" + " $name$_.get(index).getValue($type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " return ($type$OrBuilder)\n" + " $name$_.get(index).getValue($type$.getDefaultInstance());\n" + "}\n"); + + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$is_mutable$) {\n" + " $name$_ = newProtobufList($name$_);\n" + " }\n" + "}\n" + "\n"); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(\n" + " index, com.google.protobuf.LazyFieldLite.fromValue(value));\n" + "}\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "}\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(value));\n" + "}\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(\n" + " index, com.google.protobuf.LazyFieldLite.fromValue(value));\n" + "}\n"); + + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "}\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(index, com.google.protobuf.LazyFieldLite.fromValue(\n" + " builderForValue.build()));\n" + "}\n"); + + // Builder addAllRepeatedField(Iterable values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " for (com.google.protobuf.MessageLite v : values) {\n" + " $name$_.add(com.google.protobuf.LazyFieldLite.fromValue(v));\n" + " }\n" + "}\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = emptyProtobufList();\n" + "}\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void remove$capitalized_name$(int index) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.remove(index);\n" + "}\n"); +} + +void RepeatedImmutableLazyMessageFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // List getRepeatedFieldList() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + + // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + + // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index, builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addAllRepeatedField(Iterable values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder remove$capitalized_name$(int index) {\n" + " copyOnWrite();\n" + " instance.remove$capitalized_name$(index);\n" + " return this;\n" + "}\n"); +} + +void RepeatedImmutableLazyMessageFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ = newProtobufList();\n" + "}\n" + "$name$_.add(new com.google.protobuf.LazyFieldLite(\n" + " extensionRegistry, input.readBytes()));\n"); +} + +void RepeatedImmutableLazyMessageFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeBytes($number$, $name$_.get(i).toByteString());\n" + "}\n"); +} + +void RepeatedImmutableLazyMessageFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeLazyFieldSize($number$, $name$_.get(i));\n" + "}\n"); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h new file mode 100644 index 0000000000..e85ec0f35a --- /dev/null +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h @@ -0,0 +1,118 @@ +// 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. + +// Author: niwasaki@google.com (Naoki Iwasaki) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__ + +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableLazyMessageFieldLiteGenerator + : public ImmutableMessageFieldLiteGenerator { + public: + explicit ImmutableLazyMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableLazyMessageFieldLiteGenerator(); + + // overroads ImmutableMessageFieldLiteGenerator ------------------------------ + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageFieldLiteGenerator); +}; + +class ImmutableLazyMessageOneofFieldLiteGenerator + : public ImmutableLazyMessageFieldLiteGenerator { + public: + ImmutableLazyMessageOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableLazyMessageOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableLazyMessageOneofFieldLiteGenerator); +}; + +class RepeatedImmutableLazyMessageFieldLiteGenerator + : public RepeatedImmutableMessageFieldLiteGenerator { + public: + explicit RepeatedImmutableLazyMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableLazyMessageFieldLiteGenerator(); + + // overroads RepeatedImmutableMessageFieldLiteGenerator ---------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableLazyMessageFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_LAZY_MESSAGE_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index cf1ef5890c..f25970e565 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -133,9 +133,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["set_mutable_bit_parser"] = GenerateSetBitMutableLocal(builderBitIndex); + (*variables)["default_entry"] = (*variables)["capitalized_name"] + + "DefaultEntryHolder.defaultEntry"; if (HasDescriptorMethods(descriptor->file())) { (*variables)["lite"] = ""; - (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry"; + (*variables)["map_field_parameter"] = (*variables)["default_entry"]; (*variables)["descriptor"] = name_resolver->GetImmutableClassName(descriptor->file()) + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + @@ -197,27 +199,21 @@ GenerateInterfaceMembers(io::Printer* printer) const { } } -void ImmutableMapFieldGenerator:: -GenerateStaticInitializationCode(io::Printer* printer) const { - printer->Print( - variables_, - "$name$DefaultEntry =\n" - " com.google.protobuf.MapEntry$lite$\n" - " .<$type_parameters$>newDefaultInstance(\n" - " $descriptor$\n" - " $key_wire_type$,\n" - " $key_default_value$,\n" - " $value_wire_type$,\n" - " $value_default_value$);\n" - "\n"); -} - void ImmutableMapFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print( variables_, - "private static final com.google.protobuf.MapEntry$lite$<\n" - " $type_parameters$> $name$DefaultEntry;\n"); + "private static final class $capitalized_name$DefaultEntryHolder {\n" + " static final com.google.protobuf.MapEntry$lite$<\n" + " $type_parameters$> defaultEntry =\n" + " com.google.protobuf.MapEntry$lite$\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $descriptor$\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n" + "}\n"); printer->Print( variables_, "private com.google.protobuf.MapField$lite$<\n" @@ -291,7 +287,10 @@ GenerateBuilderMembers(io::Printer* printer) const { " if ($name$_ == null) {\n" " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n" " $map_field_parameter$);\n" - " }\n" + " }\n" + " if (!$name$_.isMutable()) {\n" + " $name$_ = $name$_.copy();\n" + " }\n" " return $name$_;\n" "}\n"); if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { @@ -381,10 +380,8 @@ void ImmutableMapFieldGenerator:: GenerateBuildingCode(io::Printer* printer) const { printer->Print( variables_, - // We do a copy of the map field to ensure that the built result is - // immutable. Implementation of this copy() method can do copy-on-write - // to defer this copy until further modifications are made on the field. - "result.$name$_ = internalGet$capitalized_name$().copy();\n"); + "result.$name$_ = internalGet$capitalized_name$();\n" + "result.$name$_.makeImmutable();\n"); } void ImmutableMapFieldGenerator:: @@ -402,7 +399,7 @@ GenerateParsingCode(io::Printer* printer) const { variables_, "com.google.protobuf.ByteString bytes = input.readBytes();\n" "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" - "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n"); + "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" @@ -415,7 +412,7 @@ GenerateParsingCode(io::Printer* printer) const { variables_, "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" "$name$ = input.readMessage(\n" - " $name$DefaultEntry.getParserForType(), extensionRegistry);\n" + " $default_entry$.getParserForType(), extensionRegistry);\n" "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"); } } @@ -432,7 +429,7 @@ GenerateSerializationCode(io::Printer* printer) const { "for (java.util.Map.Entry<$type_parameters$> entry\n" " : internalGet$capitalized_name$().getMap().entrySet()) {\n" " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" - " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " $name$ = $default_entry$.newBuilderForType()\n" " .setKey(entry.getKey())\n" " .setValue(entry.getValue())\n" " .build();\n" @@ -447,7 +444,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { "for (java.util.Map.Entry<$type_parameters$> entry\n" " : internalGet$capitalized_name$().getMap().entrySet()) {\n" " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" - " $name$ = $name$DefaultEntry.newBuilderForType()\n" + " $name$ = $default_entry$.newBuilderForType()\n" " .setKey(entry.getKey())\n" " .setValue(entry.getValue())\n" " .build();\n" diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h index 3e6dd97313..80a94f4568 100644 --- a/src/google/protobuf/compiler/java/java_map_field.h +++ b/src/google/protobuf/compiler/java/java_map_field.h @@ -60,7 +60,6 @@ class ImmutableMapFieldGenerator : public ImmutableFieldGenerator { void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; - void GenerateStaticInitializationCode(io::Printer* printer) const; void GenerateEqualsCode(io::Printer* printer) const; void GenerateHashCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc new file mode 100644 index 0000000000..ccc1b32e72 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -0,0 +1,461 @@ +// 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. + +#include + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + +string TypeName(const FieldDescriptor* field, + ClassNameResolver* name_resolver, + bool boxed) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { + return name_resolver->GetImmutableClassName(field->message_type()); + } else if (GetJavaType(field) == JAVATYPE_ENUM) { + return name_resolver->GetImmutableClassName(field->enum_type()); + } else { + return boxed ? BoxedPrimitiveTypeName(GetJavaType(field)) + : PrimitiveTypeName(GetJavaType(field)); + } +} + +string WireType(const FieldDescriptor* field) { + return "com.google.protobuf.WireFormat.FieldType." + + string(FieldTypeName(field->type())); +} + +void SetMessageVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); + (*variables)["key_type"] = TypeName(key, name_resolver, false); + (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true); + (*variables)["key_wire_type"] = WireType(key); + (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver); + if (GetJavaType(value) == JAVATYPE_ENUM) { + // We store enums as Integers internally. + (*variables)["value_type"] = "int"; + (*variables)["boxed_value_type"] = "java.lang.Integer"; + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver) + ".getNumber()"; + + (*variables)["value_enum_type"] = TypeName(value, name_resolver, false); + + if (SupportUnknownEnumValue(descriptor->file())) { + // Map unknown values to a special UNRECOGNIZED value if supported. + (*variables)["unrecognized_value"] = + (*variables)["value_enum_type"] + ".UNRECOGNIZED"; + } else { + // Map unknown values to the default value if we don't have UNRECOGNIZED. + (*variables)["unrecognized_value"] = + DefaultValue(value, true, name_resolver); + } + } else { + (*variables)["value_type"] = TypeName(value, name_resolver, false); + (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true); + (*variables)["value_wire_type"] = WireType(value); + (*variables)["value_default_value"] = + DefaultValue(value, true, name_resolver); + } + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + (*variables)["default_entry"] = (*variables)["capitalized_name"] + + "DefaultEntryHolder.defaultEntry"; + (*variables)["lite"] = "Lite"; + (*variables)["descriptor"] = ""; +} + +} // namespace + +ImmutableMapFieldLiteGenerator:: +ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMapFieldLiteGenerator:: +~ImmutableMapFieldLiteGenerator() {} + +int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void ImmutableMapFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$();\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$Value();\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$java.util.Map<$type_parameters$>\n" + "get$capitalized_name$();\n"); + } +} + +void ImmutableMapFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print( + variables_, + "private static final class $capitalized_name$DefaultEntryHolder {\n" + " static final com.google.protobuf.MapEntry$lite$<\n" + " $type_parameters$> defaultEntry =\n" + " com.google.protobuf.MapEntry$lite$\n" + " .<$type_parameters$>newDefaultInstance(\n" + " $descriptor$\n" + " $key_wire_type$,\n" + " $key_default_value$,\n" + " $value_wire_type$,\n" + " $value_default_value$);\n" + "}\n"); + printer->Print( + variables_, + "private com.google.protobuf.MapField$lite$<\n" + " $type_parameters$> $name$_ =\n" + " com.google.protobuf.MapField$lite$.emptyMapField();\n" + "private com.google.protobuf.MapField$lite$<$type_parameters$>\n" + "internalGet$capitalized_name$() {\n" + " return $name$_;\n" + "}\n" + "private com.google.protobuf.MapField$lite$<$type_parameters$>\n" + "internalGetMutable$capitalized_name$() {\n" + " if (!$name$_.isMutable()) {\n" + " $name$_ = $name$_.copy();\n" + " }\n" + " return $name$_;\n" + "}\n"); + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "private static final\n" + "com.google.protobuf.Internal.MapAdapter.Converter<\n" + " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n" + " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n" + " $value_enum_type$.internalGetValueMap(),\n" + " $unrecognized_value$);\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return internalGet$capitalized_name$().getMap();\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " internalGet$capitalized_name$().getMap(),\n" + " $name$ValueConverter);\n" + "}\n"); + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return internalGet$capitalized_name$().getMap();\n" + "}\n"); + } + + // Generate private setters for the builder to proxy into. + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "getMutable$capitalized_name$() {\n" + " return new com.google.protobuf.Internal.MapAdapter<\n" + " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n" + " internalGetMutable$capitalized_name$().getMutableMap(),\n" + " $name$ValueConverter);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "getMutable$capitalized_name$Value() {\n" + " return internalGetMutable$capitalized_name$().getMutableMap();\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "private java.util.Map<$type_parameters$>\n" + "getMutable$capitalized_name$() {\n" + " return internalGetMutable$capitalized_name$().getMutableMap();\n" + "}\n"); + } +} + +void ImmutableMapFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n" + "getMutable$capitalized_name$() {\n" + " copyOnWrite();\n" + " return instance.getMutable$capitalized_name$();\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "get$capitalized_name$Value() {\n" + " return instance.get$capitalized_name$Value();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$\n" + "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n" + "getMutable$capitalized_name$Value() {\n" + " copyOnWrite();\n" + " return instance.getMutable$capitalized_name$Value();\n" + "}\n"); + } + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public java.util.Map<$type_parameters$>\n" + "getMutable$capitalized_name$() {\n" + " copyOnWrite();\n" + " return instance.getMutable$capitalized_name$();\n" + "}\n"); + } +} + +void ImmutableMapFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Nothing to initialize. +} + +void ImmutableMapFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print( + variables_, + "internalGetMutable$capitalized_name$().mergeFrom(\n" + " other.internalGet$capitalized_name$());\n"); +} + +void ImmutableMapFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.makeImmutable();\n"); +} + +void ImmutableMapFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!$name$_.isMutable()) {\n" + " $name$_ = $name$_.copy();\n" + "}\n"); + if (!SupportUnknownEnumValue(descriptor_->file()) && + GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { + printer->Print( + variables_, + "com.google.protobuf.ByteString bytes = input.readBytes();\n" + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); + printer->Print( + variables_, + "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" + "} else {\n" + " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" + "}\n"); + } else { + printer->Print( + variables_, + "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + "$name$ = input.readMessage(\n" + " $default_entry$.getParserForType(), extensionRegistry);\n" + "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"); + } +} + +void ImmutableMapFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // Nothing to do here. +} + +void ImmutableMapFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : internalGet$capitalized_name$().getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $default_entry$.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " output.writeMessage($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print( + variables_, + "for (java.util.Map.Entry<$type_parameters$> entry\n" + " : internalGet$capitalized_name$().getMap().entrySet()) {\n" + " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n" + " $name$ = $default_entry$.newBuilderForType()\n" + " .setKey(entry.getKey())\n" + " .setValue(entry.getValue())\n" + " .build();\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeMessageSize($number$, $name$);\n" + "}\n"); +} + +void ImmutableMapFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print( + variables_, + "result = result && internalGet$capitalized_name$().equals(\n" + " other.internalGet$capitalized_name$());\n"); +} + +void ImmutableMapFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print( + variables_, + "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n" + "}\n"); +} + +string ImmutableMapFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h new file mode 100644 index 0000000000..8247260222 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_map_field_lite.h @@ -0,0 +1,81 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ + +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableMapFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMapFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MAP_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 63df10b4c5..09b0fd945c 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -93,43 +95,46 @@ ImmutableMessageGenerator::ImmutableMessageGenerator( : MessageGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { + GOOGLE_CHECK_NE( + FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); } ImmutableMessageGenerator::~ImmutableMessageGenerator() {} void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_)) { - // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is - // used in the construction of descriptors, we have a tricky bootstrapping - // problem. To help control static initialization order, we make sure all - // descriptors and other static data that depends on them are members of - // the outermost class in the file. This way, they will be initialized in - // a deterministic order. - - map vars; - vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); - vars["index"] = SimpleItoa(descriptor_->index()); - vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); - if (descriptor_->containing_type() != NULL) { - vars["parent"] = UniqueFileScopeIdentifier( - descriptor_->containing_type()); - } - if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { - // We can only make these package-private since the classes that use them - // are in separate files. - vars["private"] = ""; - } else { - vars["private"] = "private "; - } - - // The descriptor for this type. - printer->Print(vars, - "$private$static com.google.protobuf.Descriptors.Descriptor\n" - " internal_$identifier$_descriptor;\n"); + // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is + // used in the construction of descriptors, we have a tricky bootstrapping + // problem. To help control static initialization order, we make sure all + // descriptors and other static data that depends on them are members of + // the outermost class in the file. This way, they will be initialized in + // a deterministic order. - // And the FieldAccessorTable. - GenerateFieldAccessorTable(printer); + map vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + vars["index"] = SimpleItoa(descriptor_->index()); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); + if (descriptor_->containing_type() != NULL) { + vars["parent"] = UniqueFileScopeIdentifier( + descriptor_->containing_type()); } + if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { + // We can only make these package-private since the classes that use them + // are in separate files. + vars["private"] = ""; + } else { + vars["private"] = "private "; + } + + // The descriptor for this type. + printer->Print(vars, + // TODO(teboring): final needs to be added back. The way to fix it is to + // generate methods that can construct the types, and then still declare the + // types, and then init them in clinit with the new method calls. + "$private$static com.google.protobuf.Descriptors.Descriptor\n" + " internal_$identifier$_descriptor;\n"); + + // And the FieldAccessorTable. + GenerateFieldAccessorTable(printer); // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { @@ -142,38 +147,37 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { int ImmutableMessageGenerator::GenerateStaticVariableInitializers( io::Printer* printer) { int bytecode_estimate = 0; - if (HasDescriptorMethods(descriptor_)) { - map vars; - vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); - vars["index"] = SimpleItoa(descriptor_->index()); - vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); - if (descriptor_->containing_type() != NULL) { - vars["parent"] = UniqueFileScopeIdentifier( - descriptor_->containing_type()); - } - - // The descriptor for this type. - if (descriptor_->containing_type() == NULL) { - printer->Print(vars, - "internal_$identifier$_descriptor =\n" - " getDescriptor().getMessageTypes().get($index$);\n"); - bytecode_estimate += 30; - } else { - printer->Print(vars, - "internal_$identifier$_descriptor =\n" - " internal_$parent$_descriptor.getNestedTypes().get($index$);\n"); - bytecode_estimate += 30; - } + map vars; + vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); + vars["index"] = SimpleItoa(descriptor_->index()); + vars["classname"] = name_resolver_->GetImmutableClassName(descriptor_); + if (descriptor_->containing_type() != NULL) { + vars["parent"] = UniqueFileScopeIdentifier( + descriptor_->containing_type()); + } - // And the FieldAccessorTable. - bytecode_estimate += GenerateFieldAccessorTableInitializer(printer); + // The descriptor for this type. + if (descriptor_->containing_type() == NULL) { + printer->Print(vars, + "internal_$identifier$_descriptor =\n" + " getDescriptor().getMessageTypes().get($index$);\n"); + bytecode_estimate += 30; + } else { + printer->Print(vars, + "internal_$identifier$_descriptor =\n" + " internal_$parent$_descriptor.getNestedTypes().get($index$);\n"); + bytecode_estimate += 30; } + // And the FieldAccessorTable. + bytecode_estimate += GenerateFieldAccessorTableInitializer(printer); + // Generate static member initializers for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? - bytecode_estimate += ImmutableMessageGenerator(descriptor_->nested_type(i), context_) - .GenerateStaticVariableInitializers(printer); + bytecode_estimate += + ImmutableMessageGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariableInitializers(printer); } return bytecode_estimate; } @@ -229,40 +233,20 @@ GenerateFieldAccessorTableInitializer(io::Printer* printer) { void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public interface $classname$OrBuilder extends\n" - " $extra_interfaces$\n" - " com.google.protobuf.GeneratedMessage.\n" - " ExtendableMessageOrBuilder<$classname$> {\n", - "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), - "classname", descriptor_->name()); - } else { - printer->Print( - "public interface $classname$OrBuilder extends \n" - " $extra_interfaces$\n" - " com.google.protobuf.GeneratedMessageLite.\n" - " ExtendableMessageOrBuilder<\n" - " $classname$, $classname$.Builder> {\n", - "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), - "classname", descriptor_->name()); - } + printer->Print( + "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.GeneratedMessage.\n" + " ExtendableMessageOrBuilder<$classname$> {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name()); } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public interface $classname$OrBuilder extends\n" - " $extra_interfaces$\n" - " com.google.protobuf.MessageOrBuilder {\n", - "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), - "classname", descriptor_->name()); - } else { - printer->Print( - "public interface $classname$OrBuilder extends\n" - " $extra_interfaces$\n" - " com.google.protobuf.MessageLiteOrBuilder {\n", - "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), - "classname", descriptor_->name()); - } + printer->Print( + "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageOrBuilder {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name()); } printer->Indent(); @@ -287,98 +271,71 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { variables["static"] = is_own_file ? " " : " static "; variables["classname"] = descriptor_->name(); variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); - variables["lite"] = HasDescriptorMethods(descriptor_) ? "" : "Lite"; WriteMessageDocComment(printer, descriptor_); // The builder_type stores the super type name of the nested Builder class. string builder_type; if (descriptor_->extension_range_count() > 0) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print(variables, - "public $static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n" - " $classname$> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n"); - } else { - printer->Print(variables, - "public $static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" - " $classname$, $classname$.Builder> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n"); - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage.ExtendableMessage<\n" + " $classname$> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); builder_type = strings::Substitute( - "com.google.protobuf.GeneratedMessage$1.ExtendableBuilder<$0, ?>", - name_resolver_->GetImmutableClassName(descriptor_), - variables["lite"]); + "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_)); } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print(variables, - "public $static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessage implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n"); - } else { - printer->Print(variables, - "public $static$final class $classname$ extends\n" - " com.google.protobuf.GeneratedMessageLite<\n" - " $classname$, $classname$.Builder> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n"); - } + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessage implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); - builder_type = strings::Substitute( - "com.google.protobuf.GeneratedMessage$0.Builder", - variables["lite"]); + builder_type = "com.google.protobuf.GeneratedMessage.Builder"; } printer->Indent(); - if (HasDescriptorMethods(descriptor_)) { - // Using builder_type, instead of Builder, prevents the Builder class from - // being loaded into PermGen space when the default instance is created. - // This optimizes the PermGen space usage for clients that do not modify - // messages. - printer->Print( - "// Use $classname$.newBuilder() to construct.\n" - "private $classname$($buildertype$ builder) {\n" - " super(builder);\n" - "}\n", - "classname", descriptor_->name(), - "buildertype", builder_type); - printer->Print( - "private $classname$() {\n", - "classname", descriptor_->name()); - printer->Indent(); - GenerateInitializers(printer); - printer->Outdent(); - printer->Print( - "}\n" - "\n"); - } + // Using builder_type, instead of Builder, prevents the Builder class from + // being loaded into PermGen space when the default instance is created. + // This optimizes the PermGen space usage for clients that do not modify + // messages. + printer->Print( + "// Use $classname$.newBuilder() to construct.\n" + "private $classname$($buildertype$ builder) {\n" + " super(builder);\n" + "}\n", + "classname", descriptor_->name(), + "buildertype", builder_type); + printer->Print( + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + GenerateInitializers(printer); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); - if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "@java.lang.Override\n" + "public final com.google.protobuf.UnknownFieldSet\n" + "getUnknownFields() {\n"); + if (PreserveUnknownFields(descriptor_)) { printer->Print( - "@java.lang.Override\n" - "public final com.google.protobuf.UnknownFieldSet\n" - "getUnknownFields() {\n"); - if (PreserveUnknownFields(descriptor_)) { - printer->Print( - " return this.unknownFields;\n"); - } else { - printer->Print( - " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n"); - } + " return this.unknownFields;\n"); + } else { printer->Print( - "}\n"); + " return com.google.protobuf.UnknownFieldSet.getDefaultInstance();\n"); } + printer->Print( + "}\n"); if (HasGeneratedMethods(descriptor_)) { GenerateParsingConstructor(printer); } - GenerateDescriptorMethods(printer, false); - GenerateParser(printer); + GenerateDescriptorMethods(printer); // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { @@ -488,7 +445,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { } if (HasGeneratedMethods(descriptor_)) { - GenerateIsInitialized(printer, MEMOIZE); + GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); } @@ -509,78 +466,39 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { // Carefully initialize the default instance in such a way that it doesn't // conflict with other initialization. printer->Print( - "private static final $classname$ defaultInstance;\n", + "private static final $classname$ DEFAULT_INSTANCE;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "static {\n" - " defaultInstance = new $classname$();\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - // LITE_RUNTIME only has one constructor. - printer->Print( - "static {\n" - " defaultInstance = new $classname$(\n" - " com.google.protobuf.Internal\n" - " .EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" - "}\n" - "\n", - "classname", descriptor_->name()); - } + printer->Print( + "static {\n" + " DEFAULT_INSTANCE = new $classname$();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + printer->Print( "public static $classname$ getDefaultInstance() {\n" - " return defaultInstance;\n" + " return DEFAULT_INSTANCE;\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); - if (HasDescriptorMethods(descriptor_)) { - // LITE_RUNTIME implements this at the GeneratedMessageLite level. - printer->Print( - "public $classname$ getDefaultInstanceForType() {\n" - " return defaultInstance;\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - // LITE_RUNTIME uses this to implement the *ForType methods at the - // GeneratedMessageLite level. - printer->Print( - "static {" - " com.google.protobuf.GeneratedMessageLite.onLoad(\n" - " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n" - " .PrototypeHolder<$classname$, Builder>(\n" - " defaultInstance, PARSER));" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } + GenerateParser(printer); - // Extensions must be declared after the defaultInstance is initialized - // because the defaultInstance is used by the extension to lazily retrieve + printer->Print( + "public $classname$ getDefaultInstanceForType() {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // Extensions must be declared after the DEFAULT_INSTANCE is initialized + // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. for (int i = 0; i < descriptor_->extension_count(); i++) { ImmutableExtensionGenerator(descriptor_->extension(i), context_) .Generate(printer); } - // Some fields also have static members that must be initialized after we - // have the default instance available. - printer->Print( - "static {\n"); - printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateStaticInitializationCode(printer); - } - printer->Outdent(); - printer->Print( - "}\n"); - printer->Outdent(); printer->Print("}\n\n"); } @@ -617,35 +535,17 @@ GenerateMessageSerializationMethods(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { if (descriptor_->options().message_set_wire_format()) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "com.google.protobuf.GeneratedMessage\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newMessageSetExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - printer->Print( - "com.google.protobuf.GeneratedMessageLite\n" - " .ExtendableMessage<$classname$, $classname$.Builder>\n" - " .ExtensionWriter extensionWriter =\n" - " newMessageSetExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } + printer->Print( + "com.google.protobuf.GeneratedMessage\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newMessageSetExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "com.google.protobuf.GeneratedMessage\n" - " .ExtendableMessage<$classname$>.ExtensionWriter\n" - " extensionWriter = newExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - printer->Print( - "com.google.protobuf.GeneratedMessageLite\n" - " .ExtendableMessage<$classname$, $classname$.Builder>\n" - " .ExtensionWriter extensionWriter =\n" - " newExtensionWriter();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } + printer->Print( + "com.google.protobuf.GeneratedMessage\n" + " .ExtendableMessage<$classname$>.ExtensionWriter\n" + " extensionWriter = newExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); } } @@ -665,8 +565,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (descriptor_->options().message_set_wire_format() - && HasDescriptorMethods(descriptor_)) { + if (descriptor_->options().message_set_wire_format()) { printer->Print( "unknownFields.writeAsMessageSetTo(output);\n"); } else { @@ -702,8 +601,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (descriptor_->options().message_set_wire_format() - && HasDescriptorMethods(descriptor_)) { + if (descriptor_->options().message_set_wire_format()) { printer->Print( "size += unknownFields.getSerializedSizeAsMessageSet();\n"); } else { @@ -800,609 +698,115 @@ void ImmutableMessageGenerator::GenerateSerializeOneExtensionRange( // =================================================================== void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_)) { - // LITE_RUNTIME implements this at the GeneratedMessageLite level. - printer->Print( - "public Builder newBuilderForType() { return newBuilder(); }\n"); - } + // LITE_RUNTIME implements this at the GeneratedMessageLite level. + printer->Print( + "public Builder newBuilderForType() { return newBuilder(); }\n"); printer->Print( "public static Builder newBuilder() {\n" - " return defaultInstance.toBuilder();\n" + " return DEFAULT_INSTANCE.toBuilder();\n" "}\n" "public static Builder newBuilder($classname$ prototype) {\n" - " return defaultInstance.toBuilder().mergeFrom(prototype);\n" + " return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n" "}\n" "public Builder toBuilder() {\n" - " return this == defaultInstance\n" + " return this == DEFAULT_INSTANCE\n" " ? new Builder() : new Builder().mergeFrom(this);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); - if (HasNestedBuilders(descriptor_)) { - printer->Print( - "@java.lang.Override\n" - "protected Builder newBuilderForType(\n" - " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n" - " Builder builder = new Builder(parent);\n" - " return builder;\n" - "}\n"); - } - - WriteMessageDocComment(printer, descriptor_); - - if (descriptor_->extension_range_count() > 0) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public static final class Builder extends\n" - " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n" - " $classname$, Builder> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); - } else { - printer->Print( - "public static final class Builder extends\n" - " com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<\n" - " $classname$, Builder> implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); - } - } else { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public static final class Builder extends\n" - " com.google.protobuf.GeneratedMessage.Builder implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); - } else { - printer->Print( - "public static final class Builder extends\n" - " com.google.protobuf.GeneratedMessageLite.Builder<\n" - " $classname$, Builder>\n" - " implements\n" - " $extra_interfaces$\n" - " $classname$OrBuilder {\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), - "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); - } - } - printer->Indent(); - - GenerateDescriptorMethods(printer, true); - GenerateCommonBuilderMethods(printer); - - if (HasGeneratedMethods(descriptor_)) { - GenerateIsInitialized(printer, DONT_MEMOIZE); - GenerateBuilderParsingMethods(printer); - } - - // oneof - map vars; - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - vars["oneof_name"] = context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name; - vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->capitalized_name; - vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); - // oneofCase_ and oneof_ - printer->Print(vars, - "private int $oneof_name$Case_ = 0;\n" - "private java.lang.Object $oneof_name$_;\n"); - // oneofCase() and clearOneof() - printer->Print(vars, - "public $oneof_capitalized_name$Case\n" - " get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" - " $oneof_name$Case_);\n" - "}\n" - "\n" - "public Builder clear$oneof_capitalized_name$() {\n" - " $oneof_name$Case_ = 0;\n" - " $oneof_name$_ = null;\n"); - if (HasDescriptorMethods(descriptor_)) { - printer->Print(" onChanged();\n"); - } - printer->Print( - " return this;\n" - "}\n" - "\n"); - } - - if (GenerateHasBits(descriptor_)) { - // Integers for bit fields. - int totalBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - totalBits += field_generators_.get(descriptor_->field(i)) - .GetNumBitsForBuilder(); - } - int totalInts = (totalBits + 31) / 32; - for (int i = 0; i < totalInts; i++) { - printer->Print("private int $bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); - } - } - - for (int i = 0; i < descriptor_->field_count(); i++) { - printer->Print("\n"); - field_generators_.get(descriptor_->field(i)) - .GenerateBuilderMembers(printer); - } - - if (!PreserveUnknownFields(descriptor_)) { - printer->Print( - "public final Builder setUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n" - "public final Builder mergeUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n"); - } - printer->Print( - "\n" - "// @@protoc_insertion_point(builder_scope:$full_name$)\n", - "full_name", descriptor_->full_name()); - - printer->Outdent(); - printer->Print("}\n"); + "@java.lang.Override\n" + "protected Builder newBuilderForType(\n" + " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n" + " Builder builder = new Builder(parent);\n" + " return builder;\n" + "}\n"); + + MessageBuilderGenerator builderGenerator(descriptor_, context_); + builderGenerator.Generate(printer); } void ImmutableMessageGenerator:: -GenerateDescriptorMethods(io::Printer* printer, bool is_builder) { - if (HasDescriptorMethods(descriptor_)) { - if (!descriptor_->options().no_standard_descriptor_accessor()) { - printer->Print( - "public static final com.google.protobuf.Descriptors.Descriptor\n" - " getDescriptor() {\n" - " return $fileclass$.internal_$identifier$_descriptor;\n" - "}\n" - "\n", - "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), - "identifier", UniqueFileScopeIdentifier(descriptor_)); - } - vector map_fields; - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (GetJavaType(field) == JAVATYPE_MESSAGE && - IsMapEntry(field->message_type())) { - map_fields.push_back(field); - } - } - if (!map_fields.empty()) { - printer->Print( - "@SuppressWarnings({\"rawtypes\"})\n" - "protected com.google.protobuf.MapField internalGetMapField(\n" - " int number) {\n" - " switch (number) {\n"); - printer->Indent(); - printer->Indent(); - for (int i = 0; i < map_fields.size(); ++i) { - const FieldDescriptor* field = map_fields[i]; - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - printer->Print( - "case $number$:\n" - " return internalGet$capitalized_name$();\n", - "number", SimpleItoa(field->number()), - "capitalized_name", info->capitalized_name); - } - printer->Print( - "default:\n" - " throw new RuntimeException(\n" - " \"Invalid map field number: \" + number);\n"); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" - "}\n"); - if (is_builder) { - printer->Print( - "@SuppressWarnings({\"rawtypes\"})\n" - "protected com.google.protobuf.MapField internalGetMutableMapField(\n" - " int number) {\n" - " switch (number) {\n"); - printer->Indent(); - printer->Indent(); - for (int i = 0; i < map_fields.size(); ++i) { - const FieldDescriptor* field = map_fields[i]; - const FieldGeneratorInfo* info = - context_->GetFieldGeneratorInfo(field); - printer->Print( - "case $number$:\n" - " return internalGetMutable$capitalized_name$();\n", - "number", SimpleItoa(field->number()), - "capitalized_name", info->capitalized_name); - } - printer->Print( - "default:\n" - " throw new RuntimeException(\n" - " \"Invalid map field number: \" + number);\n"); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" - "}\n"); - } - } +GenerateDescriptorMethods(io::Printer* printer) { + if (!descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( - "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" - " internalGetFieldAccessorTable() {\n" - " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" - " .ensureFieldAccessorsInitialized(\n" - " $classname$.class, $classname$.Builder.class);\n" + "public static final com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptor() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" "}\n" "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_), "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), "identifier", UniqueFileScopeIdentifier(descriptor_)); } -} - -// =================================================================== - -void ImmutableMessageGenerator:: -GenerateCommonBuilderMethods(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "// Construct using $classname$.newBuilder()\n" - "private Builder() {\n" - " maybeForceBuilderInitialization();\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - printer->Print( - "private Builder(\n" - " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n" - " super(parent);\n" - " maybeForceBuilderInitialization();\n" - "}\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - // LITE runtime passes along the default instance to implement - // getDefaultInstanceForType() at the GeneratedMessageLite level. - printer->Print( - "// Construct using $classname$.newBuilder()\n" - "private Builder() {\n" - " super(defaultInstance);\n" - " maybeForceBuilderInitialization();\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + vector map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } } - - - if (HasNestedBuilders(descriptor_)) { + if (!map_fields.empty()) { printer->Print( - "private void maybeForceBuilderInitialization() {\n" - " if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n"); - + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); printer->Indent(); printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateFieldBuilderInitializationCode(printer); - } + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGet$capitalized_name$();\n", + "number", SimpleItoa(field->number()), + "capitalized_name", info->capitalized_name); } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); printer->Outdent(); printer->Outdent(); - - printer->Print( - " }\n" - "}\n"); - } else { - printer->Print( - "private void maybeForceBuilderInitialization() {\n" - "}\n"); - } - - printer->Print( - "public Builder clear() {\n" - " super.clear();\n"); - - printer->Indent(); - - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateBuilderClearCode(printer); - } - } - - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "$oneof_name$Case_ = 0;\n" - "$oneof_name$_ = null;\n", - "oneof_name", context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name); - } - - printer->Outdent(); - - printer->Print( - " return this;\n" - "}\n" - "\n"); - - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public com.google.protobuf.Descriptors.Descriptor\n" - " getDescriptorForType() {\n" - " return $fileclass$.internal_$identifier$_descriptor;\n" - "}\n" - "\n", - "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), - "identifier", UniqueFileScopeIdentifier(descriptor_)); - - // LITE runtime implements this in GeneratedMessageLite. - printer->Print( - "public $classname$ getDefaultInstanceForType() {\n" - " return $classname$.getDefaultInstance();\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } - - // ----------------------------------------------------------------- - - if (HasDescriptorMethods(descriptor_)) { - // LITE implements build in GeneratedMessageLite to save methods. printer->Print( - "public $classname$ build() {\n" - " $classname$ result = buildPartial();\n" - " if (!result.isInitialized()) {\n" - " throw newUninitializedMessageException(result);\n" - " }\n" - " return result;\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } - - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public $classname$ buildPartial() {\n" - " $classname$ result = new $classname$(this);\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } else { - // LITE_RUNTIME only provides a single message constructor. - printer->Print( - "public $classname$ buildPartial() {\n" - " $classname$ result = new $classname$(\n" - " com.google.protobuf.Internal\n" - " .EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" - " result.unknownFields = this.unknownFields;\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - if (descriptor_->extension_range_count() > 0) { - printer->Print( - " result.extensions = this.buildExtensions();\n"); - } - } - - printer->Indent(); - - int totalBuilderBits = 0; - int totalMessageBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - const ImmutableFieldGenerator& field = - field_generators_.get(descriptor_->field(i)); - totalBuilderBits += field.GetNumBitsForBuilder(); - totalMessageBits += field.GetNumBitsForMessage(); - } - int totalBuilderInts = (totalBuilderBits + 31) / 32; - int totalMessageInts = (totalMessageBits + 31) / 32; - - if (GenerateHasBits(descriptor_)) { - // Local vars for from and to bit fields to avoid accessing the builder and - // message over and over for these fields. Seems to provide a slight - // perforamance improvement in micro benchmark and this is also what proto1 - // code does. - for (int i = 0; i < totalBuilderInts; i++) { - printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); - } - for (int i = 0; i < totalMessageInts; i++) { - printer->Print("int to_$bit_field_name$ = 0;\n", - "bit_field_name", GetBitFieldName(i)); - } - } - - // Output generation code for each field. - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer); - } - - if (GenerateHasBits(descriptor_)) { - // Copy the bit field results to the generated message - for (int i = 0; i < totalMessageInts; i++) { - printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n", - "bit_field_name", GetBitFieldName(i)); - } - } - - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n", - "oneof_name", context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name); - } - - printer->Outdent(); - - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - " onBuilt();\n"); + " }\n" + "}\n"); } - printer->Print( - " return result;\n" + "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" + " internalGetFieldAccessorTable() {\n" + " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" + " .ensureFieldAccessorsInitialized(\n" + " $classname$.class, $classname$.Builder.class);\n" "}\n" "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - // ----------------------------------------------------------------- - - if (HasGeneratedMethods(descriptor_)) { - // MergeFrom(Message other) requires the ability to distinguish the other - // messages type by its descriptor. - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "public Builder mergeFrom(com.google.protobuf.Message other) {\n" - " if (other instanceof $classname$) {\n" - " return mergeFrom(($classname$)other);\n" - " } else {\n" - " super.mergeFrom(other);\n" - " return this;\n" - " }\n" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } - - printer->Print( - "public Builder mergeFrom($classname$ other) {\n" - // Optimization: If other is the default instance, we know none of its - // fields are set so we can skip the merge. - " if (other == $classname$.getDefaultInstance()) return this;\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - printer->Indent(); - - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get( - descriptor_->field(i)).GenerateMergingCode(printer); - } - } - - // Merge oneof fields. - for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { - printer->Print( - "switch (other.get$oneof_capitalized_name$Case()) {\n", - "oneof_capitalized_name", - context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->capitalized_name); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case $field_name$: {\n", - "field_name", - ToUpper(field->name())); - printer->Indent(); - field_generators_.get(field).GenerateMergingCode(printer); - printer->Print( - "break;\n"); - printer->Outdent(); - printer->Print( - "}\n"); - } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" - " break;\n" - "}\n", - "cap_oneof_name", - ToUpper(context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name)); - printer->Outdent(); - printer->Print( - "}\n"); - } - - printer->Outdent(); - - // if message type has extensions - if (descriptor_->extension_range_count() > 0) { - printer->Print( - " this.mergeExtensionFields(other);\n"); - } - - if (PreserveUnknownFields(descriptor_)) { - printer->Print( - " this.mergeUnknownFields(other.unknownFields);\n"); - } - - if (HasDescriptorMethods(descriptor_)) { - printer->Print(" onChanged();\n"); - } - - printer->Print( - " return this;\n" - "}\n" - "\n"); - } -} - -// =================================================================== - -void ImmutableMessageGenerator:: -GenerateBuilderParsingMethods(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_)) { - // LITE_RUNTIME implements this at the GeneratedMessageLite level. - printer->Print( - "public Builder mergeFrom(\n" - " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" - " throws java.io.IOException {\n" - " $classname$ parsedMessage = null;\n" - " try {\n" - " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" - " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" - " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" - " throw e;\n" - " } finally {\n" - " if (parsedMessage != null) {\n" - " mergeFrom(parsedMessage);\n" - " }\n" - " }\n" - " return this;\n" - "}\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); } // =================================================================== void ImmutableMessageGenerator::GenerateIsInitialized( - io::Printer* printer, UseMemoization useMemoization) { - // LITE_RUNTIME avoids generating isInitialized if it's not needed. - if (!HasDescriptorMethods(descriptor_) - && !HasRequiredFields(descriptor_)) { - return; - } - - bool memoization = useMemoization == MEMOIZE; - if (memoization) { - // Memoizes whether the protocol buffer is fully initialized (has all - // required fields). -1 means not yet computed. 0 means false and 1 means - // true. - printer->Print( - "private byte memoizedIsInitialized = -1;\n"); - } + io::Printer* printer) { + // Memoizes whether the protocol buffer is fully initialized (has all + // required fields). -1 means not yet computed. 0 means false and 1 means + // true. + printer->Print( + "private byte memoizedIsInitialized = -1;\n"); printer->Print( "public final boolean isInitialized() {\n"); printer->Indent(); - if (memoization) { - // Don't directly compare to -1 to avoid an Android x86 JIT bug. - printer->Print( - "byte isInitialized = memoizedIsInitialized;\n" - "if (isInitialized == 1) return true;\n" - "if (isInitialized == 0) return false;\n" - "\n"); - } + // Don't directly compare to -1 to avoid an Android x86 JIT bug. + printer->Print( + "byte isInitialized = memoizedIsInitialized;\n" + "if (isInitialized == 1) return true;\n" + "if (isInitialized == 0) return false;\n" + "\n"); // Check that all required fields in this message are set. // TODO(kenton): We can optimize this when we switch to putting all the @@ -1414,11 +818,10 @@ void ImmutableMessageGenerator::GenerateIsInitialized( if (field->is_required()) { printer->Print( "if (!has$name$()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" "}\n", - "name", info->capitalized_name, - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "name", info->capitalized_name); } } @@ -1432,13 +835,12 @@ void ImmutableMessageGenerator::GenerateIsInitialized( case FieldDescriptor::LABEL_REQUIRED: printer->Print( "if (!get$name$().isInitialized()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" "}\n", "type", name_resolver_->GetImmutableClassName( field->message_type()), - "name", info->capitalized_name, - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "name", info->capitalized_name); break; case FieldDescriptor::LABEL_OPTIONAL: if (!SupportFieldPresence(descriptor_->file()) && @@ -1457,38 +859,35 @@ void ImmutableMessageGenerator::GenerateIsInitialized( } printer->Print( " if (!get$name$().isInitialized()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" " }\n" "}\n", - "name", info->capitalized_name, - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "name", info->capitalized_name); break; case FieldDescriptor::LABEL_REPEATED: if (IsMapEntry(field->message_type())) { printer->Print( "for ($type$ item : get$name$().values()) {\n" " if (!item.isInitialized()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" " }\n" "}\n", "type", MapValueImmutableClassdName(field->message_type(), name_resolver_), - "name", info->capitalized_name, - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "name", info->capitalized_name); } else { printer->Print( "for (int i = 0; i < get$name$Count(); i++) {\n" " if (!get$name$(i).isInitialized()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" " }\n" "}\n", "type", name_resolver_->GetImmutableClassName( field->message_type()), - "name", info->capitalized_name, - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "name", info->capitalized_name); } break; } @@ -1498,18 +897,15 @@ void ImmutableMessageGenerator::GenerateIsInitialized( if (descriptor_->extension_range_count() > 0) { printer->Print( "if (!extensionsAreInitialized()) {\n" - " $memoize$\n" + " memoizedIsInitialized = 0;\n" " return false;\n" - "}\n", - "memoize", memoization ? "memoizedIsInitialized = 0;" : ""); + "}\n"); } printer->Outdent(); - if (memoization) { - printer->Print( - " memoizedIsInitialized = 1;\n"); - } + printer->Print( + " memoizedIsInitialized = 1;\n"); printer->Print( " return true;\n" @@ -1575,12 +971,10 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print( "result = result && unknownFields.equals(other.unknownFields);\n"); } - if (HasDescriptorMethods(descriptor_)) { - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "result = result &&\n" - " getExtensionFields().equals(other.getExtensionFields());\n"); - } + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "result = result &&\n" + " getExtensionFields().equals(other.getExtensionFields());\n"); } printer->Print( "return result;\n"); @@ -1603,14 +997,7 @@ GenerateEqualsAndHashCode(io::Printer* printer) { "}\n" "int hash = 41;\n"); - if (HasDescriptorMethods(descriptor_)) { - printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); - } else { - // Include the hash of the class so that two objects with different types - // but the same field values will probably have different hashes. - printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - } + printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); @@ -1628,11 +1015,9 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("}\n"); } } - if (HasDescriptorMethods(descriptor_)) { - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "hash = hashFields(hash, getExtensionFields());\n"); - } + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "hash = hashFields(hash, getExtensionFields());\n"); } printer->Print( @@ -1675,13 +1060,8 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Indent(); // Initialize all fields to default. - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "this();\n"); - } else { - // LITE_RUNTIME only has one constructor. - GenerateInitializers(printer); - } + printer->Print( + "this();\n"); // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; @@ -1697,15 +1077,9 @@ GenerateParsingConstructor(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (HasDescriptorMethods(descriptor_)) { - printer->Print( - "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" - " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); - } else { - printer->Print( - "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n" - " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n"); - } + printer->Print( + "com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSet.newBuilder();\n"); } printer->Print( @@ -1728,29 +1102,14 @@ GenerateParsingConstructor(io::Printer* printer) { " break;\n"); if (PreserveUnknownFields(descriptor_)) { - if (!HasDescriptorMethods(descriptor_) - && descriptor_->extension_range_count() > 0) { - // Lite runtime directly invokes parseUnknownField to reduce method - // counts. - printer->Print( - "default: {\n" - " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" - " input, unknownFields,\n" - " extensionRegistry, tag)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n"); - } else { - printer->Print( - "default: {\n" - " if (!parseUnknownField(input, unknownFields,\n" - " extensionRegistry, tag)) {\n" - " done = true;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n"); - } + printer->Print( + "default: {\n" + " if (!parseUnknownField(input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); } else { printer->Print( "default: {\n" @@ -1825,18 +1184,9 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Print("this.unknownFields = unknownFields.build();\n"); } - if (!HasDescriptorMethods(descriptor_)) { - // LITE runtime uses a static method to reduce method count. - if (descriptor_->extension_range_count() > 0) { - // Make extensions immutable. - printer->Print( - "makeExtensionsImmutable(extensions);\n"); - } - } else { - // Make extensions immutable. - printer->Print( - "makeExtensionsImmutable();\n"); - } + // Make extensions immutable. + printer->Print( + "makeExtensionsImmutable();\n"); printer->Outdent(); printer->Outdent(); @@ -1874,9 +1224,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { " }\n", "classname", descriptor_->name()); } else { - // When parsing constructor isn't generated, use builder to parse messages. - // Note, will fallback to use reflection based mergeFieldFrom() in - // AbstractMessage.Builder. + // When parsing constructor isn't generated, use builder to parse + // messages. Note, will fallback to use reflection based mergeFieldFrom() + // in AbstractMessage.Builder. printer->Indent(); printer->Print( "Builder builder = newBuilder();\n" @@ -1886,7 +1236,8 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { " throw e.setUnfinishedMessage(builder.buildPartial());\n" "} catch (java.io.IOException e) {\n" " throw new com.google.protobuf.InvalidProtocolBufferException(\n" - " e.getMessage()).setUnfinishedMessage(builder.buildPartial());\n" + " e.getMessage()).setUnfinishedMessage(\n" + " builder.buildPartial());\n" "}\n" "return builder.buildPartial();\n"); printer->Outdent(); @@ -1898,16 +1249,13 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { "};\n" "\n"); - if (HasDescriptorMethods(descriptor_)) { - // LITE_RUNTIME implements this at the GeneratedMessageLite level. - printer->Print( - "@java.lang.Override\n" - "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" - " return PARSER;\n" - "}\n" - "\n", - "classname", descriptor_->name()); - } + printer->Print( + "@java.lang.Override\n" + "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" + " return PARSER;\n" + "}\n" + "\n", + "classname", descriptor_->name()); } // =================================================================== diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index 58dd5f9933..c3c3776514 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -102,10 +102,6 @@ class ImmutableMessageGenerator : public MessageGenerator { virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: - enum UseMemoization { - MEMOIZE, - DONT_MEMOIZE - }; void GenerateFieldAccessorTable(io::Printer* printer); @@ -120,11 +116,8 @@ class ImmutableMessageGenerator : public MessageGenerator { io::Printer* printer, const Descriptor::ExtensionRange* range); void GenerateBuilder(io::Printer* printer); - void GenerateCommonBuilderMethods(io::Printer* printer); - void GenerateDescriptorMethods(io::Printer* printer, bool is_builder); - void GenerateBuilderParsingMethods(io::Printer* printer); - void GenerateIsInitialized(io::Printer* printer, - UseMemoization useMemoization); + void GenerateIsInitialized(io::Printer* printer); + void GenerateDescriptorMethods(io::Printer* printer); void GenerateInitializers(io::Printer* printer); void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc new file mode 100644 index 0000000000..7269411976 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -0,0 +1,661 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include +#include +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool GenerateHasBits(const Descriptor* descriptor) { + return SupportFieldPresence(descriptor->file()) || + HasRepeatedFields(descriptor); +} + +string MapValueImmutableClassdName(const Descriptor* descriptor, + ClassNameResolver* name_resolver) { + const FieldDescriptor* value_field = descriptor->FindFieldByName("value"); + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type()); + return name_resolver->GetImmutableClassName(value_field->message_type()); +} +} // namespace + +MessageBuilderGenerator::MessageBuilderGenerator( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK_NE( + FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); +} + +MessageBuilderGenerator::~MessageBuilderGenerator() {} + +void MessageBuilderGenerator:: +Generate(io::Printer* printer) { + WriteMessageDocComment(printer, descriptor_); + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n" + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); + } else { + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessage.Builder implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_)); + } + printer->Indent(); + + GenerateDescriptorMethods(printer); + GenerateCommonBuilderMethods(printer); + + if (HasGeneratedMethods(descriptor_)) { + GenerateIsInitialized(printer); + GenerateBuilderParsingMethods(printer); + } + + // oneof + map vars; + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name; + vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name; + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // oneofCase() and clearOneof() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + " get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.valueOf(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n" + "public Builder clear$oneof_capitalized_name$() {\n" + " $oneof_name$Case_ = 0;\n" + " $oneof_name$_ = null;\n"); + printer->Print(" onChanged();\n"); + printer->Print( + " return this;\n" + "}\n" + "\n"); + } + + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForBuilder(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderMembers(printer); + } + + if (!PreserveUnknownFields(descriptor_)) { + printer->Print( + "public final Builder setUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n" + "public final Builder mergeUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n"); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(builder_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +void MessageBuilderGenerator:: +GenerateDescriptorMethods(io::Printer* printer) { + if (!descriptor_->options().no_standard_descriptor_accessor()) { + printer->Print( + "public static final com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptor() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + } + vector map_fields; + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + IsMapEntry(field->message_type())) { + map_fields.push_back(field); + } + } + if (!map_fields.empty()) { + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGet$capitalized_name$();\n", + "number", SimpleItoa(field->number()), + "capitalized_name", info->capitalized_name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + printer->Print( + "@SuppressWarnings({\"rawtypes\"})\n" + "protected com.google.protobuf.MapField internalGetMutableMapField(\n" + " int number) {\n" + " switch (number) {\n"); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < map_fields.size(); ++i) { + const FieldDescriptor* field = map_fields[i]; + const FieldGeneratorInfo* info = + context_->GetFieldGeneratorInfo(field); + printer->Print( + "case $number$:\n" + " return internalGetMutable$capitalized_name$();\n", + "number", SimpleItoa(field->number()), + "capitalized_name", info->capitalized_name); + } + printer->Print( + "default:\n" + " throw new RuntimeException(\n" + " \"Invalid map field number: \" + number);\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" + "}\n"); + } + printer->Print( + "protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" + " internalGetFieldAccessorTable() {\n" + " return $fileclass$.internal_$identifier$_fieldAccessorTable\n" + " .ensureFieldAccessorsInitialized(\n" + " $classname$.class, $classname$.Builder.class);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); +} + +// =================================================================== + +void MessageBuilderGenerator:: +GenerateCommonBuilderMethods(io::Printer* printer) { + printer->Print( + "// Construct using $classname$.newBuilder()\n" + "private Builder() {\n" + " maybeForceBuilderInitialization();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "private Builder(\n" + " com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n" + " super(parent);\n" + " maybeForceBuilderInitialization();\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "private void maybeForceBuilderInitialization() {\n" + " if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n"); + + printer->Indent(); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateFieldBuilderInitializationCode(printer); + } + } + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n"); + + printer->Print( + "public Builder clear() {\n" + " super.clear();\n"); + + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderClearCode(printer); + } + } + + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "$oneof_name$Case_ = 0;\n" + "$oneof_name$_ = null;\n", + "oneof_name", context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + } + + printer->Outdent(); + + printer->Print( + " return this;\n" + "}\n" + "\n"); + + printer->Print( + "public com.google.protobuf.Descriptors.Descriptor\n" + " getDescriptorForType() {\n" + " return $fileclass$.internal_$identifier$_descriptor;\n" + "}\n" + "\n", + "fileclass", name_resolver_->GetImmutableClassName(descriptor_->file()), + "identifier", UniqueFileScopeIdentifier(descriptor_)); + + // LITE runtime implements this in GeneratedMessageLite. + printer->Print( + "public $classname$ getDefaultInstanceForType() {\n" + " return $classname$.getDefaultInstance();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "public $classname$ build() {\n" + " $classname$ result = buildPartial();\n" + " if (!result.isInitialized()) {\n" + " throw newUninitializedMessageException(result);\n" + " }\n" + " return result;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "public $classname$ buildPartial() {\n" + " $classname$ result = new $classname$(this);\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Indent(); + + int totalBuilderBits = 0; + int totalMessageBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + const ImmutableFieldGenerator& field = + field_generators_.get(descriptor_->field(i)); + totalBuilderBits += field.GetNumBitsForBuilder(); + totalMessageBits += field.GetNumBitsForMessage(); + } + int totalBuilderInts = (totalBuilderBits + 31) / 32; + int totalMessageInts = (totalMessageBits + 31) / 32; + + if (GenerateHasBits(descriptor_)) { + // Local vars for from and to bit fields to avoid accessing the builder and + // message over and over for these fields. Seems to provide a slight + // perforamance improvement in micro benchmark and this is also what proto1 + // code does. + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int from_$bit_field_name$ = $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("int to_$bit_field_name$ = 0;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + // Output generation code for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)).GenerateBuildingCode(printer); + } + + if (GenerateHasBits(descriptor_)) { + // Copy the bit field results to the generated message + for (int i = 0; i < totalMessageInts; i++) { + printer->Print("result.$bit_field_name$ = to_$bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print("result.$oneof_name$Case_ = $oneof_name$Case_;\n", + "oneof_name", context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + } + + printer->Outdent(); + + printer->Print( + " onBuilt();\n"); + + printer->Print( + " return result;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // ----------------------------------------------------------------- + + if (HasGeneratedMethods(descriptor_)) { + printer->Print( + "public Builder mergeFrom(com.google.protobuf.Message other) {\n" + " if (other instanceof $classname$) {\n" + " return mergeFrom(($classname$)other);\n" + " } else {\n" + " super.mergeFrom(other);\n" + " return this;\n" + " }\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "public Builder mergeFrom($classname$ other) {\n" + // Optimization: If other is the default instance, we know none of its + // fields are set so we can skip the merge. + " if (other == $classname$.getDefaultInstance()) return this;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get( + descriptor_->field(i)).GenerateMergingCode(printer); + } + } + + // Merge oneof fields. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + printer->Print( + "switch (other.get$oneof_capitalized_name$Case()) {\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case $field_name$: {\n", + "field_name", + ToUpper(field->name())); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } + printer->Print( + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "cap_oneof_name", + ToUpper(context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name)); + printer->Outdent(); + printer->Print( + "}\n"); + } + + printer->Outdent(); + + // if message type has extensions + if (descriptor_->extension_range_count() > 0) { + printer->Print( + " this.mergeExtensionFields(other);\n"); + } + + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + " this.mergeUnknownFields(other.unknownFields);\n"); + } + + printer->Print( + " onChanged();\n"); + + printer->Print( + " return this;\n" + "}\n" + "\n"); + } +} + +// =================================================================== + +void MessageBuilderGenerator:: +GenerateBuilderParsingMethods(io::Printer* printer) { + printer->Print( + "public Builder mergeFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " $classname$ parsedMessage = null;\n" + " try {\n" + " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" + " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" + " throw e;\n" + " } finally {\n" + " if (parsedMessage != null) {\n" + " mergeFrom(parsedMessage);\n" + " }\n" + " }\n" + " return this;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +// =================================================================== + +void MessageBuilderGenerator::GenerateIsInitialized( + io::Printer* printer) { + printer->Print( + "public final boolean isInitialized() {\n"); + printer->Indent(); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + + if (field->is_required()) { + printer->Print( + "if (!has$name$()) {\n" + " return false;\n" + "}\n", + "name", info->capitalized_name); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + switch (field->label()) { + case FieldDescriptor::LABEL_REQUIRED: + printer->Print( + "if (!get$name$().isInitialized()) {\n" + " return false;\n" + "}\n", + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_OPTIONAL: + if (!SupportFieldPresence(descriptor_->file()) && + field->containing_oneof() != NULL) { + const OneofDescriptor* oneof = field->containing_oneof(); + const OneofGeneratorInfo* oneof_info = + context_->GetOneofGeneratorInfo(oneof); + printer->Print( + "if ($oneof_name$Case_ == $field_number$) {\n", + "oneof_name", oneof_info->name, + "field_number", SimpleItoa(field->number())); + } else { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + } + printer->Print( + " if (!get$name$().isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_REPEATED: + if (IsMapEntry(field->message_type())) { + printer->Print( + "for ($type$ item : get$name$().values()) {\n" + " if (!item.isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "type", MapValueImmutableClassdName(field->message_type(), + name_resolver_), + "name", info->capitalized_name); + } else { + printer->Print( + "for (int i = 0; i < get$name$Count(); i++) {\n" + " if (!get$name$(i).isInitialized()) {\n" + " return false;\n" + " }\n" + "}\n", + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name); + } + break; + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!extensionsAreInitialized()) {\n" + " return false;\n" + "}\n"); + } + + printer->Outdent(); + + printer->Print( + " return true;\n" + "}\n" + "\n"); +} + +// =================================================================== + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_message_builder.h b/src/google/protobuf/compiler/java/java_message_builder.h new file mode 100644 index 0000000000..015ea06206 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_builder.h @@ -0,0 +1,86 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class MessageBuilderGenerator { + public: + explicit MessageBuilderGenerator(const Descriptor* descriptor, + Context* context); + virtual ~MessageBuilderGenerator(); + + virtual void Generate(io::Printer* printer); + + private: + void GenerateCommonBuilderMethods(io::Printer* printer); + void GenerateDescriptorMethods(io::Printer* printer); + void GenerateBuilderParsingMethods(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + + const Descriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_H__ diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc new file mode 100644 index 0000000000..8719d00d19 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc @@ -0,0 +1,192 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include +#include +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool GenerateHasBits(const Descriptor* descriptor) { + return SupportFieldPresence(descriptor->file()) || + HasRepeatedFields(descriptor); +} + +string MapValueImmutableClassdName(const Descriptor* descriptor, + ClassNameResolver* name_resolver) { + const FieldDescriptor* value_field = descriptor->FindFieldByName("value"); + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type()); + return name_resolver->GetImmutableClassName(value_field->message_type()); +} +} // namespace + +MessageBuilderLiteGenerator::MessageBuilderLiteGenerator( + const Descriptor* descriptor, Context* context) + : descriptor_(descriptor), context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK_EQ( + FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); +} + +MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {} + +void MessageBuilderLiteGenerator:: +Generate(io::Printer* printer) { + WriteMessageDocComment(printer, descriptor_); + printer->Print( + "public static final class Builder extends\n" + " com.google.protobuf.GeneratedMessageLite.$extendible$Builder<\n" + " $classname$, Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_), + "extra_interfaces", ExtraBuilderInterfaces(descriptor_), + "extendible", + descriptor_->extension_range_count() > 0 ? "Extendable" : ""); + printer->Indent(); + + GenerateCommonBuilderMethods(printer); + + // oneof + map vars; + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name; + vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name; + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + + // oneofCase() and clearOneof() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + " get$oneof_capitalized_name$Case() {\n" + " return instance.get$oneof_capitalized_name$Case();\n" + "}\n" + "\n" + "public Builder clear$oneof_capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$oneof_capitalized_name$();\n" + " return this;\n" + "}\n" + "\n"); + } + + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForBuilder(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateBuilderMembers(printer); + } + + if (!PreserveUnknownFields(descriptor_)) { + printer->Print( + "public final Builder setUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n" + "public final Builder mergeUnknownFields(\n" + " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" + " return this;\n" + "}\n" + "\n"); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(builder_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +void MessageBuilderLiteGenerator:: +GenerateCommonBuilderMethods(io::Printer* printer) { + printer->Print( + "// Construct using $classname$.newBuilder()\n" + "private Builder() {\n" + " super(DEFAULT_INSTANCE);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +// =================================================================== + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.h b/src/google/protobuf/compiler/java/java_message_builder_lite.h new file mode 100644 index 0000000000..8597b2e66f --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_builder_lite.h @@ -0,0 +1,83 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class MessageBuilderLiteGenerator { + public: + explicit MessageBuilderLiteGenerator(const Descriptor* descriptor, + Context* context); + virtual ~MessageBuilderLiteGenerator(); + + virtual void Generate(io::Printer* printer); + + private: + void GenerateCommonBuilderMethods(io::Printer* printer); + + const Descriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageBuilderLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_BUILDER_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index a2d12a3893..b180b4a718 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -157,11 +157,9 @@ GenerateInterfaceMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$$type$ get$capitalized_name$();\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n"); } void ImmutableMessageFieldGenerator:: @@ -182,14 +180,12 @@ GenerateMembers(io::Printer* printer) const { " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder " - "get$capitalized_name$OrBuilder() {\n" - " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "get$capitalized_name$OrBuilder() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); } else { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -202,14 +198,12 @@ GenerateMembers(io::Printer* printer) const { " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" "}\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder " - "get$capitalized_name$OrBuilder() {\n" - " return get$capitalized_name$();\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder " + "get$capitalized_name$OrBuilder() {\n" + " return get$capitalized_name$();\n" + "}\n"); } } @@ -217,19 +211,15 @@ void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition( io::Printer* printer, const char* regular_case, const char* nested_builder_case) const { - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, "if ($name$Builder_ == null) {\n"); - printer->Indent(); - printer->Print(variables_, regular_case); - printer->Outdent(); - printer->Print("} else {\n"); - printer->Indent(); - printer->Print(variables_, nested_builder_case); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print(variables_, regular_case); - } + printer->Print(variables_, "if ($name$Builder_ == null) {\n"); + printer->Indent(); + printer->Print(variables_, regular_case); + printer->Outdent(); + printer->Print("} else {\n"); + printer->Indent(); + printer->Print(variables_, nested_builder_case); + printer->Outdent(); + printer->Print("}\n"); } void ImmutableMessageFieldGenerator::PrintNestedBuilderFunction( @@ -260,14 +250,12 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "private $type$ $name$_ = null;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, + printer->Print(variables_, // If this builder is non-null, it is used and the other fields are // ignored. "private com.google.protobuf.SingleFieldBuilder<\n" " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" "\n"); - } // The comments above the methods below are based on a hypothetical // field of type "Field" called "Field". @@ -368,40 +356,38 @@ GenerateBuilderMembers(io::Printer* printer) const { "$clear_has_field_bit_builder$\n" "return this;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" - " $set_has_field_bit_builder$\n" - " $on_changed$\n" - " return get$capitalized_name$FieldBuilder().getBuilder();\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" - " if ($name$Builder_ != null) {\n" - " return $name$Builder_.getMessageOrBuilder();\n" - " } else {\n" - " return $name$_ == null ?\n" - " $type$.getDefaultInstance() : $name$_;\n" - " }\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "private com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> \n" - " get$capitalized_name$FieldBuilder() {\n" - " if ($name$Builder_ == null) {\n" - " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder>(\n" - " get$capitalized_name$(),\n" - " getParentForChildren(),\n" - " isClean());\n" - " $name$_ = null;\n" - " }\n" - " return $name$Builder_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" + " $set_has_field_bit_builder$\n" + " $on_changed$\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " return $name$_ == null ?\n" + " $type$.getDefaultInstance() : $name$_;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " get$capitalized_name$(),\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); } void ImmutableMessageFieldGenerator:: @@ -557,16 +543,14 @@ GenerateMembers(io::Printer* printer) const { " return $type$.getDefaultInstance();\n" "}\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" - " if ($has_oneof_case_message$) {\n" - " return ($type$) $oneof_name$_;\n" - " }\n" - " return $type$.getDefaultInstance();\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); } void ImmutableMessageOneofFieldGenerator:: @@ -574,14 +558,12 @@ GenerateBuilderMembers(io::Printer* printer) const { // When using nested-builders, the code initially works just like the // non-nested builder case. It only creates a nested builder lazily on // demand and then forever delegates to it after creation. - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, - // If this builder is non-null, it is used and the other fields are - // ignored. - "private com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" - "\n"); - } + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" + "\n"); // The comments above the methods below are based on a hypothetical // field of type "Field" called "Field". @@ -683,45 +665,43 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" - " return get$capitalized_name$FieldBuilder().getBuilder();\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" - " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n" - " return $name$Builder_.getMessageOrBuilder();\n" - " } else {\n" - " if ($has_oneof_case_message$) {\n" - " return ($type$) $oneof_name$_;\n" - " }\n" - " return $type$.getDefaultInstance();\n" - " }\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "private com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> \n" - " get$capitalized_name$FieldBuilder() {\n" - " if ($name$Builder_ == null) {\n" - " if (!($has_oneof_case_message$)) {\n" - " $oneof_name$_ = $type$.getDefaultInstance();\n" - " }\n" - " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder>(\n" - " ($type$) $oneof_name$_,\n" - " getParentForChildren(),\n" - " isClean());\n" - " $oneof_name$_ = null;\n" - " }\n" - " $set_oneof_case_message$;\n" - " $on_changed$;\n" - " return $name$Builder_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" + " return get$capitalized_name$FieldBuilder().getBuilder();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" + " if (($has_oneof_case_message$) && ($name$Builder_ != null)) {\n" + " return $name$Builder_.getMessageOrBuilder();\n" + " } else {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " if (!($has_oneof_case_message$)) {\n" + " $oneof_name$_ = $type$.getDefaultInstance();\n" + " }\n" + " $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " ($type$) $oneof_name$_,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $oneof_name$_ = null;\n" + " }\n" + " $set_oneof_case_message$;\n" + " $on_changed$;\n" + " return $name$Builder_;\n" + "}\n"); } void ImmutableMessageOneofFieldGenerator:: @@ -831,16 +811,15 @@ GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$int get$capitalized_name$Count();\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$java.util.List \n" - " get$capitalized_name$OrBuilderList();\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n" - " int index);\n"); - } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List \n" + " get$capitalized_name$OrBuilderList();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index);\n"); } void RepeatedImmutableMessageFieldGenerator:: @@ -882,19 +861,15 @@ void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderCondition( io::Printer* printer, const char* regular_case, const char* nested_builder_case) const { - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, "if ($name$Builder_ == null) {\n"); - printer->Indent(); - printer->Print(variables_, regular_case); - printer->Outdent(); - printer->Print("} else {\n"); - printer->Indent(); - printer->Print(variables_, nested_builder_case); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print(variables_, regular_case); - } + printer->Print(variables_, "if ($name$Builder_ == null) {\n"); + printer->Indent(); + printer->Print(variables_, regular_case); + printer->Outdent(); + printer->Print("} else {\n"); + printer->Indent(); + printer->Print(variables_, nested_builder_case); + printer->Outdent(); + printer->Print("}\n"); } void RepeatedImmutableMessageFieldGenerator::PrintNestedBuilderFunction( @@ -942,14 +917,12 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n" "\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - printer->Print(variables_, - // If this builder is non-null, it is used and the other fields are - // ignored. - "private com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" - "\n"); - } + printer->Print(variables_, + // If this builder is non-null, it is used and the other fields are + // ignored. + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" + "\n"); // The comments above the methods below are based on a hypothetical // repeated field of type "Field" called "RepeatedField". @@ -1116,70 +1089,68 @@ GenerateBuilderMembers(io::Printer* printer) const { "return this;\n"); - if (HasNestedBuilders(descriptor_->containing_type())) { - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" - " int index) {\n" - " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().getBuilder(index);\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" - " int index) {\n" - " if ($name$Builder_ == null) {\n" - " return $name$_.get(index);" - " } else {\n" - " return $name$Builder_.getMessageOrBuilder(index);\n" - " }\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " if ($name$Builder_ == null) {\n" + " return $name$_.get(index);" + " } else {\n" + " return $name$Builder_.getMessageOrBuilder(index);\n" + " }\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public java.util.List \n" - " get$capitalized_name$OrBuilderList() {\n" - " if ($name$Builder_ != null) {\n" - " return $name$Builder_.getMessageOrBuilderList();\n" - " } else {\n" - " return java.util.Collections.unmodifiableList($name$_);\n" - " }\n" - "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List \n" + " get$capitalized_name$OrBuilderList() {\n" + " if ($name$Builder_ != null) {\n" + " return $name$Builder_.getMessageOrBuilderList();\n" + " } else {\n" + " return java.util.Collections.unmodifiableList($name$_);\n" + " }\n" + "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" - " return get$capitalized_name$FieldBuilder().addBuilder(\n" - " $type$.getDefaultInstance());\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" - " int index) {\n" - " return get$capitalized_name$FieldBuilder().addBuilder(\n" - " index, $type$.getDefaultInstance());\n" - "}\n"); - WriteFieldDocComment(printer, descriptor_); - printer->Print(variables_, - "$deprecation$public java.util.List<$type$.Builder> \n" - " get$capitalized_name$BuilderList() {\n" - " return get$capitalized_name$FieldBuilder().getBuilderList();\n" - "}\n" - "private com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder> \n" - " get$capitalized_name$FieldBuilder() {\n" - " if ($name$Builder_ == null) {\n" - " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" - " $type$, $type$.Builder, $type$OrBuilder>(\n" - " $name$_,\n" - " $get_mutable_bit_builder$,\n" - " getParentForChildren(),\n" - " isClean());\n" - " $name$_ = null;\n" - " }\n" - " return $name$Builder_;\n" - "}\n"); - } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" + " int index) {\n" + " return get$capitalized_name$FieldBuilder().addBuilder(\n" + " index, $type$.getDefaultInstance());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$.Builder> \n" + " get$capitalized_name$BuilderList() {\n" + " return get$capitalized_name$FieldBuilder().getBuilderList();\n" + "}\n" + "private com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder> \n" + " get$capitalized_name$FieldBuilder() {\n" + " if ($name$Builder_ == null) {\n" + " $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" + " $type$, $type$.Builder, $type$OrBuilder>(\n" + " $name$_,\n" + " $get_mutable_bit_builder$,\n" + " getParentForChildren(),\n" + " isClean());\n" + " $name$_ = null;\n" + " }\n" + " return $name$Builder_;\n" + "}\n"); } void RepeatedImmutableMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc new file mode 100644 index 0000000000..8332202c5e --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -0,0 +1,944 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { + +void SetMessageVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = + name_resolver->GetImmutableClassName(descriptor->message_type()); + (*variables)["mutable_type"] = + name_resolver->GetMutableClassName(descriptor->message_type()); + (*variables)["group_or_message"] = + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? + "Group" : "Message"; + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != null"; + } + + // For repeated builders, the underlying list tracks mutability state. + (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()"; + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutableMessageFieldLiteGenerator:: +ImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableMessageFieldLiteGenerator::~ImmutableMessageFieldLiteGenerator() {} + +int ImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const { + return 1; +} + +int ImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + // TODO(jonp): In the future, consider having a method specific to the + // interface so that builders can choose dynamically to either return a + // message or a nested builder, so that asking for the interface doesn't + // cause a message to ever be built. + if (SupportFieldPresence(descriptor_->file()) || + descriptor_->containing_oneof() == NULL) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private $type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + } else { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $name$_ != null;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return $name$_ == null ? $type$.getDefaultInstance() : $name$_;\n" + "}\n"); + } + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $name$_ = value;\n" + " $set_has_field_bit_message$\n" + " }\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " $name$_ = builderForValue.build();\n" + " $set_has_field_bit_message$\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void merge$capitalized_name$($type$ value) {\n" + " if ($name$_ != null &&\n" + " $name$_ != $type$.getDefaultInstance()) {\n" + " $name$_ =\n" + " $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" + " } else {\n" + " $name$_ = value;\n" + " }\n" + " $set_has_field_bit_message$\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {" + " $name$_ = null;\n" + " $clear_has_field_bit_message$\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + + // Field getField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + " }\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "get$capitalized_name$FieldBuilder();\n"); + } +} + + +void ImmutableMessageFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const {} + +void ImmutableMessageFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " merge$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + // noop for scalars +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($is_field_present_message$) {\n" + " subBuilder = $name$_.toBuilder();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry);\n"); + } else { + printer->Print(variables_, + "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + } + + printer->Print(variables_, + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom($name$_);\n" + " $name$_ = subBuilder.buildPartial();\n" + "}\n" + "$set_has_field_bit_message$\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for messages. +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.write$group_or_message$($number$, get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" + "}\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); +} + +void ImmutableMessageFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n" + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); +} + +string ImmutableMessageFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +// =================================================================== + +ImmutableMessageOneofFieldLiteGenerator:: +ImmutableMessageOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableMessageFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableMessageOneofFieldLiteGenerator:: +~ImmutableMessageOneofFieldLiteGenerator() {} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($type$) $oneof_name$_;\n" + " }\n" + " return $type$.getDefaultInstance();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $oneof_name$_ = value;\n" + " $set_oneof_case_message$;\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " $oneof_name$_ = builderForValue.build();\n" + " $set_oneof_case_message$;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void merge$capitalized_name$($type$ value) {\n" + " if ($has_oneof_case_message$ &&\n" + " $oneof_name$_ != $type$.getDefaultInstance()) {\n" + " $oneof_name$_ = $type$.newBuilder(($type$) $oneof_name$_)\n" + " .mergeFrom(value).buildPartial();\n" + " } else {\n" + " $oneof_name$_ = value;\n" + " }\n" + " $set_oneof_case_message$;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // field of type "Field" called "Field". + + if (SupportFieldPresence(descriptor_->file())) { + // boolean hasField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + + // Field getField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + // Field.Builder setField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder setField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Field.Builder mergeField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder merge$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.merge$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Field.Builder clearField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "merge$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$type$.Builder subBuilder = null;\n" + "if ($has_oneof_case_message$) {\n" + " subBuilder = (($type$) $oneof_name$_).toBuilder();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry);\n"); + } else { + printer->Print(variables_, + "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + } + + printer->Print(variables_, + "if (subBuilder != null) {\n" + " subBuilder.mergeFrom(($type$) $oneof_name$_);\n" + " $oneof_name$_ = subBuilder.buildPartial();\n" + "}\n"); + printer->Print(variables_, + "$set_oneof_case_message$;\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n" + "}\n"); +} + +void ImmutableMessageOneofFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, ($type$) $oneof_name$_);\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableMessageFieldLiteGenerator:: +RepeatedImmutableMessageFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableMessageFieldLiteGenerator:: +~RepeatedImmutableMessageFieldLiteGenerator() {} + +int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableMessageFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + // TODO(jonp): In the future, consider having methods specific to the + // interface so that builders can choose dynamically to either return a + // message or a nested builder, so that asking for the interface doesn't + // cause a message to ever be built. + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$type$> \n" + " get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.Internal.ProtobufList<$type$> $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List \n" + " get$capitalized_name$OrBuilderList() {\n" + " return $name$_;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" + " int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$is_mutable$) {\n" + " $name$_ = newProtobufList($name$_);\n" + " }\n" + "}\n" + "\n"); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + "}\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, builderForValue.build());\n" + "}\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(index, value);\n" + "}\n"); + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(builderForValue.build());\n" + "}\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(index, builderForValue.build());\n" + "}\n"); + + // Builder addAllRepeatedField(Iterable values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = emptyProtobufList();\n" + "}\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void remove$capitalized_name$(int index) {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.remove(index);\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + // The comments above the methods below are based on a hypothetical + // repeated field of type "Field" called "RepeatedField". + + // List getRepeatedFieldList() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + + // int getRepeatedFieldCount() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return instance.get$capitalized_name$Count();\n" + "}"); + + // Field getRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + + // Builder setRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + + // Builder setRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(int index, Field value) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + // Builder addRepeatedField(Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addRepeatedField(int index, Field.Builder builderForValue) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " int index, $type$.Builder builderForValue) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(index, builderForValue);\n" + " return this;\n" + "}\n"); + + // Builder addAllRepeatedField(Iterable values) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + + // Builder clearAllRepeatedField() + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + // Builder removeRepeatedField(int index) + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder remove$capitalized_name$(int index) {\n" + " copyOnWrite();\n" + " instance.remove$capitalized_name$(index);\n" + " return this;\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + printer->Print(variables_, + "get$capitalized_name$FieldBuilder();\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = emptyProtobufList();\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // The code below does two optimizations (non-nested builder case): + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.makeImmutable();\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ = newProtobufList();\n" + "}\n"); + + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + " extensionRegistry));\n"); + } else { + printer->Print(variables_, + "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + } +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_mutable$) {\n" + " $name$_.makeImmutable();\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$group_or_message$($number$, $name$_.get(i));\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$group_or_message$Size($number$, $name$_.get(i));\n" + "}\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List());\n"); +} + +void RepeatedImmutableMessageFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +string RepeatedImmutableMessageFieldLiteGenerator::GetBoxedType() const { + return name_resolver_->GetImmutableClassName(descriptor_->message_type()); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h new file mode 100644 index 0000000000..ae26c06aaa --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_field_lite.h @@ -0,0 +1,157 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMessageFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + protected: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageFieldLiteGenerator); +}; + +class ImmutableMessageOneofFieldLiteGenerator + : public ImmutableMessageFieldLiteGenerator { + public: + ImmutableMessageOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableMessageOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageOneofFieldLiteGenerator); +}; + +class RepeatedImmutableMessageFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableMessageFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableMessageFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + protected: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableMessageFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc new file mode 100644 index 0000000000..3accee92c7 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -0,0 +1,1174 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include +#include +#include +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { +bool GenerateHasBits(const Descriptor* descriptor) { + return SupportFieldPresence(descriptor->file()) || + HasRepeatedFields(descriptor); +} + +string MapValueImmutableClassdName(const Descriptor* descriptor, + ClassNameResolver* name_resolver) { + const FieldDescriptor* value_field = descriptor->FindFieldByName("value"); + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type()); + return name_resolver->GetImmutableClassName(value_field->message_type()); +} +} // namespace + +// =================================================================== +ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator( + const Descriptor* descriptor, Context* context) + : MessageGenerator(descriptor), context_(context), + name_resolver_(context->GetNameResolver()), + field_generators_(descriptor, context_) { + GOOGLE_CHECK_EQ( + FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); +} + +ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {} + +void ImmutableMessageLiteGenerator::GenerateStaticVariables( + io::Printer* printer) { + // Generate static members for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariables(printer); + } +} + +int ImmutableMessageLiteGenerator::GenerateStaticVariableInitializers( + io::Printer* printer) { + int bytecode_estimate = 0; + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + bytecode_estimate += + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateStaticVariableInitializers(printer); + } + return bytecode_estimate; +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) { + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "public interface $classname$OrBuilder extends \n" + " $extra_interfaces$\n" + " com.google.protobuf.GeneratedMessageLite.\n" + " ExtendableMessageOrBuilder<\n" + " $classname$, $classname$.Builder> {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name()); + } else { + printer->Print( + "public interface $classname$OrBuilder extends\n" + " $extra_interfaces$\n" + " com.google.protobuf.MessageLiteOrBuilder {\n", + "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_), + "classname", descriptor_->name()); + } + + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + field_generators_.get(descriptor_->field(i)) + .GenerateInterfaceMembers(printer); + } + printer->Outdent(); + + printer->Print("}\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { + bool is_own_file = + descriptor_->containing_type() == NULL && + MultipleJavaFiles(descriptor_->file(), /* immutable = */ true); + + map variables; + variables["static"] = is_own_file ? " " : " static "; + variables["classname"] = descriptor_->name(); + variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_); + + WriteMessageDocComment(printer, descriptor_); + + // The builder_type stores the super type name of the nested Builder class. + string builder_type; + if (descriptor_->extension_range_count() > 0) { + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessageLite.ExtendableMessage<\n" + " $classname$, $classname$.Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + builder_type = strings::Substitute( + "com.google.protobuf.GeneratedMessageLite.ExtendableBuilder<$0, ?>", + name_resolver_->GetImmutableClassName(descriptor_)); + } else { + printer->Print(variables, + "public $static$final class $classname$ extends\n" + " com.google.protobuf.GeneratedMessageLite<\n" + " $classname$, $classname$.Builder> implements\n" + " $extra_interfaces$\n" + " $classname$OrBuilder {\n"); + + builder_type = "com.google.protobuf.GeneratedMessageLite.Builder"; + } + printer->Indent(); + + GenerateParsingConstructor(printer); + + // Nested types + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator(descriptor_->enum_type(i), true, context_) + .Generate(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // Don't generate Java classes for map entry messages. + if (IsMapEntry(descriptor_->nested_type(i))) continue; + ImmutableMessageLiteGenerator messageGenerator( + descriptor_->nested_type(i), context_); + messageGenerator.GenerateInterface(printer); + messageGenerator.Generate(printer); + } + + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + // oneof + map vars; + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + vars["oneof_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name; + vars["oneof_capitalized_name"] = context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name; + vars["oneof_index"] = SimpleItoa(descriptor_->oneof_decl(i)->index()); + // oneofCase_ and oneof_ + printer->Print(vars, + "private int $oneof_name$Case_ = 0;\n" + "private java.lang.Object $oneof_name$_;\n"); + // OneofCase enum + printer->Print(vars, + "public enum $oneof_capitalized_name$Case\n" + " implements com.google.protobuf.Internal.EnumLite {\n"); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "$field_name$($field_number$),\n", + "field_name", + ToUpper(field->name()), + "field_number", + SimpleItoa(field->number())); + } + printer->Print( + "$cap_oneof_name$_NOT_SET(0);\n", + "cap_oneof_name", + ToUpper(vars["oneof_name"])); + printer->Print(vars, + "private int value = 0;\n" + "private $oneof_capitalized_name$Case(int value) {\n" + " this.value = value;\n" + "}\n"); + printer->Print(vars, + "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " switch (value) {\n"); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + " case $field_number$: return $field_name$;\n", + "field_number", + SimpleItoa(field->number()), + "field_name", + ToUpper(field->name())); + } + printer->Print( + " case 0: return $cap_oneof_name$_NOT_SET;\n" + " default: throw new java.lang.IllegalArgumentException(\n" + " \"Value is undefined for this oneof enum.\");\n" + " }\n" + "}\n" + "public int getNumber() {\n" + " return this.value;\n" + "}\n", + "cap_oneof_name", ToUpper(vars["oneof_name"])); + printer->Outdent(); + printer->Print("};\n\n"); + // oneofCase() + printer->Print(vars, + "public $oneof_capitalized_name$Case\n" + "get$oneof_capitalized_name$Case() {\n" + " return $oneof_capitalized_name$Case.valueOf(\n" + " $oneof_name$Case_);\n" + "}\n" + "\n" + "private void clear$oneof_capitalized_name$() {\n" + " $oneof_name$Case_ = 0;\n" + " $oneof_name$_ = null;\n" + "}\n" + "\n"); + } + + // Fields + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("public static final int $constant_name$ = $number$;\n", + "constant_name", FieldConstantName(descriptor_->field(i)), + "number", SimpleItoa(descriptor_->field(i)->number())); + field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); + printer->Print("\n"); + } + + GenerateMessageSerializationMethods(printer); + + if (HasEqualsAndHashCode(descriptor_)) { + GenerateEqualsAndHashCode(printer); + } + + + GenerateParseFromMethods(printer); + GenerateBuilder(printer); + + if (HasRequiredFields(descriptor_)) { + // Memoizes whether the protocol buffer is fully initialized (has all + // required fields). -1 means not yet computed. 0 means false and 1 means + // true. + printer->Print( + "private byte memoizedIsInitialized = -1;\n"); + } + + printer->Print( + "protected final Object dynamicMethod(\n" + " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" + " Object... args) {\n" + " switch (method) {\n" + " case PARSE_PARTIAL_FROM: {\n" + " return new $classname$(" + " (com.google.protobuf.CodedInputStream) args[0],\n" + " (com.google.protobuf.ExtensionRegistryLite) args[1]);\n" + " }\n" + " case NEW_INSTANCE: {\n" + " return new $classname$(\n" + " com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n" + " com.google.protobuf.ExtensionRegistryLite\n" + " .getEmptyRegistry());\n" + " }\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Indent(); + printer->Indent(); + + printer->Print( + "case IS_INITIALIZED: {\n"); + printer->Indent(); + GenerateDynamicMethodIsInitialized(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case MAKE_IMMUTABLE: {\n"); + + printer->Indent(); + GenerateDynamicMethodMakeImmutable(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case NEW_BUILDER: {\n"); + + printer->Indent(); + GenerateDynamicMethodNewBuilder(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case MERGE_FROM: {\n"); + + printer->Indent(); + GenerateDynamicMethodMergeFrom(printer); + printer->Outdent(); + + printer->Print( + "}\n"); + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + " throw new UnsupportedOperationException();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + + // Carefully initialize the default instance in such a way that it doesn't + // conflict with other initialization. + printer->Print( + "private static final $classname$ DEFAULT_INSTANCE;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print( + "static {\n" + " DEFAULT_INSTANCE = new $classname$(\n" + " com.google.protobuf.Internal\n" + " .EMPTY_CODED_INPUT_STREAM,\n" + " com.google.protobuf.ExtensionRegistryLite\n" + " .getEmptyRegistry());\n" + "}\n" + "\n", + "classname", descriptor_->name()); + printer->Print( + "public static $classname$ getDefaultInstance() {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + GenerateParser(printer); + + // LITE_RUNTIME uses this to implement the *ForType methods at the + // GeneratedMessageLite level. + printer->Print( + "static {\n" + " com.google.protobuf.GeneratedMessageLite.onLoad(\n" + " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n" + " .PrototypeHolder<$classname$, Builder>(\n" + " DEFAULT_INSTANCE, PARSER));" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + // Extensions must be declared after the DEFAULT_INSTANCE is initialized + // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve + // the outer class's FileDescriptor. + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionGenerator(descriptor_->extension(i), context_) + .Generate(printer); + } + + printer->Outdent(); + printer->Print("}\n\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator:: +GenerateMessageSerializationMethods(io::Printer* printer) { + google::protobuf::scoped_array sorted_fields( + SortFieldsByNumber(descriptor_)); + + vector sorted_extensions; + for (int i = 0; i < descriptor_->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor_->extension_range(i)); + } + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + + printer->Print( + "public void writeTo(com.google.protobuf.CodedOutputStream output)\n" + " throws java.io.IOException {\n"); + printer->Indent(); + if (HasPackedFields(descriptor_)) { + // writeTo(CodedOutputStream output) might be invoked without + // getSerializedSize() ever being called, but we need the memoized + // sizes in case this message has packed fields. Rather than emit checks for + // each packed field, just call getSerializedSize() up front. + // In most cases, getSerializedSize() will have already been called anyway + // by one of the wrapper writeTo() methods, making this call cheap. + printer->Print( + "getSerializedSize();\n"); + } + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print( + "com.google.protobuf.GeneratedMessageLite\n" + " .ExtendableMessage<$classname$, $classname$.Builder>\n" + " .ExtensionWriter extensionWriter =\n" + " newMessageSetExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } else { + printer->Print( + "com.google.protobuf.GeneratedMessageLite\n" + " .ExtendableMessage<$classname$, $classname$.Builder>\n" + " .ExtensionWriter extensionWriter =\n" + " newExtensionWriter();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } + } + + // Merge the fields and the extension ranges, both sorted by field number. + for (int i = 0, j = 0; + i < descriptor_->field_count() || j < sorted_extensions.size(); + ) { + if (i == descriptor_->field_count()) { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } else if (j == sorted_extensions.size()) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else if (sorted_fields[i]->number() < sorted_extensions[j]->start) { + GenerateSerializeOneField(printer, sorted_fields[i++]); + } else { + GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + } + } + + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + "unknownFields.writeTo(output);\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n" + "public int getSerializedSize() {\n" + " int size = memoizedSerializedSize;\n" + " if (size != -1) return size;\n" + "\n" + " size = 0;\n"); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); + } + + if (descriptor_->extension_range_count() > 0) { + if (descriptor_->options().message_set_wire_format()) { + printer->Print( + "size += extensionsSerializedSizeAsMessageSet();\n"); + } else { + printer->Print( + "size += extensionsSerializedSize();\n"); + } + } + + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + "size += unknownFields.getSerializedSize();\n"); + } + + printer->Outdent(); + printer->Print( + " memoizedSerializedSize = size;\n" + " return size;\n" + "}\n" + "\n"); + + printer->Print( + "private static final long serialVersionUID = 0L;\n"); +} + +void ImmutableMessageLiteGenerator:: +GenerateParseFromMethods(io::Printer* printer) { + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + printer->Print( + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.ByteString data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(byte[] data)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " byte[] data,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " return PARSER.parseFrom(data, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(java.io.InputStream input)\n" + " throws java.io.IOException {\n" + " return PARSER.parseFrom(input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return PARSER.parseFrom(input, extensionRegistry);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" + " throws java.io.IOException {\n" + " return PARSER.parseDelimitedFrom(input);\n" + "}\n" + "public static $classname$ parseDelimitedFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input)\n" + " throws java.io.IOException {\n" + " return PARSER.parseFrom(input);\n" + "}\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " return PARSER.parseFrom(input, extensionRegistry);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); +} + +void ImmutableMessageLiteGenerator::GenerateSerializeOneField( + io::Printer* printer, const FieldDescriptor* field) { + field_generators_.get(field).GenerateSerializationCode(printer); +} + +void ImmutableMessageLiteGenerator::GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range) { + printer->Print( + "extensionWriter.writeUntil($end$, output);\n", + "end", SimpleItoa(range->end)); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateBuilder(io::Printer* printer) { + printer->Print( + "public static Builder newBuilder() {\n" + " return DEFAULT_INSTANCE.toBuilder();\n" + "}\n" + "public static Builder newBuilder($classname$ prototype) {\n" + " return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + MessageBuilderLiteGenerator builderGenerator(descriptor_, context_); + builderGenerator.Generate(printer); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( + io::Printer* printer) { + // Returns null for false, DEFAULT_INSTANCE for true. + if (!HasRequiredFields(descriptor_)) { + printer->Print("return DEFAULT_INSTANCE;\n"); + return; + } + + // Don't directly compare to -1 to avoid an Android x86 JIT bug. + printer->Print( + "byte isInitialized = memoizedIsInitialized;\n" + "if (isInitialized == 1) return DEFAULT_INSTANCE;\n" + "if (isInitialized == 0) return null;\n" + "\n" + "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n"); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + + if (field->is_required()) { + printer->Print( + "if (!has$name$()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + "}\n", + "name", info->capitalized_name); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + if (GetJavaType(field) == JAVATYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + switch (field->label()) { + case FieldDescriptor::LABEL_REQUIRED: + printer->Print( + "if (!get$name$().isInitialized()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + "}\n", + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_OPTIONAL: + if (!SupportFieldPresence(descriptor_->file()) && + field->containing_oneof() != NULL) { + const OneofDescriptor* oneof = field->containing_oneof(); + const OneofGeneratorInfo* oneof_info = + context_->GetOneofGeneratorInfo(oneof); + printer->Print( + "if ($oneof_name$Case_ == $field_number$) {\n", + "oneof_name", oneof_info->name, + "field_number", SimpleItoa(field->number())); + } else { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + } + printer->Print( + " if (!get$name$().isInitialized()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + " }\n" + "}\n", + "name", info->capitalized_name); + break; + case FieldDescriptor::LABEL_REPEATED: + if (IsMapEntry(field->message_type())) { + printer->Print( + "for ($type$ item : get$name$().values()) {\n" + " if (!item.isInitialized()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + " }\n" + "}\n", + "type", MapValueImmutableClassdName(field->message_type(), + name_resolver_), + "name", info->capitalized_name); + } else { + printer->Print( + "for (int i = 0; i < get$name$Count(); i++) {\n" + " if (!get$name$(i).isInitialized()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + " }\n" + "}\n", + "type", name_resolver_->GetImmutableClassName( + field->message_type()), + "name", info->capitalized_name); + } + break; + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!extensionsAreInitialized()) {\n" + " if (shouldMemoize) {\n" + " memoizedIsInitialized = 0;\n" + " }\n" + " return null;\n" + "}\n"); + } + + printer->Print( + "if (shouldMemoize) memoizedIsInitialized = 1;\n"); + + printer->Print( + "return DEFAULT_INSTANCE;\n" + "\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( + io::Printer* printer) { + // Output generation code for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateDynamicMethodMakeImmutableCode(printer); + } + printer->Print( + "return null;"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( + io::Printer* printer) { + printer->Print( + "return new Builder();"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( + io::Printer* printer) { + printer->Print( + // Optimization: If other is the default instance, we know none of its + // fields are set so we can skip the merge. + "Object arg = args[0];\n" + "if (arg == $classname$.getDefaultInstance()) return this;\n" + "$classname$ other = ($classname$) arg;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get( + descriptor_->field(i)).GenerateMergingCode(printer); + } + } + + // Merge oneof fields. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + printer->Print( + "switch (other.get$oneof_capitalized_name$Case()) {\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case $field_name$: {\n", + "field_name", + ToUpper(field->name())); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } + printer->Print( + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "cap_oneof_name", + ToUpper(context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name)); + printer->Outdent(); + printer->Print( + "}\n"); + } + + // if message type has extensions + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "this.mergeExtensionFields(other);\n"); + } + + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + "this.mergeUnknownFields(other.unknownFields);\n"); + } + + printer->Print( + "return this;\n"); +} + +// =================================================================== + +namespace { +bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { + if (field->is_repeated()) { + return false; + } + if (SupportFieldPresence(field->file())) { + return true; + } + return GetJavaType(field) == JAVATYPE_MESSAGE && + field->containing_oneof() == NULL; +} +} // namespace + +void ImmutableMessageLiteGenerator:: +GenerateEqualsAndHashCode(io::Printer* printer) { + printer->Print( + "@java.lang.Override\n" + "public boolean equals(final java.lang.Object obj) {\n"); + printer->Indent(); + printer->Print( + "if (obj == this) {\n" + " return true;\n" + "}\n" + "if (!(obj instanceof $classname$)) {\n" + " return super.equals(obj);\n" + "}\n" + "$classname$ other = ($classname$) obj;\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + printer->Print("boolean result = true;\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "result = result && (has$name$() == other.has$name$());\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print( + "}\n"); + } + } + if (PreserveUnknownFields(descriptor_)) { + // Always consider unknown fields for equality. This will sometimes return + // false for non-canonical ordering when running in LITE_RUNTIME but it's + // the best we can do. + printer->Print( + "result = result && unknownFields.equals(other.unknownFields);\n"); + } + printer->Print( + "return result;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + printer->Print( + "@java.lang.Override\n" + "public int hashCode() {\n"); + printer->Indent(); + printer->Print( + "if (memoizedHashCode != 0) {\n"); + printer->Indent(); + printer->Print( + "return memoizedHashCode;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "int hash = 41;\n"); + + // Include the hash of the class so that two objects with different types + // but the same field values will probably have different hashes. + printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateHashCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } + } + + printer->Print( + "hash = (29 * hash) + unknownFields.hashCode();\n"); + printer->Print( + "memoizedHashCode = hash;\n" + "return hash;\n"); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); +} + +// =================================================================== + +void ImmutableMessageLiteGenerator:: +GenerateExtensionRegistrationCode(io::Printer* printer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionGenerator(descriptor_->extension(i), context_) + .GenerateRegistrationCode(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateExtensionRegistrationCode(printer); + } +} + +// =================================================================== +void ImmutableMessageLiteGenerator:: +GenerateParsingConstructor(io::Printer* printer) { + google::protobuf::scoped_array sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "private $classname$(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + GenerateInitializers(printer); + + // Use builder bits to track mutable repeated fields. + int totalBuilderBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + const ImmutableFieldLiteGenerator& field = + field_generators_.get(descriptor_->field(i)); + totalBuilderBits += field.GetNumBitsForBuilder(); + } + int totalBuilderInts = (totalBuilderBits + 31) / 32; + for (int i = 0; i < totalBuilderInts; i++) { + printer->Print("int mutable_$bit_field_name$ = 0;\n", + "bit_field_name", GetBitFieldName(i)); + } + + if (PreserveUnknownFields(descriptor_)) { + printer->Print( + "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n" + " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n"); + } + + printer->Print( + "try {\n"); + printer->Indent(); + + printer->Print( + "boolean done = false;\n" + "while (!done) {\n"); + printer->Indent(); + + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); + + printer->Print( + "case 0:\n" // zero signals EOF / limit reached + " done = true;\n" + " break;\n"); + + if (PreserveUnknownFields(descriptor_)) { + if (descriptor_->extension_range_count() > 0) { + // Lite runtime directly invokes parseUnknownField to reduce method + // counts. + printer->Print( + "default: {\n" + " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n" + " input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } else { + printer->Print( + "default: {\n" + " if (!parseUnknownField(input, unknownFields,\n" + " extensionRegistry, tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } + } else { + printer->Print( + "default: {\n" + " if (!input.skipField(tag)) {\n" + " done = true;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + } + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32 tag = WireFormatLite::MakeTag(field->number(), + WireFormat::WireTypeForFieldType(field->type())); + + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(packed_tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + "}\n"); // while (!done) + + printer->Outdent(); + printer->Print( + "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw new RuntimeException(e.setUnfinishedMessage(this));\n" + "} catch (java.io.IOException e) {\n" + " throw new RuntimeException(\n" + " new com.google.protobuf.InvalidProtocolBufferException(\n" + " e.getMessage()).setUnfinishedMessage(this));\n" + "} finally {\n"); + printer->Indent(); + + // Make repeated field list immutable. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + field_generators_.get(field).GenerateParsingDoneCode(printer); + } + + if (PreserveUnknownFields(descriptor_)) { + // Make unknown fields immutable. + printer->Print("this.unknownFields = unknownFields.build();\n"); + } + + if (descriptor_->extension_range_count() > 0) { + // Make extensions immutable. + printer->Print( + "makeExtensionsImmutable(extensions);\n"); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // finally + "}\n"); +} + +// =================================================================== +void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) { + printer->Print( + "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" + " new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" + "\n", + "classname", descriptor_->name()); +} + +// =================================================================== +void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } +} + + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h new file mode 100644 index 0000000000..2bd3cdd46f --- /dev/null +++ b/src/google/protobuf/compiler/java/java_message_lite.h @@ -0,0 +1,91 @@ +// 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. + +// Author: dweis@google.com (Daniel Weis) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ + +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableMessageLiteGenerator : public MessageGenerator { + public: + explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor, + Context* context); + virtual ~ImmutableMessageLiteGenerator(); + + virtual void Generate(io::Printer* printer); + virtual void GenerateInterface(io::Printer* printer); + virtual void GenerateExtensionRegistrationCode(io::Printer* printer); + virtual void GenerateStaticVariables(io::Printer* printer); + virtual int GenerateStaticVariableInitializers(io::Printer* printer); + + private: + + void GenerateMessageSerializationMethods(io::Printer* printer); + void GenerateParseFromMethods(io::Printer* printer); + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field); + void GenerateSerializeOneExtensionRange( + io::Printer* printer, const Descriptor::ExtensionRange* range); + + void GenerateBuilder(io::Printer* printer); + void GenerateDynamicMethodIsInitialized(io::Printer* printer); + void GenerateDynamicMethodMakeImmutable(io::Printer* printer); + void GenerateDynamicMethodMergeFrom(io::Printer* printer); + void GenerateDynamicMethodNewBuilder(io::Printer* printer); + void GenerateInitializers(io::Printer* printer); + void GenerateEqualsAndHashCode(io::Printer* printer); + void GenerateParser(io::Printer* printer); + void GenerateParsingConstructor(io::Printer* printer); + + Context* context_; + ClassNameResolver* name_resolver_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableMessageLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 48757c6026..7bebe12a94 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -74,7 +74,12 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); (*variables)["capitalized_type"] = GetCapitalizedType(descriptor, /* immutable = */ true); - (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + if (descriptor->is_packed()) { + (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag( + descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + } else { + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + } (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { @@ -599,7 +604,7 @@ GenerateMembers(io::Printer* printer) const { " return $name$_.get(index);\n" "}\n"); - if (descriptor_->options().packed() && + if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); @@ -771,7 +776,7 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutablePrimitiveFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { // We invoke getSerializedSize in writeTo for messages that have packed // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods. // That makes it safe to rely on the memoized size here. @@ -812,7 +817,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print( "size += dataSize;\n"); - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "if (!get$capitalized_name$List().isEmpty()) {\n" " size += $tag_size$;\n" @@ -825,7 +830,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { } // cache the data size for packed fields. - if (descriptor_->options().packed()) { + if (descriptor_->is_packed()) { printer->Print(variables_, "$name$MemoizedSerializedSize = dataSize;\n"); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc new file mode 100644 index 0000000000..217ff9b69c --- /dev/null +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -0,0 +1,892 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["field_type"] = (*variables)["type"]; + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ? + "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); + (*variables)["capitalized_type"] = + GetCapitalizedType(descriptor, /* immutable = */ true); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + + string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName( + GetJavaType(descriptor)), true /* cap_next_letter */); + switch (GetJavaType(descriptor)) { + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_FLOAT: + case JAVATYPE_DOUBLE: + case JAVATYPE_BOOLEAN: + (*variables)["field_list_type"] = + "com.google.protobuf.Internal." + capitalized_type + "List"; + (*variables)["new_list"] = "new" + capitalized_type + "List"; + (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; + (*variables)["make_name_unmodifiable"] = + (*variables)["name"] + "_.makeImmutable()"; + (*variables)["repeated_index_get"] = + (*variables)["name"] + "_.get" + capitalized_type + "(index)"; + (*variables)["repeated_add"] = + (*variables)["name"] + "_.add" + capitalized_type; + (*variables)["repeated_set"] = + (*variables)["name"] + "_.set" + capitalized_type; + break; + default: + (*variables)["field_list_type"] = + "com.google.protobuf.Internal.ProtobufList<" + + (*variables)["boxed_type"] + ">"; + (*variables)["new_list"] = "newProtobufList"; + (*variables)["empty_list"] = "emptyProtobufList()"; + (*variables)["make_name_unmodifiable"] = + (*variables)["name"] + "_.makeImmutable()"; + (*variables)["repeated_index_get"] = + (*variables)["name"] + "_.get(index)"; + (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; + (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; + } + + if (IsReferenceType(GetJavaType(descriptor))) { + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + } else { + (*variables)["null_check"] = ""; + } + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + int fixed_size = FixedSize(GetType(descriptor)); + if (fixed_size != -1) { + (*variables)["fixed_size"] = SimpleItoa(fixed_size); + } + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + } else { + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + } + } + + // For repeated builders, the underlying list tracks mutability state. + (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()"; + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +} // namespace + +// =================================================================== + +ImmutablePrimitiveFieldLiteGenerator:: +ImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {} + +int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const { + return 1; +} + +int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$();\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private $field_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return $name$_;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + "$null_check$" + " $set_has_field_bit_message$\n" + " $name$_ = value;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n"); + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { + // The default value is not a simple literal so we want to avoid executing + // it multiple times. Instead, get the default out of the default instance. + printer->Print(variables_, + " $name$_ = getDefaultInstance().get$capitalized_name$();\n"); + } else { + printer->Print(variables_, + " $name$_ = $default$;\n"); + } + printer->Print(variables_, + "}\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for primitives +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateBuilderClearCode(io::Printer* printer) const { + // noop for primitives +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (other.get$capitalized_name$() != $default$) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); + } +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + // noop for primitives +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + // noop for scalars +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$set_has_field_bit_message$\n" + "$name$_ = input.read$capitalized_type$();\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for primitives. +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.write$capitalized_type$($number$, $name$_);\n" + "}\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$Size($number$, $name$_);\n" + "}\n"); +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + switch (GetJavaType(descriptor_)) { + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "result = result && (get$capitalized_name$()\n" + " == other.get$capitalized_name$());\n"); + break; + + case JAVATYPE_FLOAT: + printer->Print(variables_, + "result = result && (\n" + " java.lang.Float.floatToIntBits(get$capitalized_name$())\n" + " == java.lang.Float.floatToIntBits(\n" + " other.get$capitalized_name$()));\n"); + break; + + case JAVATYPE_DOUBLE: + printer->Print(variables_, + "result = result && (\n" + " java.lang.Double.doubleToLongBits(get$capitalized_name$())\n" + " == java.lang.Double.doubleToLongBits(\n" + " other.get$capitalized_name$()));\n"); + break; + + case JAVATYPE_STRING: + case JAVATYPE_BYTES: + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); + break; + + case JAVATYPE_ENUM: + case JAVATYPE_MESSAGE: + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } +} + +void ImmutablePrimitiveFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n"); + switch (GetJavaType(descriptor_)) { + case JAVATYPE_INT: + printer->Print(variables_, + "hash = (53 * hash) + get$capitalized_name$();\n"); + break; + + case JAVATYPE_LONG: + printer->Print(variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_FLOAT: + printer->Print(variables_, + "hash = (53 * hash) + java.lang.Float.floatToIntBits(\n" + " get$capitalized_name$());\n"); + break; + + case JAVATYPE_DOUBLE: + printer->Print(variables_, + "hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n" + " java.lang.Double.doubleToLongBits(get$capitalized_name$()));\n"); + break; + + case JAVATYPE_STRING: + case JAVATYPE_BYTES: + printer->Print(variables_, + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); + break; + + case JAVATYPE_ENUM: + case JAVATYPE_MESSAGE: + default: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } +} + +string ImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +// =================================================================== + +ImmutablePrimitiveOneofFieldLiteGenerator:: +ImmutablePrimitiveOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutablePrimitiveFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutablePrimitiveOneofFieldLiteGenerator:: +~ImmutablePrimitiveOneofFieldLiteGenerator() {} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " return ($boxed_type$) $oneof_name$_;\n" + " }\n" + " return $default$;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$($type$ value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); +} + + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + // noop for primitives +} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "set$capitalized_name$(other.get$capitalized_name$());\n"); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$set_oneof_case_message$;\n" + "$oneof_name$_ = input.read$capitalized_type$();\n"); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.write$capitalized_type$(\n" + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n" + "}\n"); +} + +void ImmutablePrimitiveOneofFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$Size(\n" + " $number$, ($type$)(($boxed_type$) $oneof_name$_));\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutablePrimitiveFieldLiteGenerator:: +RepeatedImmutablePrimitiveFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutablePrimitiveFieldLiteGenerator:: +~RepeatedImmutablePrimitiveFieldLiteGenerator() {} + +int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutablePrimitiveFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$$type$ get$capitalized_name$(int index);\n"); +} + + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private $field_list_type$ $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$boxed_type$>\n" + " get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return $repeated_index_get$;\n" + "}\n"); + + if (descriptor_->options().packed() && + HasGeneratedMethods(descriptor_->containing_type())) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize = -1;\n"); + } + + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$is_mutable$) {\n" + " $name$_ = $new_list$($name$_);\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, $type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_set$(index, value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$($type$ value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $repeated_add$(value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = $empty_list$;\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.util.List<$boxed_type$>\n" + " get$capitalized_name$List() {\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public $type$ get$capitalized_name$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, $type$ value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$($type$ value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for primitives +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateBuilderClearCode(io::Printer* printer) const { + // noop for primitives +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateBuildingCode(io::Printer* printer) const { + // noop for primitives +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.makeImmutable();\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ = $new_list$();\n" + "}\n" + "$repeated_add$(input.read$capitalized_type$());\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" + " $name$_ = $new_list$();\n" + "}\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " $repeated_add$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_mutable$) {\n" + " $make_name_unmodifiable$;\n" + "}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // We invoke getSerializedSize in writeTo for messages that have packed + // fields in ImmutableMessageGenerator::GenerateMessageSerializationMethods. + // That makes it safe to rely on the memoized size here. + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n" + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$capitalized_type$NoTag($name$_.get(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$capitalized_type$($number$, $name$_.get(i));\n" + "}\n"); + } +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + if (FixedSize(GetType(descriptor_)) == -1) { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .compute$capitalized_type$SizeNoTag($name$_.get(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); + } + + printer->Print( + "size += dataSize;\n"); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {\n" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeInt32SizeNoTag(dataSize);\n" + "}\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List());\n"); +} + +void RepeatedImmutablePrimitiveFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +string RepeatedImmutablePrimitiveFieldLiteGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h new file mode 100644 index 0000000000..ad603c2ac7 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h @@ -0,0 +1,163 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutablePrimitiveFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit ImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutablePrimitiveFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateBuilderClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + protected: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveFieldLiteGenerator); +}; + +class ImmutablePrimitiveOneofFieldLiteGenerator + : public ImmutablePrimitiveFieldLiteGenerator { + public: + ImmutablePrimitiveOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutablePrimitiveOneofFieldLiteGenerator(); + + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutablePrimitiveOneofFieldLiteGenerator); +}; + +class RepeatedImmutablePrimitiveFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutablePrimitiveFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + virtual ~RepeatedImmutablePrimitiveFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateBuilderClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateBuildingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutablePrimitiveFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 8aa5699c4a..68e863ccc3 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -208,7 +208,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableStringFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_;\n"); + "private volatile java.lang.Object $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc new file mode 100644 index 0000000000..51bb245c49 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -0,0 +1,1013 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + const FieldGeneratorInfo* info, + ClassNameResolver* name_resolver, + map* variables) { + SetCommonFieldVariables(descriptor, info, variables); + + (*variables)["empty_list"] = "emptyLazyStringArrayList()"; + + (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["default_init"] = + "= " + ImmutableDefaultValue(descriptor, name_resolver); + (*variables)["capitalized_type"] = "String"; + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + + // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported + // by the proto compiler + (*variables)["deprecation"] = descriptor->options().deprecated() + ? "@java.lang.Deprecated " : ""; + (*variables)["on_changed"] = + HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + + if (SupportFieldPresence(descriptor->file())) { + // For singular messages and builders, one bit is used for the hasField bit. + (*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); + + // Note that these have a trailing ";". + (*variables)["set_has_field_bit_message"] = + GenerateSetBit(messageBitIndex) + ";"; + (*variables)["clear_has_field_bit_message"] = + GenerateClearBit(messageBitIndex) + ";"; + + (*variables)["is_field_present_message"] = GenerateGetBit(messageBitIndex); + } else { + (*variables)["set_has_field_bit_message"] = ""; + (*variables)["clear_has_field_bit_message"] = ""; + + (*variables)["is_field_present_message"] = + "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()"; + } + + // For repeated builders, the underlying list tracks mutability state. + (*variables)["is_mutable"] = (*variables)["name"] + "_.isModifiable()"; + + (*variables)["get_has_field_bit_from_local"] = + GenerateGetBitFromLocal(builderBitIndex); + (*variables)["set_has_field_bit_to_local"] = + GenerateSetBitToLocal(messageBitIndex); +} + +bool CheckUtf8(const FieldDescriptor* descriptor) { + return descriptor->file()->options().java_string_check_utf8(); +} + +} // namespace + +// =================================================================== + +ImmutableStringFieldLiteGenerator:: +ImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {} + +int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const { + return 1; +} + +int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +// A note about how strings are handled. This code used to just store a String +// in the Message. This had two issues: +// +// 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded +// strings, but rather fields that were raw bytes incorrectly marked +// as strings in the proto file. This is common because in the proto1 +// syntax, string was the way to indicate bytes and C++ engineers can +// easily make this mistake without affecting the C++ API. By converting to +// strings immediately, some java code might corrupt these byte arrays as +// it passes through a java server even if the field was never accessed by +// application code. +// +// 2. There's a performance hit to converting between bytes and strings and +// it many cases, the field is never even read by the application code. This +// avoids unnecessary conversions in the common use cases. +// +// So now, the field for String is maintained as an Object reference which can +// either store a String or a ByteString. The code uses an instanceof check +// to see which one it has and converts to the other one if needed. It remembers +// the last value requested (in a thread safe manner) as this is most likely +// the one needed next. The thread safety is such that if two threads both +// convert the field because the changes made by each thread were not visible to +// the other, they may cause a conversion to happen more times than would +// otherwise be necessary. This was deemed better than adding synchronization +// overhead. It will not cause any corruption issues or affect the behavior of +// the API. The instanceof check is also highly optimized in the JVM and we +// decided it was better to reduce the memory overhead by not having two +// separate fields but rather use dynamic type checking. +// +// For single fields, the logic for this is done inside the generated code. For +// repeated fields, the logic is done in LazyStringArrayList and +// UnmodifiableLazyStringList. +void ImmutableStringFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$boolean has$capitalized_name$();\n"); + } + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.lang.String get$capitalized_name$();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes();\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private java.lang.Object $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $get_has_field_bit_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof java.lang.String) {\n" + " return (java.lang.String) ref;\n" + " } else {\n" + " com.google.protobuf.ByteString bs = \n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " $name$_ = s;\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8()) {\n" + " $name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " java.lang.Object ref = $name$_;\n" + " if (ref instanceof java.lang.String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " $name$_ = b;\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_has_field_bit_message$\n" + " $name$_ = value;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $clear_has_field_bit_message$\n" + // The default value is not a simple literal so we want to avoid executing + // it multiple times. Instead, get the default out of the default instance. + " $name$_ = getDefaultInstance().get$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_has_field_bit_message$\n" + " $name$_ = value;\n" + "}\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " return instance.get$capitalized_name$Bytes();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for strings +} + +void ImmutableStringFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " $set_has_field_bit_message$\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.get$capitalized_name$().isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " $on_changed$\n" + "}\n"); + } +} + +void ImmutableStringFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + // noop for scalars +} + +void ImmutableStringFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n" + "$set_has_field_bit_message$\n" + "$name$_ = s;\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_has_field_bit_message$\n" + "$name$_ = bs;\n"); + } +} + +void ImmutableStringFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + // noop for strings +} + +void ImmutableStringFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_field_present_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && get$capitalized_name$()\n" + " .equals(other.get$capitalized_name$());\n"); +} + +void ImmutableStringFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "hash = (37 * hash) + $constant_name$;\n"); + printer->Print(variables_, + "hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); +} + +string ImmutableStringFieldLiteGenerator::GetBoxedType() const { + return "java.lang.String"; +} + +// =================================================================== + +ImmutableStringOneofFieldLiteGenerator:: +ImmutableStringOneofFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : ImmutableStringFieldLiteGenerator( + descriptor, messageBitIndex, builderBitIndex, context) { + const OneofGeneratorInfo* info = + context->GetOneofGeneratorInfo(descriptor->containing_oneof()); + SetCommonOneofVariables(descriptor, info, &variables_); +} + +ImmutableStringOneofFieldLiteGenerator:: +~ImmutableStringOneofFieldLiteGenerator() {} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + PrintExtraFieldInfo(variables_, printer); + + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return $has_oneof_case_message$;\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " return (java.lang.String) ref;\n" + " } else {\n" + " com.google.protobuf.ByteString bs = \n" + " (com.google.protobuf.ByteString) ref;\n" + " java.lang.String s = bs.toStringUtf8();\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } else { + printer->Print(variables_, + " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" + " $oneof_name$_ = s;\n" + " }\n"); + } + printer->Print(variables_, + " return s;\n" + " }\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " java.lang.Object ref $default_init$;\n" + " if ($has_oneof_case_message$) {\n" + " ref = $oneof_name$_;\n" + " }\n" + " if (ref instanceof java.lang.String) {\n" + " com.google.protobuf.ByteString b = \n" + " com.google.protobuf.ByteString.copyFromUtf8(\n" + " (java.lang.String) ref);\n" + " if ($has_oneof_case_message$) {\n" + " $oneof_name$_ = b;\n" + " }\n" + " return b;\n" + " } else {\n" + " return (com.google.protobuf.ByteString) ref;\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " if ($has_oneof_case_message$) {\n" + " $clear_oneof_case_message$;\n" + " $oneof_name$_ = null;\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " $set_oneof_case_message$;\n" + " $oneof_name$_ = value;\n" + "}\n"); +} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + if (SupportFieldPresence(descriptor_->file())) { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public boolean has$capitalized_name$() {\n" + " return instance.has$capitalized_name$();\n" + "}\n"); + } + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$() {\n" + " return instance.get$capitalized_name$();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes() {\n" + " return instance.get$capitalized_name$Bytes();\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); +} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // Allow a slight breach of abstraction here in order to avoid forcing + // all string fields to Strings when copying fields from a Message. + printer->Print(variables_, + "$set_oneof_case_message$;\n" + "$oneof_name$_ = other.$oneof_name$_;\n" + "$on_changed$\n"); +} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = s;\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n" + "$set_oneof_case_message$;\n" + "$oneof_name$_ = bs;\n"); + } +} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} + +void ImmutableStringOneofFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($has_oneof_case_message$) {\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + "}\n"); +} + +// =================================================================== + +RepeatedImmutableStringFieldLiteGenerator:: +RepeatedImmutableStringFieldLiteGenerator(const FieldDescriptor* descriptor, + int messageBitIndex, + int builderBitIndex, + Context* context) + : descriptor_(descriptor), messageBitIndex_(messageBitIndex), + builderBitIndex_(builderBitIndex), context_(context), + name_resolver_(context->GetNameResolver()) { + SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, + context->GetFieldGeneratorInfo(descriptor), + name_resolver_, &variables_); +} + +RepeatedImmutableStringFieldLiteGenerator:: +~RepeatedImmutableStringFieldLiteGenerator() {} + +int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const { + return 0; +} + +int RepeatedImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { + return 0; +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateInterfaceMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ProtocolStringList\n" + " get$capitalized_name$List();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$int get$capitalized_name$Count();\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$java.lang.String get$capitalized_name$(int index);\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index);\n"); +} + + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private com.google.protobuf.LazyStringArrayList $name$_;\n"); + PrintExtraFieldInfo(variables_, printer); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ProtocolStringList\n" + " get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return $name$_.size();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" + " return $name$_.get(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index) {\n" + " return $name$_.getByteString(index);\n" + "}\n"); + + if (descriptor_->options().packed() && + HasGeneratedMethods(descriptor_->containing_type())) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize = -1;\n"); + } + + printer->Print(variables_, + "private void ensure$capitalized_name$IsMutable() {\n" + " if (!$is_mutable$) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" + " }\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void set$capitalized_name$(\n" + " int index, java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.set(index, value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$(\n" + " java.lang.String value) {\n" + "$null_check$" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " ensure$capitalized_name$IsMutable();\n" + " com.google.protobuf.AbstractMessageLite.addAll(\n" + " values, $name$_);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void clear$capitalized_name$() {\n" + " $name$_ = $empty_list$;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "private void add$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + "$null_check$"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " checkByteStringIsUtf8(value);\n"); + } + printer->Print(variables_, + " ensure$capitalized_name$IsMutable();\n" + " $name$_.add(value);\n" + "}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateBuilderMembers(io::Printer* printer) const { + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ProtocolStringList\n" + " get$capitalized_name$List() {\n" + " return ((com.google.protobuf.LazyStringList)\n" + " instance.get$capitalized_name$List()).getUnmodifiableView();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public int get$capitalized_name$Count() {\n" + " return instance.get$capitalized_name$Count();\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" + " return instance.get$capitalized_name$(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public com.google.protobuf.ByteString\n" + " get$capitalized_name$Bytes(int index) {\n" + " return instance.get$capitalized_name$Bytes(index);\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder set$capitalized_name$(\n" + " int index, java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.set$capitalized_name$(index, value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$(\n" + " java.lang.String value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$(value);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder addAll$capitalized_name$(\n" + " java.lang.Iterable values) {\n" + " copyOnWrite();\n" + " instance.addAll$capitalized_name$(values);\n" + " return this;\n" + "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder clear$capitalized_name$() {\n" + " copyOnWrite();\n" + " instance.clear$capitalized_name$();\n" + " return this;\n" + "}\n"); + + WriteFieldDocComment(printer, descriptor_); + printer->Print(variables_, + "$deprecation$public Builder add$capitalized_name$Bytes(\n" + " com.google.protobuf.ByteString value) {\n" + " copyOnWrite();\n" + " instance.add$capitalized_name$Bytes(value);\n" + " return this;\n" + "}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateFieldBuilderInitializationCode(io::Printer* printer) const { + // noop for strings +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $empty_list$;\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // The code below does two optimizations: + // 1. If the other list is empty, there's nothing to do. This ensures we + // don't allocate a new array if we already have an immutable one. + // 2. If the other list is non-empty and our current list is empty, we can + // reuse the other list which is guaranteed to be immutable. + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = other.$name$_;\n" + " } else {\n" + " ensure$capitalized_name$IsMutable();\n" + " $name$_.addAll(other.$name$_);\n" + " }\n" + " $on_changed$\n" + "}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_.makeImmutable();\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + "String s = input.readStringRequireUtf8();\n"); + } else if (!HasDescriptorMethods(descriptor_->file())) { + // Lite runtime should attempt to reduce allocations by attempting to + // construct the string directly from the input stream buffer. This avoids + // spurious intermediary ByteString allocations, cutting overall allocations + // in half. + printer->Print(variables_, + "String s = input.readString();\n"); + } else { + printer->Print(variables_, + "com.google.protobuf.ByteString bs = input.readBytes();\n"); + } + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + "}\n"); + if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { + printer->Print(variables_, + "$name$_.add(s);\n"); + } else { + printer->Print(variables_, + "$name$_.add(bs);\n"); + } +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" + " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + "}\n" + "while (input.getBytesUntilLimit() > 0) {\n"); + if (CheckUtf8(descriptor_)) { + printer->Print(variables_, + " String s = input.readStringRequireUtf8();\n"); + } else { + printer->Print(variables_, + " String s = input.readString();\n"); + } + printer->Print(variables_, + " $name$.add(s);\n"); + printer->Print(variables_, + "}\n" + "input.popLimit(limit);\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateParsingDoneCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($is_mutable$) {\n" + " $name$_.makeImmutable();\n" + "}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n" + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.write$capitalized_type$NoTag($name$_.get(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " output.writeBytes($number$, $name$_.getByteString(i));\n" + "}\n"); + } +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + printer->Print(variables_, + "for (int i = 0; i < $name$_.size(); i++) {\n" + " dataSize += com.google.protobuf.CodedOutputStream\n" + " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + "}\n"); + + printer->Print( + "size += dataSize;\n"); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {\n" + " size += $tag_size$;\n" + " size += com.google.protobuf.CodedOutputStream\n" + " .computeInt32SizeNoTag(dataSize);\n" + "}\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "result = result && get$capitalized_name$List()\n" + " .equals(other.get$capitalized_name$List());\n"); +} + +void RepeatedImmutableStringFieldLiteGenerator:: +GenerateHashCode(io::Printer* printer) const { + printer->Print(variables_, + "if (get$capitalized_name$Count() > 0) {\n" + " hash = (37 * hash) + $constant_name$;\n" + " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" + "}\n"); +} + +string RepeatedImmutableStringFieldLiteGenerator::GetBoxedType() const { + return "String"; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h new file mode 100644 index 0000000000..9d93b30796 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_string_field_lite.h @@ -0,0 +1,158 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Author: jonp@google.com (Jon Perlow) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator { + public: + explicit ImmutableStringFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableStringFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + protected: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringFieldLiteGenerator); +}; + +class ImmutableStringOneofFieldLiteGenerator + : public ImmutableStringFieldLiteGenerator { + public: + ImmutableStringOneofFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~ImmutableStringOneofFieldLiteGenerator(); + + private: + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableStringOneofFieldLiteGenerator); +}; + +class RepeatedImmutableStringFieldLiteGenerator + : public ImmutableFieldLiteGenerator { + public: + explicit RepeatedImmutableStringFieldLiteGenerator( + const FieldDescriptor* descriptor, int messageBitIndex, + int builderBitIndex, Context* context); + ~RepeatedImmutableStringFieldLiteGenerator(); + + // implements ImmutableFieldLiteGenerator ------------------------------------ + int GetNumBitsForMessage() const; + int GetNumBitsForBuilder() const; + void GenerateInterfaceMembers(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer) const; + void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; + void GenerateParsingDoneCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map variables_; + const int messageBitIndex_; + const int builderBitIndex_; + Context* context_; + ClassNameResolver* name_resolver_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedImmutableStringFieldLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_LITE_H__ diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index c50cdf54a8..a2eeee2d31 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -686,6 +686,8 @@ bool Parser::ParseMessageStatement(DescriptorProto* message, LocationRecorder location(message_location, DescriptorProto::kExtensionRangeFieldNumber); return ParseExtensions(message, location, containing_file); + } else if (LookingAt("reserved")) { + return ParseReserved(message, message_location); } else if (LookingAt("extend")) { LocationRecorder location(message_location, DescriptorProto::kExtensionFieldNumber); @@ -733,6 +735,13 @@ bool Parser::ParseMessageField(FieldDescriptorProto* field, FieldDescriptorProto::Label label; if (ParseLabel(&label, containing_file)) { field->set_label(label); + if (label == FieldDescriptorProto::LABEL_OPTIONAL && + syntax_identifier_ == "proto3") { + AddError( + "Explicit 'optional' labels are disallowed in the Proto3 syntax. " + "To define 'optional' fields in Proto3, simply remove the " + "'optional' label, as fields are 'optional' by default."); + } } } @@ -1353,6 +1362,77 @@ bool Parser::ParseExtensions(DescriptorProto* message, return true; } +// This is similar to extension range parsing, except that "max" is not +// supported, and accepts field name literals. +bool Parser::ParseReserved(DescriptorProto* message, + const LocationRecorder& message_location) { + // Parse the declaration. + DO(Consume("reserved")); + if (LookingAtType(io::Tokenizer::TYPE_STRING)) { + LocationRecorder location(message_location, + DescriptorProto::kReservedNameFieldNumber); + return ParseReservedNames(message, location); + } else { + LocationRecorder location(message_location, + DescriptorProto::kReservedRangeFieldNumber); + return ParseReservedNumbers(message, location); + } +} + + +bool Parser::ParseReservedNames(DescriptorProto* message, + const LocationRecorder& parent_location) { + do { + LocationRecorder location(parent_location, message->reserved_name_size()); + DO(ConsumeString(message->add_reserved_name(), "Expected field name.")); + } while (TryConsume(",")); + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + +bool Parser::ParseReservedNumbers(DescriptorProto* message, + const LocationRecorder& parent_location) { + bool first = true; + do { + LocationRecorder location(parent_location, message->reserved_range_size()); + + DescriptorProto::ReservedRange* range = message->add_reserved_range(); + int start, end; + io::Tokenizer::Token start_token; + { + LocationRecorder start_location( + location, DescriptorProto::ReservedRange::kStartFieldNumber); + start_token = input_->current(); + DO(ConsumeInteger(&start, (first ? + "Expected field name or number range." : + "Expected field number range."))); + } + + if (TryConsume("to")) { + LocationRecorder end_location( + location, DescriptorProto::ReservedRange::kEndFieldNumber); + DO(ConsumeInteger(&end, "Expected integer.")); + } else { + LocationRecorder end_location( + location, DescriptorProto::ReservedRange::kEndFieldNumber); + end_location.StartAt(start_token); + end_location.EndAt(start_token); + end = start; + } + + // Users like to specify inclusive ranges, but in code we like the end + // number to be exclusive. + ++end; + + range->set_start(start); + range->set_end(end); + first = false; + } while (TryConsume(",")); + + DO(ConsumeEndOfDeclaration(";", &parent_location)); + return true; +} + bool Parser::ParseExtend(RepeatedPtrField* extensions, RepeatedPtrField* messages, const LocationRecorder& parent_location, diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 7cb1678a6b..16012e9603 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -364,6 +364,14 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& extensions_location, const FileDescriptorProto* containing_file); + // Parse an "reserved" declaration. + bool ParseReserved(DescriptorProto* message, + const LocationRecorder& message_location); + bool ParseReservedNames(DescriptorProto* message, + const LocationRecorder& parent_location); + bool ParseReservedNumbers(DescriptorProto* message, + const LocationRecorder& parent_location); + // Parse an "extend" declaration. (See also comments for // ParseMessageField().) bool ParseExtend(RepeatedPtrField* extensions, diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 1684bebed9..ddf34bfa45 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -620,6 +620,36 @@ TEST_F(ParseMessageTest, NestedEnum) { "}"); } +TEST_F(ParseMessageTest, ReservedRange) { + ExpectParsesTo( + "message TestMessage {\n" + " required int32 foo = 1;\n" + " reserved 2, 15, 9 to 11, 3;\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" + " reserved_range { start:2 end:3 }" + " reserved_range { start:15 end:16 }" + " reserved_range { start:9 end:12 }" + " reserved_range { start:3 end:4 }" + "}"); +} + +TEST_F(ParseMessageTest, ReservedNames) { + ExpectParsesTo( + "message TestMessage {\n" + " reserved \"foo\", \"bar\";\n" + "}\n", + + "message_type {" + " name: \"TestMessage\"" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + "}"); +} + TEST_F(ParseMessageTest, ExtensionRange) { ExpectParsesTo( "message TestMessage {\n" @@ -715,19 +745,17 @@ TEST_F(ParseMessageTest, MultipleExtensionsOneExtendee) { " type_name:\"TestMessage\" extendee: \"Extendee1\" }"); } -TEST_F(ParseMessageTest, OptionalOptionalLabelProto3) { +TEST_F(ParseMessageTest, OptionalLabelProto3) { ExpectParsesTo( "syntax = \"proto3\";\n" "message TestMessage {\n" " int32 foo = 1;\n" - " optional int32 bar = 2;\n" "}\n", "syntax: \"proto3\" " "message_type {" " name: \"TestMessage\"" - " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }" - " field { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:2 } }"); + " field { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 } }"); } // =================================================================== @@ -1230,6 +1258,18 @@ TEST_F(ParseErrorTest, EofInAggregateValue) { "1:0: Unexpected end of stream while parsing aggregate value.\n"); } +TEST_F(ParseErrorTest, ExplicitOptionalLabelProto3) { + ExpectHasErrors( + "syntax = 'proto3';\n" + "message TestMessage {\n" + " optional int32 foo = 1;\n" + "}\n", + "2:11: Explicit 'optional' labels are disallowed in the Proto3 syntax. " + "To define 'optional' fields in Proto3, simply remove the 'optional' " + "label, as fields are 'optional' by default.\n"); +} + + // ------------------------------------------------------------------- // Enum errors @@ -1247,6 +1287,33 @@ TEST_F(ParseErrorTest, EnumValueMissingNumber) { "1:5: Missing numeric value for enum constant.\n"); } +// ------------------------------------------------------------------- +// Reserved field number errors + +TEST_F(ParseErrorTest, ReservedMaxNotAllowed) { + ExpectHasErrors( + "message Foo {\n" + " reserved 10 to max;\n" + "}\n", + "1:17: Expected integer.\n"); +} + +TEST_F(ParseErrorTest, ReservedMixNameAndNumber) { + ExpectHasErrors( + "message Foo {\n" + " reserved 10, \"foo\";\n" + "}\n", + "1:15: Expected field number range.\n"); +} + +TEST_F(ParseErrorTest, ReservedMissingQuotes) { + ExpectHasErrors( + "message Foo {\n" + " reserved foo;\n" + "}\n", + "1:11: Expected field name or number range.\n"); +} + // ------------------------------------------------------------------- // Service errors diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index ad501acfc1..cdcaffde97 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -134,20 +134,34 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { CodeGeneratorResponse response; GeneratorResponseContext context(&response, parsed_files); - for (int i = 0; i < parsed_files.size(); i++) { - const FileDescriptor* file = parsed_files[i]; - + if (generator->HasGenerateAll()) { string error; - bool succeeded = generator->Generate( - file, request.parameter(), &context, &error); + bool succeeded = generator->GenerateAll( + parsed_files, request.parameter(), &context, &error); if (!succeeded && error.empty()) { error = "Code generator returned false but provided no error " "description."; } if (!error.empty()) { - response.set_error(file->name() + ": " + error); - break; + response.set_error(error); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + const FileDescriptor* file = parsed_files[i]; + + string error; + bool succeeded = generator->Generate( + file, request.parameter(), &context, &error); + + if (!succeeded && error.empty()) { + error = "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response.set_error(file->name() + ": " + error); + break; + } } } diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index d78b715e00..344ed45011 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -179,7 +179,7 @@ const int CodeGeneratorRequest::kProtoFileFieldNumber; #endif // !_MSC_VER CodeGeneratorRequest::CodeGeneratorRequest() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorRequest) } @@ -300,12 +300,15 @@ bool CodeGeneratorRequest::MergePartialFromCodedStream( case 15: { if (tag == 122) { parse_proto_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_proto_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_proto_file())); } else { goto handle_unusual; } - if (input->ExpectTag(122)) goto parse_proto_file; + if (input->ExpectTag(122)) goto parse_loop_proto_file; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -445,9 +448,9 @@ int CodeGeneratorRequest::ByteSize() const { void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const CodeGeneratorRequest* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const CodeGeneratorRequest* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -513,10 +516,10 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) { // CodeGeneratorRequest // repeated string file_to_generate = 1; - int CodeGeneratorRequest::file_to_generate_size() const { +int CodeGeneratorRequest::file_to_generate_size() const { return file_to_generate_.size(); } - void CodeGeneratorRequest::clear_file_to_generate() { +void CodeGeneratorRequest::clear_file_to_generate() { file_to_generate_.Clear(); } const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { @@ -567,16 +570,16 @@ CodeGeneratorRequest::mutable_file_to_generate() { } // optional string parameter = 2; - bool CodeGeneratorRequest::has_parameter() const { +bool CodeGeneratorRequest::has_parameter() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void CodeGeneratorRequest::set_has_parameter() { +void CodeGeneratorRequest::set_has_parameter() { _has_bits_[0] |= 0x00000002u; } - void CodeGeneratorRequest::clear_has_parameter() { +void CodeGeneratorRequest::clear_has_parameter() { _has_bits_[0] &= ~0x00000002u; } - void CodeGeneratorRequest::clear_parameter() { +void CodeGeneratorRequest::clear_parameter() { parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_parameter(); } @@ -620,10 +623,10 @@ CodeGeneratorRequest::mutable_file_to_generate() { } // repeated .google.protobuf.FileDescriptorProto proto_file = 15; - int CodeGeneratorRequest::proto_file_size() const { +int CodeGeneratorRequest::proto_file_size() const { return proto_file_.size(); } - void CodeGeneratorRequest::clear_proto_file() { +void CodeGeneratorRequest::clear_proto_file() { proto_file_.Clear(); } const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { @@ -660,7 +663,7 @@ const int CodeGeneratorResponse_File::kContentFieldNumber; #endif // !_MSC_VER CodeGeneratorResponse_File::CodeGeneratorResponse_File() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse.File) } @@ -946,9 +949,9 @@ int CodeGeneratorResponse_File::ByteSize() const { void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const CodeGeneratorResponse_File* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const CodeGeneratorResponse_File* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1024,7 +1027,7 @@ const int CodeGeneratorResponse::kFileFieldNumber; #endif // !_MSC_VER CodeGeneratorResponse::CodeGeneratorResponse() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.compiler.CodeGeneratorResponse) } @@ -1124,12 +1127,15 @@ bool CodeGeneratorResponse::MergePartialFromCodedStream( case 15: { if (tag == 122) { parse_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_file())); } else { goto handle_unusual; } - if (input->ExpectTag(122)) goto parse_file; + if (input->ExpectTag(122)) goto parse_loop_file; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -1242,9 +1248,9 @@ int CodeGeneratorResponse::ByteSize() const { void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const CodeGeneratorResponse* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const CodeGeneratorResponse* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1307,16 +1313,16 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { // CodeGeneratorResponse_File // optional string name = 1; - bool CodeGeneratorResponse_File::has_name() const { +bool CodeGeneratorResponse_File::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void CodeGeneratorResponse_File::set_has_name() { +void CodeGeneratorResponse_File::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void CodeGeneratorResponse_File::clear_has_name() { +void CodeGeneratorResponse_File::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void CodeGeneratorResponse_File::clear_name() { +void CodeGeneratorResponse_File::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -1360,16 +1366,16 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { } // optional string insertion_point = 2; - bool CodeGeneratorResponse_File::has_insertion_point() const { +bool CodeGeneratorResponse_File::has_insertion_point() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void CodeGeneratorResponse_File::set_has_insertion_point() { +void CodeGeneratorResponse_File::set_has_insertion_point() { _has_bits_[0] |= 0x00000002u; } - void CodeGeneratorResponse_File::clear_has_insertion_point() { +void CodeGeneratorResponse_File::clear_has_insertion_point() { _has_bits_[0] &= ~0x00000002u; } - void CodeGeneratorResponse_File::clear_insertion_point() { +void CodeGeneratorResponse_File::clear_insertion_point() { insertion_point_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_insertion_point(); } @@ -1413,16 +1419,16 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { } // optional string content = 15; - bool CodeGeneratorResponse_File::has_content() const { +bool CodeGeneratorResponse_File::has_content() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void CodeGeneratorResponse_File::set_has_content() { +void CodeGeneratorResponse_File::set_has_content() { _has_bits_[0] |= 0x00000004u; } - void CodeGeneratorResponse_File::clear_has_content() { +void CodeGeneratorResponse_File::clear_has_content() { _has_bits_[0] &= ~0x00000004u; } - void CodeGeneratorResponse_File::clear_content() { +void CodeGeneratorResponse_File::clear_content() { content_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_content(); } @@ -1470,16 +1476,16 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { // CodeGeneratorResponse // optional string error = 1; - bool CodeGeneratorResponse::has_error() const { +bool CodeGeneratorResponse::has_error() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void CodeGeneratorResponse::set_has_error() { +void CodeGeneratorResponse::set_has_error() { _has_bits_[0] |= 0x00000001u; } - void CodeGeneratorResponse::clear_has_error() { +void CodeGeneratorResponse::clear_has_error() { _has_bits_[0] &= ~0x00000001u; } - void CodeGeneratorResponse::clear_error() { +void CodeGeneratorResponse::clear_error() { error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_error(); } @@ -1523,10 +1529,10 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) { } // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; - int CodeGeneratorResponse::file_size() const { +int CodeGeneratorResponse::file_size() const { return file_.size(); } - void CodeGeneratorResponse::clear_file() { +void CodeGeneratorResponse::clear_file() { file_.Clear(); } const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index ea48b8b5bd..6fcaea2e80 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -796,6 +796,10 @@ CodeGeneratorResponse::mutable_file() { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index bfdacd9591..2855c377e1 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -1518,6 +1518,18 @@ Descriptor::FindExtensionRangeContainingNumber(int number) const { return NULL; } +const Descriptor::ReservedRange* +Descriptor::FindReservedRangeContainingNumber(int number) const { + // TODO(chrisn): Consider a non-linear search. + for (int i = 0; i < reserved_range_count(); i++) { + if (number >= reserved_range(i)->start && + number < reserved_range(i)->end) { + return reserved_range(i); + } + } + return NULL; +} + // ------------------------------------------------------------------- bool DescriptorPool::TryFindFileInFallbackDatabase(const string& name) const { @@ -1741,6 +1753,14 @@ void Descriptor::CopyTo(DescriptorProto* proto) const { for (int i = 0; i < extension_count(); i++) { extension(i)->CopyTo(proto->add_extension()); } + for (int i = 0; i < reserved_range_count(); i++) { + DescriptorProto::ReservedRange* range = proto->add_reserved_range(); + range->set_start(reserved_range(i)->start); + range->set_end(reserved_range(i)->end); + } + for (int i = 0; i < reserved_name_count(); i++) { + proto->add_reserved_name(reserved_name(i)); + } if (&options() != &MessageOptions::default_instance()) { proto->mutable_options()->CopyFrom(options()); @@ -2186,6 +2206,29 @@ void Descriptor::DebugString(int depth, string *contents, if (extension_count() > 0) strings::SubstituteAndAppend(contents, "$0 }\n", prefix); + if (reserved_range_count() > 0) { + strings::SubstituteAndAppend(contents, "$0 reserved ", prefix); + for (int i = 0; i < reserved_range_count(); i++) { + const Descriptor::ReservedRange* range = reserved_range(i); + if (range->end == range->start + 1) { + strings::SubstituteAndAppend(contents, "$0, ", range->start); + } else { + strings::SubstituteAndAppend(contents, "$0 to $1, ", + range->start, range->end - 1); + } + } + contents->replace(contents->size() - 2, 2, ";\n"); + } + + if (reserved_name_count() > 0) { + strings::SubstituteAndAppend(contents, "$0 reserved ", prefix); + for (int i = 0; i < reserved_name_count(); i++) { + strings::SubstituteAndAppend(contents, "\"$0\", ", + CEscape(reserved_name(i))); + } + contents->replace(contents->size() - 2, 2, ";\n"); + } + strings::SubstituteAndAppend(contents, "$0}\n", prefix); comment_printer.AddPostComment(contents); } @@ -2278,8 +2321,12 @@ void FieldDescriptor::DebugString(int depth, } if (type() == TYPE_GROUP) { - message_type()->DebugString(depth, contents, debug_string_options, - /* include_opening_clause */ false); + if (debug_string_options.elide_group_body) { + contents->append(" { ... };\n"); + } else { + message_type()->DebugString(depth, contents, debug_string_options, + /* include_opening_clause */ false); + } } else { contents->append(";\n"); } @@ -2308,12 +2355,16 @@ void OneofDescriptor::DebugString(int depth, string* contents, comment_printer(this, prefix, debug_string_options); comment_printer.AddPreComment(contents); strings::SubstituteAndAppend( - contents, "$0 oneof $1 {\n", prefix, name()); - for (int i = 0; i < field_count(); i++) { - field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents, - debug_string_options); + contents, "$0 oneof $1 {", prefix, name()); + if (debug_string_options.elide_oneof_body) { + contents->append(" ... }\n"); + } else { + for (int i = 0; i < field_count(); i++) { + field(i)->DebugString(depth, FieldDescriptor::OMIT_LABEL, contents, + debug_string_options); + } + strings::SubstituteAndAppend(contents, "$0}\n", prefix); } - strings::SubstituteAndAppend(contents, "$0}\n", prefix); comment_printer.AddPostComment(contents); } @@ -2491,7 +2542,12 @@ bool FileDescriptor::GetSourceLocation(SourceLocation* out_location) const { } bool FieldDescriptor::is_packed() const { - return is_packable() && (options_ != NULL) && options_->packed(); + if (!is_packable()) return false; + if (file_->syntax() == FileDescriptor::SYNTAX_PROTO2) { + return (options_ != NULL) && options_->packed(); + } else { + return options_ == NULL || !options_->has_packed() || options_->packed(); + } } bool Descriptor::GetSourceLocation(SourceLocation* out_location) const { @@ -2604,7 +2660,7 @@ void MethodDescriptor::GetLocationPath(vector* output) const { namespace { // Represents an options message to interpret. Extension names in the option -// name are respolved relative to name_scope. element_name and orig_opt are +// name are resolved relative to name_scope. element_name and orig_opt are // used only for error reporting (since the parser records locations against // pointers in the original options, not the mutable copy). The Message must be // one of the Options messages in descriptor.proto. @@ -2830,6 +2886,9 @@ class DescriptorBuilder { void BuildExtensionRange(const DescriptorProto::ExtensionRange& proto, const Descriptor* parent, Descriptor::ExtensionRange* result); + void BuildReservedRange(const DescriptorProto::ReservedRange& proto, + const Descriptor* parent, + Descriptor::ReservedRange* result); void BuildOneof(const OneofDescriptorProto& proto, Descriptor* parent, OneofDescriptor* result); @@ -3920,6 +3979,17 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, BUILD_ARRAY(proto, result, enum_type , BuildEnum , result); BUILD_ARRAY(proto, result, extension_range, BuildExtensionRange, result); BUILD_ARRAY(proto, result, extension , BuildExtension , result); + BUILD_ARRAY(proto, result, reserved_range , BuildReservedRange , result); + + // Copy reserved names. + int reserved_name_count = proto.reserved_name_size(); + result->reserved_name_count_ = reserved_name_count; + result->reserved_names_ = + tables_->AllocateArray(reserved_name_count); + for (int i = 0; i < reserved_name_count; ++i) { + result->reserved_names_[i] = + tables_->AllocateString(proto.reserved_name(i)); + } // Copy options. if (!proto.has_options()) { @@ -3931,7 +4001,34 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result)); - // Check that no fields have numbers in extension ranges. + for (int i = 0; i < proto.reserved_range_size(); i++) { + const DescriptorProto_ReservedRange& range1 = proto.reserved_range(i); + for (int j = i + 1; j < proto.reserved_range_size(); j++) { + const DescriptorProto_ReservedRange& range2 = proto.reserved_range(j); + if (range1.end() > range2.start() && range2.end() > range1.start()) { + AddError(result->full_name(), proto.reserved_range(i), + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Reserved range $0 to $1 overlaps with " + "already-defined range $2 to $3.", + range2.start(), range2.end() - 1, + range1.start(), range1.end() - 1)); + } + } + } + + hash_set reserved_name_set; + for (int i = 0; i < proto.reserved_name_size(); i++) { + const string& name = proto.reserved_name(i); + if (reserved_name_set.find(name) == reserved_name_set.end()) { + reserved_name_set.insert(name); + } else { + AddError(name, proto, DescriptorPool::ErrorCollector::NAME, + strings::Substitute( + "Field name \"$0\" is reserved multiple times.", + name)); + } + } + for (int i = 0; i < result->field_count(); i++) { const FieldDescriptor* field = result->field(i); for (int j = 0; j < result->extension_range_count(); j++) { @@ -3945,11 +4042,39 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, field->name(), field->number())); } } + for (int j = 0; j < result->reserved_range_count(); j++) { + const Descriptor::ReservedRange* range = result->reserved_range(j); + if (range->start <= field->number() && field->number() < range->end) { + AddError(field->full_name(), proto.reserved_range(j), + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute( + "Field \"$0\" uses reserved number $1.", + field->name(), field->number())); + } + } + if (reserved_name_set.find(field->name()) != reserved_name_set.end()) { + AddError(field->full_name(), proto.field(i), + DescriptorPool::ErrorCollector::NAME, + strings::Substitute( + "Field name \"$0\" is reserved.", field->name())); + } } - // Check that extension ranges don't overlap. + // Check that extension ranges don't overlap and don't include + // reserved field numbers. for (int i = 0; i < result->extension_range_count(); i++) { const Descriptor::ExtensionRange* range1 = result->extension_range(i); + for (int j = 0; j < result->reserved_range_count(); j++) { + const Descriptor::ReservedRange* range2 = result->reserved_range(j); + if (range1->end > range2->start && range2->end > range1->start) { + AddError(result->full_name(), proto.extension_range(j), + DescriptorPool::ErrorCollector::NUMBER, + strings::Substitute("Extension range $0 to $1 overlaps with " + "reserved range $2 to $3.", + range1->start, range1->end - 1, + range2->start, range2->end - 1)); + } + } for (int j = i + 1; j < result->extension_range_count(); j++) { const Descriptor::ExtensionRange* range2 = result->extension_range(j); if (range1->end > range2->start && range2->end > range1->start) { @@ -4262,6 +4387,19 @@ void DescriptorBuilder::BuildExtensionRange( } } +void DescriptorBuilder::BuildReservedRange( + const DescriptorProto::ReservedRange& proto, + const Descriptor* parent, + Descriptor::ReservedRange* result) { + result->start = proto.start(); + result->end = proto.end(); + if (result->start <= 0) { + AddError(parent->full_name(), proto, + DescriptorPool::ErrorCollector::NUMBER, + "Reserved numbers must be positive integers."); + } +} + void DescriptorBuilder::BuildOneof(const OneofDescriptorProto& proto, Descriptor* parent, OneofDescriptor* result) { @@ -4503,6 +4641,23 @@ void DescriptorBuilder::CrossLinkMessage( for (int i = 0; i < message->field_count(); i++) { const OneofDescriptor* oneof_decl = message->field(i)->containing_oneof(); if (oneof_decl != NULL) { + // Make sure fields belonging to the same oneof are defined consecutively. + // This enables optimizations in codegens and reflection libraries to + // skip fields in the oneof group, as only one of the field can be set. + // Note that field_count() returns how many fields in this oneof we have + // seen so far. field_count() > 0 guarantees that i > 0, so field(i-1) is + // safe. + if (oneof_decl->field_count() > 0 && + message->field(i - 1)->containing_oneof() != oneof_decl) { + AddWarning( + message->full_name() + "." + message->field(i - 1)->name(), + proto.field(i - 1), DescriptorPool::ErrorCollector::OTHER, + strings::Substitute( + "Fields in the same oneof must be defined consecutively. " + "\"$0\" cannot be defined before the completion of the " + "\"$1\" oneof definition.", + message->field(i - 1)->name(), oneof_decl->name())); + } // Must go through oneof_decls_ array to get a non-const version of the // OneofDescriptor. ++message->oneof_decls_[oneof_decl->index()].field_count_; @@ -4933,6 +5088,12 @@ void DescriptorBuilder::ValidateProto3Field( field->containing_type()->full_name() + "\" which is a proto3 message type."); } + bool allow_groups = false; + if (field->type() == FieldDescriptor::TYPE_GROUP && !allow_groups) { + AddError(field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "Groups are not supported in proto3 syntax."); + } } void DescriptorBuilder::ValidateProto3Enum( diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index c0a48cea9c..ca87d63415 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -135,10 +135,14 @@ struct DebugStringOptions { // example, the C++ code generation for fields in the proto compiler) rely on // DebugString() output being unobstructed by user comments. bool include_comments; + // If true, elide the braced body in the debug string. + bool elide_group_body; + bool elide_oneof_body; DebugStringOptions() - : include_comments(false) - {} + : include_comments(false), + elide_group_body(false), + elide_oneof_body(false) {} }; // Describes a type of protocol message, or a particular group within a @@ -298,6 +302,36 @@ class LIBPROTOBUF_EXPORT Descriptor { // this message type's scope. const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const; + // Reserved fields ------------------------------------------------- + + // A range of reserved field numbers. + struct ReservedRange { + int start; // inclusive + int end; // exclusive + }; + + // The number of reserved ranges in this message type. + int reserved_range_count() const; + // Gets an reserved range by index, where 0 <= index < + // reserved_range_count(). These are returned in the order they were defined + // in the .proto file. + const ReservedRange* reserved_range(int index) const; + + // Returns true if the number is in one of the reserved ranges. + bool IsReservedNumber(int number) const; + + // Returns NULL if no reserved range contains the given number. + const ReservedRange* FindReservedRangeContainingNumber(int number) const; + + // The number of reserved field names in this message type. + int reserved_name_count() const; + + // Gets a reserved name by index, where 0 <= index < reserved_name_count(). + const string& reserved_name(int index) const; + + // Returns true if the field name is reserved. + bool IsReservedName(const string& name) const; + // Source Location --------------------------------------------------- // Updates |*out_location| to the source location of the complete @@ -343,6 +377,10 @@ class LIBPROTOBUF_EXPORT Descriptor { ExtensionRange* extension_ranges_; int extension_count_; FieldDescriptor* extensions_; + int reserved_range_count_; + ReservedRange* reserved_ranges_; + int reserved_name_count_; + const string** reserved_names_; // IMPORTANT: If you add a new field, make sure to search for all instances // of Allocate() and AllocateArray() in descriptor.cc // and update them to initialize the field. @@ -1567,6 +1605,12 @@ PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension_range, const Descriptor::ExtensionRange*) PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, extension, const FieldDescriptor*) + +PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_range_count, int) +PROTOBUF_DEFINE_ARRAY_ACCESSOR(Descriptor, reserved_range, + const Descriptor::ReservedRange*) +PROTOBUF_DEFINE_ACCESSOR(Descriptor, reserved_name_count, int) + PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions); PROTOBUF_DEFINE_ACCESSOR(Descriptor, is_placeholder, bool) @@ -1667,6 +1711,25 @@ inline bool Descriptor::IsExtensionNumber(int number) const { return FindExtensionRangeContainingNumber(number) != NULL; } +inline bool Descriptor::IsReservedNumber(int number) const { + return FindReservedRangeContainingNumber(number) != NULL; +} + +inline bool Descriptor::IsReservedName(const string& name) const { + for (int i = 0; i < reserved_name_count(); i++) { + if (name == reserved_name(i)) { + return true; + } + } + return false; +} + +// Can't use PROTOBUF_DEFINE_ARRAY_ACCESSOR because reserved_names_ is actually +// an array of pointers rather than the usual array of objects. +inline const string& Descriptor::reserved_name(int index) const { + return *reserved_names_[index]; +} + inline bool FieldDescriptor::is_required() const { return label() == LABEL_REQUIRED; } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 8968f3621c..755c26175d 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -33,6 +33,9 @@ const ::google::protobuf::internal::GeneratedMessageReflection* const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* DescriptorProto_ExtensionRange_reflection_ = NULL; +const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + DescriptorProto_ReservedRange_reflection_ = NULL; const ::google::protobuf::Descriptor* FieldDescriptorProto_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* FieldDescriptorProto_reflection_ = NULL; @@ -64,6 +67,7 @@ const ::google::protobuf::Descriptor* FieldOptions_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* FieldOptions_reflection_ = NULL; const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL; +const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor_ = NULL; const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* EnumOptions_reflection_ = NULL; @@ -140,7 +144,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_), -1); DescriptorProto_descriptor_ = file->message_type(2); - static const int DescriptorProto_offsets_[8] = { + static const int DescriptorProto_offsets_[10] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_), @@ -149,6 +153,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, extension_range_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, oneof_decl_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, options_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_range_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, reserved_name_), }; DescriptorProto_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -177,6 +183,22 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { sizeof(DescriptorProto_ExtensionRange), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_), -1); + DescriptorProto_ReservedRange_descriptor_ = DescriptorProto_descriptor_->nested_type(1); + static const int DescriptorProto_ReservedRange_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, start_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, end_), + }; + DescriptorProto_ReservedRange_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + DescriptorProto_ReservedRange_descriptor_, + DescriptorProto_ReservedRange::default_instance_, + DescriptorProto_ReservedRange_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _has_bits_[0]), + -1, + -1, + sizeof(DescriptorProto_ReservedRange), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ReservedRange, _internal_metadata_), + -1); FieldDescriptorProto_descriptor_ = file->message_type(3); static const int FieldDescriptorProto_offsets_[9] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), @@ -338,9 +360,10 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_), -1); FieldOptions_descriptor_ = file->message_type(11); - static const int FieldOptions_offsets_[6] = { + static const int FieldOptions_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, jstype_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, lazy_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, weak_), @@ -358,6 +381,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_), -1); FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); + FieldOptions_JSType_descriptor_ = FieldOptions_descriptor_->enum_type(1); EnumOptions_descriptor_ = file->message_type(12); static const int EnumOptions_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_), @@ -514,6 +538,8 @@ void protobuf_RegisterTypes(const ::std::string&) { DescriptorProto_descriptor_, &DescriptorProto::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + DescriptorProto_ReservedRange_descriptor_, &DescriptorProto_ReservedRange::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( @@ -561,6 +587,8 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto() { delete DescriptorProto_reflection_; delete DescriptorProto_ExtensionRange::default_instance_; delete DescriptorProto_ExtensionRange_reflection_; + delete DescriptorProto_ReservedRange::default_instance_; + delete DescriptorProto_ReservedRange_reflection_; delete FieldDescriptorProto::default_instance_; delete FieldDescriptorProto_reflection_; delete OneofDescriptorProto::default_instance_; @@ -619,7 +647,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "\022-\n\007options\030\010 \001(\0132\034.google.protobuf.File" "Options\0229\n\020source_code_info\030\t \001(\0132\037.goog" "le.protobuf.SourceCodeInfo\022\016\n\006syntax\030\014 \001" - "(\t\"\344\003\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005" + "(\t\"\360\004\n\017DescriptorProto\022\014\n\004name\030\001 \001(\t\0224\n\005" "field\030\002 \003(\0132%.google.protobuf.FieldDescr" "iptorProto\0228\n\textension\030\006 \003(\0132%.google.p" "rotobuf.FieldDescriptorProto\0225\n\013nested_t" @@ -630,104 +658,111 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "ExtensionRange\0229\n\noneof_decl\030\010 \003(\0132%.goo" "gle.protobuf.OneofDescriptorProto\0220\n\007opt" "ions\030\007 \001(\0132\037.google.protobuf.MessageOpti" - "ons\032,\n\016ExtensionRange\022\r\n\005start\030\001 \001(\005\022\013\n\003" - "end\030\002 \001(\005\"\251\005\n\024FieldDescriptorProto\022\014\n\004na" - "me\030\001 \001(\t\022\016\n\006number\030\003 \001(\005\022:\n\005label\030\004 \001(\0162" - "+.google.protobuf.FieldDescriptorProto.L" - "abel\0228\n\004type\030\005 \001(\0162*.google.protobuf.Fie" - "ldDescriptorProto.Type\022\021\n\ttype_name\030\006 \001(" - "\t\022\020\n\010extendee\030\002 \001(\t\022\025\n\rdefault_value\030\007 \001" - "(\t\022\023\n\013oneof_index\030\t \001(\005\022.\n\007options\030\010 \001(\013" - "2\035.google.protobuf.FieldOptions\"\266\002\n\004Type" - "\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYP" - "E_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32" - "\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r" - "\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_G" - "ROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014" - "\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE" - "_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_S" - "INT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LAB" - "EL_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LAB" - "EL_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n" - "\004name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004n" - "ame\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protob" - "uf.EnumValueDescriptorProto\022-\n\007options\030\003" - " \001(\0132\034.google.protobuf.EnumOptions\"l\n\030En" - "umValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006" - "number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.p" - "rotobuf.EnumValueOptions\"\220\001\n\026ServiceDesc" - "riptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(" - "\0132&.google.protobuf.MethodDescriptorProt" - "o\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Ser" - "viceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n" - "\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outpu" - "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p" - "rotobuf.MethodOptions\022\037\n\020client_streamin" - "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010" - ":\005false\"\201\005\n\013FileOptions\022\024\n\014java_package\030" - "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j" - "ava_multiple_files\030\n \001(\010:\005false\022,\n\035java_" - "generate_equals_and_hash\030\024 \001(\010:\005false\022%\n" - "\026java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014" - "optimize_for\030\t \001(\0162).google.protobuf.Fil" - "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa" - "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f" - "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal" - "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031" - "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a" - "renas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030" - "$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" - "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" - "*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027messag" - "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" - "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031" - "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007" - " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" - "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" - "\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g" - "oogle.protobuf.FieldOptions.CType:\006STRIN" - "G\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022\031" - "\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:" - "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." - "google.protobuf.UninterpretedOption\"/\n\005C" - "Type\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIE" - "CE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow" - "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" - "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." - "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" - "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:" - "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." - "google.protobuf.UninterpretedOption*\t\010\350\007" - "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!" + "ons\022F\n\016reserved_range\030\t \003(\0132..google.pro" + "tobuf.DescriptorProto.ReservedRange\022\025\n\rr" + "eserved_name\030\n \003(\t\032,\n\016ExtensionRange\022\r\n\005" + "start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\032+\n\rReservedRang" + "e\022\r\n\005start\030\001 \001(\005\022\013\n\003end\030\002 \001(\005\"\251\005\n\024FieldD" + "escriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\003" + " \001(\005\022:\n\005label\030\004 \001(\0162+.google.protobuf.Fi" + "eldDescriptorProto.Label\0228\n\004type\030\005 \001(\0162*" + ".google.protobuf.FieldDescriptorProto.Ty" + "pe\022\021\n\ttype_name\030\006 \001(\t\022\020\n\010extendee\030\002 \001(\t\022" + "\025\n\rdefault_value\030\007 \001(\t\022\023\n\013oneof_index\030\t " + "\001(\005\022.\n\007options\030\010 \001(\0132\035.google.protobuf.F" + "ieldOptions\"\266\002\n\004Type\022\017\n\013TYPE_DOUBLE\020\001\022\016\n" + "\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UI" + "NT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006" + "\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYP" + "E_STRING\020\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSA" + "GE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n" + "\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_" + "SFIXED64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT" + "64\020\022\"C\n\005Label\022\022\n\016LABEL_OPTIONAL\020\001\022\022\n\016LAB" + "EL_REQUIRED\020\002\022\022\n\016LABEL_REPEATED\020\003\"$\n\024One" + "ofDescriptorProto\022\014\n\004name\030\001 \001(\t\"\214\001\n\023Enum" + "DescriptorProto\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002" + " \003(\0132).google.protobuf.EnumValueDescript" + "orProto\022-\n\007options\030\003 \001(\0132\034.google.protob" + "uf.EnumOptions\"l\n\030EnumValueDescriptorPro" + "to\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007opti" + "ons\030\003 \001(\0132!.google.protobuf.EnumValueOpt" + "ions\"\220\001\n\026ServiceDescriptorProto\022\014\n\004name\030" + "\001 \001(\t\0226\n\006method\030\002 \003(\0132&.google.protobuf." + "MethodDescriptorProto\0220\n\007options\030\003 \001(\0132\037" + ".google.protobuf.ServiceOptions\"\301\001\n\025Meth" + "odDescriptorProto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput" + "_type\030\002 \001(\t\022\023\n\013output_type\030\003 \001(\t\022/\n\007opti" + "ons\030\004 \001(\0132\036.google.protobuf.MethodOption" + "s\022\037\n\020client_streaming\030\005 \001(\010:\005false\022\037\n\020se" + "rver_streaming\030\006 \001(\010:\005false\"\201\005\n\013FileOpti" + "ons\022\024\n\014java_package\030\001 \001(\t\022\034\n\024java_outer_" + "classname\030\010 \001(\t\022\"\n\023java_multiple_files\030\n" + " \001(\010:\005false\022,\n\035java_generate_equals_and_" + "hash\030\024 \001(\010:\005false\022%\n\026java_string_check_u" + "tf8\030\033 \001(\010:\005false\022F\n\014optimize_for\030\t \001(\0162)" + ".google.protobuf.FileOptions.OptimizeMod" + "e:\005SPEED\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_gener" + "ic_services\030\020 \001(\010:\005false\022$\n\025java_generic" + "_services\030\021 \001(\010:\005false\022\"\n\023py_generic_ser" + "vices\030\022 \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005" + "false\022\037\n\020cc_enable_arenas\030\037 \001(\010:\005false\022\031" + "\n\021objc_class_prefix\030$ \001(\t\022\030\n\020csharp_name" + "space\030% \001(\t\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE" + "\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016Mess" + "ageOptions\022&\n\027message_set_wire_format\030\001 " + "\001(\010:\005false\022.\n\037no_standard_descriptor_acc" + "essor\030\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005" + "false\022\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterprete" + "d_option\030\347\007 \003(\0132$.google.protobuf.Uninte" + "rpretedOption*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOption" + "s\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Field" + "Options.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n" + "\006jstype\030\006 \001(\0162$.google.protobuf.FieldOpt" + "ions.JSType:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005fa" + "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n" " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" "(\0132$.google.protobuf.UninterpretedOption" - "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat" - "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" - "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" - "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022" - ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp" - "retedOption.NamePart\022\030\n\020identifier_value" - "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne" - "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006" - " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_" - "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002" - "(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceCodeI" - "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf." - "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004" - "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead" - "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030" - "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t" - "BY\n\023com.google.protobufB\020DescriptorProto" - "sH\001\242\002\003GPB\252\002\'Google.ProtocolBuffers.Descr" - "iptorProtos", 4691); + "\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRIN" + "G_PIECE\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS" + "_STRING\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013" + "EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndepr" + "ecated\030\003 \001(\010:\005false\022C\n\024uninterpreted_opt" + "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" + "edOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions\022" + "\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uninterpre" + "ted_option\030\347\007 \003(\0132$.google.protobuf.Unin" + "terpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOpt" + "ions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024unint" + "erpreted_option\030\347\007 \003(\0132$.google.protobuf" + ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMetho" + "dOptions\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024u" + "ninterpreted_option\030\347\007 \003(\0132$.google.prot" + "obuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023" + "UninterpretedOption\022;\n\004name\030\002 \003(\0132-.goog" + "le.protobuf.UninterpretedOption.NamePart" + "\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positive_i" + "nt_value\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001" + "(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_value" + "\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NameP" + "art\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002" + " \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003(" + "\0132(.google.protobuf.SourceCodeInfo.Locat" + "ion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004sp" + "an\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031" + "\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_det" + "ached_comments\030\006 \003(\tBY\n\023com.google.proto" + "bufB\020DescriptorProtosH\001\242\002\003GPB\252\002\'Google.P" + "rotocolBuffers.DescriptorProtos", 4951); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); FileDescriptorProto::default_instance_ = new FileDescriptorProto(); DescriptorProto::default_instance_ = new DescriptorProto(); DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange(); + DescriptorProto_ReservedRange::default_instance_ = new DescriptorProto_ReservedRange(); FieldDescriptorProto::default_instance_ = new FieldDescriptorProto(); OneofDescriptorProto::default_instance_ = new OneofDescriptorProto(); EnumDescriptorProto::default_instance_ = new EnumDescriptorProto(); @@ -749,6 +784,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { FileDescriptorProto::default_instance_->InitAsDefaultInstance(); DescriptorProto::default_instance_->InitAsDefaultInstance(); DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance(); + DescriptorProto_ReservedRange::default_instance_->InitAsDefaultInstance(); FieldDescriptorProto::default_instance_->InitAsDefaultInstance(); OneofDescriptorProto::default_instance_->InitAsDefaultInstance(); EnumDescriptorProto::default_instance_->InitAsDefaultInstance(); @@ -793,7 +829,7 @@ const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER FileDescriptorSet::FileDescriptorSet() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorSet) } @@ -870,13 +906,15 @@ bool FileDescriptorSet::MergePartialFromCodedStream( // repeated .google.protobuf.FileDescriptorProto file = 1; case 1: { if (tag == 10) { - parse_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_file())); } else { goto handle_unusual; } - if (input->ExpectTag(10)) goto parse_file; + if (input->ExpectTag(10)) goto parse_loop_file; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -961,9 +999,9 @@ int FileDescriptorSet::ByteSize() const { void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FileDescriptorSet* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FileDescriptorSet* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1020,10 +1058,10 @@ void FileDescriptorSet::InternalSwap(FileDescriptorSet* other) { // FileDescriptorSet // repeated .google.protobuf.FileDescriptorProto file = 1; - int FileDescriptorSet::file_size() const { +int FileDescriptorSet::file_size() const { return file_.size(); } - void FileDescriptorSet::clear_file() { +void FileDescriptorSet::clear_file() { file_.Clear(); } const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { @@ -1069,7 +1107,7 @@ const int FileDescriptorProto::kSyntaxFieldNumber; #endif // !_MSC_VER FileDescriptorProto::FileDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileDescriptorProto) } @@ -1237,54 +1275,63 @@ bool FileDescriptorProto::MergePartialFromCodedStream( case 4: { if (tag == 34) { parse_message_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_message_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_message_type())); } else { goto handle_unusual; } - if (input->ExpectTag(34)) goto parse_message_type; - if (input->ExpectTag(42)) goto parse_enum_type; + if (input->ExpectTag(34)) goto parse_loop_message_type; + if (input->ExpectTag(42)) goto parse_loop_enum_type; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; case 5: { if (tag == 42) { - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_enum_type())); } else { goto handle_unusual; } - if (input->ExpectTag(42)) goto parse_enum_type; - if (input->ExpectTag(50)) goto parse_service; + if (input->ExpectTag(42)) goto parse_loop_enum_type; + if (input->ExpectTag(50)) goto parse_loop_service; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.ServiceDescriptorProto service = 6; case 6: { if (tag == 50) { - parse_service: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_service: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_service())); } else { goto handle_unusual; } - if (input->ExpectTag(50)) goto parse_service; - if (input->ExpectTag(58)) goto parse_extension; + if (input->ExpectTag(50)) goto parse_loop_service; + if (input->ExpectTag(58)) goto parse_loop_extension; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.FieldDescriptorProto extension = 7; case 7: { if (tag == 58) { - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_extension())); } else { goto handle_unusual; } - if (input->ExpectTag(58)) goto parse_extension; + if (input->ExpectTag(58)) goto parse_loop_extension; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(66)) goto parse_options; break; } @@ -1712,9 +1759,9 @@ int FileDescriptorProto::ByteSize() const { void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FileDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FileDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1816,16 +1863,16 @@ void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) { // FileDescriptorProto // optional string name = 1; - bool FileDescriptorProto::has_name() const { +bool FileDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void FileDescriptorProto::set_has_name() { +void FileDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void FileDescriptorProto::clear_has_name() { +void FileDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void FileDescriptorProto::clear_name() { +void FileDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -1869,16 +1916,16 @@ void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) { } // optional string package = 2; - bool FileDescriptorProto::has_package() const { +bool FileDescriptorProto::has_package() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void FileDescriptorProto::set_has_package() { +void FileDescriptorProto::set_has_package() { _has_bits_[0] |= 0x00000002u; } - void FileDescriptorProto::clear_has_package() { +void FileDescriptorProto::clear_has_package() { _has_bits_[0] &= ~0x00000002u; } - void FileDescriptorProto::clear_package() { +void FileDescriptorProto::clear_package() { package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_package(); } @@ -1922,10 +1969,10 @@ void FileDescriptorProto::InternalSwap(FileDescriptorProto* other) { } // repeated string dependency = 3; - int FileDescriptorProto::dependency_size() const { +int FileDescriptorProto::dependency_size() const { return dependency_.size(); } - void FileDescriptorProto::clear_dependency() { +void FileDescriptorProto::clear_dependency() { dependency_.Clear(); } const ::std::string& FileDescriptorProto::dependency(int index) const { @@ -1976,10 +2023,10 @@ FileDescriptorProto::mutable_dependency() { } // repeated int32 public_dependency = 10; - int FileDescriptorProto::public_dependency_size() const { +int FileDescriptorProto::public_dependency_size() const { return public_dependency_.size(); } - void FileDescriptorProto::clear_public_dependency() { +void FileDescriptorProto::clear_public_dependency() { public_dependency_.Clear(); } ::google::protobuf::int32 FileDescriptorProto::public_dependency(int index) const { @@ -2006,10 +2053,10 @@ FileDescriptorProto::mutable_public_dependency() { } // repeated int32 weak_dependency = 11; - int FileDescriptorProto::weak_dependency_size() const { +int FileDescriptorProto::weak_dependency_size() const { return weak_dependency_.size(); } - void FileDescriptorProto::clear_weak_dependency() { +void FileDescriptorProto::clear_weak_dependency() { weak_dependency_.Clear(); } ::google::protobuf::int32 FileDescriptorProto::weak_dependency(int index) const { @@ -2036,10 +2083,10 @@ FileDescriptorProto::mutable_weak_dependency() { } // repeated .google.protobuf.DescriptorProto message_type = 4; - int FileDescriptorProto::message_type_size() const { +int FileDescriptorProto::message_type_size() const { return message_type_.size(); } - void FileDescriptorProto::clear_message_type() { +void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { @@ -2066,10 +2113,10 @@ FileDescriptorProto::mutable_message_type() { } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; - int FileDescriptorProto::enum_type_size() const { +int FileDescriptorProto::enum_type_size() const { return enum_type_.size(); } - void FileDescriptorProto::clear_enum_type() { +void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { @@ -2096,10 +2143,10 @@ FileDescriptorProto::mutable_enum_type() { } // repeated .google.protobuf.ServiceDescriptorProto service = 6; - int FileDescriptorProto::service_size() const { +int FileDescriptorProto::service_size() const { return service_.size(); } - void FileDescriptorProto::clear_service() { +void FileDescriptorProto::clear_service() { service_.Clear(); } const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { @@ -2126,10 +2173,10 @@ FileDescriptorProto::mutable_service() { } // repeated .google.protobuf.FieldDescriptorProto extension = 7; - int FileDescriptorProto::extension_size() const { +int FileDescriptorProto::extension_size() const { return extension_.size(); } - void FileDescriptorProto::clear_extension() { +void FileDescriptorProto::clear_extension() { extension_.Clear(); } const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { @@ -2156,16 +2203,16 @@ FileDescriptorProto::mutable_extension() { } // optional .google.protobuf.FileOptions options = 8; - bool FileDescriptorProto::has_options() const { +bool FileDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000200u) != 0; } - void FileDescriptorProto::set_has_options() { +void FileDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000200u; } - void FileDescriptorProto::clear_has_options() { +void FileDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000200u; } - void FileDescriptorProto::clear_options() { +void FileDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); clear_has_options(); } @@ -2199,16 +2246,16 @@ FileDescriptorProto::mutable_extension() { } // optional .google.protobuf.SourceCodeInfo source_code_info = 9; - bool FileDescriptorProto::has_source_code_info() const { +bool FileDescriptorProto::has_source_code_info() const { return (_has_bits_[0] & 0x00000400u) != 0; } - void FileDescriptorProto::set_has_source_code_info() { +void FileDescriptorProto::set_has_source_code_info() { _has_bits_[0] |= 0x00000400u; } - void FileDescriptorProto::clear_has_source_code_info() { +void FileDescriptorProto::clear_has_source_code_info() { _has_bits_[0] &= ~0x00000400u; } - void FileDescriptorProto::clear_source_code_info() { +void FileDescriptorProto::clear_source_code_info() { if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); clear_has_source_code_info(); } @@ -2242,16 +2289,16 @@ FileDescriptorProto::mutable_extension() { } // optional string syntax = 12; - bool FileDescriptorProto::has_syntax() const { +bool FileDescriptorProto::has_syntax() const { return (_has_bits_[0] & 0x00000800u) != 0; } - void FileDescriptorProto::set_has_syntax() { +void FileDescriptorProto::set_has_syntax() { _has_bits_[0] |= 0x00000800u; } - void FileDescriptorProto::clear_has_syntax() { +void FileDescriptorProto::clear_has_syntax() { _has_bits_[0] &= ~0x00000800u; } - void FileDescriptorProto::clear_syntax() { +void FileDescriptorProto::clear_syntax() { syntax_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_syntax(); } @@ -2304,7 +2351,7 @@ const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ExtensionRange) } @@ -2516,9 +2563,9 @@ int DescriptorProto_ExtensionRange::ByteSize() const { void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const DescriptorProto_ExtensionRange* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const DescriptorProto_ExtensionRange* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -2579,6 +2626,289 @@ void DescriptorProto_ExtensionRange::InternalSwap(DescriptorProto_ExtensionRange } +// ------------------------------------------------------------------- + +#ifndef _MSC_VER +const int DescriptorProto_ReservedRange::kStartFieldNumber; +const int DescriptorProto_ReservedRange::kEndFieldNumber; +#endif // !_MSC_VER + +DescriptorProto_ReservedRange::DescriptorProto_ReservedRange() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto.ReservedRange) +} + +void DescriptorProto_ReservedRange::InitAsDefaultInstance() { +} + +DescriptorProto_ReservedRange::DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:google.protobuf.DescriptorProto.ReservedRange) +} + +void DescriptorProto_ReservedRange::SharedCtor() { + _cached_size_ = 0; + start_ = 0; + end_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +DescriptorProto_ReservedRange::~DescriptorProto_ReservedRange() { + // @@protoc_insertion_point(destructor:google.protobuf.DescriptorProto.ReservedRange) + SharedDtor(); +} + +void DescriptorProto_ReservedRange::SharedDtor() { + if (this != default_instance_) { + } +} + +void DescriptorProto_ReservedRange::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* DescriptorProto_ReservedRange::descriptor() { + protobuf_AssignDescriptorsOnce(); + return DescriptorProto_ReservedRange_descriptor_; +} + +const DescriptorProto_ReservedRange& DescriptorProto_ReservedRange::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + return *default_instance_; +} + +DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::default_instance_ = NULL; + +DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::New(::google::protobuf::Arena* arena) const { + DescriptorProto_ReservedRange* n = new DescriptorProto_ReservedRange; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +void DescriptorProto_ReservedRange::Clear() { +#define ZR_HELPER_(f) reinterpret_cast(\ + &reinterpret_cast(16)->f) + +#define ZR_(first, last) do {\ + ::memset(&first, 0,\ + ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ +} while (0) + + ZR_(start_, end_); + +#undef ZR_HELPER_ +#undef ZR_ + + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + if (_internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->Clear(); + } +} + +bool DescriptorProto_ReservedRange::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ReservedRange) + for (;;) { + ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); + tag = p.first; + if (!p.second) goto handle_unusual; + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional int32 start = 1; + case 1: { + if (tag == 8) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &start_))); + set_has_start(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(16)) goto parse_end; + break; + } + + // optional int32 end = 2; + case 2: { + if (tag == 16) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + set_has_end(); + } else { + goto handle_unusual; + } + if (input->ExpectAtEnd()) goto success; + break; + } + + default: { + handle_unusual: + if (tag == 0 || + ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + goto success; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:google.protobuf.DescriptorProto.ReservedRange) + return true; +failure: + // @@protoc_insertion_point(parse_failure:google.protobuf.DescriptorProto.ReservedRange) + return false; +#undef DO_ +} + +void DescriptorProto_ReservedRange::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:google.protobuf.DescriptorProto.ReservedRange) + // optional int32 start = 1; + if (has_start()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output); + } + + // optional int32 end = 2; + if (has_end()) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end(), output); + } + + if (_internal_metadata_.have_unknown_fields()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange) +} + +::google::protobuf::uint8* DescriptorProto_ReservedRange::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange) + // optional int32 start = 1; + if (has_start()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->start(), target); + } + + // optional int32 end = 2; + if (has_end()) { + target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end(), target); + } + + if (_internal_metadata_.have_unknown_fields()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.DescriptorProto.ReservedRange) + return target; +} + +int DescriptorProto_ReservedRange::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & 3) { + // optional int32 start = 1; + if (has_start()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->start()); + } + + // optional int32 end = 2; + if (has_end()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->end()); + } + + } + if (_internal_metadata_.have_unknown_fields()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const DescriptorProto_ReservedRange* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from.has_start()) { + set_start(from.start()); + } + if (from.has_end()) { + set_end(from.end()); + } + } + if (from._internal_metadata_.have_unknown_fields()) { + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); + } +} + +void DescriptorProto_ReservedRange::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool DescriptorProto_ReservedRange::IsInitialized() const { + + return true; +} + +void DescriptorProto_ReservedRange::Swap(DescriptorProto_ReservedRange* other) { + if (other == this) return; + InternalSwap(other); +} +void DescriptorProto_ReservedRange::InternalSwap(DescriptorProto_ReservedRange* other) { + std::swap(start_, other->start_); + std::swap(end_, other->end_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata DescriptorProto_ReservedRange::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = DescriptorProto_ReservedRange_descriptor_; + metadata.reflection = DescriptorProto_ReservedRange_reflection_; + return metadata; +} + + // ------------------------------------------------------------------- #ifndef _MSC_VER @@ -2590,10 +2920,12 @@ const int DescriptorProto::kEnumTypeFieldNumber; const int DescriptorProto::kExtensionRangeFieldNumber; const int DescriptorProto::kOneofDeclFieldNumber; const int DescriptorProto::kOptionsFieldNumber; +const int DescriptorProto::kReservedRangeFieldNumber; +const int DescriptorProto::kReservedNameFieldNumber; #endif // !_MSC_VER DescriptorProto::DescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.DescriptorProto) } @@ -2670,6 +3002,8 @@ void DescriptorProto::Clear() { enum_type_.Clear(); extension_range_.Clear(); oneof_decl_.Clear(); + reserved_range_.Clear(); + reserved_name_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->Clear(); @@ -2706,68 +3040,79 @@ bool DescriptorProto::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_field: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_field: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_field())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_field; - if (input->ExpectTag(26)) goto parse_nested_type; + if (input->ExpectTag(18)) goto parse_loop_field; + if (input->ExpectTag(26)) goto parse_loop_nested_type; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.DescriptorProto nested_type = 3; case 3: { if (tag == 26) { - parse_nested_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_nested_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_nested_type())); } else { goto handle_unusual; } - if (input->ExpectTag(26)) goto parse_nested_type; - if (input->ExpectTag(34)) goto parse_enum_type; + if (input->ExpectTag(26)) goto parse_loop_nested_type; + if (input->ExpectTag(34)) goto parse_loop_enum_type; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; case 4: { if (tag == 34) { - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_enum_type())); } else { goto handle_unusual; } - if (input->ExpectTag(34)) goto parse_enum_type; - if (input->ExpectTag(42)) goto parse_extension_range; + if (input->ExpectTag(34)) goto parse_loop_enum_type; + if (input->ExpectTag(42)) goto parse_loop_extension_range; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; case 5: { if (tag == 42) { - parse_extension_range: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_extension_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_extension_range())); } else { goto handle_unusual; } - if (input->ExpectTag(42)) goto parse_extension_range; - if (input->ExpectTag(50)) goto parse_extension; + if (input->ExpectTag(42)) goto parse_loop_extension_range; + if (input->ExpectTag(50)) goto parse_loop_extension; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.FieldDescriptorProto extension = 6; case 6: { if (tag == 50) { - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_extension())); } else { goto handle_unusual; } - if (input->ExpectTag(50)) goto parse_extension; + if (input->ExpectTag(50)) goto parse_loop_extension; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(58)) goto parse_options; break; } @@ -2789,12 +3134,50 @@ bool DescriptorProto::MergePartialFromCodedStream( case 8: { if (tag == 66) { parse_oneof_decl: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_oneof_decl: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_oneof_decl())); } else { goto handle_unusual; } - if (input->ExpectTag(66)) goto parse_oneof_decl; + if (input->ExpectTag(66)) goto parse_loop_oneof_decl; + if (input->ExpectTag(74)) goto parse_loop_reserved_range; + input->UnsafeDecrementRecursionDepth(); + break; + } + + // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; + case 9: { + if (tag == 74) { + DO_(input->IncrementRecursionDepth()); + parse_loop_reserved_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( + input, add_reserved_range())); + } else { + goto handle_unusual; + } + if (input->ExpectTag(74)) goto parse_loop_reserved_range; + input->UnsafeDecrementRecursionDepth(); + if (input->ExpectTag(82)) goto parse_reserved_name; + break; + } + + // repeated string reserved_name = 10; + case 10: { + if (tag == 82) { + parse_reserved_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_reserved_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->reserved_name(this->reserved_name_size() - 1).data(), + this->reserved_name(this->reserved_name_size() - 1).length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.DescriptorProto.reserved_name"); + } else { + goto handle_unusual; + } + if (input->ExpectTag(82)) goto parse_reserved_name; if (input->ExpectAtEnd()) goto success; break; } @@ -2876,6 +3259,22 @@ void DescriptorProto::SerializeWithCachedSizes( 8, this->oneof_decl(i), output); } + // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; + for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 9, this->reserved_range(i), output); + } + + // repeated string reserved_name = 10; + for (int i = 0; i < this->reserved_name_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->reserved_name(i).data(), this->reserved_name(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.DescriptorProto.reserved_name"); + ::google::protobuf::internal::WireFormatLite::WriteString( + 10, this->reserved_name(i), output); + } + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); @@ -2946,6 +3345,23 @@ void DescriptorProto::SerializeWithCachedSizes( 8, this->oneof_decl(i), target); } + // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; + for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 9, this->reserved_range(i), target); + } + + // repeated string reserved_name = 10; + for (int i = 0; i < this->reserved_name_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->reserved_name(i).data(), this->reserved_name(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.DescriptorProto.reserved_name"); + target = ::google::protobuf::internal::WireFormatLite:: + WriteStringToArray(10, this->reserved_name(i), target); + } + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); @@ -3021,6 +3437,21 @@ int DescriptorProto::ByteSize() const { this->oneof_decl(i)); } + // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; + total_size += 1 * this->reserved_range_size(); + for (int i = 0; i < this->reserved_range_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->reserved_range(i)); + } + + // repeated string reserved_name = 10; + total_size += 1 * this->reserved_name_size(); + for (int i = 0; i < this->reserved_name_size(); i++) { + total_size += ::google::protobuf::internal::WireFormatLite::StringSize( + this->reserved_name(i)); + } + if (_internal_metadata_.have_unknown_fields()) { total_size += ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( @@ -3034,9 +3465,9 @@ int DescriptorProto::ByteSize() const { void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const DescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const DescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -3052,6 +3483,8 @@ void DescriptorProto::MergeFrom(const DescriptorProto& from) { enum_type_.MergeFrom(from.enum_type_); extension_range_.MergeFrom(from.extension_range_); oneof_decl_.MergeFrom(from.oneof_decl_); + reserved_range_.MergeFrom(from.reserved_range_); + reserved_name_.MergeFrom(from.reserved_name_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { set_has_name(); @@ -3103,6 +3536,8 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { extension_range_.UnsafeArenaSwap(&other->extension_range_); oneof_decl_.UnsafeArenaSwap(&other->oneof_decl_); std::swap(options_, other->options_); + reserved_range_.UnsafeArenaSwap(&other->reserved_range_); + reserved_name_.UnsafeArenaSwap(&other->reserved_name_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); @@ -3120,16 +3555,16 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { // DescriptorProto_ExtensionRange // optional int32 start = 1; - bool DescriptorProto_ExtensionRange::has_start() const { +bool DescriptorProto_ExtensionRange::has_start() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void DescriptorProto_ExtensionRange::set_has_start() { +void DescriptorProto_ExtensionRange::set_has_start() { _has_bits_[0] |= 0x00000001u; } - void DescriptorProto_ExtensionRange::clear_has_start() { +void DescriptorProto_ExtensionRange::clear_has_start() { _has_bits_[0] &= ~0x00000001u; } - void DescriptorProto_ExtensionRange::clear_start() { +void DescriptorProto_ExtensionRange::clear_start() { start_ = 0; clear_has_start(); } @@ -3144,16 +3579,16 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { } // optional int32 end = 2; - bool DescriptorProto_ExtensionRange::has_end() const { +bool DescriptorProto_ExtensionRange::has_end() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void DescriptorProto_ExtensionRange::set_has_end() { +void DescriptorProto_ExtensionRange::set_has_end() { _has_bits_[0] |= 0x00000002u; } - void DescriptorProto_ExtensionRange::clear_has_end() { +void DescriptorProto_ExtensionRange::clear_has_end() { _has_bits_[0] &= ~0x00000002u; } - void DescriptorProto_ExtensionRange::clear_end() { +void DescriptorProto_ExtensionRange::clear_end() { end_ = 0; clear_has_end(); } @@ -3169,19 +3604,71 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { // ------------------------------------------------------------------- +// DescriptorProto_ReservedRange + +// optional int32 start = 1; +bool DescriptorProto_ReservedRange::has_start() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +void DescriptorProto_ReservedRange::set_has_start() { + _has_bits_[0] |= 0x00000001u; +} +void DescriptorProto_ReservedRange::clear_has_start() { + _has_bits_[0] &= ~0x00000001u; +} +void DescriptorProto_ReservedRange::clear_start() { + start_ = 0; + clear_has_start(); +} + ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start) + return start_; +} + void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) { + set_has_start(); + start_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start) +} + +// optional int32 end = 2; +bool DescriptorProto_ReservedRange::has_end() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +void DescriptorProto_ReservedRange::set_has_end() { + _has_bits_[0] |= 0x00000002u; +} +void DescriptorProto_ReservedRange::clear_has_end() { + _has_bits_[0] &= ~0x00000002u; +} +void DescriptorProto_ReservedRange::clear_end() { + end_ = 0; + clear_has_end(); +} + ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end) + return end_; +} + void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end) +} + +// ------------------------------------------------------------------- + // DescriptorProto // optional string name = 1; - bool DescriptorProto::has_name() const { +bool DescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void DescriptorProto::set_has_name() { +void DescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void DescriptorProto::clear_has_name() { +void DescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void DescriptorProto::clear_name() { +void DescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -3225,10 +3712,10 @@ void DescriptorProto::InternalSwap(DescriptorProto* other) { } // repeated .google.protobuf.FieldDescriptorProto field = 2; - int DescriptorProto::field_size() const { +int DescriptorProto::field_size() const { return field_.size(); } - void DescriptorProto::clear_field() { +void DescriptorProto::clear_field() { field_.Clear(); } const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { @@ -3255,10 +3742,10 @@ DescriptorProto::mutable_field() { } // repeated .google.protobuf.FieldDescriptorProto extension = 6; - int DescriptorProto::extension_size() const { +int DescriptorProto::extension_size() const { return extension_.size(); } - void DescriptorProto::clear_extension() { +void DescriptorProto::clear_extension() { extension_.Clear(); } const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { @@ -3285,10 +3772,10 @@ DescriptorProto::mutable_extension() { } // repeated .google.protobuf.DescriptorProto nested_type = 3; - int DescriptorProto::nested_type_size() const { +int DescriptorProto::nested_type_size() const { return nested_type_.size(); } - void DescriptorProto::clear_nested_type() { +void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { @@ -3315,10 +3802,10 @@ DescriptorProto::mutable_nested_type() { } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; - int DescriptorProto::enum_type_size() const { +int DescriptorProto::enum_type_size() const { return enum_type_.size(); } - void DescriptorProto::clear_enum_type() { +void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { @@ -3345,10 +3832,10 @@ DescriptorProto::mutable_enum_type() { } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; - int DescriptorProto::extension_range_size() const { +int DescriptorProto::extension_range_size() const { return extension_range_.size(); } - void DescriptorProto::clear_extension_range() { +void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { @@ -3375,10 +3862,10 @@ DescriptorProto::mutable_extension_range() { } // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; - int DescriptorProto::oneof_decl_size() const { +int DescriptorProto::oneof_decl_size() const { return oneof_decl_.size(); } - void DescriptorProto::clear_oneof_decl() { +void DescriptorProto::clear_oneof_decl() { oneof_decl_.Clear(); } const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const { @@ -3405,16 +3892,16 @@ DescriptorProto::mutable_oneof_decl() { } // optional .google.protobuf.MessageOptions options = 7; - bool DescriptorProto::has_options() const { +bool DescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000080u) != 0; } - void DescriptorProto::set_has_options() { +void DescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000080u; } - void DescriptorProto::clear_has_options() { +void DescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000080u; } - void DescriptorProto::clear_options() { +void DescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); clear_has_options(); } @@ -3447,6 +3934,90 @@ DescriptorProto::mutable_oneof_decl() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options) } +// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; +int DescriptorProto::reserved_range_size() const { + return reserved_range_.size(); +} +void DescriptorProto::clear_reserved_range() { + reserved_range_.Clear(); +} + const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Get(index); +} + ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Mutable(index); +} + ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { + // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Add(); +} + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* +DescriptorProto::mutable_reserved_range() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) + return &reserved_range_; +} + +// repeated string reserved_name = 10; +int DescriptorProto::reserved_name_size() const { + return reserved_name_.size(); +} +void DescriptorProto::clear_reserved_name() { + reserved_name_.Clear(); +} + const ::std::string& DescriptorProto::reserved_name(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_.Get(index); +} + ::std::string* DescriptorProto::mutable_reserved_name(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_.Mutable(index); +} + void DescriptorProto::set_reserved_name(int index, const ::std::string& value) { + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name) + reserved_name_.Mutable(index)->assign(value); +} + void DescriptorProto::set_reserved_name(int index, const char* value) { + reserved_name_.Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name) +} + void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) { + reserved_name_.Mutable(index)->assign( + reinterpret_cast(value), size); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) +} + ::std::string* DescriptorProto::add_reserved_name() { + return reserved_name_.Add(); +} + void DescriptorProto::add_reserved_name(const ::std::string& value) { + reserved_name_.Add()->assign(value); + // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name) +} + void DescriptorProto::add_reserved_name(const char* value) { + reserved_name_.Add()->assign(value); + // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name) +} + void DescriptorProto::add_reserved_name(const char* value, size_t size) { + reserved_name_.Add()->assign(reinterpret_cast(value), size); + // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name) +} + const ::google::protobuf::RepeatedPtrField< ::std::string>& +DescriptorProto::reserved_name() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_; +} + ::google::protobuf::RepeatedPtrField< ::std::string>* +DescriptorProto::mutable_reserved_name() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name) + return &reserved_name_; +} + #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== @@ -3540,7 +4111,7 @@ const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FieldDescriptorProto::FieldDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FieldDescriptorProto) } @@ -4063,9 +4634,9 @@ int FieldDescriptorProto::ByteSize() const { void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FieldDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FieldDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -4166,16 +4737,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { // FieldDescriptorProto // optional string name = 1; - bool FieldDescriptorProto::has_name() const { +bool FieldDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void FieldDescriptorProto::set_has_name() { +void FieldDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void FieldDescriptorProto::clear_has_name() { +void FieldDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void FieldDescriptorProto::clear_name() { +void FieldDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -4219,16 +4790,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional int32 number = 3; - bool FieldDescriptorProto::has_number() const { +bool FieldDescriptorProto::has_number() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void FieldDescriptorProto::set_has_number() { +void FieldDescriptorProto::set_has_number() { _has_bits_[0] |= 0x00000002u; } - void FieldDescriptorProto::clear_has_number() { +void FieldDescriptorProto::clear_has_number() { _has_bits_[0] &= ~0x00000002u; } - void FieldDescriptorProto::clear_number() { +void FieldDescriptorProto::clear_number() { number_ = 0; clear_has_number(); } @@ -4243,16 +4814,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional .google.protobuf.FieldDescriptorProto.Label label = 4; - bool FieldDescriptorProto::has_label() const { +bool FieldDescriptorProto::has_label() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void FieldDescriptorProto::set_has_label() { +void FieldDescriptorProto::set_has_label() { _has_bits_[0] |= 0x00000004u; } - void FieldDescriptorProto::clear_has_label() { +void FieldDescriptorProto::clear_has_label() { _has_bits_[0] &= ~0x00000004u; } - void FieldDescriptorProto::clear_label() { +void FieldDescriptorProto::clear_label() { label_ = 1; clear_has_label(); } @@ -4268,16 +4839,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional .google.protobuf.FieldDescriptorProto.Type type = 5; - bool FieldDescriptorProto::has_type() const { +bool FieldDescriptorProto::has_type() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void FieldDescriptorProto::set_has_type() { +void FieldDescriptorProto::set_has_type() { _has_bits_[0] |= 0x00000008u; } - void FieldDescriptorProto::clear_has_type() { +void FieldDescriptorProto::clear_has_type() { _has_bits_[0] &= ~0x00000008u; } - void FieldDescriptorProto::clear_type() { +void FieldDescriptorProto::clear_type() { type_ = 1; clear_has_type(); } @@ -4293,16 +4864,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional string type_name = 6; - bool FieldDescriptorProto::has_type_name() const { +bool FieldDescriptorProto::has_type_name() const { return (_has_bits_[0] & 0x00000010u) != 0; } - void FieldDescriptorProto::set_has_type_name() { +void FieldDescriptorProto::set_has_type_name() { _has_bits_[0] |= 0x00000010u; } - void FieldDescriptorProto::clear_has_type_name() { +void FieldDescriptorProto::clear_has_type_name() { _has_bits_[0] &= ~0x00000010u; } - void FieldDescriptorProto::clear_type_name() { +void FieldDescriptorProto::clear_type_name() { type_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_type_name(); } @@ -4346,16 +4917,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional string extendee = 2; - bool FieldDescriptorProto::has_extendee() const { +bool FieldDescriptorProto::has_extendee() const { return (_has_bits_[0] & 0x00000020u) != 0; } - void FieldDescriptorProto::set_has_extendee() { +void FieldDescriptorProto::set_has_extendee() { _has_bits_[0] |= 0x00000020u; } - void FieldDescriptorProto::clear_has_extendee() { +void FieldDescriptorProto::clear_has_extendee() { _has_bits_[0] &= ~0x00000020u; } - void FieldDescriptorProto::clear_extendee() { +void FieldDescriptorProto::clear_extendee() { extendee_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_extendee(); } @@ -4399,16 +4970,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional string default_value = 7; - bool FieldDescriptorProto::has_default_value() const { +bool FieldDescriptorProto::has_default_value() const { return (_has_bits_[0] & 0x00000040u) != 0; } - void FieldDescriptorProto::set_has_default_value() { +void FieldDescriptorProto::set_has_default_value() { _has_bits_[0] |= 0x00000040u; } - void FieldDescriptorProto::clear_has_default_value() { +void FieldDescriptorProto::clear_has_default_value() { _has_bits_[0] &= ~0x00000040u; } - void FieldDescriptorProto::clear_default_value() { +void FieldDescriptorProto::clear_default_value() { default_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_default_value(); } @@ -4452,16 +5023,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional int32 oneof_index = 9; - bool FieldDescriptorProto::has_oneof_index() const { +bool FieldDescriptorProto::has_oneof_index() const { return (_has_bits_[0] & 0x00000080u) != 0; } - void FieldDescriptorProto::set_has_oneof_index() { +void FieldDescriptorProto::set_has_oneof_index() { _has_bits_[0] |= 0x00000080u; } - void FieldDescriptorProto::clear_has_oneof_index() { +void FieldDescriptorProto::clear_has_oneof_index() { _has_bits_[0] &= ~0x00000080u; } - void FieldDescriptorProto::clear_oneof_index() { +void FieldDescriptorProto::clear_oneof_index() { oneof_index_ = 0; clear_has_oneof_index(); } @@ -4476,16 +5047,16 @@ void FieldDescriptorProto::InternalSwap(FieldDescriptorProto* other) { } // optional .google.protobuf.FieldOptions options = 8; - bool FieldDescriptorProto::has_options() const { +bool FieldDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000100u) != 0; } - void FieldDescriptorProto::set_has_options() { +void FieldDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000100u; } - void FieldDescriptorProto::clear_has_options() { +void FieldDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000100u; } - void FieldDescriptorProto::clear_options() { +void FieldDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); clear_has_options(); } @@ -4527,7 +5098,7 @@ const int OneofDescriptorProto::kNameFieldNumber; #endif // !_MSC_VER OneofDescriptorProto::OneofDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.OneofDescriptorProto) } @@ -4709,9 +5280,9 @@ int OneofDescriptorProto::ByteSize() const { void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const OneofDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const OneofDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -4772,16 +5343,16 @@ void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) { // OneofDescriptorProto // optional string name = 1; - bool OneofDescriptorProto::has_name() const { +bool OneofDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void OneofDescriptorProto::set_has_name() { +void OneofDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void OneofDescriptorProto::clear_has_name() { +void OneofDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void OneofDescriptorProto::clear_name() { +void OneofDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -4835,7 +5406,7 @@ const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumDescriptorProto::EnumDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumDescriptorProto) } @@ -4943,12 +5514,15 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_value())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_value; + if (input->ExpectTag(18)) goto parse_loop_value; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(26)) goto parse_options; break; } @@ -5096,9 +5670,9 @@ int EnumDescriptorProto::ByteSize() const { void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const EnumDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const EnumDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -5169,16 +5743,16 @@ void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) { // EnumDescriptorProto // optional string name = 1; - bool EnumDescriptorProto::has_name() const { +bool EnumDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void EnumDescriptorProto::set_has_name() { +void EnumDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void EnumDescriptorProto::clear_has_name() { +void EnumDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void EnumDescriptorProto::clear_name() { +void EnumDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -5222,10 +5796,10 @@ void EnumDescriptorProto::InternalSwap(EnumDescriptorProto* other) { } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; - int EnumDescriptorProto::value_size() const { +int EnumDescriptorProto::value_size() const { return value_.size(); } - void EnumDescriptorProto::clear_value() { +void EnumDescriptorProto::clear_value() { value_.Clear(); } const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { @@ -5252,16 +5826,16 @@ EnumDescriptorProto::mutable_value() { } // optional .google.protobuf.EnumOptions options = 3; - bool EnumDescriptorProto::has_options() const { +bool EnumDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void EnumDescriptorProto::set_has_options() { +void EnumDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000004u; } - void EnumDescriptorProto::clear_has_options() { +void EnumDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000004u; } - void EnumDescriptorProto::clear_options() { +void EnumDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); clear_has_options(); } @@ -5305,7 +5879,7 @@ const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumValueDescriptorProto::EnumValueDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumValueDescriptorProto) } @@ -5564,9 +6138,9 @@ int EnumValueDescriptorProto::ByteSize() const { void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const EnumValueDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const EnumValueDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -5638,16 +6212,16 @@ void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) { // EnumValueDescriptorProto // optional string name = 1; - bool EnumValueDescriptorProto::has_name() const { +bool EnumValueDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void EnumValueDescriptorProto::set_has_name() { +void EnumValueDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void EnumValueDescriptorProto::clear_has_name() { +void EnumValueDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void EnumValueDescriptorProto::clear_name() { +void EnumValueDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -5691,16 +6265,16 @@ void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) { } // optional int32 number = 2; - bool EnumValueDescriptorProto::has_number() const { +bool EnumValueDescriptorProto::has_number() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void EnumValueDescriptorProto::set_has_number() { +void EnumValueDescriptorProto::set_has_number() { _has_bits_[0] |= 0x00000002u; } - void EnumValueDescriptorProto::clear_has_number() { +void EnumValueDescriptorProto::clear_has_number() { _has_bits_[0] &= ~0x00000002u; } - void EnumValueDescriptorProto::clear_number() { +void EnumValueDescriptorProto::clear_number() { number_ = 0; clear_has_number(); } @@ -5715,16 +6289,16 @@ void EnumValueDescriptorProto::InternalSwap(EnumValueDescriptorProto* other) { } // optional .google.protobuf.EnumValueOptions options = 3; - bool EnumValueDescriptorProto::has_options() const { +bool EnumValueDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void EnumValueDescriptorProto::set_has_options() { +void EnumValueDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000004u; } - void EnumValueDescriptorProto::clear_has_options() { +void EnumValueDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000004u; } - void EnumValueDescriptorProto::clear_options() { +void EnumValueDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); clear_has_options(); } @@ -5768,7 +6342,7 @@ const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER ServiceDescriptorProto::ServiceDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.ServiceDescriptorProto) } @@ -5876,12 +6450,15 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_method: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_method: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_method())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_method; + if (input->ExpectTag(18)) goto parse_loop_method; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(26)) goto parse_options; break; } @@ -6029,9 +6606,9 @@ int ServiceDescriptorProto::ByteSize() const { void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const ServiceDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const ServiceDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -6102,16 +6679,16 @@ void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) { // ServiceDescriptorProto // optional string name = 1; - bool ServiceDescriptorProto::has_name() const { +bool ServiceDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void ServiceDescriptorProto::set_has_name() { +void ServiceDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void ServiceDescriptorProto::clear_has_name() { +void ServiceDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void ServiceDescriptorProto::clear_name() { +void ServiceDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -6155,10 +6732,10 @@ void ServiceDescriptorProto::InternalSwap(ServiceDescriptorProto* other) { } // repeated .google.protobuf.MethodDescriptorProto method = 2; - int ServiceDescriptorProto::method_size() const { +int ServiceDescriptorProto::method_size() const { return method_.size(); } - void ServiceDescriptorProto::clear_method() { +void ServiceDescriptorProto::clear_method() { method_.Clear(); } const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { @@ -6185,16 +6762,16 @@ ServiceDescriptorProto::mutable_method() { } // optional .google.protobuf.ServiceOptions options = 3; - bool ServiceDescriptorProto::has_options() const { +bool ServiceDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void ServiceDescriptorProto::set_has_options() { +void ServiceDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000004u; } - void ServiceDescriptorProto::clear_has_options() { +void ServiceDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000004u; } - void ServiceDescriptorProto::clear_options() { +void ServiceDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); clear_has_options(); } @@ -6241,7 +6818,7 @@ const int MethodDescriptorProto::kServerStreamingFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MethodDescriptorProto) } @@ -6641,9 +7218,9 @@ int MethodDescriptorProto::ByteSize() const { void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const MethodDescriptorProto* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const MethodDescriptorProto* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -6729,16 +7306,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { // MethodDescriptorProto // optional string name = 1; - bool MethodDescriptorProto::has_name() const { +bool MethodDescriptorProto::has_name() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void MethodDescriptorProto::set_has_name() { +void MethodDescriptorProto::set_has_name() { _has_bits_[0] |= 0x00000001u; } - void MethodDescriptorProto::clear_has_name() { +void MethodDescriptorProto::clear_has_name() { _has_bits_[0] &= ~0x00000001u; } - void MethodDescriptorProto::clear_name() { +void MethodDescriptorProto::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name(); } @@ -6782,16 +7359,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } // optional string input_type = 2; - bool MethodDescriptorProto::has_input_type() const { +bool MethodDescriptorProto::has_input_type() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void MethodDescriptorProto::set_has_input_type() { +void MethodDescriptorProto::set_has_input_type() { _has_bits_[0] |= 0x00000002u; } - void MethodDescriptorProto::clear_has_input_type() { +void MethodDescriptorProto::clear_has_input_type() { _has_bits_[0] &= ~0x00000002u; } - void MethodDescriptorProto::clear_input_type() { +void MethodDescriptorProto::clear_input_type() { input_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_input_type(); } @@ -6835,16 +7412,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } // optional string output_type = 3; - bool MethodDescriptorProto::has_output_type() const { +bool MethodDescriptorProto::has_output_type() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void MethodDescriptorProto::set_has_output_type() { +void MethodDescriptorProto::set_has_output_type() { _has_bits_[0] |= 0x00000004u; } - void MethodDescriptorProto::clear_has_output_type() { +void MethodDescriptorProto::clear_has_output_type() { _has_bits_[0] &= ~0x00000004u; } - void MethodDescriptorProto::clear_output_type() { +void MethodDescriptorProto::clear_output_type() { output_type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_output_type(); } @@ -6888,16 +7465,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } // optional .google.protobuf.MethodOptions options = 4; - bool MethodDescriptorProto::has_options() const { +bool MethodDescriptorProto::has_options() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void MethodDescriptorProto::set_has_options() { +void MethodDescriptorProto::set_has_options() { _has_bits_[0] |= 0x00000008u; } - void MethodDescriptorProto::clear_has_options() { +void MethodDescriptorProto::clear_has_options() { _has_bits_[0] &= ~0x00000008u; } - void MethodDescriptorProto::clear_options() { +void MethodDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); clear_has_options(); } @@ -6931,16 +7508,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } // optional bool client_streaming = 5 [default = false]; - bool MethodDescriptorProto::has_client_streaming() const { +bool MethodDescriptorProto::has_client_streaming() const { return (_has_bits_[0] & 0x00000010u) != 0; } - void MethodDescriptorProto::set_has_client_streaming() { +void MethodDescriptorProto::set_has_client_streaming() { _has_bits_[0] |= 0x00000010u; } - void MethodDescriptorProto::clear_has_client_streaming() { +void MethodDescriptorProto::clear_has_client_streaming() { _has_bits_[0] &= ~0x00000010u; } - void MethodDescriptorProto::clear_client_streaming() { +void MethodDescriptorProto::clear_client_streaming() { client_streaming_ = false; clear_has_client_streaming(); } @@ -6955,16 +7532,16 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { } // optional bool server_streaming = 6 [default = false]; - bool MethodDescriptorProto::has_server_streaming() const { +bool MethodDescriptorProto::has_server_streaming() const { return (_has_bits_[0] & 0x00000020u) != 0; } - void MethodDescriptorProto::set_has_server_streaming() { +void MethodDescriptorProto::set_has_server_streaming() { _has_bits_[0] |= 0x00000020u; } - void MethodDescriptorProto::clear_has_server_streaming() { +void MethodDescriptorProto::clear_has_server_streaming() { _has_bits_[0] &= ~0x00000020u; } - void MethodDescriptorProto::clear_server_streaming() { +void MethodDescriptorProto::clear_server_streaming() { server_streaming_ = false; clear_has_server_streaming(); } @@ -7024,7 +7601,7 @@ const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FileOptions::FileOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FileOptions) } @@ -7381,12 +7958,15 @@ bool FileOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -7768,9 +8348,9 @@ int FileOptions::ByteSize() const { void FileOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FileOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FileOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -7895,16 +8475,16 @@ void FileOptions::InternalSwap(FileOptions* other) { // FileOptions // optional string java_package = 1; - bool FileOptions::has_java_package() const { +bool FileOptions::has_java_package() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void FileOptions::set_has_java_package() { +void FileOptions::set_has_java_package() { _has_bits_[0] |= 0x00000001u; } - void FileOptions::clear_has_java_package() { +void FileOptions::clear_has_java_package() { _has_bits_[0] &= ~0x00000001u; } - void FileOptions::clear_java_package() { +void FileOptions::clear_java_package() { java_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_java_package(); } @@ -7948,16 +8528,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional string java_outer_classname = 8; - bool FileOptions::has_java_outer_classname() const { +bool FileOptions::has_java_outer_classname() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void FileOptions::set_has_java_outer_classname() { +void FileOptions::set_has_java_outer_classname() { _has_bits_[0] |= 0x00000002u; } - void FileOptions::clear_has_java_outer_classname() { +void FileOptions::clear_has_java_outer_classname() { _has_bits_[0] &= ~0x00000002u; } - void FileOptions::clear_java_outer_classname() { +void FileOptions::clear_java_outer_classname() { java_outer_classname_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_java_outer_classname(); } @@ -8001,16 +8581,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool java_multiple_files = 10 [default = false]; - bool FileOptions::has_java_multiple_files() const { +bool FileOptions::has_java_multiple_files() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void FileOptions::set_has_java_multiple_files() { +void FileOptions::set_has_java_multiple_files() { _has_bits_[0] |= 0x00000004u; } - void FileOptions::clear_has_java_multiple_files() { +void FileOptions::clear_has_java_multiple_files() { _has_bits_[0] &= ~0x00000004u; } - void FileOptions::clear_java_multiple_files() { +void FileOptions::clear_java_multiple_files() { java_multiple_files_ = false; clear_has_java_multiple_files(); } @@ -8025,16 +8605,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool java_generate_equals_and_hash = 20 [default = false]; - bool FileOptions::has_java_generate_equals_and_hash() const { +bool FileOptions::has_java_generate_equals_and_hash() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void FileOptions::set_has_java_generate_equals_and_hash() { +void FileOptions::set_has_java_generate_equals_and_hash() { _has_bits_[0] |= 0x00000008u; } - void FileOptions::clear_has_java_generate_equals_and_hash() { +void FileOptions::clear_has_java_generate_equals_and_hash() { _has_bits_[0] &= ~0x00000008u; } - void FileOptions::clear_java_generate_equals_and_hash() { +void FileOptions::clear_java_generate_equals_and_hash() { java_generate_equals_and_hash_ = false; clear_has_java_generate_equals_and_hash(); } @@ -8049,16 +8629,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool java_string_check_utf8 = 27 [default = false]; - bool FileOptions::has_java_string_check_utf8() const { +bool FileOptions::has_java_string_check_utf8() const { return (_has_bits_[0] & 0x00000010u) != 0; } - void FileOptions::set_has_java_string_check_utf8() { +void FileOptions::set_has_java_string_check_utf8() { _has_bits_[0] |= 0x00000010u; } - void FileOptions::clear_has_java_string_check_utf8() { +void FileOptions::clear_has_java_string_check_utf8() { _has_bits_[0] &= ~0x00000010u; } - void FileOptions::clear_java_string_check_utf8() { +void FileOptions::clear_java_string_check_utf8() { java_string_check_utf8_ = false; clear_has_java_string_check_utf8(); } @@ -8073,16 +8653,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; - bool FileOptions::has_optimize_for() const { +bool FileOptions::has_optimize_for() const { return (_has_bits_[0] & 0x00000020u) != 0; } - void FileOptions::set_has_optimize_for() { +void FileOptions::set_has_optimize_for() { _has_bits_[0] |= 0x00000020u; } - void FileOptions::clear_has_optimize_for() { +void FileOptions::clear_has_optimize_for() { _has_bits_[0] &= ~0x00000020u; } - void FileOptions::clear_optimize_for() { +void FileOptions::clear_optimize_for() { optimize_for_ = 1; clear_has_optimize_for(); } @@ -8098,16 +8678,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional string go_package = 11; - bool FileOptions::has_go_package() const { +bool FileOptions::has_go_package() const { return (_has_bits_[0] & 0x00000040u) != 0; } - void FileOptions::set_has_go_package() { +void FileOptions::set_has_go_package() { _has_bits_[0] |= 0x00000040u; } - void FileOptions::clear_has_go_package() { +void FileOptions::clear_has_go_package() { _has_bits_[0] &= ~0x00000040u; } - void FileOptions::clear_go_package() { +void FileOptions::clear_go_package() { go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_go_package(); } @@ -8151,16 +8731,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool cc_generic_services = 16 [default = false]; - bool FileOptions::has_cc_generic_services() const { +bool FileOptions::has_cc_generic_services() const { return (_has_bits_[0] & 0x00000080u) != 0; } - void FileOptions::set_has_cc_generic_services() { +void FileOptions::set_has_cc_generic_services() { _has_bits_[0] |= 0x00000080u; } - void FileOptions::clear_has_cc_generic_services() { +void FileOptions::clear_has_cc_generic_services() { _has_bits_[0] &= ~0x00000080u; } - void FileOptions::clear_cc_generic_services() { +void FileOptions::clear_cc_generic_services() { cc_generic_services_ = false; clear_has_cc_generic_services(); } @@ -8175,16 +8755,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool java_generic_services = 17 [default = false]; - bool FileOptions::has_java_generic_services() const { +bool FileOptions::has_java_generic_services() const { return (_has_bits_[0] & 0x00000100u) != 0; } - void FileOptions::set_has_java_generic_services() { +void FileOptions::set_has_java_generic_services() { _has_bits_[0] |= 0x00000100u; } - void FileOptions::clear_has_java_generic_services() { +void FileOptions::clear_has_java_generic_services() { _has_bits_[0] &= ~0x00000100u; } - void FileOptions::clear_java_generic_services() { +void FileOptions::clear_java_generic_services() { java_generic_services_ = false; clear_has_java_generic_services(); } @@ -8199,16 +8779,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool py_generic_services = 18 [default = false]; - bool FileOptions::has_py_generic_services() const { +bool FileOptions::has_py_generic_services() const { return (_has_bits_[0] & 0x00000200u) != 0; } - void FileOptions::set_has_py_generic_services() { +void FileOptions::set_has_py_generic_services() { _has_bits_[0] |= 0x00000200u; } - void FileOptions::clear_has_py_generic_services() { +void FileOptions::clear_has_py_generic_services() { _has_bits_[0] &= ~0x00000200u; } - void FileOptions::clear_py_generic_services() { +void FileOptions::clear_py_generic_services() { py_generic_services_ = false; clear_has_py_generic_services(); } @@ -8223,16 +8803,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool deprecated = 23 [default = false]; - bool FileOptions::has_deprecated() const { +bool FileOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000400u) != 0; } - void FileOptions::set_has_deprecated() { +void FileOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000400u; } - void FileOptions::clear_has_deprecated() { +void FileOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000400u; } - void FileOptions::clear_deprecated() { +void FileOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -8247,16 +8827,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional bool cc_enable_arenas = 31 [default = false]; - bool FileOptions::has_cc_enable_arenas() const { +bool FileOptions::has_cc_enable_arenas() const { return (_has_bits_[0] & 0x00000800u) != 0; } - void FileOptions::set_has_cc_enable_arenas() { +void FileOptions::set_has_cc_enable_arenas() { _has_bits_[0] |= 0x00000800u; } - void FileOptions::clear_has_cc_enable_arenas() { +void FileOptions::clear_has_cc_enable_arenas() { _has_bits_[0] &= ~0x00000800u; } - void FileOptions::clear_cc_enable_arenas() { +void FileOptions::clear_cc_enable_arenas() { cc_enable_arenas_ = false; clear_has_cc_enable_arenas(); } @@ -8271,16 +8851,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional string objc_class_prefix = 36; - bool FileOptions::has_objc_class_prefix() const { +bool FileOptions::has_objc_class_prefix() const { return (_has_bits_[0] & 0x00001000u) != 0; } - void FileOptions::set_has_objc_class_prefix() { +void FileOptions::set_has_objc_class_prefix() { _has_bits_[0] |= 0x00001000u; } - void FileOptions::clear_has_objc_class_prefix() { +void FileOptions::clear_has_objc_class_prefix() { _has_bits_[0] &= ~0x00001000u; } - void FileOptions::clear_objc_class_prefix() { +void FileOptions::clear_objc_class_prefix() { objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_objc_class_prefix(); } @@ -8324,16 +8904,16 @@ void FileOptions::InternalSwap(FileOptions* other) { } // optional string csharp_namespace = 37; - bool FileOptions::has_csharp_namespace() const { +bool FileOptions::has_csharp_namespace() const { return (_has_bits_[0] & 0x00002000u) != 0; } - void FileOptions::set_has_csharp_namespace() { +void FileOptions::set_has_csharp_namespace() { _has_bits_[0] |= 0x00002000u; } - void FileOptions::clear_has_csharp_namespace() { +void FileOptions::clear_has_csharp_namespace() { _has_bits_[0] &= ~0x00002000u; } - void FileOptions::clear_csharp_namespace() { +void FileOptions::clear_csharp_namespace() { csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_csharp_namespace(); } @@ -8377,10 +8957,10 @@ void FileOptions::InternalSwap(FileOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int FileOptions::uninterpreted_option_size() const { +int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void FileOptions::clear_uninterpreted_option() { +void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { @@ -8419,7 +8999,7 @@ const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MessageOptions::MessageOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MessageOptions) } @@ -8574,12 +9154,15 @@ bool MessageOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -8741,9 +9324,9 @@ int MessageOptions::ByteSize() const { void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const MessageOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const MessageOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -8821,16 +9404,16 @@ void MessageOptions::InternalSwap(MessageOptions* other) { // MessageOptions // optional bool message_set_wire_format = 1 [default = false]; - bool MessageOptions::has_message_set_wire_format() const { +bool MessageOptions::has_message_set_wire_format() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void MessageOptions::set_has_message_set_wire_format() { +void MessageOptions::set_has_message_set_wire_format() { _has_bits_[0] |= 0x00000001u; } - void MessageOptions::clear_has_message_set_wire_format() { +void MessageOptions::clear_has_message_set_wire_format() { _has_bits_[0] &= ~0x00000001u; } - void MessageOptions::clear_message_set_wire_format() { +void MessageOptions::clear_message_set_wire_format() { message_set_wire_format_ = false; clear_has_message_set_wire_format(); } @@ -8845,16 +9428,16 @@ void MessageOptions::InternalSwap(MessageOptions* other) { } // optional bool no_standard_descriptor_accessor = 2 [default = false]; - bool MessageOptions::has_no_standard_descriptor_accessor() const { +bool MessageOptions::has_no_standard_descriptor_accessor() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void MessageOptions::set_has_no_standard_descriptor_accessor() { +void MessageOptions::set_has_no_standard_descriptor_accessor() { _has_bits_[0] |= 0x00000002u; } - void MessageOptions::clear_has_no_standard_descriptor_accessor() { +void MessageOptions::clear_has_no_standard_descriptor_accessor() { _has_bits_[0] &= ~0x00000002u; } - void MessageOptions::clear_no_standard_descriptor_accessor() { +void MessageOptions::clear_no_standard_descriptor_accessor() { no_standard_descriptor_accessor_ = false; clear_has_no_standard_descriptor_accessor(); } @@ -8869,16 +9452,16 @@ void MessageOptions::InternalSwap(MessageOptions* other) { } // optional bool deprecated = 3 [default = false]; - bool MessageOptions::has_deprecated() const { +bool MessageOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void MessageOptions::set_has_deprecated() { +void MessageOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000004u; } - void MessageOptions::clear_has_deprecated() { +void MessageOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000004u; } - void MessageOptions::clear_deprecated() { +void MessageOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -8893,16 +9476,16 @@ void MessageOptions::InternalSwap(MessageOptions* other) { } // optional bool map_entry = 7; - bool MessageOptions::has_map_entry() const { +bool MessageOptions::has_map_entry() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void MessageOptions::set_has_map_entry() { +void MessageOptions::set_has_map_entry() { _has_bits_[0] |= 0x00000008u; } - void MessageOptions::clear_has_map_entry() { +void MessageOptions::clear_has_map_entry() { _has_bits_[0] &= ~0x00000008u; } - void MessageOptions::clear_map_entry() { +void MessageOptions::clear_map_entry() { map_entry_ = false; clear_has_map_entry(); } @@ -8917,10 +9500,10 @@ void MessageOptions::InternalSwap(MessageOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int MessageOptions::uninterpreted_option_size() const { +int MessageOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void MessageOptions::clear_uninterpreted_option() { +void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { @@ -8973,9 +9556,33 @@ const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; const int FieldOptions::CType_ARRAYSIZE; #endif // _MSC_VER +const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor() { + protobuf_AssignDescriptorsOnce(); + return FieldOptions_JSType_descriptor_; +} +bool FieldOptions_JSType_IsValid(int value) { + switch(value) { + case 0: + case 1: + case 2: + return true; + default: + return false; + } +} + +#ifndef _MSC_VER +const FieldOptions_JSType FieldOptions::JS_NORMAL; +const FieldOptions_JSType FieldOptions::JS_STRING; +const FieldOptions_JSType FieldOptions::JS_NUMBER; +const FieldOptions_JSType FieldOptions::JSType_MIN; +const FieldOptions_JSType FieldOptions::JSType_MAX; +const int FieldOptions::JSType_ARRAYSIZE; +#endif // _MSC_VER #ifndef _MSC_VER const int FieldOptions::kCtypeFieldNumber; const int FieldOptions::kPackedFieldNumber; +const int FieldOptions::kJstypeFieldNumber; const int FieldOptions::kLazyFieldNumber; const int FieldOptions::kDeprecatedFieldNumber; const int FieldOptions::kWeakFieldNumber; @@ -8983,7 +9590,7 @@ const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FieldOptions::FieldOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FieldOptions) } @@ -9003,6 +9610,7 @@ void FieldOptions::SharedCtor() { _cached_size_ = 0; ctype_ = 0; packed_ = false; + jstype_ = 0; lazy_ = false; deprecated_ = false; weak_ = false; @@ -9054,8 +9662,9 @@ void FieldOptions::Clear() { ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) - if (_has_bits_[0 / 32] & 31u) { - ZR_(ctype_, weak_); + if (_has_bits_[0 / 32] & 63u) { + ZR_(ctype_, jstype_); + ZR_(packed_, weak_); } #undef ZR_HELPER_ @@ -9138,6 +9747,26 @@ bool FieldOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(48)) goto parse_jstype; + break; + } + + // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; + case 6: { + if (tag == 48) { + parse_jstype: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldOptions_JSType_IsValid(value)) { + set_jstype(static_cast< ::google::protobuf::FieldOptions_JSType >(value)); + } else { + mutable_unknown_fields()->AddVarint(6, value); + } + } else { + goto handle_unusual; + } if (input->ExpectTag(80)) goto parse_weak; break; } @@ -9161,12 +9790,15 @@ bool FieldOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -9222,6 +9854,12 @@ void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->lazy(), output); } + // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; + if (has_jstype()) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 6, this->jstype(), output); + } + // optional bool weak = 10 [default = false]; if (has_weak()) { ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->weak(), output); @@ -9268,6 +9906,12 @@ void FieldOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->lazy(), target); } + // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; + if (has_jstype()) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 6, this->jstype(), target); + } + // optional bool weak = 10 [default = false]; if (has_weak()) { target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->weak(), target); @@ -9295,7 +9939,7 @@ void FieldOptions::SerializeWithCachedSizes( int FieldOptions::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & 31) { + if (_has_bits_[0 / 32] & 63) { // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (has_ctype()) { total_size += 1 + @@ -9307,6 +9951,12 @@ int FieldOptions::ByteSize() const { total_size += 1 + 1; } + // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; + if (has_jstype()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->jstype()); + } + // optional bool lazy = 5 [default = false]; if (has_lazy()) { total_size += 1 + 1; @@ -9346,9 +9996,9 @@ int FieldOptions::ByteSize() const { void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FieldOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FieldOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -9366,6 +10016,9 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { if (from.has_packed()) { set_packed(from.packed()); } + if (from.has_jstype()) { + set_jstype(from.jstype()); + } if (from.has_lazy()) { set_lazy(from.lazy()); } @@ -9408,6 +10061,7 @@ void FieldOptions::Swap(FieldOptions* other) { void FieldOptions::InternalSwap(FieldOptions* other) { std::swap(ctype_, other->ctype_); std::swap(packed_, other->packed_); + std::swap(jstype_, other->jstype_); std::swap(lazy_, other->lazy_); std::swap(deprecated_, other->deprecated_); std::swap(weak_, other->weak_); @@ -9430,16 +10084,16 @@ void FieldOptions::InternalSwap(FieldOptions* other) { // FieldOptions // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; - bool FieldOptions::has_ctype() const { +bool FieldOptions::has_ctype() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void FieldOptions::set_has_ctype() { +void FieldOptions::set_has_ctype() { _has_bits_[0] |= 0x00000001u; } - void FieldOptions::clear_has_ctype() { +void FieldOptions::clear_has_ctype() { _has_bits_[0] &= ~0x00000001u; } - void FieldOptions::clear_ctype() { +void FieldOptions::clear_ctype() { ctype_ = 0; clear_has_ctype(); } @@ -9455,16 +10109,16 @@ void FieldOptions::InternalSwap(FieldOptions* other) { } // optional bool packed = 2; - bool FieldOptions::has_packed() const { +bool FieldOptions::has_packed() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void FieldOptions::set_has_packed() { +void FieldOptions::set_has_packed() { _has_bits_[0] |= 0x00000002u; } - void FieldOptions::clear_has_packed() { +void FieldOptions::clear_has_packed() { _has_bits_[0] &= ~0x00000002u; } - void FieldOptions::clear_packed() { +void FieldOptions::clear_packed() { packed_ = false; clear_has_packed(); } @@ -9478,17 +10132,42 @@ void FieldOptions::InternalSwap(FieldOptions* other) { // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed) } -// optional bool lazy = 5 [default = false]; - bool FieldOptions::has_lazy() const { +// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; +bool FieldOptions::has_jstype() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void FieldOptions::set_has_lazy() { +void FieldOptions::set_has_jstype() { _has_bits_[0] |= 0x00000004u; } - void FieldOptions::clear_has_lazy() { +void FieldOptions::clear_has_jstype() { _has_bits_[0] &= ~0x00000004u; } - void FieldOptions::clear_lazy() { +void FieldOptions::clear_jstype() { + jstype_ = 0; + clear_has_jstype(); +} + ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const { + // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype) + return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_); +} + void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) { + assert(::google::protobuf::FieldOptions_JSType_IsValid(value)); + set_has_jstype(); + jstype_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype) +} + +// optional bool lazy = 5 [default = false]; +bool FieldOptions::has_lazy() const { + return (_has_bits_[0] & 0x00000008u) != 0; +} +void FieldOptions::set_has_lazy() { + _has_bits_[0] |= 0x00000008u; +} +void FieldOptions::clear_has_lazy() { + _has_bits_[0] &= ~0x00000008u; +} +void FieldOptions::clear_lazy() { lazy_ = false; clear_has_lazy(); } @@ -9503,16 +10182,16 @@ void FieldOptions::InternalSwap(FieldOptions* other) { } // optional bool deprecated = 3 [default = false]; - bool FieldOptions::has_deprecated() const { - return (_has_bits_[0] & 0x00000008u) != 0; +bool FieldOptions::has_deprecated() const { + return (_has_bits_[0] & 0x00000010u) != 0; } - void FieldOptions::set_has_deprecated() { - _has_bits_[0] |= 0x00000008u; +void FieldOptions::set_has_deprecated() { + _has_bits_[0] |= 0x00000010u; } - void FieldOptions::clear_has_deprecated() { - _has_bits_[0] &= ~0x00000008u; +void FieldOptions::clear_has_deprecated() { + _has_bits_[0] &= ~0x00000010u; } - void FieldOptions::clear_deprecated() { +void FieldOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -9527,16 +10206,16 @@ void FieldOptions::InternalSwap(FieldOptions* other) { } // optional bool weak = 10 [default = false]; - bool FieldOptions::has_weak() const { - return (_has_bits_[0] & 0x00000010u) != 0; +bool FieldOptions::has_weak() const { + return (_has_bits_[0] & 0x00000020u) != 0; } - void FieldOptions::set_has_weak() { - _has_bits_[0] |= 0x00000010u; +void FieldOptions::set_has_weak() { + _has_bits_[0] |= 0x00000020u; } - void FieldOptions::clear_has_weak() { - _has_bits_[0] &= ~0x00000010u; +void FieldOptions::clear_has_weak() { + _has_bits_[0] &= ~0x00000020u; } - void FieldOptions::clear_weak() { +void FieldOptions::clear_weak() { weak_ = false; clear_has_weak(); } @@ -9551,10 +10230,10 @@ void FieldOptions::InternalSwap(FieldOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int FieldOptions::uninterpreted_option_size() const { +int FieldOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void FieldOptions::clear_uninterpreted_option() { +void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { @@ -9591,7 +10270,7 @@ const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumOptions::EnumOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumOptions) } @@ -9714,12 +10393,15 @@ bool EnumOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -9851,9 +10533,9 @@ int EnumOptions::ByteSize() const { void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const EnumOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const EnumOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -9923,16 +10605,16 @@ void EnumOptions::InternalSwap(EnumOptions* other) { // EnumOptions // optional bool allow_alias = 2; - bool EnumOptions::has_allow_alias() const { +bool EnumOptions::has_allow_alias() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void EnumOptions::set_has_allow_alias() { +void EnumOptions::set_has_allow_alias() { _has_bits_[0] |= 0x00000001u; } - void EnumOptions::clear_has_allow_alias() { +void EnumOptions::clear_has_allow_alias() { _has_bits_[0] &= ~0x00000001u; } - void EnumOptions::clear_allow_alias() { +void EnumOptions::clear_allow_alias() { allow_alias_ = false; clear_has_allow_alias(); } @@ -9947,16 +10629,16 @@ void EnumOptions::InternalSwap(EnumOptions* other) { } // optional bool deprecated = 3 [default = false]; - bool EnumOptions::has_deprecated() const { +bool EnumOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void EnumOptions::set_has_deprecated() { +void EnumOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000002u; } - void EnumOptions::clear_has_deprecated() { +void EnumOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000002u; } - void EnumOptions::clear_deprecated() { +void EnumOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -9971,10 +10653,10 @@ void EnumOptions::InternalSwap(EnumOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int EnumOptions::uninterpreted_option_size() const { +int EnumOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void EnumOptions::clear_uninterpreted_option() { +void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { @@ -10010,7 +10692,7 @@ const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumValueOptions::EnumValueOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumValueOptions) } @@ -10105,12 +10787,15 @@ bool EnumValueOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -10225,9 +10910,9 @@ int EnumValueOptions::ByteSize() const { void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const EnumValueOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const EnumValueOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -10293,16 +10978,16 @@ void EnumValueOptions::InternalSwap(EnumValueOptions* other) { // EnumValueOptions // optional bool deprecated = 1 [default = false]; - bool EnumValueOptions::has_deprecated() const { +bool EnumValueOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void EnumValueOptions::set_has_deprecated() { +void EnumValueOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000001u; } - void EnumValueOptions::clear_has_deprecated() { +void EnumValueOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000001u; } - void EnumValueOptions::clear_deprecated() { +void EnumValueOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -10317,10 +11002,10 @@ void EnumValueOptions::InternalSwap(EnumValueOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int EnumValueOptions::uninterpreted_option_size() const { +int EnumValueOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void EnumValueOptions::clear_uninterpreted_option() { +void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { @@ -10356,7 +11041,7 @@ const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER ServiceOptions::ServiceOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.ServiceOptions) } @@ -10451,12 +11136,15 @@ bool ServiceOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -10571,9 +11259,9 @@ int ServiceOptions::ByteSize() const { void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const ServiceOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const ServiceOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -10639,16 +11327,16 @@ void ServiceOptions::InternalSwap(ServiceOptions* other) { // ServiceOptions // optional bool deprecated = 33 [default = false]; - bool ServiceOptions::has_deprecated() const { +bool ServiceOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void ServiceOptions::set_has_deprecated() { +void ServiceOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000001u; } - void ServiceOptions::clear_has_deprecated() { +void ServiceOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000001u; } - void ServiceOptions::clear_deprecated() { +void ServiceOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -10663,10 +11351,10 @@ void ServiceOptions::InternalSwap(ServiceOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int ServiceOptions::uninterpreted_option_size() const { +int ServiceOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void ServiceOptions::clear_uninterpreted_option() { +void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { @@ -10702,7 +11390,7 @@ const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MethodOptions::MethodOptions() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.MethodOptions) } @@ -10797,12 +11485,15 @@ bool MethodOptions::MergePartialFromCodedStream( case 999: { if (tag == 7994) { parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_uninterpreted_option())); } else { goto handle_unusual; } - if (input->ExpectTag(7994)) goto parse_uninterpreted_option; + if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -10917,9 +11608,9 @@ int MethodOptions::ByteSize() const { void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const MethodOptions* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const MethodOptions* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -10985,16 +11676,16 @@ void MethodOptions::InternalSwap(MethodOptions* other) { // MethodOptions // optional bool deprecated = 33 [default = false]; - bool MethodOptions::has_deprecated() const { +bool MethodOptions::has_deprecated() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void MethodOptions::set_has_deprecated() { +void MethodOptions::set_has_deprecated() { _has_bits_[0] |= 0x00000001u; } - void MethodOptions::clear_has_deprecated() { +void MethodOptions::clear_has_deprecated() { _has_bits_[0] &= ~0x00000001u; } - void MethodOptions::clear_deprecated() { +void MethodOptions::clear_deprecated() { deprecated_ = false; clear_has_deprecated(); } @@ -11009,10 +11700,10 @@ void MethodOptions::InternalSwap(MethodOptions* other) { } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; - int MethodOptions::uninterpreted_option_size() const { +int MethodOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); } - void MethodOptions::clear_uninterpreted_option() { +void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { @@ -11048,7 +11739,7 @@ const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER UninterpretedOption_NamePart::UninterpretedOption_NamePart() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption.NamePart) } @@ -11281,9 +11972,9 @@ int UninterpretedOption_NamePart::ByteSize() const { void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const UninterpretedOption_NamePart* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const UninterpretedOption_NamePart* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -11359,7 +12050,7 @@ const int UninterpretedOption::kAggregateValueFieldNumber; #endif // !_MSC_VER UninterpretedOption::UninterpretedOption() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UninterpretedOption) } @@ -11470,13 +12161,15 @@ bool UninterpretedOption::MergePartialFromCodedStream( // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; case 2: { if (tag == 18) { - parse_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_name())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_name; + if (input->ExpectTag(18)) goto parse_loop_name; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(26)) goto parse_identifier_value; break; } @@ -11780,9 +12473,9 @@ int UninterpretedOption::ByteSize() const { void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const UninterpretedOption* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const UninterpretedOption* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -11868,16 +12561,16 @@ void UninterpretedOption::InternalSwap(UninterpretedOption* other) { // UninterpretedOption_NamePart // required string name_part = 1; - bool UninterpretedOption_NamePart::has_name_part() const { +bool UninterpretedOption_NamePart::has_name_part() const { return (_has_bits_[0] & 0x00000001u) != 0; } - void UninterpretedOption_NamePart::set_has_name_part() { +void UninterpretedOption_NamePart::set_has_name_part() { _has_bits_[0] |= 0x00000001u; } - void UninterpretedOption_NamePart::clear_has_name_part() { +void UninterpretedOption_NamePart::clear_has_name_part() { _has_bits_[0] &= ~0x00000001u; } - void UninterpretedOption_NamePart::clear_name_part() { +void UninterpretedOption_NamePart::clear_name_part() { name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_name_part(); } @@ -11921,16 +12614,16 @@ void UninterpretedOption::InternalSwap(UninterpretedOption* other) { } // required bool is_extension = 2; - bool UninterpretedOption_NamePart::has_is_extension() const { +bool UninterpretedOption_NamePart::has_is_extension() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void UninterpretedOption_NamePart::set_has_is_extension() { +void UninterpretedOption_NamePart::set_has_is_extension() { _has_bits_[0] |= 0x00000002u; } - void UninterpretedOption_NamePart::clear_has_is_extension() { +void UninterpretedOption_NamePart::clear_has_is_extension() { _has_bits_[0] &= ~0x00000002u; } - void UninterpretedOption_NamePart::clear_is_extension() { +void UninterpretedOption_NamePart::clear_is_extension() { is_extension_ = false; clear_has_is_extension(); } @@ -11949,10 +12642,10 @@ void UninterpretedOption::InternalSwap(UninterpretedOption* other) { // UninterpretedOption // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; - int UninterpretedOption::name_size() const { +int UninterpretedOption::name_size() const { return name_.size(); } - void UninterpretedOption::clear_name() { +void UninterpretedOption::clear_name() { name_.Clear(); } const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { @@ -11979,16 +12672,16 @@ UninterpretedOption::mutable_name() { } // optional string identifier_value = 3; - bool UninterpretedOption::has_identifier_value() const { +bool UninterpretedOption::has_identifier_value() const { return (_has_bits_[0] & 0x00000002u) != 0; } - void UninterpretedOption::set_has_identifier_value() { +void UninterpretedOption::set_has_identifier_value() { _has_bits_[0] |= 0x00000002u; } - void UninterpretedOption::clear_has_identifier_value() { +void UninterpretedOption::clear_has_identifier_value() { _has_bits_[0] &= ~0x00000002u; } - void UninterpretedOption::clear_identifier_value() { +void UninterpretedOption::clear_identifier_value() { identifier_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_identifier_value(); } @@ -12032,16 +12725,16 @@ UninterpretedOption::mutable_name() { } // optional uint64 positive_int_value = 4; - bool UninterpretedOption::has_positive_int_value() const { +bool UninterpretedOption::has_positive_int_value() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void UninterpretedOption::set_has_positive_int_value() { +void UninterpretedOption::set_has_positive_int_value() { _has_bits_[0] |= 0x00000004u; } - void UninterpretedOption::clear_has_positive_int_value() { +void UninterpretedOption::clear_has_positive_int_value() { _has_bits_[0] &= ~0x00000004u; } - void UninterpretedOption::clear_positive_int_value() { +void UninterpretedOption::clear_positive_int_value() { positive_int_value_ = GOOGLE_ULONGLONG(0); clear_has_positive_int_value(); } @@ -12056,16 +12749,16 @@ UninterpretedOption::mutable_name() { } // optional int64 negative_int_value = 5; - bool UninterpretedOption::has_negative_int_value() const { +bool UninterpretedOption::has_negative_int_value() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void UninterpretedOption::set_has_negative_int_value() { +void UninterpretedOption::set_has_negative_int_value() { _has_bits_[0] |= 0x00000008u; } - void UninterpretedOption::clear_has_negative_int_value() { +void UninterpretedOption::clear_has_negative_int_value() { _has_bits_[0] &= ~0x00000008u; } - void UninterpretedOption::clear_negative_int_value() { +void UninterpretedOption::clear_negative_int_value() { negative_int_value_ = GOOGLE_LONGLONG(0); clear_has_negative_int_value(); } @@ -12080,16 +12773,16 @@ UninterpretedOption::mutable_name() { } // optional double double_value = 6; - bool UninterpretedOption::has_double_value() const { +bool UninterpretedOption::has_double_value() const { return (_has_bits_[0] & 0x00000010u) != 0; } - void UninterpretedOption::set_has_double_value() { +void UninterpretedOption::set_has_double_value() { _has_bits_[0] |= 0x00000010u; } - void UninterpretedOption::clear_has_double_value() { +void UninterpretedOption::clear_has_double_value() { _has_bits_[0] &= ~0x00000010u; } - void UninterpretedOption::clear_double_value() { +void UninterpretedOption::clear_double_value() { double_value_ = 0; clear_has_double_value(); } @@ -12104,16 +12797,16 @@ UninterpretedOption::mutable_name() { } // optional bytes string_value = 7; - bool UninterpretedOption::has_string_value() const { +bool UninterpretedOption::has_string_value() const { return (_has_bits_[0] & 0x00000020u) != 0; } - void UninterpretedOption::set_has_string_value() { +void UninterpretedOption::set_has_string_value() { _has_bits_[0] |= 0x00000020u; } - void UninterpretedOption::clear_has_string_value() { +void UninterpretedOption::clear_has_string_value() { _has_bits_[0] &= ~0x00000020u; } - void UninterpretedOption::clear_string_value() { +void UninterpretedOption::clear_string_value() { string_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_string_value(); } @@ -12157,16 +12850,16 @@ UninterpretedOption::mutable_name() { } // optional string aggregate_value = 8; - bool UninterpretedOption::has_aggregate_value() const { +bool UninterpretedOption::has_aggregate_value() const { return (_has_bits_[0] & 0x00000040u) != 0; } - void UninterpretedOption::set_has_aggregate_value() { +void UninterpretedOption::set_has_aggregate_value() { _has_bits_[0] |= 0x00000040u; } - void UninterpretedOption::clear_has_aggregate_value() { +void UninterpretedOption::clear_has_aggregate_value() { _has_bits_[0] &= ~0x00000040u; } - void UninterpretedOption::clear_aggregate_value() { +void UninterpretedOption::clear_aggregate_value() { aggregate_value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_aggregate_value(); } @@ -12222,7 +12915,7 @@ const int SourceCodeInfo_Location::kLeadingDetachedCommentsFieldNumber; #endif // !_MSC_VER SourceCodeInfo_Location::SourceCodeInfo_Location() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo.Location) } @@ -12625,9 +13318,9 @@ int SourceCodeInfo_Location::ByteSize() const { void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const SourceCodeInfo_Location* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const SourceCodeInfo_Location* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -12703,7 +13396,7 @@ const int SourceCodeInfo::kLocationFieldNumber; #endif // !_MSC_VER SourceCodeInfo::SourceCodeInfo() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.SourceCodeInfo) } @@ -12780,13 +13473,15 @@ bool SourceCodeInfo::MergePartialFromCodedStream( // repeated .google.protobuf.SourceCodeInfo.Location location = 1; case 1: { if (tag == 10) { - parse_location: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_location: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_location())); } else { goto handle_unusual; } - if (input->ExpectTag(10)) goto parse_location; + if (input->ExpectTag(10)) goto parse_loop_location; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -12871,9 +13566,9 @@ int SourceCodeInfo::ByteSize() const { void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const SourceCodeInfo* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const SourceCodeInfo* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -12929,10 +13624,10 @@ void SourceCodeInfo::InternalSwap(SourceCodeInfo* other) { // SourceCodeInfo_Location // repeated int32 path = 1 [packed = true]; - int SourceCodeInfo_Location::path_size() const { +int SourceCodeInfo_Location::path_size() const { return path_.size(); } - void SourceCodeInfo_Location::clear_path() { +void SourceCodeInfo_Location::clear_path() { path_.Clear(); } ::google::protobuf::int32 SourceCodeInfo_Location::path(int index) const { @@ -12959,10 +13654,10 @@ SourceCodeInfo_Location::mutable_path() { } // repeated int32 span = 2 [packed = true]; - int SourceCodeInfo_Location::span_size() const { +int SourceCodeInfo_Location::span_size() const { return span_.size(); } - void SourceCodeInfo_Location::clear_span() { +void SourceCodeInfo_Location::clear_span() { span_.Clear(); } ::google::protobuf::int32 SourceCodeInfo_Location::span(int index) const { @@ -12989,16 +13684,16 @@ SourceCodeInfo_Location::mutable_span() { } // optional string leading_comments = 3; - bool SourceCodeInfo_Location::has_leading_comments() const { +bool SourceCodeInfo_Location::has_leading_comments() const { return (_has_bits_[0] & 0x00000004u) != 0; } - void SourceCodeInfo_Location::set_has_leading_comments() { +void SourceCodeInfo_Location::set_has_leading_comments() { _has_bits_[0] |= 0x00000004u; } - void SourceCodeInfo_Location::clear_has_leading_comments() { +void SourceCodeInfo_Location::clear_has_leading_comments() { _has_bits_[0] &= ~0x00000004u; } - void SourceCodeInfo_Location::clear_leading_comments() { +void SourceCodeInfo_Location::clear_leading_comments() { leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_leading_comments(); } @@ -13042,16 +13737,16 @@ SourceCodeInfo_Location::mutable_span() { } // optional string trailing_comments = 4; - bool SourceCodeInfo_Location::has_trailing_comments() const { +bool SourceCodeInfo_Location::has_trailing_comments() const { return (_has_bits_[0] & 0x00000008u) != 0; } - void SourceCodeInfo_Location::set_has_trailing_comments() { +void SourceCodeInfo_Location::set_has_trailing_comments() { _has_bits_[0] |= 0x00000008u; } - void SourceCodeInfo_Location::clear_has_trailing_comments() { +void SourceCodeInfo_Location::clear_has_trailing_comments() { _has_bits_[0] &= ~0x00000008u; } - void SourceCodeInfo_Location::clear_trailing_comments() { +void SourceCodeInfo_Location::clear_trailing_comments() { trailing_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_trailing_comments(); } @@ -13095,10 +13790,10 @@ SourceCodeInfo_Location::mutable_span() { } // repeated string leading_detached_comments = 6; - int SourceCodeInfo_Location::leading_detached_comments_size() const { +int SourceCodeInfo_Location::leading_detached_comments_size() const { return leading_detached_comments_.size(); } - void SourceCodeInfo_Location::clear_leading_detached_comments() { +void SourceCodeInfo_Location::clear_leading_detached_comments() { leading_detached_comments_.Clear(); } const ::std::string& SourceCodeInfo_Location::leading_detached_comments(int index) const { @@ -13153,10 +13848,10 @@ SourceCodeInfo_Location::mutable_leading_detached_comments() { // SourceCodeInfo // repeated .google.protobuf.SourceCodeInfo.Location location = 1; - int SourceCodeInfo::location_size() const { +int SourceCodeInfo::location_size() const { return location_.size(); } - void SourceCodeInfo::clear_location() { +void SourceCodeInfo::clear_location() { location_.Clear(); } const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 5bebf4fdbb..b887b8cb29 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -42,6 +42,7 @@ class FileDescriptorSet; class FileDescriptorProto; class DescriptorProto; class DescriptorProto_ExtensionRange; +class DescriptorProto_ReservedRange; class FieldDescriptorProto; class OneofDescriptorProto; class EnumDescriptorProto; @@ -155,6 +156,26 @@ inline bool FieldOptions_CType_Parse( return ::google::protobuf::internal::ParseNamedEnum( FieldOptions_CType_descriptor(), name, value); } +enum FieldOptions_JSType { + FieldOptions_JSType_JS_NORMAL = 0, + FieldOptions_JSType_JS_STRING = 1, + FieldOptions_JSType_JS_NUMBER = 2 +}; +LIBPROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value); +const FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL; +const FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER; +const int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor(); +inline const ::std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) { + return ::google::protobuf::internal::NameOfEnum( + FieldOptions_JSType_descriptor(), value); +} +inline bool FieldOptions_JSType_Parse( + const ::std::string& name, FieldOptions_JSType* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldOptions_JSType_descriptor(), name, value); +} // =================================================================== class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message { @@ -591,6 +612,105 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto }; // ------------------------------------------------------------------- +class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message { + public: + DescriptorProto_ReservedRange(); + virtual ~DescriptorProto_ReservedRange(); + + DescriptorProto_ReservedRange(const DescriptorProto_ReservedRange& from); + + inline DescriptorProto_ReservedRange& operator=(const DescriptorProto_ReservedRange& from) { + CopyFrom(from); + return *this; + } + + inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { + return _internal_metadata_.unknown_fields(); + } + + inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { + return _internal_metadata_.mutable_unknown_fields(); + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const DescriptorProto_ReservedRange& default_instance(); + + void Swap(DescriptorProto_ReservedRange* other); + + // implements Message ---------------------------------------------- + + inline DescriptorProto_ReservedRange* New() const { return New(NULL); } + + DescriptorProto_ReservedRange* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const DescriptorProto_ReservedRange& from); + void MergeFrom(const DescriptorProto_ReservedRange& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + void InternalSwap(DescriptorProto_ReservedRange* other); + private: + inline ::google::protobuf::Arena* GetArenaNoVirtual() const { + return _internal_metadata_.arena(); + } + inline void* MaybeArenaPtr() const { + return _internal_metadata_.raw_arena_ptr(); + } + public: + + ::google::protobuf::Metadata GetMetadata() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // optional int32 start = 1; + bool has_start() const; + void clear_start(); + static const int kStartFieldNumber = 1; + ::google::protobuf::int32 start() const; + void set_start(::google::protobuf::int32 value); + + // optional int32 end = 2; + bool has_end() const; + void clear_end(); + static const int kEndFieldNumber = 2; + ::google::protobuf::int32 end() const; + void set_end(::google::protobuf::int32 value); + + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ReservedRange) + private: + inline void set_has_start(); + inline void clear_has_start(); + inline void set_has_end(); + inline void clear_has_end(); + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + ::google::protobuf::uint32 _has_bits_[1]; + mutable int _cached_size_; + ::google::protobuf::int32 start_; + ::google::protobuf::int32 end_; + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); + + void InitAsDefaultInstance(); + static DescriptorProto_ReservedRange* default_instance_; +}; +// ------------------------------------------------------------------- + class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { public: DescriptorProto(); @@ -654,6 +774,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef DescriptorProto_ExtensionRange ExtensionRange; + typedef DescriptorProto_ReservedRange ReservedRange; // accessors ------------------------------------------------------- @@ -750,6 +871,34 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { ::google::protobuf::MessageOptions* release_options(); void set_allocated_options(::google::protobuf::MessageOptions* options); + // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; + int reserved_range_size() const; + void clear_reserved_range(); + static const int kReservedRangeFieldNumber = 9; + const ::google::protobuf::DescriptorProto_ReservedRange& reserved_range(int index) const; + ::google::protobuf::DescriptorProto_ReservedRange* mutable_reserved_range(int index); + ::google::protobuf::DescriptorProto_ReservedRange* add_reserved_range(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& + reserved_range() const; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* + mutable_reserved_range(); + + // repeated string reserved_name = 10; + int reserved_name_size() const; + void clear_reserved_name(); + static const int kReservedNameFieldNumber = 10; + const ::std::string& reserved_name(int index) const; + ::std::string* mutable_reserved_name(int index); + void set_reserved_name(int index, const ::std::string& value); + void set_reserved_name(int index, const char* value); + void set_reserved_name(int index, const char* value, size_t size); + ::std::string* add_reserved_name(); + void add_reserved_name(const ::std::string& value); + void add_reserved_name(const char* value); + void add_reserved_name(const char* value, size_t size); + const ::google::protobuf::RepeatedPtrField< ::std::string>& reserved_name() const; + ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_reserved_name(); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) private: inline void set_has_name(); @@ -768,6 +917,8 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto > oneof_decl_; ::google::protobuf::MessageOptions* options_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange > reserved_range_; + ::google::protobuf::RepeatedPtrField< ::std::string> reserved_name_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -2144,6 +2295,31 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { return FieldOptions_CType_Parse(name, value); } + typedef FieldOptions_JSType JSType; + static const JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL; + static const JSType JS_STRING = FieldOptions_JSType_JS_STRING; + static const JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER; + static inline bool JSType_IsValid(int value) { + return FieldOptions_JSType_IsValid(value); + } + static const JSType JSType_MIN = + FieldOptions_JSType_JSType_MIN; + static const JSType JSType_MAX = + FieldOptions_JSType_JSType_MAX; + static const int JSType_ARRAYSIZE = + FieldOptions_JSType_JSType_ARRAYSIZE; + static inline const ::google::protobuf::EnumDescriptor* + JSType_descriptor() { + return FieldOptions_JSType_descriptor(); + } + static inline const ::std::string& JSType_Name(JSType value) { + return FieldOptions_JSType_Name(value); + } + static inline bool JSType_Parse(const ::std::string& name, + JSType* value) { + return FieldOptions_JSType_Parse(name, value); + } + // accessors ------------------------------------------------------- // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; @@ -2160,6 +2336,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { bool packed() const; void set_packed(bool value); + // optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; + bool has_jstype() const; + void clear_jstype(); + static const int kJstypeFieldNumber = 6; + ::google::protobuf::FieldOptions_JSType jstype() const; + void set_jstype(::google::protobuf::FieldOptions_JSType value); + // optional bool lazy = 5 [default = false]; bool has_lazy() const; void clear_lazy(); @@ -2200,6 +2383,8 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline void clear_has_ctype(); inline void set_has_packed(); inline void clear_has_packed(); + inline void set_has_jstype(); + inline void clear_has_jstype(); inline void set_has_lazy(); inline void clear_has_lazy(); inline void set_has_deprecated(); @@ -2213,11 +2398,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { ::google::protobuf::uint32 _has_bits_[1]; mutable int _cached_size_; int ctype_; + int jstype_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool packed_; bool lazy_; bool deprecated_; bool weak_; - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -3754,6 +3940,58 @@ inline void DescriptorProto_ExtensionRange::set_end(::google::protobuf::int32 va // ------------------------------------------------------------------- +// DescriptorProto_ReservedRange + +// optional int32 start = 1; +inline bool DescriptorProto_ReservedRange::has_start() const { + return (_has_bits_[0] & 0x00000001u) != 0; +} +inline void DescriptorProto_ReservedRange::set_has_start() { + _has_bits_[0] |= 0x00000001u; +} +inline void DescriptorProto_ReservedRange::clear_has_start() { + _has_bits_[0] &= ~0x00000001u; +} +inline void DescriptorProto_ReservedRange::clear_start() { + start_ = 0; + clear_has_start(); +} +inline ::google::protobuf::int32 DescriptorProto_ReservedRange::start() const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.start) + return start_; +} +inline void DescriptorProto_ReservedRange::set_start(::google::protobuf::int32 value) { + set_has_start(); + start_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.start) +} + +// optional int32 end = 2; +inline bool DescriptorProto_ReservedRange::has_end() const { + return (_has_bits_[0] & 0x00000002u) != 0; +} +inline void DescriptorProto_ReservedRange::set_has_end() { + _has_bits_[0] |= 0x00000002u; +} +inline void DescriptorProto_ReservedRange::clear_has_end() { + _has_bits_[0] &= ~0x00000002u; +} +inline void DescriptorProto_ReservedRange::clear_end() { + end_ = 0; + clear_has_end(); +} +inline ::google::protobuf::int32 DescriptorProto_ReservedRange::end() const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.ReservedRange.end) + return end_; +} +inline void DescriptorProto_ReservedRange::set_end(::google::protobuf::int32 value) { + set_has_end(); + end_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.ReservedRange.end) +} + +// ------------------------------------------------------------------- + // DescriptorProto // optional string name = 1; @@ -4032,6 +4270,90 @@ inline void DescriptorProto::set_allocated_options(::google::protobuf::MessageOp // @@protoc_insertion_point(field_set_allocated:google.protobuf.DescriptorProto.options) } +// repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9; +inline int DescriptorProto::reserved_range_size() const { + return reserved_range_.size(); +} +inline void DescriptorProto::clear_reserved_range() { + reserved_range_.Clear(); +} +inline const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Get(index); +} +inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Mutable(index); +} +inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { + // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_.Add(); +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* +DescriptorProto::mutable_reserved_range() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) + return &reserved_range_; +} + +// repeated string reserved_name = 10; +inline int DescriptorProto::reserved_name_size() const { + return reserved_name_.size(); +} +inline void DescriptorProto::clear_reserved_name() { + reserved_name_.Clear(); +} +inline const ::std::string& DescriptorProto::reserved_name(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_.Get(index); +} +inline ::std::string* DescriptorProto::mutable_reserved_name(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_.Mutable(index); +} +inline void DescriptorProto::set_reserved_name(int index, const ::std::string& value) { + // @@protoc_insertion_point(field_set:google.protobuf.DescriptorProto.reserved_name) + reserved_name_.Mutable(index)->assign(value); +} +inline void DescriptorProto::set_reserved_name(int index, const char* value) { + reserved_name_.Mutable(index)->assign(value); + // @@protoc_insertion_point(field_set_char:google.protobuf.DescriptorProto.reserved_name) +} +inline void DescriptorProto::set_reserved_name(int index, const char* value, size_t size) { + reserved_name_.Mutable(index)->assign( + reinterpret_cast(value), size); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) +} +inline ::std::string* DescriptorProto::add_reserved_name() { + return reserved_name_.Add(); +} +inline void DescriptorProto::add_reserved_name(const ::std::string& value) { + reserved_name_.Add()->assign(value); + // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_name) +} +inline void DescriptorProto::add_reserved_name(const char* value) { + reserved_name_.Add()->assign(value); + // @@protoc_insertion_point(field_add_char:google.protobuf.DescriptorProto.reserved_name) +} +inline void DescriptorProto::add_reserved_name(const char* value, size_t size) { + reserved_name_.Add()->assign(reinterpret_cast(value), size); + // @@protoc_insertion_point(field_add_pointer:google.protobuf.DescriptorProto.reserved_name) +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +DescriptorProto::reserved_name() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_name) + return reserved_name_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +DescriptorProto::mutable_reserved_name() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_name) + return &reserved_name_; +} + // ------------------------------------------------------------------- // FieldDescriptorProto @@ -5783,15 +6105,40 @@ inline void FieldOptions::set_packed(bool value) { // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.packed) } +// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL]; +inline bool FieldOptions::has_jstype() const { + return (_has_bits_[0] & 0x00000004u) != 0; +} +inline void FieldOptions::set_has_jstype() { + _has_bits_[0] |= 0x00000004u; +} +inline void FieldOptions::clear_has_jstype() { + _has_bits_[0] &= ~0x00000004u; +} +inline void FieldOptions::clear_jstype() { + jstype_ = 0; + clear_has_jstype(); +} +inline ::google::protobuf::FieldOptions_JSType FieldOptions::jstype() const { + // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.jstype) + return static_cast< ::google::protobuf::FieldOptions_JSType >(jstype_); +} +inline void FieldOptions::set_jstype(::google::protobuf::FieldOptions_JSType value) { + assert(::google::protobuf::FieldOptions_JSType_IsValid(value)); + set_has_jstype(); + jstype_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.FieldOptions.jstype) +} + // optional bool lazy = 5 [default = false]; inline bool FieldOptions::has_lazy() const { - return (_has_bits_[0] & 0x00000004u) != 0; + return (_has_bits_[0] & 0x00000008u) != 0; } inline void FieldOptions::set_has_lazy() { - _has_bits_[0] |= 0x00000004u; + _has_bits_[0] |= 0x00000008u; } inline void FieldOptions::clear_has_lazy() { - _has_bits_[0] &= ~0x00000004u; + _has_bits_[0] &= ~0x00000008u; } inline void FieldOptions::clear_lazy() { lazy_ = false; @@ -5809,13 +6156,13 @@ inline void FieldOptions::set_lazy(bool value) { // optional bool deprecated = 3 [default = false]; inline bool FieldOptions::has_deprecated() const { - return (_has_bits_[0] & 0x00000008u) != 0; + return (_has_bits_[0] & 0x00000010u) != 0; } inline void FieldOptions::set_has_deprecated() { - _has_bits_[0] |= 0x00000008u; + _has_bits_[0] |= 0x00000010u; } inline void FieldOptions::clear_has_deprecated() { - _has_bits_[0] &= ~0x00000008u; + _has_bits_[0] &= ~0x00000010u; } inline void FieldOptions::clear_deprecated() { deprecated_ = false; @@ -5833,13 +6180,13 @@ inline void FieldOptions::set_deprecated(bool value) { // optional bool weak = 10 [default = false]; inline bool FieldOptions::has_weak() const { - return (_has_bits_[0] & 0x00000010u) != 0; + return (_has_bits_[0] & 0x00000020u) != 0; } inline void FieldOptions::set_has_weak() { - _has_bits_[0] |= 0x00000010u; + _has_bits_[0] |= 0x00000020u; } inline void FieldOptions::clear_has_weak() { - _has_bits_[0] &= ~0x00000010u; + _has_bits_[0] &= ~0x00000020u; } inline void FieldOptions::clear_weak() { weak_ = false; @@ -6746,6 +7093,48 @@ SourceCodeInfo::mutable_location() { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) @@ -6776,6 +7165,11 @@ template <> inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_CType>() { return ::google::protobuf::FieldOptions_CType_descriptor(); } +template <> struct is_proto_enum< ::google::protobuf::FieldOptions_JSType> : ::google::protobuf::internal::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions_JSType>() { + return ::google::protobuf::FieldOptions_JSType_descriptor(); +} } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 7099135d0f..20a6008042 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -106,6 +106,18 @@ message DescriptorProto { repeated OneofDescriptorProto oneof_decl = 8; optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; } // Describes a field within a message. @@ -251,11 +263,11 @@ message MethodDescriptorProto { // * For options which will be published and used publicly by multiple // independent entities, e-mail protobuf-global-extension-registry@google.com // to reserve extension numbers. Simply provide your project name (e.g. -// Object-C plugin) and your porject website (if available) -- there's no need -// to explain how you intend to use them. Usually you only need one extension -// number. You can declare multiple options with only one extension number by -// putting them in a sub-message. See the Custom Options section of the docs -// for examples: +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: // https://developers.google.com/protocol-buffers/docs/proto#options // If this turns out to be popular, a web service will be set up // to automatically assign option numbers. @@ -442,10 +454,31 @@ message FieldOptions { // The packed option can be enabled for repeated primitive fields to enable // a more efficient representation on the wire. Rather than repeatedly // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. optional bool packed = 2; + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). By default these types are + // represented as JavaScript strings. This avoids loss of precision that can + // happen when a large value is converted to a floating point JavaScript + // numbers. Specifying JS_NUMBER for the jstype causes the generated + // JavaScript code to use the JavaScript "number" type instead of strings. + // This option is an enum to permit additional types to be added, + // e.g. goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } // Should this field be parsed lazily? Lazy applies only to message-type // fields. It means that when the outer message is initially parsed, the diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h index 934e4022be..86002d56f6 100644 --- a/src/google/protobuf/descriptor_database.h +++ b/src/google/protobuf/descriptor_database.h @@ -312,7 +312,7 @@ class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { // A DescriptorDatabase that fetches files from a given pool. class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { public: - DescriptorPoolDatabase(const DescriptorPool& pool); + explicit DescriptorPoolDatabase(const DescriptorPool& pool); ~DescriptorPoolDatabase(); // implements DescriptorDatabase ----------------------------------- @@ -341,7 +341,7 @@ class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase { // Merge more than two databases. The sources remain property of the caller. // The vector may be deleted after the constructor returns but the // DescriptorDatabases need to stick around. - MergedDescriptorDatabase(const vector& sources); + explicit MergedDescriptorDatabase(const vector& sources); ~MergedDescriptorDatabase(); // implements DescriptorDatabase ----------------------------------- diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index fdce3d78e2..760df097e6 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -139,6 +139,14 @@ DescriptorProto::ExtensionRange* AddExtensionRange(DescriptorProto* parent, return result; } +DescriptorProto::ReservedRange* AddReservedRange(DescriptorProto* parent, + int start, int end) { + DescriptorProto::ReservedRange* result = parent->add_reserved_range(); + result->set_start(start); + result->set_end(end); + return result; +} + EnumValueDescriptorProto* AddEnumValue(EnumDescriptorProto* enum_proto, const string& name, int number) { EnumValueDescriptorProto* result = enum_proto->add_value(); @@ -1720,6 +1728,84 @@ TEST_F(ExtensionDescriptorTest, DuplicateFieldNumber) { // =================================================================== +// Test reserved fields. +class ReservedDescriptorTest : public testing::Test { + protected: + virtual void SetUp() { + // Build descriptors for the following definitions: + // + // message Foo { + // reserved 2, 9 to 11, 15; + // reserved "foo", "bar"; + // } + + FileDescriptorProto foo_file; + foo_file.set_name("foo.proto"); + + DescriptorProto* foo = AddMessage(&foo_file, "Foo"); + AddReservedRange(foo, 2, 3); + AddReservedRange(foo, 9, 12); + AddReservedRange(foo, 15, 16); + + foo->add_reserved_name("foo"); + foo->add_reserved_name("bar"); + + // Build the descriptors and get the pointers. + foo_file_ = pool_.BuildFile(foo_file); + ASSERT_TRUE(foo_file_ != NULL); + + ASSERT_EQ(1, foo_file_->message_type_count()); + foo_ = foo_file_->message_type(0); + } + + DescriptorPool pool_; + const FileDescriptor* foo_file_; + const Descriptor* foo_; +}; + +TEST_F(ReservedDescriptorTest, ReservedRanges) { + ASSERT_EQ(3, foo_->reserved_range_count()); + + EXPECT_EQ(2, foo_->reserved_range(0)->start); + EXPECT_EQ(3, foo_->reserved_range(0)->end); + + EXPECT_EQ(9, foo_->reserved_range(1)->start); + EXPECT_EQ(12, foo_->reserved_range(1)->end); + + EXPECT_EQ(15, foo_->reserved_range(2)->start); + EXPECT_EQ(16, foo_->reserved_range(2)->end); +}; + +TEST_F(ReservedDescriptorTest, IsReservedNumber) { + EXPECT_FALSE(foo_->IsReservedNumber(1)); + EXPECT_TRUE (foo_->IsReservedNumber(2)); + EXPECT_FALSE(foo_->IsReservedNumber(3)); + EXPECT_FALSE(foo_->IsReservedNumber(8)); + EXPECT_TRUE (foo_->IsReservedNumber(9)); + EXPECT_TRUE (foo_->IsReservedNumber(10)); + EXPECT_TRUE (foo_->IsReservedNumber(11)); + EXPECT_FALSE(foo_->IsReservedNumber(12)); + EXPECT_FALSE(foo_->IsReservedNumber(13)); + EXPECT_FALSE(foo_->IsReservedNumber(14)); + EXPECT_TRUE (foo_->IsReservedNumber(15)); + EXPECT_FALSE(foo_->IsReservedNumber(16)); +}; + +TEST_F(ReservedDescriptorTest, ReservedNames) { + ASSERT_EQ(2, foo_->reserved_name_count()); + + EXPECT_EQ("foo", foo_->reserved_name(0)); + EXPECT_EQ("bar", foo_->reserved_name(1)); +}; + +TEST_F(ReservedDescriptorTest, IsReservedName) { + EXPECT_TRUE (foo_->IsReservedName("foo")); + EXPECT_TRUE (foo_->IsReservedName("bar")); + EXPECT_FALSE(foo_->IsReservedName("baz")); +}; + +// =================================================================== + class MiscTest : public testing::Test { protected: // Function which makes a field descriptor of the given type. @@ -2997,10 +3083,10 @@ class ValidationErrorTest : public testing::Test { protected: // Parse file_text as a FileDescriptorProto in text format and add it // to the DescriptorPool. Expect no errors. - void BuildFile(const string& file_text) { + const FileDescriptor* BuildFile(const string& file_text) { FileDescriptorProto file_proto; - ASSERT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); - ASSERT_TRUE(pool_.BuildFile(file_proto) != NULL); + EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto)); + return GOOGLE_CHECK_NOTNULL(pool_.BuildFile(file_proto)); } // Parse file_text as a FileDescriptorProto in text format and add it @@ -3251,6 +3337,102 @@ TEST_F(ValidationErrorTest, OverlappingExtensionRanges) { "already-defined range 20 to 29.\n"); } +TEST_F(ValidationErrorTest, ReservedFieldError) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " reserved_range { start: 10 end: 20 }" + "}", + + "foo.proto: Foo.foo: NUMBER: Field \"foo\" uses reserved number 15.\n"); +} + +TEST_F(ValidationErrorTest, ReservedExtensionRangeError) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " extension_range { start: 10 end: 20 }" + " reserved_range { start: 5 end: 15 }" + "}", + + "foo.proto: Foo: NUMBER: Extension range 10 to 19" + " overlaps with reserved range 5 to 14.\n"); +} + +TEST_F(ValidationErrorTest, ReservedExtensionRangeAdjacent) { + BuildFile( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " extension_range { start: 10 end: 20 }" + " reserved_range { start: 5 end: 10 }" + "}"); +} + +TEST_F(ValidationErrorTest, ReservedRangeOverlap) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " reserved_range { start: 10 end: 20 }" + " reserved_range { start: 5 end: 15 }" + "}", + + "foo.proto: Foo: NUMBER: Reserved range 5 to 14" + " overlaps with already-defined range 10 to 19.\n"); +} + +TEST_F(ValidationErrorTest, ReservedNameError) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " field { name: \"foo\" number: 15 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name: \"bar\" number: 16 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name: \"baz\" number: 17 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + "}", + + "foo.proto: Foo.foo: NAME: Field name \"foo\" is reserved.\n" + "foo.proto: Foo.bar: NAME: Field name \"bar\" is reserved.\n"); +} + +TEST_F(ValidationErrorTest, ReservedNameRedundant) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " reserved_name: \"foo\"" + " reserved_name: \"foo\"" + "}", + + "foo.proto: foo: NAME: Field name \"foo\" is reserved multiple times.\n"); +} + +TEST_F(ValidationErrorTest, ReservedFieldsDebugString) { + const FileDescriptor* file = BuildFile( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " reserved_name: \"foo\"" + " reserved_name: \"bar\"" + " reserved_range { start: 5 end: 6 }" + " reserved_range { start: 10 end: 20 }" + "}"); + + ASSERT_EQ( + "syntax = \"proto2\";\n\n" + "message Foo {\n" + " reserved 5, 10 to 19;\n" + " reserved \"foo\", \"bar\";\n" + "}\n\n", + file->DebugString()); +} + TEST_F(ValidationErrorTest, InvalidDefaults) { BuildFileWithErrors( "name: \"foo.proto\" " @@ -3399,6 +3581,48 @@ TEST_F(ValidationErrorTest, FieldOneofIndexNegative) { "range for type \"Foo\".\n"); } +TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { + // Fields belonging to the same oneof must be defined consecutively. + BuildFileWithWarnings( + "name: \"foo.proto\" " + "message_type {" + " name: \"Foo\"" + " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " field { name:\"bar\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " oneof_decl { name:\"foos\" }" + "}", + + "foo.proto: Foo.bar: OTHER: Fields in the same oneof must be defined " + "consecutively. \"bar\" cannot be defined before the completion of the " + "\"foos\" oneof definition.\n"); + + // Prevent interleaved fields, which belong to different oneofs. + BuildFileWithWarnings( + "name: \"foo2.proto\" " + "message_type {" + " name: \"Foo2\"" + " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 1 }" + " field { name:\"foo2\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " field { name:\"bar2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 1 }" + " oneof_decl { name:\"foos\" }" + " oneof_decl { name:\"bars\" }" + "}", + "foo2.proto: Foo2.bar1: OTHER: Fields in the same oneof must be defined " + "consecutively. \"bar1\" cannot be defined before the completion of the " + "\"foos\" oneof definition.\n" + "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined " + "consecutively. \"foo2\" cannot be defined before the completion of the " + "\"bars\" oneof definition.\n"); +} + TEST_F(ValidationErrorTest, FieldNumberConflict) { BuildFileWithErrors( "name: \"foo.proto\" " @@ -5293,6 +5517,22 @@ TEST_F(ValidationErrorTest, ValidateProto3LiteRuntime) { "in proto3.\n"); } +TEST_F(ValidationErrorTest, ValidateProto3Group) { + BuildFileWithErrors( + "name: 'foo.proto' " + "syntax: 'proto3' " + "message_type { " + " name: 'Foo' " + " nested_type { " + " name: 'FooGroup' " + " } " + " field { name:'foo_group' number: 1 label:LABEL_OPTIONAL " + " type: TYPE_GROUP type_name:'FooGroup' } " + "}", + "foo.proto: Foo.foo_group: TYPE: Groups are not supported in proto3 " + "syntax.\n"); +} + TEST_F(ValidationErrorTest, ValidateProto3EnumFromProto2) { // Define an enum in a proto2 file. diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index 4a11209e67..f78fce2125 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -117,7 +117,7 @@ const int Duration::kNanosFieldNumber; #endif // !_MSC_VER Duration::Duration() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Duration) } @@ -310,9 +310,9 @@ int Duration::ByteSize() const { void Duration::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Duration* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Duration* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -370,7 +370,7 @@ void Duration::InternalSwap(Duration* other) { // Duration // optional int64 seconds = 1; - void Duration::clear_seconds() { +void Duration::clear_seconds() { seconds_ = GOOGLE_LONGLONG(0); } ::google::protobuf::int64 Duration::seconds() const { @@ -384,7 +384,7 @@ void Duration::InternalSwap(Duration* other) { } // optional int32 nanos = 2; - void Duration::clear_nanos() { +void Duration::clear_nanos() { nanos_ = 0; } ::google::protobuf::int32 Duration::nanos() const { diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index f7ca5013d0..1a9a6661a1 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -111,7 +111,7 @@ static void MergeFromFail(int line) { #endif // !_MSC_VER Empty::Empty() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Empty) } @@ -221,9 +221,9 @@ int Empty::ByteSize() const { void Empty::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Empty* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Empty* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 03b38dd011..649ae18432 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -314,7 +314,7 @@ void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ extension->is_repeated = true; \ extension->is_packed = packed; \ extension->repeated_##LOWERCASE##_value = \ - Arena::Create >(arena_, arena_); \ + Arena::CreateMessage >(arena_); \ } else { \ GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \ GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ @@ -359,43 +359,43 @@ void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type, static_cast(field_type))) { case WireFormatLite::CPPTYPE_INT32: extension->repeated_int32_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_INT64: extension->repeated_int64_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_UINT32: extension->repeated_uint32_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_UINT64: extension->repeated_uint64_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_DOUBLE: extension->repeated_double_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_FLOAT: extension->repeated_float_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_BOOL: extension->repeated_bool_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_ENUM: extension->repeated_enum_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_STRING: extension->repeated_string_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; case WireFormatLite::CPPTYPE_MESSAGE: extension->repeated_message_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); break; } } @@ -468,7 +468,7 @@ void ExtensionSet::AddEnum(int number, FieldType type, extension->is_repeated = true; extension->is_packed = packed; extension->repeated_enum_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM); GOOGLE_DCHECK_EQ(extension->is_packed, packed); @@ -529,7 +529,7 @@ string* ExtensionSet::AddString(int number, FieldType type, extension->is_repeated = true; extension->is_packed = false; extension->repeated_string_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING); } @@ -632,6 +632,35 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type, extension->is_cleared = false; } +void ExtensionSet::UnsafeArenaSetAllocatedMessage( + int number, FieldType type, const FieldDescriptor* descriptor, + MessageLite* message) { + if (message == NULL) { + ClearExtension(number); + return; + } + Extension* extension; + if (MaybeNewExtension(number, descriptor, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_lazy = false; + extension->message_value = message; + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); + if (extension->is_lazy) { + extension->lazymessage_value->UnsafeArenaSetAllocatedMessage(message); + } else { + if (arena_ == NULL) { + delete extension->message_value; + } + extension->message_value = message; + } + } + extension->is_cleared = false; +} + + MessageLite* ExtensionSet::ReleaseMessage(int number, const MessageLite& prototype) { map::iterator iter = extensions_.find(number); @@ -712,7 +741,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } @@ -866,7 +895,7 @@ void ExtensionSet::InternalExtensionMergeFrom( case WireFormatLite::CPPTYPE_##UPPERCASE: \ if (is_new) { \ extension->repeated_##LOWERCASE##_value = \ - Arena::Create(arena_, arena_); \ + Arena::CreateMessage(arena_); \ } \ extension->repeated_##LOWERCASE##_value->MergeFrom( \ *other_extension.repeated_##LOWERCASE##_value); \ @@ -886,7 +915,7 @@ void ExtensionSet::InternalExtensionMergeFrom( case WireFormatLite::CPPTYPE_MESSAGE: if (is_new) { extension->repeated_message_value = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); } // We can't call RepeatedPtrField::MergeFrom() because // it would attempt to allocate new objects. diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index 6d6702b397..c371e011e7 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -194,7 +194,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // directly, unless you are doing low-level memory management. // // When calling any of these accessors, the extension number requested - // MUST exist in the DescriptorPool provided to the constructor. Otheriwse, + // MUST exist in the DescriptorPool provided to the constructor. Otherwise, // the method will fail an assert. Normally, though, you would not call // these directly; you would either call the generated accessors of your // message class (e.g. GetExtension()) or you would call the accessors @@ -262,6 +262,9 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void SetAllocatedMessage(int number, FieldType type, const FieldDescriptor* descriptor, MessageLite* message); + void UnsafeArenaSetAllocatedMessage(int number, FieldType type, + const FieldDescriptor* descriptor, + MessageLite* message); MessageLite* ReleaseMessage(int number, const MessageLite& prototype); MessageLite* UnsafeArenaReleaseMessage( int number, const MessageLite& prototype); @@ -432,6 +435,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& prototype) const = 0; virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0; virtual void SetAllocatedMessage(MessageLite *message) = 0; + virtual void UnsafeArenaSetAllocatedMessage(MessageLite *message) = 0; virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0; virtual MessageLite* UnsafeArenaReleaseMessage( const MessageLite& prototype) = 0; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 796e7a5f32..330bd8287d 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -221,7 +221,7 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = - ::google::protobuf::Arena::Create >(arena_, arena_); + ::google::protobuf::Arena::CreateMessage >(arena_); } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index b00461d5da..68314fd316 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -114,7 +114,7 @@ const int FieldMask::kPathsFieldNumber; #endif // !_MSC_VER FieldMask::FieldMask() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FieldMask) } @@ -277,9 +277,9 @@ int FieldMask::ByteSize() const { void FieldMask::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FieldMask* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FieldMask* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -331,10 +331,10 @@ void FieldMask::InternalSwap(FieldMask* other) { // FieldMask // repeated string paths = 1; - int FieldMask::paths_size() const { +int FieldMask::paths_size() const { return paths_.size(); } - void FieldMask::clear_paths() { +void FieldMask::clear_paths() { paths_.Clear(); } const ::std::string& FieldMask::paths(int index) const { diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 4dddf6c70f..dc8abb98a0 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -40,6 +40,7 @@ #include #include +#include #include // TODO(jasonh): Remove this once the compiler change to directly include this // is released to components. @@ -597,6 +598,42 @@ inline To dynamic_cast_if_available(From from) { #endif } +// Tries to downcast this message to a generated message type. +// Returns NULL if this class is not an instance of T. +// +// This is like dynamic_cast_if_available, except it works even when +// dynamic_cast is not available by using Reflection. However it only works +// with Message objects. +// +// TODO(haberman): can we remove dynamic_cast_if_available in favor of this? +template +T* DynamicCastToGenerated(const Message* from) { + // Compile-time assert that T is a generated type that has a + // default_instance() accessor, but avoid actually calling it. + const T&(*get_default_instance)() = &T::default_instance; + (void)get_default_instance; + + // Compile-time assert that T is a subclass of google::protobuf::Message. + const Message* unused = static_cast(NULL); + (void)unused; + +#if defined(GOOGLE_PROTOBUF_NO_RTTI) || \ + (defined(_MSC_VER) && !defined(_CPPRTTI)) + bool ok = &T::default_instance() == + from->GetReflection()->GetMessageFactory()->GetPrototype( + from->GetDescriptor()); + return ok ? down_cast(from) : NULL; +#else + return dynamic_cast(from); +#endif +} + +template +T* DynamicCastToGenerated(Message* from) { + const Message* message_const = from; + return const_cast(DynamicCastToGenerated(message_const)); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 678f92a7ee..6357e27d48 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -47,6 +47,10 @@ namespace google { namespace protobuf { + +class Arena; +namespace io { class CodedInputStream; } + namespace internal { @@ -106,6 +110,15 @@ template bool AllAreInitialized(const Type& t) { return true; } +class ArenaString; + +// Read a length (varint32), followed by a string, from *input. Return a +// pointer to a copy of the string that resides in *arena. Requires both +// args to be non-NULL. If something goes wrong while reading the data +// then NULL is returned (e.g., input does not start with a valid varint). +ArenaString* ReadArenaString(::google::protobuf::io::CodedInputStream* input, + ::google::protobuf::Arena* arena); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 93e1a22e69..3b8650d627 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -156,6 +156,11 @@ CodedInputStream::IncrementRecursionDepthAndPushLimit(int byte_limit) { return std::make_pair(PushLimit(byte_limit), --recursion_budget_); } +CodedInputStream::Limit CodedInputStream::ReadLengthAndPushLimit() { + uint32 length; + return PushLimit(ReadVarint32(&length) ? length : 0); +} + bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) { bool result = ConsumedEntireMessage(); PopLimit(limit); @@ -164,6 +169,12 @@ bool CodedInputStream::DecrementRecursionDepthAndPopLimit(Limit limit) { return result; } +bool CodedInputStream::CheckEntireMessageConsumedAndPopLimit(Limit limit) { + bool result = ConsumedEntireMessage(); + PopLimit(limit); + return result; +} + int CodedInputStream::BytesUntilLimit() const { if (current_limit_ == INT_MAX) return -1; int current_position = CurrentPosition(); @@ -245,20 +256,7 @@ bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { } bool CodedInputStream::ReadRaw(void* buffer, int size) { - int current_buffer_size; - while ((current_buffer_size = BufferSize()) < size) { - // Reading past end of buffer. Copy what we have, then refresh. - memcpy(buffer, buffer_, current_buffer_size); - buffer = reinterpret_cast(buffer) + current_buffer_size; - size -= current_buffer_size; - Advance(current_buffer_size); - if (!Refresh()) return false; - } - - memcpy(buffer, buffer_, size); - Advance(size); - - return true; + return InternalReadRawInline(buffer, size); } bool CodedInputStream::ReadString(string* buffer, int size) { @@ -336,17 +334,23 @@ bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { namespace { -inline const uint8* ReadVarint32FromArray( - const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { +// Read a varint from the given buffer, write it to *value, and return a pair. +// The first part of the pair is true iff the read was successful. The second +// part is buffer + (number of bytes read). This function is always inlined, +// so returning a pair is costless. +inline ::std::pair ReadVarint32FromArray( + uint32 first_byte, const uint8* buffer, + uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline ::std::pair ReadVarint32FromArray( + uint32 first_byte, const uint8* buffer, uint32* value) { // Fast path: We have enough bytes left in the buffer to guarantee that // this read won't cross the end, so we can skip the checks. + GOOGLE_DCHECK_EQ(*buffer, first_byte); + GOOGLE_DCHECK_EQ(first_byte & 0x80, 0x80) << first_byte; const uint8* ptr = buffer; uint32 b; - uint32 result; - - b = *(ptr++); result = b ; if (!(b & 0x80)) goto done; - result -= 0x80; + uint32 result = first_byte - 0x80; + ++ptr; // We just processed the first byte. Move on to the second. b = *(ptr++); result += b << 7; if (!(b & 0x80)) goto done; result -= 0x80 << 7; b = *(ptr++); result += b << 14; if (!(b & 0x80)) goto done; @@ -364,38 +368,42 @@ inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { // We have overrun the maximum size of a varint (10 bytes). Assume // the data is corrupt. - return NULL; + return std::make_pair(false, ptr); done: *value = result; - return ptr; + return std::make_pair(true, ptr); } } // namespace bool CodedInputStream::ReadVarint32Slow(uint32* value) { - uint64 result; // Directly invoke ReadVarint64Fallback, since we already tried to optimize // for one-byte varints. - if (!ReadVarint64Fallback(&result)) return false; - *value = (uint32)result; - return true; + std::pair p = ReadVarint64Fallback(); + *value = static_cast(p.first); + return p.second; } -bool CodedInputStream::ReadVarint32Fallback(uint32* value) { +int64 CodedInputStream::ReadVarint32Fallback(uint32 first_byte_or_zero) { if (BufferSize() >= kMaxVarintBytes || // Optimization: We're also safe if the buffer is non-empty and it ends // with a byte that would terminate a varint. (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { - const uint8* end = ReadVarint32FromArray(buffer_, value); - if (end == NULL) return false; - buffer_ = end; - return true; + GOOGLE_DCHECK_NE(first_byte_or_zero, 0) + << "Caller should provide us with *buffer_ when buffer is non-empty"; + uint32 temp; + ::std::pair p = + ReadVarint32FromArray(first_byte_or_zero, buffer_, &temp); + if (!p.first) return -1; + buffer_ = p.second; + return temp; } else { // Really slow case: we will incur the cost of an extra function call here, // but moving this out of line reduces the size of this function, which // improves the common case. In micro benchmarks, this is worth about 10-15% - return ReadVarint32Slow(value); + uint32 temp; + return ReadVarint32Slow(&temp) ? static_cast(temp) : -1; } } @@ -425,18 +433,24 @@ uint32 CodedInputStream::ReadTagSlow() { return static_cast(result); } -uint32 CodedInputStream::ReadTagFallback() { +uint32 CodedInputStream::ReadTagFallback(uint32 first_byte_or_zero) { const int buf_size = BufferSize(); if (buf_size >= kMaxVarintBytes || // Optimization: We're also safe if the buffer is non-empty and it ends // with a byte that would terminate a varint. (buf_size > 0 && !(buffer_end_[-1] & 0x80))) { + GOOGLE_DCHECK_EQ(first_byte_or_zero, buffer_[0]); + if (first_byte_or_zero == 0) { + ++buffer_; + return 0; + } uint32 tag; - const uint8* end = ReadVarint32FromArray(buffer_, &tag); - if (end == NULL) { + ::std::pair p = + ReadVarint32FromArray(first_byte_or_zero, buffer_, &tag); + if (!p.first) { return 0; } - buffer_ = end; + buffer_ = p.second; return tag; } else { // We are commonly at a limit when attempting to read tags. Try to quickly @@ -479,7 +493,7 @@ bool CodedInputStream::ReadVarint64Slow(uint64* value) { return true; } -bool CodedInputStream::ReadVarint64Fallback(uint64* value) { +std::pair CodedInputStream::ReadVarint64Fallback() { if (BufferSize() >= kMaxVarintBytes || // Optimization: We're also safe if the buffer is non-empty and it ends // with a byte that would terminate a varint. @@ -517,16 +531,18 @@ bool CodedInputStream::ReadVarint64Fallback(uint64* value) { // We have overrun the maximum size of a varint (10 bytes). The data // must be corrupt. - return false; + return std::make_pair(0, false); done: Advance(ptr - buffer_); - *value = (static_cast(part0) ) | - (static_cast(part1) << 28) | - (static_cast(part2) << 56); - return true; + return std::make_pair((static_cast(part0)) | + (static_cast(part1) << 28) | + (static_cast(part2) << 56), + true); } else { - return ReadVarint64Slow(value); + uint64 temp; + bool success = ReadVarint64Slow(&temp); + return std::make_pair(temp, success); } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index dea4b6508d..961c1a3f36 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -197,6 +197,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadRawInline(void* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Like ReadRaw, but reads into a string. // // Implementation Note: ReadString() grows the string gradually as it @@ -387,9 +392,14 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // under the limit, false if it has gone over. bool IncrementRecursionDepth(); - // Decrements the recursion depth. + // Decrements the recursion depth if possible. void DecrementRecursionDepth(); + // Decrements the recursion depth blindly. This is faster than + // DecrementRecursionDepth(). It should be used only if all previous + // increments to recursion depth were successful. + void UnsafeDecrementRecursionDepth(); + // Shorthand for make_pair(PushLimit(byte_limit), --recursion_budget_). // Using this can reduce code size and complexity in some cases. The caller // is expected to check that the second part of the result is non-negative (to @@ -398,15 +408,25 @@ class LIBPROTOBUF_EXPORT CodedInputStream { std::pair IncrementRecursionDepthAndPushLimit( int byte_limit); + // Shorthand for PushLimit(ReadVarint32(&length) ? length : 0). + Limit ReadLengthAndPushLimit(); + // Helper that is equivalent to: { // bool result = ConsumedEntireMessage(); // PopLimit(limit); - // DecrementRecursionDepth(); + // UnsafeDecrementRecursionDepth(); // return result; } // Using this can reduce code size and complexity in some cases. // Do not use unless the current recursion depth is greater than zero. bool DecrementRecursionDepthAndPopLimit(Limit limit); + // Helper that is equivalent to: { + // bool result = ConsumedEntireMessage(); + // PopLimit(limit); + // return result; } + // Using this can reduce code size and complexity in some cases. + bool CheckEntireMessageConsumedAndPopLimit(Limit limit); + // Extension Registry ---------------------------------------------- // ADVANCED USAGE: 99.9% of people can ignore this section. // @@ -568,9 +588,13 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // optimization. The Slow method is yet another fallback when the buffer is // not large enough. Making the slow path out-of-line speeds up the common // case by 10-15%. The slow path is fairly uncommon: it only triggers when a - // message crosses multiple buffers. - bool ReadVarint32Fallback(uint32* value); - bool ReadVarint64Fallback(uint64* value); + // message crosses multiple buffers. Note: ReadVarint32Fallback() and + // ReadVarint64Fallback() are called frequently and generally not inlined, so + // they have been optimized to avoid "out" parameters. The former returns -1 + // if it fails and the uint32 it read otherwise. The latter has a bool + // indicating success or failure as part of its return type. + int64 ReadVarint32Fallback(uint32 first_byte_or_zero); + std::pair ReadVarint64Fallback(); bool ReadVarint32Slow(uint32* value); bool ReadVarint64Slow(uint64* value); bool ReadLittleEndian32Fallback(uint32* value); @@ -578,7 +602,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Fallback/slow methods for reading tags. These do not update last_tag_, // but will set legitimate_message_end_ if we are at the end of the input // stream. - uint32 ReadTagFallback(); + uint32 ReadTagFallback(uint32 first_byte_or_zero); uint32 ReadTagSlow(); bool ReadStringFallback(string* buffer, int size); @@ -818,13 +842,18 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // methods optimize for that case. inline bool CodedInputStream::ReadVarint32(uint32* value) { - if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { - *value = *buffer_; - Advance(1); - return true; - } else { - return ReadVarint32Fallback(value); + uint32 v = 0; + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) { + v = *buffer_; + if (v < 0x80) { + *value = v; + Advance(1); + return true; + } } + int64 result = ReadVarint32Fallback(v); + *value = static_cast(result); + return result >= 0; } inline bool CodedInputStream::ReadVarint64(uint64* value) { @@ -832,9 +861,10 @@ inline bool CodedInputStream::ReadVarint64(uint64* value) { *value = *buffer_; Advance(1); return true; - } else { - return ReadVarint64Fallback(value); } + std::pair p = ReadVarint64Fallback(); + *value = p.first; + return p.second; } // static @@ -903,14 +933,17 @@ inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { } inline uint32 CodedInputStream::ReadTag() { - if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { - last_tag_ = buffer_[0]; - Advance(1); - return last_tag_; - } else { - last_tag_ = ReadTagFallback(); - return last_tag_; + uint32 v = 0; + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) { + v = *buffer_; + if (v < 0x80) { + last_tag_ = v; + Advance(1); + return v; + } } + last_tag_ = ReadTagFallback(v); + return last_tag_; } inline std::pair CodedInputStream::ReadTagWithCutoff( @@ -918,10 +951,12 @@ inline std::pair CodedInputStream::ReadTagWithCutoff( // In performance-sensitive code we can expect cutoff to be a compile-time // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at // compile time. + uint32 first_byte_or_zero = 0; if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) { // Hot case: buffer_ non_empty, buffer_[0] in [1, 128). // TODO(gpike): Is it worth rearranging this? E.g., if the number of fields // is large enough then is it better to check for the two-byte case first? + first_byte_or_zero = buffer_[0]; if (static_cast(buffer_[0]) > 0) { const uint32 kMax1ByteVarint = 0x7f; uint32 tag = last_tag_ = buffer_[0]; @@ -948,7 +983,7 @@ inline std::pair CodedInputStream::ReadTagWithCutoff( } } // Slow path - last_tag_ = ReadTagFallback(); + last_tag_ = ReadTagFallback(first_byte_or_zero); return std::make_pair(last_tag_, static_cast(last_tag_ - 1) < cutoff); } @@ -1177,6 +1212,11 @@ inline void CodedInputStream::DecrementRecursionDepth() { if (recursion_budget_ < recursion_limit_) ++recursion_budget_; } +inline void CodedInputStream::UnsafeDecrementRecursionDepth() { + assert(recursion_budget_ < recursion_limit_); + ++recursion_budget_; +} + inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool, MessageFactory* factory) { extension_pool_ = pool; diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h index cd8d174665..fa20f20886 100644 --- a/src/google/protobuf/io/coded_stream_inl.h +++ b/src/google/protobuf/io/coded_stream_inl.h @@ -66,6 +66,23 @@ inline bool CodedInputStream::InternalReadStringInline(string* buffer, return ReadStringFallback(buffer, size); } +inline bool CodedInputStream::InternalReadRawInline(void* buffer, int size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { + // Reading past end of buffer. Copy what we have, then refresh. + memcpy(buffer, buffer_, current_buffer_size); + buffer = reinterpret_cast(buffer) + current_buffer_size; + size -= current_buffer_size; + Advance(current_buffer_size); + if (!Refresh()) return false; + } + + memcpy(buffer, buffer_, size); + Advance(size); + + return true; +} + } // namespace io } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index e621ba1d9f..3ae8c26831 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -155,6 +155,78 @@ void Printer::Print(const char* text, Print(vars, text); } +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + vars[variable4] = value4; + vars[variable5] = value5; + Print(vars, text); +} + +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + vars[variable4] = value4; + vars[variable5] = value5; + vars[variable6] = value6; + Print(vars, text); +} + +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6, + const char* variable7, const string& value7) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + vars[variable4] = value4; + vars[variable5] = value5; + vars[variable6] = value6; + vars[variable7] = value7; + Print(vars, text); +} + +void Printer::Print(const char* text, + const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6, + const char* variable7, const string& value7, + const char* variable8, const string& value8) { + map vars; + vars[variable1] = value1; + vars[variable2] = value2; + vars[variable3] = value3; + vars[variable4] = value4; + vars[variable5] = value5; + vars[variable6] = value6; + vars[variable7] = value7; + vars[variable8] = value8; + Print(vars, text); +} + void Printer::Indent() { indent_ += " "; } diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index 92ce34098e..f1490bbe5b 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -91,8 +91,36 @@ class LIBPROTOBUF_EXPORT Printer { const char* variable2, const string& value2, const char* variable3, const string& value3, const char* variable4, const string& value4); - // TODO(kenton): Overloaded versions with more variables? Three seems - // to be enough. + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6, + const char* variable7, const string& value7); + // Like the first Print(), except the substitutions are given as parameters. + void Print(const char* text, const char* variable1, const string& value1, + const char* variable2, const string& value2, + const char* variable3, const string& value3, + const char* variable4, const string& value4, + const char* variable5, const string& value5, + const char* variable6, const string& value6, + const char* variable7, const string& value7, + const char* variable8, const string& value8); // Indent text by two spaces. After calling Indent(), two spaces will be // inserted at the beginning of each line of text. Indent() may be called diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index 4ea2100729..1995cf0814 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -34,12 +34,16 @@ #include #include +#include +#include +#include #include #include #include #include #include #include +#include using namespace std; @@ -84,6 +88,12 @@ void SetSomeTypesInEmptyMessageUnknownFields( } // namespace +#define EXPECT_TRUE GOOGLE_CHECK +#define ASSERT_TRUE GOOGLE_CHECK +#define EXPECT_FALSE(COND) GOOGLE_CHECK(!(COND)) +#define EXPECT_EQ GOOGLE_CHECK_EQ +#define ASSERT_EQ GOOGLE_CHECK_EQ + int main(int argc, char* argv[]) { string data, data2, packed_data; @@ -345,6 +355,374 @@ int main(int argc, char* argv[]) { GOOGLE_CHECK_EQ(0, empty_message.unknown_fields().size()); } + // Tests for map lite ============================================= + + { + // Accessors + protobuf_unittest::TestMapLite message; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message); + + google::protobuf::MapLiteTestUtil::ModifyMapFields(&message); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message); + } + + { + // SetMapFieldsInitialized + protobuf_unittest::TestMapLite message; + + google::protobuf::MapLiteTestUtil::SetMapFieldsInitialized(&message); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSetInitialized(message); + } + + { + // Proto2SetMapFieldsInitialized + protobuf_unittest::TestEnumStartWithNonZeroMapLite message; + EXPECT_EQ(protobuf_unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE, + (*message.mutable_map_field())[0]); + } + + { + // Clear + protobuf_unittest::TestMapLite message; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message); + message.Clear(); + google::protobuf::MapLiteTestUtil::ExpectClear(message); + } + + { + // ClearMessageMap + protobuf_unittest::TestMessageMapLite message; + + // Creates a TestAllTypes with default value + google::protobuf::TestUtilLite::ExpectClear( + (*message.mutable_map_int32_message())[0]); + } + + { + // CopyFrom + protobuf_unittest::TestMapLite message1, message2; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + message2.CopyFrom(message1); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + + // Copying from self should be a no-op. + message2.CopyFrom(message2); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + { + // CopyFromMessageMap + protobuf_unittest::TestMessageMapLite message1, message2; + + (*message1.mutable_map_int32_message())[0].add_repeated_int32(100); + (*message2.mutable_map_int32_message())[0].add_repeated_int32(101); + + message1.CopyFrom(message2); + + // Checks repeated field is overwritten. + EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size()); + EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0)); + } + + { + // SwapWithEmpty + protobuf_unittest::TestMapLite message1, message2; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1); + google::protobuf::MapLiteTestUtil::ExpectClear(message2); + + message1.Swap(&message2); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + google::protobuf::MapLiteTestUtil::ExpectClear(message1); + } + + { + // SwapWithSelf + protobuf_unittest::TestMapLite message; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message); + + message.Swap(&message); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message); + } + + { + // SwapWithOther + protobuf_unittest::TestMapLite message1, message2; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + google::protobuf::MapLiteTestUtil::SetMapFields(&message2); + google::protobuf::MapLiteTestUtil::ModifyMapFields(&message2); + + message1.Swap(&message2); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsModified(message1); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + { + // CopyConstructor + protobuf_unittest::TestMapLite message1; + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + + protobuf_unittest::TestMapLite message2(message1); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + { + // CopyAssignmentOperator + protobuf_unittest::TestMapLite message1; + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + + protobuf_unittest::TestMapLite message2; + message2 = message1; + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + + // Make sure that self-assignment does something sane. + message2.operator=(message2); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + { + // NonEmptyMergeFrom + protobuf_unittest::TestMapLite message1, message2; + + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + + // This field will test merging into an empty spot. + (*message2.mutable_map_int32_int32())[1] = 1; + message1.mutable_map_int32_int32()->erase(1); + + // This tests overwriting. + (*message2.mutable_map_int32_double())[1] = 1; + (*message1.mutable_map_int32_double())[1] = 2; + + message1.MergeFrom(message2); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message1); + } + + { + // MergeFromMessageMap + protobuf_unittest::TestMessageMapLite message1, message2; + + (*message1.mutable_map_int32_message())[0].add_repeated_int32(100); + (*message2.mutable_map_int32_message())[0].add_repeated_int32(101); + + message1.MergeFrom(message2); + + // Checks repeated field is overwritten. + EXPECT_EQ(1, message1.map_int32_message().at(0).repeated_int32_size()); + EXPECT_EQ(101, message1.map_int32_message().at(0).repeated_int32(0)); + } + + { + // Test the generated SerializeWithCachedSizesToArray() + protobuf_unittest::TestMapLite message1, message2; + string data; + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + int size = message1.ByteSize(); + data.resize(size); + ::google::protobuf::uint8* start = reinterpret_cast< ::google::protobuf::uint8*>(::google::protobuf::string_as_array(&data)); + ::google::protobuf::uint8* end = message1.SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); + EXPECT_TRUE(message2.ParseFromString(data)); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + { + // Test the generated SerializeWithCachedSizes() + protobuf_unittest::TestMapLite message1, message2; + google::protobuf::MapLiteTestUtil::SetMapFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + google::protobuf::io::ArrayOutputStream array_stream( + ::google::protobuf::string_as_array(&data), size, 1); + google::protobuf::io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + google::protobuf::MapLiteTestUtil::ExpectMapFieldsSet(message2); + } + + + { + // Proto2UnknownEnum + protobuf_unittest::TestEnumMapPlusExtraLite from; + (*from.mutable_known_map_field())[0] = + protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE; + (*from.mutable_unknown_map_field())[0] = + protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE; + string data; + from.SerializeToString(&data); + + protobuf_unittest::TestEnumMapLite to; + EXPECT_TRUE(to.ParseFromString(data)); + EXPECT_EQ(0, to.unknown_map_field().size()); + EXPECT_FALSE(to.mutable_unknown_fields()->empty()); + EXPECT_EQ(1, to.known_map_field().size()); + EXPECT_EQ(protobuf_unittest::PROTO2_MAP_ENUM_FOO_LITE, + to.known_map_field().at(0)); + + data.clear(); + from.Clear(); + to.SerializeToString(&data); + EXPECT_TRUE(from.ParseFromString(data)); + EXPECT_EQ(1, from.known_map_field().size()); + EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_FOO_LITE, + from.known_map_field().at(0)); + EXPECT_EQ(1, from.unknown_map_field().size()); + EXPECT_EQ(protobuf_unittest::E_PROTO2_MAP_ENUM_EXTRA_LITE, + from.unknown_map_field().at(0)); + } + + { + // StandardWireFormat + protobuf_unittest::TestMapLite message; + string data = "\x0A\x04\x08\x01\x10\x01"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(1, message.map_int32_int32().at(1)); + } + + { + // UnorderedWireFormat + protobuf_unittest::TestMapLite message; + + // put value before key in wire format + string data = "\x0A\x04\x10\x01\x08\x02"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(1, message.map_int32_int32().at(2)); + } + + { + // DuplicatedKeyWireFormat + protobuf_unittest::TestMapLite message; + + // Two key fields in wire format + string data = "\x0A\x06\x08\x01\x08\x02\x10\x01"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(1, message.map_int32_int32().at(2)); + } + + { + // DuplicatedValueWireFormat + protobuf_unittest::TestMapLite message; + + // Two value fields in wire format + string data = "\x0A\x06\x08\x01\x10\x01\x10\x02"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(2, message.map_int32_int32().at(1)); + } + + { + // MissedKeyWireFormat + protobuf_unittest::TestMapLite message; + + // No key field in wire format + string data = "\x0A\x02\x10\x01"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(1, message.map_int32_int32().at(0)); + } + + { + // MissedValueWireFormat + protobuf_unittest::TestMapLite message; + + // No value field in wire format + string data = "\x0A\x02\x08\x01"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(0, message.map_int32_int32().at(1)); + } + + { + // UnknownFieldWireFormat + protobuf_unittest::TestMapLite message; + + // Unknown field in wire format + string data = "\x0A\x06\x08\x02\x10\x03\x18\x01"; + + EXPECT_TRUE(message.ParseFromString(data)); + EXPECT_EQ(1, message.map_int32_int32().size()); + EXPECT_EQ(3, message.map_int32_int32().at(2)); + } + + { + // CorruptedWireFormat + protobuf_unittest::TestMapLite message; + + // corrupted data in wire format + string data = "\x0A\x06\x08\x02\x11\x03"; + + EXPECT_FALSE(message.ParseFromString(data)); + } + + { + // IsInitialized + protobuf_unittest::TestRequiredMessageMapLite map_message; + + // Add an uninitialized message. + (*map_message.mutable_map_field())[0]; + EXPECT_FALSE(map_message.IsInitialized()); + + // Initialize uninitialized message + (*map_message.mutable_map_field())[0].set_a(0); + (*map_message.mutable_map_field())[0].set_b(0); + (*map_message.mutable_map_field())[0].set_c(0); + EXPECT_TRUE(map_message.IsInitialized()); + } + + // arena support for map ========================================= + + { + // ParsingAndSerializingNoHeapAllocation + + // Allocate a large initial block to avoid mallocs during hooked test. + std::vector arena_block(128 * 1024); + google::protobuf::ArenaOptions options; + options.initial_block = arena_block.data(); + options.initial_block_size = arena_block.size(); + google::protobuf::Arena arena(options); + string data; + data.reserve(128 * 1024); + + { + google::protobuf::internal::NoHeapChecker no_heap; + + protobuf_unittest::TestArenaMapLite* from = + google::protobuf::Arena::CreateMessage( + &arena); + google::protobuf::MapLiteTestUtil::SetArenaMapFields(from); + from->SerializeToString(&data); + + protobuf_unittest::TestArenaMapLite* to = + google::protobuf::Arena::CreateMessage( + &arena); + to->ParseFromString(data); + google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to); + } + } + std::cout << "PASS" << std::endl; return 0; } diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index e56af3fcbf..1858e2f9f5 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -422,6 +422,7 @@ class Map { int default_enum_value_; friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; template >( - arena, key, value, arena); + arena, key, value); } // Like above, but for all the other types. This avoids value copy to create // MapEntryLite from google::protobuf::Map in serialization. static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) { - return Arena::Create >( - arena, key, value, arena); + return Arena::CreateMessage >( + arena, key, value); } protected: @@ -308,7 +309,7 @@ class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite { typedef typename Base::ValCppType ValCppType; public: - MapEntryWrapper(const K& key, const V& value, Arena* arena) + MapEntryWrapper(Arena* arena, const K& key, const V& value) : MapEntryLite(arena), key_(key), value_(value) { @@ -323,6 +324,7 @@ class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite { const Value& value_; friend class ::google::protobuf::Arena; + typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; }; @@ -341,7 +343,7 @@ class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite { typedef typename Base::ValCppType ValCppType; public: - MapEnumEntryWrapper(const K& key, const V& value, Arena* arena) + MapEnumEntryWrapper(Arena* arena, const K& key, const V& value) : MapEntryLite(arena), key_(key), value_(value) { @@ -355,7 +357,7 @@ class LIBPROTOBUF_EXPORT MapEntryLite : public MessageLite { const KeyCppType& key_; const ValCppType value_; - friend class ::google::protobuf::Arena; + friend class LIBPROTOBUF_EXPORT google::protobuf::Arena; typedef void DestructorSkippable_; }; diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index fd40c0d8f6..6ff1936eb4 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -104,14 +104,18 @@ void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; } void* MapFieldBase::MutableRepeatedPtrField() const { return repeated_field_; } void MapFieldBase::SyncRepeatedFieldWithMap() const { - Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_); + // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get + // executed before state_ is checked. + Atomic32 state = google::protobuf::internal::Acquire_Load(&state_); if (state == STATE_MODIFIED_MAP) { mutex_.Lock(); // Double check state, because another thread may have seen the same state // and done the synchronization before the current thread. if (state_ == STATE_MODIFIED_MAP) { SyncRepeatedFieldWithMapNoLock(); - google::protobuf::internal::NoBarrier_Store(&state_, CLEAN); + // "Release" insures state_ can only be changed "after" + // SyncRepeatedFieldWithMapNoLock is finished. + google::protobuf::internal::Release_Store(&state_, CLEAN); } mutex_.Unlock(); } @@ -119,19 +123,23 @@ void MapFieldBase::SyncRepeatedFieldWithMap() const { void MapFieldBase::SyncRepeatedFieldWithMapNoLock() const { if (repeated_field_ == NULL) { - repeated_field_ = Arena::Create >(arena_, arena_); + repeated_field_ = Arena::CreateMessage >(arena_); } } void MapFieldBase::SyncMapWithRepeatedField() const { - Atomic32 state = google::protobuf::internal::NoBarrier_Load(&state_); + // "Acquire" insures the operation after SyncMapWithRepeatedField won't get + // executed before state_ is checked. + Atomic32 state = google::protobuf::internal::Acquire_Load(&state_); if (state == STATE_MODIFIED_REPEATED) { mutex_.Lock(); // Double check state, because another thread may have seen the same state // and done the synchronization before the current thread. if (state_ == STATE_MODIFIED_REPEATED) { SyncMapWithRepeatedFieldNoLock(); - google::protobuf::internal::NoBarrier_Store(&state_, CLEAN); + // "Release" insures state_ can only be changed "after" + // SyncRepeatedFieldWithMapNoLock is finished. + google::protobuf::internal::Release_Store(&state_, CLEAN); } mutex_.Unlock(); } diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 6d8b6ec85b..f3504f1b6c 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -208,6 +208,7 @@ class LIBPROTOBUF_EXPORT MapField : public MapFieldBase, void SetAssignDescriptorCallback(void (*callback)()); private: + typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; // MapField needs MapEntry's default instance to create new MapEntry. diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index ae63c7215e..cbfc0c8ffc 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -216,7 +216,7 @@ MapField(); } else { repeated_field_ = - Arena::Create >(arena_, arena_); + Arena::CreateMessage >(arena_); } } const Map& map = GetInternalMap(); diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h index 549ecc0802..4032285153 100644 --- a/src/google/protobuf/map_field_lite.h +++ b/src/google/protobuf/map_field_lite.h @@ -109,7 +109,7 @@ template ::MapFieldLite(Arena* arena) : arena_(arena) { - map_ = Arena::Create >(arena, arena); + map_ = Arena::CreateMessage >(arena); SetDefaultEnumValue(); } diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index 61344cbb82..f4681866c3 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc @@ -56,6 +56,7 @@ using unittest::TestAllTypes; class MapFieldBaseStub : public MapFieldBase { public: + typedef void InternalArenaConstructable_; typedef void DestructorSkippable_; MapFieldBaseStub() {} explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {} @@ -149,10 +150,12 @@ TEST_F(MapFieldBasePrimitiveTest, Arena) { Arena arena(options); { - NoHeapChecker no_heap; + // TODO(liujisi): Re-write the test to ensure the memory for the map and + // repeated fields are allocated from arenas. + // NoHeapChecker no_heap; MapFieldType* map_field = - Arena::Create(&arena, &arena, default_entry_); + Arena::CreateMessage(&arena, default_entry_); // Set content in map (*map_field->MutableMap())[100] = 101; @@ -162,10 +165,12 @@ TEST_F(MapFieldBasePrimitiveTest, Arena) { } { - NoHeapChecker no_heap; + // TODO(liujisi): Re-write the test to ensure the memory for the map and + // repeated fields are allocated from arenas. + // NoHeapChecker no_heap; MapFieldBaseStub* map_field = - Arena::Create(&arena, &arena); + Arena::CreateMessage(&arena); // Trigger conversion to repeated field. EXPECT_TRUE(map_field->MutableRepeatedField() != NULL); diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 88cba1f26c..447f52d9e7 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -2258,6 +2258,27 @@ TEST(TextFormatMapTest, SerializeAndParse) { MapTestUtil::ExpectMapFieldsSet(dest); } +TEST(TextFormatMapTest, Sorted) { + unittest::TestMap message; + MapTestUtil::MapReflectionTester tester(message.GetDescriptor()); + tester.SetMapFieldsViaReflection(&message); + + string expected_text; + GOOGLE_CHECK_OK(File::GetContents( + TestSourceDir() + + "/google/protobuf/" + "testdata/map_test_data.txt", + &expected_text, true)); + + EXPECT_EQ(message.DebugString(), expected_text); + + // Test again on the reverse order. + unittest::TestMap message2; + tester.SetMapFieldsViaReflection(&message2); + tester.SwapMapsViaReflection(&message2); + EXPECT_EQ(message2.DebugString(), expected_text); +} + // arena support ================================================= TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) { diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h index 278b78ae24..ffdb6dfbac 100644 --- a/src/google/protobuf/map_type_handler.h +++ b/src/google/protobuf/map_type_handler.h @@ -129,11 +129,11 @@ class MapCppTypeHandler : public MapCommonTypeHandler { // Return bytes used by value in Map. static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); } static inline void Clear(Type** value) { - if (*value != NULL) (*value)->Type::Clear(); + if (*value != NULL) (*value)->Clear(); } static inline void ClearMaybeByDefaultEnum(Type** value, int default_enum_value) { - if (*value != NULL) (*value)->Type::Clear(); + if (*value != NULL) (*value)->Clear(); } static inline void Merge(const Type& from, Type** to) { (*to)->MergeFrom(from); diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index b6a988b316..cbf747d95b 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -62,7 +62,7 @@ message TestMap { } message TestMapSubmessage { - optional TestMap test_map = 1; + TestMap test_map = 1; } message TestMessageMap { @@ -104,3 +104,17 @@ message TestArenaMap { map map_int32_enum = 14; map map_int32_foreign_message = 15; } + +// Previously, message containing enum called Type cannot be used as value of +// map field. +message MessageContainingEnumCalledType { + enum Type { + TYPE_FOO = 0; + } + map type = 1; +} + +// Previously, message cannot contain map field called "entry". +message MessageContainingMapCalledEntry { + map entry = 1; +} diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index f58be848aa..276d7de579 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -465,10 +465,21 @@ struct ShutdownRepeatedFieldRegister { } // namespace internal namespace internal { -// Macro defined in repeated_field.h. We can only define the Message-specific -// GenericTypeHandler specializations here because we depend on Message, which -// is not part of proto2-lite hence is not available in repeated_field.h. -DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(Message); +template<> +Message* GenericTypeHandler::NewFromPrototype( + const Message* prototype, google::protobuf::Arena* arena) { + return prototype->New(arena); +} +template<> +google::protobuf::Arena* GenericTypeHandler::GetArena( + Message* value) { + return value->GetArena(); +} +template<> +void* GenericTypeHandler::GetMaybeArenaPointer( + Message* value) { + return value->GetMaybeArenaPointer(); +} } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 6e1929e5c3..18c092d051 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -98,11 +98,11 @@ // // // Use the reflection interface to examine the contents. // const Reflection* reflection = foo->GetReflection(); -// assert(reflection->GetString(foo, text_field) == "Hello World!"); -// assert(reflection->FieldSize(foo, numbers_field) == 3); -// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1); -// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5); -// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42); +// assert(reflection->GetString(*foo, text_field) == "Hello World!"); +// assert(reflection->FieldSize(*foo, numbers_field) == 3); +// assert(reflection->GetRepeatedInt32(*foo, numbers_field, 0) == 1); +// assert(reflection->GetRepeatedInt32(*foo, numbers_field, 1) == 5); +// assert(reflection->GetRepeatedInt32(*foo, numbers_field, 2) == 42); // // delete foo; // } @@ -229,6 +229,11 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // Computes (an estimate of) the total number of bytes currently used for // storing the message in memory. The default implementation calls the // Reflection object's SpaceUsed() method. + // + // SpaceUsed() is noticeably slower than ByteSize(), as it is implemented + // using reflection (rather than the generated code implementation for + // ByteSize()). Like ByteSize(), its CPU time is linear in the number of + // fields defined for the proto. virtual int SpaceUsed() const; // Debugging & Testing---------------------------------------------- diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 63be0e9b2f..4f63ad2bf9 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -337,7 +337,7 @@ bool MessageLite::SerializePartialToArray(void* data, int size) const { string MessageLite::SerializeAsString() const { // If the compiler implements the (Named) Return Value Optimization, - // the local variable 'result' will not actually reside on the stack + // the local variable 'output' will not actually reside on the stack // of this function, but will be overlaid with the object that the // caller supplied for the return value to be constructed in. string output; diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index eab61c14a3..4c16f4c057 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -238,6 +238,9 @@ class LIBPROTOBUF_EXPORT MessageLite { // Computes the serialized size of the message. This recursively calls // ByteSize() on all embedded messages. If a subclass does not override // this, it MUST override SetCachedSize(). + // + // ByteSize() is generally linear in the number of fields defined for the + // proto. virtual int ByteSize() const = 0; // Serializes the message without recomputing the size. The message must diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index ebfb432139..75d60b8b4a 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -45,12 +45,13 @@ #include #include -#include +#include +#include #include -#include +#include #include -#include -#include +#include +#include #include #include @@ -205,6 +206,28 @@ TEST(MessageTest, InitializationErrorString) { EXPECT_EQ("a, b, c", message.InitializationErrorString()); } +TEST(MessageTest, DynamicCastToGenerated) { + unittest::TestAllTypes test_all_types; + + google::protobuf::Message* test_all_types_pointer = &test_all_types; + EXPECT_EQ(&test_all_types, + google::protobuf::internal::DynamicCastToGenerated( + test_all_types_pointer)); + EXPECT_EQ(NULL, + google::protobuf::internal::DynamicCastToGenerated( + test_all_types_pointer)); + + const google::protobuf::Message* test_all_types_pointer_const = &test_all_types; + EXPECT_EQ( + &test_all_types, + google::protobuf::internal::DynamicCastToGenerated( + test_all_types_pointer_const)); + EXPECT_EQ( + NULL, + google::protobuf::internal::DynamicCastToGenerated( + test_all_types_pointer_const)); +} + #ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet. TEST(MessageTest, SerializeFailsIfNotInitialized) { diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc index c3b5996f74..da4be67368 100644 --- a/src/google/protobuf/proto3_arena_unittest.cc +++ b/src/google/protobuf/proto3_arena_unittest.cc @@ -180,6 +180,16 @@ TEST(ArenaTest, ReleaseMessage) { EXPECT_EQ(118, nested->bb()); } +TEST(ArenaTest, MessageFieldClear) { + // GitHub issue #310: https://github.com/google/protobuf/issues/310 + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(118); + // This should not crash, but prior to the bugfix, it tried to use `operator + // delete` the nested message (which is on the arena): + arena_message->Clear(); +} + } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h index 03c761c1f7..4ff0f6b40e 100755 --- a/src/google/protobuf/reflection.h +++ b/src/google/protobuf/reflection.h @@ -39,6 +39,7 @@ #endif #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 7bfdc40a5e..5a2fb409df 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -576,26 +576,21 @@ class GenericTypeHandler { } }; -// Macros for specializing GenericTypeHandler for base proto types, these are -// are defined here, to allow inlining them at their callsites. -#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(Inline, TypeName) \ - template<> \ - Inline TypeName* GenericTypeHandler::NewFromPrototype( \ - const TypeName* prototype, google::protobuf::Arena* arena) { \ - return prototype->New(arena); \ - } \ - template<> \ - Inline google::protobuf::Arena* GenericTypeHandler::GetArena( \ - TypeName* value) { \ - return value->GetArena(); \ - } \ - template<> \ - Inline void* GenericTypeHandler::GetMaybeArenaPointer( \ - TypeName* value) { \ - return value->GetMaybeArenaPointer(); \ - } -#define DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES_NOINLINE(TypeName) \ - DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(, TypeName) +template<> +inline MessageLite* GenericTypeHandler::NewFromPrototype( + const MessageLite* prototype, google::protobuf::Arena* arena) { + return prototype->New(arena); +} +template<> +inline google::protobuf::Arena* GenericTypeHandler::GetArena( + MessageLite* value) { + return value->GetArena(); +} +template<> +inline void* GenericTypeHandler::GetMaybeArenaPointer( + MessageLite* value) { + return value->GetMaybeArenaPointer(); +} // Implements GenericTypeHandler specialization required by RepeatedPtrFields // to work with MessageLite type. @@ -605,8 +600,6 @@ inline void GenericTypeHandler::Merge( to->CheckTypeAndMergeFrom(from); } -DEFINE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(inline, MessageLite); - // Declarations of the specialization as we cannot define them here, as the // header that defines ProtocolMessage depends on types defined in this header. #define DECLARE_SPECIALIZATIONS_FOR_BASE_PROTO_TYPES(TypeName) \ @@ -1235,6 +1228,7 @@ void RepeatedField::Reserve(int new_size) { kRepHeaderSize + sizeof(Element)*new_size)); } rep_->arena = arena; + int old_total_size = total_size_; total_size_ = new_size; // Invoke placement-new on newly allocated elements. We shouldn't have to do // this, since Element is supposed to be POD, but a previous version of this @@ -1253,15 +1247,17 @@ void RepeatedField::Reserve(int new_size) { if (current_size_ > 0) { MoveArray(rep_->elements, old_rep->elements, current_size_); } - // Likewise, we need to invoke destructors on the old array. If Element has no - // destructor, this loop will disappear. - e = &old_rep->elements[0]; - limit = &old_rep->elements[current_size_]; - for (; e < limit; e++) { - e->Element::~Element(); - } - if (arena == NULL) { - delete[] reinterpret_cast(old_rep); + if (old_rep) { + // Likewise, we need to invoke destructors on the old array. If Element has + // no destructor, this loop will disappear. + e = &old_rep->elements[0]; + limit = &old_rep->elements[old_total_size]; + for (; e < limit; e++) { + e->Element::~Element(); + } + if (arena == NULL) { + delete[] reinterpret_cast(old_rep); + } } } @@ -1418,7 +1414,7 @@ void RepeatedPtrFieldBase::Clear() { const int n = current_size_; GOOGLE_DCHECK_GE(n, 0); if (n > 0) { - void* const* elements = raw_data(); + void* const* elements = rep_->elements; int i = 0; do { TypeHandler::Clear(cast(elements[i++])); diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 66e74523c2..af39793223 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -456,6 +456,28 @@ TEST(RepeatedField, ExtractSubrange) { } } +TEST(RepeatedField, ClearThenReserveMore) { + // Test that Reserve properly destroys the old internal array when it's forced + // to allocate a new one, even when cleared-but-not-deleted objects are + // present. Use a 'string' and > 16 bytes length so that the elements are + // non-POD and allocate -- the leak checker will catch any skipped destructor + // calls here. + RepeatedField field; + for (int i = 0; i < 32; i++) { + field.Add(string("abcdefghijklmnopqrstuvwxyz0123456789")); + } + EXPECT_EQ(32, field.size()); + field.Clear(); + EXPECT_EQ(0, field.size()); + EXPECT_EQ(32, field.Capacity()); + + field.Reserve(1024); + EXPECT_EQ(0, field.size()); + EXPECT_EQ(1024, field.Capacity()); + // Finish test -- |field| should destroy the cleared-but-not-yet-destroyed + // strings. +} + // =================================================================== // RepeatedPtrField tests. These pretty much just mirror the RepeatedField // tests above. diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index 0926e74718..3b3799a9d5 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -114,7 +114,7 @@ const int SourceContext::kFileNameFieldNumber; #endif // !_MSC_VER SourceContext::SourceContext() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.SourceContext) } @@ -277,9 +277,9 @@ int SourceContext::ByteSize() const { void SourceContext::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const SourceContext* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const SourceContext* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -334,7 +334,7 @@ void SourceContext::InternalSwap(SourceContext* other) { // SourceContext // optional string file_name = 1; - void SourceContext::clear_file_name() { +void SourceContext::clear_file_name() { file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& SourceContext::file_name() const { diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index 4405a5bf33..30113cdb29 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -217,7 +217,7 @@ const int Struct::kFieldsFieldNumber; #endif // !_MSC_VER Struct::Struct() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Struct) } @@ -295,7 +295,8 @@ bool Struct::MergePartialFromCodedStream( // map fields = 1; case 1: { if (tag == 10) { - parse_fields: + DO_(input->IncrementRecursionDepth()); + parse_loop_fields: ::google::protobuf::scoped_ptr entry(fields_.NewEntry()); DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( input, entry.get())); @@ -303,7 +304,8 @@ bool Struct::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(10)) goto parse_fields; + if (input->ExpectTag(10)) goto parse_loop_fields; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -336,7 +338,8 @@ void Struct::SerializeWithCachedSizes( { ::google::protobuf::scoped_ptr entry; for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator - it = fields().begin(); it != fields().end(); ++it) { + it = this->fields().begin(); + it != this->fields().end(); ++it) { entry.reset(fields_.NewEntryWrapper(it->first, it->second)); ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 1, *entry, output); @@ -353,7 +356,8 @@ void Struct::SerializeWithCachedSizes( { ::google::protobuf::scoped_ptr entry; for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator - it = fields().begin(); it != fields().end(); ++it) { + it = this->fields().begin(); + it != this->fields().end(); ++it) { entry.reset(fields_.NewEntryWrapper(it->first, it->second)); target = ::google::protobuf::internal::WireFormatLite:: WriteMessageNoVirtualToArray( @@ -373,7 +377,8 @@ int Struct::ByteSize() const { { ::google::protobuf::scoped_ptr entry; for (::google::protobuf::Map< ::std::string, ::google::protobuf::Value >::const_iterator - it = fields().begin(); it != fields().end(); ++it) { + it = this->fields().begin(); + it != this->fields().end(); ++it) { entry.reset(fields_.NewEntryWrapper(it->first, it->second)); total_size += ::google::protobuf::internal::WireFormatLite:: MessageSizeNoVirtual(*entry); @@ -388,9 +393,9 @@ int Struct::ByteSize() const { void Struct::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Struct* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Struct* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -442,10 +447,10 @@ void Struct::InternalSwap(Struct* other) { // Struct // map fields = 1; - int Struct::fields_size() const { +int Struct::fields_size() const { return fields_.size(); } - void Struct::clear_fields() { +void Struct::clear_fields() { fields_.Clear(); } const ::google::protobuf::Map< ::std::string, ::google::protobuf::Value >& @@ -473,7 +478,7 @@ const int Value::kListValueFieldNumber; #endif // !_MSC_VER Value::Value() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Value) } @@ -845,9 +850,9 @@ int Value::ByteSize() const { void Value::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Value* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Value* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -928,13 +933,13 @@ void Value::InternalSwap(Value* other) { // Value // optional .google.protobuf.NullValue null_value = 1; - bool Value::has_null_value() const { +bool Value::has_null_value() const { return kind_case() == kNullValue; } - void Value::set_has_null_value() { +void Value::set_has_null_value() { _oneof_case_[0] = kNullValue; } - void Value::clear_null_value() { +void Value::clear_null_value() { if (has_null_value()) { kind_.null_value_ = 0; clear_has_kind(); @@ -957,13 +962,13 @@ void Value::InternalSwap(Value* other) { } // optional double number_value = 2; - bool Value::has_number_value() const { +bool Value::has_number_value() const { return kind_case() == kNumberValue; } - void Value::set_has_number_value() { +void Value::set_has_number_value() { _oneof_case_[0] = kNumberValue; } - void Value::clear_number_value() { +void Value::clear_number_value() { if (has_number_value()) { kind_.number_value_ = 0; clear_has_kind(); @@ -986,13 +991,13 @@ void Value::InternalSwap(Value* other) { } // optional string string_value = 3; - bool Value::has_string_value() const { +bool Value::has_string_value() const { return kind_case() == kStringValue; } - void Value::set_has_string_value() { +void Value::set_has_string_value() { _oneof_case_[0] = kStringValue; } - void Value::clear_string_value() { +void Value::clear_string_value() { if (has_string_value()) { kind_.string_value_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); clear_has_kind(); @@ -1066,13 +1071,13 @@ void Value::InternalSwap(Value* other) { } // optional bool bool_value = 4; - bool Value::has_bool_value() const { +bool Value::has_bool_value() const { return kind_case() == kBoolValue; } - void Value::set_has_bool_value() { +void Value::set_has_bool_value() { _oneof_case_[0] = kBoolValue; } - void Value::clear_bool_value() { +void Value::clear_bool_value() { if (has_bool_value()) { kind_.bool_value_ = false; clear_has_kind(); @@ -1095,13 +1100,13 @@ void Value::InternalSwap(Value* other) { } // optional .google.protobuf.Struct struct_value = 5; - bool Value::has_struct_value() const { +bool Value::has_struct_value() const { return kind_case() == kStructValue; } - void Value::set_has_struct_value() { +void Value::set_has_struct_value() { _oneof_case_[0] = kStructValue; } - void Value::clear_struct_value() { +void Value::clear_struct_value() { if (has_struct_value()) { delete kind_.struct_value_; clear_has_kind(); @@ -1141,13 +1146,13 @@ void Value::InternalSwap(Value* other) { } // optional .google.protobuf.ListValue list_value = 6; - bool Value::has_list_value() const { +bool Value::has_list_value() const { return kind_case() == kListValue; } - void Value::set_has_list_value() { +void Value::set_has_list_value() { _oneof_case_[0] = kListValue; } - void Value::clear_list_value() { +void Value::clear_list_value() { if (has_list_value()) { delete kind_.list_value_; clear_has_kind(); @@ -1186,10 +1191,10 @@ void Value::InternalSwap(Value* other) { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Value.list_value) } - bool Value::has_kind() const { +bool Value::has_kind() const { return kind_case() != KIND_NOT_SET; } - void Value::clear_has_kind() { +void Value::clear_has_kind() { _oneof_case_[0] = KIND_NOT_SET; } Value::KindCase Value::kind_case() const { @@ -1204,7 +1209,7 @@ const int ListValue::kValuesFieldNumber; #endif // !_MSC_VER ListValue::ListValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.ListValue) } @@ -1278,13 +1283,15 @@ bool ListValue::MergePartialFromCodedStream( // repeated .google.protobuf.Value values = 1; case 1: { if (tag == 10) { - parse_values: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_values: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_values())); } else { goto handle_unusual; } - if (input->ExpectTag(10)) goto parse_values; + if (input->ExpectTag(10)) goto parse_loop_values; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -1355,9 +1362,9 @@ int ListValue::ByteSize() const { void ListValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const ListValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const ListValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1409,10 +1416,10 @@ void ListValue::InternalSwap(ListValue* other) { // ListValue // repeated .google.protobuf.Value values = 1; - int ListValue::values_size() const { +int ListValue::values_size() const { return values_.size(); } - void ListValue::clear_values() { +void ListValue::clear_values() { values_.Clear(); } const ::google::protobuf::Value& ListValue::values(int index) const { diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 4648214264..2889c8fe1a 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -735,6 +735,10 @@ ListValue::mutable_values() { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 37123c7b17..3acaeba112 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -1141,6 +1141,14 @@ class LIBPROTOBUF_EXPORT Mutex { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Mutex); }; +// Undefine the macros to workaround the conflicts with Google internal +// MutexLock implementation. +// TODO(liujisi): Remove the undef once internal macros are removed. +#undef MutexLock +#undef ReaderMutexLock +#undef WriterMutexLock +#undef MutexLockMaybe + // MutexLock(mu) acquires mu when constructed and releases it when destroyed. class LIBPROTOBUF_EXPORT MutexLock { public: diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index 7955d26113..7ecc17ee69 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -1285,24 +1285,6 @@ char* FloatToBuffer(float value, char* buffer) { return buffer; } -string ToHex(uint64 num) { - if (num == 0) { - return string("0"); - } - - // Compute hex bytes in reverse order, writing to the back of the - // buffer. - char buf[16]; // No more than 16 hex digits needed. - char* bufptr = buf + 16; - static const char kHexChars[] = "0123456789abcdef"; - while (num != 0) { - *--bufptr = kHexChars[num & 0xf]; - num >>= 4; - } - - return string(bufptr, buf + 16 - bufptr); -} - namespace strings { AlphaNum::AlphaNum(strings::Hex hex) { diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 920701ebfc..5faa81e062 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -682,12 +682,6 @@ string Join(const Range& components, return result; } -// ---------------------------------------------------------------------- -// ToHex() -// Return a lower-case hex string representation of the given integer. -// ---------------------------------------------------------------------- -LIBPROTOBUF_EXPORT string ToHex(uint64 num); - // ---------------------------------------------------------------------- // GlobalReplaceSubstring() // Replaces all instances of a substring in a string. Does nothing diff --git a/src/google/protobuf/testdata/golden_message_proto3 b/src/google/protobuf/testdata/golden_message_proto3 index 934f36face..bd646a0dc8 100644 Binary files a/src/google/protobuf/testdata/golden_message_proto3 and b/src/google/protobuf/testdata/golden_message_proto3 differ diff --git a/src/google/protobuf/testdata/map_test_data.txt b/src/google/protobuf/testdata/map_test_data.txt new file mode 100644 index 0000000000..bc2723214a --- /dev/null +++ b/src/google/protobuf/testdata/map_test_data.txt @@ -0,0 +1,140 @@ +map_int32_int32 { + key: 0 + value: 0 +} +map_int32_int32 { + key: 1 + value: 1 +} +map_int64_int64 { + key: 0 + value: 0 +} +map_int64_int64 { + key: 1 + value: 1 +} +map_uint32_uint32 { + key: 0 + value: 0 +} +map_uint32_uint32 { + key: 1 + value: 1 +} +map_uint64_uint64 { + key: 0 + value: 0 +} +map_uint64_uint64 { + key: 1 + value: 1 +} +map_sint32_sint32 { + key: 0 + value: 0 +} +map_sint32_sint32 { + key: 1 + value: 1 +} +map_sint64_sint64 { + key: 0 + value: 0 +} +map_sint64_sint64 { + key: 1 + value: 1 +} +map_fixed32_fixed32 { + key: 0 + value: 0 +} +map_fixed32_fixed32 { + key: 1 + value: 1 +} +map_fixed64_fixed64 { + key: 0 + value: 0 +} +map_fixed64_fixed64 { + key: 1 + value: 1 +} +map_sfixed32_sfixed32 { + key: 0 + value: 0 +} +map_sfixed32_sfixed32 { + key: 1 + value: 1 +} +map_sfixed64_sfixed64 { + key: 0 + value: 0 +} +map_sfixed64_sfixed64 { + key: 1 + value: 1 +} +map_int32_float { + key: 0 + value: 0 +} +map_int32_float { + key: 1 + value: 1 +} +map_int32_double { + key: 0 + value: 0 +} +map_int32_double { + key: 1 + value: 1 +} +map_bool_bool { + key: false + value: false +} +map_bool_bool { + key: true + value: true +} +map_string_string { + key: "0" + value: "0" +} +map_string_string { + key: "1" + value: "1" +} +map_int32_bytes { + key: 0 + value: "0" +} +map_int32_bytes { + key: 1 + value: "1" +} +map_int32_enum { + key: 0 + value: MAP_ENUM_BAR +} +map_int32_enum { + key: 1 + value: MAP_ENUM_BAZ +} +map_int32_foreign_message { + key: 0 + value { + c: 0 + } +} +map_int32_foreign_message { + key: 1 + value { + c: 1 + } +} diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index ec070c51f9..61dfa5d6db 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -43,6 +43,8 @@ #include #include +#include +#include #include #include #include @@ -50,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +73,18 @@ inline bool IsOctNumber(const string& str) { (str[1] >= '0' && str[1] < '8')); } +inline bool GetAnyFieldDescriptors(const Message& message, + const FieldDescriptor** type_url_field, + const FieldDescriptor** value_field) { + const Descriptor* descriptor = message.GetDescriptor(); + *type_url_field = descriptor->FindFieldByNumber(1); + *value_field = descriptor->FindFieldByNumber(2); + return (*type_url_field != NULL && + (*type_url_field)->type() == FieldDescriptor::TYPE_STRING && + *value_field != NULL && + (*value_field)->type() == FieldDescriptor::TYPE_BYTES); +} + } // namespace string Message::DebugString() const { @@ -330,7 +345,17 @@ class TextFormat::Parser::ParserImpl { // Confirm that we have a valid ending delimiter. DO(Consume(delimiter)); + return true; + } + // Consume either "<" or "{". + bool ConsumeMessageDelimiter(string* delimiter) { + if (TryConsume("<")) { + *delimiter = ">"; + } else { + DO(Consume("{")); + *delimiter = "}"; + } return true; } @@ -347,15 +372,28 @@ class TextFormat::Parser::ParserImpl { int start_line = tokenizer_.current().line; int start_column = tokenizer_.current().column; + const FieldDescriptor* any_type_url_field; + const FieldDescriptor* any_value_field; + if (internal::GetAnyFieldDescriptors(*message, &any_type_url_field, + &any_value_field) && + TryConsume("[")) { + string full_type_name; + DO(ConsumeAnyTypeUrl(&full_type_name)); + DO(Consume("]")); + string serialized_value; + DO(ConsumeAnyValue(full_type_name, + message->GetDescriptor()->file()->pool(), + &serialized_value)); + reflection->SetString( + message, any_type_url_field, + string(internal::kTypeGoogleApisComPrefix) + full_type_name); + reflection->SetString(message, any_value_field, serialized_value); + return true; + // Fall through. + } if (TryConsume("[")) { // Extension. - DO(ConsumeIdentifier(&field_name)); - while (TryConsume(".")) { - string part; - DO(ConsumeIdentifier(&part)); - field_name += "."; - field_name += part; - } + DO(ConsumeFullTypeName(&field_name)); DO(Consume("]")); field = (finder_ != NULL @@ -512,13 +550,7 @@ class TextFormat::Parser::ParserImpl { string field_name; if (TryConsume("[")) { // Extension name. - DO(ConsumeIdentifier(&field_name)); - while (TryConsume(".")) { - string part; - DO(ConsumeIdentifier(&part)); - field_name += "."; - field_name += part; - } + DO(ConsumeFullTypeName(&field_name)); DO(Consume("]")); } else { DO(ConsumeIdentifier(&field_name)); @@ -553,13 +585,7 @@ class TextFormat::Parser::ParserImpl { } string delimiter; - if (TryConsume("<")) { - delimiter = ">"; - } else { - DO(Consume("{")); - delimiter = "}"; - } - + DO(ConsumeMessageDelimiter(&delimiter)); if (field->is_repeated()) { DO(ConsumeMessage(reflection->AddMessage(message, field), delimiter)); } else { @@ -576,12 +602,7 @@ class TextFormat::Parser::ParserImpl { // the ending delimiter. bool SkipFieldMessage() { string delimiter; - if (TryConsume("<")) { - delimiter = ">"; - } else { - DO(Consume("{")); - delimiter = "}"; - } + DO(ConsumeMessageDelimiter(&delimiter)); while (!LookingAt(">") && !LookingAt("}")) { DO(SkipField()); } @@ -808,6 +829,18 @@ class TextFormat::Parser::ParserImpl { return false; } + // Consume a string of form ".....". + bool ConsumeFullTypeName(string* name) { + DO(ConsumeIdentifier(name)); + while (TryConsume(".")) { + string part; + DO(ConsumeIdentifier(&part)); + *name += "."; + *name += part; + } + return true; + } + // Consumes a string and saves its value in the text parameter. // Returns false if the token is not of type STRING. bool ConsumeString(string* text) { @@ -947,6 +980,54 @@ class TextFormat::Parser::ParserImpl { return true; } + // Consumes Any::type_url value, of form "type.googleapis.com/full.type.Name" + bool ConsumeAnyTypeUrl(string* full_type_name) { + // TODO(saito) Extend Consume() to consume multiple tokens at once, so that + // this code can be written as just DO(Consume(kGoogleApisTypePrefix)). + string url1, url2, url3; + DO(ConsumeIdentifier(&url1)); // type + DO(Consume(".")); + DO(ConsumeIdentifier(&url2)); // googleapis + DO(Consume(".")); + DO(ConsumeIdentifier(&url3)); // com + DO(Consume("/")); + DO(ConsumeFullTypeName(full_type_name)); + + const string prefix = url1 + "." + url2 + "." + url3 + "/"; + if (prefix != internal::kTypeGoogleApisComPrefix) { + ReportError("TextFormat::Parser for Any supports only " + "type.googleapi.com, but found \"" + prefix + "\""); + return false; + } + return true; + } + + // A helper function for reconstructing Any::value. Consumes a text of + // full_type_name, then serializes it into serialized_value. "pool" is used to + // look up and create a temporary object with full_type_name. + bool ConsumeAnyValue(const string& full_type_name, const DescriptorPool* pool, + string* serialized_value) { + const Descriptor* value_descriptor = + pool->FindMessageTypeByName(full_type_name); + if (value_descriptor == NULL) { + ReportError("Could not find type \"" + full_type_name + + "\" stored in google.protobuf.Any."); + return false; + } + DynamicMessageFactory factory; + const Message* value_prototype = factory.GetPrototype(value_descriptor); + if (value_prototype == NULL) { + return false; + } + google::protobuf::scoped_ptr value(value_prototype->New()); + string sub_delimiter; + DO(ConsumeMessageDelimiter(&sub_delimiter)); + DO(ConsumeMessage(value.get(), sub_delimiter)); + + value->AppendToString(serialized_value); + return true; + } + // Consumes a token and confirms that it matches that specified in the // value parameter. Returns false if the token found does not match that // which was specified. @@ -1338,7 +1419,8 @@ TextFormat::Printer::Printer() use_field_number_(false), use_short_repeated_primitives_(false), hide_unknown_fields_(false), - print_message_fields_in_index_order_(false) { + print_message_fields_in_index_order_(false), + expand_any_(false) { SetUseUtf8StringEscaping(false); } @@ -1413,11 +1495,63 @@ struct FieldIndexSorter { return left->index() < right->index(); } }; + } // namespace +bool TextFormat::Printer::PrintAny(const Message& message, + TextGenerator& generator) const { + const FieldDescriptor* type_url_field; + const FieldDescriptor* value_field; + if (!internal::GetAnyFieldDescriptors(message, &type_url_field, + &value_field)) { + return false; + } + + const Reflection* reflection = message.GetReflection(); + + // Extract the full type name from the type_url field. + const string& type_url = reflection->GetString(message, type_url_field); + string full_type_name; + if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) { + return false; + } + + // Print the "value" in text. + const google::protobuf::Descriptor* value_descriptor = + message.GetDescriptor()->file()->pool()->FindMessageTypeByName( + full_type_name); + if (value_descriptor == NULL) { + GOOGLE_LOG(WARNING) << "Proto type " << type_url << " not found"; + return false; + } + DynamicMessageFactory factory; + google::protobuf::scoped_ptr value_message( + factory.GetPrototype(value_descriptor)->New()); + string serialized_value = reflection->GetString(message, value_field); + if (!value_message->ParseFromString(serialized_value)) { + GOOGLE_LOG(WARNING) << type_url << ": failed to parse contents"; + return false; + } + generator.Print(StrCat("[", type_url, "]")); + const FieldValuePrinter* printer = FindWithDefault( + custom_printers_, value_field, default_field_value_printer_.get()); + generator.Print( + printer->PrintMessageStart(message, -1, 0, single_line_mode_)); + generator.Indent(); + Print(*value_message, generator); + generator.Outdent(); + generator.Print(printer->PrintMessageEnd(message, -1, 0, single_line_mode_)); + return true; +} + void TextFormat::Printer::Print(const Message& message, TextGenerator& generator) const { + const Descriptor* descriptor = message.GetDescriptor(); const Reflection* reflection = message.GetReflection(); + if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ && + PrintAny(message, generator)) { + return; + } vector fields; reflection->ListFields(message, &fields); if (print_message_fields_in_index_order_) { @@ -1446,6 +1580,54 @@ void TextFormat::Printer::PrintFieldValueToString( PrintFieldValue(message, message.GetReflection(), field, index, generator); } +class MapEntryMessageComparator { + public: + explicit MapEntryMessageComparator(const Descriptor* descriptor) + : field_(descriptor->field(0)) {} + + bool operator()(const Message* a, const Message* b) { + const Reflection* reflection = a->GetReflection(); + switch (field_->cpp_type()) { + case FieldDescriptor::CPPTYPE_BOOL: { + bool first = reflection->GetBool(*a, field_); + bool second = reflection->GetBool(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_INT32: { + int32 first = reflection->GetInt32(*a, field_); + int32 second = reflection->GetInt32(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_INT64: { + int64 first = reflection->GetInt64(*a, field_); + int64 second = reflection->GetInt64(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_UINT32: { + uint32 first = reflection->GetUInt32(*a, field_); + uint32 second = reflection->GetUInt32(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_UINT64: { + uint64 first = reflection->GetUInt64(*a, field_); + uint64 second = reflection->GetUInt64(*b, field_); + return first < second; + } + case FieldDescriptor::CPPTYPE_STRING: { + string first = reflection->GetString(*a, field_); + string second = reflection->GetString(*b, field_); + return first < second; + } + default: + GOOGLE_LOG(DFATAL) << "Invalid key for map field."; + return true; + } + } + + private: + const FieldDescriptor* field_; +}; + void TextFormat::Printer::PrintField(const Message& message, const Reflection* reflection, const FieldDescriptor* field, @@ -1466,6 +1648,21 @@ void TextFormat::Printer::PrintField(const Message& message, count = 1; } + std::vector sorted_map_field; + if (field->is_map()) { + const RepeatedPtrField& map_field = + reflection->GetRepeatedPtrField(message, field); + for (RepeatedPtrField::const_pointer_iterator it = + map_field.pointer_begin(); + it != map_field.pointer_end(); ++it) { + sorted_map_field.push_back(*it); + } + + MapEntryMessageComparator comparator(field->message_type()); + std::stable_sort(sorted_map_field.begin(), sorted_map_field.end(), + comparator); + } + for (int j = 0; j < count; ++j) { const int field_index = field->is_repeated() ? j : -1; @@ -1475,8 +1672,10 @@ void TextFormat::Printer::PrintField(const Message& message, const FieldValuePrinter* printer = FindWithDefault( custom_printers_, field, default_field_value_printer_.get()); const Message& sub_message = - field->is_repeated() - ? reflection->GetRepeatedMessage(message, field, j) + field->is_repeated() + ? (field->is_map() + ? *sorted_map_field[j] + : reflection->GetRepeatedMessage(message, field, j)) : reflection->GetMessage(message, field); generator.Print( printer->PrintMessageStart( @@ -1680,8 +1879,8 @@ void TextFormat::Printer::PrintUnknownFields( case UnknownField::TYPE_FIXED32: { generator.Print(field_number); generator.Print(": 0x"); - char buffer[kFastToBufferSize]; - generator.Print(FastHex32ToBuffer(field.fixed32(), buffer)); + generator.Print( + StrCat(strings::Hex(field.fixed32(), strings::Hex::ZERO_PAD_8))); if (single_line_mode_) { generator.Print(" "); } else { @@ -1692,8 +1891,8 @@ void TextFormat::Printer::PrintUnknownFields( case UnknownField::TYPE_FIXED64: { generator.Print(field_number); generator.Print(": 0x"); - char buffer[kFastToBufferSize]; - generator.Print(FastHex64ToBuffer(field.fixed64(), buffer)); + generator.Print( + StrCat(strings::Hex(field.fixed64(), strings::Hex::ZERO_PAD_16))); if (single_line_mode_) { generator.Print(" "); } else { diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 9e2cb070c6..6717aecd81 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -208,6 +208,17 @@ class LIBPROTOBUF_EXPORT TextFormat { print_message_fields_in_index_order; } + // If expand==true, expand google.protobuf.Any payloads. The output + // will be of form + // [type_url] { } + // + // If expand==false, print Any using the default printer. The output will + // look like + // type_url: "" value: "serialized_content" + void SetExpandAny(bool expand) { + expand_any_ = expand; + } + // Register a custom field-specific FieldValuePrinter for fields // with a particular FieldDescriptor. // Returns "true" if the registration succeeded, or "false", if there is @@ -259,6 +270,8 @@ class LIBPROTOBUF_EXPORT TextFormat { void PrintUnknownFields(const UnknownFieldSet& unknown_fields, TextGenerator& generator) const; + bool PrintAny(const Message& message, TextGenerator& generator) const; + int initial_indent_level_; bool single_line_mode_; @@ -271,6 +284,8 @@ class LIBPROTOBUF_EXPORT TextFormat { bool print_message_fields_in_index_order_; + bool expand_any_; + google::protobuf::scoped_ptr default_field_value_printer_; typedef map CustomPrinterMap; diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 477fdcbdb3..1b18c5ede4 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -32,23 +32,24 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #include -#include -#include -#include -#include -#include -#include - #include #include -#include -#include +#include +#include +#include +#include +#include #include #include +#include +#include + namespace google { namespace protobuf { @@ -451,7 +452,7 @@ TEST_F(TextFormatTest, ErrorCasesRegisteringFieldValuePrinterShouldFail) { class CustomMessageFieldValuePrinter : public TextFormat::FieldValuePrinter { public: virtual string PrintInt32(int32 v) const { - return StrCat(FieldValuePrinter::PrintInt32(v), " # x", ToHex(v)); + return StrCat(FieldValuePrinter::PrintInt32(v), " # x", strings::Hex(v)); } virtual string PrintMessageStart(const Message& message, diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index 6edfe056c3..877dc8f323 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -117,7 +117,7 @@ const int Timestamp::kNanosFieldNumber; #endif // !_MSC_VER Timestamp::Timestamp() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Timestamp) } @@ -310,9 +310,9 @@ int Timestamp::ByteSize() const { void Timestamp::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Timestamp* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Timestamp* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -370,7 +370,7 @@ void Timestamp::InternalSwap(Timestamp* other) { // Timestamp // optional int64 seconds = 1; - void Timestamp::clear_seconds() { +void Timestamp::clear_seconds() { seconds_ = GOOGLE_LONGLONG(0); } ::google::protobuf::int64 Timestamp::seconds() const { @@ -384,7 +384,7 @@ void Timestamp::InternalSwap(Timestamp* other) { } // optional int32 nanos = 2; - void Timestamp::clear_nanos() { +void Timestamp::clear_nanos() { nanos_ = 0; } ::google::protobuf::int32 Timestamp::nanos() const { diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index d77bc6ce78..8b08909e75 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -267,7 +267,7 @@ const int Type::kSourceContextFieldNumber; #endif // !_MSC_VER Type::Type() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Type) } @@ -332,7 +332,7 @@ Type* Type::New(::google::protobuf::Arena* arena) const { void Type::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; fields_.Clear(); oneofs_.Clear(); @@ -369,12 +369,15 @@ bool Type::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_fields: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_fields: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_fields())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_fields; + if (input->ExpectTag(18)) goto parse_loop_fields; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(26)) goto parse_oneofs; break; } @@ -402,12 +405,15 @@ bool Type::MergePartialFromCodedStream( case 4: { if (tag == 34) { parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(34)) goto parse_options; + if (input->ExpectTag(34)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(42)) goto parse_source_context; break; } @@ -587,9 +593,9 @@ int Type::ByteSize() const { void Type::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Type* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Type* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -654,7 +660,7 @@ void Type::InternalSwap(Type* other) { // Type // optional string name = 1; - void Type::clear_name() { +void Type::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Type::name() const { @@ -697,10 +703,10 @@ void Type::InternalSwap(Type* other) { } // repeated .google.protobuf.Field fields = 2; - int Type::fields_size() const { +int Type::fields_size() const { return fields_.size(); } - void Type::clear_fields() { +void Type::clear_fields() { fields_.Clear(); } const ::google::protobuf::Field& Type::fields(int index) const { @@ -727,10 +733,10 @@ Type::mutable_fields() { } // repeated string oneofs = 3; - int Type::oneofs_size() const { +int Type::oneofs_size() const { return oneofs_.size(); } - void Type::clear_oneofs() { +void Type::clear_oneofs() { oneofs_.Clear(); } const ::std::string& Type::oneofs(int index) const { @@ -781,10 +787,10 @@ Type::mutable_oneofs() { } // repeated .google.protobuf.Option options = 4; - int Type::options_size() const { +int Type::options_size() const { return options_.size(); } - void Type::clear_options() { +void Type::clear_options() { options_.Clear(); } const ::google::protobuf::Option& Type::options(int index) const { @@ -811,11 +817,11 @@ Type::mutable_options() { } // optional .google.protobuf.SourceContext source_context = 5; - bool Type::has_source_context() const { +bool Type::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } - void Type::clear_source_context() { - if (source_context_ != NULL) delete source_context_; +void Type::clear_source_context() { + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } const ::google::protobuf::SourceContext& Type::source_context() const { @@ -941,7 +947,7 @@ const int Field::kOptionsFieldNumber; #endif // !_MSC_VER Field::Field() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Field) } @@ -1153,12 +1159,15 @@ bool Field::MergePartialFromCodedStream( case 9: { if (tag == 74) { parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(74)) goto parse_options; + if (input->ExpectTag(74)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -1370,9 +1379,9 @@ int Field::ByteSize() const { void Field::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Field* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Field* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1454,7 +1463,7 @@ void Field::InternalSwap(Field* other) { // Field // optional .google.protobuf.Field.Kind kind = 1; - void Field::clear_kind() { +void Field::clear_kind() { kind_ = 0; } ::google::protobuf::Field_Kind Field::kind() const { @@ -1468,7 +1477,7 @@ void Field::InternalSwap(Field* other) { } // optional .google.protobuf.Field.Cardinality cardinality = 2; - void Field::clear_cardinality() { +void Field::clear_cardinality() { cardinality_ = 0; } ::google::protobuf::Field_Cardinality Field::cardinality() const { @@ -1482,7 +1491,7 @@ void Field::InternalSwap(Field* other) { } // optional int32 number = 3; - void Field::clear_number() { +void Field::clear_number() { number_ = 0; } ::google::protobuf::int32 Field::number() const { @@ -1496,7 +1505,7 @@ void Field::InternalSwap(Field* other) { } // optional string name = 4; - void Field::clear_name() { +void Field::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Field::name() const { @@ -1539,7 +1548,7 @@ void Field::InternalSwap(Field* other) { } // optional string type_url = 6; - void Field::clear_type_url() { +void Field::clear_type_url() { type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Field::type_url() const { @@ -1582,7 +1591,7 @@ void Field::InternalSwap(Field* other) { } // optional int32 oneof_index = 7; - void Field::clear_oneof_index() { +void Field::clear_oneof_index() { oneof_index_ = 0; } ::google::protobuf::int32 Field::oneof_index() const { @@ -1596,7 +1605,7 @@ void Field::InternalSwap(Field* other) { } // optional bool packed = 8; - void Field::clear_packed() { +void Field::clear_packed() { packed_ = false; } bool Field::packed() const { @@ -1610,10 +1619,10 @@ void Field::InternalSwap(Field* other) { } // repeated .google.protobuf.Option options = 9; - int Field::options_size() const { +int Field::options_size() const { return options_.size(); } - void Field::clear_options() { +void Field::clear_options() { options_.Clear(); } const ::google::protobuf::Option& Field::options(int index) const { @@ -1651,7 +1660,7 @@ const int Enum::kSourceContextFieldNumber; #endif // !_MSC_VER Enum::Enum() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Enum) } @@ -1716,7 +1725,7 @@ Enum* Enum::New(::google::protobuf::Arena* arena) const { void Enum::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; enumvalue_.Clear(); options_.Clear(); @@ -1752,26 +1761,31 @@ bool Enum::MergePartialFromCodedStream( case 2: { if (tag == 18) { parse_enumvalue: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_enumvalue: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_enumvalue())); } else { goto handle_unusual; } - if (input->ExpectTag(18)) goto parse_enumvalue; - if (input->ExpectTag(26)) goto parse_options; + if (input->ExpectTag(18)) goto parse_loop_enumvalue; + if (input->ExpectTag(26)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); break; } // repeated .google.protobuf.Option options = 3; case 3: { if (tag == 26) { - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(26)) goto parse_options; + if (input->ExpectTag(26)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectTag(34)) goto parse_source_context; break; } @@ -1924,9 +1938,9 @@ int Enum::ByteSize() const { void Enum::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Enum* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Enum* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1989,7 +2003,7 @@ void Enum::InternalSwap(Enum* other) { // Enum // optional string name = 1; - void Enum::clear_name() { +void Enum::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Enum::name() const { @@ -2032,10 +2046,10 @@ void Enum::InternalSwap(Enum* other) { } // repeated .google.protobuf.EnumValue enumvalue = 2; - int Enum::enumvalue_size() const { +int Enum::enumvalue_size() const { return enumvalue_.size(); } - void Enum::clear_enumvalue() { +void Enum::clear_enumvalue() { enumvalue_.Clear(); } const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const { @@ -2062,10 +2076,10 @@ Enum::mutable_enumvalue() { } // repeated .google.protobuf.Option options = 3; - int Enum::options_size() const { +int Enum::options_size() const { return options_.size(); } - void Enum::clear_options() { +void Enum::clear_options() { options_.Clear(); } const ::google::protobuf::Option& Enum::options(int index) const { @@ -2092,11 +2106,11 @@ Enum::mutable_options() { } // optional .google.protobuf.SourceContext source_context = 4; - bool Enum::has_source_context() const { +bool Enum::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } - void Enum::clear_source_context() { - if (source_context_ != NULL) delete source_context_; +void Enum::clear_source_context() { + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } const ::google::protobuf::SourceContext& Enum::source_context() const { @@ -2139,7 +2153,7 @@ const int EnumValue::kOptionsFieldNumber; #endif // !_MSC_VER EnumValue::EnumValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.EnumValue) } @@ -2251,12 +2265,15 @@ bool EnumValue::MergePartialFromCodedStream( case 3: { if (tag == 26) { parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + DO_(input->IncrementRecursionDepth()); + parse_loop_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( input, add_options())); } else { goto handle_unusual; } - if (input->ExpectTag(26)) goto parse_options; + if (input->ExpectTag(26)) goto parse_loop_options; + input->UnsafeDecrementRecursionDepth(); if (input->ExpectAtEnd()) goto success; break; } @@ -2372,9 +2389,9 @@ int EnumValue::ByteSize() const { void EnumValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const EnumValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const EnumValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -2435,7 +2452,7 @@ void EnumValue::InternalSwap(EnumValue* other) { // EnumValue // optional string name = 1; - void EnumValue::clear_name() { +void EnumValue::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& EnumValue::name() const { @@ -2478,7 +2495,7 @@ void EnumValue::InternalSwap(EnumValue* other) { } // optional int32 number = 2; - void EnumValue::clear_number() { +void EnumValue::clear_number() { number_ = 0; } ::google::protobuf::int32 EnumValue::number() const { @@ -2492,10 +2509,10 @@ void EnumValue::InternalSwap(EnumValue* other) { } // repeated .google.protobuf.Option options = 3; - int EnumValue::options_size() const { +int EnumValue::options_size() const { return options_.size(); } - void EnumValue::clear_options() { +void EnumValue::clear_options() { options_.Clear(); } const ::google::protobuf::Option& EnumValue::options(int index) const { @@ -2531,7 +2548,7 @@ const int Option::kValueFieldNumber; #endif // !_MSC_VER Option::Option() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Option) } @@ -2596,7 +2613,7 @@ Option* Option::New(::google::protobuf::Arena* arena) const { void Option::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (value_ != NULL) delete value_; + if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; } @@ -2732,9 +2749,9 @@ int Option::ByteSize() const { void Option::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Option* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Option* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -2793,7 +2810,7 @@ void Option::InternalSwap(Option* other) { // Option // optional string name = 1; - void Option::clear_name() { +void Option::clear_name() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& Option::name() const { @@ -2836,11 +2853,11 @@ void Option::InternalSwap(Option* other) { } // optional .google.protobuf.Any value = 2; - bool Option::has_value() const { +bool Option::has_value() const { return !_is_default_instance_ && value_ != NULL; } - void Option::clear_value() { - if (value_ != NULL) delete value_; +void Option::clear_value() { + if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; } const ::google::protobuf::Any& Option::value() const { diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index a14edd4a0b..c9952efa8e 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -936,7 +936,7 @@ inline bool Type::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } inline void Type::clear_source_context() { - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } inline const ::google::protobuf::SourceContext& Type::source_context() const { @@ -1270,7 +1270,7 @@ inline bool Enum::has_source_context() const { return !_is_default_instance_ && source_context_ != NULL; } inline void Enum::clear_source_context() { - if (source_context_ != NULL) delete source_context_; + if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } inline const ::google::protobuf::SourceContext& Enum::source_context() const { @@ -1445,7 +1445,7 @@ inline bool Option::has_value() const { return !_is_default_instance_ && value_ != NULL; } inline void Option::clear_value() { - if (value_ != NULL) delete value_; + if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; } inline const ::google::protobuf::Any& Option::value() const { @@ -1478,6 +1478,14 @@ inline void Option::set_allocated_value(::google::protobuf::Any* value) { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index a32291e000..834c9b5696 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -185,6 +185,7 @@ message TestAllTypes { message NestedTestAllTypes { optional NestedTestAllTypes child = 1; optional TestAllTypes payload = 2; + repeated NestedTestAllTypes repeated_child = 3; } message TestDeprecatedFields { @@ -203,6 +204,11 @@ enum ForeignEnum { FOREIGN_BAZ = 6; } +message TestReservedFields { + reserved 2, 15, 9 to 11; + reserved "bar", "baz"; +} + message TestAllExtensions { extensions 1 to max; } diff --git a/src/google/protobuf/unittest_drop_unknown_fields.proto b/src/google/protobuf/unittest_drop_unknown_fields.proto index 1b35fad010..faaddc6e67 100644 --- a/src/google/protobuf/unittest_drop_unknown_fields.proto +++ b/src/google/protobuf/unittest_drop_unknown_fields.proto @@ -41,8 +41,8 @@ message Foo { BAR = 1; BAZ = 2; } - optional int32 int32_value = 1; - optional NestedEnum enum_value = 2; + int32 int32_value = 1; + NestedEnum enum_value = 2; } message FooWithExtraFields { @@ -52,7 +52,7 @@ message FooWithExtraFields { BAZ = 2; QUX = 3; } - optional int32 int32_value = 1; - optional NestedEnum enum_value = 2; - optional int32 extra_int32_value = 3; + int32 int32_value = 1; + NestedEnum enum_value = 2; + int32 extra_int32_value = 3; } diff --git a/src/google/protobuf/unittest_no_field_presence.proto b/src/google/protobuf/unittest_no_field_presence.proto index f261b58e63..f5cc4cc35f 100644 --- a/src/google/protobuf/unittest_no_field_presence.proto +++ b/src/google/protobuf/unittest_no_field_presence.proto @@ -43,7 +43,7 @@ option csharp_namespace = "Google.ProtocolBuffers.TestProtos.Proto3"; // forms. message TestAllTypes { message NestedMessage { - optional int32 bb = 1; + int32 bb = 1; } enum NestedEnum { @@ -55,36 +55,36 @@ message TestAllTypes { // Singular // TODO: remove 'optional' labels as soon as CL 69188077 is LGTM'd to make // 'optional' optional. - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessage optional_foreign_message = 19; - optional protobuf_unittest.TestAllTypes optional_proto2_message = 20; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnum optional_foreign_enum = 22; + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest.TestAllTypes optional_proto2_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; // N.B.: proto2-enum-type fields not allowed, because their default values // might not be zero. //optional protobuf_unittest.ForeignEnum optional_proto2_enum = 23; - optional string optional_string_piece = 24 [ctype=STRING_PIECE]; - optional string optional_cord = 25 [ctype=CORD]; + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; - optional NestedMessage optional_lazy_message = 30 [lazy=true]; + NestedMessage optional_lazy_message = 30 [lazy=true]; // Repeated repeated int32 repeated_int32 = 31; @@ -124,13 +124,13 @@ message TestAllTypes { } message TestProto2Required { - optional protobuf_unittest.TestRequired proto2 = 1; + protobuf_unittest.TestRequired proto2 = 1; } // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { - optional int32 c = 1; + int32 c = 1; } enum ForeignEnum { diff --git a/src/google/protobuf/unittest_preserve_unknown_enum.proto b/src/google/protobuf/unittest_preserve_unknown_enum.proto index 24e6828ff7..abc3de2813 100644 --- a/src/google/protobuf/unittest_preserve_unknown_enum.proto +++ b/src/google/protobuf/unittest_preserve_unknown_enum.proto @@ -49,7 +49,7 @@ enum MyEnumPlusExtra { } message MyMessage { - optional MyEnum e = 1; + MyEnum e = 1; repeated MyEnum repeated_e = 2; repeated MyEnum repeated_packed_e = 3 [packed=true]; repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4; // not packed @@ -60,7 +60,7 @@ message MyMessage { } message MyMessagePlusExtra { - optional MyEnumPlusExtra e = 1; + MyEnumPlusExtra e = 1; repeated MyEnumPlusExtra repeated_e = 2; repeated MyEnumPlusExtra repeated_packed_e = 3 [packed=true]; repeated MyEnumPlusExtra repeated_packed_unexpected_e = 4 [packed=true]; diff --git a/src/google/protobuf/unittest_proto3_arena.proto b/src/google/protobuf/unittest_proto3_arena.proto index 6d7bada8f3..b835a6ba36 100644 --- a/src/google/protobuf/unittest_proto3_arena.proto +++ b/src/google/protobuf/unittest_proto3_arena.proto @@ -43,7 +43,7 @@ message TestAllTypes { // The field name "b" fails to compile in proto1 because it conflicts with // a local variable named "b" in one of the generated methods. Doh. // This file needs to compile in proto1 to test backwards-compatibility. - optional int32 bb = 1; + int32 bb = 1; } enum NestedEnum { @@ -55,46 +55,47 @@ message TestAllTypes { } // Singular - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional group OptionalGroup = 16 { - optional int32 a = 17; - } - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessage optional_foreign_message = 19; - optional protobuf_unittest_import.ImportMessage optional_import_message = 20; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnum optional_foreign_enum = 22; + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; // Omitted (compared to unittest.proto) because proto2 enums are not allowed // inside proto2 messages. // // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; - optional string optional_string_piece = 24 [ctype=STRING_PIECE]; - optional string optional_cord = 25 [ctype=CORD]; + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; // Defined in unittest_import_public.proto - optional protobuf_unittest_import.PublicImportMessage + protobuf_unittest_import.PublicImportMessage optional_public_import_message = 26; - optional NestedMessage optional_lazy_message = 27 [lazy=true]; + NestedMessage optional_lazy_message = 27 [lazy=true]; // Repeated repeated int32 repeated_int32 = 31; @@ -113,9 +114,10 @@ message TestAllTypes { repeated string repeated_string = 44; repeated bytes repeated_bytes = 45; - repeated group RepeatedGroup = 46 { - optional int32 a = 47; - } + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } repeated NestedMessage repeated_nested_message = 48; repeated ForeignMessage repeated_foreign_message = 49; @@ -161,6 +163,24 @@ message TestPackedTypes { repeated ForeignEnum packed_enum = 103 [packed = true]; } +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + // This proto includes a recusively nested message. message NestedTestAllTypes { NestedTestAllTypes child = 1; @@ -170,7 +190,7 @@ message NestedTestAllTypes { // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { - optional int32 c = 1; + int32 c = 1; } enum ForeignEnum { diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index e15280c8e4..766449003c 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -93,7 +93,7 @@ void UnknownFieldSet::InternalMergeFrom(const UnknownFieldSet& other) { fields_ = new vector(); for (int i = 0; i < other_field_count; i++) { fields_->push_back((*other.fields_)[i]); - fields_->back().DeepCopy(); + fields_->back().DeepCopy((*other.fields_)[i]); } } } @@ -104,7 +104,7 @@ void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { if (fields_ == NULL) fields_ = new vector(); for (int i = 0; i < other_field_count; i++) { fields_->push_back((*other.fields_)[i]); - fields_->back().DeepCopy(); + fields_->back().DeepCopy((*other.fields_)[i]); } } } @@ -202,7 +202,7 @@ UnknownFieldSet* UnknownFieldSet::AddGroup(int number) { void UnknownFieldSet::AddField(const UnknownField& field) { if (fields_ == NULL) fields_ = new vector(); fields_->push_back(field); - fields_->back().DeepCopy(); + fields_->back().DeepCopy(field); } void UnknownFieldSet::DeleteSubrange(int start, int num) { @@ -303,7 +303,7 @@ void UnknownField::Reset() { } } -void UnknownField::DeepCopy() { +void UnknownField::DeepCopy(const UnknownField& other) { switch (type()) { case UnknownField::TYPE_LENGTH_DELIMITED: length_delimited_.string_value_ = new string( diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 987b1979d5..6781cd0f12 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -216,7 +216,7 @@ class LIBPROTOBUF_EXPORT UnknownField { void Reset(); // Make a deep copy of any pointers in this UnknownField. - void DeepCopy(); + void DeepCopy(const UnknownField& other); // Set the wire type of this UnknownField. Should only be used when this // UnknownField is being created. diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index c5bbbf2ed9..54cd653a77 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -829,7 +829,7 @@ void WireFormat::SerializeFieldWithCachedSizes( count = 1; } - const bool is_packed = field->options().packed(); + const bool is_packed = field->is_packed(); if (is_packed && count > 0) { WireFormatLite::WriteTag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); @@ -996,7 +996,7 @@ int WireFormat::FieldByteSize( const int data_size = FieldDataOnlyByteSize(field, message); int our_size = data_size; - if (field->options().packed()) { + if (field->is_packed()) { if (data_size > 0) { // Packed fields get serialized like a string, not their native type. // Technically this doesn't really matter; the size only changes if it's diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index 76bc75a1c7..ac83abdc0d 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -330,6 +330,17 @@ class LIBPROTOBUF_EXPORT WireFormatLite { template static inline bool ReadMessageNoVirtual(input, MessageType* value); + // The same, but do not modify input's recursion depth. This is useful + // when reading a bunch of groups or messages in a loop, because then the + // recursion depth can be incremented before the loop and decremented after. + template + static inline bool ReadGroupNoVirtualNoRecursionDepth(field_number, input, + MessageType* value); + + template + static inline bool ReadMessageNoVirtualNoRecursionDepth(input, + MessageType* value); + // Write a tag. The Write*() functions typically include the tag, so // normally there's no need to call this unless using the Write*NoTag() // variants. diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index 129fc63f8c..d073ff9232 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -470,7 +470,7 @@ inline bool WireFormatLite::ReadGroupNoVirtual( if (!value-> MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) return false; - input->DecrementRecursionDepth(); + input->UnsafeDecrementRecursionDepth(); // Make sure the last thing read was an end tag for this group. if (!input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP))) { return false; @@ -478,6 +478,14 @@ inline bool WireFormatLite::ReadGroupNoVirtual( return true; } template +inline bool WireFormatLite::ReadGroupNoVirtualNoRecursionDepth( + int field_number, io::CodedInputStream* input, + MessageType_WorkAroundCppLookupDefect* value) { + return value->MessageType_WorkAroundCppLookupDefect:: + MergePartialFromCodedStream(input) && + input->LastTagWas(MakeTag(field_number, WIRETYPE_END_GROUP)); +} +template inline bool WireFormatLite::ReadMessageNoVirtual( io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) { uint32 length; @@ -491,6 +499,17 @@ inline bool WireFormatLite::ReadMessageNoVirtual( // tag. return input->DecrementRecursionDepthAndPopLimit(p.first); } +template +inline bool WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( + io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) { + io::CodedInputStream::Limit old_limit = input->ReadLengthAndPushLimit(); + if (!value-> + MessageType_WorkAroundCppLookupDefect::MergePartialFromCodedStream(input)) + return false; + // Make sure that parsing stopped when the limit was hit, not at an endgroup + // tag. + return input->CheckEntireMessageConsumedAndPopLimit(old_limit); +} // =================================================================== diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index a3062a6acd..e80c5a710b 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -794,6 +795,137 @@ TEST(WireFormatTest, CompatibleTypes) { ASSERT_EQ(static_cast(data), msg5.data()); } +class Proto3PrimitiveRepeatedWireFormatTest + : public ::testing::TestWithParam { + protected: + template + void SetProto3PrimitiveRepeatedFields(Proto* message) { + message->add_repeated_int32(1); + message->add_repeated_int64(1); + message->add_repeated_uint32(1); + message->add_repeated_uint64(1); + message->add_repeated_sint32(1); + message->add_repeated_sint64(1); + message->add_repeated_fixed32(1); + message->add_repeated_fixed64(1); + message->add_repeated_sfixed32(1); + message->add_repeated_sfixed64(1); + message->add_repeated_float(1.0); + message->add_repeated_double(1.0); + message->add_repeated_bool(true); + message->add_repeated_nested_enum( + proto3_arena_unittest::TestAllTypes_NestedEnum_FOO); + } + + template + void ExpectProto3PrimitiveRepeatedFieldsSet(const Proto& message) { + EXPECT_EQ(1, message.repeated_int32(0)); + EXPECT_EQ(1, message.repeated_int64(0)); + EXPECT_EQ(1, message.repeated_uint32(0)); + EXPECT_EQ(1, message.repeated_uint64(0)); + EXPECT_EQ(1, message.repeated_sint32(0)); + EXPECT_EQ(1, message.repeated_sint64(0)); + EXPECT_EQ(1, message.repeated_fixed32(0)); + EXPECT_EQ(1, message.repeated_fixed64(0)); + EXPECT_EQ(1, message.repeated_sfixed32(0)); + EXPECT_EQ(1, message.repeated_sfixed64(0)); + EXPECT_EQ(1.0, message.repeated_float(0)); + EXPECT_EQ(1.0, message.repeated_double(0)); + EXPECT_EQ(true, message.repeated_bool(0)); + EXPECT_EQ(proto3_arena_unittest::TestAllTypes_NestedEnum_FOO, + message.repeated_nested_enum(0)); + } + + template + void TestProto3PrimitiveRepeatedFields(Proto* message, + const string& expected) { + SetProto3PrimitiveRepeatedFields(message); + + int size = message->ByteSize(); + + // Serialize using the generated code. + string generated_data; + { + io::StringOutputStream raw_output(&generated_data); + io::CodedOutputStream output(&raw_output); + message->SerializeWithCachedSizes(&output); + ASSERT_FALSE(output.HadError()); + } + + EXPECT_TRUE(expected == generated_data); + + message->Clear(); + message->ParseFromString(generated_data); + ExpectProto3PrimitiveRepeatedFieldsSet(*message); + + // Serialize using the dynamic code. + string dynamic_data; + { + io::StringOutputStream raw_output(&dynamic_data); + io::CodedOutputStream output(&raw_output); + WireFormat::SerializeWithCachedSizes(*message, size, &output); + ASSERT_FALSE(output.HadError()); + } + + EXPECT_TRUE(expected == dynamic_data); + + message->Clear(); + io::CodedInputStream input( + reinterpret_cast(dynamic_data.data()), + dynamic_data.size()); + WireFormat::ParseAndMergePartial(&input, message); + ExpectProto3PrimitiveRepeatedFieldsSet(*message); + } +}; +INSTANTIATE_TEST_CASE_P(SetPacked, + Proto3PrimitiveRepeatedWireFormatTest, + ::testing::Values(false, true)); + +TEST_P(Proto3PrimitiveRepeatedWireFormatTest, Proto3PrimitiveRepeated) { + proto3_arena_unittest::TestAllTypes packed_message; + proto3_arena_unittest::TestUnpackedTypes unpacked_message; + + const string packedExpected( + "\xFA\x01\x01\x01" + "\x82\x02\x01\x01" + "\x8A\x02\x01\x01" + "\x92\x02\x01\x01" + "\x9A\x02\x01\x02" + "\xA2\x02\x01\x02" + "\xAA\x02\x04\x01\x00\x00\x00" + "\xB2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00" + "\xBA\x02\x04\x01\x00\x00\x00" + "\xC2\x02\x08\x01\x00\x00\x00\x00\x00\x00\x00" + "\xCA\x02\x04\x00\x00\x80\x3f" + "\xD2\x02\x08\x00\x00\x00\x00\x00\x00\xf0\x3f" + "\xDA\x02\x01\x01" + "\x9A\x03\x01\x01", + 86); + + const string unpackedExpected( + "\x08\x01" + "\x10\x01" + "\x18\x01" + "\x20\x01" + "\x28\x02" + "\x30\x02" + "\x3D\x01\x00\x00\x00" + "\x41\x01\x00\x00\x00\x00\x00\x00\x00" + "\x4D\x01\x00\x00\x00" + "\x51\x01\x00\x00\x00\x00\x00\x00\x00" + "\x5D\x00\x00\x80\x3f" + "\x61\x00\x00\x00\x00\x00\x00\xf0\x3f" + "\x68\x01" + "\x70\x01", + 58); + + if (GetParam()) { + TestProto3PrimitiveRepeatedFields(&packed_message, packedExpected); + } else { + TestProto3PrimitiveRepeatedFields(&unpacked_message, unpackedExpected); + } +} + class WireFormatInvalidInputTest : public testing::Test { protected: // Make a serialized TestAllTypes in which the field optional_nested_message diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 4d91ed56f1..ffc77f1c2f 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -312,7 +312,7 @@ const int DoubleValue::kValueFieldNumber; #endif // !_MSC_VER DoubleValue::DoubleValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.DoubleValue) } @@ -458,9 +458,9 @@ int DoubleValue::ByteSize() const { void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const DoubleValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const DoubleValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -514,7 +514,7 @@ void DoubleValue::InternalSwap(DoubleValue* other) { // DoubleValue // optional double value = 1; - void DoubleValue::clear_value() { +void DoubleValue::clear_value() { value_ = 0; } double DoubleValue::value() const { @@ -536,7 +536,7 @@ const int FloatValue::kValueFieldNumber; #endif // !_MSC_VER FloatValue::FloatValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.FloatValue) } @@ -682,9 +682,9 @@ int FloatValue::ByteSize() const { void FloatValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const FloatValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const FloatValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -738,7 +738,7 @@ void FloatValue::InternalSwap(FloatValue* other) { // FloatValue // optional float value = 1; - void FloatValue::clear_value() { +void FloatValue::clear_value() { value_ = 0; } float FloatValue::value() const { @@ -760,7 +760,7 @@ const int Int64Value::kValueFieldNumber; #endif // !_MSC_VER Int64Value::Int64Value() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Int64Value) } @@ -908,9 +908,9 @@ int Int64Value::ByteSize() const { void Int64Value::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Int64Value* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Int64Value* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -964,7 +964,7 @@ void Int64Value::InternalSwap(Int64Value* other) { // Int64Value // optional int64 value = 1; - void Int64Value::clear_value() { +void Int64Value::clear_value() { value_ = GOOGLE_LONGLONG(0); } ::google::protobuf::int64 Int64Value::value() const { @@ -986,7 +986,7 @@ const int UInt64Value::kValueFieldNumber; #endif // !_MSC_VER UInt64Value::UInt64Value() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UInt64Value) } @@ -1134,9 +1134,9 @@ int UInt64Value::ByteSize() const { void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const UInt64Value* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const UInt64Value* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1190,7 +1190,7 @@ void UInt64Value::InternalSwap(UInt64Value* other) { // UInt64Value // optional uint64 value = 1; - void UInt64Value::clear_value() { +void UInt64Value::clear_value() { value_ = GOOGLE_ULONGLONG(0); } ::google::protobuf::uint64 UInt64Value::value() const { @@ -1212,7 +1212,7 @@ const int Int32Value::kValueFieldNumber; #endif // !_MSC_VER Int32Value::Int32Value() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.Int32Value) } @@ -1360,9 +1360,9 @@ int Int32Value::ByteSize() const { void Int32Value::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const Int32Value* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const Int32Value* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1416,7 +1416,7 @@ void Int32Value::InternalSwap(Int32Value* other) { // Int32Value // optional int32 value = 1; - void Int32Value::clear_value() { +void Int32Value::clear_value() { value_ = 0; } ::google::protobuf::int32 Int32Value::value() const { @@ -1438,7 +1438,7 @@ const int UInt32Value::kValueFieldNumber; #endif // !_MSC_VER UInt32Value::UInt32Value() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.UInt32Value) } @@ -1586,9 +1586,9 @@ int UInt32Value::ByteSize() const { void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const UInt32Value* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const UInt32Value* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1642,7 +1642,7 @@ void UInt32Value::InternalSwap(UInt32Value* other) { // UInt32Value // optional uint32 value = 1; - void UInt32Value::clear_value() { +void UInt32Value::clear_value() { value_ = 0u; } ::google::protobuf::uint32 UInt32Value::value() const { @@ -1664,7 +1664,7 @@ const int BoolValue::kValueFieldNumber; #endif // !_MSC_VER BoolValue::BoolValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.BoolValue) } @@ -1810,9 +1810,9 @@ int BoolValue::ByteSize() const { void BoolValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const BoolValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const BoolValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -1866,7 +1866,7 @@ void BoolValue::InternalSwap(BoolValue* other) { // BoolValue // optional bool value = 1; - void BoolValue::clear_value() { +void BoolValue::clear_value() { value_ = false; } bool BoolValue::value() const { @@ -1888,7 +1888,7 @@ const int StringValue::kValueFieldNumber; #endif // !_MSC_VER StringValue::StringValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.StringValue) } @@ -2051,9 +2051,9 @@ int StringValue::ByteSize() const { void StringValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const StringValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const StringValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -2108,7 +2108,7 @@ void StringValue::InternalSwap(StringValue* other) { // StringValue // optional string value = 1; - void StringValue::clear_value() { +void StringValue::clear_value() { value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& StringValue::value() const { @@ -2159,7 +2159,7 @@ const int BytesValue::kValueFieldNumber; #endif // !_MSC_VER BytesValue::BytesValue() - : ::google::protobuf::Message() , _internal_metadata_(NULL) { + : ::google::protobuf::Message(), _internal_metadata_(NULL) { SharedCtor(); // @@protoc_insertion_point(constructor:google.protobuf.BytesValue) } @@ -2310,9 +2310,9 @@ int BytesValue::ByteSize() const { void BytesValue::MergeFrom(const ::google::protobuf::Message& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); - const BytesValue* source = - ::google::protobuf::internal::dynamic_cast_if_available( - &from); + const BytesValue* source = + ::google::protobuf::internal::DynamicCastToGenerated( + &from); if (source == NULL) { ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { @@ -2367,7 +2367,7 @@ void BytesValue::InternalSwap(BytesValue* other) { // BytesValue // optional bytes value = 1; - void BytesValue::clear_value() { +void BytesValue::clear_value() { value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } const ::std::string& BytesValue::value() const { diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index c318f95020..387ebd7cb1 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -984,6 +984,22 @@ inline void BytesValue::set_allocated_value(::std::string* value) { } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/vsprojects/libprotoc.vcproj b/vsprojects/libprotoc.vcproj index d1f065e225..3474d21f47 100644 --- a/vsprojects/libprotoc.vcproj +++ b/vsprojects/libprotoc.vcproj @@ -295,6 +295,10 @@ RelativePath="..\src\google\protobuf\compiler\java\java_enum_field.h" > + + @@ -323,14 +327,34 @@ RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.h" > + + + + + + + + + + @@ -339,6 +363,10 @@ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.h" > + + @@ -351,6 +379,10 @@ RelativePath="..\src\google\protobuf\compiler\java\java_string_field.h" > + + @@ -607,18 +639,42 @@ RelativePath="..\src\google\protobuf\compiler\java\java_lazy_message_field.cc" > + + + + + + + + + + + + @@ -627,6 +683,10 @@ RelativePath="..\src\google\protobuf\compiler\java\java_primitive_field.cc" > + + @@ -639,6 +699,10 @@ RelativePath="..\src\google\protobuf\compiler\java\java_string_field.cc" > + +