From d37d46dfbcedadeb439ad0367f8afcf8867dca43 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Sat, 25 Apr 2009 02:53:47 +0000 Subject: Integrate recent changes from Google-internal code tree. See CHANGES.txt for details. --- CHANGES.txt | 81 +- CONTRIBUTORS.txt | 3 +- Makefile.am | 3 + .../java/com/google/protobuf/AbstractMessage.java | 58 +- .../com/google/protobuf/BlockingRpcChannel.java | 51 + .../java/com/google/protobuf/BlockingService.java | 64 + .../java/com/google/protobuf/CodedInputStream.java | 62 +- .../main/java/com/google/protobuf/Descriptors.java | 2 +- .../java/com/google/protobuf/DynamicMessage.java | 7 +- .../src/main/java/com/google/protobuf/Message.java | 43 +- .../src/main/java/com/google/protobuf/RpcUtil.java | 6 +- .../java/com/google/protobuf/ServiceException.java | 42 + .../java/com/google/protobuf/UnknownFieldSet.java | 45 + .../com/google/protobuf/AbstractMessageTest.java | 38 +- .../com/google/protobuf/CodedInputStreamTest.java | 61 + .../com/google/protobuf/DynamicMessageTest.java | 12 + .../com/google/protobuf/GeneratedMessageTest.java | 11 + .../test/java/com/google/protobuf/ServiceTest.java | 99 +- .../com/google/protobuf/UnknownFieldSetTest.java | 99 +- .../java/com/google/protobuf/WireFormatTest.java | 20 + python/google/protobuf/internal/input_stream.py | 115 +- .../google/protobuf/internal/input_stream_test.py | 21 +- python/google/protobuf/internal/reflection_test.py | 9 + python/google/protobuf/reflection.py | 4 + src/Makefile.am | 6 + src/google/protobuf/compiler/cpp/cpp_enum.cc | 24 +- src/google/protobuf/compiler/cpp/cpp_enum_field.cc | 72 +- src/google/protobuf/compiler/cpp/cpp_enum_field.h | 6 +- src/google/protobuf/compiler/cpp/cpp_extension.cc | 81 +- src/google/protobuf/compiler/cpp/cpp_extension.h | 3 + src/google/protobuf/compiler/cpp/cpp_field.h | 23 +- src/google/protobuf/compiler/cpp/cpp_file.cc | 152 +- src/google/protobuf/compiler/cpp/cpp_helpers.cc | 47 +- src/google/protobuf/compiler/cpp/cpp_helpers.h | 10 +- src/google/protobuf/compiler/cpp/cpp_message.cc | 455 +++-- src/google/protobuf/compiler/cpp/cpp_message.h | 29 +- .../protobuf/compiler/cpp/cpp_message_field.cc | 34 +- .../protobuf/compiler/cpp/cpp_message_field.h | 6 +- .../protobuf/compiler/cpp/cpp_primitive_field.cc | 99 +- .../protobuf/compiler/cpp/cpp_primitive_field.h | 6 +- src/google/protobuf/compiler/cpp/cpp_service.cc | 6 +- .../protobuf/compiler/cpp/cpp_string_field.cc | 100 +- .../protobuf/compiler/cpp/cpp_string_field.h | 6 +- src/google/protobuf/compiler/cpp/cpp_unittest.cc | 140 +- src/google/protobuf/compiler/importer.cc | 34 +- src/google/protobuf/compiler/importer.h | 10 + src/google/protobuf/compiler/importer_unittest.cc | 28 + src/google/protobuf/compiler/java/java_message.cc | 20 +- src/google/protobuf/compiler/java/java_service.cc | 281 ++- src/google/protobuf/compiler/java/java_service.h | 33 + src/google/protobuf/compiler/parser.cc | 9 +- src/google/protobuf/compiler/parser.h | 15 +- src/google/protobuf/compiler/parser_unittest.cc | 44 +- src/google/protobuf/descriptor.cc | 1195 ++++++++---- src/google/protobuf/descriptor.h | 97 +- src/google/protobuf/descriptor.pb.cc | 2001 +++++++++++++------- src/google/protobuf/descriptor.pb.h | 1036 ++++------ src/google/protobuf/descriptor.proto | 9 +- src/google/protobuf/descriptor_database.cc | 397 +++- src/google/protobuf/descriptor_database.h | 207 +- .../protobuf/descriptor_database_unittest.cc | 413 ++-- src/google/protobuf/descriptor_unittest.cc | 313 ++- src/google/protobuf/dynamic_message.cc | 4 +- src/google/protobuf/extension_set.cc | 988 +++++++--- src/google/protobuf/extension_set.h | 441 +++-- src/google/protobuf/extension_set_unittest.cc | 86 +- .../protobuf/generated_message_reflection.cc | 67 +- src/google/protobuf/generated_message_reflection.h | 26 + src/google/protobuf/io/coded_stream.cc | 258 ++- src/google/protobuf/io/coded_stream.h | 179 +- src/google/protobuf/io/coded_stream_unittest.cc | 20 +- src/google/protobuf/io/zero_copy_stream_impl.cc | 5 +- src/google/protobuf/message.cc | 112 +- src/google/protobuf/message.h | 58 +- src/google/protobuf/reflection_ops_unittest.cc | 36 +- src/google/protobuf/repeated_field.h | 124 ++ src/google/protobuf/repeated_field_unittest.cc | 149 ++ src/google/protobuf/stubs/common.h | 6 + src/google/protobuf/stubs/hash.h | 27 + src/google/protobuf/stubs/map-util.h | 15 + src/google/protobuf/stubs/once.cc | 82 + src/google/protobuf/stubs/once.h | 122 ++ src/google/protobuf/stubs/once_unittest.cc | 253 +++ src/google/protobuf/test_util.cc | 22 + src/google/protobuf/test_util.h | 6 + src/google/protobuf/text_format.cc | 271 ++- src/google/protobuf/text_format.h | 99 +- src/google/protobuf/text_format_unittest.cc | 83 +- src/google/protobuf/unittest.proto | 8 + src/google/protobuf/unittest_empty.proto | 37 + src/google/protobuf/unknown_field_set.cc | 244 ++- src/google/protobuf/unknown_field_set.h | 415 +--- src/google/protobuf/unknown_field_set_unittest.cc | 361 ++-- src/google/protobuf/wire_format.cc | 297 +-- src/google/protobuf/wire_format.h | 183 +- src/google/protobuf/wire_format_inl.h | 408 +++- src/google/protobuf/wire_format_unittest.cc | 75 +- 97 files changed, 9635 insertions(+), 4335 deletions(-) create mode 100644 java/src/main/java/com/google/protobuf/BlockingRpcChannel.java create mode 100644 java/src/main/java/com/google/protobuf/BlockingService.java create mode 100644 java/src/main/java/com/google/protobuf/ServiceException.java create mode 100644 src/google/protobuf/stubs/once.cc create mode 100644 src/google/protobuf/stubs/once.h create mode 100644 src/google/protobuf/stubs/once_unittest.cc create mode 100644 src/google/protobuf/unittest_empty.proto diff --git a/CHANGES.txt b/CHANGES.txt index 2ac9091e..8fa7a536 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,4 @@ -????-??-?? version 2.0.4: +????-??-?? version 2.1.0: General * Repeated fields of primitive types (types other that string, group, and @@ -20,22 +20,70 @@ * Updated bundled Google Test to version 1.3.0. Google Test is now bundled in its verbatim form as a nested autoconf package, so you can drop in any other version of Google Test if needed. + * optimize_for = SPEED is now the default, by popular demand. Use + optimize_for = CODE_SIZE if code size is more important in your app. + * It is now an error to define a default value for a repeated field. + Previously, this was silently ignored (it had no effect on the generated + code). + * Fields can now be marked deprecated like: + optional int32 foo = 1 [deprecated = true]; + Currently this does not have any actual effect, but in the future the code + generators may generate deprecation annotations in each language. protoc * --error_format=msvs option causes errors to be printed in Visual Studio format, which should allow them to be clicked on in the build log to go - directly to the error location. + directly to the error location. + * The type name resolver will no longer resolve type names to fields. For + example, this now works: + message Foo {} + message Bar { + optional int32 Foo = 1; + optional Foo baz = 2; + } + Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get + an error because Bar.Foo is a field, not a type. Now the type of "baz" + resolves to the message type Foo. This change is unlikely to make a + difference to anyone who follows the Protocol Buffers style guide. C++ - * UnknownFieldSet now supports STL-like iteration. + * Several optimizations, including but not limited to: + - Serialization, especially to flat arrays, is 10%-50% faster, possibly + more for small objects. + - Several descriptor operations which previously required locking no longer + do. + - Descriptors are now constructed lazily on first use, rather than at + process startup time. This should save memory in programs which do not + use descriptors or reflection. + - UnknownFieldSet completely redesigned to be more efficient (especially in + terms of memory usage). + - Various optimizations to reduce code size (though the serialization speed + optimizations increased code size). * Message interface has method ParseFromBoundedZeroCopyStream() which parses a limited number of bytes from an input stream rather than parsing until EOF. * GzipInputStream and GzipOutputStream support reading/writing gzip- or zlib-compressed streams if zlib is available. (google/protobuf/io/gzip_stream.h) - * Generated constructors explicitly initialize all fields (to avoid warnings - with certain compiler settings). + * DescriptorPool::FindAllExtensions() and corresponding + DescriptorDatabase::FindAllExtensions() can be used to enumerate all + extensions of a given type. + * For each enum type Foo, protoc will generate functions: + const string& Foo_Name(Foo value); + bool Foo_Parse(const string& name, Foo* result); + The former returns the name of the enum constant corresponding to the given + value while the latter finds the value corresponding to a name. + * RepeatedField and RepeatedPtrField now have back-insertion iterators. + * String fields now have setters that take a char* and a size, in addition + to the existing ones that took char* or const string&. + * DescriptorPool::AllowUnknownDependencies() may be used to tell + DescriptorPool to create placeholder descriptors for unknown entities + referenced in a FileDescriptorProto. This can allow you to parse a .proto + file without having access to other .proto files that it imports, for + example. + * Updated gtest to latest version. The gtest package is now included as a + nested autoconf package, so it should be able to drop new versions into the + "gtest" subdirectory without modification. Java * Fixed bug where Message.mergeFrom(Message) failed to merge extensions. @@ -48,6 +96,28 @@ regex implementation (which unfortunately uses recursive backtracking rather than building an NFA). Worked around by making use of possesive quantifiers. + * Generated service classes now also generate pure interfaces. For a service + Foo, Foo.Interface is a pure interface containing all of the service's + defined methods. Foo.newReflectiveService() can be called to wrap an + instance of this interface in a class that implements the generic + RpcService interface, which provides reflection support that is usually + needed by RPC server implementations. + * RPC interfaces now support blocking operation in addition to non-blocking. + The protocol compiler generates separate blocking and non-blocking stubs + which operate against separate blocking and non-blocking RPC interfaces. + RPC implementations will have to implement the new interfaces in order to + support blocking mode. + * New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and + writeDelimitedTo() read and write "delemited" messages from/to a stream, + meaning that the message size precedes the data. This way, you can write + multiple messages to a stream without having to worry about delimiting + them yourself. + * Throw a more descriptive exception when build() is double-called. + * Add a method to query whether CodedInputStream is at the end of the input + stream. + * Add a method to reset a CodedInputStream's size counter; useful when + reading many messages with the same stream. + * equals() and hashCode() now account for unknown fields. Python * Added slicing support for repeated scalar fields. Added slice retrieval and @@ -58,6 +128,7 @@ object will be returned directly to the caller. This interface change cannot be used in practice until RPC implementations are updated to implement it. + * Changes to input_stream.py should make protobuf compatible with appengine. 2008-11-25 version 2.0.3: diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 259a6f7e..8adb1ff7 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -18,6 +18,7 @@ Proto2 Python primary authors: Petar Petrov Large code contributions: + Jason Hsueh Joseph Schorr Wenbo Zhu @@ -38,7 +39,7 @@ Patch contributors: Kevin Ko * Small patch to handle trailing slashes in --proto_path flag. Johan Euphrosine - * Small patch to fix Pyhton CallMethod(). + * Small patch to fix Python CallMethod(). Ulrich Kunitz * Small optimizations to Python serialization. Leandro Lucarella diff --git a/Makefile.am b/Makefile.am index c7aadc60..afdfff09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,8 @@ EXTRA_DIST = \ examples/add_person.py \ examples/list_people.py \ java/src/main/java/com/google/protobuf/AbstractMessage.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/ByteString.java \ java/src/main/java/com/google/protobuf/CodedInputStream.java \ java/src/main/java/com/google/protobuf/CodedOutputStream.java \ @@ -77,6 +79,7 @@ EXTRA_DIST = \ java/src/main/java/com/google/protobuf/RpcController.java \ java/src/main/java/com/google/protobuf/RpcUtil.java \ java/src/main/java/com/google/protobuf/Service.java \ + java/src/main/java/com/google/protobuf/ServiceException.java \ java/src/main/java/com/google/protobuf/TextFormat.java \ java/src/main/java/com/google/protobuf/UninitializedMessageException.java \ java/src/main/java/com/google/protobuf/UnknownFieldSet.java \ diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java index 24c32a47..53175cdd 100644 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -32,6 +32,7 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.FieldDescriptor; +import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; @@ -152,6 +153,13 @@ public abstract class AbstractMessage implements Message { codedOutput.flush(); } + public void writeDelimitedTo(OutputStream output) throws IOException { + CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + codedOutput.writeRawVarint32(getSerializedSize()); + writeTo(codedOutput); + codedOutput.flush(); + } + private int memoizedSize = -1; public int getSerializedSize() { @@ -207,7 +215,8 @@ public abstract class AbstractMessage implements Message { if (getDescriptorForType() != otherMessage.getDescriptorForType()) { return false; } - return getAllFields().equals(otherMessage.getAllFields()); + return getAllFields().equals(otherMessage.getAllFields()) && + getUnknownFields().equals(otherMessage.getUnknownFields()); } @Override @@ -215,6 +224,7 @@ public abstract class AbstractMessage implements Message { int hash = 41; hash = (19 * hash) + getDescriptorForType().hashCode(); hash = (53 * hash) + getAllFields().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); return hash; } @@ -397,5 +407,51 @@ public abstract class AbstractMessage implements Message { codedInput.checkLastTagWas(0); return (BuilderType) this; } + + public BuilderType mergeDelimitedFrom(InputStream input, + ExtensionRegistry extensionRegistry) + throws IOException { + final int size = CodedInputStream.readRawVarint32(input); + + // A stream which will not read more than |size| bytes. + InputStream limitedInput = new FilterInputStream(input) { + int limit = size; + + @Override + public int available() throws IOException { + return Math.min(super.available(), limit); + } + + @Override + public int read() throws IOException { + if (limit <= 0) return -1; + int result = super.read(); + if (result >= 0) --limit; + return result; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (limit <= 0) return -1; + len = Math.min(len, limit); + int result = super.read(b, off, len); + if (result >= 0) limit -= result; + return result; + } + + @Override + public long skip(long n) throws IOException { + long result = super.skip(Math.min(n, limit)); + if (result >= 0) limit -= result; + return result; + } + }; + return mergeFrom(limitedInput, extensionRegistry); + } + + public BuilderType mergeDelimitedFrom(InputStream input) + throws IOException { + return mergeDelimitedFrom(input, ExtensionRegistry.getEmptyRegistry()); + } } } diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java new file mode 100644 index 00000000..1e81143a --- /dev/null +++ b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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; + +/** + *

Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel} + * is the blocking equivalent to {@link RpcChannel}. + * + * @author kenton@google.com Kenton Varda + * @author cpovirk@google.com Chris Povirk + */ +public interface BlockingRpcChannel { + /** + * Call the given method of the remote service and blocks until it returns. + * {@code callBlockingMethod()} is the blocking equivalent to + * {@link RpcChannel#callMethod}. + */ + Message callBlockingMethod( + Descriptors.MethodDescriptor method, + RpcController controller, + Message request, + Message responsePrototype) throws ServiceException; +} diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/src/main/java/com/google/protobuf/BlockingService.java new file mode 100644 index 00000000..ecc80096 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/BlockingService.java @@ -0,0 +1,64 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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; + +/** + * Blocking equivalent to {@link Service}. + * + * @author kenton@google.com Kenton Varda + * @author cpovirk@google.com Chris Povirk + */ +public interface BlockingService { + /** + * Equivalent to {@link Service#getDescriptorForType}. + */ + Descriptors.ServiceDescriptor getDescriptorForType(); + + /** + * Equivalent to {@link Service#callMethod}, except that + * {@code callBlockingMethod()} returns the result of the RPC or throws a + * {@link ServiceException} if there is a failure, rather than passing the + * information to a callback. + */ + Message callBlockingMethod(Descriptors.MethodDescriptor method, + RpcController controller, + Message request) throws ServiceException; + + /** + * Equivalent to {@link Service#getRequestPrototype}. + */ + Message getRequestPrototype(Descriptors.MethodDescriptor method); + + /** + * Equivalent to {@link Service#getResponsePrototype}. + */ + Message getResponsePrototype(Descriptors.MethodDescriptor method); +} diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java index 8f277a9f..b6be2e87 100644 --- a/java/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java @@ -77,7 +77,7 @@ public final class CodedInputStream { * may legally end wherever a tag occurs, and zero is not a valid tag number. */ public int readTag() throws IOException { - if (bufferPos == bufferSize && !refillBuffer(false)) { + if (isAtEnd()) { lastTag = 0; return 0; } @@ -383,6 +383,39 @@ public final class CodedInputStream { return result; } + /** + * Reads a varint from the input one byte at a time, so that it does not + * read any bytes after the end of the varint. If you simply wrapped the + * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)} + * then you would probably end up reading past the end of the varint since + * CodedInputStream buffers its input. + */ + static int readRawVarint32(InputStream input) throws IOException { + int result = 0; + int offset = 0; + for (; offset < 32; offset += 7) { + int b = input.read(); + if (b == -1) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + result |= (b & 0x7f) << offset; + if ((b & 0x80) == 0) { + return result; + } + } + // Keep reading up to 64 bits. + for (; offset < 64; offset += 7) { + int b = input.read(); + if (b == -1) { + throw InvalidProtocolBufferException.truncatedMessage(); + } + if ((b & 0x80) == 0) { + return result; + } + } + throw InvalidProtocolBufferException.malformedVarint(); + } + /** Read a raw Varint from the stream. */ public long readRawVarint64() throws IOException { int shift = 0; @@ -526,6 +559,10 @@ public final class CodedInputStream { * size limits only apply when reading from an {@code InputStream}, not * when constructed around a raw byte array (nor with * {@link ByteString#newCodedInput}). + *

+ * If you want to read several messages from a single CodedInputStream, you + * could call {@link #resetSizeCounter()} after each one to avoid hitting the + * size limit. * * @return the old limit. */ @@ -539,6 +576,13 @@ public final class CodedInputStream { return oldLimit; } + /** + * Resets the current size counter to zero (see {@link #setSizeLimit(int)}). + */ + public void resetSizeCounter() { + totalBytesRetired = 0; + } + /** * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This * is called when descending into a length-delimited embedded message. @@ -596,6 +640,15 @@ public final class CodedInputStream { return currentLimit - currentAbsolutePosition; } + /** + * Returns true if the stream has reached the end of the input. This is the + * case if either the end of the underlying input source has been reached or + * if the stream has reached a limit created using {@link #pushLimit(int)}. + */ + public boolean isAtEnd() throws IOException { + return bufferPos == bufferSize && !refillBuffer(false); + } + /** * Called with {@code this.buffer} is empty to read more bytes from the * input. If {@code mustSucceed} is true, refillBuffer() gurantees that @@ -622,6 +675,11 @@ public final class CodedInputStream { bufferPos = 0; bufferSize = (input == null) ? -1 : input.read(buffer); + if (bufferSize == 0 || bufferSize < -1) { + throw new IllegalStateException( + "InputStream#read(byte[]) returned invalid result: " + bufferSize + + "\nThe InputStream implementation is buggy."); + } if (bufferSize == -1) { bufferSize = 0; if (mustSucceed) { @@ -778,7 +836,7 @@ public final class CodedInputStream { throw InvalidProtocolBufferException.truncatedMessage(); } - if (size < bufferSize - bufferPos) { + if (size <= bufferSize - bufferPos) { // We have all the bytes we need already. bufferPos += size; } else { diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index 80266a59..24499efb 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -1689,7 +1689,7 @@ public final class Descriptors { GenericDescriptor old = descriptorsByName.put(fullName, - new PackageDescriptor(fullName, name, file)); + new PackageDescriptor(name, fullName, file)); if (old != null) { descriptorsByName.put(fullName, old); if (!(old instanceof PackageDescriptor)) { diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java index 99ae253c..59fb7b02 100644 --- a/java/src/main/java/com/google/protobuf/DynamicMessage.java +++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java @@ -260,7 +260,8 @@ public final class DynamicMessage extends AbstractMessage { } public DynamicMessage build() { - if (!isInitialized()) { + // If fields == null, we'll throw an appropriate exception later. + if (fields != null && !isInitialized()) { throw new UninitializedMessageException( new DynamicMessage(type, fields, unknownFields)); } @@ -282,6 +283,10 @@ public final class DynamicMessage extends AbstractMessage { } public DynamicMessage buildPartial() { + if (fields == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } fields.makeImmutable(); DynamicMessage result = new DynamicMessage(type, fields, unknownFields); diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java index 2f8700db..a5951232 100644 --- a/java/src/main/java/com/google/protobuf/Message.java +++ b/java/src/main/java/com/google/protobuf/Message.java @@ -183,9 +183,28 @@ public interface Message { * Serializes the message and writes it to {@code output}. This is just a * trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does * not flush or close the stream. + *

+ * NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write + * any more data to the stream after the message, you must somehow ensure + * that the parser on the receiving end does not interpret this as being + * part of the protocol message. This can be done e.g. by writing the size + * of the message before the data, then making sure to limit the input to + * that size on the receiving end (e.g. by wrapping the InputStream in one + * which limits the input). Alternatively, just use + * {@link #writeDelimitedTo(OutputStream)}. */ void writeTo(OutputStream output) throws IOException; + /** + * Like {@link #writeTo(OutputStream)}, but writes the size of the message + * as a varint before writing the data. This allows more data to be written + * to the stream after the message without the need to delimit the message + * data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or + * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)}) + * to parse messages written by this method. + */ + void writeDelimitedTo(OutputStream output) throws IOException; + // ================================================================= // Builders @@ -434,8 +453,11 @@ public interface Message { * {@link #mergeFrom(CodedInputStream)}. Note that this method always * reads the entire input (unless it throws an exception). If you * want it to stop earlier, you will need to wrap your input in some - * wrapper stream that limits reading. Despite usually reading the entire - * input, this does not close the stream. + * wrapper stream that limits reading. Or, use + * {@link Message#writeDelimitedTo(OutputStream)} to write your message and + * {@link #mergeDelimitedFrom(InputStream)} to read it. + *

+ * Despite usually reading the entire input, this does not close the stream. */ Builder mergeFrom(InputStream input) throws IOException; @@ -447,5 +469,22 @@ public interface Message { Builder mergeFrom(InputStream input, ExtensionRegistry extensionRegistry) throws IOException; + + /** + * Like {@link #mergeFrom(InputStream)}, but does not read until EOF. + * Instead, the size of the message (encoded as a varint) is read first, + * then the message data. Use + * {@link Message#writeDelimitedTo(OutputStream)} to write messages in this + * format. + */ + Builder mergeDelimitedFrom(InputStream input) + throws IOException; + + /** + * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions. + */ + Builder mergeDelimitedFrom(InputStream input, + ExtensionRegistry extensionRegistry) + throws IOException; } } diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/src/main/java/com/google/protobuf/RpcUtil.java index a11b0437..8144bbfb 100644 --- a/java/src/main/java/com/google/protobuf/RpcUtil.java +++ b/java/src/main/java/com/google/protobuf/RpcUtil.java @@ -39,7 +39,7 @@ public final class RpcUtil { private RpcUtil() {} /** - * Take an {@code RcpCallabck} and convert it to an + * Take an {@code RpcCallback} and convert it to an * {@code RpcCallback} accepting a specific message type. This is always * type-safe (parameter type contravariance). */ @@ -58,8 +58,8 @@ public final class RpcUtil { } /** - * Take an {@code RcpCallabck} accepting a specific message type and convert - * it to an {@code RcpCallabck}. The generalized callback will + * Take an {@code RpcCallback} accepting a specific message type and convert + * it to an {@code RpcCallback}. The generalized callback will * accept any message object which has the same descriptor, and will convert * it to the correct class before calling the original callback. However, * if the generalized callback is given a message with a different descriptor, diff --git a/java/src/main/java/com/google/protobuf/ServiceException.java b/java/src/main/java/com/google/protobuf/ServiceException.java new file mode 100644 index 00000000..70b9d0c1 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/ServiceException.java @@ -0,0 +1,42 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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; + +/** + * Thrown by blocking RPC methods when a failure occurs. + * + * @author cpovirk@google.com (Chris Povirk) + */ +public final class ServiceException extends Exception { + public ServiceException(String message) { + super(message); + } +} diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java index 445951b0..77fef323 100644 --- a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -34,6 +34,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.TreeMap; import java.util.List; @@ -85,6 +86,20 @@ public final class UnknownFieldSet { } private Map fields; + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + return (other instanceof UnknownFieldSet) && + this.fields.equals(((UnknownFieldSet) other).fields); + } + + @Override + public int hashCode() { + return this.fields.hashCode(); + } + /** Get a map of fields in the set by number. */ public Map asMap() { return fields; @@ -540,6 +555,36 @@ public final class UnknownFieldSet { */ public List getGroupList() { return group; } + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof Field)) { + return false; + } + return Arrays.equals(this.getIdentityArray(), + ((Field) other).getIdentityArray()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(getIdentityArray()); + } + + /** + * Returns the array of objects to be used to uniquely identify this + * {@link UnknownFieldSet.Field} instance. + */ + private Object[] getIdentityArray() { + return new Object[] { + this.varint, + this.fixed32, + this.fixed64, + this.lengthDelimited, + this.group}; + } + /** * Serializes the field, including field number, and writes it to * {@code output}. diff --git a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java index da073561..2c59fd0d 100644 --- a/java/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -30,14 +30,14 @@ package com.google.protobuf; +import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.ForeignMessage; -import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequiredForeign; -import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; import junit.framework.TestCase; @@ -329,7 +329,7 @@ public class AbstractMessageTest extends TestCase { // ----------------------------------------------------------------- // Tests for equals and hashCode - public void testEqualsAndHashCode() { + public void testEqualsAndHashCode() throws Exception { TestAllTypes a = TestUtil.getAllSet(); TestAllTypes b = TestAllTypes.newBuilder().build(); TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build(); @@ -337,7 +337,7 @@ public class AbstractMessageTest extends TestCase { TestAllExtensions e = TestUtil.getAllExtensionsSet(); TestAllExtensions f = TestAllExtensions.newBuilder(e) .addExtension(UnittestProto.repeatedInt32Extension, 999).build(); - + checkEqualsIsConsistent(a); checkEqualsIsConsistent(b); checkEqualsIsConsistent(c); @@ -364,10 +364,25 @@ public class AbstractMessageTest extends TestCase { checkNotEqual(d, f); checkNotEqual(e, f); + + // Deserializing into the TestEmptyMessage such that every field + // is an {@link UnknownFieldSet.Field}. + UnittestProto.TestEmptyMessage eUnknownFields = + UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); + UnittestProto.TestEmptyMessage fUnknownFields = + UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray()); + checkNotEqual(eUnknownFields, fUnknownFields); + checkEqualsIsConsistent(eUnknownFields); + checkEqualsIsConsistent(fUnknownFields); + + // Subseqent reconstitutions should be identical + UnittestProto.TestEmptyMessage eUnknownFields2 = + UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); + checkEqualsIsConsistent(eUnknownFields, eUnknownFields2); } /** - * Asserts that the given protos are equal and have the same hash code. + * Asserts that the given proto has symetric equals and hashCode methods. */ private void checkEqualsIsConsistent(Message message) { // Object should be equal to itself. @@ -375,9 +390,16 @@ public class AbstractMessageTest extends TestCase { // Object should be equal to a dynamic copy of itself. DynamicMessage dynamic = DynamicMessage.newBuilder(message).build(); - assertEquals(message, dynamic); - assertEquals(dynamic, message); - assertEquals(dynamic.hashCode(), message.hashCode()); + checkEqualsIsConsistent(message, dynamic); + } + + /** + * Asserts that the given protos are equal and have the same hash code. + */ + private void checkEqualsIsConsistent(Message message1, Message message2) { + assertEquals(message1, message2); + assertEquals(message2, message1); + assertEquals(message2.hashCode(), message1.hashCode()); } /** diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java index eaaddf44..850b8aa7 100644 --- a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -95,6 +95,7 @@ public class CodedInputStreamTest extends TestCase { input = CodedInputStream.newInstance(data); assertEquals(value, input.readRawVarint64()); + assertTrue(input.isAtEnd()); // Try different block sizes. for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { @@ -105,7 +106,17 @@ public class CodedInputStreamTest extends TestCase { input = CodedInputStream.newInstance( new SmallBlockInputStream(data, blockSize)); assertEquals(value, input.readRawVarint64()); + assertTrue(input.isAtEnd()); } + + // Try reading direct from an InputStream. We want to verify that it + // doesn't read past the end of the input, so we copy to a new, bigger + // array first. + byte[] longerData = new byte[data.length + 1]; + System.arraycopy(data, 0, longerData, 0, data.length); + InputStream rawInput = new ByteArrayInputStream(longerData); + assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput)); + assertEquals(1, rawInput.available()); } /** @@ -131,6 +142,14 @@ public class CodedInputStreamTest extends TestCase { } catch (InvalidProtocolBufferException e) { assertEquals(expected.getMessage(), e.getMessage()); } + + // Make sure we get the same error when reading direct from an InputStream. + try { + CodedInputStream.readRawVarint32(new ByteArrayInputStream(data)); + fail("Should have thrown an exception."); + } catch (InvalidProtocolBufferException e) { + assertEquals(expected.getMessage(), e.getMessage()); + } } /** Tests readRawVarint32() and readRawVarint64(). */ @@ -180,12 +199,14 @@ public class CodedInputStreamTest extends TestCase { throws Exception { CodedInputStream input = CodedInputStream.newInstance(data); assertEquals(value, input.readRawLittleEndian32()); + assertTrue(input.isAtEnd()); // Try different block sizes. for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { input = CodedInputStream.newInstance( new SmallBlockInputStream(data, blockSize)); assertEquals(value, input.readRawLittleEndian32()); + assertTrue(input.isAtEnd()); } } @@ -197,12 +218,14 @@ public class CodedInputStreamTest extends TestCase { throws Exception { CodedInputStream input = CodedInputStream.newInstance(data); assertEquals(value, input.readRawLittleEndian64()); + assertTrue(input.isAtEnd()); // Try different block sizes. for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { input = CodedInputStream.newInstance( new SmallBlockInputStream(data, blockSize)); assertEquals(value, input.readRawLittleEndian64()); + assertTrue(input.isAtEnd()); } } @@ -288,6 +311,20 @@ public class CodedInputStreamTest extends TestCase { } } + /** + * Test that a bug in skipRawBytes() has been fixed: if the skip skips + * exactly up to a limit, this should not break things. + */ + public void testSkipRawBytesBug() throws Exception { + byte[] rawBytes = new byte[] { 1, 2 }; + CodedInputStream input = CodedInputStream.newInstance(rawBytes); + + int limit = input.pushLimit(1); + input.skipRawBytes(1); + input.popLimit(limit); + assertEquals(2, input.readRawByte()); + } + public void testReadHugeBlob() throws Exception { // Allocate and initialize a 1MB blob. byte[] blob = new byte[1 << 20]; @@ -392,6 +429,30 @@ public class CodedInputStreamTest extends TestCase { } } + public void testResetSizeCounter() throws Exception { + CodedInputStream input = CodedInputStream.newInstance( + new SmallBlockInputStream(new byte[256], 8)); + input.setSizeLimit(16); + input.readRawBytes(16); + + try { + input.readRawByte(); + fail("Should have thrown an exception!"); + } catch (InvalidProtocolBufferException e) { + // success. + } + + input.resetSizeCounter(); + input.readRawByte(); // No exception thrown. + + try { + input.readRawBytes(16); // Hits limit again. + fail("Should have thrown an exception!"); + } catch (InvalidProtocolBufferException e) { + // success. + } + } + /** * Tests that if we read an string that contains invalid UTF-8, no exception * is thrown. Instead, the invalid bytes are replaced with the Unicode diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java index fc53c531..120b0f13 100644 --- a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -61,6 +61,18 @@ public class DynamicMessageTest extends TestCase { reflectionTester.assertAllFieldsSetViaReflection(message); } + public void testDoubleBuildError() throws Exception { + Message.Builder builder = + DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); + builder.build(); + try { + builder.build(); + fail("Should have thrown exception."); + } catch (IllegalStateException e) { + // Success. + } + } + public void testDynamicMessageSettersRejectNull() throws Exception { Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 04ba769e..58d82193 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -71,6 +71,17 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertAllFieldsSet(message); } + public void testDoubleBuildError() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + builder.build(); + try { + builder.build(); + fail("Should have thrown exception."); + } catch (IllegalStateException e) { + // Success. + } + } + public void testSettersRejectNull() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); try { diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java index 6a747f48..d8523ea3 100644 --- a/java/src/test/java/com/google/protobuf/ServiceTest.java +++ b/java/src/test/java/com/google/protobuf/ServiceTest.java @@ -30,6 +30,10 @@ package com.google.protobuf; +import com.google.protobuf.Descriptors.MethodDescriptor; +import protobuf_unittest.MessageWithNoOuter; +import protobuf_unittest.ServiceWithNoOuter; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestService; import protobuf_unittest.UnittestProto.FooRequest; import protobuf_unittest.UnittestProto.FooResponse; @@ -56,6 +60,7 @@ public class ServiceTest extends TestCase { private final Descriptors.MethodDescriptor barDescriptor = TestService.getDescriptor().getMethods().get(1); + @Override protected void setUp() throws Exception { super.setUp(); control = EasyMock.createStrictControl(); @@ -127,6 +132,94 @@ public class ServiceTest extends TestCase { control.verify(); } + /** Tests generated blocking stubs. */ + public void testBlockingStub() throws Exception { + FooRequest fooRequest = FooRequest.newBuilder().build(); + BarRequest barRequest = BarRequest.newBuilder().build(); + BlockingRpcChannel mockChannel = + control.createMock(BlockingRpcChannel.class); + TestService.BlockingInterface stub = + TestService.newBlockingStub(mockChannel); + + FooResponse fooResponse = FooResponse.newBuilder().build(); + BarResponse barResponse = BarResponse.newBuilder().build(); + + EasyMock.expect(mockChannel.callBlockingMethod( + EasyMock.same(fooDescriptor), + EasyMock.same(mockController), + EasyMock.same(fooRequest), + EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse); + EasyMock.expect(mockChannel.callBlockingMethod( + EasyMock.same(barDescriptor), + EasyMock.same(mockController), + EasyMock.same(barRequest), + EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse); + control.replay(); + + assertSame(fooResponse, stub.foo(mockController, fooRequest)); + assertSame(barResponse, stub.bar(mockController, barRequest)); + control.verify(); + } + + public void testNewReflectiveService() { + ServiceWithNoOuter.Interface impl = + control.createMock(ServiceWithNoOuter.Interface.class); + RpcController controller = control.createMock(RpcController.class); + Service service = ServiceWithNoOuter.newReflectiveService(impl); + + MethodDescriptor fooMethod = + ServiceWithNoOuter.getDescriptor().findMethodByName("Foo"); + MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); + RpcCallback callback = new RpcCallback() { + public void run(Message parameter) { + // No reason this should be run. + fail(); + } + }; + RpcCallback specializedCallback = + RpcUtil.specializeCallback(callback); + + impl.foo(EasyMock.same(controller), EasyMock.same(request), + EasyMock.same(specializedCallback)); + EasyMock.expectLastCall(); + + control.replay(); + + service.callMethod(fooMethod, controller, request, callback); + + control.verify(); + } + + public void testNewReflectiveBlockingService() throws ServiceException { + ServiceWithNoOuter.BlockingInterface impl = + control.createMock(ServiceWithNoOuter.BlockingInterface.class); + RpcController controller = control.createMock(RpcController.class); + BlockingService service = + ServiceWithNoOuter.newReflectiveBlockingService(impl); + + MethodDescriptor fooMethod = + ServiceWithNoOuter.getDescriptor().findMethodByName("Foo"); + MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); + RpcCallback callback = new RpcCallback() { + public void run(Message parameter) { + // No reason this should be run. + fail(); + } + }; + + TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance(); + EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request))) + .andReturn(expectedResponse); + + control.replay(); + + Message response = + service.callBlockingMethod(fooMethod, controller, request); + assertEquals(expectedResponse, response); + + control.verify(); + } + // ================================================================= /** @@ -135,7 +228,7 @@ public class ServiceTest extends TestCase { * In other words, c wraps the given callback. */ private RpcCallback wrapsCallback( - MockCallback callback) { + MockCallback callback) { EasyMock.reportMatcher(new WrapsCallback(callback)); return null; } @@ -153,9 +246,9 @@ public class ServiceTest extends TestCase { /** Implementation of the wrapsCallback() argument matcher. */ private static class WrapsCallback implements IArgumentMatcher { - private MockCallback callback; + private MockCallback callback; - public WrapsCallback(MockCallback callback) { + public WrapsCallback(MockCallback callback) { this.callback = callback; } diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java index 212b381f..ea088b32 100644 --- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java +++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java @@ -31,13 +31,13 @@ package com.google.protobuf; import protobuf_unittest.UnittestProto; -import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; -import protobuf_unittest.UnittestProto. - TestEmptyMessageWithExtensions; +import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions; import junit.framework.TestCase; + import java.util.Arrays; import java.util.Map; @@ -341,4 +341,97 @@ public class UnknownFieldSetTest extends TestCase { assertEquals(1, field.getVarintList().size()); assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0)); } + + public void testEqualsAndHashCode() { + UnknownFieldSet.Field fixed32Field = + UnknownFieldSet.Field.newBuilder() + .addFixed32(1) + .build(); + UnknownFieldSet.Field fixed64Field = + UnknownFieldSet.Field.newBuilder() + .addFixed64(1) + .build(); + UnknownFieldSet.Field varIntField = + UnknownFieldSet.Field.newBuilder() + .addVarint(1) + .build(); + UnknownFieldSet.Field lengthDelimitedField = + UnknownFieldSet.Field.newBuilder() + .addLengthDelimited(ByteString.EMPTY) + .build(); + UnknownFieldSet.Field groupField = + UnknownFieldSet.Field.newBuilder() + .addGroup(unknownFields) + .build(); + + UnknownFieldSet a = + UnknownFieldSet.newBuilder() + .addField(1, fixed32Field) + .build(); + UnknownFieldSet b = + UnknownFieldSet.newBuilder() + .addField(1, fixed64Field) + .build(); + UnknownFieldSet c = + UnknownFieldSet.newBuilder() + .addField(1, varIntField) + .build(); + UnknownFieldSet d = + UnknownFieldSet.newBuilder() + .addField(1, lengthDelimitedField) + .build(); + UnknownFieldSet e = + UnknownFieldSet.newBuilder() + .addField(1, groupField) + .build(); + + checkEqualsIsConsistent(a); + checkEqualsIsConsistent(b); + checkEqualsIsConsistent(c); + checkEqualsIsConsistent(d); + checkEqualsIsConsistent(e); + + checkNotEqual(a, b); + checkNotEqual(a, c); + checkNotEqual(a, d); + checkNotEqual(a, e); + checkNotEqual(b, c); + checkNotEqual(b, d); + checkNotEqual(b, e); + checkNotEqual(c, d); + checkNotEqual(c, e); + checkNotEqual(d, e); + } + + /** + * Asserts that the given field sets are not equal and have different + * hash codes. + * + * @warning It's valid for non-equal objects to have the same hash code, so + * this test is stricter than it needs to be. However, this should happen + * relatively rarely. + */ + private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) { + String equalsError = String.format("%s should not be equal to %s", s1, s2); + assertFalse(equalsError, s1.equals(s2)); + assertFalse(equalsError, s2.equals(s1)); + + assertFalse( + String.format("%s should have a different hash code from %s", s1, s2), + s1.hashCode() == s2.hashCode()); + } + + /** + * Asserts that the given field sets are equal and have identical hash codes. + */ + private void checkEqualsIsConsistent(UnknownFieldSet set) { + // Object should be equal to itself. + assertEquals(set, set); + + // Object should be equal to a copy of itself. + UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build(); + assertEquals(set, copy); + assertEquals(copy, set); + assertEquals(set.hashCode(), copy.hashCode()); + } } diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 48453faf..4afefdb6 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -31,6 +31,10 @@ package com.google.protobuf; import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; @@ -130,6 +134,22 @@ public class WireFormatTest extends TestCase { TestUtil.getAllExtensionsSet().getSerializedSize()); } + public void testSerializeDelimited() throws Exception { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + TestUtil.getAllSet().writeDelimitedTo(output); + output.write(12); + TestUtil.getPackedSet().writeDelimitedTo(output); + output.write(34); + + ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); + + TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input)); + assertEquals(12, input.read()); + TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input)); + assertEquals(34, input.read()); + assertEquals(-1, input.read()); + } + private void assertFieldsInOrder(ByteString data) throws Exception { CodedInputStream input = data.newCodedInput(); int previousTag = 0; diff --git a/python/google/protobuf/internal/input_stream.py b/python/google/protobuf/internal/input_stream.py index 2cff93db..7bda17e3 100755 --- a/python/google/protobuf/internal/input_stream.py +++ b/python/google/protobuf/internal/input_stream.py @@ -36,6 +36,7 @@ the InputStream primitives provided here. __author__ = 'robinson@google.com (Will Robinson)' +import array import struct from google.protobuf import message from google.protobuf.internal import wire_format @@ -46,7 +47,7 @@ from google.protobuf.internal import wire_format # proto2 implementation. -class InputStream(object): +class InputStreamBuffer(object): """Contains all logic for reading bits, and dealing with stream position. @@ -223,3 +224,115 @@ class InputStream(object): shift += 7 if not (b & 0x80): return result + + +class InputStreamArray(object): + + """Contains all logic for reading bits, and dealing with stream position. + + If an InputStream method ever raises an exception, the stream is left + in an indeterminate state and is not safe for further use. + + This alternative to InputStreamBuffer is used in environments where buffer() + is unavailble, such as Google App Engine. + """ + + def __init__(self, s): + self._buffer = array.array('B', s) + self._pos = 0 + + def EndOfStream(self): + return self._pos >= len(self._buffer) + + def Position(self): + return self._pos + + def GetSubBuffer(self, size=None): + if size is None: + return self._buffer[self._pos : ].tostring() + else: + if size < 0: + raise message.DecodeError('Negative size %d' % size) + return self._buffer[self._pos : self._pos + size].tostring() + + def SkipBytes(self, num_bytes): + if num_bytes < 0: + raise message.DecodeError('Negative num_bytes %d' % num_bytes) + self._pos += num_bytes + self._pos = min(self._pos, len(self._buffer)) + + def ReadBytes(self, size): + if size < 0: + raise message.DecodeError('Negative size %d' % size) + s = self._buffer[self._pos : self._pos + size].tostring() + self._pos += len(s) # Only advance by the number of bytes actually read. + return s + + def ReadLittleEndian32(self): + try: + i = struct.unpack(wire_format.FORMAT_UINT32_LITTLE_ENDIAN, + self._buffer[self._pos : self._pos + 4]) + self._pos += 4 + return i[0] # unpack() result is a 1-element tuple. + except struct.error, e: + raise message.DecodeError(e) + + def ReadLittleEndian64(self): + try: + i = struct.unpack(wire_format.FORMAT_UINT64_LITTLE_ENDIAN, + self._buffer[self._pos : self._pos + 8]) + self._pos += 8 + return i[0] # unpack() result is a 1-element tuple. + except struct.error, e: + raise message.DecodeError(e) + + def ReadVarint32(self): + i = self.ReadVarint64() + if not wire_format.INT32_MIN <= i <= wire_format.INT32_MAX: + raise message.DecodeError('Value out of range for int32: %d' % i) + return int(i) + + def ReadVarUInt32(self): + i = self.ReadVarUInt64() + if i > wire_format.UINT32_MAX: + raise message.DecodeError('Value out of range for uint32: %d' % i) + return i + + def ReadVarint64(self): + i = self.ReadVarUInt64() + if i > wire_format.INT64_MAX: + i -= (1 << 64) + return i + + def ReadVarUInt64(self): + i = self._ReadVarintHelper() + if not 0 <= i <= wire_format.UINT64_MAX: + raise message.DecodeError('Value out of range for uint64: %d' % i) + return i + + def _ReadVarintHelper(self): + result = 0 + shift = 0 + while 1: + if shift >= 64: + raise message.DecodeError('Too many bytes when decoding varint.') + try: + b = self._buffer[self._pos] + except IndexError: + raise message.DecodeError('Truncated varint.') + self._pos += 1 + result |= ((b & 0x7f) << shift) + shift += 7 + if not (b & 0x80): + return result + + +try: + buffer('') + InputStream = InputStreamBuffer +except NotImplementedError: + # Google App Engine: dev_appserver.py + InputStream = InputStreamArray +except RuntimeError: + # Google App Engine: production + InputStream = InputStreamArray diff --git a/python/google/protobuf/internal/input_stream_test.py b/python/google/protobuf/internal/input_stream_test.py index 8cc1d126..ecec7f7d 100755 --- a/python/google/protobuf/internal/input_stream_test.py +++ b/python/google/protobuf/internal/input_stream_test.py @@ -40,7 +40,14 @@ from google.protobuf.internal import wire_format from google.protobuf.internal import input_stream -class InputStreamTest(unittest.TestCase): +class InputStreamBufferTest(unittest.TestCase): + + def setUp(self): + self.__original_input_stream = input_stream.InputStream + input_stream.InputStream = input_stream.InputStreamBuffer + + def tearDown(self): + input_stream.InputStream = self.__original_input_stream def testEndOfStream(self): stream = input_stream.InputStream('abcd') @@ -291,5 +298,17 @@ class InputStreamTest(unittest.TestCase): stream = input_stream.InputStream(s) self.assertRaises(message.DecodeError, stream.ReadVarUInt64) + +class InputStreamArrayTest(InputStreamBufferTest): + + def setUp(self): + # Test InputStreamArray against the same tests in InputStreamBuffer + self.__original_input_stream = input_stream.InputStream + input_stream.InputStream = input_stream.InputStreamArray + + def tearDown(self): + input_stream.InputStream = self.__original_input_stream + + if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 1d88c1cc..e2da769a 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -1102,6 +1102,15 @@ class FullProtosEqualityTest(unittest.TestCase): test_util.SetAllFields(self.first_proto) test_util.SetAllFields(self.second_proto) + def testNoneNotEqual(self): + self.assertNotEqual(self.first_proto, None) + self.assertNotEqual(None, self.second_proto) + + def testNotEqualToOtherMessage(self): + third_proto = unittest_pb2.TestRequired() + self.assertNotEqual(self.first_proto, third_proto) + self.assertNotEqual(third_proto, self.second_proto) + def testAllFieldsFilledEquality(self): self.assertEqual(self.first_proto, self.second_proto) diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py index f345067a..5ab7a1b1 100755 --- a/python/google/protobuf/reflection.py +++ b/python/google/protobuf/reflection.py @@ -599,6 +599,10 @@ def _AddHasExtensionMethod(cls): def _AddEqualsMethod(message_descriptor, cls): """Helper for _AddMessageMethods().""" def __eq__(self, other): + if (not isinstance(other, message_mod.Message) or + other.DESCRIPTOR != self.DESCRIPTOR): + return False + if self is other: return True diff --git a/src/Makefile.am b/src/Makefile.am index c12d3b9b..9206d094 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,6 +35,7 @@ MAINTAINERCLEANFILES = \ nobase_include_HEADERS = \ google/protobuf/stubs/common.h \ + google/protobuf/stubs/once.h \ google/protobuf/descriptor.h \ google/protobuf/descriptor.pb.h \ google/protobuf/descriptor_database.h \ @@ -69,6 +70,7 @@ libprotobuf_la_LIBADD = $(PTHREAD_LIBS) libprotobuf_la_LDFLAGS = -version-info 3:0:0 libprotobuf_la_SOURCES = \ google/protobuf/stubs/common.cc \ + google/protobuf/stubs/once.cc \ google/protobuf/stubs/hash.cc \ google/protobuf/stubs/hash.h \ google/protobuf/stubs/map-util.cc \ @@ -161,6 +163,7 @@ protoc_SOURCES = google/protobuf/compiler/main.cc protoc_inputs = \ google/protobuf/unittest.proto \ + google/protobuf/unittest_empty.proto \ google/protobuf/unittest_import.proto \ google/protobuf/unittest_mset.proto \ google/protobuf/unittest_optimize_for.proto \ @@ -184,6 +187,8 @@ EXTRA_DIST = \ protoc_outputs = \ google/protobuf/unittest.pb.cc \ google/protobuf/unittest.pb.h \ + google/protobuf/unittest_empty.pb.cc \ + google/protobuf/unittest_empty.pb.h \ google/protobuf/unittest_import.pb.cc \ google/protobuf/unittest_import.pb.h \ google/protobuf/unittest_mset.pb.cc \ @@ -223,6 +228,7 @@ protobuf_test_CPPFLAGS = -I$(top_srcdir)/gtest/include \ -I$(top_builddir)/gtest/include protobuf_test_SOURCES = \ google/protobuf/stubs/common_unittest.cc \ + google/protobuf/stubs/once_unittest.cc \ google/protobuf/stubs/strutil_unittest.cc \ google/protobuf/stubs/structurally_valid_unittest.cc \ google/protobuf/descriptor_database_unittest.cc \ diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 77e50332..875cbef8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -100,6 +100,19 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n" "\n"); + + // The _Name and _Parse methods + printer->Print(vars, + "inline const ::std::string& $classname$_Name($classname$ value) {\n" + " return ::google::protobuf::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); + printer->Print(vars, + "inline bool $classname$_Parse(\n" + " const ::std::string& name, $classname$* value) {\n" + " return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n" + " $classname$_descriptor(), name, value);\n" + "}\n"); } void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { @@ -122,6 +135,13 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { "static inline bool $nested_name$_IsValid(int value) {\n" " return $classname$_IsValid(value);\n" "}\n" + "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" + " return $classname$_Name(value);\n" + "}\n" + "static inline bool $nested_name$_Parse(const ::std::string& name,\n" + " $nested_name$* value) {\n" + " return $classname$_Parse(name, value);\n" + "}\n" "static const $nested_name$ $nested_name$_MIN =\n" " $classname$_$nested_name$_MIN;\n" "static const $nested_name$ $nested_name$_MAX =\n" @@ -147,12 +167,10 @@ void EnumGenerator::GenerateDescriptorInitializer( void EnumGenerator::GenerateMethods(io::Printer* printer) { map vars; vars["classname"] = classname_; - vars["builddescriptorsname"] = - GlobalBuildDescriptorsName(descriptor_->file()->name()); printer->Print(vars, "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" - " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "bool $classname$_IsValid(int value) {\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index a78bf887..b90eb372 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -116,8 +116,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void EnumFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_($default$)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); } void EnumFieldGenerator:: @@ -128,15 +128,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "if ($type$_IsValid(value)) {\n" " set_$name$(static_cast< $type$ >(value));\n" "} else {\n" - " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n" "}\n"); } void EnumFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::WriteEnum(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::WriteEnum(" + "$number$, this->$name$(), output);\n"); +} + +void EnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(" + "$number$, this->$name$(), target);\n"); } void EnumFieldGenerator:: @@ -217,12 +224,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); - if (descriptor_->options().packed() && - descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { - printer->Print(variables_, ",\n_$name$_cached_byte_size_()"); - } +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedEnumFieldGenerator:: @@ -248,7 +251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" "} else {\n" - " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n" "}\n"); } } @@ -259,22 +262,51 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" - " DO_(::google::protobuf::internal::WireFormat::WriteTag(" - "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," - "output));\n" - " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + " ::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::WriteEnumNoTag(" + "this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::WriteEnum(" + "$number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormat::WriteTagToArray(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" + "_$name$_cached_byte_size_, target);\n" "}\n"); } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); if (descriptor_->options().packed()) { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::WriteEnumNoTag(" - "this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::WriteEnumNoTagToArray(" + "this->$name$(i), target);\n"); } else { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::WriteEnum(" - "$number$, this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(" + "$number$, this->$name$(i), target);\n"); } printer->Print("}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index f67b7ac0..20dd57bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -56,9 +56,10 @@ class EnumFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: @@ -80,9 +81,10 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 3f212b93..61ebda73 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -36,6 +36,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -55,7 +56,9 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, case FieldDescriptor::CPPTYPE_ENUM: type_traits_.append("EnumTypeTraits< "); type_traits_.append(ClassName(descriptor_->enum_type(), true)); - type_traits_.append(" >"); + type_traits_.append(", "); + type_traits_.append(ClassName(descriptor_->enum_type(), true)); + type_traits_.append("_IsValid>"); break; case FieldDescriptor::CPPTYPE_STRING: type_traits_.append("StringTypeTraits"); @@ -81,6 +84,8 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; vars["name" ] = descriptor_->name(); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; vars["constant_name"] = FieldConstantName(descriptor_); // If this is a class member, it needs to be declared "static". Otherwise, @@ -95,19 +100,39 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { printer->Print(vars, "static const int $constant_name$ = $number$;\n" "$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$ > $name$;\n"); + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$;\n" + ); } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { + // If this is a class member, it needs to be declared in its class scope. + string scope = (descriptor_->extension_scope() == NULL) ? "" : + ClassName(descriptor_->extension_scope(), false) + "::"; + string name = scope + descriptor_->name(); + map vars; vars["extendee" ] = ClassName(descriptor_->containing_type(), true); vars["type_traits" ] = type_traits_; - vars["name" ] = descriptor_->name(); + vars["name" ] = name; vars["constant_name"] = FieldConstantName(descriptor_); - - // If this is a class member, it needs to be declared in its class scope. - vars["scope"] = (descriptor_->extension_scope() == NULL) ? "" : - ClassName(descriptor_->extension_scope(), false) + "::"; + vars["default" ] = DefaultValue(descriptor_); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; + vars["scope" ] = scope; + + if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + // We need to declare a global string which will contain the default value. + // We cannot declare it at class scope because that would require exposing + // it in the header which would be annoying for other reasons. So we + // replace :: with _ in the name and declare it as a global. + string global_name = StringReplace(name, "::", "_", true); + vars["global_name"] = global_name; + printer->Print(vars, + "const ::std::string $global_name$_default($default$);\n"); + // Update the default to refer to the string global. + vars["default"] = global_name + "_default"; + } // Likewise, class members need to declare the field constant variable. if (descriptor_->extension_scope() != NULL) { @@ -119,8 +144,46 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { printer->Print(vars, "::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" - " ::google::protobuf::internal::$type_traits$ > $scope$$name$(" - "$constant_name$);\n"); + " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" + " $name$($constant_name$, $default$);\n"); +} + +void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { + map vars; + vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["number" ] = SimpleItoa(descriptor_->number()); + vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); + vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; + vars["is_packed" ] = (descriptor_->is_repeated() && + descriptor_->options().packed()) + ? "true" : "false"; + + switch (descriptor_->cpp_type()) { + case FieldDescriptor::CPPTYPE_ENUM: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$_IsValid);\n", + "type", ClassName(descriptor_->enum_type(), true)); + break; + case FieldDescriptor::CPPTYPE_MESSAGE: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$,\n"); + printer->Print( + " &$type$::default_instance());\n", + "type", ClassName(descriptor_->message_type(), true)); + break; + default: + printer->Print(vars, + "::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" + " &$extendee$::default_instance(),\n" + " $number$, $field_type$, $is_repeated$, $is_packed$);\n"); + break; + } } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index a9e58c18..3068b091 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -66,6 +66,9 @@ class ExtensionGenerator { // Source file stuff. void GenerateDefinition(io::Printer* printer); + // Generate code to register the extension. + void GenerateRegistration(io::Printer* printer); + private: const FieldDescriptor* descriptor_; string type_traits_; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index e5f8258f..7e7c7f83 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -94,16 +94,13 @@ class FieldGenerator { // message.cc under the GenerateSwap method. virtual void GenerateSwappingCode(io::Printer* printer) const = 0; - // Generate any initializers needed for the private members declared by - // GeneratePrivateMembers(). These go into the message class's - // constructor's initializer list. For each initializer, this method - // must print the comma and newline separating it from the *previous* - // initializer, not the *next* initailizer. That is, print a ",\n" first, - // e.g.: - // printer->Print(",\n$name$_($default$)"); - virtual void GenerateInitializer(io::Printer* printer) const = 0; - - // Generate any code that needs to go in the class's destructor. + // Generate initialization code for private members declared by + // GeneratePrivateMembers(). These go into the message class's SharedCtor() + // method, invoked by each of the generated constructors. + virtual void GenerateConstructorCode(io::Printer* printer) const = 0; + + // Generate any code that needs to go in the class's SharedDtor() method, + // invoked by the destructor. // Most field types don't need this, so the default implementation is empty. virtual void GenerateDestructorCode(io::Printer* printer) const {} @@ -115,6 +112,12 @@ class FieldGenerator { // message's SerializeWithCachedSizes() method. virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; + // Generate lines to serialize this field directly to the array "target", + // which are placed within the message's SerializeWithCachedSizesToArray() + // method. This must also advance "target" past the written bytes. + virtual void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const = 0; + // Generate lines to compute the serialized size of this field, which // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 6487979f..dcc48552 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -143,17 +143,20 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Open namespace. GenerateNamespaceOpeners(printer); - // Forward-declare the AssignGlobalDescriptors function, so that we can - // declare it to be a friend of each class. + // Forward-declare the AddDescriptors and AssignDescriptors 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$ $builddescriptorsname$();\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(\n" - " ::google::protobuf::FileDescriptor* file);\n" - "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "void $dllexport_decl$ $adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "dllexport_decl", dllexport_decl_); + printer->Print( + // Note that we don't put dllexport_decl on this because it is only called + // by the .pb.cc file in which it is defined. + "void $assigndescriptorsname$();\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); // Generate forward declarations of classes. for (int i = 0; i < file_->message_type_count(); i++) { @@ -232,6 +235,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "\n" "#include \"$basename$.pb.h\"\n" + "#include \n" "#include \n" "#include \n" "#include \n" @@ -296,23 +300,46 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { - // BuildDescriptors() is a file-level procedure which initializes all of - // the Descriptor objects for this file. It runs the first time one of the - // descriptors is accessed. This will always be at static initialization - // time, because every message has a statically-initialized default instance, - // and the constructor for a message class accesses its descriptor. See the - // constructor and the descriptor() method of message classes. + // AddDescriptors() is a file-level procedure which adds the encoded + // FileDescriptorProto for this .proto file to the global DescriptorPool + // for generated files (DescriptorPool::generated_pool()). It always runs + // at static initialization time, so all files will be registered before + // main() starts. This procedure also constructs default instances and + // registers extensions. // - // We also construct the reflection object for each class inside - // BuildDescriptors(). + // Its sibling, AssignDescriptors(), actually pulls the compiled + // FileDescriptor from the DescriptorPool and uses it to populate all of + // the global variables which store pointers to the descriptor objects. + // It also constructs the reflection objects. It is called the first time + // anyone calls descriptor() or GetReflection() on one of the types defined + // in the file. - // First we generate a method to assign the global descriptors. printer->Print( "\n" - "void $builddescriptorsname$_AssignGlobalDescriptors(" - "const ::google::protobuf::FileDescriptor* file) {\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "void $assigndescriptorsname$() {\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); printer->Indent(); + + // Make sure the file has found its way into the pool. If a descriptor + // is requested *during* static init then AddDescriptors() may not have + // been called yet, so we call it manually. Note that it's fine if + // AddDescriptors() is called multiple times. + printer->Print( + "$adddescriptorsname$();\n", + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + + // Get the file's descriptor from the pool. + printer->Print( + "const ::google::protobuf::FileDescriptor* file =\n" + " ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n" + " \"$filename$\");\n" + // Note that this GOOGLE_CHECK is necessary to prevent a warning about "file" + // being unused when compiling an empty .proto file. + "GOOGLE_CHECK(file != NULL);\n", + "filename", file_->name()); + + // Go through all the stuff defined in this file and generated code to + // assign the global descriptor pointers based on the file descriptor. for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->GenerateDescriptorInitializer(printer, i); } @@ -322,29 +349,63 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->service_count(); i++) { service_generators_[i]->GenerateDescriptorInitializer(printer, i); } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + // ----------------------------------------------------------------- + + // protobuf_AssignDescriptorsOnce(): The first time it is called, calls + // AssignDescriptors(). All later times, waits for the first call to + // complete and then returns. + printer->Print( + "namespace {\n" + "\n" + "GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" + "inline void protobuf_AssignDescriptorsOnce() {\n" + " ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" + " &$assigndescriptorsname$);\n" + "}\n" + "\n", + "assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); + + // protobuf_RegisterTypes(): Calls + // MessageFactory::InternalRegisterGeneratedType() for each message type. + printer->Print( + "void protobuf_RegisterTypes() {\n" + " protobuf_AssignDescriptorsOnce();\n"); + printer->Indent(); + for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + message_generators_[i]->GenerateTypeRegistrations(printer); } printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "\n" + "} // namespace\n"); + // ----------------------------------------------------------------- + + // Now generate the AddDescriptors() function. printer->Print( "\n" - "void $builddescriptorsname$() {\n" + "void $adddescriptorsname$() {\n" + // We don't need any special synchronization here because this code is + // called at static init time before any threads exist. " static bool already_here = false;\n" " if (already_here) return;\n" " already_here = true;\n" " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - " ::google::protobuf::DescriptorPool* pool =\n" - " ::google::protobuf::DescriptorPool::internal_generated_pool();\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); printer->Indent(); - // Call the BuildDescriptors() methods for all of our dependencies, to make - // sure they get initialized first. + // Call the AddDescriptors() methods for all of our dependencies, to make + // sure they get added first. for (int i = 0; i < file_->dependency_count(); i++) { const FileDescriptor* dependency = file_->dependency(i); // Print the namespace prefix for the dependency. @@ -355,10 +416,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { printer->Print("$name$::", "name", dependency_package_parts[i]); } - // Call its BuildDescriptors function. + // Call its AddDescriptors function. printer->Print( "$name$();\n", - "name", GlobalBuildDescriptorsName(dependency->name())); + "name", GlobalAddDescriptorsName(dependency->name())); } // Embed the descriptor. We simply serialize the entire FileDescriptorProto @@ -370,7 +431,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { file_proto.SerializeToString(&file_data); printer->Print( - "pool->InternalBuildGeneratedFile("); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); // Only write 40 bytes per line. static const int kBytesPerLine = 40; @@ -379,24 +440,41 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", CEscape(file_data.substr(i, kBytesPerLine))); } printer->Print( - ", $size$,\n" - "&$builddescriptorsname$_AssignGlobalDescriptors);\n", - "size", SimpleItoa(file_data.size()), - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name())); + ", $size$);\n", + "size", SimpleItoa(file_data.size())); + + // Call MessageFactory::InternalRegisterGeneratedFile(). + printer->Print( + "::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" + " \"$filename$\", &protobuf_RegisterTypes);\n", + "filename", file_->name()); + + // Allocate and initialize default instances. This can't be done lazily + // since default instances are returned by simple accessors and are used with + // extensions. Speaking of which, we also register extensions at this time. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } + for (int i = 0; i < file_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->GenerateDefaultInstanceInitializer(printer); + } printer->Outdent(); printer->Print( "}\n" "\n" - "// Force BuildDescriptors() to be called at static initialization time.\n" + "// Force AddDescriptors() to be called at static initialization time.\n" "struct StaticDescriptorInitializer_$filename$ {\n" " StaticDescriptorInitializer_$filename$() {\n" - " $builddescriptorsname$();\n" + " $adddescriptorsname$();\n" " }\n" "} static_descriptor_initializer_$filename$_;\n" "\n", - "builddescriptorsname", GlobalBuildDescriptorsName(file_->name()), + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename", FilenameIdentifier(file_->name())); } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index d536bea4..214daff9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -38,6 +38,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -213,6 +214,41 @@ const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { return ""; } +string DefaultValue(const FieldDescriptor* field) { + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + return SimpleItoa(field->default_value_uint32()) + "u"; + case FieldDescriptor::CPPTYPE_INT64: + return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; + case FieldDescriptor::CPPTYPE_UINT64: + return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return SimpleDtoa(field->default_value_double()); + case FieldDescriptor::CPPTYPE_FLOAT: + return SimpleFtoa(field->default_value_float()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + // Lazy: Generate a static_cast because we don't have a helper function + // that constructs the full name of an enum value. + return strings::Substitute( + "static_cast< $0 >($1)", + ClassName(field->enum_type(), true), + field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: + return "\"" + CEscape(field->default_value_string()) + "\""; + case FieldDescriptor::CPPTYPE_MESSAGE: + return ClassName(field->message_type(), true) + "::default_instance()"; + } + // Can't actually get here; make compiler happy. (We could add a default + // case above but then we wouldn't get the nice compiler warning when a + // new type is added.) + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + // Convert a file name into a valid identifier. string FilenameIdentifier(const string& filename) { string result; @@ -230,9 +266,14 @@ string FilenameIdentifier(const string& filename) { return result; } -// Return the name of the BuildDescriptors() function for a given file. -string GlobalBuildDescriptorsName(const string& filename) { - return "protobuf_BuildDesc_" + FilenameIdentifier(filename); +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename) { + return "protobuf_AddDesc_" + FilenameIdentifier(filename); +} + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename) { + return "protobuf_AssignDesc_" + FilenameIdentifier(filename); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 30c6e7d0..2260a934 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -90,11 +90,17 @@ const char* PrimitiveTypeName(FieldDescriptor::CppType type); // methods of WireFormat. For example, TYPE_INT32 becomes "Int32". const char* DeclaredTypeMethodName(FieldDescriptor::Type type); +// Get code that evaluates to the field's default value. +string DefaultValue(const FieldDescriptor* field); + // Convert a file name into a valid identifier. string FilenameIdentifier(const string& filename); -// Return the name of the BuildDescriptors() function for a given file. -string GlobalBuildDescriptorsName(const string& filename); +// Return the name of the AddDescriptors() function for a given file. +string GlobalAddDescriptorsName(const string& filename); + +// Return the name of the AssignDescriptors() function for a given file. +string GlobalAssignDescriptorsName(const string& filename); } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 2ec49234..44546bd0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -223,104 +223,10 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (descriptor_->extension_range_count() > 0) { - // Generate accessors for extensions. - - // Normally I'd generate prototypes here and generate the actual - // definitions of these methods in GenerateFieldAccessorDefinitions, but - // the prototypes for these silly methods are so absurdly complicated that - // it meant way too much repitition. - // - // We use "_proto_TypeTraits" as a type name below because "TypeTraits" - // causes problems if the class has a nested message or enum type with that - // name and "_TypeTraits" is technically reserved for the C++ library since - // it starts with an underscore followed by a capital letter. + // Generate accessors for extensions. We just call a macro located in + // extension_set.h since the accessors about 80 lines of static code. printer->Print( - // Has, Size, Clear - "template \n" - "inline bool HasExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _extensions_.Has(id.number());\n" - "}\n" - "\n" - "template \n" - "inline void ClearExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " _extensions_.ClearExtension(id.number());\n" - "}\n" - "\n" - "template \n" - "inline int ExtensionSize(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _extensions_.ExtensionSize(id.number());\n" - "}\n" - "\n" - - // Singular accessors - "template \n" - "inline typename _proto_TypeTraits::ConstType GetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) const {\n" - " return _proto_TypeTraits::Get(id.number(), _extensions_);\n" - "}\n" - "\n" - "template \n" - "inline typename _proto_TypeTraits::MutableType MutableExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " return _proto_TypeTraits::Mutable(id.number(), &_extensions_);\n" - "}\n" - "\n" - "template \n" - "inline void SetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Set(id.number(), value, &_extensions_);\n" - "}\n" - "\n" - - // Repeated accessors - "template \n" - "inline typename _proto_TypeTraits::ConstType GetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index) const {\n" - " return _proto_TypeTraits::Get(id.number(), _extensions_, index);\n" - "}\n" - "\n" - "template \n" - "inline typename _proto_TypeTraits::MutableType MutableExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index) {\n" - " return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_);\n" - "}\n" - "\n" - "template \n" - "inline void SetExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " int index, typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Set(id.number(), index, value, &_extensions_);\n" - "}\n" - "\n" - "template \n" - "inline typename _proto_TypeTraits::MutableType AddExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id) {\n" - " return _proto_TypeTraits::Add(id.number(), &_extensions_);\n" - "}\n" - "\n" - "template \n" - "inline void AddExtension(\n" - " const ::google::protobuf::internal::ExtensionIdentifier<\n" - " $classname$, _proto_TypeTraits>& id,\n" - " typename _proto_TypeTraits::ConstType value) {\n" - " _proto_TypeTraits::Add(id.number(), value, &_extensions_);\n" - "}\n", + "GOOGLE_PROTOBUF_EXTENSION_ACCESSORS($classname$)\n", "classname", classname_); } } @@ -391,8 +297,6 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = dllexport_decl_ + " "; } - vars["builddescriptorsname"] = - GlobalBuildDescriptorsName(descriptor_->file()->name()); printer->Print(vars, "class $dllexport$$classname$ : public ::google::protobuf::Message {\n" @@ -433,18 +337,30 @@ GenerateClassDefinition(io::Printer* printer) { "void CopyFrom(const $classname$& from);\n" "void MergeFrom(const $classname$& from);\n" "void Clear();\n" - "bool IsInitialized() const;\n" - "int ByteSize() const;\n" - "\n" - "bool MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input);\n" - "bool SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const;\n"); + "bool IsInitialized() const;\n"); + + if (!descriptor_->options().message_set_wire_format()) { + // For message_set_wire_format, we don't generate parsing or + // serialization code even if optimize_for = SPEED, since MessageSet + // encoding is somewhat more complicated than normal extension encoding + // and we'd like to avoid having to implement it in multiple places. + // WireFormat's implementation is probably good enough. + printer->Print(vars, + "\n" + "int ByteSize() const;\n" + "bool MergePartialFromCodedStream(\n" + " ::google::protobuf::io::CodedInputStream* input);\n" + "void SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const;\n" + "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n"); + } } printer->Print(vars, "int GetCachedSize() const { return _cached_size_; }\n" "private:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" "void SetCachedSize(int size) const { _cached_size_ = size; }\n" "public:\n" "\n" @@ -505,11 +421,17 @@ GenerateClassDefinition(io::Printer* printer) { .GeneratePrivateMembers(printer); } - // Generate offsets and _has_bits_ boilerplate. - printer->Print(vars, - "friend void $builddescriptorsname$_AssignGlobalDescriptors(\n" - " const ::google::protobuf::FileDescriptor* file);\n"); + // Declare AddDescriptors() and BuildDescriptors() as friends so that they + // can assign private static variables like default_instance_ and reflection_. + printer->Print( + "friend void $adddescriptorsname$();\n" + "friend void $assigndescriptorsname$();\n", + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name()), + "assigndescriptorsname", + GlobalAssignDescriptorsName(descriptor_->file()->name())); + // Generate offsets and _has_bits_ boilerplate. if (descriptor_->field_count() > 0) { printer->Print(vars, "::google::protobuf::uint32 _has_bits_[($field_count$ + 31) / 32];\n"); @@ -592,12 +514,6 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { "$parent$_descriptor_->nested_type($index$);\n"); } - // Construct the default instance. We can't call InitAsDefaultInstance() yet - // because we need to make sure all default instances that this one might - // depend on are constructed first. - printer->Print(vars, - "$classname$::default_instance_ = new $classname$();\n"); - // Generate the offsets. GenerateOffsets(printer); @@ -622,6 +538,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { } printer->Print(vars, " ::google::protobuf::DescriptorPool::generated_pool(),\n" + " ::google::protobuf::MessageFactory::generated_factory(),\n" " sizeof($classname$));\n"); // Handle nested types. @@ -632,11 +549,35 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { for (int i = 0; i < descriptor_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } +} +void MessageGenerator:: +GenerateTypeRegistrations(io::Printer* printer) { // Register this message type with the message factory. - printer->Print(vars, + printer->Print( "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n" - " $classname$_descriptor_, $classname$::default_instance_);\n"); + " $classname$_descriptor_, &$classname$::default_instance());\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateTypeRegistrations(printer); + } +} + +void MessageGenerator:: +GenerateDefaultInstanceAllocator(io::Printer* printer) { + // Construct the default instance. We can't call InitAsDefaultInstance() yet + // because we need to make sure all default instances that this one might + // depend on are constructed first. + printer->Print( + "$classname$::default_instance_ = new $classname$();\n", + "classname", classname_); + + // Handle nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); + } } void MessageGenerator:: @@ -645,6 +586,11 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) { "$classname$::default_instance_->InitAsDefaultInstance();\n", "classname", classname_); + // Register extensions. + for (int i = 0; i < descriptor_->extension_count(); i++) { + extension_generators_[i]->GenerateRegistration(printer); + } + // Handle nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateDefaultInstanceInitializer(printer); @@ -695,14 +641,24 @@ GenerateClassMethods(io::Printer* printer) { GenerateClear(printer); printer->Print("\n"); - GenerateMergeFromCodedStream(printer); - printer->Print("\n"); + if (!descriptor_->options().message_set_wire_format()) { + // For message_set_wire_format, we don't generate parsing or + // serialization code even if optimize_for = SPEED, since MessageSet + // encoding is somewhat more complicated than normal extension encoding + // and we'd like to avoid having to implement it in multiple places. + // WireFormat's implementation is probably good enough. + GenerateMergeFromCodedStream(printer); + printer->Print("\n"); - GenerateSerializeWithCachedSizes(printer); - printer->Print("\n"); + GenerateSerializeWithCachedSizes(printer); + printer->Print("\n"); - GenerateByteSize(printer); - printer->Print("\n"); + GenerateSerializeWithCachedSizesToArray(printer); + printer->Print("\n"); + + GenerateByteSize(printer); + printer->Print("\n"); + } GenerateMergeFrom(printer); printer->Print("\n"); @@ -723,12 +679,10 @@ GenerateClassMethods(io::Printer* printer) { "}\n" "\n" "const ::google::protobuf::Reflection* $classname$::GetReflection() const {\n" - " if ($classname$_reflection_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_reflection_;\n" "}\n", - "classname", classname_, - "builddescriptorsname", - GlobalBuildDescriptorsName(descriptor_->file()->name())); + "classname", classname_); } void MessageGenerator:: @@ -757,28 +711,68 @@ GenerateInitializerList(io::Printer* printer) { printer->Indent(); printer->Print( - "::google::protobuf::Message(),\n"); + "::google::protobuf::Message()"); - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "_extensions_(&$classname$_descriptor_,\n" - " ::google::protobuf::DescriptorPool::generated_pool(),\n" - " ::google::protobuf::MessageFactory::generated_factory()),\n", - "classname", classname_); - } + printer->Outdent(); + printer->Outdent(); +} + +void MessageGenerator:: +GenerateSharedConstructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedCtor() {\n", + "classname", classname_); + printer->Indent(); printer->Print( - "_unknown_fields_(),\n" - "_cached_size_(0)"); + "_cached_size_ = 0;\n"); - // Write the initializers for each field. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) - .GenerateInitializer(printer); + .GenerateConstructorCode(printer); } + printer->Print( + "::memset(_has_bits_, 0, sizeof(_has_bits_));\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void MessageGenerator:: +GenerateSharedDestructorCode(io::Printer* printer) { + printer->Print( + "void $classname$::SharedDtor() {\n", + "classname", classname_); + printer->Indent(); + // Write the destructors for each field. + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateDestructorCode(printer); + } + + printer->Print( + "if (this != default_instance_) {\n"); + + // We need to delete all embedded messages. + // TODO(kenton): If we make unset messages point at default instances + // instead of NULL, then it would make sense to move this code into + // MessageFieldGenerator::GenerateDestructorCode(). + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer->Print(" delete $name$_;\n", + "name", FieldName(field)); + } + } + printer->Outdent(); + printer->Print( + " }\n" + "}\n" + "\n"); } void MessageGenerator:: @@ -790,7 +784,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); GenerateInitializerList(printer); printer->Print(" {\n" - " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n" + " SharedCtor();\n" "}\n"); printer->Print( @@ -826,54 +820,33 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); GenerateInitializerList(printer); printer->Print(" {\n" - " ::memset(_has_bits_, 0, sizeof(_has_bits_));\n" + " SharedCtor();\n" " MergeFrom(from);\n" "}\n" "\n"); + // Generate the shared constructor code. + GenerateSharedConstructorCode(printer); + // Generate the destructor. printer->Print( - "$classname$::~$classname$() {\n", + "$classname$::~$classname$() {\n" + " SharedDtor();\n" + "}\n" + "\n", "classname", classname_); - printer->Indent(); - - // Write the destructors for each field. - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(descriptor_->field(i)) - .GenerateDestructorCode(printer); - } + // Generate the shared destructor code. + GenerateSharedDestructorCode(printer); printer->Print( - "if (this != default_instance_) {\n"); - - // We need to delete all embedded messages. - // TODO(kenton): If we make unset messages point at default instances - // instead of NULL, then it would make sense to move this code into - // MessageFieldGenerator::GenerateDestructorCode(). - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - if (!field->is_repeated() && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - printer->Print(" delete $name$_;\n", - "name", FieldName(field)); - } - } - - printer->Outdent(); - - printer->Print( - " }\n" - "}\n" - "\n" "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" - " if ($classname$_descriptor_ == NULL) $builddescriptorsname$();\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "\n" "const $classname$& $classname$::default_instance() {\n" - " if (default_instance_ == NULL) $builddescriptorsname$();\n" + " if (default_instance_ == NULL) $adddescriptorsname$();" " return *default_instance_;\n" "}\n" "\n" @@ -883,8 +856,8 @@ GenerateStructors(io::Printer* printer) { " return new $classname$;\n" "}\n", "classname", classname_, - "builddescriptorsname", - GlobalBuildDescriptorsName(descriptor_->file()->name())); + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); } void MessageGenerator:: @@ -1127,24 +1100,6 @@ GenerateCopyFrom(io::Printer* printer) { void MessageGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) { - if (descriptor_->options().message_set_wire_format()) { - // For message_set_wire_format, we don't generate a parser, for two - // reasons: - // - WireFormat already needs to special-case this, and we'd like to - // avoid having multiple implementations of MessageSet wire format - // lying around the code base. - // - All fields are extensions, and extension parsing falls back to - // reflection anyway, so it wouldn't be any faster. - printer->Print( - "bool $classname$::MergePartialFromCodedStream(\n" - " ::google::protobuf::io::CodedInputStream* input) {\n" - " return ::google::protobuf::internal::WireFormat::ParseAndMergePartial(\n" - " input, this);\n" - "}\n", - "classname", classname_); - return; - } - printer->Print( "bool $classname$::MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input) {\n" @@ -1267,7 +1222,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } printer->Print(") {\n" - " DO_(_extensions_.ParseField(tag, input, this));\n" + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " mutable_unknown_fields()));\n" " continue;\n" "}\n"); } @@ -1295,7 +1251,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } void MessageGenerator::GenerateSerializeOneField( - io::Printer* printer, const FieldDescriptor* field) { + io::Printer* printer, const FieldDescriptor* field, bool to_array) { PrintFieldComment(printer, field); if (!field->is_repeated()) { @@ -1305,7 +1261,12 @@ void MessageGenerator::GenerateSerializeOneField( printer->Indent(); } - field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + if (to_array) { + field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( + printer); + } else { + field_generators_.get(field).GenerateSerializeWithCachedSizes(printer); + } if (!field->is_repeated()) { printer->Outdent(); @@ -1315,25 +1276,66 @@ void MessageGenerator::GenerateSerializeOneField( } void MessageGenerator::GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range) { + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool to_array) { map vars; vars["start"] = SimpleItoa(range->start); vars["end"] = SimpleItoa(range->end); printer->Print(vars, - "// Extension range [$start$, $end$)\n" - "DO_(_extensions_.SerializeWithCachedSizes(\n" - " $start$, $end$, *this, output));\n\n"); + "// Extension range [$start$, $end$)\n"); + if (to_array) { + printer->Print(vars, + "target = _extensions_.SerializeWithCachedSizesToArray(\n" + " $start$, $end$, target);\n\n"); + } else { + printer->Print(vars, + "_extensions_.SerializeWithCachedSizes(\n" + " $start$, $end$, output);\n\n"); + } } void MessageGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) { printer->Print( - "bool $classname$::SerializeWithCachedSizes(\n" - " ::google::protobuf::io::CodedOutputStream* output) const {\n" - "#define DO_(EXPRESSION) if (!(EXPRESSION)) return false\n", + "void $classname$::SerializeWithCachedSizes(\n" + " ::google::protobuf::io::CodedOutputStream* output) const {\n", + "classname", classname_); + printer->Indent(); + + printer->Print( + "::google::protobuf::uint8* raw_buffer = " + "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n" + "if (raw_buffer != NULL) {\n" + " $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n" + " return;\n" + "}\n" + "\n", + "classname", classname_); + GenerateSerializeWithCachedSizesBody(printer, false); + + printer->Outdent(); + printer->Print( + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { + printer->Print( + "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n" + " ::google::protobuf::uint8* target) const {\n", "classname", classname_); printer->Indent(); + GenerateSerializeWithCachedSizesBody(printer, true); + + printer->Outdent(); + printer->Print( + " return target;\n" + "}\n"); +} + +void MessageGenerator:: +GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { scoped_array ordered_fields( SortFieldsByNumber(descriptor_)); @@ -1350,35 +1352,35 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { i < descriptor_->field_count() || j < sorted_extensions.size(); ) { if (i == descriptor_->field_count()) { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); } else if (j == sorted_extensions.size()) { - GenerateSerializeOneField(printer, ordered_fields[i++]); + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); } else if (ordered_fields[i]->number() < sorted_extensions[j]->start) { - GenerateSerializeOneField(printer, ordered_fields[i++]); + GenerateSerializeOneField(printer, ordered_fields[i++], to_array); } else { - GenerateSerializeOneExtensionRange(printer, sorted_extensions[j++]); + GenerateSerializeOneExtensionRange(printer, + sorted_extensions[j++], + to_array); } } printer->Print("if (!unknown_fields().empty()) {\n"); printer->Indent(); - if (descriptor_->options().message_set_wire_format()) { + if (to_array) { printer->Print( - "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" - " unknown_fields(), output));\n"); + "target = " + "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n" + " unknown_fields(), target);\n"); } else { printer->Print( - "DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" - " unknown_fields(), output));\n"); + "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n" + " unknown_fields(), output);\n"); } printer->Outdent(); - printer->Print( - "}\n" - "return true;\n"); - printer->Outdent(); printer->Print( - "#undef DO_\n" "}\n"); } @@ -1449,23 +1451,16 @@ GenerateByteSize(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { printer->Print( - "total_size += _extensions_.ByteSize(*this);\n" + "total_size += _extensions_.ByteSize();\n" "\n"); } printer->Print("if (!unknown_fields().empty()) {\n"); printer->Indent(); - if (descriptor_->options().message_set_wire_format()) { - printer->Print( - "total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownMessageSetItemsSize(\n" - " unknown_fields());\n"); - } else { - printer->Print( - "total_size +=\n" - " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" - " unknown_fields());\n"); - } + printer->Print( + "total_size +=\n" + " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n" + " unknown_fields());\n"); printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index d6669a34..31aa1c4c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -86,7 +86,16 @@ class MessageGenerator { // descriptor. void GenerateDescriptorInitializer(io::Printer* printer, int index); - // Generates code that initializes the message's default instance. + // Generate code that calls MessageFactory::InternalRegisterGeneratedMessage() + // for all types. + void GenerateTypeRegistrations(io::Printer* printer); + + // Generates code that allocates the message's default instance. + void GenerateDefaultInstanceAllocator(io::Printer* printer); + + // Generates code that initializes the message's default instance. This + // is separate from allocating because all default instances must be + // allocated before any can be initialized. void GenerateDefaultInstanceInitializer(io::Printer* printer); // Generate all non-inline methods for this class. @@ -103,6 +112,15 @@ class MessageGenerator { // Generate constructors and destructor. void GenerateStructors(io::Printer* printer); + // The compiler typically generates multiple copies of each constructor and + // destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx + // Placing common code in a separate method reduces the generated code size. + // + // Generate the shared constructor code. + void GenerateSharedConstructorCode(io::Printer* printer); + // Generate the shared destructor code. + void GenerateSharedDestructorCode(io::Printer* printer); + // Generate the member initializer list for the constructors. The member // initializer list is shared between the default constructor and the copy // constructor. @@ -112,6 +130,9 @@ class MessageGenerator { void GenerateClear(io::Printer* printer); void GenerateMergeFromCodedStream(io::Printer* printer); void GenerateSerializeWithCachedSizes(io::Printer* printer); + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); + void GenerateSerializeWithCachedSizesBody(io::Printer* printer, + bool to_array); void GenerateByteSize(io::Printer* printer); void GenerateMergeFrom(io::Printer* printer); void GenerateCopyFrom(io::Printer* printer); @@ -120,9 +141,11 @@ class MessageGenerator { // Helpers for GenerateSerializeWithCachedSizes(). void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field); + const FieldDescriptor* field, + bool unbounded); void GenerateSerializeOneExtensionRange( - io::Printer* printer, const Descriptor::ExtensionRange* range); + io::Printer* printer, const Descriptor::ExtensionRange* range, + bool unbounded); const Descriptor* descriptor_; string classname_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index e2d2370b..2a7eb3f8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -116,8 +116,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void MessageFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_(NULL)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = NULL;\n"); } void MessageFieldGenerator:: @@ -136,8 +136,16 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" + "$number$, this->$name$(), output);\n"); +} + +void MessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoVirtualToArray(" + "$number$, this->$name$(), target);\n"); } void MessageFieldGenerator:: @@ -212,8 +220,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedMessageFieldGenerator:: @@ -233,8 +241,18 @@ void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" - "$number$, this->$name$(i), output));\n" + " ::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual(" + "$number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoVirtualToArray(" + "$number$, this->$name$(i), target);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 7ce4c32b..f5147278 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -56,9 +56,10 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: @@ -80,9 +81,10 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 57244c5d..44d0b97c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -79,35 +79,6 @@ int FixedSize(FieldDescriptor::Type type) { return -1; } -string DefaultValue(const FieldDescriptor* field) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return SimpleItoa(field->default_value_int32()); - case FieldDescriptor::CPPTYPE_UINT32: - return SimpleItoa(field->default_value_uint32()) + "u"; - case FieldDescriptor::CPPTYPE_INT64: - return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; - case FieldDescriptor::CPPTYPE_UINT64: - return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()); - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field->default_value_float()); - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool() ? "true" : "false"; - - case FieldDescriptor::CPPTYPE_ENUM: - case FieldDescriptor::CPPTYPE_STRING: - case FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Shouldn't get here."; - return ""; - } - // Can't actually get here; make compiler happy. (We could add a default - // case above but then we wouldn't get the nice compiler warning when a - // new type is added.) - return ""; -} - // TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of // repeat code between this and the other field types. void SetPrimitiveVariables(const FieldDescriptor* descriptor, @@ -180,8 +151,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void PrimitiveFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_($default$)"); +GenerateConstructorCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); } void PrimitiveFieldGenerator:: @@ -195,8 +166,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(), output);\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray(" + "$number$, this->$name$(), target);\n"); } void PrimitiveFieldGenerator:: @@ -282,12 +260,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); - if (descriptor_->options().packed() && - descriptor_->file()->options().optimize_for() == FileOptions::SPEED) { - printer->Print(variables_, ",\n_$name$_cached_byte_size_()"); - } +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedPrimitiveFieldGenerator:: @@ -324,22 +298,53 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { // Write the tag and the size. printer->Print(variables_, "if (this->$name$_size() > 0) {\n" - " DO_(::google::protobuf::internal::WireFormat::WriteTag(" - "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED," - "output));\n" - " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n" + " ::google::protobuf::internal::WireFormat::WriteTag(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "output);\n" + " output->WriteVarint32(_$name$_cached_byte_size_);\n" + "}\n"); + } + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::Write$declared_type$NoTag(" + "this->$name$(i), output);\n"); + } else { + printer->Print(variables_, + " ::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output);\n"); + } + printer->Print("}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + if (descriptor_->options().packed()) { + // Write the tag and the size. + printer->Print(variables_, + "if (this->$name$_size() > 0) {\n" + " target = ::google::protobuf::internal::WireFormat::WriteTagToArray(" + "$number$, " + "::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED, " + "target);\n" + " target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" + "_$name$_cached_byte_size_, target);\n" "}\n"); } printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); if (descriptor_->options().packed()) { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoTag(" - "this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$NoTagToArray(" + "this->$name$(i), target);\n"); } else { printer->Print(variables_, - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n"); + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$ToArray(" + "$number$, this->$name$(i), target);\n"); } printer->Print("}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index c7f7f310..6b96614c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -56,9 +56,10 @@ class PrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: @@ -80,9 +81,10 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_service.cc b/src/google/protobuf/compiler/cpp/cpp_service.cc index 59dbac1f..7689fa13 100644 --- a/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -176,10 +176,12 @@ void ServiceGenerator::GenerateImplementation(io::Printer* printer) { "$classname$::~$classname$() {}\n" "\n" "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "\n" "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" + " protobuf_AssignDescriptorsOnce();\n" " return $classname$_descriptor_;\n" "}\n" "\n"); @@ -279,7 +281,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, printer->Print(vars_, " const ::google::protobuf::MethodDescriptor* method) const {\n" - " GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" + " GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" " switch(method->index()) {\n"); for (int i = 0; i < descriptor_->method_count(); i++) { @@ -320,7 +322,7 @@ void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { " const $input_type$* request,\n" " $output_type$* response,\n" " ::google::protobuf::Closure* done) {\n" - " channel_->CallMethod($classname$_descriptor_->method($index$),\n" + " channel_->CallMethod(descriptor()->method($index$),\n" " controller, request, response, done);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 8e10e9b0..05858da4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -61,6 +61,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["pointer_type"] = + descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; } } // namespace @@ -111,13 +113,8 @@ GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, "inline const ::std::string& $name$() const;\n" "inline void set_$name$(const ::std::string& value);\n" - "inline void set_$name$(const char* value);\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void set_$name$(const void* value, size_t size);\n"); - } - - printer->Print(variables_, + "inline void set_$name$(const char* value);\n" + "inline void set_$name$(const $pointer_type$* value, size_t size);\n" "inline ::std::string* mutable_$name$();\n"); if (descriptor_->options().has_ctype()) { @@ -146,20 +143,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " $name$_ = new ::std::string;\n" " }\n" " $name$_->assign(value);\n" - "}\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void $classname$::set_$name$(const void* value, size_t size) {\n" - " _set_bit($index$);\n" - " if ($name$_ == &_default_$name$_) {\n" - " $name$_ = new ::std::string;\n" - " }\n" - " $name$_->assign(reinterpret_cast(value), size);\n" - "}\n"); - } - - printer->Print(variables_, + "}\n" + "inline " + "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" + " _set_bit($index$);\n" + " if ($name$_ == &_default_$name$_) {\n" + " $name$_ = new ::std::string;\n" + " }\n" + " $name$_->assign(reinterpret_cast(value), size);\n" + "}\n" "inline ::std::string* $classname$::mutable_$name$() {\n" " _set_bit($index$);\n" " if ($name$_ == &_default_$name$_) {\n"); @@ -213,9 +205,9 @@ GenerateSwappingCode(io::Printer* printer) const { } void StringFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { +GenerateConstructorCode(io::Printer* printer) const { printer->Print(variables_, - ",\n$name$_(const_cast< ::std::string*>(&_default_$name$_))"); + "$name$_ = const_cast< ::std::string*>(&_default_$name$_);\n"); } void StringFieldGenerator:: @@ -236,8 +228,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(), output));\n"); + "::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(), output);\n"); +} + +void StringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "target = ::google::protobuf::internal::WireFormat::Write$declared_type$ToArray(" + "$number$, this->$name$(), target);\n"); } void StringFieldGenerator:: @@ -281,15 +280,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline ::std::string* mutable_$name$(int index);\n" "inline void set_$name$(int index, const ::std::string& value);\n" "inline void set_$name$(int index, const char* value);\n" + "inline " + "void set_$name$(int index, const $pointer_type$* value, size_t size);\n" "inline ::std::string* add_$name$();\n" "inline void add_$name$(const ::std::string& value);\n" - "inline void add_$name$(const char* value);\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void set_$name$(int index, const void* value, size_t size);\n" - "inline void add_$name$(const void* value, size_t size);\n"); - } + "inline void add_$name$(const char* value);\n" + "inline void add_$name$(const $pointer_type$* value, size_t size);\n"); if (descriptor_->options().has_ctype()) { printer->Outdent(); @@ -321,6 +317,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline void $classname$::set_$name$(int index, const char* value) {\n" " $name$_.Mutable(index)->assign(value);\n" "}\n" + "inline void " + "$classname$::set_$name$" + "(int index, const $pointer_type$* value, size_t size) {\n" + " $name$_.Mutable(index)->assign(\n" + " reinterpret_cast(value), size);\n" + "}\n" "inline ::std::string* $classname$::add_$name$() {\n" " return $name$_.Add();\n" "}\n" @@ -329,19 +331,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "inline void $classname$::add_$name$(const char* value) {\n" " $name$_.Add()->assign(value);\n" + "}\n" + "inline void " + "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" + " $name$_.Add()->assign(reinterpret_cast(value), size);\n" "}\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { - printer->Print(variables_, - "inline void " - "$classname$::set_$name$(int index, const void* value, size_t size) {\n" - " $name$_.Mutable(index)->assign(\n" - " reinterpret_cast(value), size);\n" - "}\n" - "inline void $classname$::add_$name$(const void* value, size_t size) {\n" - " $name$_.Add()->assign(reinterpret_cast(value), size);\n" - "}\n"); - } } void RepeatedStringFieldGenerator:: @@ -360,8 +354,8 @@ GenerateSwappingCode(io::Printer* printer) const { } void RepeatedStringFieldGenerator:: -GenerateInitializer(io::Printer* printer) const { - printer->Print(variables_, ",\n$name$_()"); +GenerateConstructorCode(io::Printer* printer) const { + // Not needed for repeated fields. } void RepeatedStringFieldGenerator:: @@ -375,8 +369,18 @@ void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$(" - "$number$, this->$name$(i), output));\n" + " ::google::protobuf::internal::WireFormat::Write$declared_type$(" + "$number$, this->$name$(i), output);\n" + "}\n"); +} + +void RepeatedStringFieldGenerator:: +GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { + printer->Print(variables_, + "for (int i = 0; i < this->$name$_size(); i++) {\n" + " target = ::google::protobuf::internal::WireFormat::" + "Write$declared_type$ToArray(" + "$number$, this->$name$(i), target);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 2244bd77..7f45107d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -57,10 +57,11 @@ class StringFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateDestructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: @@ -82,9 +83,10 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; - void GenerateInitializer(io::Printer* printer) const; + void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; private: diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index c7e4ee3d..ea9cc32d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -52,6 +52,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,6 +63,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -86,6 +89,8 @@ class MockErrorCollector : public MultiFileErrorCollector { } }; +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + // Test that generated code has proper descriptors: // Parse a descriptor directly (using google::protobuf::compiler::Importer) and // compare it to the one that was produced by generated code. @@ -115,6 +120,8 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) { generated_decsriptor_proto.DebugString()); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== TEST(GeneratedMessageTest, Defaults) { @@ -222,6 +229,22 @@ TEST(GeneratedMessageTest, ClearOneField) { TestUtil::ExpectAllFieldsSet(message); } +TEST(GeneratedMessageTest, StringCharStarLength) { + // Verify that we can use a char*,length to set one of the string fields. + unittest::TestAllTypes message; + message.set_optional_string("abcdef", 3); + EXPECT_EQ("abc", message.optional_string()); + + // Verify that we can use a char*,length to add to a repeated string field. + message.add_repeated_string("abcdef", 3); + EXPECT_EQ(1, message.repeated_string_size()); + EXPECT_EQ("abc", message.repeated_string(0)); + + // Verify that we can use a char*,length to set a repeated string field. + message.set_repeated_string(0, "wxyz", 2); + EXPECT_EQ("wx", message.repeated_string(0)); +} + TEST(GeneratedMessageTest, CopyFrom) { unittest::TestAllTypes message1, message2; @@ -346,6 +369,8 @@ TEST(GeneratedMessageTest, UpcastCopyFrom) { TestUtil::ExpectAllFieldsSet(message2); } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { // Test copying from a DynamicMessage, which must fall back to using // reflection. @@ -366,6 +391,8 @@ TEST(GeneratedMessageTest, DynamicMessageCopyFrom) { TestUtil::ExpectAllFieldsSet(message2); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, NonEmptyMergeFrom) { // Test merging with a non-empty message. Code is a modified form // of that found in google/protobuf/reflection_ops_unittest.cc. @@ -403,24 +430,75 @@ TEST(GeneratedMessageTest, MergeFromSelf) { #endif // GTEST_HAS_DEATH_TEST -TEST(GeneratedMessageTest, Serialization) { +// Test the generated SerializeWithCachedSizesToArray(), +TEST(GeneratedMessageTest, SerializationToArray) { unittest::TestAllTypes message1, message2; string data; - TestUtil::SetAllFields(&message1); - message1.SerializeToString(&data); + int size = message1.ByteSize(); + data.resize(size); + uint8* start = reinterpret_cast(string_as_array(&data)); + uint8* end = + message1.TestAllTypes::SerializeWithCachedSizesToArray(start); + EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); TestUtil::ExpectAllFieldsSet(message2); +} +TEST(GeneratedMessageTest, PackedFieldsSerializationToArray) { unittest::TestPackedTypes packed_message1, packed_message2; string packed_data; TestUtil::SetPackedFields(&packed_message1); - packed_message1.SerializeToString(&packed_data); + int packed_size = packed_message1.ByteSize(); + packed_data.resize(packed_size); + uint8* start = reinterpret_cast(string_as_array(&packed_data)); + uint8* end = + packed_message1.TestPackedTypes::SerializeWithCachedSizesToArray(start); + EXPECT_EQ(packed_size, end - start); EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); TestUtil::ExpectPackedFieldsSet(packed_message2); } +// Test the generated SerializeWithCachedSizes() by forcing the buffer to write +// one byte at a time. +TEST(GeneratedMessageTest, SerializationToStream) { + unittest::TestAllTypes message1, message2; + TestUtil::SetAllFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.TestAllTypes::SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(message2); + +} + +TEST(GeneratedMessageTest, PackedFieldsSerializationToStream) { + unittest::TestPackedTypes message1, message2; + TestUtil::SetPackedFields(&message1); + int size = message1.ByteSize(); + string data; + data.resize(size); + { + // Allow the output stream to buffer only one byte at a time. + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.TestPackedTypes::SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); + } + EXPECT_TRUE(message2.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(message2); +} + TEST(GeneratedMessageTest, Required) { // Test that IsInitialized() returns false if required fields are missing. @@ -547,6 +625,8 @@ TEST(GeneratedMessageTest, TestConflictingSymbolNames) { EXPECT_EQ(5, message.friend_()); } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + TEST(GeneratedMessageTest, TestOptimizedForSize) { // We rely on the tests in reflection_ops_unittest and wire_format_unittest // to really test that reflection-based methods work. Here we are mostly @@ -614,6 +694,8 @@ TEST(GeneratedMessageTest, TestSpaceUsed) { message1.SpaceUsed()); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) { @@ -682,8 +764,37 @@ TEST(GeneratedEnumTest, MinAndMax) { } } +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + +TEST(GeneratedEnumTest, Name) { + // "Names" in the presence of dup values are a bit arbitrary. + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO1)); + EXPECT_EQ("FOO1", unittest::TestEnumWithDupValue_Name(unittest::FOO2)); + + EXPECT_EQ("SPARSE_A", unittest::TestSparseEnum_Name(unittest::SPARSE_A)); + EXPECT_EQ("SPARSE_B", unittest::TestSparseEnum_Name(unittest::SPARSE_B)); + EXPECT_EQ("SPARSE_C", unittest::TestSparseEnum_Name(unittest::SPARSE_C)); + EXPECT_EQ("SPARSE_D", unittest::TestSparseEnum_Name(unittest::SPARSE_D)); + EXPECT_EQ("SPARSE_E", unittest::TestSparseEnum_Name(unittest::SPARSE_E)); + EXPECT_EQ("SPARSE_F", unittest::TestSparseEnum_Name(unittest::SPARSE_F)); + EXPECT_EQ("SPARSE_G", unittest::TestSparseEnum_Name(unittest::SPARSE_G)); +} + +TEST(GeneratedEnumTest, Parse) { + unittest::TestEnumWithDupValue dup_value = unittest::FOO1; + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO1", &dup_value)); + EXPECT_EQ(unittest::FOO1, dup_value); + EXPECT_TRUE(unittest::TestEnumWithDupValue_Parse("FOO2", &dup_value)); + EXPECT_EQ(unittest::FOO2, dup_value); + EXPECT_FALSE(unittest::TestEnumWithDupValue_Parse("FOO", &dup_value)); +} + +#endif // PROTOBUF_TEST_NO_DESCRIPTORS + // =================================================================== +#ifndef PROTOBUF_TEST_NO_DESCRIPTORS + // Support code for testing services. class GeneratedServiceTest : public testing::Test { protected: @@ -977,6 +1088,27 @@ TEST_F(GeneratedServiceTest, NotImplemented) { EXPECT_TRUE(controller.called_); } +#endif // !PROTOBUF_TEST_NO_DESCRIPTORS + +// =================================================================== + +// This test must run last. It verifies that descriptors were or were not +// initialized depending on whether PROTOBUF_TEST_NO_DESCRIPTORS was defined. +// When this is defined, we skip all tests which are expected to trigger +// descriptor initialization. This verifies that everything else still works +// if descriptors are not initialized. +TEST(DescriptorInitializationTest, Initialized) { +#ifdef PROTOBUF_TEST_NO_DESCRIPTORS + bool should_have_descriptors = false; +#else + bool should_have_descriptors = true; +#endif + + EXPECT_EQ(should_have_descriptors, + DescriptorPool::generated_pool()->InternalIsFileLoaded( + "google/protobuf/unittest.proto")); +} + } // namespace cpp_unittest } // namespace cpp diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc index 30e106e8..8a07dfc4 100644 --- a/src/google/protobuf/compiler/importer.cc +++ b/src/google/protobuf/compiler/importer.cc @@ -387,9 +387,22 @@ DiskSourceTree::DiskFileToVirtualFile( return SUCCESS; } +bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file, + string* disk_file) { + scoped_ptr stream(OpenVirtualFile(virtual_file, + disk_file)); + return stream != NULL; +} + io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) { - if (filename != CanonicalizePath(filename) || - ContainsParentReference(filename)) { + return OpenVirtualFile(filename, NULL); +} + +io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile( + const string& virtual_file, + string* disk_file) { + if (virtual_file != CanonicalizePath(virtual_file) || + ContainsParentReference(virtual_file)) { // We do not allow importing of paths containing things like ".." or // consecutive slashes since the compiler expects files to be uniquely // identified by file name. @@ -397,16 +410,21 @@ io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) { } for (int i = 0; i < mappings_.size(); i++) { - string disk_file; - if (ApplyMapping(filename, mappings_[i].virtual_path, - mappings_[i].disk_path, &disk_file)) { - io::ZeroCopyInputStream* stream = OpenDiskFile(disk_file); - if (stream != NULL) return stream; + string temp_disk_file; + if (ApplyMapping(virtual_file, mappings_[i].virtual_path, + mappings_[i].disk_path, &temp_disk_file)) { + io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file); + if (stream != NULL) { + if (disk_file != NULL) { + *disk_file = temp_disk_file; + } + return stream; + } if (errno == EACCES) { // The file exists but is not readable. // TODO(kenton): Find a way to report this more nicely. - GOOGLE_LOG(WARNING) << "Read access is denied for file: " << disk_file; + GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file; return NULL; } } diff --git a/src/google/protobuf/compiler/importer.h b/src/google/protobuf/compiler/importer.h index e2177e1c..7a2efc29 100644 --- a/src/google/protobuf/compiler/importer.h +++ b/src/google/protobuf/compiler/importer.h @@ -267,6 +267,11 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree { string* virtual_file, string* shadowing_disk_file); + // Given a virtual path, find the path to the file on disk. + // Return true and update disk_file with the on-disk path if the file exists. + // Return false and leave disk_file untouched if the file doesn't exist. + bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file); + // implements SourceTree ------------------------------------------- io::ZeroCopyInputStream* Open(const string& filename); @@ -280,6 +285,11 @@ class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree { }; vector mappings_; + // Like Open(), but returns the on-disk path in disk_file if disk_file is + // non-NULL and the file could be successfully opened. + io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file, + string* disk_file); + // Like Open() but given the actual on-disk path. io::ZeroCopyInputStream* OpenDiskFile(const string& filename); diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 51aeb90c..56fad56e 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -565,6 +565,34 @@ TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) { EXPECT_EQ("dir5/bar", virtual_file); } +TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) { + // Test VirtualFileToDiskFile. + + AddFile(dirnames_[0] + "/foo", "Hello World!"); + AddFile(dirnames_[1] + "/foo", "This file should be hidden."); + AddFile(dirnames_[1] + "/quux", "This file should not be hidden."); + source_tree_.MapPath("bar", dirnames_[0]); + source_tree_.MapPath("bar", dirnames_[1]); + + // Existent files, shadowed and non-shadowed case. + string disk_file; + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file)); + EXPECT_EQ(dirnames_[0] + "/foo", disk_file); + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file)); + EXPECT_EQ(dirnames_[1] + "/quux", disk_file); + + // Nonexistent file in existent directory and vice versa. + string not_touched = "not touched"; + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", ¬_touched)); + EXPECT_EQ("not touched", not_touched); + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", ¬_touched)); + EXPECT_EQ("not touched", not_touched); + + // Accept NULL as output parameter. + EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL)); + EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL)); +} + } // namespace } // namespace compiler diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index c2e0c115..c9cbd13f 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -466,6 +466,17 @@ GenerateParseFromMethods(io::Printer* printer) { " return newBuilder().mergeFrom(input, extensionRegistry)\n" " .buildParsed();\n" "}\n" + "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" + " throws java.io.IOException {\n" + " return newBuilder().mergeDelimitedFrom(input).buildParsed();\n" + "}\n" + "public static $classname$ parseDelimitedFrom(\n" + " java.io.InputStream input,\n" + " com.google.protobuf.ExtensionRegistry extensionRegistry)\n" + " throws java.io.IOException {\n" + " return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n" + " .buildParsed();\n" + "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" @@ -579,7 +590,8 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { printer->Print( "public $classname$ build() {\n" - " if (!isInitialized()) {\n" + // If result == null, we'll throw an appropriate exception later. + " if (result != null && !isInitialized()) {\n" " throw new com.google.protobuf.UninitializedMessageException(\n" " result);\n" " }\n" @@ -595,7 +607,11 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) { " return buildPartial();\n" "}\n" "\n" - "public $classname$ buildPartial() {\n", + "public $classname$ buildPartial() {\n" + " if (result == null) {\n" + " throw new IllegalStateException(\n" + " \"build() has already been called on this Builder.\");" + " }\n", "classname", ClassName(descriptor_)); printer->Indent(); diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 5308dd20..5545bf7f 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -57,45 +57,111 @@ void ServiceGenerator::Generate(io::Printer* printer) { "classname", descriptor_->name()); printer->Indent(); - // Generate abstract method declarations. - for (int i = 0; i < descriptor_->method_count(); i++) { - const MethodDescriptor* method = descriptor_->method(i); - map vars; - vars["name"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); - vars["output"] = ClassName(method->output_type()); - printer->Print(vars, - "public abstract void $name$(\n" - " com.google.protobuf.RpcController controller,\n" - " $input$ request,\n" - " com.google.protobuf.RpcCallback<$output$> done);\n"); - } + printer->Print( + "protected $classname$() {}\n\n", + "classname", descriptor_->name()); + + GenerateInterface(printer); + + GenerateNewReflectiveServiceMethod(printer); + GenerateNewReflectiveBlockingServiceMethod(printer); + + GenerateAbstractMethods(printer); // Generate getDescriptor() and getDescriptorForType(). printer->Print( - "\n" "public static final\n" " com.google.protobuf.Descriptors.ServiceDescriptor\n" " getDescriptor() {\n" " return $file$.getDescriptor().getServices().get($index$);\n" - "}\n" - "public final com.google.protobuf.Descriptors.ServiceDescriptor\n" - " getDescriptorForType() {\n" - " return getDescriptor();\n" "}\n", "file", ClassName(descriptor_->file()), "index", SimpleItoa(descriptor_->index())); + GenerateGetDescriptorForType(printer); // Generate more stuff. GenerateCallMethod(printer); GenerateGetPrototype(REQUEST, printer); GenerateGetPrototype(RESPONSE, printer); GenerateStub(printer); + GenerateBlockingStub(printer); printer->Outdent(); printer->Print("}\n\n"); } +void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) { + printer->Print( + "public final com.google.protobuf.Descriptors.ServiceDescriptor\n" + " getDescriptorForType() {\n" + " return getDescriptor();\n" + "}\n"); +} + +void ServiceGenerator::GenerateInterface(io::Printer* printer) { + printer->Print("public interface Interface {\n"); + printer->Indent(); + GenerateAbstractMethods(printer); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ServiceGenerator::GenerateNewReflectiveServiceMethod( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.Service newReflectiveService(\n" + " final Interface impl) {\n" + " return new $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + printer->Print("@Override\n"); + GenerateMethodSignature(printer, method, IS_CONCRETE); + printer->Print( + " {\n" + " impl.$method$(controller, request, done);\n" + "}\n\n", + "method", UnderscoresToCamelCase(method)); + } + + printer->Outdent(); + printer->Print("};\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( + io::Printer* printer) { + printer->Print( + "public static com.google.protobuf.BlockingService\n" + " newReflectiveBlockingService(final BlockingInterface impl) {\n" + " return new com.google.protobuf.BlockingService() {\n"); + printer->Indent(); + printer->Indent(); + + GenerateGetDescriptorForType(printer); + + GenerateCallBlockingMethod(printer); + GenerateGetPrototype(REQUEST, printer); + GenerateGetPrototype(RESPONSE, printer); + + printer->Outdent(); + printer->Print("};\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + GenerateMethodSignature(printer, method, IS_ABSTRACT); + printer->Print(";\n\n"); + } +} + void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { printer->Print( "\n" @@ -131,7 +197,49 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { printer->Print( "default:\n" - " throw new java.lang.RuntimeException(\"Can't get here.\");\n"); + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); + + printer->Outdent(); + printer->Outdent(); + + printer->Print( + " }\n" + "}\n" + "\n"); +} + +void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) { + printer->Print( + "\n" + "public final com.google.protobuf.Message callBlockingMethod(\n" + " com.google.protobuf.Descriptors.MethodDescriptor method,\n" + " com.google.protobuf.RpcController controller,\n" + " com.google.protobuf.Message request)\n" + " throws com.google.protobuf.ServiceException {\n" + " if (method.getService() != getDescriptor()) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Service.callBlockingMethod() given method descriptor for \" +\n" + " \"wrong service type.\");\n" + " }\n" + " switch(method.getIndex()) {\n"); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + map vars; + vars["index"] = SimpleItoa(i); + vars["method"] = UnderscoresToCamelCase(method); + vars["input"] = ClassName(method->input_type()); + vars["output"] = ClassName(method->output_type()); + printer->Print(vars, + "case $index$:\n" + " return impl.$method$(controller, ($input$)request);\n"); + } + + printer->Print( + "default:\n" + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); printer->Outdent(); printer->Outdent(); @@ -144,6 +252,10 @@ void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, io::Printer* printer) { + /* + * TODO(cpovirk): The exception message says "Service.foo" when it may be + * "BlockingService.foo." Consider fixing. + */ printer->Print( "public final com.google.protobuf.Message\n" " get$request_or_response$Prototype(\n" @@ -171,7 +283,7 @@ void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, printer->Print( "default:\n" - " throw new java.lang.RuntimeException(\"Can't get here.\");\n"); + " throw new java.lang.AssertionError(\"Can't get here.\");\n"); printer->Outdent(); printer->Outdent(); @@ -189,7 +301,8 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) { " return new Stub(channel);\n" "}\n" "\n" - "public static final class Stub extends $classname$ {\n", + "public static final class Stub extends $classname$ implements Interface {" + "\n", "classname", ClassName(descriptor_)); printer->Indent(); @@ -206,33 +319,125 @@ void ServiceGenerator::GenerateStub(io::Printer* printer) { for (int i = 0; i < descriptor_->method_count(); i++) { const MethodDescriptor* method = descriptor_->method(i); + printer->Print("\n"); + GenerateMethodSignature(printer, method, IS_CONCRETE); + printer->Print(" {\n"); + printer->Indent(); + map vars; vars["index"] = SimpleItoa(i); - vars["method"] = UnderscoresToCamelCase(method); - vars["input"] = ClassName(method->input_type()); vars["output"] = ClassName(method->output_type()); printer->Print(vars, - "\n" - "public void $method$(\n" - " com.google.protobuf.RpcController controller,\n" - " $input$ request,\n" - " com.google.protobuf.RpcCallback<$output$> done) {\n" - " channel.callMethod(\n" - " getDescriptor().getMethods().get($index$),\n" - " controller,\n" - " request,\n" - " $output$.getDefaultInstance(),\n" - " com.google.protobuf.RpcUtil.generalizeCallback(\n" - " done,\n" - " $output$.class,\n" - " $output$.getDefaultInstance()));\n" - "}\n"); + "channel.callMethod(\n" + " getDescriptor().getMethods().get($index$),\n" + " controller,\n" + " request,\n" + " $output$.getDefaultInstance(),\n" + " com.google.protobuf.RpcUtil.generalizeCallback(\n" + " done,\n" + " $output$.class,\n" + " $output$.getDefaultInstance()));\n"); + + printer->Outdent(); + printer->Print("}\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); +} + +void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) { + printer->Print( + "public static BlockingInterface newBlockingStub(\n" + " com.google.protobuf.BlockingRpcChannel channel) {\n" + " return new BlockingStub(channel);\n" + "}\n" + "\n"); + + printer->Print( + "public interface BlockingInterface {"); + printer->Indent(); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + GenerateBlockingMethodSignature(printer, method); + printer->Print(";\n"); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); + + printer->Print( + "private static final class BlockingStub implements BlockingInterface {\n"); + printer->Indent(); + + printer->Print( + "private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n" + " this.channel = channel;\n" + "}\n" + "\n" + "private final com.google.protobuf.BlockingRpcChannel channel;\n"); + + for (int i = 0; i < descriptor_->method_count(); i++) { + const MethodDescriptor* method = descriptor_->method(i); + GenerateBlockingMethodSignature(printer, method); + printer->Print(" {\n"); + printer->Indent(); + + map vars; + vars["index"] = SimpleItoa(i); + vars["output"] = ClassName(method->output_type()); + printer->Print(vars, + "return ($output$) channel.callBlockingMethod(\n" + " getDescriptor().getMethods().get($index$),\n" + " controller,\n" + " request,\n" + " $output$.getDefaultInstance());\n"); + + printer->Outdent(); + printer->Print( + "}\n" + "\n"); } printer->Outdent(); printer->Print("}\n"); } +void ServiceGenerator::GenerateMethodSignature(io::Printer* printer, + const MethodDescriptor* method, + IsAbstract is_abstract) { + map vars; + vars["name"] = UnderscoresToCamelCase(method); + vars["input"] = ClassName(method->input_type()); + vars["output"] = ClassName(method->output_type()); + vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; + printer->Print(vars, + "public $abstract$ void $name$(\n" + " com.google.protobuf.RpcController controller,\n" + " $input$ request,\n" + " com.google.protobuf.RpcCallback<$output$> done)"); +} + +void ServiceGenerator::GenerateBlockingMethodSignature( + io::Printer* printer, + const MethodDescriptor* method) { + map vars; + vars["method"] = UnderscoresToCamelCase(method); + vars["input"] = ClassName(method->input_type()); + vars["output"] = ClassName(method->output_type()); + printer->Print(vars, + "\n" + "public $output$ $method$(\n" + " com.google.protobuf.RpcController controller,\n" + " $input$ request)\n" + " throws com.google.protobuf.ServiceException"); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h index 83404174..e07eebf7 100644 --- a/src/google/protobuf/compiler/java/java_service.h +++ b/src/google/protobuf/compiler/java/java_service.h @@ -57,9 +57,28 @@ class ServiceGenerator { void Generate(io::Printer* printer); private: + + // Generate the getDescriptorForType() method. + void GenerateGetDescriptorForType(io::Printer* printer); + + // Generate a Java interface for the service. + void GenerateInterface(io::Printer* printer); + + // Generate newReflectiveService() method. + void GenerateNewReflectiveServiceMethod(io::Printer* printer); + + // Generate newReflectiveBlockingService() method. + void GenerateNewReflectiveBlockingServiceMethod(io::Printer* printer); + + // Generate abstract method declarations for all methods. + void GenerateAbstractMethods(io::Printer* printer); + // Generate the implementation of Service.callMethod(). void GenerateCallMethod(io::Printer* printer); + // Generate the implementation of BlockingService.callBlockingMethod(). + void GenerateCallBlockingMethod(io::Printer* printer); + // Generate the implementations of Service.get{Request,Response}Prototype(). enum RequestOrResponse { REQUEST, RESPONSE }; void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); @@ -67,6 +86,20 @@ class ServiceGenerator { // Generate a stub implementation of the service. void GenerateStub(io::Printer* printer); + // Generate a method signature, possibly abstract, without body or trailing + // semicolon. + enum IsAbstract { IS_ABSTRACT, IS_CONCRETE }; + void GenerateMethodSignature(io::Printer* printer, + const MethodDescriptor* method, + IsAbstract is_abstract); + + // Generate a blocking stub interface and implementation of the service. + void GenerateBlockingStub(io::Printer* printer); + + // Generate the method signature for one method of a blocking stub. + void GenerateBlockingMethodSignature(io::Printer* printer, + const MethodDescriptor* method); + const ServiceDescriptor* descriptor_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index e1c0d0d1..e9e01545 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -97,7 +97,8 @@ Parser::Parser() error_collector_(NULL), source_location_table_(NULL), had_errors_(false), - require_syntax_identifier_(false) { + require_syntax_identifier_(false), + stop_after_syntax_identifier_(false) { } Parser::~Parser() { @@ -309,10 +310,12 @@ bool Parser::Parse(io::Tokenizer* input, FileDescriptorProto* file) { // identifier. return false; } - } else { + } else if (!stop_after_syntax_identifier_) { syntax_identifier_ = "proto2"; } + if (stop_after_syntax_identifier_) return !had_errors_; + // Repeatedly parse statements until we reach the end of the file. while (!AtEnd()) { if (!ParseTopLevelStatement(file)) { @@ -341,7 +344,7 @@ bool Parser::ParseSyntaxIdentifier() { syntax_identifier_ = syntax; - if (syntax != "proto2") { + if (syntax != "proto2" && !stop_after_syntax_identifier_) { AddError(syntax_token.line, syntax_token.column, "Unrecognized syntax identifier \"" + syntax + "\". This parser " "only recognizes \"proto2\"."); diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index b670f740..72c96d04 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -90,7 +90,7 @@ class LIBPROTOBUF_EXPORT Parser { // Returns the identifier used in the "syntax = " declaration, if one was // seen during the last call to Parse(), or the empty string otherwise. - const string& GetSyntaxIndentifier() { return syntax_identifier_; } + const string& GetSyntaxIdentifier() { return syntax_identifier_; } // If set true, input files will be required to begin with a syntax // identifier. Otherwise, files may omit this. If a syntax identifier @@ -100,6 +100,18 @@ class LIBPROTOBUF_EXPORT Parser { require_syntax_identifier_ = value; } + // Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop + // parsing as soon as it has seen the syntax identifier, or lack thereof. + // This is useful for quickly identifying the syntax of the file without + // parsing the whole thing. If this is enabled, no error will be recorded + // if the syntax identifier is something other than "proto2" (since + // presumably the caller intends to deal with that), but other kinds of + // errors (e.g. parse errors) will still be reported. When this is enabled, + // you may pass a NULL FileDescriptorProto to Parse(). + void SetStopAfterSyntaxIdentifier(bool value) { + stop_after_syntax_identifier_ = value; + } + private: // ================================================================= // Error recovery helpers @@ -281,6 +293,7 @@ class LIBPROTOBUF_EXPORT Parser { SourceLocationTable* source_location_table_; bool had_errors_; bool require_syntax_identifier_; + bool stop_after_syntax_identifier_; string syntax_identifier_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser); diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index 2d48c5ae..c4f08e7f 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -176,6 +176,38 @@ class ParserTest : public testing::Test { // =================================================================== +TEST_F(ParserTest, StopAfterSyntaxIdentifier) { + SetupParser( + "// blah\n" + "syntax = \"foobar\";\n" + "this line will not be parsed\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_TRUE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("", error_collector_.text_); + EXPECT_EQ("foobar", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParserTest, StopAfterOmittedSyntaxIdentifier) { + SetupParser( + "// blah\n" + "this line will not be parsed\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_TRUE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("", error_collector_.text_); + EXPECT_EQ("", parser_->GetSyntaxIdentifier()); +} + +TEST_F(ParserTest, StopAfterSyntaxIdentifierWithErrors) { + SetupParser( + "// blah\n" + "syntax = error;\n"); + parser_->SetStopAfterSyntaxIdentifier(true); + EXPECT_FALSE(parser_->Parse(input_.get(), NULL)); + EXPECT_EQ("1:9: Expected syntax identifier.\n", error_collector_.text_); +} + +// =================================================================== + typedef ParserTest ParseMessageTest; TEST_F(ParseMessageTest, SimpleMessage) { @@ -201,7 +233,7 @@ TEST_F(ParseMessageTest, ImplicitSyntaxIdentifier) { " name: \"TestMessage\"" " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" "}"); - EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); } TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) { @@ -215,7 +247,7 @@ TEST_F(ParseMessageTest, ExplicitSyntaxIdentifier) { " name: \"TestMessage\"" " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" "}"); - EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); } TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) { @@ -230,7 +262,7 @@ TEST_F(ParseMessageTest, ExplicitRequiredSyntaxIdentifier) { " name: \"TestMessage\"" " field { name:\"foo\" label:LABEL_REQUIRED type:TYPE_INT32 number:1 }" "}"); - EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); } TEST_F(ParseMessageTest, SimpleFields) { @@ -673,7 +705,7 @@ TEST_F(ParseErrorTest, MissingSyntaxIdentifier) { ExpectHasEarlyExitErrors( "message TestMessage {}", "0:0: File must begin with 'syntax = \"proto2\";'.\n"); - EXPECT_EQ("", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("", parser_->GetSyntaxIdentifier()); } TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) { @@ -681,14 +713,14 @@ TEST_F(ParseErrorTest, UnknownSyntaxIdentifier) { "syntax = \"no_such_syntax\";", "0:9: Unrecognized syntax identifier \"no_such_syntax\". This parser " "only recognizes \"proto2\".\n"); - EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("no_such_syntax", parser_->GetSyntaxIdentifier()); } TEST_F(ParseErrorTest, SimpleSyntaxError) { ExpectHasErrors( "message TestMessage @#$ { blah }", "0:20: Expected \"{\".\n"); - EXPECT_EQ("proto2", parser_->GetSyntaxIndentifier()); + EXPECT_EQ("proto2", parser_->GetSyntaxIdentifier()); } TEST_F(ParseErrorTest, ExpectedTopLevel) { diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index eb5b5937..ecca3293 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -167,14 +167,6 @@ string ToCamelCase(const string& input) { typedef pair PointerStringPair; -// Used by GCC/SGI STL only. (Why isn't this provided by the standard -// library? :( ) -struct CStringEqual { - inline bool operator()(const char* a, const char* b) const { - return strcmp(a, b) == 0; - } -}; - struct PointerStringPairEqual { inline bool operator()(const PointerStringPair& a, const PointerStringPair& b) const { @@ -240,6 +232,13 @@ struct Symbol { inline Symbol() : type(NULL_SYMBOL) { descriptor = NULL; } inline bool IsNull() const { return type == NULL_SYMBOL; } + inline bool IsType() const { + return type == MESSAGE || type == ENUM; + } + inline bool IsAggregate() const { + return type == MESSAGE || type == PACKAGE + || type == ENUM || type == SERVICE; + } #define CONSTRUCTOR(TYPE, TYPE_CONSTANT, FIELD) \ inline explicit Symbol(const TYPE* value) { \ @@ -274,13 +273,13 @@ struct Symbol { const Symbol kNullSymbol; typedef hash_map, CStringEqual> + hash, streq> SymbolsByNameMap; typedef hash_map SymbolsByParentMap; typedef hash_map, CStringEqual> + hash, streq> FilesByNameMap; typedef hash_map @@ -291,6 +290,12 @@ typedef hash_map > EnumValuesByNumberMap; +// This is a map rather than a hash_map, since we use it to iterate +// through all the extensions that extend a given Descriptor, and an +// ordered data structure that implements lower_bound is convenient +// for that. +typedef map + ExtensionsGroupedByDescriptorMap; } // anonymous namespace @@ -324,17 +329,16 @@ class DescriptorPool::Tables { // Not used when fallback_database_ == NULL. hash_set known_bad_files_; + // The set of descriptors for which we've already loaded the full + // set of extensions numbers from fallback_database_. + hash_set extensions_loaded_from_db_; + // ----------------------------------------------------------------- // Finding items. - // Find symbols. These return a null Symbol (symbol.IsNull() is true) + // Find symbols. This returns a null Symbol (symbol.IsNull() is true) // if not found. inline Symbol FindSymbol(const string& key) const; - inline Symbol FindNestedSymbol(const void* parent, - const string& name) const; - inline Symbol FindNestedSymbolOfType(const void* parent, - const string& name, - const Symbol::Type type) const; // This implements the body of DescriptorPool::Find*ByName(). It should // really be a private method of DescriptorPool, but that would require @@ -345,40 +349,21 @@ class DescriptorPool::Tables { // These return NULL if not found. inline const FileDescriptor* FindFile(const string& key) const; - inline const FieldDescriptor* FindFieldByNumber( - const Descriptor* parent, int number) const; - inline const FieldDescriptor* FindFieldByLowercaseName( - const void* parent, const string& lowercase_name) const; - inline const FieldDescriptor* FindFieldByCamelcaseName( - const void* parent, const string& camelcase_name) const; - inline const EnumValueDescriptor* FindEnumValueByNumber( - const EnumDescriptor* parent, int number) const; + inline const FieldDescriptor* FindExtension(const Descriptor* extendee, + int number); + inline void FindAllExtensions(const Descriptor* extendee, + vector* out) const; // ----------------------------------------------------------------- // Adding items. // These add items to the corresponding tables. They return false if - // the key already exists in the table. For AddSymbol(), the strings passed - // in must be ones that were constructed using AllocateString(), as they will - // be used as keys in the symbols_by_name_ and symbols_by_parent_ maps - // without copying. (If parent is NULL, nothing is added to - // symbols_by_parent_.) - bool AddSymbol(const string& full_name, - const void* parent, const string& name, - Symbol symbol); + // the key already exists in the table. For AddSymbol(), the string passed + // in must be one that was constructed using AllocateString(), as it will + // be used as a key in the symbols_by_name_ map without copying. + bool AddSymbol(const string& full_name, Symbol symbol); bool AddFile(const FileDescriptor* file); - bool AddFieldByNumber(const FieldDescriptor* field); - bool AddEnumValueByNumber(const EnumValueDescriptor* value); - - // Adds the field to the lowercase_name and camelcase_name maps. Never - // fails because we allow duplicates; the first field by the name wins. - void AddFieldByStylizedNames(const FieldDescriptor* field); - - // Like AddSymbol(), but only adds to symbols_by_parent_, not - // symbols_by_name_. Used for enum values, which need to be registered - // under multiple parents (their type and its parent). - bool AddAliasUnderParent(const void* parent, const string& name, - Symbol symbol); + bool AddExtension(const FieldDescriptor* field); // ----------------------------------------------------------------- // Allocating memory. @@ -397,38 +382,100 @@ class DescriptorPool::Tables { // The string is initialized to the given value for convenience. string* AllocateString(const string& value); - // Allocate a protocol message object. - template Type* AllocateMessage(); + // Allocate a protocol message object. Some older versions of GCC have + // trouble understanding explicit template instantiations in some cases, so + // in those cases we have to pass a dummy pointer of the right type as the + // parameter instead of specifying the type explicitly. + template Type* AllocateMessage(Type* dummy = NULL); + + // Allocate a FileDescriptorTables object. + FileDescriptorTables* AllocateFileTables(); private: vector strings_; // All strings in the pool. vector messages_; // All messages in the pool. + vector file_tables_; // All file tables in the pool. vector allocations_; // All other memory allocated in the pool. SymbolsByNameMap symbols_by_name_; - SymbolsByParentMap symbols_by_parent_; FilesByNameMap files_by_name_; - FieldsByNameMap fields_by_lowercase_name_; - FieldsByNameMap fields_by_camelcase_name_; - FieldsByNumberMap fields_by_number_; // Includes extensions. - EnumValuesByNumberMap enum_values_by_number_; + ExtensionsGroupedByDescriptorMap extensions_; int strings_before_checkpoint_; int messages_before_checkpoint_; + int file_tables_before_checkpoint_; int allocations_before_checkpoint_; vector symbols_after_checkpoint_; - vector symbols_by_parent_after_checkpoint_; vector files_after_checkpoint_; - vector field_lowercase_names_after_checkpoint_; - vector field_camelcase_names_after_checkpoint_; - vector field_numbers_after_checkpoint_; - vector enum_numbers_after_checkpoint_; + vector extensions_after_checkpoint_; // Allocate some bytes which will be reclaimed when the pool is // destroyed. void* AllocateBytes(int size); }; +// Contains tables specific to a particular file. These tables are not +// modified once the file has been constructed, so they need not be +// protected by a mutex. This makes operations that depend only on the +// contents of a single file -- e.g. Descriptor::FindFieldByName() -- +// lock-free. +// +// For historical reasons, the definitions of the methods of +// FileDescriptorTables and DescriptorPool::Tables are interleaved below. +// These used to be a single class. +class FileDescriptorTables { + public: + FileDescriptorTables(); + ~FileDescriptorTables(); + + // Empty table, used with placeholder files. + static const FileDescriptorTables kEmpty; + + // ----------------------------------------------------------------- + // Finding items. + + // Find symbols. These return a null Symbol (symbol.IsNull() is true) + // if not found. + inline Symbol FindNestedSymbol(const void* parent, + const string& name) const; + inline Symbol FindNestedSymbolOfType(const void* parent, + const string& name, + const Symbol::Type type) const; + + // These return NULL if not found. + inline const FieldDescriptor* FindFieldByNumber( + const Descriptor* parent, int number) const; + inline const FieldDescriptor* FindFieldByLowercaseName( + const void* parent, const string& lowercase_name) const; + inline const FieldDescriptor* FindFieldByCamelcaseName( + const void* parent, const string& camelcase_name) const; + inline const EnumValueDescriptor* FindEnumValueByNumber( + const EnumDescriptor* parent, int number) const; + + // ----------------------------------------------------------------- + // Adding items. + + // These add items to the corresponding tables. They return false if + // the key already exists in the table. For AddAliasUnderParent(), the + // string passed in must be one that was constructed using AllocateString(), + // as it will be used as a key in the symbols_by_parent_ map without copying. + bool AddAliasUnderParent(const void* parent, const string& name, + Symbol symbol); + bool AddFieldByNumber(const FieldDescriptor* field); + bool AddEnumValueByNumber(const EnumValueDescriptor* value); + + // Adds the field to the lowercase_name and camelcase_name maps. Never + // fails because we allow duplicates; the first field by the name wins. + void AddFieldByStylizedNames(const FieldDescriptor* field); + + private: + SymbolsByParentMap symbols_by_parent_; + FieldsByNameMap fields_by_lowercase_name_; + FieldsByNameMap fields_by_camelcase_name_; + FieldsByNumberMap fields_by_number_; // Not including extensions. + EnumValuesByNumberMap enum_values_by_number_; +}; + DescriptorPool::Tables::Tables() : strings_before_checkpoint_(0), messages_before_checkpoint_(0), @@ -442,63 +489,53 @@ DescriptorPool::Tables::~Tables() { operator delete(allocations_[i]); } STLDeleteElements(&strings_); + STLDeleteElements(&file_tables_); } +FileDescriptorTables::FileDescriptorTables() {} +FileDescriptorTables::~FileDescriptorTables() {} + +const FileDescriptorTables FileDescriptorTables::kEmpty; + void DescriptorPool::Tables::Checkpoint() { strings_before_checkpoint_ = strings_.size(); messages_before_checkpoint_ = messages_.size(); + file_tables_before_checkpoint_ = file_tables_.size(); allocations_before_checkpoint_ = allocations_.size(); symbols_after_checkpoint_.clear(); - symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); - field_lowercase_names_after_checkpoint_.clear(); - field_camelcase_names_after_checkpoint_.clear(); - field_numbers_after_checkpoint_.clear(); - enum_numbers_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); } void DescriptorPool::Tables::Rollback() { for (int i = 0; i < symbols_after_checkpoint_.size(); i++) { symbols_by_name_.erase(symbols_after_checkpoint_[i]); } - for (int i = 0; i < symbols_by_parent_after_checkpoint_.size(); i++) { - symbols_by_parent_.erase(symbols_by_parent_after_checkpoint_[i]); - } for (int i = 0; i < files_after_checkpoint_.size(); i++) { files_by_name_.erase(files_after_checkpoint_[i]); } - for (int i = 0; i < field_lowercase_names_after_checkpoint_.size(); i++) { - fields_by_lowercase_name_.erase(field_lowercase_names_after_checkpoint_[i]); - } - for (int i = 0; i < field_camelcase_names_after_checkpoint_.size(); i++) { - fields_by_camelcase_name_.erase(field_camelcase_names_after_checkpoint_[i]); - } - for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) { - fields_by_number_.erase(field_numbers_after_checkpoint_[i]); - } - for (int i = 0; i < enum_numbers_after_checkpoint_.size(); i++) { - enum_values_by_number_.erase(enum_numbers_after_checkpoint_[i]); + for (int i = 0; i < extensions_after_checkpoint_.size(); i++) { + extensions_.erase(extensions_after_checkpoint_[i]); } symbols_after_checkpoint_.clear(); - symbols_by_parent_after_checkpoint_.clear(); files_after_checkpoint_.clear(); - field_lowercase_names_after_checkpoint_.clear(); - field_camelcase_names_after_checkpoint_.clear(); - field_numbers_after_checkpoint_.clear(); - enum_numbers_after_checkpoint_.clear(); + extensions_after_checkpoint_.clear(); STLDeleteContainerPointers( strings_.begin() + strings_before_checkpoint_, strings_.end()); STLDeleteContainerPointers( messages_.begin() + messages_before_checkpoint_, messages_.end()); + STLDeleteContainerPointers( + file_tables_.begin() + file_tables_before_checkpoint_, file_tables_.end()); for (int i = allocations_before_checkpoint_; i < allocations_.size(); i++) { operator delete(allocations_[i]); } strings_.resize(strings_before_checkpoint_); messages_.resize(messages_before_checkpoint_); + file_tables_.resize(file_tables_before_checkpoint_); allocations_.resize(allocations_before_checkpoint_); } @@ -513,7 +550,7 @@ inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const { } } -inline Symbol DescriptorPool::Tables::FindNestedSymbol( +inline Symbol FileDescriptorTables::FindNestedSymbol( const void* parent, const string& name) const { const Symbol* result = FindOrNull(symbols_by_parent_, PointerStringPair(parent, name.c_str())); @@ -524,7 +561,7 @@ inline Symbol DescriptorPool::Tables::FindNestedSymbol( } } -inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType( +inline Symbol FileDescriptorTables::FindNestedSymbolOfType( const void* parent, const string& name, const Symbol::Type type) const { Symbol result = FindNestedSymbol(parent, name); if (result.type != type) return kNullSymbol; @@ -557,59 +594,58 @@ inline const FileDescriptor* DescriptorPool::Tables::FindFile( return FindPtrOrNull(files_by_name_, key.c_str()); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByNumber( const Descriptor* parent, int number) const { return FindPtrOrNull(fields_by_number_, make_pair(parent, number)); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByLowercaseName( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByLowercaseName( const void* parent, const string& lowercase_name) const { return FindPtrOrNull(fields_by_lowercase_name_, PointerStringPair(parent, lowercase_name.c_str())); } -inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByCamelcaseName( +inline const FieldDescriptor* FileDescriptorTables::FindFieldByCamelcaseName( const void* parent, const string& camelcase_name) const { return FindPtrOrNull(fields_by_camelcase_name_, PointerStringPair(parent, camelcase_name.c_str())); } -inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber( +inline const EnumValueDescriptor* FileDescriptorTables::FindEnumValueByNumber( const EnumDescriptor* parent, int number) const { return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number)); } +inline const FieldDescriptor* DescriptorPool::Tables::FindExtension( + const Descriptor* extendee, int number) { + return FindPtrOrNull(extensions_, make_pair(extendee, number)); +} + +inline void DescriptorPool::Tables::FindAllExtensions( + const Descriptor* extendee, vector* out) const { + ExtensionsGroupedByDescriptorMap::const_iterator it = + extensions_.lower_bound(make_pair(extendee, 0)); + for (; it != extensions_.end() && it->first.first == extendee; ++it) { + out->push_back(it->second); + } +} + // ------------------------------------------------------------------- bool DescriptorPool::Tables::AddSymbol( - const string& full_name, - const void* parent, const string& name, - Symbol symbol) { + const string& full_name, Symbol symbol) { if (InsertIfNotPresent(&symbols_by_name_, full_name.c_str(), symbol)) { symbols_after_checkpoint_.push_back(full_name.c_str()); - - if (parent != NULL && !AddAliasUnderParent(parent, name, symbol)) { - GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in " - "symbols_by_name_, but was defined in symbols_by_parent_; " - "this shouldn't be possible."; - return false; - } - return true; } else { return false; } } -bool DescriptorPool::Tables::AddAliasUnderParent( +bool FileDescriptorTables::AddAliasUnderParent( const void* parent, const string& name, Symbol symbol) { PointerStringPair by_parent_key(parent, name.c_str()); - if (InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol)) { - symbols_by_parent_after_checkpoint_.push_back(by_parent_key); - return true; - } else { - return false; - } + return InsertIfNotPresent(&symbols_by_parent_, by_parent_key, symbol); } bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { @@ -621,7 +657,7 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) { } } -void DescriptorPool::Tables::AddFieldByStylizedNames( +void FileDescriptorTables::AddFieldByStylizedNames( const FieldDescriptor* field) { const void* parent; if (field->is_extension()) { @@ -635,31 +671,27 @@ void DescriptorPool::Tables::AddFieldByStylizedNames( } PointerStringPair lowercase_key(parent, field->lowercase_name().c_str()); - if (InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field)) { - field_lowercase_names_after_checkpoint_.push_back(lowercase_key); - } + InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field); PointerStringPair camelcase_key(parent, field->camelcase_name().c_str()); - if (InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field)) { - field_camelcase_names_after_checkpoint_.push_back(camelcase_key); - } + InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field); } -bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) { +bool FileDescriptorTables::AddFieldByNumber(const FieldDescriptor* field) { DescriptorIntPair key(field->containing_type(), field->number()); - if (InsertIfNotPresent(&fields_by_number_, key, field)) { - field_numbers_after_checkpoint_.push_back(key); - return true; - } else { - return false; - } + return InsertIfNotPresent(&fields_by_number_, key, field); } -bool DescriptorPool::Tables::AddEnumValueByNumber( +bool FileDescriptorTables::AddEnumValueByNumber( const EnumValueDescriptor* value) { EnumIntPair key(value->type(), value->number()); - if (InsertIfNotPresent(&enum_values_by_number_, key, value)) { - enum_numbers_after_checkpoint_.push_back(key); + return InsertIfNotPresent(&enum_values_by_number_, key, value); +} + +bool DescriptorPool::Tables::AddExtension(const FieldDescriptor* field) { + DescriptorIntPair key(field->containing_type(), field->number()); + if (InsertIfNotPresent(&extensions_, key, field)) { + extensions_after_checkpoint_.push_back(key); return true; } else { return false; @@ -685,12 +717,18 @@ string* DescriptorPool::Tables::AllocateString(const string& value) { } template -Type* DescriptorPool::Tables::AllocateMessage() { +Type* DescriptorPool::Tables::AllocateMessage(Type* dummy) { Type* result = new Type; messages_.push_back(result); return result; } +FileDescriptorTables* DescriptorPool::Tables::AllocateFileTables() { + FileDescriptorTables* result = new FileDescriptorTables; + file_tables_.push_back(result); + return result; +} + void* DescriptorPool::Tables::AllocateBytes(int size) { // TODO(kenton): Would it be worthwhile to implement this in some more // sophisticated way? Probably not for the open source release, but for @@ -715,7 +753,7 @@ DescriptorPool::DescriptorPool() underlay_(NULL), tables_(new Tables), enforce_dependencies_(true), - last_internal_build_generated_file_call_(NULL) {} + allow_unknown_(false) {} DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database, ErrorCollector* error_collector) @@ -725,7 +763,7 @@ DescriptorPool::DescriptorPool(DescriptorDatabase* fallback_database, underlay_(NULL), tables_(new Tables), enforce_dependencies_(true), - last_internal_build_generated_file_call_(NULL) { + allow_unknown_(false) { } DescriptorPool::DescriptorPool(const DescriptorPool* underlay) @@ -734,7 +772,8 @@ DescriptorPool::DescriptorPool(const DescriptorPool* underlay) default_error_collector_(NULL), underlay_(underlay), tables_(new Tables), - last_internal_build_generated_file_call_(NULL) {} + enforce_dependencies_(true), + allow_unknown_(false) {} DescriptorPool::~DescriptorPool() { if (mutex_ != NULL) delete mutex_; @@ -742,21 +781,78 @@ DescriptorPool::~DescriptorPool() { // DescriptorPool::BuildFile() defined later. // DescriptorPool::BuildFileCollectingErrors() defined later. -// DescriptorPool::InternalBuildGeneratedFile() defined later. + +void DescriptorPool::InternalDontEnforceDependencies() { + enforce_dependencies_ = false; +} + +bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { + MutexLockMaybe lock(mutex_); + return tables_->FindFile(filename) != NULL; +} + +// generated_pool ==================================================== + +namespace { + +EncodedDescriptorDatabase* generated_database_ = NULL; +DescriptorPool* generated_pool_ = NULL; + +void InitGeneratedPool() { + GOOGLE_CHECK(generated_pool_ == NULL); + generated_database_ = new EncodedDescriptorDatabase; + generated_pool_ = new DescriptorPool(generated_database_); +} + +// Force InitGeneratedPool to be called at static init time, before any threads +// can be created. +struct Initializer { + Initializer() { + if (generated_pool_ == NULL) InitGeneratedPool(); + } +} initializer; + +} // anonymous namespace const DescriptorPool* DescriptorPool::generated_pool() { - return internal_generated_pool(); + if (generated_pool_ == NULL) InitGeneratedPool(); + return generated_pool_; } DescriptorPool* DescriptorPool::internal_generated_pool() { - static DescriptorPool singleton; - return &singleton; + if (generated_pool_ == NULL) InitGeneratedPool(); + return generated_pool_; } -void DescriptorPool::InternalDontEnforceDependencies() { - enforce_dependencies_ = false; +void DescriptorPool::InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size) { + // So, this function is called in the process of initializing the + // descriptors for generated proto classes. Each generated .pb.cc file + // has an internal procedure called AddDescriptors() which is called at + // process startup, and that function calls this one in order to register + // the raw bytes of the FileDescriptorProto representing the file. + // + // We do not actually construct the descriptor objects right away. We just + // hang on to the bytes until they are actually needed. We actually construct + // the descriptor the first time one of the following things happens: + // * Someone calls a method like descriptor(), GetDescriptor(), or + // GetReflection() on the generated types, which requires returning the + // descriptor or an object based on it. + // * Someone looks up the descriptor in DescriptorPool::generated_pool(). + // + // Once one of these happens, the DescriptorPool actually parses the + // FileDescriptorProto and generates a FileDescriptor (and all its children) + // based on it. + // + // Note that FileDescriptorProto is itself a generated protocol message. + // Therefore, when we parse one, we have to be very careful to avoid using + // any descriptor-based operations, since this might cause infinite recursion + // or deadlock. + if (generated_pool_ == NULL) InitGeneratedPool(); + GOOGLE_CHECK(generated_database_->Add(encoded_file_descriptor, size)); } + // Find*By* methods ================================================== // TODO(kenton): There's a lot of repeated code here, but I'm not sure if @@ -851,8 +947,8 @@ const MethodDescriptor* DescriptorPool::FindMethodByName( const FieldDescriptor* DescriptorPool::FindExtensionByNumber( const Descriptor* extendee, int number) const { MutexLockMaybe lock(mutex_); - const FieldDescriptor* result = tables_->FindFieldByNumber(extendee, number); - if (result != NULL && result->is_extension()) { + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { return result; } if (underlay_ != NULL) { @@ -861,22 +957,47 @@ const FieldDescriptor* DescriptorPool::FindExtensionByNumber( if (result != NULL) return result; } if (TryFindExtensionInFallbackDatabase(extendee, number)) { - const FieldDescriptor* result = - tables_->FindFieldByNumber(extendee, number); - if (result != NULL && result->is_extension()) { + const FieldDescriptor* result = tables_->FindExtension(extendee, number); + if (result != NULL) { return result; } } return NULL; } +void DescriptorPool::FindAllExtensions( + const Descriptor* extendee, vector* out) const { + MutexLockMaybe lock(mutex_); + + // Initialize tables_->extensions_ from the fallback database first + // (but do this only once per descriptor). + if (fallback_database_ != NULL && + tables_->extensions_loaded_from_db_.count(extendee) == 0) { + vector numbers; + if (fallback_database_->FindAllExtensionNumbers(extendee->full_name(), + &numbers)) { + for (int i = 0; i < numbers.size(); ++i) { + int number = numbers[i]; + if (tables_->FindExtension(extendee, number) == NULL) { + TryFindExtensionInFallbackDatabase(extendee, number); + } + } + tables_->extensions_loaded_from_db_.insert(extendee); + } + } + + tables_->FindAllExtensions(extendee, out); + if (underlay_ != NULL) { + underlay_->FindAllExtensions(extendee, out); + } +} + // ------------------------------------------------------------------- const FieldDescriptor* Descriptor::FindFieldByNumber(int key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByNumber(this, key); + file()->tables_->FindFieldByNumber(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -886,9 +1007,8 @@ Descriptor::FindFieldByNumber(int key) const { const FieldDescriptor* Descriptor::FindFieldByLowercaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByLowercaseName(this, key); + file()->tables_->FindFieldByLowercaseName(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -898,9 +1018,8 @@ Descriptor::FindFieldByLowercaseName(const string& key) const { const FieldDescriptor* Descriptor::FindFieldByCamelcaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + file()->tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || result->is_extension()) { return NULL; } else { @@ -910,9 +1029,8 @@ Descriptor::FindFieldByCamelcaseName(const string& key) const { const FieldDescriptor* Descriptor::FindFieldByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && !result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -922,9 +1040,8 @@ Descriptor::FindFieldByName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -934,9 +1051,8 @@ Descriptor::FindExtensionByName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByLowercaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByLowercaseName(this, key); + file()->tables_->FindFieldByLowercaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -946,9 +1062,8 @@ Descriptor::FindExtensionByLowercaseName(const string& key) const { const FieldDescriptor* Descriptor::FindExtensionByCamelcaseName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); const FieldDescriptor* result = - file()->pool()->tables_->FindFieldByCamelcaseName(this, key); + file()->tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -958,9 +1073,8 @@ Descriptor::FindExtensionByCamelcaseName(const string& key) const { const Descriptor* Descriptor::FindNestedTypeByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); if (!result.IsNull()) { return result.descriptor; } else { @@ -970,9 +1084,8 @@ Descriptor::FindNestedTypeByName(const string& key) const { const EnumDescriptor* Descriptor::FindEnumTypeByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); if (!result.IsNull()) { return result.enum_descriptor; } else { @@ -982,10 +1095,8 @@ Descriptor::FindEnumTypeByName(const string& key) const { const EnumValueDescriptor* Descriptor::FindEnumValueByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType( - this, key, Symbol::ENUM_VALUE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -995,10 +1106,8 @@ Descriptor::FindEnumValueByName(const string& key) const { const EnumValueDescriptor* EnumDescriptor::FindValueByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType( - this, key, Symbol::ENUM_VALUE); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -1008,15 +1117,13 @@ EnumDescriptor::FindValueByName(const string& key) const { const EnumValueDescriptor* EnumDescriptor::FindValueByNumber(int key) const { - MutexLockMaybe lock(file()->pool()->mutex_); - return file()->pool()->tables_->FindEnumValueByNumber(this, key); + return file()->tables_->FindEnumValueByNumber(this, key); } const MethodDescriptor* ServiceDescriptor::FindMethodByName(const string& key) const { - MutexLockMaybe lock(file()->pool()->mutex_); Symbol result = - file()->pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD); + file()->tables_->FindNestedSymbolOfType(this, key, Symbol::METHOD); if (!result.IsNull()) { return result.method_descriptor; } else { @@ -1026,9 +1133,7 @@ ServiceDescriptor::FindMethodByName(const string& key) const { const Descriptor* FileDescriptor::FindMessageTypeByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::MESSAGE); if (!result.IsNull()) { return result.descriptor; } else { @@ -1038,9 +1143,7 @@ FileDescriptor::FindMessageTypeByName(const string& key) const { const EnumDescriptor* FileDescriptor::FindEnumTypeByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM); if (!result.IsNull()) { return result.enum_descriptor; } else { @@ -1050,9 +1153,8 @@ FileDescriptor::FindEnumTypeByName(const string& key) const { const EnumValueDescriptor* FileDescriptor::FindEnumValueByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); + tables_->FindNestedSymbolOfType(this, key, Symbol::ENUM_VALUE); if (!result.IsNull()) { return result.enum_value_descriptor; } else { @@ -1062,9 +1164,7 @@ FileDescriptor::FindEnumValueByName(const string& key) const { const ServiceDescriptor* FileDescriptor::FindServiceByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::SERVICE); if (!result.IsNull()) { return result.service_descriptor; } else { @@ -1074,9 +1174,7 @@ FileDescriptor::FindServiceByName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - Symbol result = - pool()->tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); + Symbol result = tables_->FindNestedSymbolOfType(this, key, Symbol::FIELD); if (!result.IsNull() && result.field_descriptor->is_extension()) { return result.field_descriptor; } else { @@ -1086,9 +1184,7 @@ FileDescriptor::FindExtensionByName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByLowercaseName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - const FieldDescriptor* result = - pool()->tables_->FindFieldByLowercaseName(this, key); + const FieldDescriptor* result = tables_->FindFieldByLowercaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -1098,9 +1194,7 @@ FileDescriptor::FindExtensionByLowercaseName(const string& key) const { const FieldDescriptor* FileDescriptor::FindExtensionByCamelcaseName(const string& key) const { - MutexLockMaybe lock(pool()->mutex_); - const FieldDescriptor* result = - pool()->tables_->FindFieldByCamelcaseName(this, key); + const FieldDescriptor* result = tables_->FindFieldByCamelcaseName(this, key); if (result == NULL || !result->is_extension()) { return NULL; } else { @@ -1297,15 +1391,27 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { implicit_cast(type()))); if (is_extension()) { - proto->set_extendee("."); + if (!containing_type()->is_unqualified_placeholder_) { + proto->set_extendee("."); + } proto->mutable_extendee()->append(containing_type()->full_name()); } if (cpp_type() == CPPTYPE_MESSAGE) { - proto->set_type_name("."); + if (message_type()->is_placeholder_) { + // We don't actually know if the type is a message type. It could be + // an enum. + proto->clear_type(); + } + + if (!message_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } proto->mutable_type_name()->append(message_type()->full_name()); } else if (cpp_type() == CPPTYPE_ENUM) { - proto->set_type_name("."); + if (!enum_type()->is_unqualified_placeholder_) { + proto->set_type_name("."); + } proto->mutable_type_name()->append(enum_type()->full_name()); } @@ -1354,9 +1460,14 @@ void ServiceDescriptor::CopyTo(ServiceDescriptorProto* proto) const { void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const { proto->set_name(name()); - proto->set_input_type("."); + if (!input_type()->is_unqualified_placeholder_) { + proto->set_input_type("."); + } proto->mutable_input_type()->append(input_type()->full_name()); - proto->set_output_type("."); + + if (!output_type()->is_unqualified_placeholder_) { + proto->set_output_type("."); + } proto->mutable_output_type()->append(output_type()->full_name()); if (&options() != &MethodOptions::default_instance()) { @@ -1720,8 +1831,7 @@ class DescriptorBuilder { DescriptorPool::ErrorCollector* error_collector); ~DescriptorBuilder(); - const FileDescriptor* BuildFile(const FileDescriptorProto& proto, - DescriptorPool::InternalDescriptorAssigner descriptor_assigner); + const FileDescriptor* BuildFile(const FileDescriptorProto& proto); private: friend class OptionInterpreter; @@ -1738,6 +1848,7 @@ class DescriptorBuilder { bool had_errors_; string filename_; FileDescriptor* file_; + FileDescriptorTables* file_tables_; // If LookupSymbol() finds a symbol that is in a file which is not a declared // dependency of this file, it will fail, but will set @@ -1778,8 +1889,40 @@ class DescriptorBuilder { // parents, etc. For example, LookupSymbol("foo.bar", "baz.qux.corge") makes // the following calls, returning the first non-null result: // FindSymbol("baz.qux.foo.bar"), FindSymbol("baz.foo.bar"), - // FindSymbol("foo.bar"). - Symbol LookupSymbol(const string& name, const string& relative_to); + // FindSymbol("foo.bar"). If AllowUnknownDependencies() has been called + // on the DescriptorPool, this will generate a placeholder type if + // the name is not found (unless the name itself is malformed). The + // placeholder_type parameter indicates what kind of placeholder should be + // constructed in this case. The resolve_mode parameter determines whether + // any symbol is returned, or only symbols that are types. Note, however, + // that LookupSymbol may still return a non-type symbol in LOOKUP_TYPES mode, + // if it believes that's all it could refer to. The caller should always + // check that it receives the type of symbol it was expecting. + enum PlaceholderType { + PLACEHOLDER_MESSAGE, + PLACEHOLDER_ENUM, + PLACEHOLDER_EXTENDABLE_MESSAGE + }; + enum ResolveMode { + LOOKUP_ALL, LOOKUP_TYPES + }; + Symbol LookupSymbol(const string& name, const string& relative_to, + PlaceholderType placeholder_type = PLACEHOLDER_MESSAGE, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Like LookupSymbol() but will not return a placeholder even if + // AllowUnknownDependencies() has been used. + Symbol LookupSymbolNoPlaceholder(const string& name, + const string& relative_to, + ResolveMode resolve_mode = LOOKUP_ALL); + + // Creates a placeholder type suitable for return from LookupSymbol(). May + // return kNullSymbol if the name is not a valid type name. + Symbol NewPlaceholder(const string& name, PlaceholderType placeholder_type); + + // Creates a placeholder file. Never returns NULL. This is used when an + // import is not found and AllowUnknownDependencies() is enabled. + const FileDescriptor* NewPlaceholderFile(const string& name); // Calls tables_->AddSymbol() and records an error if it fails. Returns // true if successful or false if failed, though most callers can ignore @@ -1801,6 +1944,10 @@ class DescriptorBuilder { void ValidateSymbolName(const string& name, const string& full_name, const Message& proto); + // Like ValidateSymbolName(), but the name is allowed to contain periods and + // an error is indicated by returning false (not recording the error). + bool ValidateQualifiedName(const string& name); + // Used by BUILD_ARRAY macro (below) to avoid having to have the type // specified as a macro parameter. template @@ -1903,6 +2050,12 @@ class DescriptorBuilder { // uninterpreted_option_ belongs. bool InterpretSingleOption(Message* options); + // Adds the uninterpreted_option to the given options message verbatim. + // Used when AllowUnknownDependencies() is in effect and we can't find + // the option's definition. + void AddWithoutInterpreting(const UninterpretedOption& uninterpreted_option, + Message* options); + // A recursive helper function that drills into the intermediate fields // in unknown_fields to check if field #field_number is set on the // innermost message. Returns false and sets an error if so. @@ -1915,18 +2068,18 @@ class DescriptorBuilder { // Validates the value for the option field of the currently interpreted // option and then sets it on the unknown_field. bool SetOptionValue(const FieldDescriptor* option_field, - UnknownField* unknown_field); + UnknownFieldSet* unknown_fields); // Convenience functions to set an int field the right way, depending on // its wire type (a single int CppType can represent multiple wire types). - void SetInt32(int32 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetInt64(int64 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetUInt32(uint32 value, FieldDescriptor::Type type, - UnknownField* unknown_field); - void SetUInt64(uint64 value, FieldDescriptor::Type type, - UnknownField* unknown_field); + void SetInt32(int number, int32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetInt64(int number, int64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt32(int number, uint32 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); + void SetUInt64(int number, uint64 value, FieldDescriptor::Type type, + UnknownFieldSet* unknown_fields); // A helper function that adds an error at the specified location of the // option we're currently interpreting, and returns false. @@ -1966,6 +2119,21 @@ class DescriptorBuilder { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OptionInterpreter); }; + // Work-around for broken compilers: According to the C++ standard, + // OptionInterpreter should have access to the private members of any class + // which has declared DescriptorBuilder as a friend. Unfortunately some old + // versions of GCC and other compilers do not implement this correctly. So, + // we have to have these intermediate methods to provide access. We also + // redundantly declare OptionInterpreter a friend just to make things extra + // clear for these bad compilers. + friend class OptionInterpreter; + static inline bool get_allow_unknown(const DescriptorPool* pool) { + return pool->allow_unknown_; + } + static inline bool get_is_placeholder(const Descriptor* descriptor) { + return descriptor->is_placeholder_; + } + // Must be run only after options have been interpreted. // // NOTE: Validation code must only reference the options in the mutable @@ -1998,7 +2166,7 @@ const FileDescriptor* DescriptorPool::BuildFile( "DescriptorDatabase. You must instead find a way to get your file " "into the underlying database."; GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. - return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto, NULL); + return DescriptorBuilder(this, tables_.get(), NULL).BuildFile(proto); } const FileDescriptor* DescriptorPool::BuildFileCollectingErrors( @@ -2010,73 +2178,14 @@ const FileDescriptor* DescriptorPool::BuildFileCollectingErrors( "into the underlying database."; GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. return DescriptorBuilder(this, tables_.get(), - error_collector).BuildFile(proto, NULL); + error_collector).BuildFile(proto); } const FileDescriptor* DescriptorPool::BuildFileFromDatabase( const FileDescriptorProto& proto) const { mutex_->AssertHeld(); return DescriptorBuilder(this, tables_.get(), - default_error_collector_).BuildFile(proto, NULL); -} - -const FileDescriptor* DescriptorPool::InternalBuildGeneratedFile( - const void* data, int size, - InternalDescriptorAssigner descriptor_assigner) { - // So, this function is called in the process of initializing the - // descriptors for generated proto classes. Each generated .pb.cc file - // has an internal procedure called BuildDescriptors() which is called the - // first time one of its descriptors is accessed, and that function calls - // this one in order to parse the raw bytes of the FileDescriptorProto - // representing the file. - // - // Note, though, that FileDescriptorProto is itself a generated protocol - // message. So, when we attempt to construct one below, it will attempt - // to initialize its own descriptors via its own BuildDescriptors() method. - // This will in turn cause InternalBuildGeneratedFile() to build - // descriptor.proto's descriptors. - // - // We are saved from an infinite loop by the fact that BuildDescriptors() - // only does anything the first time it is called. That is, the first few - // lines of any BuildDescriptors() procedure look like this: - // void BuildDescriptors() { - // static bool already_here = false; - // if (already_here) return; - // already_here = true; - // ... - // So, when descriptor.pb.cc's BuildDescriptors() is called recursively, it - // will end up just returning without doing anything. The result is that - // all of the descriptors for FileDescriptorProto and friends will just be - // NULL. - // - // Luckily, it turns out that our limited use of FileDescriptorProto within - // InternalBuildGeneratedFile() does not require that its descriptors be - // initialized. So, this ends up working. As soon as - // InternalBuildGeneratedFile() returns, the descriptors will be initialized - // by the original call to BuildDescriptors(), and everything will be happy - // again. - // - // If this turns out to be too fragile a hack, there are other ways we - // can accomplish bootstrapping here (like building the descriptor for - // descriptor.proto manually), but if this works then it's a lot easier. - // - // Note that because this is only triggered at static initialization time, - // there are no thread-safety concerns here. - GOOGLE_CHECK(fallback_database_ == NULL) - << "Cannot call BuildFile on a DescriptorPool that uses a " - "DescriptorDatabase. You must instead find a way to get your file " - "into the underlying database."; - GOOGLE_CHECK(mutex_ == NULL); // Implied by the above GOOGLE_CHECK. - - FileDescriptorProto proto; - GOOGLE_CHECK(proto.ParseFromArray(data, size)); - const FileDescriptor* result = - DescriptorBuilder(this, tables_.get(), NULL).BuildFile( - proto, descriptor_assigner); - - GOOGLE_CHECK(result != NULL); - - return result; + default_error_collector_).BuildFile(proto); } DescriptorBuilder::DescriptorBuilder( @@ -2189,8 +2298,8 @@ Symbol DescriptorBuilder::FindSymbol(const string& name) { return kNullSymbol; } -Symbol DescriptorBuilder::LookupSymbol( - const string& name, const string& relative_to) { +Symbol DescriptorBuilder::LookupSymbolNoPlaceholder( + const string& name, const string& relative_to, ResolveMode resolve_mode) { possible_undeclared_dependency_ = NULL; if (name.size() > 0 && name[0] == '.') { @@ -2237,11 +2346,20 @@ Symbol DescriptorBuilder::LookupSymbol( if (first_part_of_name.size() < name.size()) { // name is a compound symbol, of which we only found the first part. // Now try to look up the rest of it. - scope_to_try.append(name, first_part_of_name.size(), - name.size() - first_part_of_name.size()); - result = FindSymbol(scope_to_try); + if (result.IsAggregate()) { + scope_to_try.append(name, first_part_of_name.size(), + name.size() - first_part_of_name.size()); + return FindSymbol(scope_to_try); + } else { + // We found a symbol but it's not an aggregate. Continue the loop. + } + } else { + if (resolve_mode == LOOKUP_TYPES && !result.IsType()) { + // We found a symbol but it's not a type. Continue the loop. + } else { + return result; + } } - return result; } // Not found. Remove the name so we can try again. @@ -2249,6 +2367,134 @@ Symbol DescriptorBuilder::LookupSymbol( } } +Symbol DescriptorBuilder::LookupSymbol( + const string& name, const string& relative_to, + PlaceholderType placeholder_type, ResolveMode resolve_mode) { + Symbol result = LookupSymbolNoPlaceholder( + name, relative_to, resolve_mode); + if (result.IsNull() && pool_->allow_unknown_) { + // Not found, but AllowUnknownDependencies() is enabled. Return a + // placeholder instead. + result = NewPlaceholder(name, placeholder_type); + } + return result; +} + +Symbol DescriptorBuilder::NewPlaceholder(const string& name, + PlaceholderType placeholder_type) { + // Compute names. + const string* placeholder_full_name; + const string* placeholder_name; + const string* placeholder_package; + + if (!ValidateQualifiedName(name)) return kNullSymbol; + if (name[0] == '.') { + // Fully-qualified. + placeholder_full_name = tables_->AllocateString(name.substr(1)); + } else { + placeholder_full_name = tables_->AllocateString(name); + } + + string::size_type dotpos = placeholder_full_name->find_last_of('.'); + if (dotpos != string::npos) { + placeholder_package = tables_->AllocateString( + placeholder_full_name->substr(0, dotpos)); + placeholder_name = tables_->AllocateString( + placeholder_full_name->substr(dotpos + 1)); + } else { + placeholder_package = &kEmptyString; + placeholder_name = placeholder_full_name; + } + + // Create the placeholders. + FileDescriptor* placeholder_file = tables_->Allocate(); + memset(placeholder_file, 0, sizeof(*placeholder_file)); + + placeholder_file->name_ = + tables_->AllocateString(*placeholder_full_name + ".placeholder.proto"); + placeholder_file->package_ = placeholder_package; + placeholder_file->pool_ = pool_; + placeholder_file->options_ = &FileOptions::default_instance(); + placeholder_file->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + if (placeholder_type == PLACEHOLDER_ENUM) { + placeholder_file->enum_type_count_ = 1; + placeholder_file->enum_types_ = + tables_->AllocateArray(1); + + EnumDescriptor* placeholder_enum = &placeholder_file->enum_types_[0]; + memset(placeholder_enum, 0, sizeof(*placeholder_enum)); + + placeholder_enum->full_name_ = placeholder_full_name; + placeholder_enum->name_ = placeholder_name; + placeholder_enum->file_ = placeholder_file; + placeholder_enum->options_ = &EnumOptions::default_instance(); + placeholder_enum->is_placeholder_ = true; + placeholder_enum->is_unqualified_placeholder_ = (name[0] != '.'); + + // Enums must have at least one value. + placeholder_enum->value_count_ = 1; + placeholder_enum->values_ = tables_->AllocateArray(1); + + EnumValueDescriptor* placeholder_value = &placeholder_enum->values_[0]; + memset(placeholder_value, 0, sizeof(*placeholder_value)); + + placeholder_value->name_ = tables_->AllocateString("PLACEHOLDER_VALUE"); + // Note that enum value names are siblings of their type, not children. + placeholder_value->full_name_ = + placeholder_package->empty() ? placeholder_value->name_ : + tables_->AllocateString(*placeholder_package + ".PLACEHOLDER_VALUE"); + + placeholder_value->number_ = 0; + placeholder_value->type_ = placeholder_enum; + placeholder_value->options_ = &EnumValueOptions::default_instance(); + + return Symbol(placeholder_enum); + } else { + placeholder_file->message_type_count_ = 1; + placeholder_file->message_types_ = + tables_->AllocateArray(1); + + Descriptor* placeholder_message = &placeholder_file->message_types_[0]; + memset(placeholder_message, 0, sizeof(*placeholder_message)); + + placeholder_message->full_name_ = placeholder_full_name; + placeholder_message->name_ = placeholder_name; + placeholder_message->file_ = placeholder_file; + placeholder_message->options_ = &MessageOptions::default_instance(); + placeholder_message->is_placeholder_ = true; + placeholder_message->is_unqualified_placeholder_ = (name[0] != '.'); + + if (placeholder_type == PLACEHOLDER_EXTENDABLE_MESSAGE) { + placeholder_message->extension_range_count_ = 1; + placeholder_message->extension_ranges_ = + tables_->AllocateArray(1); + placeholder_message->extension_ranges_->start = 1; + // kMaxNumber + 1 because ExtensionRange::end is exclusive. + placeholder_message->extension_ranges_->end = + FieldDescriptor::kMaxNumber + 1; + } + + return Symbol(placeholder_message); + } +} + +const FileDescriptor* DescriptorBuilder::NewPlaceholderFile( + const string& name) { + FileDescriptor* placeholder = tables_->Allocate(); + memset(placeholder, 0, sizeof(*placeholder)); + + placeholder->name_ = tables_->AllocateString(name); + placeholder->package_ = &kEmptyString; + placeholder->pool_ = pool_; + placeholder->options_ = &FileOptions::default_instance(); + placeholder->tables_ = &FileDescriptorTables::kEmpty; + // All other fields are zero or NULL. + + return placeholder; +} + bool DescriptorBuilder::AddSymbol( const string& full_name, const void* parent, const string& name, const Message& proto, Symbol symbol) { @@ -2256,7 +2502,13 @@ bool DescriptorBuilder::AddSymbol( // Use its file as the parent instead. if (parent == NULL) parent = file_; - if (tables_->AddSymbol(full_name, parent, name, symbol)) { + if (tables_->AddSymbol(full_name, symbol)) { + if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) { + GOOGLE_LOG(DFATAL) << "\"" << full_name << "\" not previously defined in " + "symbols_by_name_, but was defined in symbols_by_parent_; " + "this shouldn't be possible."; + return false; + } return true; } else { const FileDescriptor* other_file = tables_->FindSymbol(full_name).GetFile(); @@ -2283,7 +2535,7 @@ bool DescriptorBuilder::AddSymbol( void DescriptorBuilder::AddPackage( const string& name, const Message& proto, const FileDescriptor* file) { - if (tables_->AddSymbol(name, NULL, name, Symbol(file))) { + if (tables_->AddSymbol(name, Symbol(file))) { // Success. Also add parent package, if any. string::size_type dot_pos = name.find_last_of('.'); if (dot_pos == string::npos) { @@ -2327,6 +2579,27 @@ void DescriptorBuilder::ValidateSymbolName( } } +bool DescriptorBuilder::ValidateQualifiedName(const string& name) { + bool last_was_period = false; + + for (int i = 0; i < name.size(); i++) { + // I don't trust isalnum() due to locales. :( + if (('a' <= name[i] && name[i] <= 'z') || + ('A' <= name[i] && name[i] <= 'Z') || + ('0' <= name[i] && name[i] <= '9') || + (name[i] == '_')) { + last_was_period = false; + } else if (name[i] == '.') { + if (last_was_period) return false; + last_was_period = true; + } else { + return false; + } + } + + return !name.empty() && !last_was_period; +} + // ------------------------------------------------------------------- // This generic implementation is good for all descriptors except @@ -2351,12 +2624,26 @@ template void DescriptorBuilder::AllocateOptionsImpl( const string& element_name, const typename DescriptorT::OptionsType& orig_options, DescriptorT* descriptor) { - typename DescriptorT::OptionsType* options = - tables_->AllocateMessage(); + // We need to use a dummy pointer to work around a bug in older versions of + // GCC. Otherwise, the following two lines could be replaced with: + // typename DescriptorT::OptionsType* options = + // tables_->AllocateMessage(); + typename DescriptorT::OptionsType* const dummy = NULL; + typename DescriptorT::OptionsType* options = tables_->AllocateMessage(dummy); options->CopyFrom(orig_options); - options_to_interpret_.push_back( - OptionsToInterpret(name_scope, element_name, &orig_options, options)); descriptor->options_ = options; + + // Don't add to options_to_interpret_ unless there were uninterpreted + // options. This not only avoids unnecessary work, but prevents a + // bootstrapping problem when building descriptors for descriptor.proto. + // descriptor.proto does not contain any uninterpreted options, but + // attempting to interpret options anyway will cause + // OptionsType::GetDescriptor() to be called which may then deadlock since + // we're still trying to build it. + if (options->uninterpreted_option_size() > 0) { + options_to_interpret_.push_back( + OptionsToInterpret(name_scope, element_name, &orig_options, options)); + } } @@ -2370,10 +2657,27 @@ template void DescriptorBuilder::AllocateOptionsImpl( } const FileDescriptor* DescriptorBuilder::BuildFile( - const FileDescriptorProto& proto, - DescriptorPool::InternalDescriptorAssigner descriptor_assigner) { + const FileDescriptorProto& proto) { filename_ = proto.name(); + // Check if the file already exists and is identical to the one being built. + // Note: This only works if the input is canonical -- that is, it + // fully-qualifies all type names, has no UninterpretedOptions, etc. + // This is fine, because this idempotency "feature" really only exists to + // accomodate one hack in the proto1->proto2 migration layer. + const FileDescriptor* existing_file = tables_->FindFile(filename_); + if (existing_file != NULL) { + // File already in pool. Compare the existing one to the input. + FileDescriptorProto existing_proto; + existing_file->CopyTo(&existing_proto); + if (existing_proto.SerializeAsString() == proto.SerializeAsString()) { + // They're identical. Return the existing descriptor. + return existing_file; + } + + // Not a match. The error will be detected and handled later. + } + // Check to see if this file is already on the pending files list. // TODO(kenton): Allow recursive imports? It may not work with some // (most?) programming languages. E.g., in C++, a forward declaration @@ -2420,6 +2724,9 @@ const FileDescriptor* DescriptorBuilder::BuildFile( FileDescriptor* result = tables_->Allocate(); file_ = result; + file_tables_ = tables_->AllocateFileTables(); + file_->tables_ = file_tables_; + if (!proto.has_name()) { AddError("", proto, DescriptorPool::ErrorCollector::OTHER, "Missing field: FileDescriptorProto.name."); @@ -2468,17 +2775,21 @@ const FileDescriptor* DescriptorBuilder::BuildFile( } if (dependency == NULL) { - string message; - if (pool_->fallback_database_ == NULL) { - message = "Import \"" + proto.dependency(i) + - "\" has not been loaded."; + if (pool_->allow_unknown_) { + dependency = NewPlaceholderFile(proto.dependency(i)); } else { - message = "Import \"" + proto.dependency(i) + - "\" was not found or had errors."; + string message; + if (pool_->fallback_database_ == NULL) { + message = "Import \"" + proto.dependency(i) + + "\" has not been loaded."; + } else { + message = "Import \"" + proto.dependency(i) + + "\" was not found or had errors."; + } + AddError(proto.name(), proto, + DescriptorPool::ErrorCollector::OTHER, + message); } - AddError(proto.name(), proto, - DescriptorPool::ErrorCollector::OTHER, - message); } result->dependencies_[i] = dependency; @@ -2499,11 +2810,6 @@ const FileDescriptor* DescriptorBuilder::BuildFile( // Note that the following steps must occur in exactly the specified order. - // Assign descriptors, if needed. - if (descriptor_assigner != NULL) { - (*descriptor_assigner)(result); - } - // Cross-link. CrossLinkFile(result, proto); @@ -2549,6 +2855,8 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, result->full_name_ = full_name; result->file_ = file_; result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; BUILD_ARRAY(proto, result, field , BuildField , result); BUILD_ARRAY(proto, result, nested_type , BuildMessage , result); @@ -2648,6 +2956,12 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, result->enum_type_ = NULL; result->has_default_value_ = proto.has_default_value(); + if (proto.has_default_value() && result->is_repeated()) { + AddError(result->full_name(), proto, + DescriptorPool::ErrorCollector::DEFAULT_VALUE, + "Repeated fields can't have default values."); + } + if (proto.has_type()) { if (proto.has_default_value()) { char* end_pos = NULL; @@ -2842,6 +3156,8 @@ void DescriptorBuilder::BuildEnum(const EnumDescriptorProto& proto, result->full_name_ = full_name; result->file_ = file_; result->containing_type_ = parent; + result->is_placeholder_ = false; + result->is_unqualified_placeholder_ = false; if (proto.value_size() == 0) { // We cannot allow enums with no values because this would mean there @@ -2899,7 +3215,7 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto, // Note: This could fail, but if it does, the error has already been // reported by the above AddSymbol() call, so we ignore the return code. bool added_to_inner_scope = - tables_->AddAliasUnderParent(parent, result->name(), Symbol(result)); + file_tables_->AddAliasUnderParent(parent, result->name(), Symbol(result)); if (added_to_inner_scope && !added_to_outer_scope) { // This value did not conflict with any values defined in the same enum, @@ -2929,7 +3245,7 @@ void DescriptorBuilder::BuildEnumValue(const EnumValueDescriptorProto& proto, // An enum is allowed to define two numbers that refer to the same value. // FindValueByNumber() should return the first such value, so we simply // ignore AddEnumValueByNumber()'s return code. - tables_->AddEnumValueByNumber(result); + file_tables_->AddEnumValueByNumber(result); } void DescriptorBuilder::BuildService(const ServiceDescriptorProto& proto, @@ -3043,7 +3359,8 @@ void DescriptorBuilder::CrossLinkField( } if (proto.has_extendee()) { - Symbol extendee = LookupSymbol(proto.extendee(), field->full_name()); + Symbol extendee = LookupSymbol(proto.extendee(), field->full_name(), + PLACEHOLDER_EXTENDABLE_MESSAGE); if (extendee.IsNull()) { AddNotDefinedError(field->full_name(), proto, DescriptorPool::ErrorCollector::EXTENDEE, @@ -3068,7 +3385,17 @@ void DescriptorBuilder::CrossLinkField( } if (proto.has_type_name()) { - Symbol type = LookupSymbol(proto.type_name(), field->full_name()); + // Assume we are expecting a message type unless the proto contains some + // evidence that it expects an enum type. This only makes a difference if + // we end up creating a placeholder. + bool expecting_enum = (proto.type() == FieldDescriptorProto::TYPE_ENUM) || + proto.has_default_value(); + + Symbol type = + LookupSymbol(proto.type_name(), field->full_name(), + expecting_enum ? PLACEHOLDER_ENUM : PLACEHOLDER_MESSAGE, + LOOKUP_TYPES); + if (type.IsNull()) { AddNotDefinedError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, @@ -3113,12 +3440,19 @@ void DescriptorBuilder::CrossLinkField( } field->enum_type_ = type.enum_descriptor; + if (field->enum_type()->is_placeholder_) { + // We can't look up default values for placeholder types. We'll have + // to just drop them. + field->has_default_value_ = false; + } + if (field->has_default_value()) { // We can't just use field->enum_type()->FindValueByName() here // because that locks the pool's mutex, which we have already locked // at this point. Symbol default_value = - LookupSymbol(proto.default_value(), field->enum_type()->full_name()); + LookupSymbolNoPlaceholder(proto.default_value(), + field->enum_type()->full_name()); if (default_value.type == Symbol::ENUM_VALUE && default_value.enum_value_descriptor->type() == field->enum_type()) { @@ -3150,9 +3484,10 @@ void DescriptorBuilder::CrossLinkField( // Add the field to the fields-by-number table. // Note: We have to do this *after* cross-linking because extensions do not // know their containing type until now. - if (!tables_->AddFieldByNumber(field)) { + if (!file_tables_->AddFieldByNumber(field)) { const FieldDescriptor* conflicting_field = - tables_->FindFieldByNumber(field->containing_type(), field->number()); + file_tables_->FindFieldByNumber(field->containing_type(), + field->number()); if (field->is_extension()) { AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::NUMBER, @@ -3172,8 +3507,14 @@ void DescriptorBuilder::CrossLinkField( } } + if (field->is_extension()) { + // No need for error checking: if the extension number collided, + // we've already been informed of it by the if() above. + tables_->AddExtension(field); + } + // Add the field to the lowercase-name and camelcase-name tables. - tables_->AddFieldByStylizedNames(field); + file_tables_->AddFieldByStylizedNames(field); } void DescriptorBuilder::CrossLinkEnum( @@ -3397,6 +3738,14 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions( bool failed = false; options_to_interpret_ = options_to_interpret; + // Find the uninterpreted_option field in the mutable copy of the options + // and clear them, since we're about to interpret them. + const FieldDescriptor* uninterpreted_options_field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(uninterpreted_options_field != NULL) + << "No field named \"uninterpreted_option\" in the Options proto."; + options->GetReflection()->ClearField(options, uninterpreted_options_field); + // Find the uninterpreted_option field in the original options. const FieldDescriptor* original_uninterpreted_options_field = original_options->GetDescriptor()-> @@ -3421,17 +3770,6 @@ bool DescriptorBuilder::OptionInterpreter::InterpretOptions( options_to_interpret_ = NULL; if (!failed) { - // Find the uninterpreted_option field in the mutable copy of the options. - const FieldDescriptor* uninterpreted_options_field = - options->GetDescriptor()->FindFieldByName("uninterpreted_option"); - GOOGLE_CHECK(uninterpreted_options_field != NULL) - << "No field named \"uninterpreted_option\" in the Options proto."; - - // We don't want to carry around the uninterpreted options, now that we've - // interpreted them. - options->GetReflection()->ClearField(options, uninterpreted_options_field); - - // InterpretSingleOption() added the interpreted options in the // UnknownFieldSet, in case the option isn't yet known to us. Now we // serialize the options message and deserialize it back. That way, any @@ -3517,36 +3855,36 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( // you use, so they must be present in the builder's pool. } else { debug_msg_name += name_part; - // Search for the field's descriptor as a regular field in the builder's - // pool. First we must qualify it by its message name. Note that we use - // DescriptorBuilder::FindSymbolNotEnforcingDeps(), not - // DescriptorPool::FindFieldByName() because we're already holding the - // pool's mutex, and the latter method locks it again. We must not - // enforce dependencies here because we did not enforce dependencies - // when looking up |descriptor|, and we need the two to match. - string fully_qualified_name = descriptor->full_name() + "." + name_part; - Symbol symbol = - builder_->FindSymbolNotEnforcingDeps(fully_qualified_name); - if (!symbol.IsNull() && symbol.type == Symbol::FIELD) { - field = symbol.field_descriptor; - } else { - // The field's descriptor was not in the builder's pool, so search for - // the standard version from the generated pool. We're not holding the - // generated pool's mutex, so we can search it the straightforward way. - field = DescriptorPool::generated_pool()->FindFieldByName( - fully_qualified_name); - } + // Search for the field's descriptor as a regular field. + field = descriptor->FindFieldByName(name_part); } if (field == NULL) { - return AddNameError("Option \"" + debug_msg_name + "\" unknown."); + if (get_allow_unknown(builder_->pool_)) { + // We can't find the option, but AllowUnknownDependencies() is enabled, + // so we will just leave it as uninterpreted. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + return AddNameError("Option \"" + debug_msg_name + "\" unknown."); + } } else if (field->containing_type() != descriptor) { - // This can only happen if, due to some insane misconfiguration of the - // pools, we find the options message in one pool but the field in - // another. This would probably imply a hefty bug somewhere. - return AddNameError("Option field \"" + debug_msg_name + - "\" is not a field or extension of message \"" + - descriptor->name() + "\"."); + if (get_is_placeholder(field->containing_type())) { + // The field is an extension of a placeholder type, so we can't + // reliably verify whether it is a valid extension to use here (e.g. + // we don't know if it is an extension of the correct *Options message, + // or if it has a valid field number, etc.). Just leave it as + // uninterpreted instead. + AddWithoutInterpreting(*uninterpreted_option_, options); + return true; + } else { + // This can only happen if, due to some insane misconfiguration of the + // pools, we find the options message in one pool but the field in + // another. This would probably imply a hefty bug somewhere. + return AddNameError("Option field \"" + debug_msg_name + + "\" is not a field or extension of message \"" + + descriptor->name() + "\"."); + } } else if (field->is_repeated()) { return AddNameError("Option field \"" + debug_msg_name + "\" is repeated. Repeated options are not " @@ -3586,7 +3924,7 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( // First set the value on the UnknownFieldSet corresponding to the // innermost message. scoped_ptr unknown_fields(new UnknownFieldSet()); - if (!SetOptionValue(field, unknown_fields.get()->AddField(field->number()))) { + if (!SetOptionValue(field, unknown_fields.get())) { return false; // SetOptionValue() already added the error. } @@ -3599,19 +3937,18 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( switch ((*iter)->type()) { case FieldDescriptor::TYPE_MESSAGE: { io::StringOutputStream outstr( - parent_unknown_fields->AddField((*iter)->number())-> - add_length_delimited()); + parent_unknown_fields->AddLengthDelimited((*iter)->number())); io::CodedOutputStream out(&outstr); - GOOGLE_CHECK(internal::WireFormat::SerializeUnknownFields(*unknown_fields, - &out)) + internal::WireFormat::SerializeUnknownFields(*unknown_fields, &out); + GOOGLE_CHECK(!out.HadError()) << "Unexpected failure while serializing option submessage " << debug_msg_name << "\"."; break; } case FieldDescriptor::TYPE_GROUP: { - parent_unknown_fields->AddField((*iter)->number())-> - add_group()->MergeFrom(*unknown_fields); + parent_unknown_fields->AddGroup((*iter)->number()) + ->MergeFrom(*unknown_fields); break; } @@ -3631,56 +3968,73 @@ bool DescriptorBuilder::OptionInterpreter::InterpretSingleOption( return true; } +void DescriptorBuilder::OptionInterpreter::AddWithoutInterpreting( + const UninterpretedOption& uninterpreted_option, Message* options) { + const FieldDescriptor* field = + options->GetDescriptor()->FindFieldByName("uninterpreted_option"); + GOOGLE_CHECK(field != NULL); + + options->GetReflection()->AddMessage(options, field) + ->CopyFrom(uninterpreted_option); +} + bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet( vector::const_iterator intermediate_fields_iter, vector::const_iterator intermediate_fields_end, const FieldDescriptor* innermost_field, const string& debug_msg_name, const UnknownFieldSet& unknown_fields) { + // We do linear searches of the UnknownFieldSet and its sub-groups. This + // should be fine since it's unlikely that any one options structure will + // contain more than a handful of options. + if (intermediate_fields_iter == intermediate_fields_end) { // We're at the innermost submessage. - if (unknown_fields.FindFieldByNumber(innermost_field->number()) != NULL) { - return AddNameError("Option \"" + debug_msg_name + - "\" was already set."); - } else { - return true; + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == innermost_field->number()) { + return AddNameError("Option \"" + debug_msg_name + + "\" was already set."); + } } + return true; } - const UnknownField* unknown_field = unknown_fields.FindFieldByNumber( - (*intermediate_fields_iter)->number()); - if (unknown_field != NULL) { - FieldDescriptor::Type type = (*intermediate_fields_iter)->type(); - // Recurse into the next submessage. - ++intermediate_fields_iter; - switch (type) { - case FieldDescriptor::TYPE_MESSAGE: - for (int i = 0; i < unknown_field->length_delimited_size(); ++i) { - UnknownFieldSet intermediate_unknown_fields; - if (intermediate_unknown_fields.ParseFromString( - unknown_field->length_delimited(i)) && - !ExamineIfOptionIsSet(intermediate_fields_iter, - intermediate_fields_end, - innermost_field, debug_msg_name, - intermediate_unknown_fields)) { - return false; // Error already added. + for (int i = 0; i < unknown_fields.field_count(); i++) { + if (unknown_fields.field(i).number() == + (*intermediate_fields_iter)->number()) { + const UnknownField* unknown_field = &unknown_fields.field(i); + FieldDescriptor::Type type = (*intermediate_fields_iter)->type(); + // Recurse into the next submessage. + ++intermediate_fields_iter; + switch (type) { + case FieldDescriptor::TYPE_MESSAGE: + if (unknown_field->type() == UnknownField::TYPE_LENGTH_DELIMITED) { + UnknownFieldSet intermediate_unknown_fields; + if (intermediate_unknown_fields.ParseFromString( + unknown_field->length_delimited()) && + !ExamineIfOptionIsSet(intermediate_fields_iter, + intermediate_fields_end, + innermost_field, debug_msg_name, + intermediate_unknown_fields)) { + return false; // Error already added. + } } - } - break; + break; - case FieldDescriptor::TYPE_GROUP: - for (int i = 0; i < unknown_field->group_size(); ++i) { - if (!ExamineIfOptionIsSet(intermediate_fields_iter, - intermediate_fields_end, - innermost_field, debug_msg_name, - unknown_field->group(i))) { - return false; // Error already added. + case FieldDescriptor::TYPE_GROUP: + if (unknown_field->type() == UnknownField::TYPE_GROUP) { + if (!ExamineIfOptionIsSet(intermediate_fields_iter, + intermediate_fields_end, + innermost_field, debug_msg_name, + unknown_field->group())) { + return false; // Error already added. + } } - } - break; + break; - default: - GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type; - return false; + default: + GOOGLE_LOG(FATAL) << "Invalid wire type for CPPTYPE_MESSAGE: " << type; + return false; + } } } return true; @@ -3688,7 +4042,7 @@ bool DescriptorBuilder::OptionInterpreter::ExamineIfOptionIsSet( bool DescriptorBuilder::OptionInterpreter::SetOptionValue( const FieldDescriptor* option_field, - UnknownField* unknown_field) { + UnknownFieldSet* unknown_fields) { // We switch on the CppType to validate. switch (option_field->cpp_type()) { @@ -3699,8 +4053,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int32 option \"" + option_field->full_name() + "\"."); } else { - SetInt32(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else if (uninterpreted_option_->has_negative_int_value()) { if (uninterpreted_option_->negative_int_value() < @@ -3708,8 +4063,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int32 option \"" + option_field->full_name() + "\"."); } else { - SetInt32(uninterpreted_option_->negative_int_value(), - option_field->type(), unknown_field); + SetInt32(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); } } else { return AddValueError("Value must be integer for int32 option \"" + @@ -3724,12 +4080,14 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for int64 option \"" + option_field->full_name() + "\"."); } else { - SetInt64(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else if (uninterpreted_option_->has_negative_int_value()) { - SetInt64(uninterpreted_option_->negative_int_value(), - option_field->type(), unknown_field); + SetInt64(option_field->number(), + uninterpreted_option_->negative_int_value(), + option_field->type(), unknown_fields); } else { return AddValueError("Value must be integer for int64 option \"" + option_field->full_name() + "\"."); @@ -3742,8 +4100,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value out of range for uint32 option \"" + option_field->name() + "\"."); } else { - SetUInt32(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetUInt32(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } } else { return AddValueError("Value must be non-negative integer for uint32 " @@ -3753,8 +4112,9 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( case FieldDescriptor::CPPTYPE_UINT64: if (uninterpreted_option_->has_positive_int_value()) { - SetUInt64(uninterpreted_option_->positive_int_value(), - option_field->type(), unknown_field); + SetUInt64(option_field->number(), + uninterpreted_option_->positive_int_value(), + option_field->type(), unknown_fields); } else { return AddValueError("Value must be non-negative integer for uint64 " "option \"" + option_field->full_name() + "\"."); @@ -3773,7 +4133,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be number for float option \"" + option_field->full_name() + "\"."); } - unknown_field->add_fixed32( + unknown_fields->AddFixed32(option_field->number(), google::protobuf::internal::WireFormat::EncodeFloat(value)); break; } @@ -3790,7 +4150,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be number for double option \"" + option_field->full_name() + "\"."); } - unknown_field->add_fixed64( + unknown_fields->AddFixed64(option_field->number(), google::protobuf::internal::WireFormat::EncodeDouble(value)); break; } @@ -3809,7 +4169,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return AddValueError("Value must be \"true\" or \"false\" for boolean " "option \"" + option_field->full_name() + "\"."); } - unknown_field->add_varint(value); + unknown_fields->AddVarint(option_field->number(), value); break; case FieldDescriptor::CPPTYPE_ENUM: { @@ -3859,8 +4219,8 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( } else { // Sign-extension is not a problem, since we cast directly from int32 to // uint64, without first going through uint32. - unknown_field->add_varint(static_cast( - static_cast(enum_value->number()))); + unknown_fields->AddVarint(option_field->number(), + static_cast(static_cast(enum_value->number()))); } break; } @@ -3871,7 +4231,7 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( "\"" + option_field->full_name() + "\"."); } // The string has already been unquoted and unescaped by the parser. - unknown_field->add_length_delimited( + unknown_fields->AddLengthDelimited(option_field->number(), uninterpreted_option_->string_value()); break; @@ -3888,19 +4248,20 @@ bool DescriptorBuilder::OptionInterpreter::SetOptionValue( return true; } -void DescriptorBuilder::OptionInterpreter::SetInt32(int32 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetInt32(int number, int32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_INT32: - unknown_field->add_varint(static_cast(static_cast(value))); + unknown_fields->AddVarint(number, + static_cast(static_cast(value))); break; case FieldDescriptor::TYPE_SFIXED32: - unknown_field->add_fixed32(static_cast(value)); + unknown_fields->AddFixed32(number, static_cast(value)); break; case FieldDescriptor::TYPE_SINT32: - unknown_field->add_varint( + unknown_fields->AddVarint(number, google::protobuf::internal::WireFormat::ZigZagEncode32(value)); break; @@ -3910,19 +4271,19 @@ void DescriptorBuilder::OptionInterpreter::SetInt32(int32 value, } } -void DescriptorBuilder::OptionInterpreter::SetInt64(int64 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetInt64(int number, int64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_INT64: - unknown_field->add_varint(static_cast(value)); + unknown_fields->AddVarint(number, static_cast(value)); break; case FieldDescriptor::TYPE_SFIXED64: - unknown_field->add_fixed64(static_cast(value)); + unknown_fields->AddFixed64(number, static_cast(value)); break; case FieldDescriptor::TYPE_SINT64: - unknown_field->add_varint( + unknown_fields->AddVarint(number, google::protobuf::internal::WireFormat::ZigZagEncode64(value)); break; @@ -3932,15 +4293,15 @@ void DescriptorBuilder::OptionInterpreter::SetInt64(int64 value, } } -void DescriptorBuilder::OptionInterpreter::SetUInt32(uint32 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetUInt32(int number, uint32 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_UINT32: - unknown_field->add_varint(static_cast(value)); + unknown_fields->AddVarint(number, static_cast(value)); break; case FieldDescriptor::TYPE_FIXED32: - unknown_field->add_fixed32(static_cast(value)); + unknown_fields->AddFixed32(number, static_cast(value)); break; default: @@ -3949,15 +4310,15 @@ void DescriptorBuilder::OptionInterpreter::SetUInt32(uint32 value, } } -void DescriptorBuilder::OptionInterpreter::SetUInt64(uint64 value, - FieldDescriptor::Type type, UnknownField* unknown_field) { +void DescriptorBuilder::OptionInterpreter::SetUInt64(int number, uint64 value, + FieldDescriptor::Type type, UnknownFieldSet* unknown_fields) { switch (type) { case FieldDescriptor::TYPE_UINT64: - unknown_field->add_varint(value); + unknown_fields->AddVarint(number, value); break; case FieldDescriptor::TYPE_FIXED64: - unknown_field->add_fixed64(value); + unknown_fields->AddFixed64(number, value); break; default: diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 918aafbc..5b629a5d 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -55,6 +55,7 @@ #define GOOGLE_PROTOBUF_DESCRIPTOR_H__ #include +#include #include @@ -94,6 +95,7 @@ class Message; // Defined in descriptor.cc class DescriptorBuilder; +class FileDescriptorTables; // Defined in unknown_field_set.h. class UnknownField; @@ -246,6 +248,12 @@ class LIBPROTOBUF_EXPORT Descriptor { const FileDescriptor* file_; const Descriptor* containing_type_; const MessageOptions* options_; + + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + int field_count_; FieldDescriptor* fields_; int nested_type_count_; @@ -256,12 +264,16 @@ class LIBPROTOBUF_EXPORT Descriptor { ExtensionRange* extension_ranges_; int extension_count_; FieldDescriptor* extensions_; + // 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. // Must be constructed using DescriptorPool. Descriptor() {} friend class DescriptorBuilder; friend class EnumDescriptor; friend class FieldDescriptor; + friend class MethodDescriptor; friend class FileDescriptor; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Descriptor); }; @@ -458,6 +470,10 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // See Descriptor::DebugString(). string DebugString() const; + + // Helper method to get the CppType for a particular Type. + static CppType TypeToCppType(Type type); + private: typedef FieldOptions OptionsType; @@ -484,6 +500,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { const EnumDescriptor* enum_type_; const FieldDescriptor* experimental_map_key_; const FieldOptions* options_; + // 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. bool has_default_value_; union { @@ -568,15 +587,25 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { const string* name_; const string* full_name_; const FileDescriptor* file_; - int value_count_; - EnumValueDescriptor* values_; const Descriptor* containing_type_; const EnumOptions* options_; + // True if this is a placeholder for an unknown type. + bool is_placeholder_; + // True if this is a placeholder and the type name wasn't fully-qualified. + bool is_unqualified_placeholder_; + + int value_count_; + EnumValueDescriptor* values_; + // 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. + // Must be constructed using DescriptorPool. EnumDescriptor() {} friend class DescriptorBuilder; friend class Descriptor; + friend class FieldDescriptor; friend class EnumValueDescriptor; friend class FileDescriptor; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); @@ -627,6 +656,9 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { int number_; const EnumDescriptor* type_; const EnumValueOptions* options_; + // 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. // Must be constructed using DescriptorPool. EnumValueDescriptor() {} @@ -685,6 +717,9 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor { const ServiceOptions* options_; int method_count_; MethodDescriptor* methods_; + // 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. // Must be constructed using DescriptorPool. ServiceDescriptor() {} @@ -740,6 +775,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { const Descriptor* input_type_; const Descriptor* output_type_; const MethodOptions* options_; + // 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. // Must be constructed using DescriptorPool. MethodDescriptor() {} @@ -846,6 +884,11 @@ class LIBPROTOBUF_EXPORT FileDescriptor { FieldDescriptor* extensions_; const FileOptions* options_; + const FileDescriptorTables* tables_; + // 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. + FileDescriptor() {} friend class DescriptorBuilder; friend class Descriptor; @@ -945,6 +988,14 @@ class LIBPROTOBUF_EXPORT DescriptorPool { const FieldDescriptor* FindExtensionByNumber(const Descriptor* extendee, int number) const; + // Finds extensions of extendee. The extensions will be appended to + // out in an undefined order. Only extensions defined directly in + // this DescriptorPool or one of its underlays are guaranteed to be + // found: extensions defined in the fallback database might not be found + // depending on the database implementation. + void FindAllExtensions(const Descriptor* extendee, + vector* out) const; + // Building descriptors -------------------------------------------- // When converting a FileDescriptorProto to a FileDescriptor, various @@ -996,6 +1047,23 @@ class LIBPROTOBUF_EXPORT DescriptorPool { const FileDescriptorProto& proto, ErrorCollector* error_collector); + // By default, it is an error if a FileDescriptorProto contains references + // to types or other files that are not found in the DescriptorPool (or its + // backing DescriptorDatabase, if any). If you call + // AllowUnknownDependencies(), however, then unknown types and files + // will be replaced by placeholder descriptors. This can allow you to + // perform some useful operations with a .proto file even if you do not + // have access to other .proto files on which it depends. However, some + // heuristics must be used to fill in the gaps in information, and these + // can lead to descriptors which are inaccurate. For example, the + // DescriptorPool may be forced to guess whether an unknown type is a message + // or an enum, as well as what package it resides in. Furthermore, + // placeholder types will not be discoverable via FindMessageTypeByName() + // and similar methods, which could confuse some descriptor-based algorithms. + // Generally, the results of this option should only be relied upon for + // debugging purposes. + void AllowUnknownDependencies() { allow_unknown_ = true; } + // Internal stuff -------------------------------------------------- // These methods MUST NOT be called from outside the proto2 library. // These methods may contain hidden pitfalls and may be removed in a @@ -1024,12 +1092,12 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // underlay for a new DescriptorPool in which you add only the new file. explicit DescriptorPool(const DescriptorPool* underlay); - // Called by generated classes at init time. Do NOT call this in your own - // code! descriptor_assigner, if not NULL, is used to assign global - // descriptor pointers at the appropriate point during building. - typedef void (*InternalDescriptorAssigner)(const FileDescriptor*); - const FileDescriptor* InternalBuildGeneratedFile( - const void* data, int size, InternalDescriptorAssigner descriptor_assigner); + // Called by generated classes at init time to add their descriptors to + // generated_pool. Do NOT call this in your own code! filename must be a + // permanent string (e.g. a string literal). + static void InternalAddGeneratedFile( + const void* encoded_file_descriptor, int size); + // For internal use only: Gets a non-const pointer to the generated pool. // This is called at static-initialization time only, so thread-safety is @@ -1047,6 +1115,11 @@ class LIBPROTOBUF_EXPORT DescriptorPool { underlay_ = underlay; } + // For internal (unit test) use only: Returns true if a FileDescriptor has + // been constructed for the given file, false otherwise. Useful for testing + // lazy descriptor initialization behavior. + bool InternalIsFileLoaded(const string& filename) const; + private: friend class Descriptor; friend class FieldDescriptor; @@ -1085,9 +1158,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool { scoped_ptr tables_; bool enforce_dependencies_; - - // See InternalBuildGeneratedFile(). - const void* last_internal_build_generated_file_call_; + bool allow_unknown_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPool); }; @@ -1267,6 +1338,10 @@ inline FieldDescriptor::CppType FieldDescriptor::cpp_type() const { return kTypeToCppTypeMap[type_]; } +inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { + return kTypeToCppTypeMap[type]; +} + inline const FileDescriptor* FileDescriptor::dependency(int index) const { return dependencies_[index]; } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 8d1b7e3e..6f0b5b54 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -1,6 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! #include "google/protobuf/descriptor.pb.h" +#include #include #include #include @@ -73,9 +74,13 @@ const ::google::protobuf::internal::GeneratedMessageReflection* } // namespace -void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors(const ::google::protobuf::FileDescriptor* file) { +void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + const ::google::protobuf::FileDescriptor* file = + ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( + "google/protobuf/descriptor.proto"); + GOOGLE_CHECK(file != NULL); FileDescriptorSet_descriptor_ = file->message_type(0); - FileDescriptorSet::default_instance_ = new FileDescriptorSet(); static const int FileDescriptorSet_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, file_), }; @@ -88,11 +93,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(FileDescriptorSet)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - FileDescriptorSet_descriptor_, FileDescriptorSet::default_instance_); FileDescriptorProto_descriptor_ = file->message_type(1); - FileDescriptorProto::default_instance_ = new FileDescriptorProto(); static const int FileDescriptorProto_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, package_), @@ -112,11 +115,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(FileDescriptorProto)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - FileDescriptorProto_descriptor_, FileDescriptorProto::default_instance_); DescriptorProto_descriptor_ = file->message_type(2); - DescriptorProto::default_instance_ = new DescriptorProto(); static const int DescriptorProto_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, field_), @@ -135,9 +136,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(DescriptorProto)); DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0); - DescriptorProto_ExtensionRange::default_instance_ = new DescriptorProto_ExtensionRange(); static const int DescriptorProto_ExtensionRange_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, end_), @@ -151,13 +152,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(DescriptorProto_ExtensionRange)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - DescriptorProto_ExtensionRange_descriptor_, DescriptorProto_ExtensionRange::default_instance_); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - DescriptorProto_descriptor_, DescriptorProto::default_instance_); FieldDescriptorProto_descriptor_ = file->message_type(3); - FieldDescriptorProto::default_instance_ = new FieldDescriptorProto(); static const int FieldDescriptorProto_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, number_), @@ -177,13 +174,11 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(FieldDescriptorProto)); FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0); FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - FieldDescriptorProto_descriptor_, FieldDescriptorProto::default_instance_); EnumDescriptorProto_descriptor_ = file->message_type(4); - EnumDescriptorProto::default_instance_ = new EnumDescriptorProto(); static const int EnumDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, value_), @@ -198,11 +193,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(EnumDescriptorProto)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - EnumDescriptorProto_descriptor_, EnumDescriptorProto::default_instance_); EnumValueDescriptorProto_descriptor_ = file->message_type(5); - EnumValueDescriptorProto::default_instance_ = new EnumValueDescriptorProto(); static const int EnumValueDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, number_), @@ -217,11 +210,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(EnumValueDescriptorProto)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - EnumValueDescriptorProto_descriptor_, EnumValueDescriptorProto::default_instance_); ServiceDescriptorProto_descriptor_ = file->message_type(6); - ServiceDescriptorProto::default_instance_ = new ServiceDescriptorProto(); static const int ServiceDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, method_), @@ -236,11 +227,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(ServiceDescriptorProto)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - ServiceDescriptorProto_descriptor_, ServiceDescriptorProto::default_instance_); MethodDescriptorProto_descriptor_ = file->message_type(7); - MethodDescriptorProto::default_instance_ = new MethodDescriptorProto(); static const int MethodDescriptorProto_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_), @@ -256,11 +245,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(MethodDescriptorProto)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - MethodDescriptorProto_descriptor_, MethodDescriptorProto::default_instance_); FileOptions_descriptor_ = file->message_type(8); - FileOptions::default_instance_ = new FileOptions(); static const int FileOptions_offsets_[5] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), @@ -277,12 +264,10 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(FileOptions)); FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - FileOptions_descriptor_, FileOptions::default_instance_); MessageOptions_descriptor_ = file->message_type(9); - MessageOptions::default_instance_ = new MessageOptions(); static const int MessageOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, message_set_wire_format_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, uninterpreted_option_), @@ -296,14 +281,13 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(MessageOptions)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - MessageOptions_descriptor_, MessageOptions::default_instance_); FieldOptions_descriptor_ = file->message_type(10); - FieldOptions::default_instance_ = new FieldOptions(); - static const int FieldOptions_offsets_[4] = { + static const int FieldOptions_offsets_[5] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, deprecated_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_), }; @@ -316,12 +300,10 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(FieldOptions)); FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - FieldOptions_descriptor_, FieldOptions::default_instance_); EnumOptions_descriptor_ = file->message_type(11); - EnumOptions::default_instance_ = new EnumOptions(); static const int EnumOptions_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, uninterpreted_option_), }; @@ -334,11 +316,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(EnumOptions)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - EnumOptions_descriptor_, EnumOptions::default_instance_); EnumValueOptions_descriptor_ = file->message_type(12); - EnumValueOptions::default_instance_ = new EnumValueOptions(); static const int EnumValueOptions_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_), }; @@ -351,11 +331,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(EnumValueOptions)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - EnumValueOptions_descriptor_, EnumValueOptions::default_instance_); ServiceOptions_descriptor_ = file->message_type(13); - ServiceOptions::default_instance_ = new ServiceOptions(); static const int ServiceOptions_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_), }; @@ -368,11 +346,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(ServiceOptions)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - ServiceOptions_descriptor_, ServiceOptions::default_instance_); MethodOptions_descriptor_ = file->message_type(14); - MethodOptions::default_instance_ = new MethodOptions(); static const int MethodOptions_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_), }; @@ -385,11 +361,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _unknown_fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_), ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(MethodOptions)); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - MethodOptions_descriptor_, MethodOptions::default_instance_); UninterpretedOption_descriptor_ = file->message_type(15); - UninterpretedOption::default_instance_ = new UninterpretedOption(); static const int UninterpretedOption_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, identifier_value_), @@ -407,9 +381,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(UninterpretedOption)); UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0); - UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart(); static const int UninterpretedOption_NamePart_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, is_extension_), @@ -423,40 +397,67 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _unknown_fields_), -1, ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), sizeof(UninterpretedOption_NamePart)); +} + +namespace { + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); +inline void protobuf_AssignDescriptorsOnce() { + ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, + &protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto); +} + +void protobuf_RegisterTypes() { + protobuf_AssignDescriptorsOnce(); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - UninterpretedOption_NamePart_descriptor_, UninterpretedOption_NamePart::default_instance_); + FileDescriptorSet_descriptor_, &FileDescriptorSet::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - UninterpretedOption_descriptor_, UninterpretedOption::default_instance_); - FileDescriptorSet::default_instance_->InitAsDefaultInstance(); - FileDescriptorProto::default_instance_->InitAsDefaultInstance(); - DescriptorProto::default_instance_->InitAsDefaultInstance(); - DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance(); - FieldDescriptorProto::default_instance_->InitAsDefaultInstance(); - EnumDescriptorProto::default_instance_->InitAsDefaultInstance(); - EnumValueDescriptorProto::default_instance_->InitAsDefaultInstance(); - ServiceDescriptorProto::default_instance_->InitAsDefaultInstance(); - MethodDescriptorProto::default_instance_->InitAsDefaultInstance(); - FileOptions::default_instance_->InitAsDefaultInstance(); - MessageOptions::default_instance_->InitAsDefaultInstance(); - FieldOptions::default_instance_->InitAsDefaultInstance(); - EnumOptions::default_instance_->InitAsDefaultInstance(); - EnumValueOptions::default_instance_->InitAsDefaultInstance(); - ServiceOptions::default_instance_->InitAsDefaultInstance(); - MethodOptions::default_instance_->InitAsDefaultInstance(); - UninterpretedOption::default_instance_->InitAsDefaultInstance(); - UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance(); + FileDescriptorProto_descriptor_, &FileDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + DescriptorProto_descriptor_, &DescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + DescriptorProto_ExtensionRange_descriptor_, &DescriptorProto_ExtensionRange::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FieldDescriptorProto_descriptor_, &FieldDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumDescriptorProto_descriptor_, &EnumDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumValueDescriptorProto_descriptor_, &EnumValueDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + ServiceDescriptorProto_descriptor_, &ServiceDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MethodDescriptorProto_descriptor_, &MethodDescriptorProto::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FileOptions_descriptor_, &FileOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MessageOptions_descriptor_, &MessageOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + FieldOptions_descriptor_, &FieldOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumOptions_descriptor_, &EnumOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + EnumValueOptions_descriptor_, &EnumValueOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + ServiceOptions_descriptor_, &ServiceOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + MethodOptions_descriptor_, &MethodOptions::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + UninterpretedOption_descriptor_, &UninterpretedOption::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + UninterpretedOption_NamePart_descriptor_, &UninterpretedOption_NamePart::default_instance()); } -void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto() { +} // namespace + +void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { static bool already_here = false; if (already_here) return; already_here = true; GOOGLE_PROTOBUF_VERIFY_VERSION; - ::google::protobuf::DescriptorPool* pool = - ::google::protobuf::DescriptorPool::internal_generated_pool(); - pool->InternalBuildGeneratedFile( + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n google/protobuf/descriptor.proto\022\017goog" "le.protobuf\"G\n\021FileDescriptorSet\0222\n\004file" "\030\001 \003(\0132$.google.protobuf.FileDescriptorP" @@ -509,48 +510,86 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto() { "ptions\"\177\n\025MethodDescriptorProto\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\007options\030\004 \001(\0132\036.google.protobu" - "f.MethodOptions\"\253\002\n\013FileOptions\022\024\n\014java_" + "f.MethodOptions\"\247\002\n\013FileOptions\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" - "J\n\014optimize_for\030\t \001(\0162).google.protobuf." - "FileOptions.OptimizeMode:\tCODE_SIZE\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\"(\n\014OptimizeMode" - "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002*\t\010\350\007\020\200\200\200\200\002\"\210\001" - "\n\016MessageOptions\022&\n\027message_set_wire_for" - "mat\030\001 \001(\010:\005false\022C\n\024uninterpreted_option" - "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO" - "ption*\t\010\350\007\020\200\200\200\200\002\"\345\001\n\014FieldOptions\0222\n\005cty" - "pe\030\001 \001(\0162#.google.protobuf.FieldOptions." - "CType\022\016\n\006packed\030\002 \001(\010\022\034\n\024experimental_ma" - "p_key\030\t \001(\t\022C\n\024uninterpreted_option\030\347\007 \003" - "(\0132$.google.protobuf.UninterpretedOption" - "\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002*\t\010" - "\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpreted" - "_option\030\347\007 \003(\0132$.google.protobuf.Uninter" - "pretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValueOpti" - "ons\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" - "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200" - "\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpreted_o" + "F\n\014optimize_for\030\t \001(\0162).google.protobuf." + "FileOptions.OptimizeMode:\005SPEED\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*\t\010\350\007\020\200\200\200\200\002\"\210\001\n\016Me" + "ssageOptions\022&\n\027message_set_wire_format\030" + "\001 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 " + "\003(\0132$.google.protobuf.UninterpretedOptio" + "n*\t\010\350\007\020\200\200\200\200\002\"\200\002\n\014FieldOptions\0222\n\005ctype\030\001" + " \001(\0162#.google.protobuf.FieldOptions.CTyp" + "e\022\016\n\006packed\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f" + "alse\022\034\n\024experimental_map_key\030\t \001(\t\022C\n\024un" + "interpreted_option\030\347\007 \003(\0132$.google.proto" + "buf.UninterpretedOption\"#\n\005CType\022\010\n\004CORD" + "\020\001\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumO" + "ptions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption*\t\010\350\007" + "\020\200\200\200\200\002\"b\n\020EnumValueOptions\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\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" + "\200\200\200\002\"_\n\rMethodOptions\022C\n\024uninterpreted_o" "ption\030\347\007 \003(\0132$.google.protobuf.Uninterpr" - "etedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptions\022C" - "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" - "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\205" - "\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.g" - "oogle.protobuf.UninterpretedOption.NameP" - "art\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positiv" - "e_int_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_va" - "lue\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_part\030\001 \002(\t" - "\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.google.pro" - "tobufB\020DescriptorProtosH\001", 3465, - &protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors); -} - -// Force BuildDescriptors() to be called at static initialization time. + "etedOption*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedO" + "ption\022;\n\004name\030\002 \003(\0132-.google.protobuf.Un" + "interpretedOption.NamePart\022\030\n\020identifier" + "_value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004" + "\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_v" + "alue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010Name" + "Part\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension\030" + "\002 \002(\010B)\n\023com.google.protobufB\020Descriptor" + "ProtosH\001", 3488); + ::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(); + FieldDescriptorProto::default_instance_ = new FieldDescriptorProto(); + EnumDescriptorProto::default_instance_ = new EnumDescriptorProto(); + EnumValueDescriptorProto::default_instance_ = new EnumValueDescriptorProto(); + ServiceDescriptorProto::default_instance_ = new ServiceDescriptorProto(); + MethodDescriptorProto::default_instance_ = new MethodDescriptorProto(); + FileOptions::default_instance_ = new FileOptions(); + MessageOptions::default_instance_ = new MessageOptions(); + FieldOptions::default_instance_ = new FieldOptions(); + EnumOptions::default_instance_ = new EnumOptions(); + EnumValueOptions::default_instance_ = new EnumValueOptions(); + ServiceOptions::default_instance_ = new ServiceOptions(); + MethodOptions::default_instance_ = new MethodOptions(); + UninterpretedOption::default_instance_ = new UninterpretedOption(); + UninterpretedOption_NamePart::default_instance_ = new UninterpretedOption_NamePart(); + FileDescriptorSet::default_instance_->InitAsDefaultInstance(); + FileDescriptorProto::default_instance_->InitAsDefaultInstance(); + DescriptorProto::default_instance_->InitAsDefaultInstance(); + DescriptorProto_ExtensionRange::default_instance_->InitAsDefaultInstance(); + FieldDescriptorProto::default_instance_->InitAsDefaultInstance(); + EnumDescriptorProto::default_instance_->InitAsDefaultInstance(); + EnumValueDescriptorProto::default_instance_->InitAsDefaultInstance(); + ServiceDescriptorProto::default_instance_->InitAsDefaultInstance(); + MethodDescriptorProto::default_instance_->InitAsDefaultInstance(); + FileOptions::default_instance_->InitAsDefaultInstance(); + MessageOptions::default_instance_->InitAsDefaultInstance(); + FieldOptions::default_instance_->InitAsDefaultInstance(); + EnumOptions::default_instance_->InitAsDefaultInstance(); + EnumValueOptions::default_instance_->InitAsDefaultInstance(); + ServiceOptions::default_instance_->InitAsDefaultInstance(); + MethodOptions::default_instance_->InitAsDefaultInstance(); + UninterpretedOption::default_instance_->InitAsDefaultInstance(); + UninterpretedOption_NamePart::default_instance_->InitAsDefaultInstance(); +} + +// Force AddDescriptors() to be called at static initialization time. struct StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto { StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto() { - protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); } } static_descriptor_initializer_google_2fprotobuf_2fdescriptor_2eproto_; @@ -562,37 +601,39 @@ const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER FileDescriptorSet::FileDescriptorSet() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - file_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void FileDescriptorSet::InitAsDefaultInstance() {} FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - file_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void FileDescriptorSet::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + FileDescriptorSet::~FileDescriptorSet() { + SharedDtor(); +} + +void FileDescriptorSet::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() { - if (FileDescriptorSet_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileDescriptorSet_descriptor_; } const FileDescriptorSet& FileDescriptorSet::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } FileDescriptorSet* FileDescriptorSet::default_instance_ = NULL; @@ -643,20 +684,37 @@ bool FileDescriptorSet::MergePartialFromCodedStream( #undef DO_ } -bool FileDescriptorSet::SerializeWithCachedSizes( +void FileDescriptorSet::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + FileDescriptorSet::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.FileDescriptorProto file = 1; for (int i = 0; i < this->file_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(1, this->file(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(1, this->file(i), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* FileDescriptorSet::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.FileDescriptorProto file = 1; + for (int i = 0; i < this->file_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(1, this->file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int FileDescriptorSet::ByteSize() const { @@ -731,7 +789,7 @@ const ::google::protobuf::Descriptor* FileDescriptorSet::GetDescriptor() const { } const ::google::protobuf::Reflection* FileDescriptorSet::GetReflection() const { - if (FileDescriptorSet_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileDescriptorSet_reflection_; } @@ -751,40 +809,32 @@ const int FileDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FileDescriptorProto::FileDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - package_(const_cast< ::std::string*>(&_default_package_)), - dependency_(), - message_type_(), - enum_type_(), - service_(), - extension_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void FileDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FileOptions*>(&::google::protobuf::FileOptions::default_instance()); } FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - package_(const_cast< ::std::string*>(&_default_package_)), - dependency_(), - message_type_(), - enum_type_(), - service_(), - extension_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void FileDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + package_ = const_cast< ::std::string*>(&_default_package_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + FileDescriptorProto::~FileDescriptorProto() { + SharedDtor(); +} + +void FileDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -797,13 +847,12 @@ FileDescriptorProto::~FileDescriptorProto() { } const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() { - if (FileDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileDescriptorProto_descriptor_; } const FileDescriptorProto& FileDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } FileDescriptorProto* FileDescriptorProto::default_instance_ = NULL; @@ -965,55 +1014,107 @@ bool FileDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool FileDescriptorProto::SerializeWithCachedSizes( +void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + FileDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // optional string package = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->package(), output)); + ::google::protobuf::internal::WireFormat::WriteString(2, this->package(), output); } // repeated string dependency = 3; for (int i = 0; i < this->dependency_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->dependency(i), output)); + ::google::protobuf::internal::WireFormat::WriteString(3, this->dependency(i), output); } // repeated .google.protobuf.DescriptorProto message_type = 4; for (int i = 0; i < this->message_type_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->message_type(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->message_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; for (int i = 0; i < this->enum_type_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->enum_type(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->enum_type(i), output); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; for (int i = 0; i < this->service_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->service(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->service(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; for (int i = 0; i < this->extension_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->extension(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->extension(i), output); } // optional .google.protobuf.FileOptions options = 8; if (_has_bit(7)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* FileDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // optional string package = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(2, this->package(), target); + } + + // repeated string dependency = 3; + for (int i = 0; i < this->dependency_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(3, this->dependency(i), target); + } + + // repeated .google.protobuf.DescriptorProto message_type = 4; + for (int i = 0; i < this->message_type_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(4, this->message_type(i), target); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; + for (int i = 0; i < this->enum_type_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(5, this->enum_type(i), target); + } + + // repeated .google.protobuf.ServiceDescriptorProto service = 6; + for (int i = 0; i < this->service_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(6, this->service(i), target); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 7; + for (int i = 0; i < this->extension_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(7, this->extension(i), target); + } + + // optional .google.protobuf.FileOptions options = 8; + if (_has_bit(7)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(8, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int FileDescriptorProto::ByteSize() const { @@ -1174,7 +1275,7 @@ const ::google::protobuf::Descriptor* FileDescriptorProto::GetDescriptor() const } const ::google::protobuf::Reflection* FileDescriptorProto::GetReflection() const { - if (FileDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileDescriptorProto_reflection_; } @@ -1186,39 +1287,41 @@ const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - start_(0), - end_(0) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void DescriptorProto_ExtensionRange::InitAsDefaultInstance() {} DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - start_(0), - end_(0) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void DescriptorProto_ExtensionRange::SharedCtor() { + _cached_size_ = 0; + start_ = 0; + end_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + DescriptorProto_ExtensionRange::~DescriptorProto_ExtensionRange() { + SharedDtor(); +} + +void DescriptorProto_ExtensionRange::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() { - if (DescriptorProto_ExtensionRange_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return DescriptorProto_ExtensionRange_descriptor_; } const DescriptorProto_ExtensionRange& DescriptorProto_ExtensionRange::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::default_instance_ = NULL; @@ -1285,25 +1388,47 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( #undef DO_ } -bool DescriptorProto_ExtensionRange::SerializeWithCachedSizes( +void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional int32 start = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteInt32(1, this->start(), output)); + ::google::protobuf::internal::WireFormat::WriteInt32(1, this->start(), output); } // optional int32 end = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteInt32(2, this->end(), output)); + ::google::protobuf::internal::WireFormat::WriteInt32(2, this->end(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional int32 start = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteInt32ToArray(1, this->start(), target); + } + + // optional int32 end = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteInt32ToArray(2, this->end(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int DescriptorProto_ExtensionRange::ByteSize() const { @@ -1391,7 +1516,7 @@ const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::GetDescrip } const ::google::protobuf::Reflection* DescriptorProto_ExtensionRange::GetReflection() const { - if (DescriptorProto_ExtensionRange_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return DescriptorProto_ExtensionRange_reflection_; } @@ -1409,38 +1534,31 @@ const int DescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER DescriptorProto::DescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - field_(), - extension_(), - nested_type_(), - enum_type_(), - extension_range_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void DescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MessageOptions*>(&::google::protobuf::MessageOptions::default_instance()); } DescriptorProto::DescriptorProto(const DescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - field_(), - extension_(), - nested_type_(), - enum_type_(), - extension_range_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void DescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + DescriptorProto::~DescriptorProto() { + SharedDtor(); +} + +void DescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -1450,13 +1568,12 @@ DescriptorProto::~DescriptorProto() { } const ::google::protobuf::Descriptor* DescriptorProto::descriptor() { - if (DescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return DescriptorProto_descriptor_; } const DescriptorProto& DescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } DescriptorProto* DescriptorProto::default_instance_ = NULL; @@ -1601,50 +1718,97 @@ bool DescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool DescriptorProto::SerializeWithCachedSizes( +void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + DescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // repeated .google.protobuf.FieldDescriptorProto field = 2; for (int i = 0; i < this->field_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->field(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->field(i), output); } // repeated .google.protobuf.DescriptorProto nested_type = 3; for (int i = 0; i < this->nested_type_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->nested_type(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->nested_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; for (int i = 0; i < this->enum_type_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->enum_type(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->enum_type(i), output); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; for (int i = 0; i < this->extension_range_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->extension_range(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->extension_range(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; for (int i = 0; i < this->extension_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->extension(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->extension(i), output); } // optional .google.protobuf.MessageOptions options = 7; if (_has_bit(6)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* DescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // repeated .google.protobuf.FieldDescriptorProto field = 2; + for (int i = 0; i < this->field_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(2, this->field(i), target); + } + + // repeated .google.protobuf.DescriptorProto nested_type = 3; + for (int i = 0; i < this->nested_type_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(3, this->nested_type(i), target); + } + + // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; + for (int i = 0; i < this->enum_type_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(4, this->enum_type(i), target); + } + + // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; + for (int i = 0; i < this->extension_range_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(5, this->extension_range(i), target); + } + + // repeated .google.protobuf.FieldDescriptorProto extension = 6; + for (int i = 0; i < this->extension_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(6, this->extension(i), target); + } + + // optional .google.protobuf.MessageOptions options = 7; + if (_has_bit(6)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(7, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int DescriptorProto::ByteSize() const { @@ -1796,14 +1960,14 @@ const ::google::protobuf::Descriptor* DescriptorProto::GetDescriptor() const { } const ::google::protobuf::Reflection* DescriptorProto::GetReflection() const { - if (DescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return DescriptorProto_reflection_; } // =================================================================== const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor() { - if (FieldDescriptorProto_Type_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_Type_descriptor_; } bool FieldDescriptorProto_Type_IsValid(int value) { @@ -1855,7 +2019,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; #endif // _MSC_VER const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { - if (FieldDescriptorProto_Label_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_Label_descriptor_; } bool FieldDescriptorProto_Label_IsValid(int value) { @@ -1892,40 +2056,37 @@ const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FieldDescriptorProto::FieldDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - number_(0), - label_(1), - type_(1), - type_name_(const_cast< ::std::string*>(&_default_type_name_)), - extendee_(const_cast< ::std::string*>(&_default_extendee_)), - default_value_(const_cast< ::std::string*>(&_default_default_value_)), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void FieldDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FieldOptions*>(&::google::protobuf::FieldOptions::default_instance()); } FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - number_(0), - label_(1), - type_(1), - type_name_(const_cast< ::std::string*>(&_default_type_name_)), - extendee_(const_cast< ::std::string*>(&_default_extendee_)), - default_value_(const_cast< ::std::string*>(&_default_default_value_)), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void FieldDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + number_ = 0; + label_ = 1; + type_ = 1; + type_name_ = const_cast< ::std::string*>(&_default_type_name_); + extendee_ = const_cast< ::std::string*>(&_default_extendee_); + default_value_ = const_cast< ::std::string*>(&_default_default_value_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + FieldDescriptorProto::~FieldDescriptorProto() { + SharedDtor(); +} + +void FieldDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -1944,13 +2105,12 @@ FieldDescriptorProto::~FieldDescriptorProto() { } const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() { - if (FieldDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_descriptor_; } const FieldDescriptorProto& FieldDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } FieldDescriptorProto* FieldDescriptorProto::default_instance_ = NULL; @@ -2047,7 +2207,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); } else { - mutable_unknown_fields()->AddField(4)->add_varint(value); + mutable_unknown_fields()->AddVarint(4, value); } if (input->ExpectTag(40)) goto parse_type; break; @@ -2065,7 +2225,7 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); } else { - mutable_unknown_fields()->AddField(5)->add_varint(value); + mutable_unknown_fields()->AddVarint(5, value); } if (input->ExpectTag(50)) goto parse_type_name; break; @@ -2124,55 +2284,107 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool FieldDescriptorProto::SerializeWithCachedSizes( +void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + FieldDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // optional string extendee = 2; if (_has_bit(5)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->extendee(), output)); + ::google::protobuf::internal::WireFormat::WriteString(2, this->extendee(), output); } // optional int32 number = 3; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteInt32(3, this->number(), output)); + ::google::protobuf::internal::WireFormat::WriteInt32(3, this->number(), output); } // optional .google.protobuf.FieldDescriptorProto.Label label = 4; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteEnum(4, this->label(), output)); + ::google::protobuf::internal::WireFormat::WriteEnum(4, this->label(), output); } // optional .google.protobuf.FieldDescriptorProto.Type type = 5; if (_has_bit(3)) { - DO_(::google::protobuf::internal::WireFormat::WriteEnum(5, this->type(), output)); + ::google::protobuf::internal::WireFormat::WriteEnum(5, this->type(), output); } // optional string type_name = 6; if (_has_bit(4)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(6, this->type_name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(6, this->type_name(), output); } // optional string default_value = 7; if (_has_bit(6)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(7, this->default_value(), output)); + ::google::protobuf::internal::WireFormat::WriteString(7, this->default_value(), output); } // optional .google.protobuf.FieldOptions options = 8; if (_has_bit(7)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(8, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* FieldDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // optional string extendee = 2; + if (_has_bit(5)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(2, this->extendee(), target); + } + + // optional int32 number = 3; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteInt32ToArray(3, this->number(), target); + } + + // optional .google.protobuf.FieldDescriptorProto.Label label = 4; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(4, this->label(), target); + } + + // optional .google.protobuf.FieldDescriptorProto.Type type = 5; + if (_has_bit(3)) { + target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(5, this->type(), target); + } + + // optional string type_name = 6; + if (_has_bit(4)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(6, this->type_name(), target); + } + + // optional string default_value = 7; + if (_has_bit(6)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(7, this->default_value(), target); + } + + // optional .google.protobuf.FieldOptions options = 8; + if (_has_bit(7)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(8, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int FieldDescriptorProto::ByteSize() const { @@ -2323,7 +2535,7 @@ const ::google::protobuf::Descriptor* FieldDescriptorProto::GetDescriptor() cons } const ::google::protobuf::Reflection* FieldDescriptorProto::GetReflection() const { - if (FieldDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_reflection_; } @@ -2337,30 +2549,31 @@ const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumDescriptorProto::EnumDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - value_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void EnumDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumOptions*>(&::google::protobuf::EnumOptions::default_instance()); } EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - value_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void EnumDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + EnumDescriptorProto::~EnumDescriptorProto() { + SharedDtor(); +} + +void EnumDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -2370,13 +2583,12 @@ EnumDescriptorProto::~EnumDescriptorProto() { } const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() { - if (EnumDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumDescriptorProto_descriptor_; } const EnumDescriptorProto& EnumDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } EnumDescriptorProto* EnumDescriptorProto::default_instance_ = NULL; @@ -2461,30 +2673,57 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool EnumDescriptorProto::SerializeWithCachedSizes( +void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + EnumDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; for (int i = 0; i < this->value_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->value(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->value(i), output); } // optional .google.protobuf.EnumOptions options = 3; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* EnumDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // repeated .google.protobuf.EnumValueDescriptorProto value = 2; + for (int i = 0; i < this->value_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(2, this->value(i), target); + } + + // optional .google.protobuf.EnumOptions options = 3; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int EnumDescriptorProto::ByteSize() const { @@ -2587,7 +2826,7 @@ const ::google::protobuf::Descriptor* EnumDescriptorProto::GetDescriptor() const } const ::google::protobuf::Reflection* EnumDescriptorProto::GetReflection() const { - if (EnumDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumDescriptorProto_reflection_; } @@ -2601,30 +2840,32 @@ const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumValueDescriptorProto::EnumValueDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - number_(0), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void EnumValueDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumValueOptions*>(&::google::protobuf::EnumValueOptions::default_instance()); } EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - number_(0), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void EnumValueDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + number_ = 0; + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + EnumValueDescriptorProto::~EnumValueDescriptorProto() { + SharedDtor(); +} + +void EnumValueDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -2634,13 +2875,12 @@ EnumValueDescriptorProto::~EnumValueDescriptorProto() { } const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() { - if (EnumValueDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumValueDescriptorProto_descriptor_; } const EnumValueDescriptorProto& EnumValueDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } EnumValueDescriptorProto* EnumValueDescriptorProto::default_instance_ = NULL; @@ -2725,30 +2965,57 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool EnumValueDescriptorProto::SerializeWithCachedSizes( +void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + EnumValueDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // optional int32 number = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteInt32(2, this->number(), output)); + ::google::protobuf::internal::WireFormat::WriteInt32(2, this->number(), output); } // optional .google.protobuf.EnumValueOptions options = 3; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* EnumValueDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // optional int32 number = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteInt32ToArray(2, this->number(), target); + } + + // optional .google.protobuf.EnumValueOptions options = 3; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int EnumValueDescriptorProto::ByteSize() const { @@ -2849,7 +3116,7 @@ const ::google::protobuf::Descriptor* EnumValueDescriptorProto::GetDescriptor() } const ::google::protobuf::Reflection* EnumValueDescriptorProto::GetReflection() const { - if (EnumValueDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumValueDescriptorProto_reflection_; } @@ -2863,30 +3130,31 @@ const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER ServiceDescriptorProto::ServiceDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - method_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void ServiceDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::ServiceOptions*>(&::google::protobuf::ServiceOptions::default_instance()); } ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - method_(), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void ServiceDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + ServiceDescriptorProto::~ServiceDescriptorProto() { + SharedDtor(); +} + +void ServiceDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -2896,13 +3164,12 @@ ServiceDescriptorProto::~ServiceDescriptorProto() { } const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() { - if (ServiceDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return ServiceDescriptorProto_descriptor_; } const ServiceDescriptorProto& ServiceDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } ServiceDescriptorProto* ServiceDescriptorProto::default_instance_ = NULL; @@ -2987,30 +3254,57 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool ServiceDescriptorProto::SerializeWithCachedSizes( +void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + ServiceDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // repeated .google.protobuf.MethodDescriptorProto method = 2; for (int i = 0; i < this->method_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->method(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->method(i), output); } // optional .google.protobuf.ServiceOptions options = 3; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* ServiceDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // repeated .google.protobuf.MethodDescriptorProto method = 2; + for (int i = 0; i < this->method_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(2, this->method(i), target); + } + + // optional .google.protobuf.ServiceOptions options = 3; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(3, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int ServiceDescriptorProto::ByteSize() const { @@ -3113,7 +3407,7 @@ const ::google::protobuf::Descriptor* ServiceDescriptorProto::GetDescriptor() co } const ::google::protobuf::Reflection* ServiceDescriptorProto::GetReflection() const { - if (ServiceDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return ServiceDescriptorProto_reflection_; } @@ -3130,32 +3424,33 @@ const int MethodDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - input_type_(const_cast< ::std::string*>(&_default_input_type_)), - output_type_(const_cast< ::std::string*>(&_default_output_type_)), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void MethodDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MethodOptions*>(&::google::protobuf::MethodOptions::default_instance()); } MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(const_cast< ::std::string*>(&_default_name_)), - input_type_(const_cast< ::std::string*>(&_default_input_type_)), - output_type_(const_cast< ::std::string*>(&_default_output_type_)), - options_(NULL) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void MethodDescriptorProto::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + input_type_ = const_cast< ::std::string*>(&_default_input_type_); + output_type_ = const_cast< ::std::string*>(&_default_output_type_); + options_ = NULL; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + MethodDescriptorProto::~MethodDescriptorProto() { + SharedDtor(); +} + +void MethodDescriptorProto::SharedDtor() { if (name_ != &_default_name_) { delete name_; } @@ -3171,13 +3466,12 @@ MethodDescriptorProto::~MethodDescriptorProto() { } const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() { - if (MethodDescriptorProto_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MethodDescriptorProto_descriptor_; } const MethodDescriptorProto& MethodDescriptorProto::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } MethodDescriptorProto* MethodDescriptorProto::default_instance_ = NULL; @@ -3281,35 +3575,67 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( #undef DO_ } -bool MethodDescriptorProto::SerializeWithCachedSizes( +void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + MethodDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional string name = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name(), output); } // optional string input_type = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(2, this->input_type(), output)); + ::google::protobuf::internal::WireFormat::WriteString(2, this->input_type(), output); } // optional string output_type = 3; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->output_type(), output)); + ::google::protobuf::internal::WireFormat::WriteString(3, this->output_type(), output); } // optional .google.protobuf.MethodOptions options = 4; if (_has_bit(3)) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->options(), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->options(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* MethodDescriptorProto::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name(), target); + } + + // optional string input_type = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(2, this->input_type(), target); + } + + // optional string output_type = 3; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(3, this->output_type(), target); + } + + // optional .google.protobuf.MethodOptions options = 4; + if (_has_bit(3)) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(4, this->options(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int MethodDescriptorProto::ByteSize() const { @@ -3419,14 +3745,14 @@ const ::google::protobuf::Descriptor* MethodDescriptorProto::GetDescriptor() con } const ::google::protobuf::Reflection* MethodDescriptorProto::GetReflection() const { - if (MethodDescriptorProto_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MethodDescriptorProto_reflection_; } // =================================================================== const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor() { - if (FileOptions_OptimizeMode_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileOptions_OptimizeMode_descriptor_; } bool FileOptions_OptimizeMode_IsValid(int value) { @@ -3456,39 +3782,32 @@ const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FileOptions::FileOptions() - : ::google::protobuf::Message(), - _extensions_(&FileOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - java_package_(const_cast< ::std::string*>(&_default_java_package_)), - java_outer_classname_(const_cast< ::std::string*>(&_default_java_outer_classname_)), - java_multiple_files_(false), - optimize_for_(2), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void FileOptions::InitAsDefaultInstance() {} FileOptions::FileOptions(const FileOptions& from) - : ::google::protobuf::Message(), - _extensions_(&FileOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - java_package_(const_cast< ::std::string*>(&_default_java_package_)), - java_outer_classname_(const_cast< ::std::string*>(&_default_java_outer_classname_)), - java_multiple_files_(false), - optimize_for_(2), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void FileOptions::SharedCtor() { + _cached_size_ = 0; + java_package_ = const_cast< ::std::string*>(&_default_java_package_); + java_outer_classname_ = const_cast< ::std::string*>(&_default_java_outer_classname_); + java_multiple_files_ = false; + optimize_for_ = 1; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + FileOptions::~FileOptions() { + SharedDtor(); +} + +void FileOptions::SharedDtor() { if (java_package_ != &_default_java_package_) { delete java_package_; } @@ -3500,13 +3819,12 @@ FileOptions::~FileOptions() { } const ::google::protobuf::Descriptor* FileOptions::descriptor() { - if (FileOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileOptions_descriptor_; } const FileOptions& FileOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } FileOptions* FileOptions::default_instance_ = NULL; @@ -3529,7 +3847,7 @@ void FileOptions::Clear() { } } java_multiple_files_ = false; - optimize_for_ = 2; + optimize_for_ = 1; } uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -3565,7 +3883,7 @@ bool FileOptions::MergePartialFromCodedStream( break; } - // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE]; + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; case 9: { if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) != ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) { @@ -3577,7 +3895,7 @@ bool FileOptions::MergePartialFromCodedStream( if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); } else { - mutable_unknown_fields()->AddField(9)->add_varint(value); + mutable_unknown_fields()->AddVarint(9, value); } if (input->ExpectTag(80)) goto parse_java_multiple_files; break; @@ -3618,7 +3936,8 @@ bool FileOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -3627,48 +3946,89 @@ bool FileOptions::MergePartialFromCodedStream( } } } - return true; -#undef DO_ + return true; +#undef DO_ +} + +void FileOptions::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + FileOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + + // optional string java_package = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormat::WriteString(1, this->java_package(), output); + } + + // optional string java_outer_classname = 8; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormat::WriteString(8, this->java_outer_classname(), output); + } + + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; + if (_has_bit(3)) { + ::google::protobuf::internal::WireFormat::WriteEnum(9, this->optimize_for(), output); + } + + // optional bool java_multiple_files = 10 [default = false]; + if (_has_bit(2)) { + ::google::protobuf::internal::WireFormat::WriteBool(10, this->java_multiple_files(), output); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } } -bool FileOptions::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false +::google::protobuf::uint8* FileOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { // optional string java_package = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->java_package(), output)); + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->java_package(), target); } // optional string java_outer_classname = 8; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(8, this->java_outer_classname(), output)); + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(8, this->java_outer_classname(), target); } - // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE]; + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; if (_has_bit(3)) { - DO_(::google::protobuf::internal::WireFormat::WriteEnum(9, this->optimize_for(), output)); + target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(9, this->optimize_for(), target); } // optional bool java_multiple_files = 10 [default = false]; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteBool(10, this->java_multiple_files(), output)); + target = ::google::protobuf::internal::WireFormat::WriteBoolToArray(10, this->java_multiple_files(), target); } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); } - return true; -#undef DO_ + return target; } int FileOptions::ByteSize() const { @@ -3692,7 +4052,7 @@ int FileOptions::ByteSize() const { total_size += 1 + 1; } - // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE]; + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; if (has_optimize_for()) { total_size += 1 + ::google::protobuf::internal::WireFormat::EnumSize(this->optimize_for()); @@ -3707,7 +4067,7 @@ int FileOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -3791,7 +4151,7 @@ const ::google::protobuf::Descriptor* FileOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* FileOptions::GetReflection() const { - if (FileOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FileOptions_reflection_; } @@ -3803,45 +4163,40 @@ const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MessageOptions::MessageOptions() - : ::google::protobuf::Message(), - _extensions_(&MessageOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - message_set_wire_format_(false), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void MessageOptions::InitAsDefaultInstance() {} MessageOptions::MessageOptions(const MessageOptions& from) - : ::google::protobuf::Message(), - _extensions_(&MessageOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - message_set_wire_format_(false), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void MessageOptions::SharedCtor() { + _cached_size_ = 0; + message_set_wire_format_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + MessageOptions::~MessageOptions() { + SharedDtor(); +} + +void MessageOptions::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* MessageOptions::descriptor() { - if (MessageOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MessageOptions_descriptor_; } const MessageOptions& MessageOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } MessageOptions* MessageOptions::default_instance_ = NULL; @@ -3900,7 +4255,8 @@ bool MessageOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -3913,29 +4269,55 @@ bool MessageOptions::MergePartialFromCodedStream( #undef DO_ } -bool MessageOptions::SerializeWithCachedSizes( +void MessageOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + MessageOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional bool message_set_wire_format = 1 [default = false]; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteBool(1, this->message_set_wire_format(), output)); + ::google::protobuf::internal::WireFormat::WriteBool(1, this->message_set_wire_format(), output); } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* MessageOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional bool message_set_wire_format = 1 [default = false]; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteBoolToArray(1, this->message_set_wire_format(), target); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int MessageOptions::ByteSize() const { @@ -3956,7 +4338,7 @@ int MessageOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -4028,14 +4410,14 @@ const ::google::protobuf::Descriptor* MessageOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* MessageOptions::GetReflection() const { - if (MessageOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MessageOptions_reflection_; } // =================================================================== const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() { - if (FieldOptions_CType_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldOptions_CType_descriptor_; } bool FieldOptions_CType_IsValid(int value) { @@ -4058,42 +4440,38 @@ const ::std::string FieldOptions::_default_experimental_map_key_; #ifndef _MSC_VER const int FieldOptions::kCtypeFieldNumber; const int FieldOptions::kPackedFieldNumber; +const int FieldOptions::kDeprecatedFieldNumber; const int FieldOptions::kExperimentalMapKeyFieldNumber; const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FieldOptions::FieldOptions() - : ::google::protobuf::Message(), - _extensions_(&FieldOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - ctype_(1), - packed_(false), - experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void FieldOptions::InitAsDefaultInstance() {} FieldOptions::FieldOptions(const FieldOptions& from) - : ::google::protobuf::Message(), - _extensions_(&FieldOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - ctype_(1), - packed_(false), - experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void FieldOptions::SharedCtor() { + _cached_size_ = 0; + ctype_ = 1; + packed_ = false; + deprecated_ = false; + experimental_map_key_ = const_cast< ::std::string*>(&_default_experimental_map_key_); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + FieldOptions::~FieldOptions() { + SharedDtor(); +} + +void FieldOptions::SharedDtor() { if (experimental_map_key_ != &_default_experimental_map_key_) { delete experimental_map_key_; } @@ -4102,13 +4480,12 @@ FieldOptions::~FieldOptions() { } const ::google::protobuf::Descriptor* FieldOptions::descriptor() { - if (FieldOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldOptions_descriptor_; } const FieldOptions& FieldOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } FieldOptions* FieldOptions::default_instance_ = NULL; @@ -4122,7 +4499,8 @@ void FieldOptions::Clear() { if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { ctype_ = 1; packed_ = false; - if (_has_bit(2)) { + deprecated_ = false; + if (_has_bit(3)) { if (experimental_map_key_ != &_default_experimental_map_key_) { experimental_map_key_->clear(); } @@ -4150,7 +4528,7 @@ bool FieldOptions::MergePartialFromCodedStream( if (::google::protobuf::FieldOptions_CType_IsValid(value)) { set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); } else { - mutable_unknown_fields()->AddField(1)->add_varint(value); + mutable_unknown_fields()->AddVarint(1, value); } if (input->ExpectTag(16)) goto parse_packed; break; @@ -4166,6 +4544,20 @@ bool FieldOptions::MergePartialFromCodedStream( DO_(::google::protobuf::internal::WireFormat::ReadBool( input, &packed_)); _set_bit(1); + if (input->ExpectTag(24)) goto parse_deprecated; + break; + } + + // optional bool deprecated = 3 [default = false]; + case 3: { + if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) != + ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) { + goto handle_uninterpreted; + } + parse_deprecated: + DO_(::google::protobuf::internal::WireFormat::ReadBool( + input, &deprecated_)); + _set_bit(2); if (input->ExpectTag(74)) goto parse_experimental_map_key; break; } @@ -4203,7 +4595,8 @@ bool FieldOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -4216,39 +4609,85 @@ bool FieldOptions::MergePartialFromCodedStream( #undef DO_ } -bool FieldOptions::SerializeWithCachedSizes( +void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + FieldOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // optional .google.protobuf.FieldOptions.CType ctype = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteEnum(1, this->ctype(), output)); + ::google::protobuf::internal::WireFormat::WriteEnum(1, this->ctype(), output); } // optional bool packed = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteBool(2, this->packed(), output)); + ::google::protobuf::internal::WireFormat::WriteBool(2, this->packed(), output); + } + + // optional bool deprecated = 3 [default = false]; + if (_has_bit(2)) { + ::google::protobuf::internal::WireFormat::WriteBool(3, this->deprecated(), output); } // optional string experimental_map_key = 9; + if (_has_bit(3)) { + ::google::protobuf::internal::WireFormat::WriteString(9, this->experimental_map_key(), output); + } + + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); + } + + // Extension range [1000, 536870912) + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional .google.protobuf.FieldOptions.CType ctype = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteEnumToArray(1, this->ctype(), target); + } + + // optional bool packed = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteBoolToArray(2, this->packed(), target); + } + + // optional bool deprecated = 3 [default = false]; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(9, this->experimental_map_key(), output)); + target = ::google::protobuf::internal::WireFormat::WriteBoolToArray(3, this->deprecated(), target); + } + + // optional string experimental_map_key = 9; + if (_has_bit(3)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(9, this->experimental_map_key(), target); } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); } - return true; -#undef DO_ + return target; } int FieldOptions::ByteSize() const { @@ -4266,6 +4705,11 @@ int FieldOptions::ByteSize() const { total_size += 1 + 1; } + // optional bool deprecated = 3 [default = false]; + if (has_deprecated()) { + total_size += 1 + 1; + } + // optional string experimental_map_key = 9; if (has_experimental_map_key()) { total_size += 1 + @@ -4281,7 +4725,7 @@ int FieldOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -4315,6 +4759,9 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { set_packed(from.packed()); } if (from._has_bit(2)) { + set_deprecated(from.deprecated()); + } + if (from._has_bit(3)) { set_experimental_map_key(from.experimental_map_key()); } } @@ -4338,6 +4785,7 @@ void FieldOptions::Swap(FieldOptions* other) { if (other != this) { std::swap(ctype_, other->ctype_); std::swap(packed_, other->packed_); + std::swap(deprecated_, other->deprecated_); std::swap(experimental_map_key_, other->experimental_map_key_); uninterpreted_option_.Swap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); @@ -4361,7 +4809,7 @@ const ::google::protobuf::Descriptor* FieldOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* FieldOptions::GetReflection() const { - if (FieldOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return FieldOptions_reflection_; } @@ -4372,43 +4820,39 @@ const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumOptions::EnumOptions() - : ::google::protobuf::Message(), - _extensions_(&EnumOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void EnumOptions::InitAsDefaultInstance() {} EnumOptions::EnumOptions(const EnumOptions& from) - : ::google::protobuf::Message(), - _extensions_(&EnumOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void EnumOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + EnumOptions::~EnumOptions() { + SharedDtor(); +} + +void EnumOptions::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* EnumOptions::descriptor() { - if (EnumOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumOptions_descriptor_; } const EnumOptions& EnumOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } EnumOptions* EnumOptions::default_instance_ = NULL; @@ -4451,7 +4895,8 @@ bool EnumOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -4464,24 +4909,45 @@ bool EnumOptions::MergePartialFromCodedStream( #undef DO_ } -bool EnumOptions::SerializeWithCachedSizes( +void EnumOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + EnumOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int EnumOptions::ByteSize() const { @@ -4495,7 +4961,7 @@ int EnumOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -4561,7 +5027,7 @@ const ::google::protobuf::Descriptor* EnumOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* EnumOptions::GetReflection() const { - if (EnumOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumOptions_reflection_; } @@ -4572,43 +5038,39 @@ const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumValueOptions::EnumValueOptions() - : ::google::protobuf::Message(), - _extensions_(&EnumValueOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void EnumValueOptions::InitAsDefaultInstance() {} EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) - : ::google::protobuf::Message(), - _extensions_(&EnumValueOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void EnumValueOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + EnumValueOptions::~EnumValueOptions() { + SharedDtor(); +} + +void EnumValueOptions::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() { - if (EnumValueOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumValueOptions_descriptor_; } const EnumValueOptions& EnumValueOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } EnumValueOptions* EnumValueOptions::default_instance_ = NULL; @@ -4651,7 +5113,8 @@ bool EnumValueOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -4664,24 +5127,45 @@ bool EnumValueOptions::MergePartialFromCodedStream( #undef DO_ } -bool EnumValueOptions::SerializeWithCachedSizes( +void EnumValueOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + EnumValueOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* EnumValueOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int EnumValueOptions::ByteSize() const { @@ -4695,7 +5179,7 @@ int EnumValueOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -4761,7 +5245,7 @@ const ::google::protobuf::Descriptor* EnumValueOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* EnumValueOptions::GetReflection() const { - if (EnumValueOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return EnumValueOptions_reflection_; } @@ -4772,43 +5256,39 @@ const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER ServiceOptions::ServiceOptions() - : ::google::protobuf::Message(), - _extensions_(&ServiceOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void ServiceOptions::InitAsDefaultInstance() {} ServiceOptions::ServiceOptions(const ServiceOptions& from) - : ::google::protobuf::Message(), - _extensions_(&ServiceOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void ServiceOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + ServiceOptions::~ServiceOptions() { + SharedDtor(); +} + +void ServiceOptions::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* ServiceOptions::descriptor() { - if (ServiceOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return ServiceOptions_descriptor_; } const ServiceOptions& ServiceOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } ServiceOptions* ServiceOptions::default_instance_ = NULL; @@ -4851,7 +5331,8 @@ bool ServiceOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -4864,24 +5345,45 @@ bool ServiceOptions::MergePartialFromCodedStream( #undef DO_ } -bool ServiceOptions::SerializeWithCachedSizes( +void ServiceOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + ServiceOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* ServiceOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int ServiceOptions::ByteSize() const { @@ -4895,7 +5397,7 @@ int ServiceOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -4961,7 +5463,7 @@ const ::google::protobuf::Descriptor* ServiceOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* ServiceOptions::GetReflection() const { - if (ServiceOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return ServiceOptions_reflection_; } @@ -4972,43 +5474,39 @@ const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MethodOptions::MethodOptions() - : ::google::protobuf::Message(), - _extensions_(&MethodOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void MethodOptions::InitAsDefaultInstance() {} MethodOptions::MethodOptions(const MethodOptions& from) - : ::google::protobuf::Message(), - _extensions_(&MethodOptions_descriptor_, - ::google::protobuf::DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory()), - _unknown_fields_(), - _cached_size_(0), - uninterpreted_option_() { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void MethodOptions::SharedCtor() { + _cached_size_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + MethodOptions::~MethodOptions() { + SharedDtor(); +} + +void MethodOptions::SharedDtor() { if (this != default_instance_) { } } const ::google::protobuf::Descriptor* MethodOptions::descriptor() { - if (MethodOptions_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MethodOptions_descriptor_; } const MethodOptions& MethodOptions::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } MethodOptions* MethodOptions::default_instance_ = NULL; @@ -5051,7 +5549,8 @@ bool MethodOptions::MergePartialFromCodedStream( return true; } if ((8000u <= tag)) { - DO_(_extensions_.ParseField(tag, input, this)); + DO_(_extensions_.ParseField(tag, input, default_instance_, + mutable_unknown_fields())); continue; } DO_(::google::protobuf::internal::WireFormat::SkipField( @@ -5064,24 +5563,45 @@ bool MethodOptions::MergePartialFromCodedStream( #undef DO_ } -bool MethodOptions::SerializeWithCachedSizes( +void MethodOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + MethodOptions::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output); } // Extension range [1000, 536870912) - DO_(_extensions_.SerializeWithCachedSizes( - 1000, 536870912, *this, output)); + _extensions_.SerializeWithCachedSizes( + 1000, 536870912, output); if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* MethodOptions::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; + for (int i = 0; i < this->uninterpreted_option_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(999, this->uninterpreted_option(i), target); + } + + // Extension range [1000, 536870912) + target = _extensions_.SerializeWithCachedSizesToArray( + 1000, 536870912, target); + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int MethodOptions::ByteSize() const { @@ -5095,7 +5615,7 @@ int MethodOptions::ByteSize() const { this->uninterpreted_option(i)); } - total_size += _extensions_.ByteSize(*this); + total_size += _extensions_.ByteSize(); if (!unknown_fields().empty()) { total_size += @@ -5161,7 +5681,7 @@ const ::google::protobuf::Descriptor* MethodOptions::GetDescriptor() const { } const ::google::protobuf::Reflection* MethodOptions::GetReflection() const { - if (MethodOptions_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return MethodOptions_reflection_; } @@ -5174,27 +5694,30 @@ const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER UninterpretedOption_NamePart::UninterpretedOption_NamePart() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_part_(const_cast< ::std::string*>(&_default_name_part_)), - is_extension_(false) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void UninterpretedOption_NamePart::InitAsDefaultInstance() {} UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_part_(const_cast< ::std::string*>(&_default_name_part_)), - is_extension_(false) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void UninterpretedOption_NamePart::SharedCtor() { + _cached_size_ = 0; + name_part_ = const_cast< ::std::string*>(&_default_name_part_); + is_extension_ = false; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + UninterpretedOption_NamePart::~UninterpretedOption_NamePart() { + SharedDtor(); +} + +void UninterpretedOption_NamePart::SharedDtor() { if (name_part_ != &_default_name_part_) { delete name_part_; } @@ -5203,13 +5726,12 @@ UninterpretedOption_NamePart::~UninterpretedOption_NamePart() { } const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor() { - if (UninterpretedOption_NamePart_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return UninterpretedOption_NamePart_descriptor_; } const UninterpretedOption_NamePart& UninterpretedOption_NamePart::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } UninterpretedOption_NamePart* UninterpretedOption_NamePart::default_instance_ = NULL; @@ -5278,25 +5800,47 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( #undef DO_ } -bool UninterpretedOption_NamePart::SerializeWithCachedSizes( +void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // required string name_part = 1; if (_has_bit(0)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(1, this->name_part(), output)); + ::google::protobuf::internal::WireFormat::WriteString(1, this->name_part(), output); } // required bool is_extension = 2; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteBool(2, this->is_extension(), output)); + ::google::protobuf::internal::WireFormat::WriteBool(2, this->is_extension(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* UninterpretedOption_NamePart::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // required string name_part = 1; + if (_has_bit(0)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(1, this->name_part(), target); + } + + // required bool is_extension = 2; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteBoolToArray(2, this->is_extension(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int UninterpretedOption_NamePart::ByteSize() const { @@ -5382,7 +5926,7 @@ const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::GetDescripto } const ::google::protobuf::Reflection* UninterpretedOption_NamePart::GetReflection() const { - if (UninterpretedOption_NamePart_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return UninterpretedOption_NamePart_reflection_; } @@ -5400,35 +5944,33 @@ const int UninterpretedOption::kStringValueFieldNumber; #endif // !_MSC_VER UninterpretedOption::UninterpretedOption() - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(), - identifier_value_(const_cast< ::std::string*>(&_default_identifier_value_)), - positive_int_value_(GOOGLE_ULONGLONG(0)), - negative_int_value_(GOOGLE_LONGLONG(0)), - double_value_(0), - string_value_(const_cast< ::std::string*>(&_default_string_value_)) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); } void UninterpretedOption::InitAsDefaultInstance() {} UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) - : ::google::protobuf::Message(), - _unknown_fields_(), - _cached_size_(0), - name_(), - identifier_value_(const_cast< ::std::string*>(&_default_identifier_value_)), - positive_int_value_(GOOGLE_ULONGLONG(0)), - negative_int_value_(GOOGLE_LONGLONG(0)), - double_value_(0), - string_value_(const_cast< ::std::string*>(&_default_string_value_)) { - ::memset(_has_bits_, 0, sizeof(_has_bits_)); + : ::google::protobuf::Message() { + SharedCtor(); MergeFrom(from); } +void UninterpretedOption::SharedCtor() { + _cached_size_ = 0; + identifier_value_ = const_cast< ::std::string*>(&_default_identifier_value_); + positive_int_value_ = GOOGLE_ULONGLONG(0); + negative_int_value_ = GOOGLE_LONGLONG(0); + double_value_ = 0; + string_value_ = const_cast< ::std::string*>(&_default_string_value_); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + UninterpretedOption::~UninterpretedOption() { + SharedDtor(); +} + +void UninterpretedOption::SharedDtor() { if (identifier_value_ != &_default_identifier_value_) { delete identifier_value_; } @@ -5440,13 +5982,12 @@ UninterpretedOption::~UninterpretedOption() { } const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() { - if (UninterpretedOption_descriptor_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return UninterpretedOption_descriptor_; } const UninterpretedOption& UninterpretedOption::default_instance() { - if (default_instance_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); - return *default_instance_; + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); return *default_instance_; } UninterpretedOption* UninterpretedOption::default_instance_ = NULL; @@ -5578,45 +6119,87 @@ bool UninterpretedOption::MergePartialFromCodedStream( #undef DO_ } -bool UninterpretedOption::SerializeWithCachedSizes( +void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { -#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); + if (raw_buffer != NULL) { + UninterpretedOption::SerializeWithCachedSizesToArray(raw_buffer); + return; + } + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; for (int i = 0; i < this->name_size(); i++) { - DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->name(i), output)); + ::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->name(i), output); } // optional string identifier_value = 3; if (_has_bit(1)) { - DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->identifier_value(), output)); + ::google::protobuf::internal::WireFormat::WriteString(3, this->identifier_value(), output); } // optional uint64 positive_int_value = 4; if (_has_bit(2)) { - DO_(::google::protobuf::internal::WireFormat::WriteUInt64(4, this->positive_int_value(), output)); + ::google::protobuf::internal::WireFormat::WriteUInt64(4, this->positive_int_value(), output); } // optional int64 negative_int_value = 5; if (_has_bit(3)) { - DO_(::google::protobuf::internal::WireFormat::WriteInt64(5, this->negative_int_value(), output)); + ::google::protobuf::internal::WireFormat::WriteInt64(5, this->negative_int_value(), output); } // optional double double_value = 6; if (_has_bit(4)) { - DO_(::google::protobuf::internal::WireFormat::WriteDouble(6, this->double_value(), output)); + ::google::protobuf::internal::WireFormat::WriteDouble(6, this->double_value(), output); } // optional bytes string_value = 7; if (_has_bit(5)) { - DO_(::google::protobuf::internal::WireFormat::WriteBytes(7, this->string_value(), output)); + ::google::protobuf::internal::WireFormat::WriteBytes(7, this->string_value(), output); } if (!unknown_fields().empty()) { - DO_(::google::protobuf::internal::WireFormat::SerializeUnknownFields( - unknown_fields(), output)); + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); } - return true; -#undef DO_ +} + +::google::protobuf::uint8* UninterpretedOption::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; + for (int i = 0; i < this->name_size(); i++) { + target = ::google::protobuf::internal::WireFormat::WriteMessageNoVirtualToArray(2, this->name(i), target); + } + + // optional string identifier_value = 3; + if (_has_bit(1)) { + target = ::google::protobuf::internal::WireFormat::WriteStringToArray(3, this->identifier_value(), target); + } + + // optional uint64 positive_int_value = 4; + if (_has_bit(2)) { + target = ::google::protobuf::internal::WireFormat::WriteUInt64ToArray(4, this->positive_int_value(), target); + } + + // optional int64 negative_int_value = 5; + if (_has_bit(3)) { + target = ::google::protobuf::internal::WireFormat::WriteInt64ToArray(5, this->negative_int_value(), target); + } + + // optional double double_value = 6; + if (_has_bit(4)) { + target = ::google::protobuf::internal::WireFormat::WriteDoubleToArray(6, this->double_value(), target); + } + + // optional bytes string_value = 7; + if (_has_bit(5)) { + target = ::google::protobuf::internal::WireFormat::WriteBytesToArray(7, this->string_value(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; } int UninterpretedOption::ByteSize() const { @@ -5746,7 +6329,7 @@ const ::google::protobuf::Descriptor* UninterpretedOption::GetDescriptor() const } const ::google::protobuf::Reflection* UninterpretedOption::GetReflection() const { - if (UninterpretedOption_reflection_ == NULL) protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); + protobuf_AssignDescriptorsOnce(); return UninterpretedOption_reflection_; } diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index c073db51..96ccdea0 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -26,9 +26,8 @@ namespace google { namespace protobuf { // Internal implementation detail -- do not call these. -void LIBPROTOBUF_EXPORT protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto(); -void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - ::google::protobuf::FileDescriptor* file); +void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); +void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); class FileDescriptorSet; class FileDescriptorProto; @@ -74,6 +73,15 @@ LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; +inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Type_descriptor(), value); +} +inline bool FieldDescriptorProto_Type_Parse( + const ::std::string& name, FieldDescriptorProto_Type* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Type_descriptor(), name, value); +} enum FieldDescriptorProto_Label { FieldDescriptorProto_Label_LABEL_OPTIONAL = 1, FieldDescriptorProto_Label_LABEL_REQUIRED = 2, @@ -84,6 +92,15 @@ LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; +inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { + return ::google::protobuf::internal::NameOfEnum( + FieldDescriptorProto_Label_descriptor(), value); +} +inline bool FieldDescriptorProto_Label_Parse( + const ::std::string& name, FieldDescriptorProto_Label* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldDescriptorProto_Label_descriptor(), name, value); +} enum FileOptions_OptimizeMode { FileOptions_OptimizeMode_SPEED = 1, FileOptions_OptimizeMode_CODE_SIZE = 2 @@ -93,6 +110,15 @@ LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_CODE_SIZE; +inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { + return ::google::protobuf::internal::NameOfEnum( + FileOptions_OptimizeMode_descriptor(), value); +} +inline bool FileOptions_OptimizeMode_Parse( + const ::std::string& name, FileOptions_OptimizeMode* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FileOptions_OptimizeMode_descriptor(), name, value); +} enum FieldOptions_CType { FieldOptions_CType_CORD = 1, FieldOptions_CType_STRING_PIECE = 2 @@ -102,6 +128,15 @@ LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD; const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { + return ::google::protobuf::internal::NameOfEnum( + FieldOptions_CType_descriptor(), value); +} +inline bool FieldOptions_CType_Parse( + const ::std::string& name, FieldOptions_CType* value) { + return ::google::protobuf::internal::ParseNamedEnum( + FieldOptions_CType_descriptor(), name, value); +} // =================================================================== class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message { @@ -137,14 +172,17 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message void MergeFrom(const FileDescriptorSet& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -170,8 +208,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > file_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -223,14 +261,17 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag void MergeFrom(const FileDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -248,6 +289,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // optional string package = 2; @@ -257,6 +299,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline const ::std::string& package() const; inline void set_package(const ::std::string& value); inline void set_package(const char* value); + inline void set_package(const char* value, size_t size); inline ::std::string* mutable_package(); // repeated string dependency = 3; @@ -269,9 +312,11 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline ::std::string* mutable_dependency(int index); inline void set_dependency(int index, const ::std::string& value); inline void set_dependency(int index, const char* value); + inline void set_dependency(int index, const char* value, size_t size); inline ::std::string* add_dependency(); inline void add_dependency(const ::std::string& value); inline void add_dependency(const char* value); + inline void add_dependency(const char* value, size_t size); // repeated .google.protobuf.DescriptorProto message_type = 4; inline int message_type_size() const; @@ -334,8 +379,8 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto > service_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto > extension_; ::google::protobuf::FileOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -387,14 +432,17 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto void MergeFrom(const DescriptorProto_ExtensionRange& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -425,8 +473,8 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto ::google::protobuf::int32 start_; ::google::protobuf::int32 end_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -478,14 +526,17 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { void MergeFrom(const DescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -505,6 +556,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // repeated .google.protobuf.FieldDescriptorProto field = 2; @@ -576,8 +628,8 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto > enum_type_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange > extension_range_; ::google::protobuf::MessageOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -629,14 +681,17 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa void MergeFrom(const FieldDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -671,6 +726,13 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa static inline bool Type_IsValid(int value) { return FieldDescriptorProto_Type_IsValid(value); } + static inline const ::std::string& Type_Name(Type value) { + return FieldDescriptorProto_Type_Name(value); + } + static inline bool Type_Parse(const ::std::string& name, + Type* value) { + return FieldDescriptorProto_Type_Parse(name, value); + } static const Type Type_MIN = FieldDescriptorProto_Type_Type_MIN; static const Type Type_MAX = @@ -687,6 +749,13 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa static inline bool Label_IsValid(int value) { return FieldDescriptorProto_Label_IsValid(value); } + static inline const ::std::string& Label_Name(Label value) { + return FieldDescriptorProto_Label_Name(value); + } + static inline bool Label_Parse(const ::std::string& name, + Label* value) { + return FieldDescriptorProto_Label_Parse(name, value); + } static const Label Label_MIN = FieldDescriptorProto_Label_Label_MIN; static const Label Label_MAX = @@ -701,6 +770,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // optional int32 number = 3; @@ -731,6 +801,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::std::string& type_name() const; inline void set_type_name(const ::std::string& value); inline void set_type_name(const char* value); + inline void set_type_name(const char* value, size_t size); inline ::std::string* mutable_type_name(); // optional string extendee = 2; @@ -740,6 +811,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::std::string& extendee() const; inline void set_extendee(const ::std::string& value); inline void set_extendee(const char* value); + inline void set_extendee(const char* value, size_t size); inline ::std::string* mutable_extendee(); // optional string default_value = 7; @@ -749,6 +821,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::std::string& default_value() const; inline void set_default_value(const ::std::string& value); inline void set_default_value(const char* value); + inline void set_default_value(const char* value, size_t size); inline ::std::string* mutable_default_value(); // optional .google.protobuf.FieldOptions options = 8; @@ -774,8 +847,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa ::std::string* default_value_; static const ::std::string _default_default_value_; ::google::protobuf::FieldOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -827,14 +900,17 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag void MergeFrom(const EnumDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -852,6 +928,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // repeated .google.protobuf.EnumValueDescriptorProto value = 2; @@ -879,8 +956,8 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag static const ::std::string _default_name_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto > value_; ::google::protobuf::EnumOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -932,14 +1009,17 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M void MergeFrom(const EnumValueDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -957,6 +1037,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // optional int32 number = 2; @@ -981,8 +1062,8 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M static const ::std::string _default_name_; ::google::protobuf::int32 number_; ::google::protobuf::EnumValueOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -1034,14 +1115,17 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes void MergeFrom(const ServiceDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1059,6 +1143,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // repeated .google.protobuf.MethodDescriptorProto method = 2; @@ -1086,8 +1171,8 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes static const ::std::string _default_name_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto > method_; ::google::protobuf::ServiceOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -1139,14 +1224,17 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess void MergeFrom(const MethodDescriptorProto& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1164,6 +1252,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); + inline void set_name(const char* value, size_t size); inline ::std::string* mutable_name(); // optional string input_type = 2; @@ -1173,6 +1262,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::std::string& input_type() const; inline void set_input_type(const ::std::string& value); inline void set_input_type(const char* value); + inline void set_input_type(const char* value, size_t size); inline ::std::string* mutable_input_type(); // optional string output_type = 3; @@ -1182,6 +1272,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::std::string& output_type() const; inline void set_output_type(const ::std::string& value); inline void set_output_type(const char* value); + inline void set_output_type(const char* value, size_t size); inline ::std::string* mutable_output_type(); // optional .google.protobuf.MethodOptions options = 4; @@ -1202,8 +1293,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess ::std::string* output_type_; static const ::std::string _default_output_type_; ::google::protobuf::MethodOptions* options_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -1255,14 +1346,17 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { void MergeFrom(const FileOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1281,6 +1375,13 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static inline bool OptimizeMode_IsValid(int value) { return FileOptions_OptimizeMode_IsValid(value); } + static inline const ::std::string& OptimizeMode_Name(OptimizeMode value) { + return FileOptions_OptimizeMode_Name(value); + } + static inline bool OptimizeMode_Parse(const ::std::string& name, + OptimizeMode* value) { + return FileOptions_OptimizeMode_Parse(name, value); + } static const OptimizeMode OptimizeMode_MIN = FileOptions_OptimizeMode_OptimizeMode_MIN; static const OptimizeMode OptimizeMode_MAX = @@ -1295,6 +1396,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline const ::std::string& java_package() const; inline void set_java_package(const ::std::string& value); inline void set_java_package(const char* value); + inline void set_java_package(const char* value, size_t size); inline ::std::string* mutable_java_package(); // optional string java_outer_classname = 8; @@ -1304,6 +1406,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline const ::std::string& java_outer_classname() const; inline void set_java_outer_classname(const ::std::string& value); inline void set_java_outer_classname(const char* value); + inline void set_java_outer_classname(const char* value, size_t size); inline ::std::string* mutable_java_outer_classname(); // optional bool java_multiple_files = 10 [default = false]; @@ -1313,7 +1416,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline bool java_multiple_files() const; inline void set_java_multiple_files(bool value); - // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE]; + // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; inline bool has_optimize_for() const; inline void clear_optimize_for(); static const int kOptimizeForFieldNumber = 9; @@ -1330,87 +1433,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FileOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1423,8 +1446,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { bool java_multiple_files_; int optimize_for_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -1476,14 +1499,17 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { void MergeFrom(const MessageOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1511,87 +1537,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MessageOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1599,8 +1545,8 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { bool message_set_wire_format_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -1652,14 +1598,17 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { void MergeFrom(const FieldOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1678,6 +1627,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { static inline bool CType_IsValid(int value) { return FieldOptions_CType_IsValid(value); } + static inline const ::std::string& CType_Name(CType value) { + return FieldOptions_CType_Name(value); + } + static inline bool CType_Parse(const ::std::string& name, + CType* value) { + return FieldOptions_CType_Parse(name, value); + } static const CType CType_MIN = FieldOptions_CType_CType_MIN; static const CType CType_MAX = @@ -1699,6 +1655,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline bool packed() const; inline void set_packed(bool value); + // optional bool deprecated = 3 [default = false]; + inline bool has_deprecated() const; + inline void clear_deprecated(); + static const int kDeprecatedFieldNumber = 3; + inline bool deprecated() const; + inline void set_deprecated(bool value); + // optional string experimental_map_key = 9; inline bool has_experimental_map_key() const; inline void clear_experimental_map_key(); @@ -1706,6 +1669,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline const ::std::string& experimental_map_key() const; inline void set_experimental_map_key(const ::std::string& value); inline void set_experimental_map_key(const char* value); + inline void set_experimental_map_key(const char* value, size_t size); inline ::std::string* mutable_experimental_map_key(); // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; @@ -1718,87 +1682,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - FieldOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1806,12 +1690,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { int ctype_; bool packed_; + bool deprecated_; ::std::string* experimental_map_key_; static const ::std::string _default_experimental_map_key_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); - ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32]; + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); + ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1862,14 +1747,17 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { void MergeFrom(const EnumOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -1890,95 +1778,15 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2030,14 +1838,17 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { void MergeFrom(const EnumValueOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -2058,95 +1869,15 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - EnumValueOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2198,14 +1929,17 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { void MergeFrom(const ServiceOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -2226,95 +1960,15 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - ServiceOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2366,14 +2020,17 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { void MergeFrom(const MethodOptions& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -2394,95 +2051,15 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - template - inline bool HasExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) const { - return _extensions_.Has(id.number()); - } - - template - inline void ClearExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) { - _extensions_.ClearExtension(id.number()); - } - - template - inline int ExtensionSize( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) const { - return _extensions_.ExtensionSize(id.number()); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) const { - return _proto_TypeTraits::Get(id.number(), _extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Mutable(id.number(), &_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::ConstType GetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id, - int index) const { - return _proto_TypeTraits::Get(id.number(), _extensions_, index); - } - - template - inline typename _proto_TypeTraits::MutableType MutableExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id, - int index) { - return _proto_TypeTraits::Mutable(id.number(),index,&_extensions_); - } - - template - inline void SetExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id, - int index, typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); - } - - template - inline typename _proto_TypeTraits::MutableType AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id) { - return _proto_TypeTraits::Add(id.number(), &_extensions_); - } - - template - inline void AddExtension( - const ::google::protobuf::internal::ExtensionIdentifier< - MethodOptions, _proto_TypeTraits>& id, - typename _proto_TypeTraits::ConstType value) { - _proto_TypeTraits::Add(id.number(), value, &_extensions_); - } + GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2534,14 +2111,17 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu void MergeFrom(const UninterpretedOption_NamePart& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -2559,6 +2139,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline const ::std::string& name_part() const; inline void set_name_part(const ::std::string& value); inline void set_name_part(const char* value); + inline void set_name_part(const char* value, size_t size); inline ::std::string* mutable_name_part(); // required bool is_extension = 2; @@ -2575,8 +2156,8 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu ::std::string* name_part_; static const ::std::string _default_name_part_; bool is_extension_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2628,14 +2209,17 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag void MergeFrom(const UninterpretedOption& from); void Clear(); bool IsInitialized() const; - int ByteSize() const; + int ByteSize() const; bool MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input); - bool SerializeWithCachedSizes( + 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 { _cached_size_ = size; } public: @@ -2665,6 +2249,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline const ::std::string& identifier_value() const; inline void set_identifier_value(const ::std::string& value); inline void set_identifier_value(const char* value); + inline void set_identifier_value(const char* value, size_t size); inline ::std::string* mutable_identifier_value(); // optional uint64 positive_int_value = 4; @@ -2710,8 +2295,8 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag double double_value_; ::std::string* string_value_; static const ::std::string _default_string_value_; - friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors( - const ::google::protobuf::FileDescriptor* file); + friend void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? @@ -2794,6 +2379,13 @@ inline void FileDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void FileDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* FileDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -2829,6 +2421,13 @@ inline void FileDescriptorProto::set_package(const char* value) { } package_->assign(value); } +inline void FileDescriptorProto::set_package(const char* value, size_t size) { + _set_bit(1); + if (package_ == &_default_package_) { + package_ = new ::std::string; + } + package_->assign(reinterpret_cast(value), size); +} inline ::std::string* FileDescriptorProto::mutable_package() { _set_bit(1); if (package_ == &_default_package_) { @@ -2864,6 +2463,10 @@ inline void FileDescriptorProto::set_dependency(int index, const ::std::string& inline void FileDescriptorProto::set_dependency(int index, const char* value) { dependency_.Mutable(index)->assign(value); } +inline void FileDescriptorProto::set_dependency(int index, const char* value, size_t size) { + dependency_.Mutable(index)->assign( + reinterpret_cast(value), size); +} inline ::std::string* FileDescriptorProto::add_dependency() { return dependency_.Add(); } @@ -2873,6 +2476,9 @@ inline void FileDescriptorProto::add_dependency(const ::std::string& value) { inline void FileDescriptorProto::add_dependency(const char* value) { dependency_.Add()->assign(value); } +inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { + dependency_.Add()->assign(reinterpret_cast(value), size); +} // repeated .google.protobuf.DescriptorProto message_type = 4; inline int FileDescriptorProto::message_type_size() const { @@ -3058,6 +2664,13 @@ inline void DescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void DescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* DescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3239,6 +2852,13 @@ inline void FieldDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void FieldDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* FieldDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3324,6 +2944,13 @@ inline void FieldDescriptorProto::set_type_name(const char* value) { } type_name_->assign(value); } +inline void FieldDescriptorProto::set_type_name(const char* value, size_t size) { + _set_bit(4); + if (type_name_ == &_default_type_name_) { + type_name_ = new ::std::string; + } + type_name_->assign(reinterpret_cast(value), size); +} inline ::std::string* FieldDescriptorProto::mutable_type_name() { _set_bit(4); if (type_name_ == &_default_type_name_) { @@ -3359,6 +2986,13 @@ inline void FieldDescriptorProto::set_extendee(const char* value) { } extendee_->assign(value); } +inline void FieldDescriptorProto::set_extendee(const char* value, size_t size) { + _set_bit(5); + if (extendee_ == &_default_extendee_) { + extendee_ = new ::std::string; + } + extendee_->assign(reinterpret_cast(value), size); +} inline ::std::string* FieldDescriptorProto::mutable_extendee() { _set_bit(5); if (extendee_ == &_default_extendee_) { @@ -3394,6 +3028,13 @@ inline void FieldDescriptorProto::set_default_value(const char* value) { } default_value_->assign(value); } +inline void FieldDescriptorProto::set_default_value(const char* value, size_t size) { + _set_bit(6); + if (default_value_ == &_default_default_value_) { + default_value_ = new ::std::string; + } + default_value_->assign(reinterpret_cast(value), size); +} inline ::std::string* FieldDescriptorProto::mutable_default_value() { _set_bit(6); if (default_value_ == &_default_default_value_) { @@ -3450,6 +3091,13 @@ inline void EnumDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void EnumDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* EnumDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3531,6 +3179,13 @@ inline void EnumValueDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void EnumValueDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* EnumValueDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3603,6 +3258,13 @@ inline void ServiceDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void ServiceDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* ServiceDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3684,6 +3346,13 @@ inline void MethodDescriptorProto::set_name(const char* value) { } name_->assign(value); } +inline void MethodDescriptorProto::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast(value), size); +} inline ::std::string* MethodDescriptorProto::mutable_name() { _set_bit(0); if (name_ == &_default_name_) { @@ -3719,6 +3388,13 @@ inline void MethodDescriptorProto::set_input_type(const char* value) { } input_type_->assign(value); } +inline void MethodDescriptorProto::set_input_type(const char* value, size_t size) { + _set_bit(1); + if (input_type_ == &_default_input_type_) { + input_type_ = new ::std::string; + } + input_type_->assign(reinterpret_cast(value), size); +} inline ::std::string* MethodDescriptorProto::mutable_input_type() { _set_bit(1); if (input_type_ == &_default_input_type_) { @@ -3754,6 +3430,13 @@ inline void MethodDescriptorProto::set_output_type(const char* value) { } output_type_->assign(value); } +inline void MethodDescriptorProto::set_output_type(const char* value, size_t size) { + _set_bit(2); + if (output_type_ == &_default_output_type_) { + output_type_ = new ::std::string; + } + output_type_->assign(reinterpret_cast(value), size); +} inline ::std::string* MethodDescriptorProto::mutable_output_type() { _set_bit(2); if (output_type_ == &_default_output_type_) { @@ -3810,6 +3493,13 @@ inline void FileOptions::set_java_package(const char* value) { } java_package_->assign(value); } +inline void FileOptions::set_java_package(const char* value, size_t size) { + _set_bit(0); + if (java_package_ == &_default_java_package_) { + java_package_ = new ::std::string; + } + java_package_->assign(reinterpret_cast(value), size); +} inline ::std::string* FileOptions::mutable_java_package() { _set_bit(0); if (java_package_ == &_default_java_package_) { @@ -3845,6 +3535,13 @@ inline void FileOptions::set_java_outer_classname(const char* value) { } java_outer_classname_->assign(value); } +inline void FileOptions::set_java_outer_classname(const char* value, size_t size) { + _set_bit(1); + if (java_outer_classname_ == &_default_java_outer_classname_) { + java_outer_classname_ = new ::std::string; + } + java_outer_classname_->assign(reinterpret_cast(value), size); +} inline ::std::string* FileOptions::mutable_java_outer_classname() { _set_bit(1); if (java_outer_classname_ == &_default_java_outer_classname_) { @@ -3869,12 +3566,12 @@ inline void FileOptions::set_java_multiple_files(bool value) { java_multiple_files_ = value; } -// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = CODE_SIZE]; +// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; inline bool FileOptions::has_optimize_for() const { return _has_bit(3); } inline void FileOptions::clear_optimize_for() { - optimize_for_ = 2; + optimize_for_ = 1; _clear_bit(3); } inline ::google::protobuf::FileOptions_OptimizeMode FileOptions::optimize_for() const { @@ -3993,35 +3690,58 @@ inline void FieldOptions::set_packed(bool value) { packed_ = value; } +// optional bool deprecated = 3 [default = false]; +inline bool FieldOptions::has_deprecated() const { + return _has_bit(2); +} +inline void FieldOptions::clear_deprecated() { + deprecated_ = false; + _clear_bit(2); +} +inline bool FieldOptions::deprecated() const { + return deprecated_; +} +inline void FieldOptions::set_deprecated(bool value) { + _set_bit(2); + deprecated_ = value; +} + // optional string experimental_map_key = 9; inline bool FieldOptions::has_experimental_map_key() const { - return _has_bit(2); + return _has_bit(3); } inline void FieldOptions::clear_experimental_map_key() { if (experimental_map_key_ != &_default_experimental_map_key_) { experimental_map_key_->clear(); } - _clear_bit(2); + _clear_bit(3); } inline const ::std::string& FieldOptions::experimental_map_key() const { return *experimental_map_key_; } inline void FieldOptions::set_experimental_map_key(const ::std::string& value) { - _set_bit(2); + _set_bit(3); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } experimental_map_key_->assign(value); } inline void FieldOptions::set_experimental_map_key(const char* value) { - _set_bit(2); + _set_bit(3); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } experimental_map_key_->assign(value); } +inline void FieldOptions::set_experimental_map_key(const char* value, size_t size) { + _set_bit(3); + if (experimental_map_key_ == &_default_experimental_map_key_) { + experimental_map_key_ = new ::std::string; + } + experimental_map_key_->assign(reinterpret_cast(value), size); +} inline ::std::string* FieldOptions::mutable_experimental_map_key() { - _set_bit(2); + _set_bit(3); if (experimental_map_key_ == &_default_experimental_map_key_) { experimental_map_key_ = new ::std::string; } @@ -4200,6 +3920,13 @@ inline void UninterpretedOption_NamePart::set_name_part(const char* value) { } name_part_->assign(value); } +inline void UninterpretedOption_NamePart::set_name_part(const char* value, size_t size) { + _set_bit(0); + if (name_part_ == &_default_name_part_) { + name_part_ = new ::std::string; + } + name_part_->assign(reinterpret_cast(value), size); +} inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { _set_bit(0); if (name_part_ == &_default_name_part_) { @@ -4280,6 +4007,13 @@ inline void UninterpretedOption::set_identifier_value(const char* value) { } identifier_value_->assign(value); } +inline void UninterpretedOption::set_identifier_value(const char* value, size_t size) { + _set_bit(1); + if (identifier_value_ == &_default_identifier_value_) { + identifier_value_ = new ::std::string; + } + identifier_value_->assign(reinterpret_cast(value), size); +} inline ::std::string* UninterpretedOption::mutable_identifier_value() { _set_bit(1); if (identifier_value_ == &_default_identifier_value_) { diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index e0e6f7f2..381a7438 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -250,7 +250,7 @@ message FileOptions { SPEED = 1; // Generate complete code for parsing, serialization, etc. CODE_SIZE = 2; // Use ReflectionOps to implement these methods. } - optional OptimizeMode optimize_for = 9 [default=CODE_SIZE]; + optional OptimizeMode optimize_for = 9 [default=SPEED]; @@ -306,6 +306,12 @@ message FieldOptions { // a single length-delimited blob. optional bool packed = 2; + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default=false]; + // EXPERIMENTAL. DO NOT USE. // For "map" fields, the name of the field in the enclosed type that // is the key for this map. For example, suppose we have: @@ -328,6 +334,7 @@ message FieldOptions { } message EnumOptions { + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc index 6a233cea..910f7e4e 100644 --- a/src/google/protobuf/descriptor_database.cc +++ b/src/google/protobuf/descriptor_database.cc @@ -33,7 +33,11 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include + +#include + #include +#include #include #include @@ -44,151 +48,312 @@ DescriptorDatabase::~DescriptorDatabase() {} // =================================================================== -SimpleDescriptorDatabase::SimpleDescriptorDatabase() {} -SimpleDescriptorDatabase::~SimpleDescriptorDatabase() { - STLDeleteElements(&files_to_delete_); -} - -void SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) { - FileDescriptorProto* new_file = new FileDescriptorProto; - new_file->CopyFrom(file); - AddAndOwn(new_file); -} - -void SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) { - files_to_delete_.push_back(file); - InsertOrUpdate(&files_by_name_, file->name(), file); +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddFile( + const FileDescriptorProto& file, + Value value) { + if (!InsertIfNotPresent(&by_name_, file.name(), value)) { + GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name(); + return false; + } - string path = file->package(); + string path = file.package(); if (!path.empty()) path += '.'; - for (int i = 0; i < file->message_type_size(); i++) { - AddMessage(path, file->message_type(i), file); + for (int i = 0; i < file.message_type_size(); i++) { + if (!AddSymbol(path + file.message_type(i).name(), value)) return false; + if (!AddNestedExtensions(file.message_type(i), value)) return false; } - for (int i = 0; i < file->enum_type_size(); i++) { - AddEnum(path, file->enum_type(i), file); + for (int i = 0; i < file.enum_type_size(); i++) { + if (!AddSymbol(path + file.enum_type(i).name(), value)) return false; } - for (int i = 0; i < file->extension_size(); i++) { - AddField(path, file->extension(i), file); + for (int i = 0; i < file.extension_size(); i++) { + if (!AddSymbol(path + file.extension(i).name(), value)) return false; + if (!AddExtension(file.extension(i), value)) return false; } - for (int i = 0; i < file->service_size(); i++) { - AddService(path, file->service(i), file); + for (int i = 0; i < file.service_size(); i++) { + if (!AddSymbol(path + file.service(i).name(), value)) return false; } + + return true; } -void SimpleDescriptorDatabase::AddMessage( - const string& path, - const DescriptorProto& message_type, - const FileDescriptorProto* file) { - string full_name = path + message_type.name(); - InsertOrUpdate(&files_by_symbol_, full_name, file); +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddSymbol( + const string& name, Value value) { + // We need to make sure not to violate our map invariant. - string sub_path = full_name + '.'; - for (int i = 0; i < message_type.nested_type_size(); i++) { - AddMessage(sub_path, message_type.nested_type(i), file); + // If the symbol name is invalid it could break our lookup algorithm (which + // relies on the fact that '.' sorts before all other characters that are + // valid in symbol names). + if (!ValidateSymbolName(name)) { + GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name; + return false; + } + + // Try to look up the symbol to make sure a super-symbol doesn't already + // exist. + typename map::iterator iter = FindLastLessOrEqual(name); + + if (iter == by_symbol_.end()) { + // Apparently the map is currently empty. Just insert and be done with it. + by_symbol_.insert(make_pair(name, value)); + return true; } - for (int i = 0; i < message_type.enum_type_size(); i++) { - AddEnum(sub_path, message_type.enum_type(i), file); + + if (IsSubSymbol(iter->first, name)) { + GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing " + "symbol \"" << iter->first << "\"."; + return false; } - for (int i = 0; i < message_type.field_size(); i++) { - AddField(sub_path, message_type.field(i), file); + + // OK, that worked. Now we have to make sure that no symbol in the map is + // a sub-symbol of the one we are inserting. The only symbol which could + // be so is the first symbol that is greater than the new symbol. Since + // |iter| points at the last symbol that is less than or equal, we just have + // to increment it. + ++iter; + + if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) { + GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing " + "symbol \"" << iter->first << "\"."; + return false; + } + + // OK, no conflicts. + + // Insert the new symbol using the iterator as a hint, the new entry will + // appear immediately before the one the iterator is pointing at. + by_symbol_.insert(iter, make_pair(name, value)); + + return true; +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddNestedExtensions( + const DescriptorProto& message_type, + Value value) { + for (int i = 0; i < message_type.nested_type_size(); i++) { + if (!AddNestedExtensions(message_type.nested_type(i), value)) return false; } for (int i = 0; i < message_type.extension_size(); i++) { - AddField(sub_path, message_type.extension(i), file); + if (!AddExtension(message_type.extension(i), value)) return false; } + return true; } -void SimpleDescriptorDatabase::AddField( - const string& path, +template +bool SimpleDescriptorDatabase::DescriptorIndex::AddExtension( const FieldDescriptorProto& field, - const FileDescriptorProto* file) { - string full_name = path + field.name(); - InsertOrUpdate(&files_by_symbol_, full_name, file); - - if (field.has_extendee()) { - // This field is an extension. - if (!field.extendee().empty() && field.extendee()[0] == '.') { - // The extension is fully-qualified. We can use it as a lookup key in - // the files_by_symbol_ table. - InsertOrUpdate(&files_by_extension_, - make_pair(field.extendee().substr(1), field.number()), - file); - } else { - // Not fully-qualified. We can't really do anything here, unfortunately. + Value value) { + if (!field.extendee().empty() && field.extendee()[0] == '.') { + // The extension is fully-qualified. We can use it as a lookup key in + // the by_symbol_ table. + if (!InsertIfNotPresent(&by_extension_, + make_pair(field.extendee().substr(1), + field.number()), + value)) { + GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: " + "extend " << field.extendee() << " { " + << field.name() << " = " << field.number() << " }"; + return false; } + } else { + // Not fully-qualified. We can't really do anything here, unfortunately. + // We don't consider this an error, though, because the descriptor is + // valid. } + return true; } -void SimpleDescriptorDatabase::AddEnum( - const string& path, - const EnumDescriptorProto& enum_type, - const FileDescriptorProto* file) { - string full_name = path + enum_type.name(); - InsertOrUpdate(&files_by_symbol_, full_name, file); +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindFile( + const string& filename) { + return FindWithDefault(by_name_, filename, Value()); +} + +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindSymbol( + const string& name) { + typename map::iterator iter = FindLastLessOrEqual(name); + + return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ? + iter->second : Value(); +} - string sub_path = full_name + '.'; - for (int i = 0; i < enum_type.value_size(); i++) { - InsertOrUpdate(&files_by_symbol_, - sub_path + enum_type.value(i).name(), - file); +template +Value SimpleDescriptorDatabase::DescriptorIndex::FindExtension( + const string& containing_type, + int field_number) { + return FindWithDefault(by_extension_, + make_pair(containing_type, field_number), + Value()); +} + +template +bool SimpleDescriptorDatabase::DescriptorIndex::FindAllExtensionNumbers( + const string& containing_type, + vector* output) { + typename map, Value >::const_iterator it = + by_extension_.lower_bound(make_pair(containing_type, 0)); + bool success = false; + + for (; it != by_extension_.end() && it->first.first == containing_type; + ++it) { + output->push_back(it->first.second); + success = true; } + + return success; +} + +template +typename map::iterator +SimpleDescriptorDatabase::DescriptorIndex::FindLastLessOrEqual( + const string& name) { + // Find the last key in the map which sorts less than or equal to the + // symbol name. Since upper_bound() returns the *first* key that sorts + // *greater* than the input, we want the element immediately before that. + typename map::iterator iter = by_symbol_.upper_bound(name); + if (iter != by_symbol_.begin()) --iter; + return iter; } -void SimpleDescriptorDatabase::AddService( - const string& path, - const ServiceDescriptorProto& service, - const FileDescriptorProto* file) { - string full_name = path + service.name(); - InsertOrUpdate(&files_by_symbol_, full_name, file); +template +bool SimpleDescriptorDatabase::DescriptorIndex::IsSubSymbol( + const string& sub_symbol, const string& super_symbol) { + return sub_symbol == super_symbol || + (HasPrefixString(super_symbol, sub_symbol) && + super_symbol[sub_symbol.size()] == '.'); +} - string sub_path = full_name + '.'; - for (int i = 0; i < service.method_size(); i++) { - InsertOrUpdate(&files_by_symbol_, - sub_path + service.method(i).name(), - file); +template +bool SimpleDescriptorDatabase::DescriptorIndex::ValidateSymbolName( + const string& name) { + for (int i = 0; i < name.size(); i++) { + // I don't trust ctype.h due to locales. :( + if (name[i] != '.' && name[i] != '_' && + (name[i] < '0' || name[i] > '9') && + (name[i] < 'A' || name[i] > 'Z') && + (name[i] < 'a' || name[i] > 'z')) { + return false; + } } + return true; +} + +// ------------------------------------------------------------------- + +SimpleDescriptorDatabase::SimpleDescriptorDatabase() {} +SimpleDescriptorDatabase::~SimpleDescriptorDatabase() { + STLDeleteElements(&files_to_delete_); +} + +bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) { + FileDescriptorProto* new_file = new FileDescriptorProto; + new_file->CopyFrom(file); + return AddAndOwn(new_file); +} + +bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) { + files_to_delete_.push_back(file); + return index_.AddFile(*file, file); } bool SimpleDescriptorDatabase::FindFileByName( const string& filename, FileDescriptorProto* output) { - const FileDescriptorProto* result = FindPtrOrNull(files_by_name_, filename); - if (result == NULL) { - return false; - } else { - output->CopyFrom(*result); - return true; - } + return MaybeCopy(index_.FindFile(filename), output); } bool SimpleDescriptorDatabase::FindFileContainingSymbol( const string& symbol_name, FileDescriptorProto* output) { - const FileDescriptorProto* result = - FindPtrOrNull(files_by_symbol_, symbol_name); - if (result == NULL) { - return false; - } else { - output->CopyFrom(*result); - return true; - } + return MaybeCopy(index_.FindSymbol(symbol_name), output); } bool SimpleDescriptorDatabase::FindFileContainingExtension( const string& containing_type, int field_number, FileDescriptorProto* output) { - const FileDescriptorProto* result = - FindPtrOrNull(files_by_extension_, - make_pair(containing_type, field_number)); - if (result == NULL) { - return false; + return MaybeCopy(index_.FindExtension(containing_type, field_number), output); +} + +bool SimpleDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + return index_.FindAllExtensionNumbers(extendee_type, output); +} + +bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file, + FileDescriptorProto* output) { + if (file == NULL) return false; + output->CopyFrom(*file); + return true; +} + +// ------------------------------------------------------------------- + +EncodedDescriptorDatabase::EncodedDescriptorDatabase() {} +EncodedDescriptorDatabase::~EncodedDescriptorDatabase() { + for (int i = 0; i < files_to_delete_.size(); i++) { + operator delete(files_to_delete_[i]); + } +} + +bool EncodedDescriptorDatabase::Add( + const void* encoded_file_descriptor, int size) { + FileDescriptorProto file; + if (file.ParseFromArray(encoded_file_descriptor, size)) { + return index_.AddFile(file, make_pair(encoded_file_descriptor, size)); } else { - output->CopyFrom(*result); - return true; + GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to " + "EncodedDescriptorDatabase::Add()."; + return false; } } +bool EncodedDescriptorDatabase::AddCopy( + const void* encoded_file_descriptor, int size) { + void* copy = operator new(size); + memcpy(copy, encoded_file_descriptor, size); + files_to_delete_.push_back(copy); + return Add(copy, size); +} + +bool EncodedDescriptorDatabase::FindFileByName( + const string& filename, + FileDescriptorProto* output) { + return MaybeParse(index_.FindFile(filename), output); +} + +bool EncodedDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, + FileDescriptorProto* output) { + return MaybeParse(index_.FindSymbol(symbol_name), output); +} + +bool EncodedDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, + int field_number, + FileDescriptorProto* output) { + return MaybeParse(index_.FindExtension(containing_type, field_number), + output); +} + +bool EncodedDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + return index_.FindAllExtensionNumbers(extendee_type, output); +} + +bool EncodedDescriptorDatabase::MaybeParse( + pair encoded_file, + FileDescriptorProto* output) { + if (encoded_file.first == NULL) return false; + return output->ParseFromArray(encoded_file.first, encoded_file.second); +} + // =================================================================== DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool) @@ -231,6 +396,22 @@ bool DescriptorPoolDatabase::FindFileContainingExtension( return true; } +bool DescriptorPoolDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type); + if (extendee == NULL) return false; + + vector extensions; + pool_.FindAllExtensions(extendee, &extensions); + + for (int i = 0; i < extensions.size(); ++i) { + output->push_back(extensions[i]->number()); + } + + return true; +} + // =================================================================== MergedDescriptorDatabase::MergedDescriptorDatabase( @@ -301,5 +482,27 @@ bool MergedDescriptorDatabase::FindFileContainingExtension( return false; } +bool MergedDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, + vector* output) { + set merged_results; + vector results; + bool success = false; + + for (int i = 0; i < sources_.size(); i++) { + if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) { + copy(results.begin(), results.end(), + insert_iterator >(merged_results, merged_results.begin())); + success = true; + } + results.clear(); + } + + copy(merged_results.begin(), merged_results.end(), + insert_iterator >(*output, output->end())); + + return success; +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h index 1230d09b..c23ab75f 100644 --- a/src/google/protobuf/descriptor_database.h +++ b/src/google/protobuf/descriptor_database.h @@ -46,6 +46,13 @@ namespace google { namespace protobuf { +// Defined in this file. +class DescriptorDatabase; +class SimpleDescriptorDatabase; +class EncodedDescriptorDatabase; +class DescriptorPoolDatabase; +class MergedDescriptorDatabase; + // Abstract interface for a database of descriptors. // // This is useful if you want to create a DescriptorPool which loads @@ -78,6 +85,21 @@ class LIBPROTOBUF_EXPORT DescriptorDatabase { int field_number, FileDescriptorProto* output) = 0; + // Finds the tag numbers used by all known extensions of + // extendee_type, and appends them to output in an undefined + // order. This method is best-effort: it's not guaranteed that the + // database will find all extensions, and it's not guaranteed that + // FindFileContainingExtension will return true on all of the found + // numbers. Returns true if the search was successful, otherwise + // returns false and leaves output unchanged. + // + // This method has a default implementation that always returns + // false. + virtual bool FindAllExtensionNumbers(const string& extendee_type, + vector* output) { + return false; + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase); }; @@ -85,7 +107,11 @@ class LIBPROTOBUF_EXPORT DescriptorDatabase { // A DescriptorDatabase into which you can insert files manually. // // FindFileContainingSymbol() is fully-implemented. When you add a file, its -// symbols will be indexed for this purpose. +// symbols will be indexed for this purpose. Note that the implementation +// may return false positives, but only if it isn't possible for the symbol +// to be defined in any other file. In particular, if a file defines a symbol +// "Foo", then searching for "Foo.[anything]" will match that file. This way, +// the database does not need to aggressively index all children of a symbol. // // FindFileContainingExtension() is mostly-implemented. It works if and only // if the original FieldDescriptorProto defining the extension has a @@ -105,11 +131,13 @@ class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase { ~SimpleDescriptorDatabase(); // Adds the FileDescriptorProto to the database, making a copy. The object - // can be deleted after Add() returns. - void Add(const FileDescriptorProto& file); + // can be deleted after Add() returns. Returns false if the file conflicted + // with a file already in the database, in which case an error will have + // been written to GOOGLE_LOG(ERROR). + bool Add(const FileDescriptorProto& file); // Adds the FileDescriptorProto to the database and takes ownership of it. - void AddAndOwn(const FileDescriptorProto* file); + bool AddAndOwn(const FileDescriptorProto* file); // implements DescriptorDatabase ----------------------------------- bool FindFileByName(const string& filename, @@ -119,31 +147,162 @@ class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase { bool FindFileContainingExtension(const string& containing_type, int field_number, FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); private: - // Helpers to recursively add particular descriptors and all their contents - // to the by-symbol and by-extension tables. - void AddMessage(const string& path, - const DescriptorProto& message_type, - const FileDescriptorProto* file); - void AddField(const string& path, - const FieldDescriptorProto& field, - const FileDescriptorProto* file); - void AddEnum(const string& path, - const EnumDescriptorProto& enum_type, - const FileDescriptorProto* file); - void AddService(const string& path, - const ServiceDescriptorProto& service, - const FileDescriptorProto* file); + // So that it can use DescriptorIndex. + friend class EncodedDescriptorDatabase; + + // An index mapping file names, symbol names, and extension numbers to + // some sort of values. + template + class DescriptorIndex { + public: + // Helpers to recursively add particular descriptors and all their contents + // to the index. + bool AddFile(const FileDescriptorProto& file, + Value value); + bool AddSymbol(const string& name, Value value); + bool AddNestedExtensions(const DescriptorProto& message_type, + Value value); + bool AddExtension(const FieldDescriptorProto& field, + Value value); + + Value FindFile(const string& filename); + Value FindSymbol(const string& name); + Value FindExtension(const string& containing_type, int field_number); + bool FindAllExtensionNumbers(const string& containing_type, + vector* output); + + private: + map by_name_; + map by_symbol_; + map, Value> by_extension_; + + // Invariant: The by_symbol_ map does not contain any symbols which are + // prefixes of other symbols in the map. For example, "foo.bar" is a + // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz"). + // + // This invariant is important because it means that given a symbol name, + // we can find a key in the map which is a prefix of the symbol in O(lg n) + // time, and we know that there is at most one such key. + // + // The prefix lookup algorithm works like so: + // 1) Find the last key in the map which is less than or equal to the + // search key. + // 2) If the found key is a prefix of the search key, then return it. + // Otherwise, there is no match. + // + // I am sure this algorithm has been described elsewhere, but since I + // wasn't able to find it quickly I will instead prove that it works + // myself. The key to the algorithm is that if a match exists, step (1) + // will find it. Proof: + // 1) Define the "search key" to be the key we are looking for, the "found + // key" to be the key found in step (1), and the "match key" to be the + // key which actually matches the serach key (i.e. the key we're trying + // to find). + // 2) The found key must be less than or equal to the search key by + // definition. + // 3) The match key must also be less than or equal to the search key + // (because it is a prefix). + // 4) The match key cannot be greater than the found key, because if it + // were, then step (1) of the algorithm would have returned the match + // key instead (since it finds the *greatest* key which is less than or + // equal to the search key). + // 5) Therefore, the found key must be between the match key and the search + // key, inclusive. + // 6) Since the search key must be a sub-symbol of the match key, if it is + // not equal to the match key, then search_key[match_key.size()] must + // be '.'. + // 7) Since '.' sorts before any other character that is valid in a symbol + // name, then if the found key is not equal to the match key, then + // found_key[match_key.size()] must also be '.', because any other value + // would make it sort after the search key. + // 8) Therefore, if the found key is not equal to the match key, then the + // found key must be a sub-symbol of the match key. However, this would + // contradict our map invariant which says that no symbol in the map is + // a sub-symbol of any other. + // 9) Therefore, the found key must match the match key. + // + // The above proof assumes the match key exists. In the case that the + // match key does not exist, then step (1) will return some other symbol. + // That symbol cannot be a super-symbol of the search key since if it were, + // then it would be a match, and we're assuming the match key doesn't exist. + // Therefore, step 2 will correctly return no match. + + // Find the last entry in the by_symbol_ map whose key is less than or + // equal to the given name. + typename map::iterator FindLastLessOrEqual( + const string& name); + + // True if either the arguments are equal or super_symbol identifies a + // parent symbol of sub_symbol (e.g. "foo.bar" is a parent of + // "foo.bar.baz", but not a parent of "foo.barbaz"). + bool IsSubSymbol(const string& sub_symbol, const string& super_symbol); + // Returns true if and only if all characters in the name are alphanumerics, + // underscores, or periods. + bool ValidateSymbolName(const string& name); + }; + + + DescriptorIndex index_; vector files_to_delete_; - map files_by_name_; - map files_by_symbol_; - map, const FileDescriptorProto*> files_by_extension_; + + // If file is non-NULL, copy it into *output and return true, otherwise + // return false. + bool MaybeCopy(const FileDescriptorProto* file, + FileDescriptorProto* output); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase); }; +// Very similar to SimpleDescriptorDatabase, but stores all the descriptors +// as raw bytes and generally tries to use as little memory as possible. +// +// The same caveats regarding FindFileContainingExtension() apply as with +// SimpleDescriptorDatabase. +class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { + public: + EncodedDescriptorDatabase(); + ~EncodedDescriptorDatabase(); + + // Adds the FileDescriptorProto to the database. The descriptor is provided + // in encoded form. The database does not make a copy of the bytes, nor + // does it take ownership; it's up to the caller to make sure the bytes + // remain valid for the life of the database. Returns false and logs an error + // if the bytes are not a valid FileDescriptorProto or if the file conflicted + // with a file already in the database. + bool Add(const void* encoded_file_descriptor, int size); + + // Like Add(), but makes a copy of the data, so that the caller does not + // need to keep it around. + bool AddCopy(const void* encoded_file_descriptor, int size); + + // implements DescriptorDatabase ----------------------------------- + bool FindFileByName(const string& filename, + FileDescriptorProto* output); + bool FindFileContainingSymbol(const string& symbol_name, + FileDescriptorProto* output); + bool FindFileContainingExtension(const string& containing_type, + int field_number, + FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); + + private: + SimpleDescriptorDatabase::DescriptorIndex > index_; + vector files_to_delete_; + + // If encoded_file.first is non-NULL, parse the data into *output and return + // true, otherwise return false. + bool MaybeParse(pair encoded_file, + FileDescriptorProto* output); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase); +}; + // A DescriptorDatabase that fetches files from a given pool. class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { public: @@ -158,6 +317,8 @@ class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase { bool FindFileContainingExtension(const string& containing_type, int field_number, FileDescriptorProto* output); + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); private: const DescriptorPool& pool_; @@ -185,6 +346,10 @@ class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase { bool FindFileContainingExtension(const string& containing_type, int field_number, FileDescriptorProto* output); + // Merges the results of calling all databases. Returns true iff any + // of the databases returned true. + bool FindAllExtensionNumbers(const string& extendee_type, + vector* output); private: vector sources_; diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index d56de04c..64ec551a 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -48,13 +48,6 @@ namespace google { namespace protobuf { namespace { -static bool AddToPool(DescriptorPool* pool, const char* file_text) { - FileDescriptorProto file_proto; - if (!TextFormat::ParseFromString(file_text, &file_proto)) return false; - if (pool->BuildFile(file_proto) == NULL) return false; - return true; -} - static void AddToDatabase(SimpleDescriptorDatabase* database, const char* file_text) { FileDescriptorProto file_proto; @@ -74,25 +67,134 @@ static void ExpectContainsType(const FileDescriptorProto& proto, // =================================================================== -TEST(SimpleDescriptorDatabaseTest, FindFileByName) { - SimpleDescriptorDatabase database; - AddToDatabase(&database, +#if GTEST_HAS_PARAM_TEST + +// SimpleDescriptorDatabase, EncodedDescriptorDatabase, and +// DescriptorPoolDatabase call for very similar tests. Instead of writing +// three nearly-identical sets of tests, we use parameterized tests to apply +// the same code to all three. + +// The parameterized test runs against a DescriptarDatabaseTestCase. We have +// implementations for each of the three classes we want to test. +class DescriptorDatabaseTestCase { + public: + virtual ~DescriptorDatabaseTestCase() {} + + virtual DescriptorDatabase* GetDatabase() = 0; + virtual bool AddToDatabase(const FileDescriptorProto& file) = 0; +}; + +// Factory function type. +typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory(); + +// Specialization for SimpleDescriptorDatabase. +class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase { + public: + static DescriptorDatabaseTestCase* New() { + return new SimpleDescriptorDatabaseTestCase; + } + + virtual ~SimpleDescriptorDatabaseTestCase() {} + + virtual DescriptorDatabase* GetDatabase() { + return &database_; + } + virtual bool AddToDatabase(const FileDescriptorProto& file) { + return database_.Add(file); + } + + private: + SimpleDescriptorDatabase database_; +}; + +// Specialization for EncodedDescriptorDatabase. +class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase { + public: + static DescriptorDatabaseTestCase* New() { + return new EncodedDescriptorDatabaseTestCase; + } + + virtual ~EncodedDescriptorDatabaseTestCase() {} + + virtual DescriptorDatabase* GetDatabase() { + return &database_; + } + virtual bool AddToDatabase(const FileDescriptorProto& file) { + string data; + file.SerializeToString(&data); + return database_.AddCopy(data.data(), data.size()); + } + + private: + EncodedDescriptorDatabase database_; +}; + +// Specialization for DescriptorPoolDatabase. +class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase { + public: + static DescriptorDatabaseTestCase* New() { + return new EncodedDescriptorDatabaseTestCase; + } + + DescriptorPoolDatabaseTestCase() : database_(pool_) {} + virtual ~DescriptorPoolDatabaseTestCase() {} + + virtual DescriptorDatabase* GetDatabase() { + return &database_; + } + virtual bool AddToDatabase(const FileDescriptorProto& file) { + return pool_.BuildFile(file); + } + + private: + DescriptorPool pool_; + DescriptorPoolDatabase database_; +}; + +// ------------------------------------------------------------------- + +class DescriptorDatabaseTest + : public testing::TestWithParam { + protected: + virtual void SetUp() { + test_case_.reset(GetParam()()); + database_ = test_case_->GetDatabase(); + } + + void AddToDatabase(const char* file_descriptor_text) { + FileDescriptorProto file_proto; + EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto)); + EXPECT_TRUE(test_case_->AddToDatabase(file_proto)); + } + + void AddToDatabaseWithError(const char* file_descriptor_text) { + FileDescriptorProto file_proto; + EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto)); + EXPECT_FALSE(test_case_->AddToDatabase(file_proto)); + } + + scoped_ptr test_case_; + DescriptorDatabase* database_; +}; + +TEST_P(DescriptorDatabaseTest, FindFileByName) { + AddToDatabase( "name: \"foo.proto\" " "message_type { name:\"Foo\" }"); - AddToDatabase(&database, + AddToDatabase( "name: \"bar.proto\" " "message_type { name:\"Bar\" }"); { FileDescriptorProto file; - EXPECT_TRUE(database.FindFileByName("foo.proto", &file)); + EXPECT_TRUE(database_->FindFileByName("foo.proto", &file)); EXPECT_EQ("foo.proto", file.name()); ExpectContainsType(file, "Foo"); } { FileDescriptorProto file; - EXPECT_TRUE(database.FindFileByName("bar.proto", &file)); + EXPECT_TRUE(database_->FindFileByName("bar.proto", &file)); EXPECT_EQ("bar.proto", file.name()); ExpectContainsType(file, "Bar"); } @@ -100,13 +202,12 @@ TEST(SimpleDescriptorDatabaseTest, FindFileByName) { { // Fails to find undefined files. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileByName("baz.proto", &file)); + EXPECT_FALSE(database_->FindFileByName("baz.proto", &file)); } } -TEST(SimpleDescriptorDatabaseTest, FindFileContainingSymbol) { - SimpleDescriptorDatabase database; - AddToDatabase(&database, +TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) { + AddToDatabase( "name: \"foo.proto\" " "message_type { " " name: \"Foo\" " @@ -124,96 +225,95 @@ TEST(SimpleDescriptorDatabaseTest, FindFileContainingSymbol) { " method { name: \"Thud\" } " "}" ); - AddToDatabase(&database, + AddToDatabase( "name: \"bar.proto\" " "package: \"corge\" " "message_type { name: \"Bar\" }"); { FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find fields. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo.qux", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find nested types. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo.Grault", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find nested enums. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo.Garply", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find enum types. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Waldo", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find enum values. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Waldo.FRED", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find extensions. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("plugh", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find services. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Xyzzy", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find methods. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Xyzzy.Thud", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file)); EXPECT_EQ("foo.proto", file.name()); } { // Can find things in packages. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("corge.Bar", &file)); + EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file)); EXPECT_EQ("bar.proto", file.name()); } { // Fails to find undefined symbols. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingSymbol("Baz", &file)); + EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file)); } { // Names must be fully-qualified. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingSymbol("Bar", &file)); + EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file)); } } -TEST(SimpleDescriptorDatabaseTest, FindFileContainingExtension) { - SimpleDescriptorDatabase database; - AddToDatabase(&database, +TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) { + AddToDatabase( "name: \"foo.proto\" " "message_type { " " name: \"Foo\" " @@ -221,7 +321,7 @@ TEST(SimpleDescriptorDatabaseTest, FindFileContainingExtension) { " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " " extendee: \".Foo\" }" "}"); - AddToDatabase(&database, + AddToDatabase( "name: \"bar.proto\" " "package: \"corge\" " "dependency: \"foo.proto\" " @@ -235,20 +335,20 @@ TEST(SimpleDescriptorDatabaseTest, FindFileContainingExtension) { { FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("Foo", 5, &file)); + EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file)); EXPECT_EQ("foo.proto", file.name()); } { FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("Foo", 32, &file)); + EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file)); EXPECT_EQ("bar.proto", file.name()); } { // Can find extensions for qualified type names. FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("corge.Bar", 70, &file)); + EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file)); EXPECT_EQ("bar.proto", file.name()); } @@ -256,173 +356,127 @@ TEST(SimpleDescriptorDatabaseTest, FindFileContainingExtension) { // Can't find extensions whose extendee was not fully-qualified in the // FileDescriptorProto. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("Bar", 56, &file)); - EXPECT_FALSE(database.FindFileContainingExtension("corge.Bar", 56, &file)); + EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file)); + EXPECT_FALSE( + database_->FindFileContainingExtension("corge.Bar", 56, &file)); } { // Can't find non-existent extension numbers. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("Foo", 12, &file)); + EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file)); } { // Can't find extensions for non-existent types. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("NoSuchType", 5, &file)); + EXPECT_FALSE( + database_->FindFileContainingExtension("NoSuchType", 5, &file)); } { // Can't find extensions for unqualified type names. FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("Bar", 70, &file)); + EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file)); } } -// =================================================================== - -TEST(DescriptorPoolDatabaseTest, FindFileByName) { - DescriptorPool pool; - ASSERT_TRUE(AddToPool(&pool, - "name: \"foo.proto\" " - "message_type { name:\"Foo\" }")); - ASSERT_TRUE(AddToPool(&pool, - "name: \"bar.proto\" " - "message_type { name:\"Bar\" }")); - - DescriptorPoolDatabase database(pool); - - { - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileByName("foo.proto", &file)); - EXPECT_EQ("foo.proto", file.name()); - ExpectContainsType(file, "Foo"); - } - - { - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileByName("bar.proto", &file)); - EXPECT_EQ("bar.proto", file.name()); - ExpectContainsType(file, "Bar"); - } - - { - // Fails to find undefined files. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileByName("baz.proto", &file)); - } -} - -TEST(DescriptorPoolDatabaseTest, FindFileContainingSymbol) { - DescriptorPool pool; - ASSERT_TRUE(AddToPool(&pool, +TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) { + AddToDatabase( "name: \"foo.proto\" " "message_type { " " name: \"Foo\" " - " field { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:1 }" - "}")); - ASSERT_TRUE(AddToPool(&pool, + " extension_range { start: 1 end: 1000 } " + " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " + " extendee: \".Foo\" }" + "}"); + AddToDatabase( "name: \"bar.proto\" " "package: \"corge\" " - "message_type { name: \"Bar\" }")); - - DescriptorPoolDatabase database(pool); - - { - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo", &file)); - EXPECT_EQ("foo.proto", file.name()); - } + "dependency: \"foo.proto\" " + "message_type { " + " name: \"Bar\" " + " extension_range { start: 1 end: 1000 } " + "} " + "extension { name:\"grault\" extendee: \".Foo\" number:32 } " + "extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } " + "extension { name:\"waldo\" extendee: \"Bar\" number:56 } "); { - // Can find fields. - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("Foo.qux", &file)); - EXPECT_EQ("foo.proto", file.name()); + vector numbers; + EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers)); + ASSERT_EQ(2, numbers.size()); + sort(numbers.begin(), numbers.end()); + EXPECT_EQ(5, numbers[0]); + EXPECT_EQ(32, numbers[1]); } { - // Can find things in packages. - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingSymbol("corge.Bar", &file)); - EXPECT_EQ("bar.proto", file.name()); + vector numbers; + EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers)); + // Note: won't find extension 56 due to the name not being fully qualified. + ASSERT_EQ(1, numbers.size()); + EXPECT_EQ(70, numbers[0]); } { - // Fails to find undefined symbols. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingSymbol("Baz", &file)); + // Can't find extensions for non-existent types. + vector numbers; + EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers)); } { - // Names must be fully-qualified. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingSymbol("Bar", &file)); + // Can't find extensions for unqualified types. + vector numbers; + EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers)); } } -TEST(DescriptorPoolDatabaseTest, FindFileContainingExtension) { - DescriptorPool pool; - ASSERT_TRUE(AddToPool(&pool, +TEST_P(DescriptorDatabaseTest, ConflictingFileError) { + AddToDatabase( "name: \"foo.proto\" " "message_type { " " name: \"Foo\" " - " extension_range { start: 1 end: 1000 } " - " extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " - " extendee: \"Foo\" }" - "}")); - ASSERT_TRUE(AddToPool(&pool, - "name: \"bar.proto\" " - "package: \"corge\" " - "dependency: \"foo.proto\" " + "}"); + AddToDatabaseWithError( + "name: \"foo.proto\" " "message_type { " " name: \"Bar\" " - " extension_range { start: 1 end: 1000 } " - "} " - "extension { name:\"grault\" label:LABEL_OPTIONAL type:TYPE_BOOL number:32 " - " extendee: \"Foo\" } " - "extension { name:\"garply\" label:LABEL_OPTIONAL type:TYPE_BOOL number:70 " - " extendee: \"Bar\" } ")); - - DescriptorPoolDatabase database(pool); - - { - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("Foo", 5, &file)); - EXPECT_EQ("foo.proto", file.name()); - } - - { - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("Foo", 32, &file)); - EXPECT_EQ("bar.proto", file.name()); - } + "}"); +} - { - // Can find extensions for qualified type names.. - FileDescriptorProto file; - EXPECT_TRUE(database.FindFileContainingExtension("corge.Bar", 70, &file)); - EXPECT_EQ("bar.proto", file.name()); - } +TEST_P(DescriptorDatabaseTest, ConflictingTypeError) { + AddToDatabase( + "name: \"foo.proto\" " + "message_type { " + " name: \"Foo\" " + "}"); + AddToDatabaseWithError( + "name: \"bar.proto\" " + "message_type { " + " name: \"Foo\" " + "}"); +} - { - // Can't find non-existent extension numbers. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("Foo", 12, &file)); - } +TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) { + AddToDatabase( + "name: \"foo.proto\" " + "extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " + " extendee: \".Foo\" }"); + AddToDatabaseWithError( + "name: \"bar.proto\" " + "extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 " + " extendee: \".Foo\" }"); +} - { - // Can't find extensions for non-existent types. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("NoSuchType", 5, &file)); - } +INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest, + testing::Values(&SimpleDescriptorDatabaseTestCase::New)); +INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest, + testing::Values(&EncodedDescriptorDatabaseTestCase::New)); +INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest, + testing::Values(&DescriptorPoolDatabaseTestCase::New)); - { - // Can't find extensions for unqualified type names. - FileDescriptorProto file; - EXPECT_FALSE(database.FindFileContainingExtension("Bar", 70, &file)); - } -} +#endif // GTEST_HAS_PARAM_TEST // =================================================================== @@ -610,6 +664,49 @@ TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) { } } +TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) { + { + // Message only has extension in database1_ + vector numbers; + EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers)); + ASSERT_EQ(1, numbers.size()); + EXPECT_EQ(3, numbers[0]); + } + + { + // Message only has extension in database2_ + vector numbers; + EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers)); + ASSERT_EQ(1, numbers.size()); + EXPECT_EQ(5, numbers[0]); + } + + { + // Merge results from the two databases. + vector numbers; + EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers)); + ASSERT_EQ(2, numbers.size()); + sort(numbers.begin(), numbers.end()); + EXPECT_EQ(12, numbers[0]); + EXPECT_EQ(13, numbers[1]); + } + + { + vector numbers; + EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers)); + ASSERT_EQ(2, numbers.size()); + sort(numbers.begin(), numbers.end()); + EXPECT_EQ(12, numbers[0]); + EXPECT_EQ(13, numbers[1]); + } + + { + // Can't find extensions for a non-existent message. + vector numbers; + EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers)); + } +} + } // anonymous namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 5ffaea77..ce216135 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -346,6 +346,18 @@ TEST_F(FileDescriptorTest, FindExtensionByNumber) { EXPECT_TRUE(pool_.FindExtensionByNumber(foo_message_, 2) == NULL); } +TEST_F(FileDescriptorTest, BuildAgain) { + // Test that if te call BuildFile again on the same input we get the same + // FileDescriptor back. + FileDescriptorProto file; + foo_file_->CopyTo(&file); + EXPECT_EQ(foo_file_, pool_.BuildFile(file)); + + // But if we change the file then it won't work. + file.set_package("some.other.package"); + EXPECT_TRUE(pool_.BuildFile(file) == NULL); +} + // =================================================================== // Test simple flat messages and fields. @@ -1492,6 +1504,16 @@ TEST_F(ExtensionDescriptorTest, FindExtensionByName) { EXPECT_TRUE(foo_->FindExtensionByName("foo_message") == NULL); } +TEST_F(ExtensionDescriptorTest, FindAllExtensions) { + vector extensions; + pool_.FindAllExtensions(foo_, &extensions); + ASSERT_EQ(4, extensions.size()); + EXPECT_EQ(10, extensions[0]->number()); + EXPECT_EQ(19, extensions[1]->number()); + EXPECT_EQ(30, extensions[2]->number()); + EXPECT_EQ(39, extensions[3]->number()); +} + // =================================================================== class MiscTest : public testing::Test { @@ -1716,6 +1738,219 @@ TEST_F(MiscTest, FieldOptions) { EXPECT_EQ(FieldOptions::CORD, bar->options().ctype()); } +// =================================================================== + +class AllowUnknownDependenciesTest : public testing::Test { + protected: + virtual void SetUp() { + FileDescriptorProto foo_proto, bar_proto; + + pool_.AllowUnknownDependencies(); + + ASSERT_TRUE(TextFormat::ParseFromString( + "name: 'foo.proto'" + "dependency: 'bar.proto'" + "dependency: 'baz.proto'" + "message_type {" + " name: 'Foo'" + " field { name:'bar' number:1 label:LABEL_OPTIONAL type_name:'Bar' }" + " field { name:'baz' number:2 label:LABEL_OPTIONAL type_name:'Baz' }" + " field { name:'qux' number:3 label:LABEL_OPTIONAL" + " type_name: '.corge.Qux'" + " type: TYPE_ENUM" + " options {" + " uninterpreted_option {" + " name {" + " name_part: 'grault'" + " is_extension: true" + " }" + " positive_int_value: 1234" + " }" + " }" + " }" + "}", + &foo_proto)); + ASSERT_TRUE(TextFormat::ParseFromString( + "name: 'bar.proto'" + "message_type { name: 'Bar' }", + &bar_proto)); + + // Collect pointers to stuff. + bar_file_ = pool_.BuildFile(bar_proto); + ASSERT_TRUE(bar_file_ != NULL); + + ASSERT_EQ(1, bar_file_->message_type_count()); + bar_type_ = bar_file_->message_type(0); + + foo_file_ = pool_.BuildFile(foo_proto); + ASSERT_TRUE(foo_file_ != NULL); + + ASSERT_EQ(1, foo_file_->message_type_count()); + foo_type_ = foo_file_->message_type(0); + + ASSERT_EQ(3, foo_type_->field_count()); + bar_field_ = foo_type_->field(0); + baz_field_ = foo_type_->field(1); + qux_field_ = foo_type_->field(2); + } + + const FileDescriptor* bar_file_; + const Descriptor* bar_type_; + const FileDescriptor* foo_file_; + const Descriptor* foo_type_; + const FieldDescriptor* bar_field_; + const FieldDescriptor* baz_field_; + const FieldDescriptor* qux_field_; + + DescriptorPool pool_; +}; + +TEST_F(AllowUnknownDependenciesTest, PlaceholderFile) { + ASSERT_EQ(2, foo_file_->dependency_count()); + EXPECT_EQ(bar_file_, foo_file_->dependency(0)); + + const FileDescriptor* baz_file = foo_file_->dependency(1); + EXPECT_EQ("baz.proto", baz_file->name()); + EXPECT_EQ(0, baz_file->message_type_count()); + + // Placeholder files should not be findable. + EXPECT_EQ(bar_file_, pool_.FindFileByName(bar_file_->name())); + EXPECT_TRUE(pool_.FindFileByName(baz_file->name()) == NULL); +} + +TEST_F(AllowUnknownDependenciesTest, PlaceholderTypes) { + ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, bar_field_->type()); + EXPECT_EQ(bar_type_, bar_field_->message_type()); + + ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, baz_field_->type()); + const Descriptor* baz_type = baz_field_->message_type(); + EXPECT_EQ("Baz", baz_type->name()); + EXPECT_EQ("Baz", baz_type->full_name()); + EXPECT_EQ("Baz.placeholder.proto", baz_type->file()->name()); + EXPECT_EQ(0, baz_type->extension_range_count()); + + ASSERT_EQ(FieldDescriptor::TYPE_ENUM, qux_field_->type()); + const EnumDescriptor* qux_type = qux_field_->enum_type(); + EXPECT_EQ("Qux", qux_type->name()); + EXPECT_EQ("corge.Qux", qux_type->full_name()); + EXPECT_EQ("corge.Qux.placeholder.proto", qux_type->file()->name()); + + // Placeholder types should not be findable. + EXPECT_EQ(bar_type_, pool_.FindMessageTypeByName(bar_type_->full_name())); + EXPECT_TRUE(pool_.FindMessageTypeByName(baz_type->full_name()) == NULL); + EXPECT_TRUE(pool_.FindEnumTypeByName(qux_type->full_name()) == NULL); +} + +TEST_F(AllowUnknownDependenciesTest, CopyTo) { + // FieldDescriptor::CopyTo() should write non-fully-qualified type names + // for placeholder types which were not originally fully-qualified. + FieldDescriptorProto proto; + + // Bar is not a placeholder, so it is fully-qualified. + bar_field_->CopyTo(&proto); + EXPECT_EQ(".Bar", proto.type_name()); + EXPECT_EQ(FieldDescriptorProto::TYPE_MESSAGE, proto.type()); + + // Baz is an unqualified placeholder. + proto.Clear(); + baz_field_->CopyTo(&proto); + EXPECT_EQ("Baz", proto.type_name()); + EXPECT_FALSE(proto.has_type()); + + // Qux is a fully-qualified placeholder. + proto.Clear(); + qux_field_->CopyTo(&proto); + EXPECT_EQ(".corge.Qux", proto.type_name()); + EXPECT_EQ(FieldDescriptorProto::TYPE_ENUM, proto.type()); +} + +TEST_F(AllowUnknownDependenciesTest, CustomOptions) { + // Qux should still have the uninterpreted option attached. + ASSERT_EQ(1, qux_field_->options().uninterpreted_option_size()); + const UninterpretedOption& option = + qux_field_->options().uninterpreted_option(0); + ASSERT_EQ(1, option.name_size()); + EXPECT_EQ("grault", option.name(0).name_part()); +} + +TEST_F(AllowUnknownDependenciesTest, UnknownExtendee) { + // Test that we can extend an unknown type. This is slightly tricky because + // it means that the placeholder type must have an extension range. + + FileDescriptorProto extension_proto; + + ASSERT_TRUE(TextFormat::ParseFromString( + "name: 'extension.proto'" + "extension { extendee: 'UnknownType' name:'some_extension' number:123" + " label:LABEL_OPTIONAL type:TYPE_INT32 }", + &extension_proto)); + const FileDescriptor* file = pool_.BuildFile(extension_proto); + + ASSERT_TRUE(file != NULL); + + ASSERT_EQ(1, file->extension_count()); + const Descriptor* extendee = file->extension(0)->containing_type(); + EXPECT_EQ("UnknownType", extendee->name()); + ASSERT_EQ(1, extendee->extension_range_count()); + EXPECT_EQ(1, extendee->extension_range(0)->start); + EXPECT_EQ(FieldDescriptor::kMaxNumber + 1, extendee->extension_range(0)->end); +} + +TEST_F(AllowUnknownDependenciesTest, CustomOption) { + // Test that we can use a custom option without having parsed + // descriptor.proto. + + FileDescriptorProto option_proto; + + ASSERT_TRUE(TextFormat::ParseFromString( + "name: \"unknown_custom_options.proto\" " + "dependency: \"google/protobuf/descriptor.proto\" " + "extension { " + " extendee: \"google.protobuf.FileOptions\" " + " name: \"some_option\" " + " number: 123456 " + " label: LABEL_OPTIONAL " + " type: TYPE_INT32 " + "} " + "options { " + " uninterpreted_option { " + " name { " + " name_part: \"some_option\" " + " is_extension: true " + " } " + " positive_int_value: 1234 " + " } " + " uninterpreted_option { " + " name { " + " name_part: \"unknown_option\" " + " is_extension: true " + " } " + " positive_int_value: 1234 " + " } " + " uninterpreted_option { " + " name { " + " name_part: \"optimize_for\" " + " is_extension: false " + " } " + " identifier_value: \"SPEED\" " + " } " + "}", + &option_proto)); + + const FileDescriptor* file = pool_.BuildFile(option_proto); + ASSERT_TRUE(file != NULL); + + // Verify that no extension options were set, but they were left as + // uninterpreted_options. + vector fields; + file->options().GetReflection()->ListFields(file->options(), &fields); + ASSERT_EQ(2, fields.size()); + EXPECT_TRUE(file->options().has_optimize_for()); + EXPECT_EQ(2, file->options().uninterpreted_option_size()); +} + +// =================================================================== + TEST(CustomOptions, OptionLocations) { const Descriptor* message = protobuf_unittest::TestMessageWithCustomOptions::descriptor(); @@ -2108,7 +2343,10 @@ TEST_F(ValidationErrorTest, DupeFile) { // defined. BuildFileWithErrors( "name: \"foo.proto\" " - "message_type { name: \"Foo\" }", + "message_type { name: \"Foo\" } " + // Add another type so that the files aren't identical (in which case there + // would be no error). + "enum_type { name: \"Bar\" }", "foo.proto: foo.proto: OTHER: A file with this name is already in the " "pool.\n"); @@ -2174,6 +2412,10 @@ TEST_F(ValidationErrorTest, InvalidDefaults) { // we look up the type name. " field { name: \"quux\" number: 5 label: LABEL_OPTIONAL" " default_value: \"abc\" type_name: \"Foo\" }" + + // Repeateds can't have defaults. + " field { name: \"corge\" number: 6 label: LABEL_REPEATED type: TYPE_INT32" + " default_value: \"1\" }" "}", "foo.proto: Foo.foo: DEFAULT_VALUE: Couldn't parse default value.\n" @@ -2181,6 +2423,10 @@ TEST_F(ValidationErrorTest, InvalidDefaults) { "foo.proto: Foo.baz: DEFAULT_VALUE: Boolean default must be true or " "false.\n" "foo.proto: Foo.qux: DEFAULT_VALUE: Messages can't have default values.\n" + "foo.proto: Foo.corge: DEFAULT_VALUE: Repeated fields can't have default " + "values.\n" + // This ends up being reported later because the error is detected at + // cross-linking time. "foo.proto: Foo.quux: DEFAULT_VALUE: Messages can't have default " "values.\n"); } @@ -2473,6 +2719,24 @@ TEST_F(ValidationErrorTest, SearchMostLocalFirst) { "foo.proto: Foo.baz: TYPE: \"Bar.Baz\" is not defined.\n"); } +TEST_F(ValidationErrorTest, SearchMostLocalFirst2) { + // This test would find the most local "Bar" first, and does, but + // proceeds to find the outer one because the inner one's not an + // aggregate. + BuildFile( + "name: \"foo.proto\" " + "message_type {" + " name: \"Bar\"" + " nested_type { name: \"Baz\" }" + "}" + "message_type {" + " name: \"Foo\"" + " field { name: \"Bar\" number:1 type:TYPE_BYTES } " + " field { name:\"baz\" number:2 label:LABEL_OPTIONAL" + " type_name:\"Bar.Baz\" }" + "}"); +} + TEST_F(ValidationErrorTest, PackageOriginallyDeclaredInTransitiveDependent) { // Imagine we have the following: // @@ -2519,11 +2783,39 @@ TEST_F(ValidationErrorTest, FieldTypeNotAType) { "name: \"foo.proto\" " "message_type {" " name: \"Foo\"" - " field { name:\"foo\" number:1 label:LABEL_OPTIONAL type_name:\"bar\" }" + " field { name:\"foo\" number:1 label:LABEL_OPTIONAL " + " type_name:\".Foo.bar\" }" " field { name:\"bar\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" "}", - "foo.proto: Foo.foo: TYPE: \"bar\" is not a type.\n"); + "foo.proto: Foo.foo: TYPE: \".Foo.bar\" is not a type.\n"); +} + +TEST_F(ValidationErrorTest, RelativeFieldTypeNotAType) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "message_type {" + " nested_type {" + " name: \"Bar\"" + " field { name:\"Baz\" number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " }" + " name: \"Foo\"" + " field { name:\"foo\" number:1 label:LABEL_OPTIONAL " + " type_name:\"Bar.Baz\" }" + "}", + "foo.proto: Foo.foo: TYPE: \"Bar.Baz\" is not a type.\n"); +} + +TEST_F(ValidationErrorTest, FieldTypeMayBeItsName) { + BuildFile( + "name: \"foo.proto\" " + "message_type {" + " name: \"Bar\"" + "}" + "message_type {" + " name: \"Foo\"" + " field { name:\"Bar\" number:1 label:LABEL_OPTIONAL type_name:\"Bar\" }" + "}"); } TEST_F(ValidationErrorTest, EnumFieldTypeIsMessage) { @@ -3346,6 +3638,21 @@ TEST_F(DatabaseBackedPoolTest, FindExtensionByNumber) { EXPECT_TRUE(pool.FindExtensionByNumber(foo, 12) == NULL); } +TEST_F(DatabaseBackedPoolTest, FindAllExtensions) { + DescriptorPool pool(&database_); + + const Descriptor* foo = pool.FindMessageTypeByName("Foo"); + + for (int i = 0; i < 2; ++i) { + // Repeat the lookup twice, to check that we get consistent + // results despite the fallback database lookup mutating the pool. + vector extensions; + pool.FindAllExtensions(foo, &extensions); + ASSERT_EQ(1, extensions.size()); + EXPECT_EQ(5, extensions[0]->number()); + } +} + TEST_F(DatabaseBackedPoolTest, ErrorWithoutErrorCollector) { ErrorDescriptorDatabase error_database; DescriptorPool pool(&error_database); diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index b969c13b..be8235e7 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -229,8 +229,7 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info) new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet; if (type_info_->extensions_offset != -1) { - new(OffsetToPointer(type_info_->extensions_offset)) - ExtensionSet(&type_info_->type, type_info_->pool, type_info_->factory); + new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet; } for (int i = 0; i < descriptor->field_count(); i++) { @@ -508,6 +507,7 @@ const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) { type_info->unknown_fields_offset, type_info->extensions_offset, type_info->pool, + this, type_info->size)); // Cross link prototypes. diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index f431cedc..0e618902 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -33,68 +33,108 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include +#include #include #include #include #include #include -#include +#include +#include #include #include +#include namespace google { namespace protobuf { namespace internal { -// ------------------------------------------------------------------- -// Lookup functions - -const FieldDescriptor* -ExtensionSet::FindKnownExtensionOrDie(int number) const { - const FieldDescriptor* descriptor = - descriptor_pool_->FindExtensionByNumber(*extendee_, number); - if (descriptor == NULL) { - // This extension doesn't exist, so we have to crash. However, let's - // try to provide an informative error message. - if (descriptor_pool_ == DescriptorPool::generated_pool() && - message_factory_ == MessageFactory::generated_factory()) { - // This is probably the ExtensionSet for a generated class. - GOOGLE_LOG(FATAL) << ": No extension is registered for \"" - << (*extendee_)->full_name() << "\" with number " - << number << ". Perhaps you were trying to access it via " - "the Reflection interface, but you provided a " - "FieldDescriptor which did not come from a linked-in " - "message type? This is not permitted; linkin-in message " - "types cannot use non-linked-in extensions. Try " - "converting to a DynamicMessage first."; - } else { - // This is probably a DynamicMessage. - GOOGLE_LOG(FATAL) << ": No extension is registered for \"" - << (*extendee_)->full_name() << "\" with number " - << number << ". If you were using a DynamicMessage, " - "remember that you are only allowed to access extensions " - "which are defined in the DescriptorPool which you passed " - "to DynamicMessageFactory's constructor."; - } +namespace { + +inline FieldDescriptor::Type real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); + return static_cast(type); +} + +inline FieldDescriptor::CppType cpp_type(FieldType type) { + return FieldDescriptor::TypeToCppType(real_type(type)); +} + +// Registry stuff. +struct ExtensionInfo { + inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) + : type(type), is_repeated(is_repeated), is_packed(is_packed) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + union { + ExtensionSet::EnumValidityFunc* enum_is_valid; + const Message* message_prototype; + }; +}; + +typedef hash_map, ExtensionInfo> ExtensionRegistry; +ExtensionRegistry* registry_ = NULL; + +// This function is only called at startup, so there is no need for thread- +// safety. +void Register(const Message* containing_type, int number, ExtensionInfo info) { + if (registry_ == NULL) registry_ = new ExtensionRegistry; + + if (!InsertIfNotPresent(registry_, make_pair(containing_type, number), + info)) { + GOOGLE_LOG(FATAL) << "Multiple extension registrations for type \"" + << containing_type->GetDescriptor()->full_name() + << "\", field number " << number << "."; } - return descriptor; } -const Message* -ExtensionSet::GetPrototype(const Descriptor* message_type) const { - return message_factory_->GetPrototype(message_type); +const ExtensionInfo* FindRegisteredExtension( + const Message* containing_type, int number) { + return (registry_ == NULL) ? NULL : + FindOrNull(*registry_, make_pair(containing_type, number)); +} + +} // namespace + +void ExtensionSet::RegisterExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed) { + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_ENUM); + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_MESSAGE); + GOOGLE_CHECK_NE(type, FieldDescriptor::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + Register(containing_type, number, info); +} + +void ExtensionSet::RegisterEnumExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid) { + GOOGLE_CHECK_EQ(type, FieldDescriptor::TYPE_ENUM); + ExtensionInfo info(type, is_repeated, is_packed); + info.enum_is_valid = is_valid; + Register(containing_type, number, info); +} + +void ExtensionSet::RegisterMessageExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const Message* prototype) { + GOOGLE_CHECK(type == FieldDescriptor::TYPE_MESSAGE || + type == FieldDescriptor::TYPE_GROUP); + ExtensionInfo info(type, is_repeated, is_packed); + info.message_prototype = prototype; + Register(containing_type, number, info); } // =================================================================== // Constructors and basic methods. -ExtensionSet::ExtensionSet(const Descriptor* const* extendee, - const DescriptorPool* pool, - MessageFactory* factory) - : extendee_(extendee), - descriptor_pool_(pool), - message_factory_(factory) { -} +ExtensionSet::ExtensionSet() {} ExtensionSet::~ExtensionSet() { for (map::iterator iter = extensions_.begin(); @@ -103,18 +143,21 @@ ExtensionSet::~ExtensionSet() { } } -void ExtensionSet::AppendToList(vector* output) const { +void ExtensionSet::AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const { for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { bool has = false; - if (iter->second.descriptor->is_repeated()) { + if (iter->second.is_repeated) { has = iter->second.GetSize() > 0; } else { has = !iter->second.is_cleared; } if (has) { - output->push_back(iter->second.descriptor); + output->push_back( + pool->FindExtensionByNumber(containing_type, iter->first)); } } } @@ -122,7 +165,7 @@ void ExtensionSet::AppendToList(vector* output) const { bool ExtensionSet::Has(int number) const { map::const_iterator iter = extensions_.find(number); if (iter == extensions_.end()) return false; - GOOGLE_DCHECK(!iter->second.descriptor->is_repeated()); + GOOGLE_DCHECK(!iter->second.is_repeated); return !iter->second.is_cleared; } @@ -141,47 +184,46 @@ void ExtensionSet::ClearExtension(int number) { // =================================================================== // Field accessors -#define GOOGLE_DCHECK_TYPE(DESCRIPTOR, LABEL, CPPTYPE) \ - GOOGLE_DCHECK_EQ(DESCRIPTOR->label(), FieldDescriptor::LABEL_##LABEL); \ - GOOGLE_DCHECK_EQ(DESCRIPTOR->cpp_type(), FieldDescriptor::CPPTYPE_##CPPTYPE) +#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \ + GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \ + : FieldDescriptor::LABEL_OPTIONAL, \ + FieldDescriptor::LABEL_##LABEL); \ + GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE) // ------------------------------------------------------------------- // Primitives #define PRIMITIVE_ACCESSORS(UPPERCASE, LOWERCASE, CAMELCASE) \ \ -LOWERCASE ExtensionSet::Get##CAMELCASE(int number) const { \ +LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ + LOWERCASE default_value) const { \ map::const_iterator iter = extensions_.find(number); \ - if (iter == extensions_.end()) { \ - /* Not present. Return the default value. */ \ - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \ - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \ - return descriptor->default_value_##LOWERCASE(); \ + if (iter == extensions_.end() || iter->second.is_cleared) { \ + return default_value; \ } else { \ - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, UPPERCASE); \ return iter->second.LOWERCASE##_value; \ } \ } \ \ -void ExtensionSet::Set##CAMELCASE(int number, LOWERCASE value) { \ - Extension* extension = &extensions_[number]; \ - if (extension->descriptor == NULL) { \ - /* Not previoulsy present. Initialize it. */ \ - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \ - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, UPPERCASE); \ - extension->descriptor = descriptor; \ - extension->LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \ +void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ + LOWERCASE value) { \ + Extension* extension; \ + if (MaybeNewExtension(number, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_##UPPERCASE);\ + extension->is_repeated = false; \ } else { \ - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, UPPERCASE); \ - extension->is_cleared = false; \ + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, UPPERCASE); \ } \ + extension->is_cleared = false; \ extension->LOWERCASE##_value = value; \ } \ \ LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const { \ map::const_iterator iter = extensions_.find(number); \ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \ - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \ return iter->second.repeated_##LOWERCASE##_value->Get(index); \ } \ \ @@ -189,20 +231,22 @@ void ExtensionSet::SetRepeated##CAMELCASE( \ int number, int index, LOWERCASE value) { \ map::iterator iter = extensions_.find(number); \ GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \ - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE); \ iter->second.repeated_##LOWERCASE##_value->Set(index, value); \ } \ \ -void ExtensionSet::Add##CAMELCASE(int number, LOWERCASE value) { \ - Extension* extension = &extensions_[number]; \ - if (extension->descriptor == NULL) { \ - /* Not previoulsy present. Initialize it. */ \ - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); \ - GOOGLE_DCHECK_TYPE(descriptor, REPEATED, UPPERCASE); \ +void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ + bool packed, LOWERCASE value) { \ + Extension* extension; \ + if (MaybeNewExtension(number, &extension)) { \ + extension->type = type; \ + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_##UPPERCASE);\ + extension->is_repeated = true; \ + extension->is_packed = packed; \ extension->repeated_##LOWERCASE##_value = new RepeatedField(); \ - extension->descriptor = descriptor; \ } else { \ - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_TYPE(*extension, REPEATED, UPPERCASE); \ + GOOGLE_DCHECK_EQ(extension->is_packed, packed); \ } \ extension->repeated_##LOWERCASE##_value->Add(value); \ } @@ -220,121 +264,113 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool) // ------------------------------------------------------------------- // Enums -int ExtensionSet::GetEnum(int number) const { +int ExtensionSet::GetEnum(int number, int default_value) const { map::const_iterator iter = extensions_.find(number); - if (iter == extensions_.end()) { + if (iter == extensions_.end() || iter->second.is_cleared) { // Not present. Return the default value. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM); - return descriptor->default_value_enum()->number(); + return default_value; } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, ENUM); + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, ENUM); return iter->second.enum_value; } } -void ExtensionSet::SetEnum(int number, int value) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, ENUM); - extension->descriptor = descriptor; - extension->enum_value = descriptor->default_value_enum()->number(); +void ExtensionSet::SetEnum(int number, FieldType type, int value) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_ENUM); + extension->is_repeated = false; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, ENUM); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, ENUM); } - GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL); + extension->is_cleared = false; extension->enum_value = value; } int ExtensionSet::GetRepeatedEnum(int number, int index) const { map::const_iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM); return iter->second.repeated_enum_value->Get(index); } void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { map::iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, ENUM); - GOOGLE_DCHECK(iter->second.descriptor->enum_type() - ->FindValueByNumber(value) != NULL); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM); iter->second.repeated_enum_value->Set(index, value); } -void ExtensionSet::AddEnum(int number, int value) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, REPEATED, ENUM); +void ExtensionSet::AddEnum(int number, FieldType type, + bool packed, int value) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_ENUM); + extension->is_repeated = true; + extension->is_packed = packed; extension->repeated_enum_value = new RepeatedField(); - extension->descriptor = descriptor; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, ENUM); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, ENUM); + GOOGLE_DCHECK_EQ(extension->is_packed, packed); } - GOOGLE_DCHECK(extension->descriptor->enum_type()->FindValueByNumber(value) != NULL); extension->repeated_enum_value->Add(value); } // ------------------------------------------------------------------- // Strings -const string& ExtensionSet::GetString(int number) const { +const string& ExtensionSet::GetString(int number, + const string& default_value) const { map::const_iterator iter = extensions_.find(number); - if (iter == extensions_.end()) { + if (iter == extensions_.end() || iter->second.is_cleared) { // Not present. Return the default value. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING); - return descriptor->default_value_string(); + return default_value; } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, STRING); + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, STRING); return *iter->second.string_value; } } -string* ExtensionSet::MutableString(int number) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, STRING); - extension->descriptor = descriptor; +string* ExtensionSet::MutableString(int number, FieldType type) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_STRING); + extension->is_repeated = false; extension->string_value = new string; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, STRING); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, STRING); } + extension->is_cleared = false; return extension->string_value; } const string& ExtensionSet::GetRepeatedString(int number, int index) const { map::const_iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING); return iter->second.repeated_string_value->Get(index); } string* ExtensionSet::MutableRepeatedString(int number, int index) { map::iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, STRING); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING); return iter->second.repeated_string_value->Mutable(index); } -string* ExtensionSet::AddString(int number) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, REPEATED, STRING); +string* ExtensionSet::AddString(int number, FieldType type) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_STRING); + extension->is_repeated = true; + extension->is_packed = false; extension->repeated_string_value = new RepeatedPtrField(); - extension->descriptor = descriptor; } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, STRING); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, STRING); } return extension->repeated_string_value->Add(); } @@ -342,59 +378,108 @@ string* ExtensionSet::AddString(int number) { // ------------------------------------------------------------------- // Messages -const Message& ExtensionSet::GetMessage(int number) const { +const Message& ExtensionSet::GetMessage(int number, + const Message& default_value) const { map::const_iterator iter = extensions_.find(number); if (iter == extensions_.end()) { // Not present. Return the default value. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE); - return *GetPrototype(descriptor->message_type()); + return default_value; + } else { + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); + return *iter->second.message_value; + } +} + +const Message& ExtensionSet::GetMessage(int number, + const Descriptor* message_type, + MessageFactory* factory) const { + map::const_iterator iter = extensions_.find(number); + if (iter == extensions_.end() || iter->second.is_cleared) { + // Not present. Return the default value. + return *factory->GetPrototype(message_type); } else { - GOOGLE_DCHECK_TYPE(iter->second.descriptor, OPTIONAL, MESSAGE); + GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE); return *iter->second.message_value; } } -Message* ExtensionSet::MutableMessage(int number) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, OPTIONAL, MESSAGE); - extension->descriptor = descriptor; - extension->message_value = GetPrototype(descriptor->message_type())->New(); +Message* ExtensionSet::MutableMessage(int number, FieldType type, + const Message& prototype) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->message_value = prototype.New(); } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, OPTIONAL, MESSAGE); - extension->is_cleared = false; + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); } + extension->is_cleared = false; + return extension->message_value; +} + +Message* ExtensionSet::MutableMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = false; + extension->is_packed = false; + const Message* prototype = factory->GetPrototype(message_type); + GOOGLE_CHECK(prototype != NULL); + extension->message_value = prototype->New(); + } else { + GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE); + } + extension->is_cleared = false; return extension->message_value; } const Message& ExtensionSet::GetRepeatedMessage(int number, int index) const { map::const_iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE); return iter->second.repeated_message_value->Get(index); } Message* ExtensionSet::MutableRepeatedMessage(int number, int index) { map::iterator iter = extensions_.find(number); GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; - GOOGLE_DCHECK_TYPE(iter->second.descriptor, REPEATED, MESSAGE); + GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE); return iter->second.repeated_message_value->Mutable(index); } -Message* ExtensionSet::AddMessage(int number) { - Extension* extension = &extensions_[number]; - if (extension->descriptor == NULL) { - // Not previoulsy present. Initialize it. - const FieldDescriptor* descriptor = FindKnownExtensionOrDie(number); - GOOGLE_DCHECK_TYPE(descriptor, REPEATED, MESSAGE); +Message* ExtensionSet::AddMessage(int number, FieldType type, + const Message& prototype) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = true; + extension->repeated_message_value = + new RepeatedPtrField(&prototype); + } else { + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); + } + return extension->repeated_message_value->Add(); +} + +Message* ExtensionSet::AddMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory) { + Extension* extension; + if (MaybeNewExtension(number, &extension)) { + extension->type = type; + GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); + extension->is_repeated = true; + const Message* prototype = factory->GetPrototype(message_type); + GOOGLE_CHECK(prototype != NULL); extension->repeated_message_value = - new RepeatedPtrField(GetPrototype(descriptor->message_type())); - extension->descriptor = descriptor; + new RepeatedPtrField(prototype); } else { - GOOGLE_DCHECK_TYPE(extension->descriptor, REPEATED, MESSAGE); + GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } return extension->repeated_message_value->Add(); } @@ -410,59 +495,32 @@ void ExtensionSet::Clear() { } } -namespace { - -// A helper function for merging RepeatedFields... -// TODO(kenton): Implement this as a method of RepeatedField? Make generated -// MergeFrom methods use it? - -template -void MergeRepeatedFields(const RepeatedField& source, - RepeatedField* destination) { - destination->Reserve(destination->size() + source.size()); - for (int i = 0; i < source.size(); i++) { - destination->Add(source.Get(i)); - } -} - -void MergeRepeatedFields(const RepeatedPtrField& source, - RepeatedPtrField* destination) { - destination->Reserve(destination->size() + source.size()); - for (int i = 0; i < source.size(); i++) { - destination->Add()->assign(source.Get(i)); - } -} - -void MergeRepeatedFields(const RepeatedPtrField& source, - RepeatedPtrField* destination) { - destination->Reserve(destination->size() + source.size()); - for (int i = 0; i < source.size(); i++) { - destination->Add()->MergeFrom(source.Get(i)); - } -} - -} // namespace - void ExtensionSet::MergeFrom(const ExtensionSet& other) { - GOOGLE_DCHECK_EQ(*extendee_, *other.extendee_); - for (map::const_iterator iter = other.extensions_.begin(); iter != other.extensions_.end(); ++iter) { - const FieldDescriptor* field = iter->second.descriptor; - if (field->is_repeated()) { - const Extension& other_extension = iter->second; - Extension* extension = &extensions_[iter->first]; - switch (field->cpp_type()) { + const Extension& other_extension = iter->second; + + if (other_extension.is_repeated) { + Extension* extension; + bool is_new = MaybeNewExtension(iter->first, &extension); + if (is_new) { + // Extension did not already exist in set. + extension->type = other_extension.type; + extension->is_repeated = true; + } else { + GOOGLE_DCHECK_EQ(extension->type, other_extension.type); + GOOGLE_DCHECK(extension->is_repeated); + } + + switch (cpp_type(other_extension.type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE, REPEATED_TYPE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ - if (extension->descriptor == NULL) { \ - extension->descriptor = field; \ + if (is_new) { \ extension->repeated_##LOWERCASE##_value = \ new REPEATED_TYPE; \ } \ - MergeRepeatedFields( \ - *other_extension.repeated_##LOWERCASE##_value, \ - extension->repeated_##LOWERCASE##_value); \ + extension->repeated_##LOWERCASE##_value->MergeFrom( \ + *other_extension.repeated_##LOWERCASE##_value); \ break; HANDLE_TYPE( INT32, int32, RepeatedField < int32>); @@ -477,22 +535,21 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_MESSAGE: - if (extension->descriptor == NULL) { - extension->descriptor = field; + if (is_new) { extension->repeated_message_value = new RepeatedPtrField( other_extension.repeated_message_value->prototype()); } - MergeRepeatedFields( - *other_extension.repeated_message_value, - extension->repeated_message_value); + extension->repeated_message_value->MergeFrom( + *other_extension.repeated_message_value); break; } } else { - if (!iter->second.is_cleared) { - switch (field->cpp_type()) { -#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ - case FieldDescriptor::CPPTYPE_##UPPERCASE: \ - Set##CAMELCASE(iter->first, iter->second.LOWERCASE##_value); \ + if (!other_extension.is_cleared) { + switch (cpp_type(other_extension.type)) { +#define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ + Set##CAMELCASE(iter->first, other_extension.type, \ + other_extension.LOWERCASE##_value); \ break; HANDLE_TYPE( INT32, int32, Int32); @@ -505,10 +562,13 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { HANDLE_TYPE( ENUM, enum, Enum); #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - SetString(iter->first, *iter->second.string_value); + SetString(iter->first, other_extension.type, + *other_extension.string_value); break; case FieldDescriptor::CPPTYPE_MESSAGE: - MutableMessage(iter->first)->MergeFrom(*iter->second.message_value); + MutableMessage(iter->first, other_extension.type, + *other_extension.message_value) + ->MergeFrom(*other_extension.message_value); break; } } @@ -518,19 +578,16 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { void ExtensionSet::Swap(ExtensionSet* x) { extensions_.swap(x->extensions_); - std::swap(extendee_, x->extendee_); - std::swap(descriptor_pool_, x->descriptor_pool_); - std::swap(message_factory_, x->message_factory_); } bool ExtensionSet::IsInitialized() const { - // Extensions are never requried. However, we need to check that all + // Extensions are never required. However, we need to check that all // embedded messages are initialized. for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { const Extension& extension = iter->second; - if (extension.descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (extension.descriptor->is_repeated()) { + if (cpp_type(extension.type) == FieldDescriptor::CPPTYPE_MESSAGE) { + if (extension.is_repeated) { for (int i = 0; i < extension.repeated_message_value->size(); i++) { if (!extension.repeated_message_value->Get(i).IsInitialized()) { return false; @@ -548,36 +605,201 @@ bool ExtensionSet::IsInitialized() const { } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - Message* message) { - const FieldDescriptor* field = - message->GetReflection() - ->FindKnownExtensionByNumber(WireFormat::GetTagFieldNumber(tag)); + const Message* containing_type, + UnknownFieldSet* unknown_fields) { + int number = WireFormat::GetTagFieldNumber(tag); + WireFormat::WireType wire_type = WireFormat::GetTagWireType(tag); + + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type, number); + + bool is_unknown; + if (extension == NULL) { + is_unknown = true; + } else if (extension->is_packed) { + is_unknown = (wire_type != WireFormat::WIRETYPE_LENGTH_DELIMITED); + } else { + WireFormat::WireType expected_wire_type = + WireFormat::WireTypeForFieldType(real_type(extension->type)); + is_unknown = (wire_type != expected_wire_type); + } + + if (is_unknown) { + WireFormat::SkipField(input, tag, unknown_fields); + } else if (extension->is_packed) { + uint32 size; + if (!input->ReadVarint32(&size)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(size); + + switch (extension->type) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + while (input->BytesUntilLimit() > 0) { \ + CPP_LOWERCASE value; \ + if (!WireFormat::Read##CAMELCASE(input, &value)) return false; \ + Add##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, \ + true, value); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, Int32, int32); + HANDLE_TYPE( INT64, Int64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, Int32, int32); + HANDLE_TYPE( SINT64, SInt64, Int64, int64); + HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, Float, float); + HANDLE_TYPE( DOUBLE, Double, Double, double); + HANDLE_TYPE( BOOL, Bool, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: + while (input->BytesUntilLimit() > 0) { + int value; + if (!WireFormat::ReadEnum(input, &value)) return false; + if (extension->enum_is_valid(value)) { + AddEnum(number, FieldDescriptor::TYPE_ENUM, true, value); + } + } + break; + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + input->PopLimit(limit); + } else { + switch (extension->type) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: { \ + CPP_LOWERCASE value; \ + if (!WireFormat::Read##CAMELCASE(input, &value)) return false; \ + if (extension->is_repeated) { \ + Add##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, \ + false, value); \ + } else { \ + Set##CPP_CAMELCASE(number, FieldDescriptor::TYPE_##UPPERCASE, value);\ + } \ + } break + + HANDLE_TYPE( INT32, Int32, Int32, int32); + HANDLE_TYPE( INT64, Int64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, Int32, int32); + HANDLE_TYPE( SINT64, SInt64, Int64, int64); + HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, Float, float); + HANDLE_TYPE( DOUBLE, Double, Double, double); + HANDLE_TYPE( BOOL, Bool, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_ENUM: { + int value; + if (!WireFormat::ReadEnum(input, &value)) return false; + + if (!extension->enum_is_valid(value)) { + // Invalid value. Treat as unknown. + if (unknown_fields != NULL) { + unknown_fields->AddVarint(number, value); + } + } else if (extension->is_repeated) { + AddEnum(number, FieldDescriptor::TYPE_ENUM, false, value); + } else { + SetEnum(number, FieldDescriptor::TYPE_ENUM, value); + } + break; + } + + case FieldDescriptor::TYPE_STRING: { + string* value = extension->is_repeated ? + AddString(number, FieldDescriptor::TYPE_STRING) : + MutableString(number, FieldDescriptor::TYPE_STRING); + if (!WireFormat::ReadString(input, value)) return false; + break; + } - return WireFormat::ParseAndMergeField(tag, field, message, input); + case FieldDescriptor::TYPE_BYTES: { + string* value = extension->is_repeated ? + AddString(number, FieldDescriptor::TYPE_STRING) : + MutableString(number, FieldDescriptor::TYPE_STRING); + if (!WireFormat::ReadBytes(input, value)) return false; + break; + } + + case FieldDescriptor::TYPE_GROUP: { + Message* value = extension->is_repeated ? + AddMessage(number, FieldDescriptor::TYPE_GROUP, + *extension->message_prototype) : + MutableMessage(number, FieldDescriptor::TYPE_GROUP, + *extension->message_prototype); + if (!WireFormat::ReadGroup(number, input, value)) return false; + break; + } + + case FieldDescriptor::TYPE_MESSAGE: { + Message* value = extension->is_repeated ? + AddMessage(number, FieldDescriptor::TYPE_MESSAGE, + *extension->message_prototype) : + MutableMessage(number, FieldDescriptor::TYPE_MESSAGE, + *extension->message_prototype); + if (!WireFormat::ReadMessage(input, value)) return false; + break; + } + } + } + + return true; } -bool ExtensionSet::SerializeWithCachedSizes( +void ExtensionSet::SerializeWithCachedSizes( int start_field_number, int end_field_number, - const Message& message, io::CodedOutputStream* output) const { map::const_iterator iter; for (iter = extensions_.lower_bound(start_field_number); iter != extensions_.end() && iter->first < end_field_number; ++iter) { - if (!iter->second.SerializeFieldWithCachedSizes(message, output)) { - return false; - } + iter->second.SerializeFieldWithCachedSizes(iter->first, output); } +} - return true; +uint8* ExtensionSet::SerializeWithCachedSizesToArray( + int start_field_number, int end_field_number, + uint8* target) const { + // For now, just create an array output stream around the target and dispatch + // to SerializeWithCachedSizes(). Give the array output stream kint32max + // bytes; we will certainly write less than that. It is up to the caller to + // ensure that the buffer has sufficient space. + int written_bytes; + { + io::ArrayOutputStream array_stream(target, kint32max); + io::CodedOutputStream output_stream(&array_stream); + SerializeWithCachedSizes(start_field_number, + end_field_number, + &output_stream); + written_bytes = output_stream.ByteCount(); + GOOGLE_DCHECK(!output_stream.HadError()); + } + return target + written_bytes; } -int ExtensionSet::ByteSize(const Message& message) const { +int ExtensionSet::ByteSize() const { int total_size = 0; for (map::const_iterator iter = extensions_.begin(); iter != extensions_.end(); ++iter) { - total_size += iter->second.ByteSize(message); + total_size += iter->second.ByteSize(iter->first); } return total_size; @@ -595,12 +817,19 @@ int ExtensionSet::SpaceUsedExcludingSelf() const { return total_size; } +bool ExtensionSet::MaybeNewExtension(int number, Extension** result) { + pair::iterator, bool> insert_result = + extensions_.insert(make_pair(number, Extension())); + *result = &insert_result.first->second; + return insert_result.second; +} + // =================================================================== // Methods of ExtensionSet::Extension void ExtensionSet::Extension::Clear() { - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ repeated_##LOWERCASE##_value->Clear(); \ @@ -620,33 +849,18 @@ void ExtensionSet::Extension::Clear() { } } else { if (!is_cleared) { - switch (descriptor->cpp_type()) { -#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ - case FieldDescriptor::CPPTYPE_##UPPERCASE: \ - LOWERCASE##_value = descriptor->default_value_##LOWERCASE(); \ - break - - HANDLE_TYPE( INT32, int32); - HANDLE_TYPE( INT64, int64); - HANDLE_TYPE(UINT32, uint32); - HANDLE_TYPE(UINT64, uint64); - HANDLE_TYPE( FLOAT, float); - HANDLE_TYPE(DOUBLE, double); - HANDLE_TYPE( BOOL, bool); -#undef HANDLE_TYPE - case FieldDescriptor::CPPTYPE_ENUM: - enum_value = descriptor->default_value_enum()->number(); - break; + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: - if (descriptor->has_default_value()) { - string_value->assign(descriptor->default_value_string()); - } else { - string_value->clear(); - } + string_value->clear(); break; case FieldDescriptor::CPPTYPE_MESSAGE: message_value->Clear(); break; + default: + // No need to do anything. Get*() will return the default value + // as long as is_cleared is true and Set*() will overwrite the + // previous value. + break; } is_cleared = true; @@ -654,29 +868,247 @@ void ExtensionSet::Extension::Clear() { } } -bool ExtensionSet::Extension::SerializeFieldWithCachedSizes( - const Message& message, +void ExtensionSet::Extension::SerializeFieldWithCachedSizes( + int number, io::CodedOutputStream* output) const { - if (descriptor->is_repeated() || !is_cleared) { - return WireFormat::SerializeFieldWithCachedSizes( - descriptor, message, output); - } else { - return true; + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return; + + WireFormat::WriteTag(number, WireFormat::WIRETYPE_LENGTH_DELIMITED, + output); + output->WriteVarint32(cached_size); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormat::Write##CAMELCASE##NoTag( \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + WireFormat::Write##CAMELCASE(number, \ + repeated_##LOWERCASE##_value->Get(i), output); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + WireFormat::Write##CAMELCASE(number, VALUE, output); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } } } -int64 ExtensionSet::Extension::ByteSize(const Message& message) const { - if (descriptor->is_repeated() || !is_cleared) { - return WireFormat::FieldByteSize(descriptor, message); - } else { - // Cleared, non-repeated field. - return 0; +int ExtensionSet::Extension::ByteSize(int number) const { + int result = 0; + + if (is_repeated) { + if (is_packed) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormat::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::k##CAMELCASE##Size * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + + cached_size = result; + if (result > 0) { + result += io::CodedOutputStream::VarintSize32(result); + result += io::CodedOutputStream::VarintSize32( + WireFormat::MakeTag(number, WireFormat::WIRETYPE_LENGTH_DELIMITED)); + } + } else { + int tag_size = WireFormat::TagSize(number, real_type(type)); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += tag_size * repeated_##LOWERCASE##_value->size(); \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + result += WireFormat::CAMELCASE##Size( \ + repeated_##LOWERCASE##_value->Get(i)); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += (tag_size + WireFormat::k##CAMELCASE##Size) * \ + repeated_##LOWERCASE##_value->size(); \ + break + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + result += WireFormat::TagSize(number, real_type(type)); + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::CAMELCASE##Size(LOWERCASE); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + + // Stuff with fixed size. +#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + result += WireFormat::k##CAMELCASE##Size; \ + break + HANDLE_TYPE( FIXED32, Fixed32); + HANDLE_TYPE( FIXED64, Fixed64); + HANDLE_TYPE(SFIXED32, SFixed32); + HANDLE_TYPE(SFIXED64, SFixed64); + HANDLE_TYPE( FLOAT, Float); + HANDLE_TYPE( DOUBLE, Double); + HANDLE_TYPE( BOOL, Bool); +#undef HANDLE_TYPE + } } + + return result; } int ExtensionSet::Extension::GetSize() const { - GOOGLE_DCHECK(descriptor->is_repeated()); - switch (descriptor->cpp_type()) { + GOOGLE_DCHECK(is_repeated); + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ return repeated_##LOWERCASE##_value->size() @@ -699,8 +1131,8 @@ int ExtensionSet::Extension::GetSize() const { } void ExtensionSet::Extension::Free() { - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ delete repeated_##LOWERCASE##_value; \ @@ -719,7 +1151,7 @@ void ExtensionSet::Extension::Free() { #undef HANDLE_TYPE } } else { - switch (descriptor->cpp_type()) { + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: delete string_value; break; @@ -734,8 +1166,8 @@ void ExtensionSet::Extension::Free() { int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { int total_size = 0; - if (descriptor->is_repeated()) { - switch (descriptor->cpp_type()) { + if (is_repeated) { + switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ @@ -754,7 +1186,7 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { HANDLE_TYPE(MESSAGE, message); } } else { - switch (descriptor->cpp_type()) { + switch (cpp_type(type)) { case FieldDescriptor::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index 9ad241f2..8e64b9bd 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -44,6 +44,7 @@ #include #include +#include #include namespace google { @@ -53,6 +54,7 @@ namespace protobuf { class DescriptorPool; // descriptor.h class Message; // message.h class MessageFactory; // message.h + class UnknownFieldSet; // unknown_field_set.h namespace io { class CodedInputStream; // coded_stream.h class CodedOutputStream; // coded_stream.h @@ -64,6 +66,12 @@ namespace protobuf { namespace protobuf { namespace internal { +// Used to store values of type FieldDescriptor::Type without having to +// #include descriptor.h. Also, ensures that we use only one byte to store +// these values, which is important to keep the layout of +// ExtensionSet::Extension small. +typedef uint8 FieldType; + // This is an internal helper class intended for use within the protocol buffer // library and generated classes. Clients should not use it directly. Instead, // use the generated accessors such as GetExtension() of the class being @@ -77,30 +85,42 @@ namespace internal { // off to the ExtensionSet for parsing. Etc. class LIBPROTOBUF_EXPORT ExtensionSet { public: - // Construct an ExtensionSet. - // extendee: Descriptor for the type being extended. We pass in a pointer - // to a pointer to the extendee to get around an initialization - // problem: when we create the ExtensionSet for a message type, - // its descriptor may not exist yet. But we know where that - // descriptor pointer will be placed, and by the time it's used - // by this ExtensionSet it will be fully initialized, so passing - // a pointer to that location works. Note that this problem - // will only occur for messages defined in descriptor.proto. - // pool: DescriptorPool to search for extension definitions. - // factory: MessageFactory used to construct implementations of messages - // for extensions with message type. This factory must be able - // to construct any message type found in "pool". - // All three objects remain property of the caller and must outlive the - // ExtensionSet. - ExtensionSet(const Descriptor* const* extendee, - const DescriptorPool* pool, - MessageFactory* factory); - + ExtensionSet(); ~ExtensionSet(); + // A function which, given an integer value, returns true if the number + // matches one of the defined values for the corresponding enum type. This + // is used with RegisterEnumExtension, below. + typedef bool EnumValidityFunc(int number); + + // These are called at startup by protocol-compiler-generated code to + // register known extensions. The registrations are used by ParseField() + // to look up extensions for parsed field numbers. Note that dynamic parsing + // does not use ParseField(); only protocol-compiler-generated parsing + // methods do. + static void RegisterExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed); + static void RegisterEnumExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + EnumValidityFunc* is_valid); + static void RegisterMessageExtension(const Message* containing_type, + int number, FieldType type, + bool is_repeated, bool is_packed, + const Message* prototype); + + // ================================================================= + // Add all fields which are currently present to the given vector. This - // is useful to implement Reflection::ListFields(). - void AppendToList(vector* output) const; + // is useful to implement Reflection::ListFields(). The FieldDescriptors + // are looked up by number from the given pool. + // + // TODO(kenton): Looking up each field by number is somewhat unfortunate. + // Is there a better way? + void AppendToList(const Descriptor* containing_type, + const DescriptorPool* pool, + vector* output) const; // ================================================================= // Accessors @@ -138,28 +158,34 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // singular fields ------------------------------------------------- - int32 GetInt32 (int number) const; - int64 GetInt64 (int number) const; - uint32 GetUInt32(int number) const; - uint64 GetUInt64(int number) const; - float GetFloat (int number) const; - double GetDouble(int number) const; - bool GetBool (int number) const; - int GetEnum (int number) const; - const string & GetString (int number) const; - const Message& GetMessage(int number) const; - - void SetInt32 (int number, int32 value); - void SetInt64 (int number, int64 value); - void SetUInt32(int number, uint32 value); - void SetUInt64(int number, uint64 value); - void SetFloat (int number, float value); - void SetDouble(int number, double value); - void SetBool (int number, bool value); - void SetEnum (int number, int value); - void SetString(int number, const string& value); - string * MutableString (int number); - Message* MutableMessage(int number); + int32 GetInt32 (int number, int32 default_value) const; + int64 GetInt64 (int number, int64 default_value) const; + uint32 GetUInt32(int number, uint32 default_value) const; + uint64 GetUInt64(int number, uint64 default_value) const; + float GetFloat (int number, float default_value) const; + double GetDouble(int number, double default_value) const; + bool GetBool (int number, bool default_value) const; + int GetEnum (int number, int default_value) const; + const string & GetString (int number, const string& default_value) const; + const Message& GetMessage(int number, const Message& default_value) const; + const Message& GetMessage(int number, const Descriptor* message_type, + MessageFactory* factory) const; + + void SetInt32 (int number, FieldType type, int32 value); + void SetInt64 (int number, FieldType type, int64 value); + void SetUInt32(int number, FieldType type, uint32 value); + void SetUInt64(int number, FieldType type, uint64 value); + void SetFloat (int number, FieldType type, float value); + void SetDouble(int number, FieldType type, double value); + void SetBool (int number, FieldType type, bool value); + void SetEnum (int number, FieldType type, int value); + void SetString(int number, FieldType type, const string& value); + string * MutableString (int number, FieldType type); + Message* MutableMessage(int number, FieldType type, + const Message& prototype); + Message* MutableMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory); // repeated fields ------------------------------------------------- @@ -186,17 +212,21 @@ class LIBPROTOBUF_EXPORT ExtensionSet { string * MutableRepeatedString (int number, int index); Message* MutableRepeatedMessage(int number, int index); - void AddInt32 (int number, int32 value); - void AddInt64 (int number, int64 value); - void AddUInt32(int number, uint32 value); - void AddUInt64(int number, uint64 value); - void AddFloat (int number, float value); - void AddDouble(int number, double value); - void AddBool (int number, bool value); - void AddEnum (int number, int value); - void AddString(int number, const string& value); - string * AddString (int number); - Message* AddMessage(int number); + void AddInt32 (int number, FieldType type, bool packed, int32 value); + void AddInt64 (int number, FieldType type, bool packed, int64 value); + void AddUInt32(int number, FieldType type, bool packed, uint32 value); + void AddUInt64(int number, FieldType type, bool packed, uint64 value); + void AddFloat (int number, FieldType type, bool packed, float value); + void AddDouble(int number, FieldType type, bool packed, double value); + void AddBool (int number, FieldType type, bool packed, bool value); + void AddEnum (int number, FieldType type, bool packed, int value); + void AddString(int number, FieldType type, const string& value); + string * AddString (int number, FieldType type); + Message* AddMessage(int number, FieldType type, + const Message& prototype); + Message* AddMessage(int number, FieldType type, + const Descriptor* message_type, + MessageFactory* factory); // ----------------------------------------------------------------- // TODO(kenton): Hardcore memory management accessors @@ -212,40 +242,41 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void Swap(ExtensionSet* other); bool IsInitialized() const; - // These parsing and serialization functions all want a pointer to the - // message object because they hand off the actual work to WireFormat, - // which works in terms of a reflection interface. Yes, this means there - // are some redundant virtual function calls that end up being made, but - // it probably doesn't matter much in practice, and the alternative would - // involve reproducing a lot of WireFormat's functionality. - // Parses a single extension from the input. The input should start out - // positioned immediately after the tag. - bool ParseField(uint32 tag, io::CodedInputStream* input, Message* message); + // positioned immediately after the tag. |containing_type| is the default + // instance for the containing message; it is used only to look up the + // extension by number. See RegisterExtension(), above. Unlike the other + // methods of ExtensionSet, this only works for generated message types -- + // it looks up extensions registered using RegisterExtension(). + bool ParseField(uint32 tag, io::CodedInputStream* input, + const Message* containing_type, + UnknownFieldSet* unknown_fields); // Write all extension fields with field numbers in the range // [start_field_number, end_field_number) // to the output stream, using the cached sizes computed when ByteSize() was // last called. Note that the range bounds are inclusive-exclusive. - bool SerializeWithCachedSizes(int start_field_number, + void SerializeWithCachedSizes(int start_field_number, int end_field_number, - const Message& message, io::CodedOutputStream* output) const; + // Same as SerializeWithCachedSizes, but without any bounds checking. + // The caller must ensure that target has sufficient capacity for the + // serialized extensions. + // + // Returns a pointer past the last written byte. + uint8* SerializeWithCachedSizesToArray(int start_field_number, + int end_field_number, + uint8* target) const; + // Returns the total serialized size of all the extensions. - int ByteSize(const Message& message) const; + int ByteSize() const; // Returns (an estimate of) the total number of bytes used for storing the // extensions in memory, excluding sizeof(*this). int SpaceUsedExcludingSelf() const; private: - // Like FindKnownExtension(), but GOOGLE_CHECK-fail if not found. - const FieldDescriptor* FindKnownExtensionOrDie(int number) const; - - // Get the prototype for the message. - const Message* GetPrototype(const Descriptor* message_type) const; - struct Extension { union { int32 int32_value; @@ -271,7 +302,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { RepeatedPtrField* repeated_message_value; }; - const FieldDescriptor* descriptor; + FieldType type; + bool is_repeated; // For singular types, indicates if the extension is "cleared". This // happens when an extension is set and then later cleared by the caller. @@ -281,19 +313,29 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // simply becomes zero when cleared. bool is_cleared; - Extension(): descriptor(NULL), is_cleared(false) {} + // For repeated types, this indicates if the [packed=true] option is set. + bool is_packed; + + // For packed fields, the size of the packed data is recorded here when + // ByteSize() is called then used during serialization. + // TODO(kenton): Use atomic when C++ supports it. + mutable int cached_size; // Some helper methods for operations on a single Extension. - bool SerializeFieldWithCachedSizes( - const Message& message, + void SerializeFieldWithCachedSizes( + int number, io::CodedOutputStream* output) const; - int64 ByteSize(const Message& message) const; + int ByteSize(int number) const; void Clear(); int GetSize() const; void Free(); int SpaceUsedExcludingSelf() const; }; + // Gets the extension with the given number, creating it if it does not + // already exist. Returns true if the extension did not already exist. + bool MaybeNewExtension(int number, Extension** result); + // The Extension struct is small enough to be passed by value, so we use it // directly as the value type in the map rather than use pointers. We use // a map rather than hash_map here because we expect most ExtensionSets will @@ -301,30 +343,26 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // for 100 elements or more. Also, we want AppendToList() to order fields // by field number. map extensions_; - const Descriptor* const* extendee_; - const DescriptorPool* descriptor_pool_; - MessageFactory* message_factory_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet); }; // These are just for convenience... -inline void ExtensionSet::SetString(int number, const string& value) { - MutableString(number)->assign(value); +inline void ExtensionSet::SetString(int number, FieldType type, + const string& value) { + MutableString(number, type)->assign(value); } inline void ExtensionSet::SetRepeatedString(int number, int index, const string& value) { MutableRepeatedString(number, index)->assign(value); } -inline void ExtensionSet::AddString(int number, const string& value) { - AddString(number)->assign(value); +inline void ExtensionSet::AddString(int number, FieldType type, + const string& value) { + AddString(number, type)->assign(value); } // =================================================================== -// Implementation details -// -// DO NOT DEPEND ON ANYTHING BELOW THIS POINT. This is for use from -// generated code only. +// Glue for generated extension accessors // ------------------------------------------------------------------- // Template magic @@ -377,8 +415,10 @@ class PrimitiveTypeTraits { public: typedef Type ConstType; - static inline ConstType Get(int number, const ExtensionSet& set); - static inline void Set(int number, ConstType value, ExtensionSet* set); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set); }; template @@ -388,17 +428,18 @@ class RepeatedPrimitiveTypeTraits { static inline Type Get(int number, const ExtensionSet& set, int index); static inline void Set(int number, int index, Type value, ExtensionSet* set); - static inline void Add(int number, Type value, ExtensionSet* set); + static inline void Add(int number, FieldType field_type, + bool is_packed, Type value, ExtensionSet* set); }; #define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \ template<> inline TYPE PrimitiveTypeTraits::Get( \ - int number, const ExtensionSet& set) { \ - return set.Get##METHOD(number); \ + int number, const ExtensionSet& set, TYPE default_value) { \ + return set.Get##METHOD(number, default_value); \ } \ template<> inline void PrimitiveTypeTraits::Set( \ - int number, ConstType value, ExtensionSet* set) { \ - set->Set##METHOD(number, value); \ + int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ + set->Set##METHOD(number, field_type, value); \ } \ \ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ @@ -406,12 +447,13 @@ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ return set.GetRepeated##METHOD(number, index); \ } \ template<> inline void RepeatedPrimitiveTypeTraits::Set( \ - int number, int index, ConstType value, ExtensionSet* set) { \ + int number, int index, TYPE value, ExtensionSet* set) { \ set->SetRepeated##METHOD(number, index, value); \ } \ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ - int number, ConstType value, ExtensionSet* set) { \ - set->Add##METHOD(number, value); \ + int number, FieldType field_type, bool is_packed, \ + TYPE value, ExtensionSet* set) { \ + set->Add##METHOD(number, field_type, is_packed, value); \ } PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) @@ -433,14 +475,17 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { typedef const string& ConstType; typedef string* MutableType; - static inline const string& Get(int number, const ExtensionSet& set) { - return set.GetString(number); + static inline const string& Get(int number, const ExtensionSet& set, + ConstType default_value) { + return set.GetString(number, default_value); } - static inline void Set(int number, const string& value, ExtensionSet* set) { - set->SetString(number, value); + static inline void Set(int number, FieldType field_type, + const string& value, ExtensionSet* set) { + set->SetString(number, field_type, value); } - static inline string* Mutable(int number, ExtensionSet* set) { - return set->MutableString(number); + static inline string* Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return set->MutableString(number, field_type); } }; @@ -460,11 +505,14 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { static inline string* Mutable(int number, int index, ExtensionSet* set) { return set->MutableRepeatedString(number, index); } - static inline void Add(int number, const string& value, ExtensionSet* set) { - set->AddString(number, value); + static inline void Add(int number, FieldType field_type, + bool is_packed, const string& value, + ExtensionSet* set) { + set->AddString(number, field_type, value); } - static inline string* Add(int number, ExtensionSet* set) { - return set->AddString(number); + static inline string* Add(int number, FieldType field_type, + ExtensionSet* set) { + return set->AddString(number, field_type); } }; @@ -473,20 +521,23 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { // ExtensionSet represents enums using integers internally, so we have to // static_cast around. -template +template class EnumTypeTraits { public: typedef Type ConstType; - static inline ConstType Get(int number, const ExtensionSet& set) { - return static_cast(set.GetEnum(number)); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast(set.GetEnum(number, default_value)); } - static inline void Set(int number, ConstType value, ExtensionSet* set) { - set->SetEnum(number, value); + static inline void Set(int number, FieldType field_type, + ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->SetEnum(number, field_type, value); } }; -template +template class RepeatedEnumTypeTraits { public: typedef Type ConstType; @@ -496,10 +547,13 @@ class RepeatedEnumTypeTraits { } static inline void Set(int number, int index, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); set->SetRepeatedEnum(number, index, value); } - static inline void Add(int number, ConstType value, ExtensionSet* set) { - set->AddEnum(number, value); + static inline void Add(int number, FieldType field_type, + bool is_packed, ConstType value, ExtensionSet* set) { + GOOGLE_DCHECK(IsValid(value)); + set->AddEnum(number, field_type, is_packed, value); } }; @@ -513,13 +567,17 @@ template class MessageTypeTraits { public: typedef const Type& ConstType; - typedef Type* MutableType; + typedef Type* MutableType; - static inline ConstType Get(int number, const ExtensionSet& set) { - return static_cast(set.GetMessage(number)); + static inline ConstType Get(int number, const ExtensionSet& set, + ConstType default_value) { + return static_cast( + set.GetMessage(number, default_value)); } - static inline MutableType Mutable(int number, ExtensionSet* set) { - return static_cast(set->MutableMessage(number)); + static inline MutableType Mutable(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->MutableMessage(number, field_type, Type::default_instance())); } }; @@ -535,8 +593,10 @@ class RepeatedMessageTypeTraits { static inline MutableType Mutable(int number, int index, ExtensionSet* set) { return static_cast(set->MutableRepeatedMessage(number, index)); } - static inline MutableType Add(int number, ExtensionSet* set) { - return static_cast(set->AddMessage(number)); + static inline MutableType Add(int number, FieldType field_type, + ExtensionSet* set) { + return static_cast( + set->AddMessage(number, field_type, Type::default_instance())); } }; @@ -546,7 +606,7 @@ class RepeatedMessageTypeTraits { // This is the type of actual extension objects. E.g. if you have: // extends Foo with optional int32 bar = 1234; // then "bar" will be defined in C++ as: -// ExtensionIdentifier> bar(1234); +// ExtensionIdentifier, 1, false> bar(1234); // // Note that we could, in theory, supply the field number as a template // parameter, and thus make an instance of ExtensionIdentifier have no @@ -557,18 +617,145 @@ class RepeatedMessageTypeTraits { // but that would be bad because it would cause this extension to not be // registered at static initialization, and therefore using it would crash. -template -class ExtensionIdentifier { +template +class LIBPROTOBUF_EXPORT ExtensionIdentifier { public: typedef TypeTraitsType TypeTraits; typedef ExtendeeType Extendee; - ExtensionIdentifier(int number): number_(number) {} + ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value) + : number_(number), default_value_(default_value) {} inline int number() const { return number_; } + typename TypeTraits::ConstType default_value() const { + return default_value_; + } + private: const int number_; + const typename TypeTraits::ConstType default_value_; }; +// ------------------------------------------------------------------- +// Generated accessors + +// This macro should be expanded in the context of a generated type which +// has extensions. +// +// We use "_proto_TypeTraits" as a type name below because "TypeTraits" +// causes problems if the class has a nested message or enum type with that +// name and "_TypeTraits" is technically reserved for the C++ library since +// it starts with an underscore followed by a capital letter. +#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \ + /* Has, Size, Clear */ \ + template \ + inline bool HasExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.Has(id.number()); \ + } \ + \ + template \ + inline void ClearExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + _extensions_.ClearExtension(id.number()); \ + } \ + \ + template \ + inline int ExtensionSize( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _extensions_.ExtensionSize(id.number()); \ + } \ + \ + /* Singular accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, \ + id.default_value()); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \ + } \ + \ + /* Repeated accessors */ \ + template \ + inline typename _proto_TypeTraits::ConstType GetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) const { \ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType MutableExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index) { \ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \ + } \ + \ + template \ + inline void SetExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + int index, typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \ + } \ + \ + template \ + inline typename _proto_TypeTraits::MutableType AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \ + return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \ + } \ + \ + template \ + inline void AddExtension( \ + const ::google::protobuf::internal::ExtensionIdentifier< \ + CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \ + typename _proto_TypeTraits::ConstType value) { \ + _proto_TypeTraits::Add(id.number(), field_type, is_packed, \ + value, &_extensions_); \ + } + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 631bbc43..dfd88318 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -35,10 +35,13 @@ #include #include #include +#include +#include #include #include #include +#include namespace google { namespace protobuf { @@ -102,6 +105,11 @@ TEST(ExtensionSetTest, Clear) { unittest::optional_foreign_message_extension)); EXPECT_NE(&unittest_import::ImportMessage::default_instance(), &message.GetExtension(unittest::optional_import_message_extension)); + + // Make sure setting stuff again after clearing works. (This takes slightly + // different code paths since the objects are reused.) + TestUtil::SetAllExtensions(&message); + TestUtil::ExpectAllExtensionsSet(message); } TEST(ExtensionSetTest, ClearOneField) { @@ -166,28 +174,90 @@ TEST(ExtensionSetTest, SwapWithSelf) { TestUtil::ExpectAllExtensionsSet(message); } -TEST(ExtensionSetTest, Serialization) { +TEST(ExtensionSetTest, SerializationToArray) { // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire // compatibility of extensions. + // + // This checks serialization to a flat array by explicitly reserving space in + // the string and calling the generated message's + // SerializeWithCachedSizesToArray. unittest::TestAllExtensions source; unittest::TestAllTypes destination; + TestUtil::SetAllExtensions(&source); + int size = source.ByteSize(); string data; + data.resize(size); + uint8* target = reinterpret_cast(string_as_array(&data)); + uint8* end = source.SerializeWithCachedSizesToArray(target); + EXPECT_EQ(size, end - target); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectAllFieldsSet(destination); +} +TEST(ExtensionSetTest, SerializationToStream) { + // Serialize as TestAllExtensions and parse as TestAllTypes to insure wire + // compatibility of extensions. + // + // This checks serialization to an output stream by creating an array output + // stream that can only buffer 1 byte at a time - this prevents the message + // from ever jumping to the fast path, ensuring that serialization happens via + // the CodedOutputStream. + unittest::TestAllExtensions source; + unittest::TestAllTypes destination; TestUtil::SetAllExtensions(&source); - source.SerializeToString(&data); + int size = source.ByteSize(); + string data; + data.resize(size); + { + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + source.SerializeWithCachedSizes(&output_stream); + ASSERT_FALSE(output_stream.HadError()); + } EXPECT_TRUE(destination.ParseFromString(data)); TestUtil::ExpectAllFieldsSet(destination); } -TEST(ExtensionSetTest, PackedSerialization) { +TEST(ExtensionSetTest, PackedSerializationToArray) { // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure // wire compatibility of extensions. + // + // This checks serialization to a flat array by explicitly reserving space in + // the string and calling the generated message's + // SerializeWithCachedSizesToArray. unittest::TestPackedExtensions source; unittest::TestPackedTypes destination; + TestUtil::SetPackedExtensions(&source); + int size = source.ByteSize(); string data; + data.resize(size); + uint8* target = reinterpret_cast(string_as_array(&data)); + uint8* end = source.SerializeWithCachedSizesToArray(target); + EXPECT_EQ(size, end - target); + EXPECT_TRUE(destination.ParseFromString(data)); + TestUtil::ExpectPackedFieldsSet(destination); +} +TEST(ExtensionSetTest, PackedSerializationToStream) { + // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure + // wire compatibility of extensions. + // + // This checks serialization to an output stream by creating an array output + // stream that can only buffer 1 byte at a time - this prevents the message + // from ever jumping to the fast path, ensuring that serialization happens via + // the CodedOutputStream. + unittest::TestPackedExtensions source; + unittest::TestPackedTypes destination; TestUtil::SetPackedExtensions(&source); - source.SerializeToString(&data); + int size = source.ByteSize(); + string data; + data.resize(size); + { + io::ArrayOutputStream array_stream(string_as_array(&data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + source.SerializeWithCachedSizes(&output_stream); + ASSERT_FALSE(output_stream.HadError()); + } EXPECT_TRUE(destination.ParseFromString(data)); TestUtil::ExpectPackedFieldsSet(destination); } @@ -395,6 +465,14 @@ TEST(ExtensionSetTest, SpaceUsedExcludingSelf) { } } +TEST(ExtensionSetTest, InvalidEnumDeath) { + unittest::TestAllExtensions message; + EXPECT_DEBUG_DEATH( + message.SetExtension(unittest::optional_foreign_enum_extension, + static_cast(53)), + "IsValid"); +} + } // namespace } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 085af8f9..ffeaf62d 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -58,6 +58,21 @@ int StringSpaceUsedExcludingSelf(const string& str) { } } +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + int* value) { + const EnumValueDescriptor* d = descriptor->FindValueByName(name); + if (d == NULL) return false; + *value = d->number(); + return true; +} + +const string& NameOfEnum(const EnumDescriptor* descriptor, int value) { + static string kEmptyString; + const EnumValueDescriptor* d = descriptor->FindValueByNumber(value); + return (d == NULL ? kEmptyString : d->name()); +} + // =================================================================== // Helpers for reporting usage errors (e.g. trying to use GetInt32() on // a string field). @@ -160,6 +175,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( int unknown_fields_offset, int extensions_offset, const DescriptorPool* descriptor_pool, + MessageFactory* factory, int object_size) : descriptor_ (descriptor), default_instance_ (default_instance), @@ -170,7 +186,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : - descriptor_pool) { + descriptor_pool), + message_factory_ (factory) { } GeneratedMessageReflection::~GeneratedMessageReflection() {} @@ -365,7 +382,8 @@ void GeneratedMessageReflection::ListFields( } if (extensions_offset_ != -1) { - GetExtensionSet(message).AppendToList(output); + GetExtensionSet(message).AppendToList(descriptor_, descriptor_pool_, + output); } // ListFields() must sort output by field number. @@ -380,7 +398,8 @@ void GeneratedMessageReflection::ListFields( const Message& message, const FieldDescriptor* field) const { \ USAGE_CHECK_ALL(Get##TYPENAME, SINGULAR, CPPTYPE); \ if (field->is_extension()) { \ - return GetExtensionSet(message).Get##TYPENAME(field->number()); \ + return GetExtensionSet(message).Get##TYPENAME( \ + field->number(), field->default_value_##PASSTYPE()); \ } else { \ return GetField(message, field); \ } \ @@ -392,7 +411,7 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ if (field->is_extension()) { \ return MutableExtensionSet(message)->Set##TYPENAME( \ - field->number(), value); \ + field->number(), field->type(), value); \ } else { \ SetField(message, field, value); \ } \ @@ -427,7 +446,8 @@ void GeneratedMessageReflection::ListFields( PASSTYPE value) const { \ USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ if (field->is_extension()) { \ - MutableExtensionSet(message)->Add##TYPENAME(field->number(), value); \ + MutableExtensionSet(message)->Add##TYPENAME( \ + field->number(), field->type(), field->options().packed(), value); \ } else { \ AddField(message, field, value); \ } \ @@ -448,7 +468,8 @@ string GeneratedMessageReflection::GetString( const Message& message, const FieldDescriptor* field) const { USAGE_CHECK_ALL(GetString, SINGULAR, STRING); if (field->is_extension()) { - return GetExtensionSet(message).GetString(field->number()); + return GetExtensionSet(message).GetString(field->number(), + field->default_value_string()); } else { return *GetField(message, field); } @@ -459,7 +480,8 @@ const string& GeneratedMessageReflection::GetStringReference( const FieldDescriptor* field, string* scratch) const { USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING); if (field->is_extension()) { - return GetExtensionSet(message).GetString(field->number()); + return GetExtensionSet(message).GetString(field->number(), + field->default_value_string()); } else { return *GetField(message, field); } @@ -471,7 +493,8 @@ void GeneratedMessageReflection::SetString( const string& value) const { USAGE_CHECK_ALL(SetString, SINGULAR, STRING); if (field->is_extension()) { - return MutableExtensionSet(message)->SetString(field->number(), value); + return MutableExtensionSet(message)->SetString(field->number(), + field->type(), value); } else { string** ptr = MutableField(message, field); if (*ptr == DefaultRaw(field)) { @@ -523,7 +546,8 @@ void GeneratedMessageReflection::AddString( const string& value) const { USAGE_CHECK_ALL(AddString, REPEATED, STRING); if (field->is_extension()) { - MutableExtensionSet(message)->AddString(field->number(), value); + MutableExtensionSet(message)->AddString(field->number(), + field->type(), value); } else { AddField(message, field, value); } @@ -538,7 +562,8 @@ const EnumValueDescriptor* GeneratedMessageReflection::GetEnum( int value; if (field->is_extension()) { - value = GetExtensionSet(message).GetEnum(field->number()); + value = GetExtensionSet(message).GetEnum( + field->number(), field->default_value_enum()->number()); } else { value = GetField(message, field); } @@ -555,7 +580,8 @@ void GeneratedMessageReflection::SetEnum( USAGE_CHECK_ENUM_VALUE(SetEnum); if (field->is_extension()) { - MutableExtensionSet(message)->SetEnum(field->number(), value->number()); + MutableExtensionSet(message)->SetEnum(field->number(), field->type(), + value->number()); } else { SetField(message, field, value->number()); } @@ -599,7 +625,9 @@ void GeneratedMessageReflection::AddEnum( USAGE_CHECK_ENUM_VALUE(AddEnum); if (field->is_extension()) { - MutableExtensionSet(message)->AddEnum(field->number(), value->number()); + MutableExtensionSet(message)->AddEnum(field->number(), field->type(), + field->options().packed(), + value->number()); } else { AddField(message, field, value->number()); } @@ -612,7 +640,9 @@ const Message& GeneratedMessageReflection::GetMessage( USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); if (field->is_extension()) { - return GetExtensionSet(message).GetMessage(field->number()); + return GetExtensionSet(message).GetMessage(field->number(), + field->message_type(), + message_factory_); } else { const Message* result = GetRaw(message, field); if (result == NULL) { @@ -627,13 +657,15 @@ Message* GeneratedMessageReflection::MutableMessage( USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); if (field->is_extension()) { - return MutableExtensionSet(message)->MutableMessage(field->number()); + return MutableExtensionSet(message)->MutableMessage(field->number(), + field->type(), + field->message_type(), + message_factory_); } else { Message** result = MutableField(message, field); if (*result == NULL) { const Message* default_message = DefaultRaw(field); *result = default_message->New(); - (*result)->CopyFrom(*default_message); } return *result; } @@ -667,7 +699,10 @@ Message* GeneratedMessageReflection::AddMessage( USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); if (field->is_extension()) { - return MutableExtensionSet(message)->AddMessage(field->number()); + return MutableExtensionSet(message)->AddMessage(field->number(), + field->type(), + field->message_type(), + message_factory_); } else { return AddField(message, field); } diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 34383df8..8f1c9cfc 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -116,6 +116,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { // pool: DescriptorPool to search for extension definitions. Only // used by FindKnownExtensionByName() and // FindKnownExtensionByNumber(). + // factory: MessageFactory to use to construct extension messages. // object_size: The size of a message object of this type, as measured // by sizeof(). GeneratedMessageReflection(const Descriptor* descriptor, @@ -125,6 +126,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int unknown_fields_offset, int extensions_offset, const DescriptorPool* pool, + MessageFactory* factory, int object_size); ~GeneratedMessageReflection(); @@ -274,6 +276,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int object_size_; const DescriptorPool* descriptor_pool_; + MessageFactory* message_factory_; template inline const Type& GetRaw(const Message& message, @@ -383,8 +386,31 @@ inline To dynamic_cast_if_available(From from) { // Compute the space used by a string, not including sizeof(string) itself. // This is slightly complicated because small strings store their data within // the string object but large strings do not. +LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str); int StringSpaceUsedExcludingSelf(const string& str); +// Helper for EnumType_Parse functions: try to parse the string 'name' as an +// enum name of the given type, returning true and filling in value on success, +// or returning false and leaving value unchanged on failure. +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + int* value); + +template +bool ParseNamedEnum(const EnumDescriptor* descriptor, + const string& name, + EnumType* value) { + int tmp; + if (!ParseNamedEnum(descriptor, name, &tmp)) return false; + *value = static_cast(tmp); + return true; +} + +// Just a wrapper around printing the name of a value. The main point of this +// function is not to be inlined, so that you can do this without including +// descriptor.h. +const string& NameOfEnum(const EnumDescriptor* descriptor, int value); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index a0f08571..0a00d2bb 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -71,18 +71,13 @@ CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) buffer_size_(0), total_bytes_read_(0), overflow_bytes_(0), - last_tag_(0), legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(INT_MAX), buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), recursion_limit_(kDefaultRecursionLimit) { } @@ -514,7 +509,14 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output) : output_(output), buffer_(NULL), buffer_size_(0), - total_bytes_(0) { + total_bytes_(0), + had_error_(false) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); + // The Refresh() may have failed. If the client doesn't write any data, + // though, don't consider this an error. If the client does write data, then + // another Refresh() will be attempted and it will set the error once again. + had_error_ = false; } CodedOutputStream::~CodedOutputStream() { @@ -543,21 +545,26 @@ bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) { return true; } -bool CodedOutputStream::WriteRaw(const void* data, int size) { +void CodedOutputStream::WriteRaw(const void* data, int size) { while (buffer_size_ < size) { memcpy(buffer_, data, buffer_size_); size -= buffer_size_; data = reinterpret_cast(data) + buffer_size_; - if (!Refresh()) return false; + if (!Refresh()) return; } memcpy(buffer_, data, size); Advance(size); - return true; +} + +uint8* CodedOutputStream::WriteRawToArray( + const void* data, int size, uint8* target) { + memcpy(target, data, size); + return target + size; } -bool CodedOutputStream::WriteLittleEndian32(uint32 value) { +void CodedOutputStream::WriteLittleEndian32(uint32 value) { uint8 bytes[sizeof(value)]; bool use_fast = buffer_size_ >= sizeof(value); @@ -570,13 +577,21 @@ bool CodedOutputStream::WriteLittleEndian32(uint32 value) { if (use_fast) { Advance(sizeof(value)); - return true; } else { - return WriteRaw(bytes, sizeof(value)); + WriteRaw(bytes, sizeof(value)); } } -bool CodedOutputStream::WriteLittleEndian64(uint64 value) { +uint8* CodedOutputStream::WriteLittleEndian32ToArray( + uint32 value, uint8* target) { + target[0] = static_cast(value ); + target[1] = static_cast(value >> 8); + target[2] = static_cast(value >> 16); + target[3] = static_cast(value >> 24); + return target + sizeof(value); +} + +void CodedOutputStream::WriteLittleEndian64(uint64 value) { uint8 bytes[sizeof(value)]; uint32 part0 = static_cast(value); @@ -596,46 +611,66 @@ bool CodedOutputStream::WriteLittleEndian64(uint64 value) { if (use_fast) { Advance(sizeof(value)); - return true; } else { - return WriteRaw(bytes, sizeof(value)); + WriteRaw(bytes, sizeof(value)); } } -bool CodedOutputStream::WriteVarint32Fallback(uint32 value) { - if (buffer_size_ >= kMaxVarint32Bytes) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this write won't cross the end, so we can skip the checks. - uint8* target = buffer_; +uint8* CodedOutputStream::WriteLittleEndian64ToArray( + uint64 value, uint8* target) { + uint32 part0 = static_cast(value); + uint32 part1 = static_cast(value >> 32); + + target[0] = static_cast(part0 ); + target[1] = static_cast(part0 >> 8); + target[2] = static_cast(part0 >> 16); + target[3] = static_cast(part0 >> 24); + target[4] = static_cast(part1 ); + target[5] = static_cast(part1 >> 8); + target[6] = static_cast(part1 >> 16); + target[7] = static_cast(part1 >> 24); + + return target + sizeof(value); +} - target[0] = static_cast(value | 0x80); - if (value >= (1 << 7)) { - target[1] = static_cast((value >> 7) | 0x80); - if (value >= (1 << 14)) { - target[2] = static_cast((value >> 14) | 0x80); - if (value >= (1 << 21)) { - target[3] = static_cast((value >> 21) | 0x80); - if (value >= (1 << 28)) { - target[4] = static_cast(value >> 28); - Advance(5); - } else { - target[3] &= 0x7F; - Advance(4); - } +inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) { + target[0] = static_cast(value | 0x80); + if (value >= (1 << 7)) { + target[1] = static_cast((value >> 7) | 0x80); + if (value >= (1 << 14)) { + target[2] = static_cast((value >> 14) | 0x80); + if (value >= (1 << 21)) { + target[3] = static_cast((value >> 21) | 0x80); + if (value >= (1 << 28)) { + target[4] = static_cast(value >> 28); + return target + 5; } else { - target[2] &= 0x7F; - Advance(3); + target[3] &= 0x7F; + return target + 4; } } else { - target[1] &= 0x7F; - Advance(2); + target[2] &= 0x7F; + return target + 3; } } else { - target[0] &= 0x7F; - Advance(1); + target[1] &= 0x7F; + return target + 2; } + } else { + target[0] &= 0x7F; + return target + 1; + } +} - return true; +void CodedOutputStream::WriteVarint32(uint32 value) { + if (buffer_size_ >= kMaxVarint32Bytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; + uint8* end = WriteVarint32FallbackToArrayInline(value, target); + int size = end - target; + Advance(size); } else { // Slow path: This write might cross the end of the buffer, so we // compose the bytes first then use WriteRaw(). @@ -646,85 +681,96 @@ bool CodedOutputStream::WriteVarint32Fallback(uint32 value) { value >>= 7; } bytes[size++] = static_cast(value) & 0x7F; - return WriteRaw(bytes, size); + WriteRaw(bytes, size); } } -bool CodedOutputStream::WriteVarint64(uint64 value) { - if (buffer_size_ >= kMaxVarintBytes) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this write won't cross the end, so we can skip the checks. - uint8* target = buffer_; +uint8* CodedOutputStream::WriteVarint32FallbackToArray( + uint32 value, uint8* target) { + return WriteVarint32FallbackToArrayInline(value, target); +} - // Splitting into 32-bit pieces gives better performance on 32-bit - // processors. - uint32 part0 = static_cast(value ); - uint32 part1 = static_cast(value >> 28); - uint32 part2 = static_cast(value >> 56); - - int size; - - // Here we can't really optimize for small numbers, since the value is - // split into three parts. Cheking for numbers < 128, for instance, - // would require three comparisons, since you'd have to make sure part1 - // and part2 are zero. However, if the caller is using 64-bit integers, - // it is likely that they expect the numbers to often be very large, so - // we probably don't want to optimize for small numbers anyway. Thus, - // we end up with a hardcoded binary search tree... - if (part2 == 0) { - if (part1 == 0) { - if (part0 < (1 << 14)) { - if (part0 < (1 << 7)) { - size = 1; goto size1; - } else { - size = 2; goto size2; - } +inline uint8* CodedOutputStream::WriteVarint64ToArrayInline( + uint64 value, uint8* target) { + // Splitting into 32-bit pieces gives better performance on 32-bit + // processors. + uint32 part0 = static_cast(value ); + uint32 part1 = static_cast(value >> 28); + uint32 part2 = static_cast(value >> 56); + + int size; + + // Here we can't really optimize for small numbers, since the value is + // split into three parts. Cheking for numbers < 128, for instance, + // would require three comparisons, since you'd have to make sure part1 + // and part2 are zero. However, if the caller is using 64-bit integers, + // it is likely that they expect the numbers to often be very large, so + // we probably don't want to optimize for small numbers anyway. Thus, + // we end up with a hardcoded binary search tree... + if (part2 == 0) { + if (part1 == 0) { + if (part0 < (1 << 14)) { + if (part0 < (1 << 7)) { + size = 1; goto size1; } else { - if (part0 < (1 << 21)) { - size = 3; goto size3; - } else { - size = 4; goto size4; - } + size = 2; goto size2; } } else { - if (part1 < (1 << 14)) { - if (part1 < (1 << 7)) { - size = 5; goto size5; - } else { - size = 6; goto size6; - } + if (part0 < (1 << 21)) { + size = 3; goto size3; } else { - if (part1 < (1 << 21)) { - size = 7; goto size7; - } else { - size = 8; goto size8; - } + size = 4; goto size4; } } } else { - if (part2 < (1 << 7)) { - size = 9; goto size9; + if (part1 < (1 << 14)) { + if (part1 < (1 << 7)) { + size = 5; goto size5; + } else { + size = 6; goto size6; + } } else { - size = 10; goto size10; + if (part1 < (1 << 21)) { + size = 7; goto size7; + } else { + size = 8; goto size8; + } } } + } else { + if (part2 < (1 << 7)) { + size = 9; goto size9; + } else { + size = 10; goto size10; + } + } - GOOGLE_LOG(FATAL) << "Can't get here."; + GOOGLE_LOG(FATAL) << "Can't get here."; + + size10: target[9] = static_cast((part2 >> 7) | 0x80); + size9 : target[8] = static_cast((part2 ) | 0x80); + size8 : target[7] = static_cast((part1 >> 21) | 0x80); + size7 : target[6] = static_cast((part1 >> 14) | 0x80); + size6 : target[5] = static_cast((part1 >> 7) | 0x80); + size5 : target[4] = static_cast((part1 ) | 0x80); + size4 : target[3] = static_cast((part0 >> 21) | 0x80); + size3 : target[2] = static_cast((part0 >> 14) | 0x80); + size2 : target[1] = static_cast((part0 >> 7) | 0x80); + size1 : target[0] = static_cast((part0 ) | 0x80); + + target[size-1] &= 0x7F; + return target + size; +} - size10: target[9] = static_cast((part2 >> 7) | 0x80); - size9 : target[8] = static_cast((part2 ) | 0x80); - size8 : target[7] = static_cast((part1 >> 21) | 0x80); - size7 : target[6] = static_cast((part1 >> 14) | 0x80); - size6 : target[5] = static_cast((part1 >> 7) | 0x80); - size5 : target[4] = static_cast((part1 ) | 0x80); - size4 : target[3] = static_cast((part0 >> 21) | 0x80); - size3 : target[2] = static_cast((part0 >> 14) | 0x80); - size2 : target[1] = static_cast((part0 >> 7) | 0x80); - size1 : target[0] = static_cast((part0 ) | 0x80); +void CodedOutputStream::WriteVarint64(uint64 value) { + if (buffer_size_ >= kMaxVarintBytes) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; - target[size-1] &= 0x7F; + uint8* end = WriteVarint64ToArrayInline(value, target); + int size = end - target; Advance(size); - return true; } else { // Slow path: This write might cross the end of the buffer, so we // compose the bytes first then use WriteRaw(). @@ -735,10 +781,15 @@ bool CodedOutputStream::WriteVarint64(uint64 value) { value >>= 7; } bytes[size++] = static_cast(value) & 0x7F; - return WriteRaw(bytes, size); + WriteRaw(bytes, size); } } +uint8* CodedOutputStream::WriteVarint64ToArray( + uint64 value, uint8* target) { + return WriteVarint64ToArrayInline(value, target); +} + bool CodedOutputStream::Refresh() { void* void_buffer; if (output_->Next(&void_buffer, &buffer_size_)) { @@ -748,6 +799,7 @@ bool CodedOutputStream::Refresh() { } else { buffer_ = NULL; buffer_size_ = 0; + had_error_ = true; return false; } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 8ebe4b35..9e450216 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -380,7 +380,46 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // // Most methods of CodedOutputStream which return a bool return false if an // underlying I/O error occurs. Once such a failure occurs, the -// CodedOutputStream is broken and is no longer useful. +// CodedOutputStream is broken and is no longer useful. The Write* methods do +// not return the stream status, but will invalidate the stream if an error +// occurs. The client can probe HadError() to determine the status. +// +// Note that every method of CodedOutputStream which writes some data has +// a corresponding static "ToArray" version. These versions write directly +// to the provided buffer, returning a pointer past the last written byte. +// They require that the buffer has sufficient capacity for the encoded data. +// This allows an optimization where we check if an output stream has enough +// space for an entire message before we start writing and, if there is, we +// call only the ToArray methods to avoid doing bound checks for each +// individual value. +// i.e., in the example above: +// +// CodedOutputStream coded_output = new CodedOutputStream(raw_output); +// int magic_number = 1234; +// char text[] = "Hello world!"; +// +// int coded_size = sizeof(magic_number) + +// CodedOutputStream::Varint32Size(strlen(text)) + +// strlen(text); +// +// uint8* buffer = +// coded_output->GetDirectBufferForNBytesAndAdvance(coded_size); +// if (buffer != NULL) { +// // The output stream has enough space in the buffer: write directly to +// // the array. +// buffer = CodedOutputStream::WriteLittleEndian32ToArray(magic_number, +// buffer); +// buffer = CodedOutputStream::WriteVarint32ToArray(strlen(text), buffer); +// buffer = CodedOutputStream::WriteRawToArray(text, strlen(text), buffer); +// } else { +// // Make bound-checked writes, which will ask the underlying stream for +// // more space as needed. +// coded_output->WriteLittleEndian32(magic_number); +// coded_output->WriteVarint32(strlen(text)); +// coded_output->WriteRaw(text, strlen(text)); +// } +// +// delete coded_output; class LIBPROTOBUF_EXPORT CodedOutputStream { public: // Create an CodedOutputStream that writes to the given ZeroCopyOutputStream. @@ -405,35 +444,65 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // CodedOutputStream interface. bool GetDirectBufferPointer(void** data, int* size); + // If there are at least "size" bytes available in the current buffer, + // returns a pointer directly into the buffer and advances over these bytes. + // The caller may then write directly into this buffer (e.g. using the + // *ToArray static methods) rather than go through CodedOutputStream. If + // there are not enough bytes available, returns NULL. The return pointer is + // invalidated as soon as any other non-const method of CodedOutputStream + // is called. + inline uint8* GetDirectBufferForNBytesAndAdvance(int size); + // Write raw bytes, copying them from the given buffer. - bool WriteRaw(const void* buffer, int size); + void WriteRaw(const void* buffer, int size); + // Like WriteRaw() but writing directly to the target array. + // This is _not_ inlined, as the compiler often optimizes memcpy into inline + // copy loops. Since this gets called by every field with string or bytes + // type, inlining may lead to a significant amount of code bloat, with only a + // minor performance gain. + static uint8* WriteRawToArray(const void* buffer, int size, uint8* target); // Equivalent to WriteRaw(str.data(), str.size()). - bool WriteString(const string& str); + void WriteString(const string& str); + // Like WriteString() but writing directly to the target array. + static uint8* WriteStringToArray(const string& str, uint8* target); // Write a 32-bit little-endian integer. - bool WriteLittleEndian32(uint32 value); + void WriteLittleEndian32(uint32 value); + // Like WriteLittleEndian32() but writing directly to the target array. + static uint8* WriteLittleEndian32ToArray(uint32 value, uint8* target); // Write a 64-bit little-endian integer. - bool WriteLittleEndian64(uint64 value); + void WriteLittleEndian64(uint64 value); + // Like WriteLittleEndian64() but writing directly to the target array. + static uint8* WriteLittleEndian64ToArray(uint64 value, uint8* target); // Write an unsigned integer with Varint encoding. Writing a 32-bit value // is equivalent to casting it to uint64 and writing it as a 64-bit value, // but may be more efficient. - bool WriteVarint32(uint32 value); + void WriteVarint32(uint32 value); + // Like WriteVarint32() but writing directly to the target array. + static uint8* WriteVarint32ToArray(uint32 value, uint8* target); // Write an unsigned integer with Varint encoding. - bool WriteVarint64(uint64 value); + void WriteVarint64(uint64 value); + // Like WriteVarint64() but writing directly to the target array. + static uint8* WriteVarint64ToArray(uint64 value, uint8* target); // Equivalent to WriteVarint32() except when the value is negative, // in which case it must be sign-extended to a full 10 bytes. - bool WriteVarint32SignExtended(int32 value); + void WriteVarint32SignExtended(int32 value); + // Like WriteVarint32SignExtended() but writing directly to the target array. + static uint8* WriteVarint32SignExtendedToArray(int32 value, uint8* target); // This is identical to WriteVarint32(), but optimized for writing tags. // In particular, if the input is a compile-time constant, this method // compiles down to a couple instructions. // Always inline because otherwise the aformentioned optimization can't work, // but GCC by default doesn't want to inline this. - bool WriteTag(uint32 value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + void WriteTag(uint32 value); + // Like WriteTag() but writing directly to the target array. + static uint8* WriteTagToArray( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; // Returns the number of bytes needed to encode the given value as a varint. static int VarintSize32(uint32 value); @@ -446,6 +515,10 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // Returns the total number of bytes written since this object was created. inline int ByteCount() const; + // Returns true if there was an underlying I/O error since this object was + // created. + bool HadError() const { return had_error_; } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedOutputStream); @@ -453,6 +526,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { uint8* buffer_; int buffer_size_; int total_bytes_; // Sum of sizes of all buffers seen so far. + bool had_error_; // Whether an error occurred during output. // Advance the buffer by a given number of bytes. void Advance(int amount); @@ -461,7 +535,20 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // Advance(buffer_size_). bool Refresh(); - bool WriteVarint32Fallback(uint32 value); + static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target); + + // Always-inlined versions of WriteVarint* functions so that code can be + // reused, while still controlling size. For instance, WriteVarint32ToArray() + // should not directly call this: since it is inlined itself, doing so + // would greatly increase the size of generated code. Instead, it should call + // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already + // out-of-line, so it should just invoke this directly to avoid any extra + // function call overhead. + static uint8* WriteVarint32FallbackToArrayInline( + uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static int VarintSize32Fallback(uint32 value); }; @@ -540,40 +627,59 @@ inline bool CodedInputStream::ExpectAtEnd() { } } -inline bool CodedOutputStream::WriteVarint32(uint32 value) { - if (value < 0x80 && buffer_size_ > 0) { - *buffer_ = static_cast(value); - Advance(1); - return true; +inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) { + if (buffer_size_ < size) { + return NULL; + } else { + uint8* result = buffer_; + Advance(size); + return result; + } +} + +inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value, + uint8* target) { + if (value < 0x80) { + *target = value; + return target + 1; } else { - return WriteVarint32Fallback(value); + return WriteVarint32FallbackToArray(value, target); } } -inline bool CodedOutputStream::WriteVarint32SignExtended(int32 value) { +inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { if (value < 0) { - return WriteVarint64(static_cast(value)); + WriteVarint64(static_cast(value)); } else { - return WriteVarint32(static_cast(value)); + WriteVarint32(static_cast(value)); } } -inline bool CodedOutputStream::WriteTag(uint32 value) { +inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( + int32 value, uint8* target) { + if (value < 0) { + return WriteVarint64ToArray(static_cast(value), target); + } else { + return WriteVarint32ToArray(static_cast(value), target); + } +} + +inline void CodedOutputStream::WriteTag(uint32 value) { + WriteVarint32(value); +} + +inline uint8* CodedOutputStream::WriteTagToArray( + uint32 value, uint8* target) { if (value < (1 << 7)) { - if (buffer_size_ != 0) { - buffer_[0] = static_cast(value); - Advance(1); - return true; - } + target[0] = value; + return target + 1; } else if (value < (1 << 14)) { - if (buffer_size_ >= 2) { - buffer_[0] = static_cast(value | 0x80); - buffer_[1] = static_cast(value >> 7); - Advance(2); - return true; - } + target[0] = static_cast(value | 0x80); + target[1] = static_cast(value >> 7); + return target + 2; + } else { + return WriteVarint32FallbackToArray(value, target); } - return WriteVarint32Fallback(value); } inline int CodedOutputStream::VarintSize32(uint32 value) { @@ -592,8 +698,13 @@ inline int CodedOutputStream::VarintSize32SignExtended(int32 value) { } } -inline bool CodedOutputStream::WriteString(const string& str) { - return WriteRaw(str.data(), str.size()); +inline void CodedOutputStream::WriteString(const string& str) { + WriteRaw(str.data(), str.size()); +} + +inline uint8* CodedOutputStream::WriteStringToArray( + const string& str, uint8* target) { + return WriteRawToArray(str.data(), str.size(), target); } inline int CodedOutputStream::ByteCount() const { diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 6a6eafe9..e165fb93 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -268,8 +268,8 @@ TEST_2D(CodedStreamTest, WriteVarint32, kVarintCases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint32( - static_cast(kVarintCases_case.value))); + coded_output.WriteVarint32(static_cast(kVarintCases_case.value)); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount()); } @@ -285,7 +285,8 @@ TEST_2D(CodedStreamTest, WriteVarint64, kVarintCases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint64(kVarintCases_case.value)); + coded_output.WriteVarint64(kVarintCases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(kVarintCases_case.size, coded_output.ByteCount()); } @@ -310,8 +311,8 @@ TEST_2D(CodedStreamTest, WriteVarint32SignExtended, { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteVarint32SignExtended( - kSignExtendedVarintCases_case)); + coded_output.WriteVarint32SignExtended(kSignExtendedVarintCases_case); + EXPECT_FALSE(coded_output.HadError()); if (kSignExtendedVarintCases_case < 0) { EXPECT_EQ(10, coded_output.ByteCount()); @@ -502,7 +503,8 @@ TEST_2D(CodedStreamTest, WriteLittleEndian32, kFixed32Cases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteLittleEndian32(kFixed32Cases_case.value)); + coded_output.WriteLittleEndian32(kFixed32Cases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(uint32), coded_output.ByteCount()); } @@ -517,7 +519,8 @@ TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteLittleEndian64(kFixed64Cases_case.value)); + coded_output.WriteLittleEndian64(kFixed64Cases_case.value); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(uint64), coded_output.ByteCount()); } @@ -552,7 +555,8 @@ TEST_1D(CodedStreamTest, WriteRaw, kBlockSizes) { { CodedOutputStream coded_output(&output); - EXPECT_TRUE(coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes))); + coded_output.WriteRaw(kRawBytes, sizeof(kRawBytes)); + EXPECT_FALSE(coded_output.HadError()); EXPECT_EQ(sizeof(kRawBytes), coded_output.ByteCount()); } diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc index 730bd2f7..0b4516ef 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl.cc @@ -185,11 +185,12 @@ bool StringOutputStream::Next(void** data, int* size) { if (old_size < target_->capacity()) { // Resize the string to match its capacity, since we can get away // without a memory allocation this way. - target_->resize(target_->capacity()); + STLStringResizeUninitialized(target_, target_->capacity()); } else { // Size has reached capacity, so double the size. Also make sure // that the new size is at least kMinimumSize. - target_->resize( + STLStringResizeUninitialized( + target_, max(old_size * 2, kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. } diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 097411cb..9df3d394 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -47,6 +47,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -205,9 +206,19 @@ bool Message::ParsePartialFromIstream(istream* input) { -bool Message::SerializeWithCachedSizes( +void Message::SerializeWithCachedSizes( io::CodedOutputStream* output) const { - return WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); + WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output); +} + +uint8* Message::SerializeWithCachedSizesToArray(uint8* target) const { + // We only optimize this when using optimize_for = SPEED. + int size = GetCachedSize(); + io::ArrayOutputStream out(target, size); + io::CodedOutputStream coded_out(&out); + SerializeWithCachedSizes(&coded_out); + GOOGLE_CHECK(!coded_out.HadError()); + return target + size; } int Message::ByteSize() const { @@ -234,8 +245,8 @@ bool Message::SerializeToCodedStream(io::CodedOutputStream* output) const { bool Message::SerializePartialToCodedStream( io::CodedOutputStream* output) const { ByteSize(); // Force size to be cached. - if (!SerializeWithCachedSizes(output)) return false; - return true; + SerializeWithCachedSizes(output); + return !output->HadError(); } bool Message::SerializeToZeroCopyStream( @@ -256,19 +267,12 @@ bool Message::AppendToString(string* output) const { } bool Message::AppendPartialToString(string* output) const { - // For efficiency, we'd like to reserve the exact amount of space we need - // in the string. - int total_size = output->size() + ByteSize(); - output->reserve(total_size); - - io::StringOutputStream output_stream(output); - - { - io::CodedOutputStream encoder(&output_stream); - if (!SerializeWithCachedSizes(&encoder)) return false; - } - - GOOGLE_CHECK_EQ(output_stream.ByteCount(), total_size); + int old_size = output->size(); + int byte_size = ByteSize(); + STLStringResizeUninitialized(output, old_size + byte_size); + uint8* start = reinterpret_cast(string_as_array(output) + old_size); + uint8* end = SerializeWithCachedSizesToArray(start); + GOOGLE_CHECK_EQ(end, start + byte_size); return true; } @@ -283,13 +287,17 @@ bool Message::SerializePartialToString(string* output) const { } bool Message::SerializeToArray(void* data, int size) const { - io::ArrayOutputStream output_stream(data, size); - return SerializeToZeroCopyStream(&output_stream); + GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this); + return SerializePartialToArray(data, size); } bool Message::SerializePartialToArray(void* data, int size) const { - io::ArrayOutputStream output_stream(data, size); - return SerializePartialToZeroCopyStream(&output_stream); + int byte_size = ByteSize(); + if (size < byte_size) return false; + uint8* end = + SerializeWithCachedSizesToArray(reinterpret_cast(data)); + GOOGLE_CHECK_EQ(end, reinterpret_cast(data) + byte_size); + return true; } bool Message::SerializeToFileDescriptor(int file_descriptor) const { @@ -347,12 +355,20 @@ class GeneratedMessageFactory : public MessageFactory { static GeneratedMessageFactory* singleton(); + typedef void RegistrationFunc(); + void RegisterFile(const char* file, RegistrationFunc* registration_func); void RegisterType(const Descriptor* descriptor, const Message* prototype); // implements MessageFactory --------------------------------------- const Message* GetPrototype(const Descriptor* type); private: + // Only written at static init time, so does not require locking. + hash_map, streq> file_map_; + + // Initialized lazily, so requires locking. + Mutex mutex_; hash_map type_map_; }; @@ -366,19 +382,65 @@ GeneratedMessageFactory* GeneratedMessageFactory::singleton() { return &singleton; } +void GeneratedMessageFactory::RegisterFile( + const char* file, RegistrationFunc* registration_func) { + if (!InsertIfNotPresent(&file_map_, file, registration_func)) { + GOOGLE_LOG(FATAL) << "File is already registered: " << file; + } +} + void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor, const Message* prototype) { GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool()) << "Tried to register a non-generated type with the generated " "type registry."; + // This should only be called as a result of calling a file registration + // function during GetPrototype(), in which case we already have locked + // the mutex. + mutex_.AssertHeld(); if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) { GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name(); } } const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { - return FindPtrOrNull(type_map_, type); + { + ReaderMutexLock lock(&mutex_); + const Message* result = FindPtrOrNull(type_map_, type); + if (result != NULL) return result; + } + + // If the type is not in the generated pool, then we can't possibly handle + // it. + if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL; + + // Apparently the file hasn't been registered yet. Let's do that now. + RegistrationFunc* registration_func = + FindPtrOrNull(file_map_, type->file()->name().c_str()); + if (registration_func == NULL) { + GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't " + "registered: " << type->file()->name(); + return NULL; + } + + WriterMutexLock lock(&mutex_); + + // Check if another thread preempted us. + const Message* result = FindPtrOrNull(type_map_, type); + if (result == NULL) { + // Nope. OK, register everything. + registration_func(); + // Should be here now. + result = FindPtrOrNull(type_map_, type); + } + + if (result == NULL) { + GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't " + << "registered: " << type->full_name(); + } + + return result; } } // namespace @@ -387,6 +449,12 @@ MessageFactory* MessageFactory::generated_factory() { return GeneratedMessageFactory::singleton(); } +void MessageFactory::InternalRegisterGeneratedFile( + const char* filename, void (*register_messages)()) { + GeneratedMessageFactory::singleton()->RegisterFile(filename, + register_messages); +} + void MessageFactory::InternalRegisterGeneratedMessage( const Descriptor* descriptor, const Message* prototype) { GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype); diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index b4209026..b05ea954 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -117,24 +117,24 @@ #else #include #endif - -#if defined(_WIN32) && defined(GetMessage) -// windows.h defines GetMessage() as a macro. Let's re-define it as an inline -// function. This is necessary because Reflection has a method called -// GetMessage() which we don't want overridden. The inline function should be -// equivalent for C++ users. -inline BOOL GetMessage_Win32( - LPMSG lpMsg, HWND hWnd, - UINT wMsgFilterMin, UINT wMsgFilterMax) { - return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); -} -#undef GetMessage -inline BOOL GetMessage( - LPMSG lpMsg, HWND hWnd, - UINT wMsgFilterMin, UINT wMsgFilterMax) { - return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); -} -#endif + +#if defined(_WIN32) && defined(GetMessage) +// windows.h defines GetMessage() as a macro. Let's re-define it as an inline +// function. This is necessary because Reflection has a method called +// GetMessage() which we don't want overridden. The inline function should be +// equivalent for C++ users. +inline BOOL GetMessage_Win32( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#undef GetMessage +inline BOOL GetMessage( + LPMSG lpMsg, HWND hWnd, + UINT wMsgFilterMin, UINT wMsgFilterMax) { + return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax); +} +#endif #include @@ -370,7 +370,12 @@ class LIBPROTOBUF_EXPORT Message { // Serializes the message without recomputing the size. The message must // not have changed since the last call to ByteSize(); if it has, the results // are undefined. - virtual bool SerializeWithCachedSizes(io::CodedOutputStream* output) const; + virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const; + + // Like SerializeWithCachedSizes, but writes directly to *target, returning + // a pointer to the byte immediately after the last byte written. "target" + // must point at a byte array of at least ByteSize() bytes. + virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const; // Returns the result of the last call to ByteSize(). An embedded message's // size is needed both to serialize it (because embedded messages are @@ -731,8 +736,19 @@ class LIBPROTOBUF_EXPORT MessageFactory { // This factory is a singleton. The caller must not delete the object. static MessageFactory* generated_factory(); - // For internal use only: Registers a message type at static initialization - // time, to be placed in generated_factory(). + // For internal use only: Registers a .proto file at static initialization + // time, to be placed in generated_factory. The first time GetPrototype() + // is called with a descriptor from this file, |register_messages| will be + // called. It must call InternalRegisterGeneratedMessage() (below) to + // register each message type in the file. This strange mechanism is + // necessary because descriptors are built lazily, so we can't register + // types by their descriptor until we know that the descriptor exists. + static void InternalRegisterGeneratedFile(const char* filename, + void (*register_messages)()); + + // For internal use only: Registers a message type. Called only by the + // functions which are registered with InternalRegisterGeneratedFile(), + // above. static void InternalRegisterGeneratedMessage(const Descriptor* descriptor, const Message* prototype); diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc index 2f2d5262..1cd56f1e 100644 --- a/src/google/protobuf/reflection_ops_unittest.cc +++ b/src/google/protobuf/reflection_ops_unittest.cc @@ -138,16 +138,18 @@ TEST(ReflectionOpsTest, MergeExtensions) { TEST(ReflectionOpsTest, MergeUnknown) { // Test that the messages' UnknownFieldSets are correctly merged. unittest::TestEmptyMessage message1, message2; - message1.mutable_unknown_fields()->AddField(1234)->add_varint(1); - message2.mutable_unknown_fields()->AddField(1234)->add_varint(2); + message1.mutable_unknown_fields()->AddVarint(1234, 1); + message2.mutable_unknown_fields()->AddVarint(1234, 2); ReflectionOps::Merge(message2, &message1); - ASSERT_EQ(1, message1.unknown_fields().field_count()); - const UnknownField& field = message1.unknown_fields().field(0); - ASSERT_EQ(2, field.varint_size()); - EXPECT_EQ(1, field.varint(0)); - EXPECT_EQ(2, field.varint(1)); + ASSERT_EQ(2, message1.unknown_fields().field_count()); + ASSERT_EQ(UnknownField::TYPE_VARINT, + message1.unknown_fields().field(0).type()); + EXPECT_EQ(1, message1.unknown_fields().field(0).varint()); + ASSERT_EQ(UnknownField::TYPE_VARINT, + message1.unknown_fields().field(1).type()); + EXPECT_EQ(2, message1.unknown_fields().field(1).varint()); } #ifdef GTEST_HAS_DEATH_TEST @@ -211,7 +213,7 @@ TEST(ReflectionOpsTest, ClearExtensions) { TEST(ReflectionOpsTest, ClearUnknown) { // Test that the message's UnknownFieldSet is correctly cleared. unittest::TestEmptyMessage message; - message.mutable_unknown_fields()->AddField(1234)->add_varint(1); + message.mutable_unknown_fields()->AddVarint(1234, 1); ReflectionOps::Clear(&message); @@ -224,16 +226,13 @@ TEST(ReflectionOpsTest, DiscardUnknownFields) { // Set some unknown fields in message. message.mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); message.mutable_optional_nested_message() ->mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); message.mutable_repeated_nested_message(0) ->mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); EXPECT_EQ(1, message.unknown_fields().field_count()); EXPECT_EQ(1, message.optional_nested_message() @@ -258,16 +257,13 @@ TEST(ReflectionOpsTest, DiscardUnknownExtensions) { // Set some unknown fields. message.mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); message.MutableExtension(unittest::optional_nested_message_extension) ->mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); message.MutableExtension(unittest::repeated_nested_message_extension, 0) ->mutable_unknown_fields() - ->AddField(123456) - ->add_varint(654321); + ->AddVarint(123456, 654321); EXPECT_EQ(1, message.unknown_fields().field_count()); EXPECT_EQ(1, diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 44cd875b..8d5dc480 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -93,6 +93,7 @@ class LIBPROTOBUF_EXPORT GenericRepeatedField { }; // We need this (from generated_message_reflection.cc). +LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str); int StringSpaceUsedExcludingSelf(const string& str); } // namespace internal @@ -865,6 +866,129 @@ RepeatedPtrField::end() const { return iterator(elements_ + current_size_); } +// Iterators and helper functions that follow the spirit of the STL +// std::back_insert_iterator and std::back_inserter but are tailor-made +// for RepeatedField and RepatedPtrField. Typical usage would be: +// +// std::copy(some_sequence.begin(), some_sequence.end(), +// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence())); +// +// Ported by johannes from util/gtl/proto-array-iterators-inl.h + +namespace internal { +// A back inserter for RepeatedField objects. +template class RepeatedFieldBackInsertIterator + : public std::iterator { + public: + explicit RepeatedFieldBackInsertIterator( + RepeatedField* const mutable_field) + : field_(mutable_field) { + } + RepeatedFieldBackInsertIterator& operator=(const T& value) { + field_->Add(value); + return *this; + } + RepeatedFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedFieldBackInsertIterator& operator++(int ignores_parameter) { + return *this; + } + + private: + RepeatedField* const field_; +}; + +// A back inserter for RepeatedPtrField objects. +template class RepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + RepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + RepeatedPtrFieldBackInsertIterator& operator=(const T& value) { + *field_->Add() = value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator=( + const T* const ptr_to_value) { + *field_->Add() = *ptr_to_value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator++(int ignores_parameter) { + return *this; + } + + private: + RepeatedPtrField* const field_; +}; + +// A back inserter for RepeatedPtrFields that inserts by transfering ownership +// of a pointer. +template class AllocatedRepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + explicit AllocatedRepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T* const ptr_to_value) { + field_->AddAllocated(ptr_to_value); + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++( + int ignores_parameter) { + return *this; + } + + private: + RepeatedPtrField* const field_; +}; +} // namespace internal + +// Provides a back insert iterator for RepeatedField instances, +// similar to std::back_inserter(). Note the identically named +// function for RepeatedPtrField instances. +template internal::RepeatedFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedField* const mutable_field) { + return internal::RepeatedFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances, +// similar to std::back_inserter(). Note the identically named +// function for RepeatedField instances. +template internal::RepeatedPtrFieldBackInsertIterator +RepeatedFieldBackInserter(RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances +// similar to std::back_inserter() which transfers the ownership while +// copying elements. +template internal::AllocatedRepeatedPtrFieldBackInsertIterator +AllocatedRepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::AllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 3ab97620..50f009b5 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -36,15 +36,22 @@ // other proto2 unittests. #include +#include #include #include +#include +#include #include #include +#include namespace google { +using protobuf_unittest::TestAllTypes; + namespace protobuf { +namespace { // Test operations on a RepeatedField which is small enough that it does // not allocate a separate array for storage. @@ -621,5 +628,147 @@ TEST_F(RepeatedPtrFieldIteratorTest, Mutation) { EXPECT_EQ("qux", proto_array_.Get(0)); } +// ----------------------------------------------------------------------------- +// Unit-tests for the insert iterators +// google::protobuf::RepeatedFieldBackInserter, +// google::protobuf::AllocatedRepeatedPtrFieldBackInserter +// Ported from util/gtl/proto-array-iterators_unittest. + +class RepeatedFieldInsertionIteratorsTest : public testing::Test { + protected: + std::list halves; + std::list fibonacci; + std::vector words; + typedef TestAllTypes::NestedMessage Nested; + Nested nesteds[2]; + std::vector nested_ptrs; + TestAllTypes protobuffer; + + virtual void SetUp() { + fibonacci.push_back(1); + fibonacci.push_back(1); + fibonacci.push_back(2); + fibonacci.push_back(3); + fibonacci.push_back(5); + fibonacci.push_back(8); + std::copy(fibonacci.begin(), fibonacci.end(), + RepeatedFieldBackInserter(protobuffer.mutable_repeated_int32())); + + halves.push_back(1.0); + halves.push_back(0.5); + halves.push_back(0.25); + halves.push_back(0.125); + halves.push_back(0.0625); + std::copy(halves.begin(), halves.end(), + RepeatedFieldBackInserter(protobuffer.mutable_repeated_double())); + + words.push_back("Able"); + words.push_back("was"); + words.push_back("I"); + words.push_back("ere"); + words.push_back("I"); + words.push_back("saw"); + words.push_back("Elba"); + std::copy(words.begin(), words.end(), + RepeatedFieldBackInserter(protobuffer.mutable_repeated_string())); + + nesteds[0].set_bb(17); + nesteds[1].set_bb(4711); + std::copy(&nesteds[0], &nesteds[2], + RepeatedFieldBackInserter( + protobuffer.mutable_repeated_nested_message())); + + nested_ptrs.push_back(new Nested); + nested_ptrs.back()->set_bb(170); + nested_ptrs.push_back(new Nested); + nested_ptrs.back()->set_bb(47110); + std::copy(nested_ptrs.begin(), nested_ptrs.end(), + RepeatedFieldBackInserter( + protobuffer.mutable_repeated_nested_message())); + + } + + virtual void TearDown() { + STLDeleteContainerPointers(nested_ptrs.begin(), nested_ptrs.end()); + } +}; + +TEST_F(RepeatedFieldInsertionIteratorsTest, Fibonacci) { + EXPECT_TRUE(std::equal(fibonacci.begin(), + fibonacci.end(), + protobuffer.repeated_int32().begin())); + EXPECT_TRUE(std::equal(protobuffer.repeated_int32().begin(), + protobuffer.repeated_int32().end(), + fibonacci.begin())); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, Halves) { + EXPECT_TRUE(std::equal(halves.begin(), + halves.end(), + protobuffer.repeated_double().begin())); + EXPECT_TRUE(std::equal(protobuffer.repeated_double().begin(), + protobuffer.repeated_double().end(), + halves.begin())); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, Words) { + ASSERT_EQ(words.size(), protobuffer.repeated_string_size()); + EXPECT_EQ(words.at(0), protobuffer.repeated_string(0)); + EXPECT_EQ(words.at(1), protobuffer.repeated_string(1)); + EXPECT_EQ(words.at(2), protobuffer.repeated_string(2)); + EXPECT_EQ(words.at(3), protobuffer.repeated_string(3)); + EXPECT_EQ(words.at(4), protobuffer.repeated_string(4)); + EXPECT_EQ(words.at(5), protobuffer.repeated_string(5)); + EXPECT_EQ(words.at(6), protobuffer.repeated_string(6)); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, Nesteds) { + ASSERT_EQ(protobuffer.repeated_nested_message_size(), 4); + EXPECT_EQ(protobuffer.repeated_nested_message(0).bb(), 17); + EXPECT_EQ(protobuffer.repeated_nested_message(1).bb(), 4711); + EXPECT_EQ(protobuffer.repeated_nested_message(2).bb(), 170); + EXPECT_EQ(protobuffer.repeated_nested_message(3).bb(), 47110); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, + AllocatedRepeatedPtrFieldWithStringIntData) { + vector data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + Nested* new_data = new Nested; + new_data->set_bb(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_nested_message(); + new_data->set_bb(i); + } + TestAllTypes testproto; + copy(data.begin(), data.end(), + AllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_nested_message())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, + AllocatedRepeatedPtrFieldWithString) { + vector data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + string* new_data = new string; + *new_data = "name-" + SimpleItoa(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_string(); + *new_data = "name-" + SimpleItoa(i); + } + TestAllTypes testproto; + copy(data.begin(), data.end(), + AllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_string())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + +} // namespace + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index cadb3b93..4a55e004 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -1039,6 +1039,10 @@ class LIBPROTOBUF_EXPORT MutexLock { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MutexLock); }; +// TODO(kenton): Implement these? Hard to implement portably. +typedef MutexLock ReaderMutexLock; +typedef MutexLock WriterMutexLock; + // MutexLockMaybe is like MutexLock, but is a no-op when mu is NULL. class LIBPROTOBUF_EXPORT MutexLockMaybe { public: @@ -1056,6 +1060,8 @@ class LIBPROTOBUF_EXPORT MutexLockMaybe { // but we don't want to stick "internal::" in front of them everywhere. using internal::Mutex; using internal::MutexLock; +using internal::ReaderMutexLock; +using internal::WriterMutexLock; using internal::MutexLockMaybe; // =================================================================== diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index efbeeedd..c3414138 100644 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -178,6 +178,33 @@ struct hash { } }; +template +struct hash > { + inline size_t operator()(const pair& key) const { + size_t first_hash = hash()(key.first); + size_t second_hash = hash()(key.second); + + // FIXME(kenton): What is the best way to compute this hash? I have + // no idea! This seems a bit better than an XOR. + return first_hash * ((1 << 16) - 1) + second_hash; + } + + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + inline size_t operator()(const pair& a, + const pair& b) const { + return a < b; + } +}; + +// Used by GCC/SGI STL only. (Why isn't this provided by the standard +// library? :( ) +struct streq { + inline bool operator()(const char* a, const char* b) const { + return strcmp(a, b) == 0; + } +}; + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/map-util.h b/src/google/protobuf/stubs/map-util.h index 3ceecec5..f5c9d6b6 100644 --- a/src/google/protobuf/stubs/map-util.h +++ b/src/google/protobuf/stubs/map-util.h @@ -39,6 +39,21 @@ namespace google { namespace protobuf { +// Perform a lookup in a map or hash_map. +// If the key is present in the map then the value associated with that +// key is returned, otherwise the value passed as a default is returned. +template +const typename Collection::value_type::second_type& +FindWithDefault(const Collection& collection, + const typename Collection::value_type::first_type& key, + const typename Collection::value_type::second_type& value) { + typename Collection::const_iterator it = collection.find(key); + if (it == collection.end()) { + return value; + } + return it->second; +} + // Perform a lookup in a map or hash_map. // If the key is present a const pointer to the associated value is returned, // otherwise a NULL pointer is returned. diff --git a/src/google/protobuf/stubs/once.cc b/src/google/protobuf/stubs/once.cc new file mode 100644 index 00000000..b47a031c --- /dev/null +++ b/src/google/protobuf/stubs/once.cc @@ -0,0 +1,82 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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) +// +// emulates google3/base/once.h +// +// This header is intended to be included only by internal .cc files and +// generated .pb.cc files. Users should not use this directly. + +#ifdef _WIN32 +#include +#endif + +#include + +namespace google { +namespace protobuf { + +#ifdef _WIN32 + +struct GoogleOnceInternal { + GoogleOnceInternal() { + InitializeCriticalSection(&critical_section); + } + ~GoogleOnceInternal() { + DeleteCriticalSection(&critical_section); + } + CRITICAL_SECTION critical_section; +}; + +GoogleOnceType::GoogleOnceType() { + // internal_ may be non-NULL if Init() was already called. + if (internal_ == NULL) internal_ = new GoogleOnceInternal; +} + +void GoogleOnceType::Init(void (*init_func)()) { + // internal_ may be NULL if we're still in dynamic initialization and the + // constructor has not been called yet. As mentioned in once.h, we assume + // that the program is still single-threaded at this time, and therefore it + // should be safe to initialize internal_ like so. + if (internal_ == NULL) internal_ = new GoogleOnceInternal; + + EnterCriticalSection(&internal_->critical_section); + if (!initialized_) { + init_func(); + initialized_ = true; + } + LeaveCriticalSection(&internal_->critical_section); +} + +#endif + +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h new file mode 100644 index 00000000..58f1ea91 --- /dev/null +++ b/src/google/protobuf/stubs/once.h @@ -0,0 +1,122 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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) +// +// emulates google3/base/once.h +// +// This header is intended to be included only by internal .cc files and +// generated .pb.cc files. Users should not use this directly. +// +// This is basically a portable version of pthread_once(). +// +// This header declares three things: +// * A type called GoogleOnceType. +// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type +// GoogleOnceType. This is the only legal way to declare such a variable. +// The macro may only be used at the global scope (you cannot create local +// or class member variables of this type). +// * A function GogoleOnceInit(GoogleOnceType* once, void (*init_func)()). +// This function, when invoked multiple times given the same GoogleOnceType +// object, will invoke init_func on the first call only, and will make sure +// none of the calls return before that first call to init_func has finished. +// +// This implements a way to perform lazy initialization. It's more efficient +// than using mutexes as no lock is needed if initialization has already +// happened. +// +// Example usage: +// void Init(); +// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init); +// +// // Calls Init() exactly once. +// void InitOnce() { +// GoogleOnceInit(&once_init, &Init); +// } +// +// Note that if GoogleOnceInit() is called before main() has begun, it must +// only be called by the thread that will eventually call main() -- that is, +// the thread that performs dynamic initialization. In general this is a safe +// assumption since people don't usually construct threads before main() starts, +// but it is technically not guaranteed. Unfortunately, Win32 provides no way +// whatsoever to statically-initialize its synchronization primitives, so our +// only choice is to assume that dynamic initialization is single-threaded. + +#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__ +#define GOOGLE_PROTOBUF_STUBS_ONCE_H__ + +#include + +#ifndef _WIN32 +#include +#endif + +namespace google { +namespace protobuf { + +#ifdef _WIN32 + +struct GoogleOnceInternal; + +struct GoogleOnceType { + GoogleOnceType(); + void Init(void (*init_func)()); + + volatile bool initialized_; + GoogleOnceInternal* internal_; +}; + +#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ + ::google::protobuf::GoogleOnceType NAME + +inline void GoogleOnceInit(GoogleOnceType* once, void (*init_func)()) { + // Note: Double-checked locking is safe on x86. + if (!once->initialized_) { + once->Init(init_func); + } +} + +#else + +typedef pthread_once_t GoogleOnceType; + +#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ + pthread_once_t NAME = PTHREAD_ONCE_INIT + +inline void GoogleOnceInit(GoogleOnceType* once, void (*init_func)()) { + pthread_once(once, init_func); +} + +#endif + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__ diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc new file mode 100644 index 00000000..86e06478 --- /dev/null +++ b/src/google/protobuf/stubs/once_unittest.cc @@ -0,0 +1,253 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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) + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace { + +class OnceInitTest : public testing::Test { + protected: + void SetUp() { + state_ = INIT_NOT_STARTED; + current_test_ = this; + } + + // Since GoogleOnceType is only allowed to be allocated in static storage, + // each test must use a different pair of GoogleOnceType objects which it + // must declare itself. + void SetOnces(GoogleOnceType* once, GoogleOnceType* recursive_once) { + once_ = once; + recursive_once_ = recursive_once; + } + + void InitOnce() { + GoogleOnceInit(once_, &InitStatic); + } + void InitRecursiveOnce() { + GoogleOnceInit(recursive_once_, &InitRecursiveStatic); + } + + void BlockInit() { init_blocker_.Lock(); } + void UnblockInit() { init_blocker_.Unlock(); } + + class TestThread { + public: + TestThread(Closure* callback) + : done_(false), joined_(false), callback_(callback) { +#ifdef _WIN32 + thread_ = CreateThread(NULL, 0, &Start, this, 0, NULL); +#else + pthread_create(&thread_, NULL, &Start, this); +#endif + } + ~TestThread() { + if (!joined_) Join(); + } + + bool IsDone() { + MutexLock lock(&done_mutex_); + return done_; + } + void Join() { + joined_ = true; +#ifdef _WIN32 + WaitForSingleObject(thread_, INFINITE); + CloseHandle(thread_); +#else + pthread_join(thread_, NULL); +#endif + } + + private: +#ifdef _WIN32 + HANDLE thread_; +#else + pthread_t thread_; +#endif + + Mutex done_mutex_; + bool done_; + bool joined_; + Closure* callback_; + +#ifdef _WIN32 + static DWORD WINAPI Start(LPVOID arg) { +#else + static void* Start(void* arg) { +#endif + reinterpret_cast(arg)->Run(); + return 0; + } + + void Run() { + callback_->Run(); + MutexLock lock(&done_mutex_); + done_ = true; + } + }; + + TestThread* RunInitOnceInNewThread() { + return new TestThread(NewCallback(this, &OnceInitTest::InitOnce)); + } + TestThread* RunInitRecursiveOnceInNewThread() { + return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce)); + } + + enum State { + INIT_NOT_STARTED, + INIT_STARTED, + INIT_DONE + }; + State CurrentState() { + MutexLock lock(&mutex_); + return state_; + } + + void WaitABit() { +#ifdef _WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + + private: + Mutex mutex_; + Mutex init_blocker_; + State state_; + GoogleOnceType* once_; + GoogleOnceType* recursive_once_; + + void Init() { + MutexLock lock(&mutex_); + EXPECT_EQ(INIT_NOT_STARTED, state_); + state_ = INIT_STARTED; + mutex_.Unlock(); + init_blocker_.Lock(); + init_blocker_.Unlock(); + mutex_.Lock(); + state_ = INIT_DONE; + } + + static OnceInitTest* current_test_; + static void InitStatic() { current_test_->Init(); } + static void InitRecursiveStatic() { current_test_->InitOnce(); } +}; + +OnceInitTest* OnceInitTest::current_test_ = NULL; + +GOOGLE_PROTOBUF_DECLARE_ONCE(simple_once); + +TEST_F(OnceInitTest, Simple) { + SetOnces(&simple_once, NULL); + + EXPECT_EQ(INIT_NOT_STARTED, CurrentState()); + InitOnce(); + EXPECT_EQ(INIT_DONE, CurrentState()); + + // Calling again has no effect. + InitOnce(); + EXPECT_EQ(INIT_DONE, CurrentState()); +} + +GOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once1); +GOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once2); + +TEST_F(OnceInitTest, Recursive) { + SetOnces(&recursive_once1, &recursive_once2); + + EXPECT_EQ(INIT_NOT_STARTED, CurrentState()); + InitRecursiveOnce(); + EXPECT_EQ(INIT_DONE, CurrentState()); +} + +GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_once); + +TEST_F(OnceInitTest, MultipleThreads) { + SetOnces(&multiple_threads_once, NULL); + + scoped_ptr threads[4]; + EXPECT_EQ(INIT_NOT_STARTED, CurrentState()); + for (int i = 0; i < 4; i++) { + threads[i].reset(RunInitOnceInNewThread()); + } + for (int i = 0; i < 4; i++) { + threads[i]->Join(); + } + EXPECT_EQ(INIT_DONE, CurrentState()); +} + +GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once1); +GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once2); + +TEST_F(OnceInitTest, MultipleThreadsBlocked) { + SetOnces(&multiple_threads_blocked_once1, &multiple_threads_blocked_once2); + + scoped_ptr threads[8]; + EXPECT_EQ(INIT_NOT_STARTED, CurrentState()); + + BlockInit(); + for (int i = 0; i < 4; i++) { + threads[i].reset(RunInitOnceInNewThread()); + } + for (int i = 4; i < 8; i++) { + threads[i].reset(RunInitRecursiveOnceInNewThread()); + } + + WaitABit(); + + // We should now have one thread blocked inside Init(), four blocked waiting + // for Init() to complete, and three blocked waiting for InitRecursive() to + // complete. + EXPECT_EQ(INIT_STARTED, CurrentState()); + UnblockInit(); + + for (int i = 0; i < 8; i++) { + threads[i]->Join(); + } + EXPECT_EQ(INIT_DONE, CurrentState()); +} + +} // anonymous namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 60413f6d..8b15ce5e 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -1871,6 +1871,15 @@ void TestUtil::ReflectionTester::SetPackedFieldsViaReflection( void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection( const Message& message) { + // We have to split this into three function otherwise it creates a stack + // frame so large that it triggers a warning. + ExpectAllFieldsSetViaReflection1(message); + ExpectAllFieldsSetViaReflection2(message); + ExpectAllFieldsSetViaReflection3(message); +} + +void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1( + const Message& message) { const Reflection* reflection = message.GetReflection(); string scratch; const Message* sub_message; @@ -1949,6 +1958,13 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection( EXPECT_EQ("125", reflection->GetString(message, F("optional_cord"))); EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"), &scratch)); +} + +void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection2( + const Message& message) { + const Reflection* reflection = message.GetReflection(); + string scratch; + const Message* sub_message; // ----------------------------------------------------------------- @@ -2060,6 +2076,12 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection( EXPECT_EQ("325", reflection->GetRepeatedString(message, F("repeated_cord"), 1)); EXPECT_EQ("325", reflection->GetRepeatedStringReference( message, F("repeated_cord"), 1, &scratch)); +} + +void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection3( + const Message& message) { + const Reflection* reflection = message.GetReflection(); + string scratch; // ----------------------------------------------------------------- diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index ca840c71..1bedb788 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -137,6 +137,12 @@ class TestUtil { const EnumValueDescriptor* import_bar_; const EnumValueDescriptor* import_baz_; + // We have to split this into three function otherwise it creates a stack + // frame so large that it triggers a warning. + void ExpectAllFieldsSetViaReflection1(const Message& message); + void ExpectAllFieldsSetViaReflection2(const Message& message); + void ExpectAllFieldsSetViaReflection3(const Message& message); + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionTester); }; diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index b7101661..ae88cdff 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -62,29 +62,20 @@ string Message::DebugString() const { } string Message::ShortDebugString() const { - // TODO(kenton): Make TextFormat support this natively instead of using - // DebugString() and munging the result. - string result = DebugString(); - - // Replace each contiguous range of whitespace (including newlines, and - // starting with a newline) with a single space. - int out = 0; - for (int i = 0; i < result.size(); ++i) { - if (result[i] != '\n') { - result[out++] = result[i]; - } else { - while (i < result.size() && isspace(result[i])) ++i; - --i; - result[out++] = ' '; - } - } - // Remove trailing space, if there is one. - if (out > 0 && isspace(result[out - 1])) { - --out; + string debug_string; + io::StringOutputStream output_stream(&debug_string); + + TextFormat::Printer printer; + printer.SetSingleLineMode(true); + + printer.Print(*this, &output_stream); + // Single line mode currently might have an extra space at the end. + if (debug_string.size() > 0 && + debug_string[debug_string.size() - 1] == ' ') { + debug_string.resize(debug_string.size() - 1); } - result.resize(out); - return result; + return debug_string; } void Message::PrintDebugString() const { @@ -429,9 +420,13 @@ class TextFormat::Parser::ParserImpl { return false; } - io::Tokenizer::ParseString(tokenizer_.current().text, text); + text->clear(); + while (LookingAtType(io::Tokenizer::TYPE_STRING)) { + io::Tokenizer::ParseStringAppend(tokenizer_.current().text, text); + + tokenizer_.Next(); + } - tokenizer_.Next(); return true; } @@ -591,15 +586,18 @@ class TextFormat::Parser::ParserImpl { // =========================================================================== // Internal class for writing text to the io::ZeroCopyOutputStream. Adapted // from the Printer found in //google/protobuf/io/printer.h -class TextFormat::TextGenerator { +class TextFormat::Printer::TextGenerator { public: - explicit TextGenerator(io::ZeroCopyOutputStream* output) + explicit TextGenerator(io::ZeroCopyOutputStream* output, + int initial_indent_level) : output_(output), buffer_(NULL), buffer_size_(0), at_start_of_line_(true), failed_(false), - indent_("") { + indent_(""), + initial_indent_level_(initial_indent_level) { + indent_.resize(initial_indent_level_ * 2, ' '); } ~TextGenerator() { @@ -620,7 +618,8 @@ class TextFormat::TextGenerator { // Reduces the current indent level by two spaces, or crashes if the indent // level is zero. void Outdent() { - if (indent_.empty()) { + if (indent_.empty() || + indent_.size() < initial_indent_level_ * 2) { GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent()."; return; } @@ -699,6 +698,7 @@ class TextFormat::TextGenerator { bool failed_; string indent_; + int initial_indent_level_; }; // =========================================================================== @@ -770,8 +770,16 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, return Parser().MergeFromString(input, output); } -/* static */ bool TextFormat::PrintToString(const Message& message, - string* output) { +// =========================================================================== + +TextFormat::Printer::Printer() + : initial_indent_level_(0), + single_line_mode_(false) {} + +TextFormat::Printer::~Printer() {} + +bool TextFormat::Printer::PrintToString(const Message& message, + string* output) { GOOGLE_DCHECK(output) << "output specified is NULL"; output->clear(); @@ -782,7 +790,7 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, return result; } -/* static */ bool TextFormat::PrintUnknownFieldsToString( +bool TextFormat::Printer::PrintUnknownFieldsToString( const UnknownFieldSet& unknown_fields, string* output) { GOOGLE_DCHECK(output) << "output specified is NULL"; @@ -792,9 +800,9 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, return PrintUnknownFields(unknown_fields, &output_stream); } -/* static */ bool TextFormat::Print(const Message& message, - io::ZeroCopyOutputStream* output) { - TextGenerator generator(output); +bool TextFormat::Printer::Print(const Message& message, + io::ZeroCopyOutputStream* output) { + TextGenerator generator(output, initial_indent_level_); Print(message, generator); @@ -802,10 +810,10 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, return !generator.failed(); } -/* static */ bool TextFormat::PrintUnknownFields( +bool TextFormat::Printer::PrintUnknownFields( const UnknownFieldSet& unknown_fields, io::ZeroCopyOutputStream* output) { - TextGenerator generator(output); + TextGenerator generator(output, initial_indent_level_); PrintUnknownFields(unknown_fields, generator); @@ -813,8 +821,8 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, return !generator.failed(); } -/* static */ void TextFormat::Print(const Message& message, - TextGenerator& generator) { +void TextFormat::Printer::Print(const Message& message, + TextGenerator& generator) { const Reflection* reflection = message.GetReflection(); vector fields; reflection->ListFields(message, &fields); @@ -824,7 +832,7 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, PrintUnknownFields(reflection->GetUnknownFields(message), generator); } -/* static */ void TextFormat::PrintFieldValueToString( +void TextFormat::Printer::PrintFieldValueToString( const Message& message, const FieldDescriptor* field, int index, @@ -834,15 +842,15 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, output->clear(); io::StringOutputStream output_stream(output); - TextGenerator generator(&output_stream); + TextGenerator generator(&output_stream, initial_indent_level_); PrintFieldValue(message, message.GetReflection(), field, index, generator); } -/* static */ void TextFormat::PrintField(const Message& message, - const Reflection* reflection, - const FieldDescriptor* field, - TextGenerator& generator) { +void TextFormat::Printer::PrintField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { int count = 0; if (field->is_repeated()) { @@ -874,8 +882,12 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, } if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (single_line_mode_) { + generator.Print(" { "); + } else { generator.Print(" {\n"); generator.Indent(); + } } else { generator.Print(": "); } @@ -889,15 +901,21 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, PrintFieldValue(message, reflection, field, field_index, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (!single_line_mode_) { generator.Outdent(); - generator.Print("}"); + } + generator.Print("}"); } - generator.Print("\n"); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } } } -/* static */ void TextFormat::PrintFieldValue( +void TextFormat::Printer::PrintFieldValue( const Message& message, const Reflection* reflection, const FieldDescriptor* field, @@ -961,6 +979,35 @@ bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input, } } +/* static */ bool TextFormat::Print(const Message& message, + io::ZeroCopyOutputStream* output) { + return Printer().Print(message, output); +} + +/* static */ bool TextFormat::PrintUnknownFields( + const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output) { + return Printer().PrintUnknownFields(unknown_fields, output); +} + +/* static */ bool TextFormat::PrintToString( + const Message& message, string* output) { + return Printer().PrintToString(message, output); +} + +/* static */ bool TextFormat::PrintUnknownFieldsToString( + const UnknownFieldSet& unknown_fields, string* output) { + return Printer().PrintUnknownFieldsToString(unknown_fields, output); +} + +/* static */ void TextFormat::PrintFieldValueToString( + const Message& message, + const FieldDescriptor* field, + int index, + string* output) { + return Printer().PrintFieldValueToString(message, field, index, output); +} + // Prints an integer as hex with a fixed number of digits dependent on the // integer type. template @@ -973,59 +1020,97 @@ static string PaddedHex(IntType value) { return result; } -/* static */ void TextFormat::PrintUnknownFields( +void TextFormat::Printer::PrintUnknownFields( const UnknownFieldSet& unknown_fields, TextGenerator& generator) { for (int i = 0; i < unknown_fields.field_count(); i++) { const UnknownField& field = unknown_fields.field(i); string field_number = SimpleItoa(field.number()); - for (int j = 0; j < field.varint_size(); j++) { - generator.Print(field_number); - generator.Print(": "); - generator.Print(SimpleItoa(field.varint(j))); - generator.Print("\n"); - } - for (int j = 0; j < field.fixed32_size(); j++) { - generator.Print(field_number); - generator.Print(": 0x"); - char buffer[kFastToBufferSize]; - generator.Print(FastHex32ToBuffer(field.fixed32(j), buffer)); - generator.Print("\n"); - } - for (int j = 0; j < field.fixed64_size(); j++) { - generator.Print(field_number); - generator.Print(": 0x"); - char buffer[kFastToBufferSize]; - generator.Print(FastHex64ToBuffer(field.fixed64(j), buffer)); - generator.Print("\n"); - } - for (int j = 0; j < field.length_delimited_size(); j++) { - generator.Print(field_number); - const string& value = field.length_delimited(j); - UnknownFieldSet embedded_unknown_fields; - if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) { - // This field is parseable as a Message. - // So it is probably an embedded message. - generator.Print(" {\n"); - generator.Indent(); - PrintUnknownFields(embedded_unknown_fields, generator); - generator.Outdent(); - generator.Print("}\n"); - } else { - // This field is not parseable as a Message. - // So it is probably just a plain string. - generator.Print(": \""); - generator.Print(CEscape(value)); - generator.Print("\"\n"); + switch (field.type()) { + case UnknownField::TYPE_VARINT: + generator.Print(field_number); + generator.Print(": "); + generator.Print(SimpleItoa(field.varint())); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; + case UnknownField::TYPE_FIXED32: { + generator.Print(field_number); + generator.Print(": 0x"); + char buffer[kFastToBufferSize]; + generator.Print(FastHex32ToBuffer(field.fixed32(), buffer)); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; } - } - for (int j = 0; j < field.group_size(); j++) { - generator.Print(field_number); - generator.Print(" {\n"); - generator.Indent(); - PrintUnknownFields(field.group(j), generator); - generator.Outdent(); - generator.Print("}\n"); + case UnknownField::TYPE_FIXED64: { + generator.Print(field_number); + generator.Print(": 0x"); + char buffer[kFastToBufferSize]; + generator.Print(FastHex64ToBuffer(field.fixed64(), buffer)); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + break; + } + case UnknownField::TYPE_LENGTH_DELIMITED: { + generator.Print(field_number); + const string& value = field.length_delimited(); + UnknownFieldSet embedded_unknown_fields; + if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) { + // This field is parseable as a Message. + // So it is probably an embedded message. + if (single_line_mode_) { + generator.Print(" { "); + } else { + generator.Print(" {\n"); + generator.Indent(); + } + PrintUnknownFields(embedded_unknown_fields, generator); + if (single_line_mode_) { + generator.Print("} "); + } else { + generator.Outdent(); + generator.Print("}\n"); + } + } else { + // This field is not parseable as a Message. + // So it is probably just a plain string. + generator.Print(": \""); + generator.Print(CEscape(value)); + generator.Print("\""); + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); + } + } + break; + } + case UnknownField::TYPE_GROUP: + generator.Print(field_number); + if (single_line_mode_) { + generator.Print(" { "); + } else { + generator.Print(" {\n"); + generator.Indent(); + } + PrintUnknownFields(field.group(), generator); + if (single_line_mode_) { + generator.Print("} "); + } else { + generator.Outdent(); + generator.Print("}\n"); + } + break; } } } diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index aa349b10..e2b27c68 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -82,6 +82,76 @@ class LIBPROTOBUF_EXPORT TextFormat { int index, string* output); + // Class for those users which require more fine-grained control over how + // a protobuffer message is printed out. + class LIBPROTOBUF_EXPORT Printer { + public: + Printer(); + ~Printer(); + + // Like TextFormat::Print + bool Print(const Message& message, io::ZeroCopyOutputStream* output); + // Like TextFormat::PrintUnknownFields + bool PrintUnknownFields(const UnknownFieldSet& unknown_fields, + io::ZeroCopyOutputStream* output); + // Like TextFormat::PrintToString + bool PrintToString(const Message& message, string* output); + // Like TextFormat::PrintUnknownFieldsToString + bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields, + string* output); + // Like TextFormat::PrintFieldValueToString + void PrintFieldValueToString(const Message& message, + const FieldDescriptor* field, + int index, + string* output); + + // Adjust the initial indent level of all output. Each indent level is + // equal to two spaces. + void SetInitialIndentLevel(int indent_level) { + initial_indent_level_ = indent_level; + } + + // If printing in single line mode, then the entire message will be output + // on a single line with no line breaks. + void SetSingleLineMode(bool single_line_mode) { + single_line_mode_ = single_line_mode; + } + + private: + // Forward declaration of an internal class used to print the text + // output to the OutputStream (see text_format.cc for implementation). + class TextGenerator; + + // Internal Print method, used for writing to the OutputStream via + // the TextGenerator class. + void Print(const Message& message, + TextGenerator& generator); + + // Print a single field. + void PrintField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + + // Outputs a textual representation of the value of the field supplied on + // the message supplied or the default value if not set. + void PrintFieldValue(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + int index, + TextGenerator& generator); + + // Print the fields in an UnknownFieldSet. They are printed by tag number + // only. Embedded messages are heuristically identified by attempting to + // parse them. + void PrintUnknownFields(const UnknownFieldSet& unknown_fields, + TextGenerator& generator); + + int initial_indent_level_; + + bool single_line_mode_; + }; + // Parses a text-format protocol message from the given input stream to // the given message object. This function parses the format written // by Print(). @@ -138,35 +208,6 @@ class LIBPROTOBUF_EXPORT TextFormat { }; private: - // Forward declaration of an internal class used to print the text - // output to the OutputStream (see text_format.cc for implementation). - class TextGenerator; - - // Internal Print method, used for writing to the OutputStream via - // the TextGenerator class. - static void Print(const Message& message, - TextGenerator& generator); - - // Print a single field. - static void PrintField(const Message& message, - const Reflection* reflection, - const FieldDescriptor* field, - TextGenerator& generator); - - // Outputs a textual representation of the value of the field supplied on - // the message supplied or the default value if not set. - static void PrintFieldValue(const Message& message, - const Reflection* reflection, - const FieldDescriptor* field, - int index, - TextGenerator& generator); - - // Print the fields in an UnknownFieldSet. They are printed by tag number - // only. Embedded messages are heuristically identified by attempting to - // parse them. - static void PrintUnknownFields(const UnknownFieldSet& unknown_fields, - TextGenerator& generator); - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat); }; diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 3d2cda9d..eaa278bc 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -163,18 +163,16 @@ TEST_F(TextFormatTest, PrintUnknownFields) { unittest::TestEmptyMessage message; UnknownFieldSet* unknown_fields = message.mutable_unknown_fields(); - UnknownField* field5 = unknown_fields->AddField(5); - field5->add_varint(1); - field5->add_fixed32(2); - field5->add_fixed64(3); - field5->add_length_delimited("4"); - field5->add_group()->AddField(10)->add_varint(5); + unknown_fields->AddVarint(5, 1); + unknown_fields->AddFixed32(5, 2); + unknown_fields->AddFixed64(5, 3); + unknown_fields->AddLengthDelimited(5, "4"); + unknown_fields->AddGroup(5)->AddVarint(10, 5); - UnknownField* field8 = unknown_fields->AddField(8); - field8->add_varint(1); - field8->add_varint(2); - field8->add_varint(3); + unknown_fields->AddVarint(8, 1); + unknown_fields->AddVarint(8, 2); + unknown_fields->AddVarint(8, 3); EXPECT_EQ( "5: 1\n" @@ -234,6 +232,48 @@ TEST_F(TextFormatTest, PrintUnknownMessage) { text); } +TEST_F(TextFormatTest, PrintMessageWithIndent) { + // Test adding an initial indent to printing. + + protobuf_unittest::TestAllTypes message; + + message.add_repeated_string("abc"); + message.add_repeated_string("def"); + message.add_repeated_nested_message()->set_bb(123); + + string text; + TextFormat::Printer printer; + printer.SetInitialIndentLevel(1); + EXPECT_TRUE(printer.PrintToString(message, &text)); + EXPECT_EQ( + " repeated_string: \"abc\"\n" + " repeated_string: \"def\"\n" + " repeated_nested_message {\n" + " bb: 123\n" + " }\n", + text); +} + +TEST_F(TextFormatTest, PrintMessageSingleLine) { + // Test printing a message on a single line. + + protobuf_unittest::TestAllTypes message; + + message.add_repeated_string("abc"); + message.add_repeated_string("def"); + message.add_repeated_nested_message()->set_bb(123); + + string text; + TextFormat::Printer printer; + printer.SetInitialIndentLevel(1); + printer.SetSingleLineMode(true); + EXPECT_TRUE(printer.PrintToString(message, &text)); + EXPECT_EQ( + " repeated_string: \"abc\" repeated_string: \"def\" " + "repeated_nested_message { bb: 123 } ", + text); +} + TEST_F(TextFormatTest, ParseBasic) { io::ArrayInputStream input_stream(proto_debug_string_.data(), proto_debug_string_.size()); @@ -262,6 +302,29 @@ TEST_F(TextFormatTest, ParseStringEscape) { EXPECT_EQ(kEscapeTestString, proto_.optional_string()); } +TEST_F(TextFormatTest, ParseConcatenatedString) { + // Create a parse string with multiple parts on one line. + string parse_string = "optional_string: \"foo\" \"bar\"\n"; + + io::ArrayInputStream input_stream1(parse_string.data(), + parse_string.size()); + TextFormat::Parse(&input_stream1, &proto_); + + // Compare. + EXPECT_EQ("foobar", proto_.optional_string()); + + // Create a parse string with multiple parts on seperate lines. + parse_string = "optional_string: \"foo\"\n" + "\"bar\"\n"; + + io::ArrayInputStream input_stream2(parse_string.data(), + parse_string.size()); + TextFormat::Parse(&input_stream2, &proto_); + + // Compare. + EXPECT_EQ("foobar", proto_.optional_string()); +} + TEST_F(TextFormatTest, ParseFloatWithSuffix) { // Test that we can parse a floating-point value with 'f' appended to the // end. This is needed for backwards-compatibility with proto1. diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 46ce77c3..85a14652 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -269,6 +269,14 @@ extend TestAllExtensions { optional string default_cord_extension = 85 [ctype=CORD, default="123"]; } +message TestNestedExtension { + extend TestAllExtensions { + // Check for bug where string extensions declared in tested scope did not + // compile. + optional string test = 1002 [default="test"]; + } +} + // We have separate messages for testing required fields because it's // annoying to have to fill in required fields in TestProto in order to // do anything with it. Note that we don't need to test every type of diff --git a/src/google/protobuf/unittest_empty.proto b/src/google/protobuf/unittest_empty.proto new file mode 100644 index 00000000..ab12d1fb --- /dev/null +++ b/src/google/protobuf/unittest_empty.proto @@ -0,0 +1,37 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// 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. +// +// This file intentionally left blank. (At one point this wouldn't compile +// correctly.) + diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index f42f9a59..318ffafe 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -43,38 +43,106 @@ namespace google { namespace protobuf { UnknownFieldSet::UnknownFieldSet() - : internal_(NULL) {} + : fields_(NULL) {} UnknownFieldSet::~UnknownFieldSet() { - if (internal_ != NULL) { - STLDeleteValues(&internal_->fields_); - delete internal_; - } + Clear(); + delete fields_; } void UnknownFieldSet::Clear() { - if (internal_ == NULL) return; - - if (internal_->fields_.size() > kMaxInactiveFields) { - STLDeleteValues(&internal_->fields_); - } else { - // Don't delete the UnknownField objects. Just remove them from the active - // set. - for (int i = 0; i < internal_->active_fields_.size(); i++) { - internal_->active_fields_[i]->Clear(); - internal_->active_fields_[i]->index_ = -1; + if (fields_ != NULL) { + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); } + fields_->clear(); } - - internal_->active_fields_.clear(); } void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { for (int i = 0; i < other.field_count(); i++) { - AddField(other.field(i).number())->MergeFrom(other.field(i)); + AddField(other.field(i)); } } +int UnknownFieldSet::SpaceUsedExcludingSelf() const { + if (fields_ == NULL) return 0; + + int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size(); + for (int i = 0; i < fields_->size(); i++) { + const UnknownField& field = (*fields_)[i]; + switch (field.type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + total_size += sizeof(*field.length_delimited_) + + internal::StringSpaceUsedExcludingSelf(*field.length_delimited_); + break; + case UnknownField::TYPE_GROUP: + total_size += field.group_->SpaceUsed(); + break; + default: + break; + } + } + return total_size; +} + +int UnknownFieldSet::SpaceUsed() const { + return sizeof(*this) + SpaceUsedExcludingSelf(); +} + +void UnknownFieldSet::AddVarint(int number, uint64 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_VARINT; + field.varint_ = value; + fields_->push_back(field); +} + +void UnknownFieldSet::AddFixed32(int number, uint32 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_FIXED32; + field.fixed32_ = value; + fields_->push_back(field); +} + +void UnknownFieldSet::AddFixed64(int number, uint64 value) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_FIXED64; + field.fixed64_ = value; + fields_->push_back(field); +} + +string* UnknownFieldSet::AddLengthDelimited(int number) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_LENGTH_DELIMITED; + field.length_delimited_ = new string; + fields_->push_back(field); + return field.length_delimited_; +} + +UnknownFieldSet* UnknownFieldSet::AddGroup(int number) { + if (fields_ == NULL) fields_ = new vector; + UnknownField field; + field.number_ = number; + field.type_ = UnknownField::TYPE_GROUP; + field.group_ = new UnknownFieldSet; + fields_->push_back(field); + return field.group_; +} + +void UnknownFieldSet::AddField(const UnknownField& field) { + if (fields_ == NULL) fields_ = new vector; + fields_->push_back(field); + fields_->back().DeepCopy(); +} + bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) { UnknownFieldSet other; @@ -103,129 +171,33 @@ bool UnknownFieldSet::ParseFromArray(const void* data, int size) { return ParseFromZeroCopyStream(&input); } -const UnknownField* UnknownFieldSet::FindFieldByNumber(int number) const { - if (internal_ == NULL) return NULL; - - map::iterator iter = internal_->fields_.find(number); - if (iter != internal_->fields_.end() && iter->second->index() != -1) { - return iter->second; - } else { - return NULL; +void UnknownField::Delete() { + switch (type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + delete length_delimited_; + break; + case UnknownField::TYPE_GROUP: + delete group_; + break; + default: + break; } } -UnknownField* UnknownFieldSet::AddField(int number) { - if (internal_ == NULL) internal_ = new Internal; - - UnknownField** map_slot = &internal_->fields_[number]; - if (*map_slot == NULL) { - *map_slot = new UnknownField(number); - } - - UnknownField* field = *map_slot; - if (field->index() == -1) { - field->index_ = internal_->active_fields_.size(); - internal_->active_fields_.push_back(field); - } - return field; -} - -int UnknownFieldSet::SpaceUsedExcludingSelf() const { - int total_size = 0; - if (internal_ != NULL) { - total_size += sizeof(*internal_); - total_size += internal_->active_fields_.capacity() * - sizeof(Internal::FieldVector::value_type); - total_size += internal_->fields_.size() * - sizeof(Internal::FieldMap::value_type); - - // Account for the UnknownField objects themselves. - for (Internal::FieldMap::const_iterator it = internal_->fields_.begin(), - end = internal_->fields_.end(); - it != end; - ++it) { - total_size += it->second->SpaceUsed(); +void UnknownField::DeepCopy() { + switch (type()) { + case UnknownField::TYPE_LENGTH_DELIMITED: + length_delimited_ = new string(*length_delimited_); + break; + case UnknownField::TYPE_GROUP: { + UnknownFieldSet* group = new UnknownFieldSet; + group->MergeFrom(*group_); + group_ = group; + break; } + default: + break; } - return total_size; -} - -int UnknownFieldSet::SpaceUsed() const { - return sizeof(*this) + SpaceUsedExcludingSelf(); -} - -UnknownFieldSet::Internal::FieldMap UnknownFieldSet::kEmptyMap; -const UnknownFieldSet::iterator UnknownFieldSet::kEmptyIterator( - kEmptyMap.end(), &kEmptyMap); -const UnknownFieldSet::const_iterator UnknownFieldSet::kEmptyConstIterator( - kEmptyMap.end(), &kEmptyMap); - -void UnknownFieldSet::iterator::AdvanceToNonEmpty() { - while (inner_iterator_ != inner_map_->end() && - (inner_iterator_->second->index() == -1 || - inner_iterator_->second->empty())) { - ++inner_iterator_; - } -} - -void UnknownFieldSet::const_iterator::AdvanceToNonEmpty() { - while (inner_iterator_ != inner_map_->end() && - (inner_iterator_->second->index() == -1 || - inner_iterator_->second->empty())) { - ++inner_iterator_; - } -} - -UnknownFieldSet::iterator UnknownFieldSet::begin() { - if (internal_ == NULL) return kEmptyIterator; - - UnknownFieldSet::iterator result(internal_->fields_.begin(), - &internal_->fields_); - result.AdvanceToNonEmpty(); - return result; -} - -UnknownFieldSet::const_iterator UnknownFieldSet::begin() const { - if (internal_ == NULL) return kEmptyIterator; - - UnknownFieldSet::const_iterator result(internal_->fields_.begin(), - &internal_->fields_); - result.AdvanceToNonEmpty(); - return result; -} - -UnknownField::UnknownField(int number) - : number_(number), - index_(-1) { -} - -UnknownField::~UnknownField() { -} - -void UnknownField::Clear() { - clear_varint(); - clear_fixed32(); - clear_fixed64(); - clear_length_delimited(); - clear_group(); -} - -void UnknownField::MergeFrom(const UnknownField& other) { - varint_ .MergeFrom(other.varint_ ); - fixed32_ .MergeFrom(other.fixed32_ ); - fixed64_ .MergeFrom(other.fixed64_ ); - length_delimited_.MergeFrom(other.length_delimited_); - group_ .MergeFrom(other.group_ ); -} - -int UnknownField::SpaceUsed() const { - int total_size = sizeof(*this); - total_size += varint_.SpaceUsedExcludingSelf(); - total_size += fixed32_.SpaceUsedExcludingSelf(); - total_size += fixed64_.SpaceUsedExcludingSelf(); - total_size += length_delimited_.SpaceUsedExcludingSelf(); - total_size += group_.SpaceUsedExcludingSelf(); - return total_size; } } // namespace protobuf diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index f17012df..d6ca70fc 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -39,7 +39,6 @@ #define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__ #include -#include #include #include @@ -70,13 +69,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { void Clear(); // Is this set empty? - // - // Note that this is equivalent to field_count() == 0 but is NOT necessarily - // equivalent to begin() == end(). The iterator class skips fields which are - // themselves empty, so if field_count() is non-zero but field(i)->empty() is - // true for all i, then begin() will be equal to end() but empty() will return - // false. This inconsistency almost never occurs in practice because typical - // code does not add empty fields to an UnknownFieldSet. inline bool empty() const; // Merge the contents of some other UnknownFieldSet with this one. @@ -85,13 +77,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // Swaps the contents of some other UnknownFieldSet with this one. inline void Swap(UnknownFieldSet* x); - // Find a field by field number. Returns NULL if not found. - const UnknownField* FindFieldByNumber(int number) const; - - // Add a field by field number. If the field number already exists, returns - // the existing UnknownField. - UnknownField* AddField(int number); - // Computes (an estimate of) the total number of bytes currently used for // storing the unknown fields in memory. Does NOT include // sizeof(*this) in the calculation. @@ -100,111 +85,28 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { // Version of SpaceUsed() including sizeof(*this). int SpaceUsed() const; - // STL-style iteration --------------------------------------------- - // These iterate over the non-empty UnknownFields in order by field - // number. All iterators are invalidated whenever the UnknownFieldSet - // is modified. - - class const_iterator; - - class LIBPROTOBUF_EXPORT iterator { - public: - iterator() {} - - bool operator==(const iterator& other) { - return inner_iterator_ == other.inner_iterator_; - } - bool operator!=(const iterator& other) { - return inner_iterator_ != other.inner_iterator_; - } - - UnknownField& operator*() { return *inner_iterator_->second; } - UnknownField* operator->() { return inner_iterator_->second; } - iterator& operator++() { - ++inner_iterator_; - AdvanceToNonEmpty(); - return *this; - } - iterator operator++(int) { - iterator copy(*this); - ++*this; - return copy; - } - - private: - friend class UnknownFieldSet; - friend class LIBPROTOBUF_EXPORT UnknownFieldSet::const_iterator; - iterator(map::iterator inner_iterator, - map* inner_map) - : inner_iterator_(inner_iterator), inner_map_(inner_map) {} - - void AdvanceToNonEmpty(); - - map::iterator inner_iterator_; - map* inner_map_; - }; - - class LIBPROTOBUF_EXPORT const_iterator { - public: - const_iterator() {} - const_iterator(const iterator& other) - : inner_iterator_(other.inner_iterator_), inner_map_(other.inner_map_) {} - - bool operator==(const const_iterator& other) { - return inner_iterator_ == other.inner_iterator_; - } - bool operator!=(const const_iterator& other) { - return inner_iterator_ != other.inner_iterator_; - } - - UnknownField& operator*() { return *inner_iterator_->second; } - UnknownField* operator->() { return inner_iterator_->second; } - const_iterator& operator++() { - ++inner_iterator_; - AdvanceToNonEmpty(); - return *this; - } - const_iterator operator++(int) { - const_iterator copy(*this); - ++*this; - return copy; - } - - private: - friend class UnknownFieldSet; - const_iterator(map::const_iterator inner_iterator, - const map* inner_map) - : inner_iterator_(inner_iterator), inner_map_(inner_map) {} - - void AdvanceToNonEmpty(); - - map::const_iterator inner_iterator_; - const map* inner_map_; - }; - - iterator begin(); - iterator end() { - return internal_ == NULL ? kEmptyIterator : - iterator(internal_->fields_.end(), &internal_->fields_); - } - const_iterator begin() const; - const_iterator end() const { - return internal_ == NULL ? kEmptyConstIterator : - const_iterator(internal_->fields_.end(), &internal_->fields_); - } - - // Old-style iteration --------------------------------------------- - // New code should use begin() and end() rather than these methods. - // Returns the number of fields present in the UnknownFieldSet. inline int field_count() const; // Get a field in the set, where 0 <= index < field_count(). The fields - // appear in arbitrary order. + // appear in the order in which they were added. inline const UnknownField& field(int index) const; // Get a mutable pointer to a field in the set, where - // 0 <= index < field_count(). The fields appear in arbitrary order. + // 0 <= index < field_count(). The fields appear in the order in which + // they were added. inline UnknownField* mutable_field(int index); + // Adding fields --------------------------------------------------- + + void AddVarint(int number, uint64 value); + void AddFixed32(int number, uint32 value); + void AddFixed64(int number, uint64 value); + void AddLengthDelimited(int number, const string& value); + string* AddLengthDelimited(int number); + UnknownFieldSet* AddGroup(int number); + + // Adds an unknown field from another set. + void AddField(const UnknownField& field); + // Parsing helpers ------------------------------------------------- // These work exactly like the similarly-named methods of Message. @@ -217,268 +119,139 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { } private: - // "Active" fields are ones which have been added since the last time Clear() - // was called. Inactive fields are objects we are keeping around incase - // they become active again. - - struct Internal { - // Contains all UnknownFields that have been allocated for this - // UnknownFieldSet, including ones not currently active. Keyed by - // field number. We intentionally try to reuse UnknownField objects for - // the same field number they were used for originally because this makes - // it more likely that the previously-allocated memory will have the right - // layout. - typedef map FieldMap; - FieldMap fields_; - - // Contains the fields from fields_ that are currently active. - typedef vector FieldVector; - FieldVector active_fields_; - }; - - // We want an UnknownFieldSet to use no more space than a single pointer - // until the first field is added. - Internal* internal_; - - // Don't keep more inactive fields than this. - static const int kMaxInactiveFields = 100; - - // Used by begin() and end() when internal_ is NULL. - static Internal::FieldMap kEmptyMap; - static const iterator kEmptyIterator; - static const const_iterator kEmptyConstIterator; + vector* fields_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); }; // Represents one field in an UnknownFieldSet. -// -// UnknownField's accessors are similar to those that would be produced by the -// protocol compiler for the fields: -// repeated uint64 varint; -// repeated fixed32 fixed32; -// repeated fixed64 fixed64; -// repeated bytes length_delimited; -// repeated UnknownFieldSet group; -// (OK, so the last one isn't actually a valid field type but you get the -// idea.) class LIBPROTOBUF_EXPORT UnknownField { public: - ~UnknownField(); + enum Type { + TYPE_VARINT, + TYPE_FIXED32, + TYPE_FIXED64, + TYPE_LENGTH_DELIMITED, + TYPE_GROUP + }; - // Clears all fields. - void Clear(); + // The field's tag number, as seen on the wire. + inline int number() const; - // Is this field empty? (I.e. all of the *_size() methods return zero.) - inline bool empty() const; + // The field type. + inline Type type() const; - // Merge the contents of some other UnknownField with this one. For each - // wire type, the values are simply concatenated. - void MergeFrom(const UnknownField& other); + // Accessors ------------------------------------------------------- + // Each method works only for UnknownFields of the corresponding type. - // The field's tag number, as seen on the wire. - inline int number() const; + inline uint64 varint() const; + inline uint32 fixed32() const; + inline uint64 fixed64() const; + inline const string& length_delimited() const; + inline const UnknownFieldSet& group() const; - // The index of this UnknownField within the UnknownFieldSet (e.g. - // set.field(field.index()) == field). - inline int index() const; - - inline int varint_size () const; - inline int fixed32_size () const; - inline int fixed64_size () const; - inline int length_delimited_size() const; - inline int group_size () const; - - inline uint64 varint (int index) const; - inline uint32 fixed32(int index) const; - inline uint64 fixed64(int index) const; - inline const string& length_delimited(int index) const; - inline const UnknownFieldSet& group(int index) const; - - inline void set_varint (int index, uint64 value); - inline void set_fixed32(int index, uint32 value); - inline void set_fixed64(int index, uint64 value); - inline void set_length_delimited(int index, const string& value); - inline string* mutable_length_delimited(int index); - inline UnknownFieldSet* mutable_group(int index); - - inline void add_varint (uint64 value); - inline void add_fixed32(uint32 value); - inline void add_fixed64(uint64 value); - inline void add_length_delimited(const string& value); - inline string* add_length_delimited(); - inline UnknownFieldSet* add_group(); - - inline void clear_varint (); - inline void clear_fixed32(); - inline void clear_fixed64(); - inline void clear_length_delimited(); - inline void clear_group(); - - inline const RepeatedField & varint () const; - inline const RepeatedField & fixed32 () const; - inline const RepeatedField & fixed64 () const; - inline const RepeatedPtrField& length_delimited() const; - inline const RepeatedPtrField& group () const; - - inline RepeatedField * mutable_varint (); - inline RepeatedField * mutable_fixed32 (); - inline RepeatedField * mutable_fixed64 (); - inline RepeatedPtrField* mutable_length_delimited(); - inline RepeatedPtrField* mutable_group (); - - // Returns (an estimate of) the total number of bytes used to represent the - // unknown field. - int SpaceUsed() const; + inline void set_varint(uint64 value); + inline void set_fixed32(uint32 value); + inline void set_fixed64(uint64 value); + inline void set_length_delimited(const string& value); + inline string* mutable_length_delimited(); + inline UnknownFieldSet* mutable_group(); private: friend class UnknownFieldSet; - UnknownField(int number); - int number_; - int index_; + // If this UnknownField contains a pointer, delete it. + void Delete(); - RepeatedField varint_; - RepeatedField fixed32_; - RepeatedField fixed64_; - RepeatedPtrField length_delimited_; - RepeatedPtrField group_; + // Make a deep copy of any pointers in this UnknownField. + void DeepCopy(); - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownField); + unsigned int number_ : 29; + unsigned int type_ : 3; + union { + uint64 varint_; + uint32 fixed32_; + uint64 fixed64_; + string* length_delimited_; + UnknownFieldSet* group_; + }; }; // =================================================================== // inline implementations inline bool UnknownFieldSet::empty() const { - return internal_ == NULL || internal_->active_fields_.empty(); + return fields_ == NULL || fields_->empty(); } inline void UnknownFieldSet::Swap(UnknownFieldSet* x) { - std::swap(internal_, x->internal_); + std::swap(fields_, x->fields_); } inline int UnknownFieldSet::field_count() const { - return (internal_ == NULL) ? 0 : internal_->active_fields_.size(); + return (fields_ == NULL) ? 0 : fields_->size(); } inline const UnknownField& UnknownFieldSet::field(int index) const { - return *(internal_->active_fields_[index]); + return (*fields_)[index]; } inline UnknownField* UnknownFieldSet::mutable_field(int index) { - return internal_->active_fields_[index]; + return &(*fields_)[index]; } -inline bool UnknownField::empty() const { - return varint_.size() == 0 && - fixed32_.size() == 0 && - fixed64_.size() == 0 && - length_delimited_.size() == 0 && - group_.size() == 0; +inline void UnknownFieldSet::AddLengthDelimited( + int number, const string& value) { + AddLengthDelimited(number)->assign(value); } inline int UnknownField::number() const { return number_; } -inline int UnknownField::index () const { return index_; } - -inline int UnknownField::varint_size () const {return varint_.size();} -inline int UnknownField::fixed32_size () const {return fixed32_.size();} -inline int UnknownField::fixed64_size () const {return fixed64_.size();} -inline int UnknownField::length_delimited_size() const { - return length_delimited_.size(); +inline UnknownField::Type UnknownField::type() const { + return static_cast(type_); } -inline int UnknownField::group_size () const {return group_.size();} -inline uint64 UnknownField::varint (int index) const { - return varint_.Get(index); -} -inline uint32 UnknownField::fixed32(int index) const { - return fixed32_.Get(index); -} -inline uint64 UnknownField::fixed64(int index) const { - return fixed64_.Get(index); -} -inline const string& UnknownField::length_delimited(int index) const { - return length_delimited_.Get(index); -} -inline const UnknownFieldSet& UnknownField::group(int index) const { - return group_.Get(index); -} - -inline void UnknownField::set_varint (int index, uint64 value) { - varint_.Set(index, value); -} -inline void UnknownField::set_fixed32(int index, uint32 value) { - fixed32_.Set(index, value); -} -inline void UnknownField::set_fixed64(int index, uint64 value) { - fixed64_.Set(index, value); -} -inline void UnknownField::set_length_delimited(int index, const string& value) { - length_delimited_.Mutable(index)->assign(value); -} -inline string* UnknownField::mutable_length_delimited(int index) { - return length_delimited_.Mutable(index); -} -inline UnknownFieldSet* UnknownField::mutable_group(int index) { - return group_.Mutable(index); -} - -inline void UnknownField::add_varint (uint64 value) { - varint_.Add(value); -} -inline void UnknownField::add_fixed32(uint32 value) { - fixed32_.Add(value); -} -inline void UnknownField::add_fixed64(uint64 value) { - fixed64_.Add(value); -} -inline void UnknownField::add_length_delimited(const string& value) { - length_delimited_.Add()->assign(value); -} -inline string* UnknownField::add_length_delimited() { - return length_delimited_.Add(); -} -inline UnknownFieldSet* UnknownField::add_group() { - return group_.Add(); -} - -inline void UnknownField::clear_varint () { varint_.Clear(); } -inline void UnknownField::clear_fixed32() { fixed32_.Clear(); } -inline void UnknownField::clear_fixed64() { fixed64_.Clear(); } -inline void UnknownField::clear_length_delimited() { - length_delimited_.Clear(); -} -inline void UnknownField::clear_group() { group_.Clear(); } - -inline const RepeatedField& UnknownField::varint () const { +inline uint64 UnknownField::varint () const { + GOOGLE_DCHECK_EQ(type_, TYPE_VARINT); return varint_; } -inline const RepeatedField& UnknownField::fixed32() const { +inline uint32 UnknownField::fixed32() const { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32); return fixed32_; } -inline const RepeatedField& UnknownField::fixed64() const { +inline uint64 UnknownField::fixed64() const { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64); return fixed64_; } -inline const RepeatedPtrField& UnknownField::length_delimited() const { - return length_delimited_; +inline const string& UnknownField::length_delimited() const { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + return *length_delimited_; } -inline const RepeatedPtrField& UnknownField::group() const { - return group_; +inline const UnknownFieldSet& UnknownField::group() const { + GOOGLE_DCHECK_EQ(type_, TYPE_GROUP); + return *group_; } -inline RepeatedField* UnknownField::mutable_varint () { - return &varint_; +inline void UnknownField::set_varint(uint64 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_VARINT); + varint_ = value; } -inline RepeatedField* UnknownField::mutable_fixed32() { - return &fixed32_; +inline void UnknownField::set_fixed32(uint32 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32); + fixed32_ = value; } -inline RepeatedField* UnknownField::mutable_fixed64() { - return &fixed64_; +inline void UnknownField::set_fixed64(uint64 value) { + GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64); + fixed64_ = value; } -inline RepeatedPtrField* UnknownField::mutable_length_delimited() { - return &length_delimited_; +inline void UnknownField::set_length_delimited(const string& value) { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + length_delimited_->assign(value); } -inline RepeatedPtrField* UnknownField::mutable_group() { - return &group_; +inline string* UnknownField::mutable_length_delimited() { + GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED); + return length_delimited_; +} +inline UnknownFieldSet* UnknownField::mutable_group() { + GOOGLE_DCHECK_EQ(type_, TYPE_GROUP); + return group_; } } // namespace protobuf diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index 0a75af9f..1235c9ee 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -37,8 +37,8 @@ #include #include -#include #include +#include #include #include #include @@ -46,6 +46,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -67,7 +68,12 @@ class UnknownFieldSetTest : public testing::Test { const UnknownField* GetField(const string& name) { const FieldDescriptor* field = descriptor_->FindFieldByName(name); if (field == NULL) return NULL; - return unknown_fields_->FindFieldByNumber(field->number()); + for (int i = 0; i < unknown_fields_->field_count(); i++) { + if (unknown_fields_->field(i).number() == field->number()) { + return &unknown_fields_->field(i); + } + } + return NULL; } // Constructs a protocol buffer which contains fields with all the same @@ -79,12 +85,10 @@ class UnknownFieldSetTest : public testing::Test { bizarro_message.mutable_unknown_fields(); for (int i = 0; i < unknown_fields_->field_count(); i++) { const UnknownField& unknown_field = unknown_fields_->field(i); - UnknownField* bizarro_field = - bizarro_unknown_fields->AddField(unknown_field.number()); - if (unknown_field.varint_size() == 0) { - bizarro_field->add_varint(1); + if (unknown_field.type() == UnknownField::TYPE_VARINT) { + bizarro_unknown_fields->AddFixed32(unknown_field.number(), 1); } else { - bizarro_field->add_fixed32(1); + bizarro_unknown_fields->AddVarint(unknown_field.number(), 1); } } @@ -103,71 +107,98 @@ class UnknownFieldSetTest : public testing::Test { UnknownFieldSet* unknown_fields_; }; -TEST_F(UnknownFieldSetTest, Index) { - for (int i = 0; i < unknown_fields_->field_count(); i++) { - EXPECT_EQ(i, unknown_fields_->field(i).index()); - } -} +TEST_F(UnknownFieldSetTest, AllFieldsPresent) { + // All fields of TestAllTypes should be present, in numeric order (because + // that's the order we parsed them in). Fields that are not valid field + // numbers of TestAllTypes should NOT be present. -TEST_F(UnknownFieldSetTest, FindFieldByNumber) { - // All fields of TestAllTypes should be present. Fields that are not valid - // field numbers of TestAllTypes should NOT be present. + int pos = 0; for (int i = 0; i < 1000; i++) { - if (descriptor_->FindFieldByNumber(i) == NULL) { - EXPECT_TRUE(unknown_fields_->FindFieldByNumber(i) == NULL); - } else { - EXPECT_TRUE(unknown_fields_->FindFieldByNumber(i) != NULL); + const FieldDescriptor* field = descriptor_->FindFieldByNumber(i); + if (field != NULL) { + ASSERT_LT(pos, unknown_fields_->field_count()); + EXPECT_EQ(i, unknown_fields_->field(pos++).number()); + if (field->is_repeated()) { + // Should have a second instance. + ASSERT_LT(pos, unknown_fields_->field_count()); + EXPECT_EQ(i, unknown_fields_->field(pos++).number()); + } } } + EXPECT_EQ(unknown_fields_->field_count(), pos); } TEST_F(UnknownFieldSetTest, Varint) { const UnknownField* field = GetField("optional_int32"); ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->varint_size()); - EXPECT_EQ(all_fields_.optional_int32(), field->varint(0)); + ASSERT_EQ(UnknownField::TYPE_VARINT, field->type()); + EXPECT_EQ(all_fields_.optional_int32(), field->varint()); } TEST_F(UnknownFieldSetTest, Fixed32) { const UnknownField* field = GetField("optional_fixed32"); ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->fixed32_size()); - EXPECT_EQ(all_fields_.optional_fixed32(), field->fixed32(0)); + ASSERT_EQ(UnknownField::TYPE_FIXED32, field->type()); + EXPECT_EQ(all_fields_.optional_fixed32(), field->fixed32()); } TEST_F(UnknownFieldSetTest, Fixed64) { const UnknownField* field = GetField("optional_fixed64"); ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->fixed64_size()); - EXPECT_EQ(all_fields_.optional_fixed64(), field->fixed64(0)); + ASSERT_EQ(UnknownField::TYPE_FIXED64, field->type()); + EXPECT_EQ(all_fields_.optional_fixed64(), field->fixed64()); } TEST_F(UnknownFieldSetTest, LengthDelimited) { const UnknownField* field = GetField("optional_string"); ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->length_delimited_size()); - EXPECT_EQ(all_fields_.optional_string(), field->length_delimited(0)); + ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED, field->type()); + EXPECT_EQ(all_fields_.optional_string(), field->length_delimited()); } TEST_F(UnknownFieldSetTest, Group) { const UnknownField* field = GetField("optionalgroup"); ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->group_size()); - EXPECT_EQ(1, field->group(0).field_count()); + ASSERT_EQ(UnknownField::TYPE_GROUP, field->type()); + ASSERT_EQ(1, field->group().field_count()); - const UnknownField& nested_field = field->group(0).field(0); + const UnknownField& nested_field = field->group().field(0); const FieldDescriptor* nested_field_descriptor = unittest::TestAllTypes::OptionalGroup::descriptor()->FindFieldByName("a"); ASSERT_TRUE(nested_field_descriptor != NULL); EXPECT_EQ(nested_field_descriptor->number(), nested_field.number()); - EXPECT_EQ(all_fields_.optionalgroup().a(), nested_field.varint(0)); + ASSERT_EQ(UnknownField::TYPE_VARINT, nested_field.type()); + EXPECT_EQ(all_fields_.optionalgroup().a(), nested_field.varint()); +} + +TEST_F(UnknownFieldSetTest, SerializeFastAndSlowAreEquivalent) { + int size = WireFormat::ComputeUnknownFieldsSize( + empty_message_.unknown_fields()); + string slow_buffer; + string fast_buffer; + slow_buffer.resize(size); + fast_buffer.resize(size); + + uint8* target = reinterpret_cast(string_as_array(&fast_buffer)); + uint8* result = WireFormat::SerializeUnknownFieldsToArray( + empty_message_.unknown_fields(), target); + EXPECT_EQ(size, result - target); + + { + io::ArrayOutputStream raw_stream(string_as_array(&slow_buffer), size, 1); + io::CodedOutputStream output_stream(&raw_stream); + WireFormat::SerializeUnknownFields(empty_message_.unknown_fields(), + &output_stream); + ASSERT_FALSE(output_stream.HadError()); + } + EXPECT_TRUE(fast_buffer == slow_buffer); } TEST_F(UnknownFieldSetTest, Serialize) { @@ -205,8 +236,8 @@ TEST_F(UnknownFieldSetTest, SerializeViaReflection) { io::StringOutputStream raw_output(&data); io::CodedOutputStream output(&raw_output); int size = WireFormat::ByteSize(empty_message_); - ASSERT_TRUE( - WireFormat::SerializeWithCachedSizes(empty_message_, size, &output)); + WireFormat::SerializeWithCachedSizes(empty_message_, size, &output); + ASSERT_FALSE(output.HadError()); } // Don't use EXPECT_EQ because we don't want to dump raw binary data to @@ -249,10 +280,10 @@ TEST_F(UnknownFieldSetTest, SwapWithSelf) { TEST_F(UnknownFieldSetTest, MergeFrom) { unittest::TestEmptyMessage source, destination; - destination.mutable_unknown_fields()->AddField(1)->add_varint(1); - destination.mutable_unknown_fields()->AddField(3)->add_varint(2); - source.mutable_unknown_fields()->AddField(2)->add_varint(3); - source.mutable_unknown_fields()->AddField(3)->add_varint(4); + destination.mutable_unknown_fields()->AddVarint(1, 1); + destination.mutable_unknown_fields()->AddVarint(3, 2); + source.mutable_unknown_fields()->AddVarint(2, 3); + source.mutable_unknown_fields()->AddVarint(3, 4); destination.MergeFrom(source); @@ -261,34 +292,22 @@ TEST_F(UnknownFieldSetTest, MergeFrom) { // and merging, above. "1: 1\n" "3: 2\n" - "3: 4\n" - "2: 3\n", + "2: 3\n" + "3: 4\n", destination.DebugString()); } TEST_F(UnknownFieldSetTest, Clear) { - // Get a pointer to a contained field object. - const UnknownField* field = GetField("optional_int32"); - ASSERT_TRUE(field != NULL); - ASSERT_EQ(1, field->varint_size()); - int number = field->number(); - // Clear the set. empty_message_.Clear(); EXPECT_EQ(0, unknown_fields_->field_count()); - - // If we add that field again we should get the same object. - ASSERT_EQ(field, unknown_fields_->AddField(number)); - - // But it should be cleared. - EXPECT_EQ(0, field->varint_size()); } TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) { // Test mixing known and unknown fields when parsing. unittest::TestEmptyMessage source; - source.mutable_unknown_fields()->AddField(123456)->add_varint(654321); + source.mutable_unknown_fields()->AddVarint(123456, 654321); string data; ASSERT_TRUE(source.SerializeToString(&data)); @@ -297,8 +316,9 @@ TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) { TestUtil::ExpectAllFieldsSet(destination); ASSERT_EQ(1, destination.unknown_fields().field_count()); - ASSERT_EQ(1, destination.unknown_fields().field(0).varint_size()); - EXPECT_EQ(654321, destination.unknown_fields().field(0).varint(0)); + ASSERT_EQ(UnknownField::TYPE_VARINT, + destination.unknown_fields().field(0).type()); + EXPECT_EQ(654321, destination.unknown_fields().field(0).varint()); } TEST_F(UnknownFieldSetTest, WrongTypeTreatedAsUnknown) { @@ -384,16 +404,12 @@ TEST_F(UnknownFieldSetTest, UnknownEnumValue) { { TestEmptyMessage empty_message; UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields(); - UnknownField* singular_unknown_field = - unknown_fields->AddField(singular_field->number()); - singular_unknown_field->add_varint(TestAllTypes::BAR); - singular_unknown_field->add_varint(5); // not valid - UnknownField* repeated_unknown_field = - unknown_fields->AddField(repeated_field->number()); - repeated_unknown_field->add_varint(TestAllTypes::FOO); - repeated_unknown_field->add_varint(4); // not valid - repeated_unknown_field->add_varint(TestAllTypes::BAZ); - repeated_unknown_field->add_varint(6); // not valid + unknown_fields->AddVarint(singular_field->number(), TestAllTypes::BAR); + unknown_fields->AddVarint(singular_field->number(), 5); // not valid + unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::FOO); + unknown_fields->AddVarint(repeated_field->number(), 4); // not valid + unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::BAZ); + unknown_fields->AddVarint(repeated_field->number(), 6); // not valid empty_message.SerializeToString(&data); } @@ -406,18 +422,19 @@ TEST_F(UnknownFieldSetTest, UnknownEnumValue) { EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(1)); const UnknownFieldSet& unknown_fields = message.unknown_fields(); - ASSERT_EQ(2, unknown_fields.field_count()); - - const UnknownField& singular_unknown_field = unknown_fields.field(0); - ASSERT_EQ(singular_field->number(), singular_unknown_field.number()); - ASSERT_EQ(1, singular_unknown_field.varint_size()); - EXPECT_EQ(5, singular_unknown_field.varint(0)); - - const UnknownField& repeated_unknown_field = unknown_fields.field(1); - ASSERT_EQ(repeated_field->number(), repeated_unknown_field.number()); - ASSERT_EQ(2, repeated_unknown_field.varint_size()); - EXPECT_EQ(4, repeated_unknown_field.varint(0)); - EXPECT_EQ(6, repeated_unknown_field.varint(1)); + ASSERT_EQ(3, unknown_fields.field_count()); + + EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type()); + EXPECT_EQ(5, unknown_fields.field(0).varint()); + + EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type()); + EXPECT_EQ(4, unknown_fields.field(1).varint()); + + EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type()); + EXPECT_EQ(6, unknown_fields.field(2).varint()); } { @@ -435,173 +452,61 @@ TEST_F(UnknownFieldSetTest, UnknownEnumValue) { message.GetExtension(repeated_nested_enum_extension, 1)); const UnknownFieldSet& unknown_fields = message.unknown_fields(); - ASSERT_EQ(2, unknown_fields.field_count()); - - const UnknownField& singular_unknown_field = unknown_fields.field(0); - ASSERT_EQ(singular_field->number(), singular_unknown_field.number()); - ASSERT_EQ(1, singular_unknown_field.varint_size()); - EXPECT_EQ(5, singular_unknown_field.varint(0)); - - const UnknownField& repeated_unknown_field = unknown_fields.field(1); - ASSERT_EQ(repeated_field->number(), repeated_unknown_field.number()); - ASSERT_EQ(2, repeated_unknown_field.varint_size()); - EXPECT_EQ(4, repeated_unknown_field.varint(0)); - EXPECT_EQ(6, repeated_unknown_field.varint(1)); - } -} + ASSERT_EQ(3, unknown_fields.field_count()); -TEST_F(UnknownFieldSetTest, SpaceUsedExcludingSelf) { - { - // Make sure an unknown field set has zero space used until a field is - // actually added. - unittest::TestEmptyMessage empty_message; - const int empty_message_size = empty_message.SpaceUsed(); - UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields(); - EXPECT_EQ(empty_message_size, empty_message.SpaceUsed()); - unknown_fields->AddField(1)->add_varint(0); - EXPECT_LT(empty_message_size, empty_message.SpaceUsed()); - } - { - // Test varints. - UnknownFieldSet unknown_fields; - UnknownField* field = unknown_fields.AddField(1); - const int base_size = unknown_fields.SpaceUsedExcludingSelf(); - for (int i = 0; i < 16; ++i) { - field->add_varint(i); - } - // Should just defer computation to the RepeatedField. - int expected_size = base_size + field->varint().SpaceUsedExcludingSelf(); - EXPECT_EQ(expected_size, unknown_fields.SpaceUsedExcludingSelf()); - } - { - // Test fixed32s. - UnknownFieldSet unknown_fields; - UnknownField* field = unknown_fields.AddField(1); - const int base_size = unknown_fields.SpaceUsedExcludingSelf(); - for (int i = 0; i < 16; ++i) { - field->add_fixed32(i); - } - int expected_size = base_size + field->fixed32().SpaceUsedExcludingSelf(); - EXPECT_EQ(expected_size, unknown_fields.SpaceUsedExcludingSelf()); - } - { - // Test fixed64s. - UnknownFieldSet unknown_fields; - UnknownField* field = unknown_fields.AddField(1); - const int base_size = unknown_fields.SpaceUsedExcludingSelf(); - for (int i = 0; i < 16; ++i) { - field->add_fixed64(i); - } - int expected_size = base_size + field->fixed64().SpaceUsedExcludingSelf(); - EXPECT_EQ(expected_size, unknown_fields.SpaceUsedExcludingSelf()); - } - { - // Test length-delimited types. - UnknownFieldSet unknown_fields; - UnknownField* field = unknown_fields.AddField(1); - const int base_size = unknown_fields.SpaceUsedExcludingSelf(); - for (int i = 0; i < 16; ++i) { - field->add_length_delimited()->assign("my length delimited string"); - } - int expected_size = base_size + - field->length_delimited().SpaceUsedExcludingSelf(); - EXPECT_EQ(expected_size, unknown_fields.SpaceUsedExcludingSelf()); + EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type()); + EXPECT_EQ(5, unknown_fields.field(0).varint()); + + EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type()); + EXPECT_EQ(4, unknown_fields.field(1).varint()); + + EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number()); + ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type()); + EXPECT_EQ(6, unknown_fields.field(2).varint()); } } TEST_F(UnknownFieldSetTest, SpaceUsed) { - UnknownFieldSet unknown_fields; - const int expected_size = sizeof(unknown_fields) + - unknown_fields.SpaceUsedExcludingSelf(); - EXPECT_EQ(expected_size, unknown_fields.SpaceUsed()); + unittest::TestEmptyMessage empty_message; + + // Make sure an unknown field set has zero space used until a field is + // actually added. + int base_size = empty_message.SpaceUsed(); + UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields(); + EXPECT_EQ(base_size, empty_message.SpaceUsed()); + + // Make sure each thing we add to the set increases the SpaceUsed(). + unknown_fields->AddVarint(1, 0); + EXPECT_LT(base_size, empty_message.SpaceUsed()); + base_size = empty_message.SpaceUsed(); + + string* str = unknown_fields->AddLengthDelimited(1); + EXPECT_LT(base_size, empty_message.SpaceUsed()); + base_size = empty_message.SpaceUsed(); + + str->assign(sizeof(string) + 1, 'x'); + EXPECT_LT(base_size, empty_message.SpaceUsed()); + base_size = empty_message.SpaceUsed(); + + UnknownFieldSet* group = unknown_fields->AddGroup(1); + EXPECT_LT(base_size, empty_message.SpaceUsed()); + base_size = empty_message.SpaceUsed(); + + group->AddVarint(1, 0); + EXPECT_LT(base_size, empty_message.SpaceUsed()); } TEST_F(UnknownFieldSetTest, Empty) { UnknownFieldSet unknown_fields; EXPECT_TRUE(unknown_fields.empty()); - unknown_fields.AddField(6)->add_varint(123); + unknown_fields.AddVarint(6, 123); EXPECT_FALSE(unknown_fields.empty()); unknown_fields.Clear(); EXPECT_TRUE(unknown_fields.empty()); } -TEST_F(UnknownFieldSetTest, FieldEmpty) { - UnknownFieldSet unknown_fields; - UnknownField* field = unknown_fields.AddField(1); - - EXPECT_TRUE(field->empty()); - - field->add_varint(1); - EXPECT_FALSE(field->empty()); - field->Clear(); - EXPECT_TRUE(field->empty()); - - field->add_fixed32(1); - EXPECT_FALSE(field->empty()); - field->Clear(); - EXPECT_TRUE(field->empty()); - - field->add_fixed64(1); - EXPECT_FALSE(field->empty()); - field->Clear(); - EXPECT_TRUE(field->empty()); - - field->add_length_delimited("foo"); - EXPECT_FALSE(field->empty()); - field->Clear(); - EXPECT_TRUE(field->empty()); - - field->add_group(); - EXPECT_FALSE(field->empty()); - field->Clear(); - EXPECT_TRUE(field->empty()); -} - -TEST_F(UnknownFieldSetTest, Iterator) { - UnknownFieldSet unknown_fields; - EXPECT_TRUE(unknown_fields.begin() == unknown_fields.end()); - - // Populate the UnknownFieldSet with some inactive fields by adding some - // fields and then clearing. - unknown_fields.AddField(6); - unknown_fields.AddField(4); - unknown_fields.Clear(); - - // Add a bunch of "active" fields. - UnknownField* a = unknown_fields.AddField(5); - unknown_fields.AddField(3); - unknown_fields.AddField(9); - unknown_fields.AddField(1); - UnknownField* b = unknown_fields.AddField(2); - - // Only make some of them non-empty. - a->add_varint(1); - b->add_length_delimited("foo"); - - // Iterate! - { - UnknownFieldSet::iterator iter = unknown_fields.begin(); - ASSERT_TRUE(iter != unknown_fields.end()); - EXPECT_EQ(b, &*iter); - ++iter; - ASSERT_TRUE(iter != unknown_fields.end()); - EXPECT_EQ(a, &*iter); - ++iter; - EXPECT_TRUE(iter == unknown_fields.end()); - } - - { - UnknownFieldSet::const_iterator iter = unknown_fields.begin(); - ASSERT_TRUE(iter != unknown_fields.end()); - EXPECT_EQ(b, &*iter); - ++iter; - ASSERT_TRUE(iter != unknown_fields.end()); - EXPECT_EQ(a, &*iter); - ++iter; - EXPECT_TRUE(iter == unknown_fields.end()); - } -} - } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index aeea3ccb..dbd39b83 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -109,29 +109,29 @@ WireFormat::kWireTypeForFieldType[FieldDescriptor::MAX_TYPE + 1] = { bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, UnknownFieldSet* unknown_fields) { - UnknownField* field = (unknown_fields == NULL) ? NULL : - unknown_fields->AddField(GetTagFieldNumber(tag)); + int number = GetTagFieldNumber(tag); switch (GetTagWireType(tag)) { case WIRETYPE_VARINT: { uint64 value; if (!input->ReadVarint64(&value)) return false; - if (field != NULL) field->add_varint(value); + if (unknown_fields != NULL) unknown_fields->AddVarint(number, value); return true; } case WIRETYPE_FIXED64: { uint64 value; if (!input->ReadLittleEndian64(&value)) return false; - if (field != NULL) field->add_fixed64(value); + if (unknown_fields != NULL) unknown_fields->AddFixed64(number, value); return true; } case WIRETYPE_LENGTH_DELIMITED: { uint32 length; if (!input->ReadVarint32(&length)) return false; - if (field == NULL) { + if (unknown_fields == NULL) { if (!input->Skip(length)) return false; } else { - if (!input->ReadString(field->add_length_delimited(), length)) { + if (!input->ReadString(unknown_fields->AddLengthDelimited(number), + length)) { return false; } } @@ -139,7 +139,8 @@ bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, } case WIRETYPE_START_GROUP: { if (!input->IncrementRecursionDepth()) return false; - if (!SkipMessage(input, (field == NULL) ? NULL : field->add_group())) { + if (!SkipMessage(input, (unknown_fields == NULL) ? + NULL : unknown_fields->AddGroup(number))) { return false; } input->DecrementRecursionDepth(); @@ -156,7 +157,7 @@ bool WireFormat::SkipField(io::CodedInputStream* input, uint32 tag, case WIRETYPE_FIXED32: { uint32 value; if (!input->ReadLittleEndian32(&value)) return false; - if (field != NULL) field->add_fixed32(value); + if (unknown_fields != NULL) unknown_fields->AddFixed32(number, value); return true; } default: { @@ -185,72 +186,130 @@ bool WireFormat::SkipMessage(io::CodedInputStream* input, } } -bool WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, +void WireFormat::SerializeUnknownFields(const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) { for (int i = 0; i < unknown_fields.field_count(); i++) { const UnknownField& field = unknown_fields.field(i); - -#define DO(EXPRESSION) if (!(EXPRESSION)) return false - for (int j = 0; j < field.varint_size(); j++) { - DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_VARINT))); - DO(output->WriteVarint64(field.varint(j))); - } - for (int j = 0; j < field.fixed32_size(); j++) { - DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED32))); - DO(output->WriteLittleEndian32(field.fixed32(j))); - } - for (int j = 0; j < field.fixed64_size(); j++) { - DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED64))); - DO(output->WriteLittleEndian64(field.fixed64(j))); - } - for (int j = 0; j < field.length_delimited_size(); j++) { - DO(output->WriteVarint32( - MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED))); - DO(output->WriteVarint32(field.length_delimited(j).size())); - DO(output->WriteString(field.length_delimited(j))); - } - for (int j = 0; j < field.group_size(); j++) { - DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_START_GROUP))); - DO(SerializeUnknownFields(field.group(j), output)); - DO(output->WriteVarint32(MakeTag(field.number(), WIRETYPE_END_GROUP))); + switch (field.type()) { + case UnknownField::TYPE_VARINT: + output->WriteVarint32(MakeTag(field.number(), WIRETYPE_VARINT)); + output->WriteVarint64(field.varint()); + break; + case UnknownField::TYPE_FIXED32: + output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED32)); + output->WriteLittleEndian32(field.fixed32()); + break; + case UnknownField::TYPE_FIXED64: + output->WriteVarint32(MakeTag(field.number(), WIRETYPE_FIXED64)); + output->WriteLittleEndian64(field.fixed64()); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + output->WriteVarint32( + MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED)); + output->WriteVarint32(field.length_delimited().size()); + output->WriteString(field.length_delimited()); + break; + case UnknownField::TYPE_GROUP: + output->WriteVarint32(MakeTag(field.number(),WIRETYPE_START_GROUP)); + SerializeUnknownFields(field.group(), output); + output->WriteVarint32(MakeTag(field.number(), WIRETYPE_END_GROUP)); + break; } -#undef DO } +} - return true; +uint8* WireFormat::SerializeUnknownFieldsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); + + switch (field.type()) { + case UnknownField::TYPE_VARINT: + target = WriteInt64ToArray(field.number(), field.varint(), target); + break; + case UnknownField::TYPE_FIXED32: + target = WriteFixed32ToArray(field.number(), field.fixed32(), target); + break; + case UnknownField::TYPE_FIXED64: + target = WriteFixed64ToArray(field.number(), field.fixed64(), target); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + target = + WriteBytesToArray(field.number(), field.length_delimited(), target); + break; + case UnknownField::TYPE_GROUP: + target = WriteTagToArray(field.number(), WIRETYPE_START_GROUP, target); + target = SerializeUnknownFieldsToArray(field.group(), target); + target = WriteTagToArray(field.number(), WIRETYPE_END_GROUP, target); + break; + } + } + return target; } -bool WireFormat::SerializeUnknownMessageSetItems( +void WireFormat::SerializeUnknownMessageSetItems( const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output) { for (int i = 0; i < unknown_fields.field_count(); i++) { const UnknownField& field = unknown_fields.field(i); + // The only unknown fields that are allowed to exist in a MessageSet are + // messages, which are length-delimited. + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { + const string& data = field.length_delimited(); + + // Start group. + output->WriteVarint32(kMessageSetItemStartTag); + + // Write type ID. + output->WriteVarint32(kMessageSetTypeIdTag); + output->WriteVarint32(field.number()); + + // Write message. + output->WriteVarint32(kMessageSetMessageTag); + output->WriteVarint32(data.size()); + output->WriteString(data); + + // End group. + output->WriteVarint32(kMessageSetItemEndTag); + } + } +} + +uint8* WireFormat::SerializeUnknownMessageSetItemsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target) { + for (int i = 0; i < unknown_fields.field_count(); i++) { + const UnknownField& field = unknown_fields.field(i); -#define DO(EXPRESSION) if (!(EXPRESSION)) return false // The only unknown fields that are allowed to exist in a MessageSet are // messages, which are length-delimited. - for (int j = 0; j < field.length_delimited_size(); j++) { - const string& data = field.length_delimited(j); + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { + const string& data = field.length_delimited(); // Start group. - DO(output->WriteVarint32(kMessageSetItemStartTag)); + target = + io::CodedOutputStream::WriteTagToArray(kMessageSetItemStartTag, target); // Write type ID. - DO(output->WriteVarint32(kMessageSetTypeIdTag)); - DO(output->WriteVarint32(field.number())); + target = + io::CodedOutputStream::WriteTagToArray(kMessageSetTypeIdTag, target); + target = + io::CodedOutputStream::WriteVarint32ToArray(field.number(), target); // Write message. - DO(output->WriteVarint32(kMessageSetMessageTag)); - DO(output->WriteVarint32(data.size())); - DO(output->WriteString(data)); + target = + io::CodedOutputStream::WriteTagToArray(kMessageSetMessageTag, target); + target = io::CodedOutputStream::WriteVarint32ToArray(data.size(), target); + target = io::CodedOutputStream::WriteStringToArray(data, target); // End group. - DO(output->WriteVarint32(kMessageSetItemEndTag)); + target = + io::CodedOutputStream::WriteTagToArray(kMessageSetItemEndTag, target); } -#undef DO } - return true; + return target; } int WireFormat::ComputeUnknownFieldsSize( @@ -259,34 +318,36 @@ int WireFormat::ComputeUnknownFieldsSize( for (int i = 0; i < unknown_fields.field_count(); i++) { const UnknownField& field = unknown_fields.field(i); - for (int j = 0; j < field.varint_size(); j++) { - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_VARINT)); - size += io::CodedOutputStream::VarintSize64(field.varint(j)); - } - for (int j = 0; j < field.fixed32_size(); j++) { - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_FIXED32)); - size += sizeof(int32); - } - for (int j = 0; j < field.fixed64_size(); j++) { - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_FIXED64)); - size += sizeof(int64); - } - for (int j = 0; j < field.length_delimited_size(); j++) { - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED)); - size += io::CodedOutputStream::VarintSize32( - field.length_delimited(j).size()); - size += field.length_delimited(j).size(); - } - for (int j = 0; j < field.group_size(); j++) { - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_START_GROUP)); - size += ComputeUnknownFieldsSize(field.group(j)); - size += io::CodedOutputStream::VarintSize32( - MakeTag(field.number(), WIRETYPE_END_GROUP)); + switch (field.type()) { + case UnknownField::TYPE_VARINT: + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_VARINT)); + size += io::CodedOutputStream::VarintSize64(field.varint()); + break; + case UnknownField::TYPE_FIXED32: + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_FIXED32)); + size += sizeof(int32); + break; + case UnknownField::TYPE_FIXED64: + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_FIXED64)); + size += sizeof(int64); + break; + case UnknownField::TYPE_LENGTH_DELIMITED: + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_LENGTH_DELIMITED)); + size += io::CodedOutputStream::VarintSize32( + field.length_delimited().size()); + size += field.length_delimited().size(); + break; + case UnknownField::TYPE_GROUP: + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_START_GROUP)); + size += ComputeUnknownFieldsSize(field.group()); + size += io::CodedOutputStream::VarintSize32( + MakeTag(field.number(), WIRETYPE_END_GROUP)); + break; } } @@ -301,12 +362,12 @@ int WireFormat::ComputeUnknownMessageSetItemsSize( // The only unknown fields that are allowed to exist in a MessageSet are // messages, which are length-delimited. - for (int j = 0; j < field.length_delimited_size(); j++) { + if (field.type() == UnknownField::TYPE_LENGTH_DELIMITED) { size += kMessageSetItemTagsSize; size += io::CodedOutputStream::VarintSize32(field.number()); size += io::CodedOutputStream::VarintSize32( - field.length_delimited(j).size()); - size += field.length_delimited(j).size(); + field.length_delimited().size()); + size += field.length_delimited().size(); } } @@ -487,8 +548,8 @@ bool WireFormat::ParseAndMergeField( // UnknownFieldSet. int64 sign_extended_value = static_cast(value); message_reflection->MutableUnknownFields(message) - ->AddField(GetTagFieldNumber(tag)) - ->add_varint(sign_extended_value); + ->AddVarint(GetTagFieldNumber(tag), + sign_extended_value); } break; } @@ -607,7 +668,7 @@ bool WireFormat::ParseAndMergeMessageSetItem( // =================================================================== -bool WireFormat::SerializeWithCachedSizes( +void WireFormat::SerializeWithCachedSizes( const Message& message, int size, io::CodedOutputStream* output) { const Descriptor* descriptor = message.GetDescriptor(); @@ -617,32 +678,24 @@ bool WireFormat::SerializeWithCachedSizes( vector fields; message_reflection->ListFields(message, &fields); for (int i = 0; i < fields.size(); i++) { - if (!SerializeFieldWithCachedSizes(fields[i], message, output)) { - return false; - } + SerializeFieldWithCachedSizes(fields[i], message, output); } if (descriptor->options().message_set_wire_format()) { - if (!SerializeUnknownMessageSetItems( - message_reflection->GetUnknownFields(message), output)) { - return false; - } + SerializeUnknownMessageSetItems( + message_reflection->GetUnknownFields(message), output); } else { - if (!SerializeUnknownFields( - message_reflection->GetUnknownFields(message), output)) { - return false; - } + SerializeUnknownFields( + message_reflection->GetUnknownFields(message), output); } GOOGLE_CHECK_EQ(output->ByteCount(), expected_endpoint) << ": Protocol message serialized to a size different from what was " "originally expected. Perhaps it was modified by another thread " "during serialization?"; - - return true; } -bool WireFormat::SerializeFieldWithCachedSizes( +void WireFormat::SerializeFieldWithCachedSizes( const FieldDescriptor* field, const Message& message, io::CodedOutputStream* output) { @@ -652,8 +705,8 @@ bool WireFormat::SerializeFieldWithCachedSizes( field->containing_type()->options().message_set_wire_format() && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !field->is_repeated()) { - return SerializeMessageSetItemWithCachedSizes( - field, message, output); + SerializeMessageSetItemWithCachedSizes(field, message, output); + return; } int count = 0; @@ -666,10 +719,9 @@ bool WireFormat::SerializeFieldWithCachedSizes( const bool is_packed = field->options().packed(); if (is_packed && count > 0) { - if (!WriteTag(field->number(), WIRETYPE_LENGTH_DELIMITED, output)) - return false; + WriteTag(field->number(), WIRETYPE_LENGTH_DELIMITED, output); const int data_size = FieldDataOnlyByteSize(field, message); - if (!output->WriteVarint32(data_size)) return false; + output->WriteVarint32(data_size); } for (int j = 0; j < count; j++) { @@ -682,13 +734,9 @@ bool WireFormat::SerializeFieldWithCachedSizes( message_reflection->Get##CPPTYPE_METHOD( \ message, field); \ if (is_packed) { \ - if (!Write##TYPE_METHOD##NoTag(value, output)) { \ - return false; \ - } \ + Write##TYPE_METHOD##NoTag(value, output); \ } else { \ - if (!Write##TYPE_METHOD(field->number(), value, output)) { \ - return false; \ - } \ + Write##TYPE_METHOD(field->number(), value, output); \ } \ break; \ } @@ -713,15 +761,13 @@ bool WireFormat::SerializeFieldWithCachedSizes( #define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: \ - if (!Write##TYPE_METHOD( \ + Write##TYPE_METHOD( \ field->number(), \ field->is_repeated() ? \ message_reflection->GetRepeated##CPPTYPE_METHOD( \ message, field, j) : \ message_reflection->Get##CPPTYPE_METHOD(message, field), \ - output)) { \ - return false; \ - } \ + output); \ break; HANDLE_TYPE(GROUP , Group , Message) @@ -733,10 +779,9 @@ bool WireFormat::SerializeFieldWithCachedSizes( message_reflection->GetRepeatedEnum(message, field, j) : message_reflection->GetEnum(message, field); if (is_packed) { - if (!WriteEnumNoTag(value->number(), output)) return false; + WriteEnumNoTag(value->number(), output); } else { - if (!WriteEnum(field->number(), value->number(), output)) - return false; + WriteEnum(field->number(), value->number(), output); } break; } @@ -749,7 +794,7 @@ bool WireFormat::SerializeFieldWithCachedSizes( message_reflection->GetRepeatedStringReference( message, field, j, &scratch) : message_reflection->GetStringReference(message, field, &scratch); - if (!WriteString(field->number(), value, output)) return false; + WriteString(field->number(), value, output); break; } @@ -759,39 +804,35 @@ bool WireFormat::SerializeFieldWithCachedSizes( message_reflection->GetRepeatedStringReference( message, field, j, &scratch) : message_reflection->GetStringReference(message, field, &scratch); - if (!WriteBytes(field->number(), value, output)) return false; + WriteBytes(field->number(), value, output); break; } } } - - return true; } -bool WireFormat::SerializeMessageSetItemWithCachedSizes( +void WireFormat::SerializeMessageSetItemWithCachedSizes( const FieldDescriptor* field, const Message& message, io::CodedOutputStream* output) { const Reflection* message_reflection = message.GetReflection(); // Start group. - if (!output->WriteVarint32(kMessageSetItemStartTag)) return false; + output->WriteVarint32(kMessageSetItemStartTag); // Write type ID. - if (!output->WriteVarint32(kMessageSetTypeIdTag)) return false; - if (!output->WriteVarint32(field->number())) return false; + output->WriteVarint32(kMessageSetTypeIdTag); + output->WriteVarint32(field->number()); // Write message. - if (!output->WriteVarint32(kMessageSetMessageTag)) return false; + output->WriteVarint32(kMessageSetMessageTag); const Message& sub_message = message_reflection->GetMessage(message, field); - if (!output->WriteVarint32(sub_message.GetCachedSize())) return false; - if (!sub_message.SerializeWithCachedSizes(output)) return false; + output->WriteVarint32(sub_message.GetCachedSize()); + sub_message.SerializeWithCachedSizes(output); // End group. - if (!output->WriteVarint32(kMessageSetItemEndTag)) return false; - - return true; + output->WriteVarint32(kMessageSetItemEndTag); } // =================================================================== diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h index 9004caaa..963f427a 100644 --- a/src/google/protobuf/wire_format.h +++ b/src/google/protobuf/wire_format.h @@ -93,7 +93,7 @@ class LIBPROTOBUF_EXPORT WireFormat { // a parameter to this procedure. // // These return false iff the underlying stream returns a write error. - static bool SerializeWithCachedSizes( + static void SerializeWithCachedSizes( const Message& message, int size, io::CodedOutputStream* output); @@ -119,14 +119,30 @@ class LIBPROTOBUF_EXPORT WireFormat { UnknownFieldSet* unknown_fields); // Write the contents of an UnknownFieldSet to the output. - static bool SerializeUnknownFields(const UnknownFieldSet& unknown_fields, + static void SerializeUnknownFields(const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownFieldsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownFieldsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); // Same thing except for messages that have the message_set_wire_format // option. - static bool SerializeUnknownMessageSetItems( + static void SerializeUnknownMessageSetItems( const UnknownFieldSet& unknown_fields, io::CodedOutputStream* output); + // Same as above, except writing directly to the provided buffer. + // Requires that the buffer have sufficient capacity for + // ComputeUnknownMessageSetItemsSize(unknown_fields). + // + // Returns a pointer past the last written byte. + static uint8* SerializeUnknownMessageSetItemsToArray( + const UnknownFieldSet& unknown_fields, + uint8* target); // Compute the size of the UnknownFieldSet on the wire. static int ComputeUnknownFieldsSize(const UnknownFieldSet& unknown_fields); @@ -210,7 +226,7 @@ class LIBPROTOBUF_EXPORT WireFormat { io::CodedInputStream* input); // Serialize a single field. - static bool SerializeFieldWithCachedSizes( + static void SerializeFieldWithCachedSizes( const FieldDescriptor* field, // Cannot be NULL const Message& message, io::CodedOutputStream* output); @@ -268,61 +284,139 @@ class LIBPROTOBUF_EXPORT WireFormat { // 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. - static inline bool WriteTag(field_number, WireType type, output) INL; + static inline void WriteTag(field_number, WireType type, output) INL; // Write fields, without tags. - static inline bool WriteInt32NoTag (int32 value, output) INL; - static inline bool WriteInt64NoTag (int64 value, output) INL; - static inline bool WriteUInt32NoTag (uint32 value, output) INL; - static inline bool WriteUInt64NoTag (uint64 value, output) INL; - static inline bool WriteSInt32NoTag (int32 value, output) INL; - static inline bool WriteSInt64NoTag (int64 value, output) INL; - static inline bool WriteFixed32NoTag (uint32 value, output) INL; - static inline bool WriteFixed64NoTag (uint64 value, output) INL; - static inline bool WriteSFixed32NoTag(int32 value, output) INL; - static inline bool WriteSFixed64NoTag(int64 value, output) INL; - static inline bool WriteFloatNoTag (float value, output) INL; - static inline bool WriteDoubleNoTag (double value, output) INL; - static inline bool WriteBoolNoTag (bool value, output) INL; - static inline bool WriteEnumNoTag (int value, output) INL; + static inline void WriteInt32NoTag (int32 value, output) INL; + static inline void WriteInt64NoTag (int64 value, output) INL; + static inline void WriteUInt32NoTag (uint32 value, output) INL; + static inline void WriteUInt64NoTag (uint64 value, output) INL; + static inline void WriteSInt32NoTag (int32 value, output) INL; + static inline void WriteSInt64NoTag (int64 value, output) INL; + static inline void WriteFixed32NoTag (uint32 value, output) INL; + static inline void WriteFixed64NoTag (uint64 value, output) INL; + static inline void WriteSFixed32NoTag(int32 value, output) INL; + static inline void WriteSFixed64NoTag(int64 value, output) INL; + static inline void WriteFloatNoTag (float value, output) INL; + static inline void WriteDoubleNoTag (double value, output) INL; + static inline void WriteBoolNoTag (bool value, output) INL; + static inline void WriteEnumNoTag (int value, output) INL; // Write fields, including tags. - static inline bool WriteInt32 (field_number, int32 value, output) INL; - static inline bool WriteInt64 (field_number, int64 value, output) INL; - static inline bool WriteUInt32 (field_number, uint32 value, output) INL; - static inline bool WriteUInt64 (field_number, uint64 value, output) INL; - static inline bool WriteSInt32 (field_number, int32 value, output) INL; - static inline bool WriteSInt64 (field_number, int64 value, output) INL; - static inline bool WriteFixed32 (field_number, uint32 value, output) INL; - static inline bool WriteFixed64 (field_number, uint64 value, output) INL; - static inline bool WriteSFixed32(field_number, int32 value, output) INL; - static inline bool WriteSFixed64(field_number, int64 value, output) INL; - static inline bool WriteFloat (field_number, float value, output) INL; - static inline bool WriteDouble (field_number, double value, output) INL; - static inline bool WriteBool (field_number, bool value, output) INL; - static inline bool WriteEnum (field_number, int value, output) INL; - - static inline bool WriteString(field_number, const string& value, output) INL; - static inline bool WriteBytes (field_number, const string& value, output) INL; - - static inline bool WriteGroup(field_number, const Message& value, output) INL; - static inline bool WriteMessage( + static inline void WriteInt32 (field_number, int32 value, output) INL; + static inline void WriteInt64 (field_number, int64 value, output) INL; + static inline void WriteUInt32 (field_number, uint32 value, output) INL; + static inline void WriteUInt64 (field_number, uint64 value, output) INL; + static inline void WriteSInt32 (field_number, int32 value, output) INL; + static inline void WriteSInt64 (field_number, int64 value, output) INL; + static inline void WriteFixed32 (field_number, uint32 value, output) INL; + static inline void WriteFixed64 (field_number, uint64 value, output) INL; + static inline void WriteSFixed32(field_number, int32 value, output) INL; + static inline void WriteSFixed64(field_number, int64 value, output) INL; + static inline void WriteFloat (field_number, float value, output) INL; + static inline void WriteDouble (field_number, double value, output) INL; + static inline void WriteBool (field_number, bool value, output) INL; + static inline void WriteEnum (field_number, int value, output) INL; + + static inline void WriteString(field_number, const string& value, output) INL; + static inline void WriteBytes (field_number, const string& value, output) INL; + + static inline void WriteGroup(field_number, const Message& value, output) INL; + static inline void WriteMessage( field_number, const Message& value, output) INL; // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The // pointer must point at an instance of MessageType, *not* a subclass (or // the subclass must not override SerializeWithCachedSizes()). template - static inline bool WriteGroupNoVirtual( + static inline void WriteGroupNoVirtual( + field_number, const MessageType& value, output) INL; + template + static inline void WriteMessageNoVirtual( + field_number, const MessageType& value, output) INL; + +#undef output +#define output uint8* target + + // Like above, but use only *ToArray methods of CodedOutputStream. + static inline uint8* WriteTagToArray(field_number, WireType type, output) INL; + + // Write fields, without tags. + static inline uint8* WriteInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteUInt32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteUInt64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSInt32NoTagToArray (int32 value, output) INL; + static inline uint8* WriteSInt64NoTagToArray (int64 value, output) INL; + static inline uint8* WriteFixed32NoTagToArray (uint32 value, output) INL; + static inline uint8* WriteFixed64NoTagToArray (uint64 value, output) INL; + static inline uint8* WriteSFixed32NoTagToArray(int32 value, output) INL; + static inline uint8* WriteSFixed64NoTagToArray(int64 value, output) INL; + static inline uint8* WriteFloatNoTagToArray (float value, output) INL; + static inline uint8* WriteDoubleNoTagToArray (double value, output) INL; + static inline uint8* WriteBoolNoTagToArray (bool value, output) INL; + static inline uint8* WriteEnumNoTagToArray (int value, output) INL; + + // Write fields, including tags. + static inline uint8* WriteInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteUInt32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteUInt64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSInt32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSInt64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFixed32ToArray( + field_number, uint32 value, output) INL; + static inline uint8* WriteFixed64ToArray( + field_number, uint64 value, output) INL; + static inline uint8* WriteSFixed32ToArray( + field_number, int32 value, output) INL; + static inline uint8* WriteSFixed64ToArray( + field_number, int64 value, output) INL; + static inline uint8* WriteFloatToArray( + field_number, float value, output) INL; + static inline uint8* WriteDoubleToArray( + field_number, double value, output) INL; + static inline uint8* WriteBoolToArray( + field_number, bool value, output) INL; + static inline uint8* WriteEnumToArray( + field_number, int value, output) INL; + + static inline uint8* WriteStringToArray( + field_number, const string& value, output) INL; + static inline uint8* WriteBytesToArray( + field_number, const string& value, output) INL; + + static inline uint8* WriteGroupToArray( + field_number, const Message& value, output) INL; + static inline uint8* WriteMessageToArray( + field_number, const Message& value, output) INL; + + // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The + // pointer must point at an instance of MessageType, *not* a subclass (or + // the subclass must not override SerializeWithCachedSizes()). + template + static inline uint8* WriteGroupNoVirtualToArray( field_number, const MessageType& value, output) INL; template - static inline bool WriteMessageNoVirtual( + static inline uint8* WriteMessageNoVirtualToArray( field_number, const MessageType& value, output) INL; +#undef output +#undef input +#undef INL + // Compute the byte size of a tag. For groups, this includes both the start // and end tags. static inline int TagSize(field_number, FieldDescriptor::Type type); +#undef field_number + // Compute the byte size of a field. The XxSize() functions do NOT include // the tag, so you must also call TagSize(). (This is because, for repeated // fields, you should only call TagSize() once and multiply it by the element @@ -358,11 +452,6 @@ class LIBPROTOBUF_EXPORT WireFormat { template static inline int MessageSizeNoVirtual(const MessageType& value); -#undef input -#undef output -#undef field_number -#undef INL - private: static const WireType kWireTypeForFieldType[]; @@ -371,7 +460,7 @@ class LIBPROTOBUF_EXPORT WireFormat { static bool ParseAndMergeMessageSetItem( io::CodedInputStream* input, Message* message); - static bool SerializeMessageSetItemWithCachedSizes( + static void SerializeMessageSetItemWithCachedSizes( const FieldDescriptor* field, const Message& message, io::CodedOutputStream* output); diff --git a/src/google/protobuf/wire_format_inl.h b/src/google/protobuf/wire_format_inl.h index 451ac11c..69256080 100644 --- a/src/google/protobuf/wire_format_inl.h +++ b/src/google/protobuf/wire_format_inl.h @@ -164,7 +164,8 @@ inline bool WireFormat::ReadBytes(io::CodedInputStream* input, string* value) { } -inline bool WireFormat::ReadGroup(int field_number, io::CodedInputStream* input, +inline bool WireFormat::ReadGroup(int field_number, + io::CodedInputStream* input, Message* value) { if (!input->IncrementRecursionDepth()) return false; if (!value->MergePartialFromCodedStream(input)) return false; @@ -175,7 +176,8 @@ inline bool WireFormat::ReadGroup(int field_number, io::CodedInputStream* input, } return true; } -inline bool WireFormat::ReadMessage(io::CodedInputStream* input, Message* value) { +inline bool WireFormat::ReadMessage(io::CodedInputStream* input, + Message* value) { uint32 length; if (!input->ReadVarint32(&length)) return false; if (!input->IncrementRecursionDepth()) return false; @@ -220,140 +222,140 @@ inline bool WireFormat::ReadMessageNoVirtual(io::CodedInputStream* input, // =================================================================== -inline bool WireFormat::WriteTag(int field_number, WireType type, +inline void WireFormat::WriteTag(int field_number, WireType type, io::CodedOutputStream* output) { - return output->WriteTag(MakeTag(field_number, type)); + output->WriteTag(MakeTag(field_number, type)); } -inline bool WireFormat::WriteInt32NoTag(int32 value, +inline void WireFormat::WriteInt32NoTag(int32 value, io::CodedOutputStream* output) { - return output->WriteVarint32SignExtended(value); + output->WriteVarint32SignExtended(value); } -inline bool WireFormat::WriteInt64NoTag(int64 value, +inline void WireFormat::WriteInt64NoTag(int64 value, io::CodedOutputStream* output) { - return output->WriteVarint64(static_cast(value)); + output->WriteVarint64(static_cast(value)); } -inline bool WireFormat::WriteUInt32NoTag(uint32 value, +inline void WireFormat::WriteUInt32NoTag(uint32 value, io::CodedOutputStream* output) { - return output->WriteVarint32(value); + output->WriteVarint32(value); } -inline bool WireFormat::WriteUInt64NoTag(uint64 value, +inline void WireFormat::WriteUInt64NoTag(uint64 value, io::CodedOutputStream* output) { - return output->WriteVarint64(value); + output->WriteVarint64(value); } -inline bool WireFormat::WriteSInt32NoTag(int32 value, +inline void WireFormat::WriteSInt32NoTag(int32 value, io::CodedOutputStream* output) { - return output->WriteVarint32(ZigZagEncode32(value)); + output->WriteVarint32(ZigZagEncode32(value)); } -inline bool WireFormat::WriteSInt64NoTag(int64 value, +inline void WireFormat::WriteSInt64NoTag(int64 value, io::CodedOutputStream* output) { - return output->WriteVarint64(ZigZagEncode64(value)); + output->WriteVarint64(ZigZagEncode64(value)); } -inline bool WireFormat::WriteFixed32NoTag(uint32 value, +inline void WireFormat::WriteFixed32NoTag(uint32 value, io::CodedOutputStream* output) { - return output->WriteLittleEndian32(value); + output->WriteLittleEndian32(value); } -inline bool WireFormat::WriteFixed64NoTag(uint64 value, +inline void WireFormat::WriteFixed64NoTag(uint64 value, io::CodedOutputStream* output) { - return output->WriteLittleEndian64(value); + output->WriteLittleEndian64(value); } -inline bool WireFormat::WriteSFixed32NoTag(int32 value, +inline void WireFormat::WriteSFixed32NoTag(int32 value, io::CodedOutputStream* output) { - return output->WriteLittleEndian32(static_cast(value)); + output->WriteLittleEndian32(static_cast(value)); } -inline bool WireFormat::WriteSFixed64NoTag(int64 value, +inline void WireFormat::WriteSFixed64NoTag(int64 value, io::CodedOutputStream* output) { - return output->WriteLittleEndian64(static_cast(value)); + output->WriteLittleEndian64(static_cast(value)); } -inline bool WireFormat::WriteFloatNoTag(float value, +inline void WireFormat::WriteFloatNoTag(float value, io::CodedOutputStream* output) { - return output->WriteLittleEndian32(EncodeFloat(value)); + output->WriteLittleEndian32(EncodeFloat(value)); } -inline bool WireFormat::WriteDoubleNoTag(double value, +inline void WireFormat::WriteDoubleNoTag(double value, io::CodedOutputStream* output) { - return output->WriteLittleEndian64(EncodeDouble(value)); + output->WriteLittleEndian64(EncodeDouble(value)); } -inline bool WireFormat::WriteBoolNoTag(bool value, +inline void WireFormat::WriteBoolNoTag(bool value, io::CodedOutputStream* output) { - return output->WriteVarint32(value ? 1 : 0); + output->WriteVarint32(value ? 1 : 0); } -inline bool WireFormat::WriteEnumNoTag(int value, +inline void WireFormat::WriteEnumNoTag(int value, io::CodedOutputStream* output) { - return output->WriteVarint32SignExtended(value); + output->WriteVarint32SignExtended(value); } -inline bool WireFormat::WriteInt32(int field_number, int32 value, +inline void WireFormat::WriteInt32(int field_number, int32 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteInt32NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt32NoTag(value, output); } -inline bool WireFormat::WriteInt64(int field_number, int64 value, +inline void WireFormat::WriteInt64(int field_number, int64 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteInt64NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt64NoTag(value, output); } -inline bool WireFormat::WriteUInt32(int field_number, uint32 value, +inline void WireFormat::WriteUInt32(int field_number, uint32 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteUInt32NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt32NoTag(value, output); } -inline bool WireFormat::WriteUInt64(int field_number, uint64 value, +inline void WireFormat::WriteUInt64(int field_number, uint64 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteUInt64NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt64NoTag(value, output); } -inline bool WireFormat::WriteSInt32(int field_number, int32 value, +inline void WireFormat::WriteSInt32(int field_number, int32 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteSInt32NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt32NoTag(value, output); } -inline bool WireFormat::WriteSInt64(int field_number, int64 value, +inline void WireFormat::WriteSInt64(int field_number, int64 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteSInt64NoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt64NoTag(value, output); } -inline bool WireFormat::WriteFixed32(int field_number, uint32 value, +inline void WireFormat::WriteFixed32(int field_number, uint32 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED32, output) && - WriteFixed32NoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFixed32NoTag(value, output); } -inline bool WireFormat::WriteFixed64(int field_number, uint64 value, +inline void WireFormat::WriteFixed64(int field_number, uint64 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED64, output) && - WriteFixed64NoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteFixed64NoTag(value, output); } -inline bool WireFormat::WriteSFixed32(int field_number, int32 value, +inline void WireFormat::WriteSFixed32(int field_number, int32 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED32, output) && - WriteSFixed32NoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteSFixed32NoTag(value, output); } -inline bool WireFormat::WriteSFixed64(int field_number, int64 value, +inline void WireFormat::WriteSFixed64(int field_number, int64 value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED64, output) && - WriteSFixed64NoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteSFixed64NoTag(value, output); } -inline bool WireFormat::WriteFloat(int field_number, float value, +inline void WireFormat::WriteFloat(int field_number, float value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED32, output) && - WriteFloatNoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFloatNoTag(value, output); } -inline bool WireFormat::WriteDouble(int field_number, double value, +inline void WireFormat::WriteDouble(int field_number, double value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_FIXED64, output) && - WriteDoubleNoTag(value, output); + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteDoubleNoTag(value, output); } -inline bool WireFormat::WriteBool(int field_number, bool value, +inline void WireFormat::WriteBool(int field_number, bool value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteBoolNoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteBoolNoTag(value, output); } -inline bool WireFormat::WriteEnum(int field_number, int value, +inline void WireFormat::WriteEnum(int field_number, int value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_VARINT, output) && - WriteEnumNoTag(value, output); + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteEnumNoTag(value, output); } -inline bool WireFormat::WriteString(int field_number, const string& value, +inline void WireFormat::WriteString(int field_number, const string& value, io::CodedOutputStream* output) { // String is for UTF-8 text only #ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED @@ -363,46 +365,256 @@ inline bool WireFormat::WriteString(int field_number, const string& value, "use the 'bytes' type for raw bytes."; } #endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED - return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) && - output->WriteVarint32(value.size()) && - output->WriteString(value); + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); } -inline bool WireFormat::WriteBytes(int field_number, const string& value, +inline void WireFormat::WriteBytes(int field_number, const string& value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) && - output->WriteVarint32(value.size()) && - output->WriteString(value); + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); } -inline bool WireFormat::WriteGroup(int field_number, const Message& value, +inline void WireFormat::WriteGroup(int field_number, const Message& value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_START_GROUP, output) && - value.SerializeWithCachedSizes(output) && - WriteTag(field_number, WIRETYPE_END_GROUP, output); + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); } -inline bool WireFormat::WriteMessage(int field_number, const Message& value, +inline void WireFormat::WriteMessage(int field_number, const Message& value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) && - output->WriteVarint32(value.GetCachedSize()) && - value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.GetCachedSize()); + value.SerializeWithCachedSizes(output); } template -inline bool WireFormat::WriteGroupNoVirtual( +inline void WireFormat::WriteGroupNoVirtual( int field_number, const MessageType& value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_START_GROUP, output) && - value.MessageType::SerializeWithCachedSizes(output) && - WriteTag(field_number, WIRETYPE_END_GROUP, output); + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.MessageType::SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); } template -inline bool WireFormat::WriteMessageNoVirtual( +inline void WireFormat::WriteMessageNoVirtual( int field_number, const MessageType& value, io::CodedOutputStream* output) { - return WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output) && - output->WriteVarint32(value.MessageType::GetCachedSize()) && - value.MessageType::SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.MessageType::GetCachedSize()); + value.MessageType::SerializeWithCachedSizes(output); +} + +// =================================================================== + +inline uint8* WireFormat::WriteTagToArray(int field_number, + WireType type, + uint8* target) { + return io::CodedOutputStream::WriteTagToArray(MakeTag(field_number, type), + target); +} + +inline uint8* WireFormat::WriteInt32NoTagToArray(int32 value, uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} +inline uint8* WireFormat::WriteInt64NoTagToArray(int64 value, uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray( + static_cast(value), target); +} +inline uint8* WireFormat::WriteUInt32NoTagToArray(uint32 value, uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value, target); +} +inline uint8* WireFormat::WriteUInt64NoTagToArray(uint64 value, uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(value, target); +} +inline uint8* WireFormat::WriteSInt32NoTagToArray(int32 value, uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(ZigZagEncode32(value), + target); +} +inline uint8* WireFormat::WriteSInt64NoTagToArray(int64 value, uint8* target) { + return io::CodedOutputStream::WriteVarint64ToArray(ZigZagEncode64(value), + target); +} +inline uint8* WireFormat::WriteFixed32NoTagToArray(uint32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(value, target); +} +inline uint8* WireFormat::WriteFixed64NoTagToArray(uint64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(value, target); +} +inline uint8* WireFormat::WriteSFixed32NoTagToArray(int32 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray( + static_cast(value), target); +} +inline uint8* WireFormat::WriteSFixed64NoTagToArray(int64 value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray( + static_cast(value), target); +} +inline uint8* WireFormat::WriteFloatNoTagToArray(float value, uint8* target) { + return io::CodedOutputStream::WriteLittleEndian32ToArray(EncodeFloat(value), + target); +} +inline uint8* WireFormat::WriteDoubleNoTagToArray(double value, + uint8* target) { + return io::CodedOutputStream::WriteLittleEndian64ToArray(EncodeDouble(value), + target); +} +inline uint8* WireFormat::WriteBoolNoTagToArray(bool value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32ToArray(value ? 1 : 0, target); +} +inline uint8* WireFormat::WriteEnumNoTagToArray(int value, + uint8* target) { + return io::CodedOutputStream::WriteVarint32SignExtendedToArray(value, target); +} + +inline uint8* WireFormat::WriteInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt32NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteInt64NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteUInt32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt32NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteUInt64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteUInt64NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteSInt32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt32NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteSInt64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteSInt64NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteFixed32ToArray(int field_number, + uint32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFixed32NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteFixed64ToArray(int field_number, + uint64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteFixed64NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteSFixed32ToArray(int field_number, + int32 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteSFixed32NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteSFixed64ToArray(int field_number, + int64 value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteSFixed64NoTagToArray(value, target); +} +inline uint8* WireFormat::WriteFloatToArray(int field_number, + float value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED32, target); + return WriteFloatNoTagToArray(value, target); +} +inline uint8* WireFormat::WriteDoubleToArray(int field_number, + double value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_FIXED64, target); + return WriteDoubleNoTagToArray(value, target); +} +inline uint8* WireFormat::WriteBoolToArray(int field_number, + bool value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteBoolNoTagToArray(value, target); +} +inline uint8* WireFormat::WriteEnumToArray(int field_number, + int value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_VARINT, target); + return WriteEnumNoTagToArray(value, target); +} + +inline uint8* WireFormat::WriteStringToArray(int field_number, + const string& value, + uint8* target) { + // String is for UTF-8 text only +#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED + if (!IsStructurallyValidUTF8(value.data(), value.size())) { + GOOGLE_LOG(ERROR) << "Encountered string containing invalid UTF-8 data while " + "serializing protocol buffer. Strings must contain only UTF-8; " + "use the 'bytes' type for raw bytes."; + } +#endif + // WARNING: In wire_format.cc, both strings and bytes are handled by + // WriteString() to avoid code duplication. If the implementations become + // different, you will need to update that usage. + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} +inline uint8* WireFormat::WriteBytesToArray(int field_number, + const string& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target); + return io::CodedOutputStream::WriteStringToArray(value, target); +} + + +inline uint8* WireFormat::WriteGroupToArray(int field_number, + const Message& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +inline uint8* WireFormat::WriteMessageToArray(int field_number, + const Message& value, + uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.GetCachedSize(), target); + return value.SerializeWithCachedSizesToArray(target); +} + +template +inline uint8* WireFormat::WriteGroupNoVirtualToArray( + int field_number, const MessageType& value, uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target); + target = value.MessageType::SerializeWithCachedSizesToArray(target); + return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target); +} +template +inline uint8* WireFormat::WriteMessageNoVirtualToArray( + int field_number, const MessageType& value, uint8* target) { + target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target); + target = io::CodedOutputStream::WriteVarint32ToArray( + value.MessageType::GetCachedSize(), target); + return value.MessageType::SerializeWithCachedSizesToArray(target); } // =================================================================== diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 5a7c6c23..1f00a93d 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -44,6 +44,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -179,6 +180,7 @@ TEST(WireFormatTest, Serialize) { io::StringOutputStream raw_output(&generated_data); io::CodedOutputStream output(&raw_output); message.SerializeWithCachedSizes(&output); + ASSERT_FALSE(output.HadError()); } // Serialize using WireFormat. @@ -186,6 +188,7 @@ TEST(WireFormatTest, Serialize) { io::StringOutputStream raw_output(&dynamic_data); io::CodedOutputStream output(&raw_output); WireFormat::SerializeWithCachedSizes(message, size, &output); + ASSERT_FALSE(output.HadError()); } // Should be the same. @@ -207,6 +210,7 @@ TEST(WireFormatTest, SerializeExtensions) { io::StringOutputStream raw_output(&generated_data); io::CodedOutputStream output(&raw_output); message.SerializeWithCachedSizes(&output); + ASSERT_FALSE(output.HadError()); } // Serialize using WireFormat. @@ -214,6 +218,7 @@ TEST(WireFormatTest, SerializeExtensions) { io::StringOutputStream raw_output(&dynamic_data); io::CodedOutputStream output(&raw_output); WireFormat::SerializeWithCachedSizes(message, size, &output); + ASSERT_FALSE(output.HadError()); } // Should be the same. @@ -235,6 +240,7 @@ TEST(WireFormatTest, SerializeFieldsAndExtensions) { io::StringOutputStream raw_output(&generated_data); io::CodedOutputStream output(&raw_output); message.SerializeWithCachedSizes(&output); + ASSERT_FALSE(output.HadError()); } // Serialize using WireFormat. @@ -242,6 +248,7 @@ TEST(WireFormatTest, SerializeFieldsAndExtensions) { io::StringOutputStream raw_output(&dynamic_data); io::CodedOutputStream output(&raw_output); WireFormat::SerializeWithCachedSizes(message, size, &output); + ASSERT_FALSE(output.HadError()); } // Should be the same. @@ -287,8 +294,8 @@ TEST(WireFormatTest, SerializeMessageSet) { unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); message_set.MutableExtension( unittest::TestMessageSetExtension2::message_set_extension)->set_str("foo"); - message_set.mutable_unknown_fields()->AddField(kUnknownTypeId) - ->add_length_delimited("bar"); + message_set.mutable_unknown_fields()->AddLengthDelimited( + kUnknownTypeId, "bar"); string data; ASSERT_TRUE(message_set.SerializeToString(&data)); @@ -319,6 +326,43 @@ TEST(WireFormatTest, SerializeMessageSet) { EXPECT_EQ("bar", raw.item(2).message()); } +TEST(WireFormatTest, SerializeMessageSetToStreamAndArrayAreEqual) { + // Serialize a MessageSet to a stream and to a flat array and check that the + // results are equal. + // Set up a TestMessageSet with two known messages and an unknown one, as + // above. + + unittest::TestMessageSet message_set; + message_set.MutableExtension( + unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); + message_set.MutableExtension( + unittest::TestMessageSetExtension2::message_set_extension)->set_str("foo"); + message_set.mutable_unknown_fields()->AddLengthDelimited( + kUnknownTypeId, "bar"); + + int size = message_set.ByteSize(); + string flat_data; + string stream_data; + flat_data.resize(size); + stream_data.resize(size); + // Serialize to flat array + { + uint8* target = reinterpret_cast(string_as_array(&flat_data)); + uint8* end = message_set.SerializeWithCachedSizesToArray(target); + EXPECT_EQ(size, end - target); + } + + // Serialize to buffer + { + io::ArrayOutputStream array_stream(string_as_array(&stream_data), size, 1); + io::CodedOutputStream output_stream(&array_stream); + message_set.SerializeWithCachedSizes(&output_stream); + ASSERT_FALSE(output_stream.HadError()); + } + + EXPECT_TRUE(flat_data == stream_data); +} + TEST(WireFormatTest, ParseMessageSet) { // Set up a RawMessageSet with two known messages and an unknown one. unittest::RawMessageSet raw; @@ -360,8 +404,9 @@ TEST(WireFormatTest, ParseMessageSet) { unittest::TestMessageSetExtension2::message_set_extension).str()); ASSERT_EQ(1, message_set.unknown_fields().field_count()); - ASSERT_EQ(1, message_set.unknown_fields().field(0).length_delimited_size()); - EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited(0)); + ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED, + message_set.unknown_fields().field(0).type()); + EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited()); } TEST(WireFormatTest, RecursionLimit) { @@ -390,11 +435,11 @@ TEST(WireFormatTest, RecursionLimit) { TEST(WireFormatTest, UnknownFieldRecursionLimit) { unittest::TestEmptyMessage message; message.mutable_unknown_fields() - ->AddField(1234)->add_group() - ->AddField(1234)->add_group() - ->AddField(1234)->add_group() - ->AddField(1234)->add_group() - ->AddField(1234)->add_varint(123); + ->AddGroup(1234) + ->AddGroup(1234) + ->AddGroup(1234) + ->AddGroup(1234) + ->AddVarint(1234, 123); string data; message.SerializeToString(&data); @@ -500,8 +545,7 @@ class WireFormatInvalidInputTest : public testing::Test { io::StringOutputStream raw_output(&result); io::CodedOutputStream output(&raw_output); - EXPECT_TRUE(WireFormat::WriteBytes( - field->number(), string(bytes, size), &output)); + WireFormat::WriteBytes(field->number(), string(bytes, size), &output); } return result; @@ -522,12 +566,11 @@ class WireFormatInvalidInputTest : public testing::Test { io::StringOutputStream raw_output(&result); io::CodedOutputStream output(&raw_output); - EXPECT_TRUE(output.WriteVarint32(WireFormat::MakeTag(field))); - EXPECT_TRUE(output.WriteString(string(bytes, size))); + output.WriteVarint32(WireFormat::MakeTag(field)); + output.WriteString(string(bytes, size)); if (include_end_tag) { - EXPECT_TRUE( - output.WriteVarint32(WireFormat::MakeTag( - field->number(), WireFormat::WIRETYPE_END_GROUP))); + output.WriteVarint32(WireFormat::MakeTag( + field->number(), WireFormat::WIRETYPE_END_GROUP)); } } -- cgit v1.2.3