diff --git a/cmake/install.cmake b/cmake/install.cmake index e14ef1d27fb1b..dbb4265d45021 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -1,103 +1,103 @@ -include(GNUInstallDirs) - -foreach(_library - libprotobuf-lite - libprotobuf - libprotoc) - set_property(TARGET ${_library} - PROPERTY INTERFACE_INCLUDE_DIRECTORIES - $) - install(TARGETS ${_library} EXPORT protobuf-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${_library} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library}) -endforeach() - -install(TARGETS protoc EXPORT protobuf-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc) - -if(TRUE) - file(STRINGS extract_includes.bat.in _extract_strings - REGEX "^copy") - foreach(_extract_string ${_extract_strings}) - string(REPLACE "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\" "" - _extract_string ${_extract_string}) - string(REPLACE "\\" "/" _extract_string ${_extract_string}) - string(REGEX MATCH "^[^ ]+" - _extract_from ${_extract_string}) - string(REGEX REPLACE "^${_extract_from} ([^$]+)" "\\1" - _extract_to ${_extract_string}) - get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/${_extract_from}" ABSOLUTE) - get_filename_component(_extract_name ${_extract_to} NAME) - get_filename_component(_extract_to ${_extract_to} PATH) - string(REPLACE "include/" "${CMAKE_INSTALL_INCLUDEDIR}/" - _extract_to "${_extract_to}") - if(EXISTS "${_extract_from}") - install(FILES "${_extract_from}" - DESTINATION "${_extract_to}" - COMPONENT protobuf-headers - RENAME "${_extract_name}") - else() - message(AUTHOR_WARNING "The file \"${_extract_from}\" is listed in " - "\"${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in\" " - "but there not exists. The file will not be installed.") - endif() - endforeach() -endif() - -# Internal function for parsing auto tools scripts -function(_protobuf_auto_list FILE_NAME VARIABLE) - file(STRINGS ${FILE_NAME} _strings) - set(_list) - foreach(_string ${_strings}) - set(_found) - string(REGEX MATCH "^[ \t]*${VARIABLE}[ \t]*=[ \t]*" _found "${_string}") - if(_found) - string(LENGTH "${_found}" _length) - string(SUBSTRING "${_string}" ${_length} -1 _draft_list) - foreach(_item ${_draft_list}) - string(STRIP "${_item}" _item) - list(APPEND _list "${_item}") - endforeach() - endif() - endforeach() - set(${VARIABLE} ${_list} PARENT_SCOPE) -endfunction() - -# Install well-known type proto files -_protobuf_auto_list("../src/Makefile.am" nobase_dist_proto_DATA) -foreach(_file ${nobase_dist_proto_DATA}) - get_filename_component(_file_from "../src/${_file}" ABSOLUTE) - get_filename_component(_file_name ${_file} NAME) - get_filename_component(_file_path ${_file} PATH) - if(EXISTS "${_file_from}") - install(FILES "${_file_from}" - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_file_path}" - COMPONENT protobuf-protos - RENAME "${_file_name}") - else() - message(AUTHOR_WARNING "The file \"${_file_from}\" is listed in " - "\"${protobuf_SOURCE_DIR}/../src/Makefile.am\" as nobase_dist_proto_DATA " - "but there not exists. The file will not be installed.") - endif() -endforeach() - -# Export configuration - -install(EXPORT protobuf-targets - DESTINATION "lib/cmake/protobuf" - COMPONENT protobuf-export) - -configure_file(protobuf-config.cmake.in - protobuf-config.cmake @ONLY) -configure_file(protobuf-config-version.cmake.in - protobuf-config-version.cmake @ONLY) -configure_file(protobuf-module.cmake.in - protobuf-module.cmake @ONLY) - -install(FILES - "${protobuf_BINARY_DIR}/protobuf-config.cmake" - "${protobuf_BINARY_DIR}/protobuf-config-version.cmake" - "${protobuf_BINARY_DIR}/protobuf-module.cmake" - DESTINATION "lib/cmake/protobuf" - COMPONENT protobuf-export) +include(GNUInstallDirs) + +foreach(_library + libprotobuf-lite + libprotobuf + libprotoc) + set_property(TARGET ${_library} + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + $) + install(TARGETS ${_library} EXPORT protobuf-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${_library} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT ${_library}) +endforeach() + +install(TARGETS protoc EXPORT protobuf-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT protoc) + +if(TRUE) + file(STRINGS extract_includes.bat.in _extract_strings + REGEX "^copy") + foreach(_extract_string ${_extract_strings}) + string(REPLACE "copy \${PROTOBUF_SOURCE_WIN32_PATH}\\" "" + _extract_string ${_extract_string}) + string(REPLACE "\\" "/" _extract_string ${_extract_string}) + string(REGEX MATCH "^[^ ]+" + _extract_from ${_extract_string}) + string(REGEX REPLACE "^${_extract_from} ([^$]+)" "\\1" + _extract_to ${_extract_string}) + get_filename_component(_extract_from "${protobuf_SOURCE_DIR}/${_extract_from}" ABSOLUTE) + get_filename_component(_extract_name ${_extract_to} NAME) + get_filename_component(_extract_to ${_extract_to} PATH) + string(REPLACE "include/" "${CMAKE_INSTALL_INCLUDEDIR}/" + _extract_to "${_extract_to}") + if(EXISTS "${_extract_from}") + install(FILES "${_extract_from}" + DESTINATION "${_extract_to}" + COMPONENT protobuf-headers + RENAME "${_extract_name}") + else() + message(AUTHOR_WARNING "The file \"${_extract_from}\" is listed in " + "\"${protobuf_SOURCE_DIR}/cmake/extract_includes.bat.in\" " + "but there not exists. The file will not be installed.") + endif() + endforeach() +endif() + +# Internal function for parsing auto tools scripts +function(_protobuf_auto_list FILE_NAME VARIABLE) + file(STRINGS ${FILE_NAME} _strings) + set(_list) + foreach(_string ${_strings}) + set(_found) + string(REGEX MATCH "^[ \t]*${VARIABLE}[ \t]*=[ \t]*" _found "${_string}") + if(_found) + string(LENGTH "${_found}" _length) + string(SUBSTRING "${_string}" ${_length} -1 _draft_list) + foreach(_item ${_draft_list}) + string(STRIP "${_item}" _item) + list(APPEND _list "${_item}") + endforeach() + endif() + endforeach() + set(${VARIABLE} ${_list} PARENT_SCOPE) +endfunction() + +# Install well-known type proto files +_protobuf_auto_list("../src/Makefile.am" nobase_dist_proto_DATA) +foreach(_file ${nobase_dist_proto_DATA}) + get_filename_component(_file_from "../src/${_file}" ABSOLUTE) + get_filename_component(_file_name ${_file} NAME) + get_filename_component(_file_path ${_file} PATH) + if(EXISTS "${_file_from}") + install(FILES "${_file_from}" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_file_path}" + COMPONENT protobuf-protos + RENAME "${_file_name}") + else() + message(AUTHOR_WARNING "The file \"${_file_from}\" is listed in " + "\"${protobuf_SOURCE_DIR}/../src/Makefile.am\" as nobase_dist_proto_DATA " + "but there not exists. The file will not be installed.") + endif() +endforeach() + +# Export configuration + +install(EXPORT protobuf-targets + DESTINATION "lib/cmake/protobuf" + COMPONENT protobuf-export) + +configure_file(protobuf-config.cmake.in + protobuf-config.cmake @ONLY) +configure_file(protobuf-config-version.cmake.in + protobuf-config-version.cmake @ONLY) +configure_file(protobuf-module.cmake.in + protobuf-module.cmake @ONLY) + +install(FILES + "${protobuf_BINARY_DIR}/protobuf-config.cmake" + "${protobuf_BINARY_DIR}/protobuf-config-version.cmake" + "${protobuf_BINARY_DIR}/protobuf-module.cmake" + DESTINATION "lib/cmake/protobuf" + COMPONENT protobuf-export) diff --git a/cmake/protobuf-config-version.cmake.in b/cmake/protobuf-config-version.cmake.in index 07ab40b990ea6..1f171c66497a5 100644 --- a/cmake/protobuf-config-version.cmake.in +++ b/cmake/protobuf-config-version.cmake.in @@ -1 +1 @@ -set(PACKAGE_VERSION @protobuf_VERSION@) +set(PACKAGE_VERSION @protobuf_VERSION@) diff --git a/cmake/protobuf-config.cmake.in b/cmake/protobuf-config.cmake.in index 51d715cfa4c2d..bb0997b88be7e 100644 --- a/cmake/protobuf-config.cmake.in +++ b/cmake/protobuf-config.cmake.in @@ -1,27 +1,27 @@ -# Version info variables -set(PROTOBUF_VERSION "@protobuf_VERSION@") -set(PROTOBUF_VERSION_STRING "@protobuf_VERSION_STRING@") - -# Current dir -get_filename_component(_PROTOBUF_PACKAGE_PREFIX - "${CMAKE_CURRENT_LIST_FILE}" PATH) - -# Imported targets -include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-targets.cmake") - -# Compute the installation prefix relative to this file. -get_filename_component(_PROTOBUF_IMPORT_PREFIX - "${_PROTOBUF_PACKAGE_PREFIX}" PATH) -get_filename_component(_PROTOBUF_IMPORT_PREFIX - "${_PROTOBUF_IMPORT_PREFIX}" PATH) -get_filename_component(_PROTOBUF_IMPORT_PREFIX - "${_PROTOBUF_IMPORT_PREFIX}" PATH) - -# CMake FindProtobuf module compatible file -if(NOT DEFINED PROTOBUF_MODULE_COMPATIBLE OR "${PROTOBUF_MODULE_COMPATIBLE}") - include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-module.cmake") -endif() - -# Cleanup temporary variables. -set(_PROTOBUF_PACKAGE_PREFIX) -set(_PROTOBUF_IMPORT_PREFIX) +# Version info variables +set(PROTOBUF_VERSION "@protobuf_VERSION@") +set(PROTOBUF_VERSION_STRING "@protobuf_VERSION_STRING@") + +# Current dir +get_filename_component(_PROTOBUF_PACKAGE_PREFIX + "${CMAKE_CURRENT_LIST_FILE}" PATH) + +# Imported targets +include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-targets.cmake") + +# Compute the installation prefix relative to this file. +get_filename_component(_PROTOBUF_IMPORT_PREFIX + "${_PROTOBUF_PACKAGE_PREFIX}" PATH) +get_filename_component(_PROTOBUF_IMPORT_PREFIX + "${_PROTOBUF_IMPORT_PREFIX}" PATH) +get_filename_component(_PROTOBUF_IMPORT_PREFIX + "${_PROTOBUF_IMPORT_PREFIX}" PATH) + +# CMake FindProtobuf module compatible file +if(NOT DEFINED PROTOBUF_MODULE_COMPATIBLE OR "${PROTOBUF_MODULE_COMPATIBLE}") + include("${_PROTOBUF_PACKAGE_PREFIX}/protobuf-module.cmake") +endif() + +# Cleanup temporary variables. +set(_PROTOBUF_PACKAGE_PREFIX) +set(_PROTOBUF_IMPORT_PREFIX) diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java index 1d5d4e8a5ebe3..0bd1750d3f841 100644 --- a/java/src/main/java/com/google/protobuf/ByteString.java +++ b/java/src/main/java/com/google/protobuf/ByteString.java @@ -294,10 +294,10 @@ public static ByteString copyFromUtf8(String text) { * Performance notes: The returned {@code ByteString} is an * immutable tree of byte arrays ("chunks") of the stream data. The * first chunk is small, with subsequent chunks each being double - * the size, up to 8K. If the caller knows the precise length of - * the stream and wishes to avoid all unnecessary copies and - * allocations, consider using the two-argument version of this - * method, below. + * the size, up to 8K. + * + *

Each byte read from the input stream will be copied twice to ensure + * that the resulting ByteString is truly immutable. * * @param streamToDrain The source stream, which is read completely * but not closed. @@ -320,12 +320,10 @@ public static ByteString readFrom(InputStream streamToDrain) * * Performance notes: The returned {@code ByteString} is an * immutable tree of byte arrays ("chunks") of the stream data. The - * chunkSize parameter sets the size of these byte arrays. In - * particular, if the chunkSize is precisely the same as the length - * of the stream, unnecessary allocations and copies will be - * avoided. Otherwise, the chunks will be of the given size, except - * for the last chunk, which will be resized (via a reallocation and - * copy) to contain the remainder of the stream. + * chunkSize parameter sets the size of these byte arrays. + * + *

Each byte read from the input stream will be copied twice to ensure + * that the resulting ByteString is truly immutable. * * @param streamToDrain The source stream, which is read completely * but not closed. @@ -386,6 +384,7 @@ private static ByteString readChunk(InputStream in, final int chunkSize) if (bytesRead == 0) { return null; } else { + // Always make a copy since InputStream could steal a reference to buf. return ByteString.copyFrom(buf, 0, bytesRead); } } @@ -736,7 +735,8 @@ public String toStringUtf8() { * returns the number of bytes remaining in the stream. The methods * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)} * and {@link InputStream#skip(long)} will read/skip as many bytes as are - * available. + * available. The method {@link InputStream#markSupported()} returns + * {@code true}. *

* The methods in the returned {@link InputStream} might not be * thread safe. diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java index 954fde0861c13..291bd20abb7b6 100644 --- a/java/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -30,9 +30,13 @@ package com.google.protobuf; +import com.google.protobuf.Utf8.UnpairedSurrogateException; + import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Encodes and writes protocol message fields. @@ -49,6 +53,10 @@ * @author kneton@google.com Kenton Varda */ public final class CodedOutputStream { + + private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); + + // TODO(dweis): Consider migrating to a ByteBuffer. private final byte[] buffer; private final int limit; private int position; @@ -415,15 +423,87 @@ public void writeBoolNoTag(final boolean value) throws IOException { } /** Write a {@code string} field to the stream. */ + // TODO(dweis): Document behavior on ill-formed UTF-16 input. public void writeStringNoTag(final String value) throws IOException { + try { + efficientWriteStringNoTag(value); + } catch (UnpairedSurrogateException e) { + logger.log(Level.WARNING, + "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e); + inefficientWriteStringNoTag(value); + } + } + + /** Write a {@code string} field to the stream. */ + private void inefficientWriteStringNoTag(final String value) throws IOException { // Unfortunately there does not appear to be any way to tell Java to encode // UTF-8 directly into our buffer, so we have to let it create its own byte // array and then copy. + // TODO(dweis): Consider using nio Charset methods instead. final byte[] bytes = value.getBytes(Internal.UTF_8); writeRawVarint32(bytes.length); writeRawBytes(bytes); } + /** + * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed, + * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the + * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}. + * + * @param value the string to write to the stream + * + * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16. + */ + private void efficientWriteStringNoTag(final String value) throws IOException { + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. We take advantage of this in both branches below. + final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; + final int maxLengthVarIntSize = computeRawVarint32Size(maxLength); + + // If we are streaming and the potential length is too big to fit in our buffer, we take the + // slower path. Otherwise, we're good to try the fast path. + if (output != null && maxLengthVarIntSize + maxLength > limit - position) { + // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() + // does the same internally and then does *another copy* to return a byte[] of exactly the + // right size. We can skip that copy and just writeRawBytes up to the actualLength of the + // UTF-8 encoded bytes. + final byte[] encodedBytes = new byte[maxLength]; + int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); + writeRawVarint32(actualLength); + writeRawBytes(encodedBytes, 0, actualLength); + } else { + // Optimize for the case where we know this length results in a constant varint length as this + // saves a pass for measuring the length of the string. + final int minLengthVarIntSize = computeRawVarint32Size(value.length()); + int oldPosition = position; + final int length; + try { + if (minLengthVarIntSize == maxLengthVarIntSize) { + position = oldPosition + minLengthVarIntSize; + int newPosition = Utf8.encode(value, buffer, position, limit - position); + // Since this class is stateful and tracks the position, we rewind and store the state, + // prepend the length, then reset it back to the end of the string. + position = oldPosition; + length = newPosition - oldPosition - minLengthVarIntSize; + writeRawVarint32(length); + position = newPosition; + } else { + length = Utf8.encodedLength(value); + writeRawVarint32(length); + position = Utf8.encode(value, buffer, position, limit - position); + } + } catch (UnpairedSurrogateException e) { + // Be extra careful and restore the original position for retrying the write with the less + // efficient path. + position = oldPosition; + throw e; + } catch (ArrayIndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } + totalBytesWritten += length; + } + } + /** Write a {@code group} field to the stream. */ public void writeGroupNoTag(final MessageLite value) throws IOException { value.writeTo(this); @@ -826,9 +906,16 @@ public static int computeBoolSizeNoTag(final boolean value) { * {@code string} field. */ public static int computeStringSizeNoTag(final String value) { - final byte[] bytes = value.getBytes(Internal.UTF_8); - return computeRawVarint32Size(bytes.length) + - bytes.length; + int length; + try { + length = Utf8.encodedLength(value); + } catch (UnpairedSurrogateException e) { + // TODO(dweis): Consider using nio Charset methods instead. + final byte[] bytes = value.getBytes(Internal.UTF_8); + length = bytes.length; + } + + return computeRawVarint32Size(length) + length; } /** @@ -1007,9 +1094,15 @@ public void checkNoSpaceLeft() { public static class OutOfSpaceException extends IOException { private static final long serialVersionUID = -6947486886997889499L; + private static final String MESSAGE = + "CodedOutputStream was writing to a flat byte array and ran out of space."; + OutOfSpaceException() { - super("CodedOutputStream was writing to a flat byte array and ran " + - "out of space."); + super(MESSAGE); + } + + OutOfSpaceException(Throwable cause) { + super(MESSAGE, cause); } } diff --git a/java/src/main/java/com/google/protobuf/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java index 3658410cd65e2..fb9005bdc0afa 100644 --- a/java/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/src/main/java/com/google/protobuf/Descriptors.java @@ -1118,9 +1118,9 @@ public static Type valueOf(final FieldDescriptorProto.Type type) { static { // Refuse to init if someone added a new declared type. if (Type.values().length != FieldDescriptorProto.Type.values().length) { - throw new RuntimeException( - "descriptor.proto has a new declared type but Desrciptors.java " + - "wasn't updated."); + throw new RuntimeException("" + + "descriptor.proto has a new declared type but Descriptors.java " + + "wasn't updated."); } } diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java index 9457d9996194e..d84fa75c5110f 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -121,22 +121,44 @@ private Map getAllFieldsMutable( final TreeMap result = new TreeMap(); final Descriptor descriptor = internalGetFieldAccessorTable().descriptor; - for (final FieldDescriptor field : descriptor.getFields()) { - if (field.isRepeated()) { - final List value = (List) getField(field); - if (!value.isEmpty()) { - result.put(field, value); + final List fields = descriptor.getFields(); + + for (int i = 0; i < fields.size(); i++) { + FieldDescriptor field = fields.get(i); + final OneofDescriptor oneofDescriptor = field.getContainingOneof(); + + /* + * If the field is part of a Oneof, then at maximum one field in the Oneof is set + * and it is not repeated. There is no need to iterate through the others. + */ + if (oneofDescriptor != null) { + // Skip other fields in the Oneof we know are not set + i += oneofDescriptor.getFieldCount() - 1; + if (!hasOneof(oneofDescriptor)) { + // If no field is set in the Oneof, skip all the fields in the Oneof + continue; } + // Get the pointer to the only field which is set in the Oneof + field = getOneofFieldDescriptor(oneofDescriptor); } else { - if (hasField(field)) { - if (getBytesForString - && field.getJavaType() == FieldDescriptor.JavaType.STRING) { - result.put(field, getFieldRaw(field)); - } else { - result.put(field, getField(field)); + // If we are not in a Oneof, we need to check if the field is set and if it is repeated + if (field.isRepeated()) { + final List value = (List) getField(field); + if (!value.isEmpty()) { + result.put(field, value); } + continue; + } + if (!hasField(field)) { + continue; } } + // Add the field to the map + if (getBytesForString && field.getJavaType() == FieldDescriptor.JavaType.STRING) { + result.put(field, getFieldRaw(field)); + } else { + result.put(field, getField(field)); + } } return result; } @@ -398,17 +420,40 @@ private Map getAllFieldsMutable() { final TreeMap result = new TreeMap(); final Descriptor descriptor = internalGetFieldAccessorTable().descriptor; - for (final FieldDescriptor field : descriptor.getFields()) { - if (field.isRepeated()) { - final List value = (List) getField(field); - if (!value.isEmpty()) { - result.put(field, value); + final List fields = descriptor.getFields(); + + for (int i = 0; i < fields.size(); i++) { + FieldDescriptor field = fields.get(i); + final OneofDescriptor oneofDescriptor = field.getContainingOneof(); + + /* + * If the field is part of a Oneof, then at maximum one field in the Oneof is set + * and it is not repeated. There is no need to iterate through the others. + */ + if (oneofDescriptor != null) { + // Skip other fields in the Oneof we know are not set + i += oneofDescriptor.getFieldCount() - 1; + if (!hasOneof(oneofDescriptor)) { + // If no field is set in the Oneof, skip all the fields in the Oneof + continue; } + // Get the pointer to the only field which is set in the Oneof + field = getOneofFieldDescriptor(oneofDescriptor); } else { - if (hasField(field)) { - result.put(field, getField(field)); + // If we are not in a Oneof, we need to check if the field is set and if it is repeated + if (field.isRepeated()) { + final List value = (List) getField(field); + if (!value.isEmpty()) { + result.put(field, value); + } + continue; + } + if (!hasField(field)) { + continue; } } + // Add the field to the map + result.put(field, getField(field)); } return result; } @@ -2696,4 +2741,38 @@ Extension checkNotLite( return (Extension) extension; } + + protected static int computeStringSize(final int fieldNumber, final Object value) { + if (value instanceof String) { + return CodedOutputStream.computeStringSize(fieldNumber, (String) value); + } else { + return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value); + } + } + + protected static int computeStringSizeNoTag(final Object value) { + if (value instanceof String) { + return CodedOutputStream.computeStringSizeNoTag((String) value); + } else { + return CodedOutputStream.computeBytesSizeNoTag((ByteString) value); + } + } + + protected static void writeString( + CodedOutputStream output, final int fieldNumber, final Object value) throws IOException { + if (value instanceof String) { + output.writeString(fieldNumber, (String) value); + } else { + output.writeBytes(fieldNumber, (ByteString) value); + } + } + + protected static void writeStringNoTag( + CodedOutputStream output, final Object value) throws IOException { + if (value instanceof String) { + output.writeStringNoTag((String) value); + } else { + output.writeBytesNoTag((ByteString) value); + } + } } diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java index bd6bc463dde5a..a535b718330c3 100644 --- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -48,7 +48,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * Lite version of {@link GeneratedMessage}. @@ -60,24 +59,6 @@ public abstract class GeneratedMessageLite< BuilderType extends GeneratedMessageLite.Builder> extends AbstractMessageLite implements Serializable { - - /** - * Holds all the {@link PrototypeHolder}s for loaded classes. - */ - // TODO(dweis): Consider different concurrency values. - // TODO(dweis): This will prevent garbage collection of the class loader. - // Ideally we'd use something like ClassValue but that's Java 7 only. - private static final Map, PrototypeHolder> PROTOTYPE_MAP = - new ConcurrentHashMap, PrototypeHolder>(); - - // For use by generated code only. - protected static < - MessageType extends GeneratedMessageLite, - BuilderType extends GeneratedMessageLite.Builder< - MessageType, BuilderType>> void onLoad(Class clazz, - PrototypeHolder protoTypeHolder) { - PROTOTYPE_MAP.put(clazz, protoTypeHolder); - } private static final long serialVersionUID = 1L; @@ -90,20 +71,17 @@ MessageType, BuilderType>> void onLoad(Class clazz, @SuppressWarnings("unchecked") // Guaranteed by runtime. public final Parser getParserForType() { - return (Parser) PROTOTYPE_MAP - .get(getClass()).getParserForType(); + return (Parser) dynamicMethod(MethodToInvoke.GET_PARSER); } @SuppressWarnings("unchecked") // Guaranteed by runtime. public final MessageType getDefaultInstanceForType() { - return (MessageType) PROTOTYPE_MAP - .get(getClass()).getDefaultInstanceForType(); + return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE); } @SuppressWarnings("unchecked") // Guaranteed by runtime. public final BuilderType newBuilderForType() { - return (BuilderType) PROTOTYPE_MAP - .get(getClass()).newBuilderForType(); + return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); } /** @@ -141,7 +119,9 @@ public static enum MethodToInvoke { MERGE_FROM, MAKE_IMMUTABLE, NEW_INSTANCE, - NEW_BUILDER; + NEW_BUILDER, + GET_DEFAULT_INSTANCE, + GET_PARSER; } /** @@ -168,9 +148,21 @@ public static enum MethodToInvoke { *

* For use by generated code only. */ - protected abstract Object dynamicMethod( - MethodToInvoke method, - Object... args); + protected abstract Object dynamicMethod(MethodToInvoke method, Object arg0, Object arg1); + + /** + * Same as {@link #dynamicMethod(MethodToInvoke, Object, Object)} with {@code null} padding. + */ + protected Object dynamicMethod(MethodToInvoke method, Object arg0) { + return dynamicMethod(method, arg0, null); + } + + /** + * Same as {@link #dynamicMethod(MethodToInvoke, Object, Object)} with {@code null} padding. + */ + protected Object dynamicMethod(MethodToInvoke method) { + return dynamicMethod(method, null, null); + } /** * Merge some unknown fields into the {@link UnknownFieldSetLite} for this @@ -1059,18 +1051,22 @@ static final class SerializedForm implements Serializable { @SuppressWarnings("unchecked") protected Object readResolve() throws ObjectStreamException { try { - Class messageClass = Class.forName(messageClassName); - Parser parser = - (Parser) messageClass.getField("PARSER").get(null); - return parser.parsePartialFrom(asBytes); + Class messageClass = Class.forName(messageClassName); + java.lang.reflect.Field defaultInstanceField = + messageClass.getDeclaredField("DEFAULT_INSTANCE"); + defaultInstanceField.setAccessible(true); + MessageLite defaultInstance = (MessageLite) defaultInstanceField.get(null); + return defaultInstance.newBuilderForType() + .mergeFrom(asBytes) + .buildPartial(); } catch (ClassNotFoundException e) { - throw new RuntimeException("Unable to find proto buffer class", e); + throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e); } catch (NoSuchFieldException e) { - throw new RuntimeException("Unable to find PARSER", e); + throw new RuntimeException("Unable to find DEFAULT_INSTANCE in " + messageClassName, e); } catch (SecurityException e) { - throw new RuntimeException("Unable to call PARSER", e); + throw new RuntimeException("Unable to call DEFAULT_INSTANCE in " + messageClassName, e); } catch (IllegalAccessException e) { - throw new RuntimeException("Unable to call parseFrom method", e); + throw new RuntimeException("Unable to call parsePartialFrom", e); } catch (InvalidProtocolBufferException e) { throw new RuntimeException("Unable to understand proto buffer", e); } @@ -1103,45 +1099,6 @@ GeneratedExtension checkIsLite( return (GeneratedExtension) extension; } - - /** - * Represents the state needed to implement *ForType methods. Generated code - * must provide a static singleton instance by adding it with - * {@link GeneratedMessageLite#onLoad(Class, PrototypeHolder)} on class load. - *

- * This allows us to trade three generated methods for a static Map. - */ - protected static class PrototypeHolder< - MessageType extends GeneratedMessageLite, - BuilderType extends GeneratedMessageLite.Builder< - MessageType, BuilderType>> { - - private final MessageType defaultInstance; - private final Parser parser; - - public PrototypeHolder( - MessageType defaultInstance, Parser parser) { - this.defaultInstance = defaultInstance; - this.parser = parser; - } - - public MessageType getDefaultInstanceForType() { - return defaultInstance; - } - - public Parser getParserForType() { - return parser; - } - - @SuppressWarnings("unchecked") // Guaranteed by runtime. - public BuilderType newBuilderForType() { - return (BuilderType) defaultInstance.toBuilder(); - } - } /** * A static helper method for checking if a message is initialized, optionally memoizing. diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java index 20054b7917da6..fefda90406f94 100644 --- a/java/src/main/java/com/google/protobuf/Internal.java +++ b/java/src/main/java/com/google/protobuf/Internal.java @@ -31,6 +31,7 @@ package com.google.protobuf; import java.io.IOException; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.AbstractList; @@ -358,6 +359,17 @@ public static int hashCodeByteBuffer(ByteBuffer bytes) { } } + @SuppressWarnings("unchecked") + public static T getDefaultInstance(Class clazz) { + try { + Method method = clazz.getMethod("getDefaultInstance"); + return (T) method.invoke(method); + } catch (Exception e) { + throw new RuntimeException( + "Failed to get default instance for " + clazz, e); + } + } + /** * An empty byte array constant used in generated code. */ diff --git a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java index 367fa23ba3b0f..0a76105278fba 100644 --- a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java +++ b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java @@ -69,7 +69,7 @@ public MessageLite getUnfinishedMessage() { static InvalidProtocolBufferException truncatedMessage() { return new InvalidProtocolBufferException( "While parsing a protocol message, the input ended unexpectedly " + - "in the middle of a field. This could mean either than the " + + "in the middle of a field. This could mean either that the " + "input has been truncated or that an embedded message " + "misreported its own length."); } diff --git a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java index a2997e1cb65ab..c3be3cca8f6c1 100644 --- a/java/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -215,6 +215,11 @@ public void add(byte[] element) { modCount++; } + @Override + public Object getRaw(int index) { + return list.get(index); + } + // @Override public ByteString getByteString(int index) { Object o = list.get(index); diff --git a/java/src/main/java/com/google/protobuf/LazyStringList.java b/java/src/main/java/com/google/protobuf/LazyStringList.java index 235126b685845..3eeedca1d3839 100644 --- a/java/src/main/java/com/google/protobuf/LazyStringList.java +++ b/java/src/main/java/com/google/protobuf/LazyStringList.java @@ -56,7 +56,18 @@ public interface LazyStringList extends ProtocolStringList { * ({@code index < 0 || index >= size()}) */ ByteString getByteString(int index); - + + /** + * Returns the element at the specified position in this list as an Object + * that will either be a String or a ByteString. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range + * ({@code index < 0 || index >= size()}) + */ + Object getRaw(int index); + /** * Returns the element at the specified position in this list as byte[]. * diff --git a/java/src/main/java/com/google/protobuf/Message.java b/java/src/main/java/com/google/protobuf/Message.java index fa0265e2e3613..9516d71f296e8 100644 --- a/java/src/main/java/com/google/protobuf/Message.java +++ b/java/src/main/java/com/google/protobuf/Message.java @@ -121,6 +121,9 @@ interface Builder extends MessageLite.Builder, MessageOrBuilder { * using the same merging rules.
* * For repeated fields, the elements in {@code other} are concatenated * with the elements in this message. + * * For oneof groups, if the other message has one of the fields set, + * the group of this message is cleared and replaced by the field + * of the other message, so that the oneof constraint is preserved. * * This is equivalent to the {@code Message::MergeFrom} method in C++. */ diff --git a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java index be737b1a3274a..f91cdbced6aef 100644 --- a/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java +++ b/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java @@ -73,7 +73,7 @@ public class RepeatedFieldBuilder private GeneratedMessage.BuilderParent parent; // List of messages. Never null. It may be immutable, in which case - // isMessagesListImmutable will be true. See note below. + // isMessagesListMutable will be false. See note below. private List messages; // Whether messages is an mutable array that can be modified. diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java index 7ea8402211128..45d5fc357f0a8 100644 --- a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java +++ b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java @@ -31,6 +31,7 @@ package com.google.protobuf; import java.io.IOException; +import java.util.Arrays; /** * {@code UnknownFieldSetLite} is used to keep track of fields which were seen @@ -45,8 +46,11 @@ */ public final class UnknownFieldSetLite { + private static final int[] EMPTY_INT_ARRAY = new int[0]; + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + private static final UnknownFieldSetLite DEFAULT_INSTANCE = - new UnknownFieldSetLite(ByteString.EMPTY); + new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY); /** * Get an empty {@code UnknownFieldSetLite}. @@ -71,19 +75,41 @@ public static Builder newBuilder() { * {@code second}. */ static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) { - return new UnknownFieldSetLite(first.byteString.concat(second.byteString)); + int count = first.count + second.count; + int[] tags = Arrays.copyOf(first.tags, count); + System.arraycopy(second.tags, 0, tags, first.count, second.count); + Object[] objects = Arrays.copyOf(first.objects, count); + System.arraycopy(second.objects, 0, objects, first.count, second.count); + return new UnknownFieldSetLite(count, tags, objects); } - + + /** + * The number of elements in the set. + */ + private int count; + + /** + * The tag numbers for the elements in the set. + */ + private int[] tags; + /** - * The internal representation of the unknown fields. + * The boxed values of the elements in the set. */ - private final ByteString byteString; + private Object[] objects; + + /** + * The lazily computed serialized size of the set. + */ + private int memoizedSerializedSize = -1; /** - * Constructs the {@code UnknownFieldSetLite} as a thin wrapper around {@link ByteString}. + * Constructs the {@code UnknownFieldSetLite}. */ - private UnknownFieldSetLite(ByteString byteString) { - this.byteString = byteString; + private UnknownFieldSetLite(int count, int[] tags, Object[] objects) { + this.count = count; + this.tags = tags; + this.objects = objects; } /** @@ -92,17 +118,73 @@ private UnknownFieldSetLite(ByteString byteString) { *

For use by generated code only. */ public void writeTo(CodedOutputStream output) throws IOException { - output.writeRawBytes(byteString); + for (int i = 0; i < count; i++) { + int tag = tags[i]; + int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + output.writeUInt64(fieldNumber, (Long) objects[i]); + break; + case WireFormat.WIRETYPE_FIXED32: + output.writeFixed32(fieldNumber, (Integer) objects[i]); + break; + case WireFormat.WIRETYPE_FIXED64: + output.writeFixed64(fieldNumber, (Long) objects[i]); + break; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + output.writeBytes(fieldNumber, (ByteString) objects[i]); + break; + case WireFormat.WIRETYPE_START_GROUP: + output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); + ((UnknownFieldSetLite) objects[i]).writeTo(output); + output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + break; + default: + throw InvalidProtocolBufferException.invalidWireType(); + } + } } - /** * Get the number of bytes required to encode this set. * *

For use by generated code only. */ public int getSerializedSize() { - return byteString.size(); + int size = memoizedSerializedSize; + if (size != -1) { + return size; + } + + size = 0; + for (int i = 0; i < count; i++) { + int tag = tags[i]; + int fieldNumber = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + size += CodedOutputStream.computeUInt64Size(fieldNumber, (Long) objects[i]); + break; + case WireFormat.WIRETYPE_FIXED32: + size += CodedOutputStream.computeFixed32Size(fieldNumber, (Integer) objects[i]); + break; + case WireFormat.WIRETYPE_FIXED64: + size += CodedOutputStream.computeFixed64Size(fieldNumber, (Long) objects[i]); + break; + case WireFormat.WIRETYPE_LENGTH_DELIMITED: + size += CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) objects[i]); + break; + case WireFormat.WIRETYPE_START_GROUP: + size += CodedOutputStream.computeTagSize(fieldNumber) * 2 + + ((UnknownFieldSetLite) objects[i]).getSerializedSize(); + break; + default: + throw new IllegalStateException(InvalidProtocolBufferException.invalidWireType()); + } + } + + memoizedSerializedSize = size; + + return size; } @Override @@ -111,16 +193,34 @@ public boolean equals(Object obj) { return true; } - if (obj instanceof UnknownFieldSetLite) { - return byteString.equals(((UnknownFieldSetLite) obj).byteString); + if (obj == null) { + return false; + } + + if (!(obj instanceof UnknownFieldSetLite)) { + return false; + } + + UnknownFieldSetLite other = (UnknownFieldSetLite) obj; + if (count != other.count + // TODO(dweis): Only have to compare up to count but at worst 2x worse than we need to do. + || !Arrays.equals(tags, other.tags) + || !Arrays.deepEquals(objects, other.objects)) { + return false; } - return false; + return true; } @Override public int hashCode() { - return byteString.hashCode(); + int hashCode = 17; + + hashCode = 31 * hashCode + count; + hashCode = 31 * hashCode + Arrays.hashCode(tags); + hashCode = 31 * hashCode + Arrays.deepHashCode(objects); + + return hashCode; } /** @@ -131,28 +231,49 @@ public int hashCode() { *

For use by generated code only. */ public static final class Builder { + + // Arbitrarily chosen. + // TODO(dweis): Tune this number? + private static final int MIN_CAPACITY = 8; + + private int count = 0; + private int[] tags = EMPTY_INT_ARRAY; + private Object[] objects = EMPTY_OBJECT_ARRAY; - private ByteString.Output byteStringOutput; - private CodedOutputStream output; private boolean built; /** - * Constructs a {@code Builder}. Lazily initialized by - * {@link #ensureInitializedButNotBuilt()}. + * Constructs a {@code Builder}. */ private Builder() {} /** * Ensures internal state is initialized for use. */ - private void ensureInitializedButNotBuilt() { + private void ensureNotBuilt() { if (built) { throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders."); } - - if (output == null && byteStringOutput == null) { - byteStringOutput = ByteString.newOutput(100 /* initialCapacity */); - output = CodedOutputStream.newInstance(byteStringOutput); + } + + private void storeField(int tag, Object value) { + ensureCapacity(); + + tags[count] = tag; + objects[count] = value; + count++; + } + + /** + * Ensures that our arrays are long enough to store more metadata. + */ + private void ensureCapacity() { + if (count == tags.length) { + int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1; + int newLength = count + increment; + + tags = Arrays.copyOf(tags, newLength); + objects = Arrays.copyOf(objects, newLength); } } @@ -166,31 +287,28 @@ private void ensureInitializedButNotBuilt() { */ public boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { - ensureInitializedButNotBuilt(); + ensureNotBuilt(); final int fieldNumber = WireFormat.getTagFieldNumber(tag); switch (WireFormat.getTagWireType(tag)) { case WireFormat.WIRETYPE_VARINT: - output.writeUInt64(fieldNumber, input.readInt64()); + storeField(tag, input.readInt64()); return true; case WireFormat.WIRETYPE_FIXED32: - output.writeFixed32(fieldNumber, input.readFixed32()); + storeField(tag, input.readFixed32()); return true; case WireFormat.WIRETYPE_FIXED64: - output.writeFixed64(fieldNumber, input.readFixed64()); + storeField(tag, input.readFixed64()); return true; case WireFormat.WIRETYPE_LENGTH_DELIMITED: - output.writeBytes(fieldNumber, input.readBytes()); + storeField(tag, input.readBytes()); return true; case WireFormat.WIRETYPE_START_GROUP: final Builder subBuilder = newBuilder(); subBuilder.mergeFrom(input); input.checkLastTagWas( WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP)); - - output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); - subBuilder.build().writeTo(output); - output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); + storeField(tag, subBuilder.build()); return true; case WireFormat.WIRETYPE_END_GROUP: return false; @@ -210,12 +328,10 @@ public Builder mergeVarintField(int fieldNumber, int value) { if (fieldNumber == 0) { throw new IllegalArgumentException("Zero is not a valid field number."); } - ensureInitializedButNotBuilt(); - try { - output.writeUInt64(fieldNumber, value); - } catch (IOException e) { - // Should never happen. - } + ensureNotBuilt(); + + storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value); + return this; } @@ -229,11 +345,24 @@ public Builder mergeLengthDelimitedField( if (fieldNumber == 0) { throw new IllegalArgumentException("Zero is not a valid field number."); } - ensureInitializedButNotBuilt(); - try { - output.writeBytes(fieldNumber, value); - } catch (IOException e) { - // Should never happen. + ensureNotBuilt(); + + storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value); + + return this; + } + + /** + * Parse an entire message from {@code input} and merge its fields into + * this set. + */ + private Builder mergeFrom(final CodedInputStream input) throws IOException { + // Ensures initialization in mergeFieldFrom. + while (true) { + final int tag = input.readTag(); + if (tag == 0 || !mergeFieldFrom(tag, input)) { + break; + } } return this; } @@ -254,44 +383,12 @@ public UnknownFieldSetLite build() { } built = true; - - final UnknownFieldSetLite result; - // If we were never initialized, no data was written. - if (output == null) { - result = getDefaultInstance(); - } else { - try { - output.flush(); - } catch (IOException e) { - // Should never happen. - } - ByteString byteString = byteStringOutput.toByteString(); - if (byteString.isEmpty()) { - result = getDefaultInstance(); - } else { - result = new UnknownFieldSetLite(byteString); - } + + if (count == 0) { + return DEFAULT_INSTANCE; } - // Allow for garbage collection. - output = null; - byteStringOutput = null; - return result; - } - - /** - * Parse an entire message from {@code input} and merge its fields into - * this set. - */ - private Builder mergeFrom(final CodedInputStream input) throws IOException { - // Ensures initialization in mergeFieldFrom. - while (true) { - final int tag = input.readTag(); - if (tag == 0 || !mergeFieldFrom(tag, input)) { - break; - } - } - return this; + return new UnknownFieldSetLite(count, tags, objects); } } } diff --git a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java index 5cc005df88eee..5257c5a2352e4 100644 --- a/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java +++ b/java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java @@ -57,6 +57,11 @@ public UnmodifiableLazyStringList(LazyStringList list) { public String get(int index) { return list.get(index); } + + @Override + public Object getRaw(int index) { + return list.getRaw(index); + } @Override public int size() { diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/src/main/java/com/google/protobuf/Utf8.java index 4271b41bc962c..0699778f73126 100644 --- a/java/src/main/java/com/google/protobuf/Utf8.java +++ b/java/src/main/java/com/google/protobuf/Utf8.java @@ -66,6 +66,12 @@ */ final class Utf8 { private Utf8() {} + + /** + * Maximum number of bytes per Java UTF-16 char in UTF-8. + * @see java.nio.charset.CharsetEncoder#maxBytesPerChar() + */ + static final int MAX_BYTES_PER_CHAR = 3; /** * State value indicating that the byte sequence is well-formed and @@ -346,4 +352,130 @@ private static int incompleteStateFor(byte[] bytes, int index, int limit) { default: throw new AssertionError(); } } + + + // These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw + // a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can + // fallback to more lenient behavior. + + static class UnpairedSurrogateException extends IllegalArgumentException { + + private UnpairedSurrogateException(int index) { + super("Unpaired surrogate at index " + index); + } + } + + /** + * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string, + * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in + * both time and space. + * + * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired + * surrogates) + */ + static int encodedLength(CharSequence sequence) { + // Warning to maintainers: this implementation is highly optimized. + int utf16Length = sequence.length(); + int utf8Length = utf16Length; + int i = 0; + + // This loop optimizes for pure ASCII. + while (i < utf16Length && sequence.charAt(i) < 0x80) { + i++; + } + + // This loop optimizes for chars less than 0x800. + for (; i < utf16Length; i++) { + char c = sequence.charAt(i); + if (c < 0x800) { + utf8Length += ((0x7f - c) >>> 31); // branch free! + } else { + utf8Length += encodedLengthGeneral(sequence, i); + break; + } + } + + if (utf8Length < utf16Length) { + // Necessary and sufficient condition for overflow because of maximum 3x expansion + throw new IllegalArgumentException("UTF-8 length does not fit in int: " + + (utf8Length + (1L << 32))); + } + return utf8Length; + } + + private static int encodedLengthGeneral(CharSequence sequence, int start) { + int utf16Length = sequence.length(); + int utf8Length = 0; + for (int i = start; i < utf16Length; i++) { + char c = sequence.charAt(i); + if (c < 0x800) { + utf8Length += (0x7f - c) >>> 31; // branch free! + } else { + utf8Length += 2; + // jdk7+: if (Character.isSurrogate(c)) { + if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) { + // Check that we have a well-formed surrogate pair. + int cp = Character.codePointAt(sequence, i); + if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) { + throw new UnpairedSurrogateException(i); + } + i++; + } + } + } + return utf8Length; + } + + static int encode(CharSequence sequence, byte[] bytes, int offset, int length) { + int utf16Length = sequence.length(); + int j = offset; + int i = 0; + int limit = offset + length; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) { + bytes[j + i] = (byte) c; + } + if (i == utf16Length) { + return j + utf16Length; + } + j += i; + for (char c; i < utf16Length; i++) { + c = sequence.charAt(i); + if (c < 0x80 && j < limit) { + bytes[j++] = (byte) c; + } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes + bytes[j++] = (byte) ((0xF << 6) | (c >>> 6)); + bytes[j++] = (byte) (0x80 | (0x3F & c)); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + bytes[j++] = (byte) ((0xF << 5) | (c >>> 12)); + bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6))); + bytes[j++] = (byte) (0x80 | (0x3F & c)); + } else if (j <= limit - 4) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes + final char low; + if (i + 1 == sequence.length() + || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { + throw new UnpairedSurrogateException((i - 1)); + } + int codePoint = Character.toCodePoint(c, low); + bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); + bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12))); + bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6))); + bytes[j++] = (byte) (0x80 | (0x3F & codePoint)); + } else { + // If we are surrogates and we're not a surrogate pair, always throw an + // IllegalArgumentException instead of an ArrayOutOfBoundsException. + if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) + && (i + 1 == sequence.length() + || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) { + throw new UnpairedSurrogateException(i); + } + throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); + } + } + return j; + } + // End Guava UTF-8 methods. } diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java index ba83b6665ac11..8dbe1ae33c762 100644 --- a/java/src/main/java/com/google/protobuf/WireFormat.java +++ b/java/src/main/java/com/google/protobuf/WireFormat.java @@ -58,7 +58,7 @@ private WireFormat() {} static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1; /** Given a tag value, determines the wire type (the lower 3 bits). */ - static int getTagWireType(final int tag) { + public static int getTagWireType(final int tag) { return tag & TAG_TYPE_MASK; } diff --git a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java index 1562a1a604601..447e6ef31f476 100644 --- a/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java +++ b/java/src/test/java/com/google/protobuf/BoundedByteStringTest.java @@ -85,6 +85,7 @@ public void testCharsetToString() throws UnsupportedEncodingException { testString.substring(2, testString.length() - 6), roundTripString); } + @Override public void testJavaSerialization() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); diff --git a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java index 6470e9ca03410..3d6381c9b1439 100644 --- a/java/src/test/java/com/google/protobuf/CheckUtf8Test.java +++ b/java/src/test/java/com/google/protobuf/CheckUtf8Test.java @@ -58,8 +58,7 @@ public void testBuildRequiredStringWithGoodUtf8() throws Exception { public void testParseRequiredStringWithGoodUtf8() throws Exception { ByteString serialized = BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString(); - assertEquals(UTF8_BYTE_STRING_TEXT, - StringWrapper.PARSER.parseFrom(serialized).getReq()); + assertEquals(UTF8_BYTE_STRING_TEXT, StringWrapper.parser().parseFrom(serialized).getReq()); } public void testBuildRequiredStringWithBadUtf8() throws Exception { @@ -93,7 +92,7 @@ public void testParseRequiredStringWithBadUtf8() throws Exception { ByteString serialized = BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString(); try { - StringWrapper.PARSER.parseFrom(serialized); + StringWrapper.parser().parseFrom(serialized); fail("Expected InvalidProtocolBufferException for non UTF-8 byte string."); } catch (InvalidProtocolBufferException exception) { assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); @@ -131,7 +130,7 @@ public void testParseRequiredStringWithBadUtf8Size() throws Exception { ByteString serialized = BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString(); try { - StringWrapperSize.PARSER.parseFrom(serialized); + StringWrapperSize.parser().parseFrom(serialized); fail("Expected InvalidProtocolBufferException for non UTF-8 byte string."); } catch (InvalidProtocolBufferException exception) { assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()); diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java index 365789c0437fd..360e759e0105f 100644 --- a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java +++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java @@ -40,6 +40,7 @@ import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -325,10 +326,41 @@ public void testGetTotalBytesWritten() throws Exception { for (int i = 0; i < 1024; ++i) { codedStream.writeRawBytes(value, 0, value.length); } + String string = + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; + // Ensure we take the slower fast path. + assertTrue(CodedOutputStream.computeRawVarint32Size(string.length()) + != CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR)); + + codedStream.writeStringNoTag(string); + int stringSize = CodedOutputStream.computeStringSizeNoTag(string); + // Make sure we have written more bytes than the buffer could hold. This is // to make the test complete. assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE); - assertEquals(value.length * 1024, codedStream.getTotalBytesWritten()); + + // Verify that the total bytes written is correct + assertEquals((value.length * 1024) + stringSize, codedStream.getTotalBytesWritten()); + } + + // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just + // this case. + public void testWriteStringNoTag_fastpath() throws Exception { + int bufferSize = 153; + String threeBytesPer = "\u0981"; + String string = threeBytesPer; + for (int i = 0; i < 50; i++) { + string += threeBytesPer; + } + // These checks ensure we will tickle the slower fast path. + assertEquals(1, CodedOutputStream.computeRawVarint32Size(string.length())); + assertEquals( + 2, CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR)); + assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR); + + CodedOutputStream output = + CodedOutputStream.newInstance(ByteBuffer.allocate(bufferSize), bufferSize); + output.writeStringNoTag(string); } public void testWriteToByteBuffer() throws Exception { @@ -398,4 +430,80 @@ public void testWriteByteArrayWithOffsets() throws Exception { assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination); assertEquals(3, codedStream.getTotalBytesWritten()); } + + public void testSerializeInvalidUtf8() throws Exception { + String[] invalidStrings = new String[] { + newString(Character.MIN_HIGH_SURROGATE), + "foobar" + newString(Character.MIN_HIGH_SURROGATE), + newString(Character.MIN_LOW_SURROGATE), + "foobar" + newString(Character.MIN_LOW_SURROGATE), + newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE) + }; + + CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream()); + CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]); + for (String s : invalidStrings) { + // TODO(dweis): These should all fail; instead they are corrupting data. + CodedOutputStream.computeStringSizeNoTag(s); + outputWithStream.writeStringNoTag(s); + outputWithArray.writeStringNoTag(s); + } + } + + private static String newString(char... chars) { + return new String(chars); + } + + /** Regression test for https://github.com/google/protobuf/issues/292 */ + public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception { + String testCase = "Foooooooo"; + assertEquals(CodedOutputStream.computeRawVarint32Size(testCase.length()), + CodedOutputStream.computeRawVarint32Size(testCase.length() * 3)); + assertEquals(11, CodedOutputStream.computeStringSize(1, testCase)); + // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes. + // An array of size 1 will cause a failure when trying to write the varint. + for (int i = 0; i < 11; i++) { + CodedOutputStream output = CodedOutputStream.newInstance(new byte[i]); + try { + output.writeString(1, testCase); + fail("Should have thrown an out of space exception"); + } catch (CodedOutputStream.OutOfSpaceException expected) {} + } + } + + public void testDifferentStringLengths() throws Exception { + // Test string serialization roundtrip using strings of the following lengths, + // with ASCII and Unicode characters requiring different UTF-8 byte counts per + // char, hence causing the length delimiter varint to sometimes require more + // bytes for the Unicode strings than the ASCII string of the same length. + int[] lengths = new int[] { + 0, + 1, + (1 << 4) - 1, // 1 byte for ASCII and Unicode + (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode + (1 << 11) - 1, // 2 bytes for ASCII and Unicode + (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode + (1 << 17) - 1, // 3 bytes for ASCII and Unicode + }; + for (int i : lengths) { + testEncodingOfString('q', i); // 1 byte per char + testEncodingOfString('\u07FF', i); // 2 bytes per char + testEncodingOfString('\u0981', i); // 3 bytes per char + } + } + + private void testEncodingOfString(char c, int length) throws Exception { + String fullString = fullString(c, length); + TestAllTypes testAllTypes = TestAllTypes.newBuilder() + .setOptionalString(fullString) + .build(); + assertEquals( + fullString, TestAllTypes.parseFrom(testAllTypes.toByteArray()).getOptionalString()); + } + + private String fullString(char c, int length) { + char[] result = new char[length]; + Arrays.fill(result, c); + return new String(result); + } } diff --git a/java/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/src/test/java/com/google/protobuf/FieldPresenceTest.java index acf2b023f0ae3..eaeec0b8aecc1 100644 --- a/java/src/test/java/com/google/protobuf/FieldPresenceTest.java +++ b/java/src/test/java/com/google/protobuf/FieldPresenceTest.java @@ -142,6 +142,16 @@ public void testHasMethod() { "OneofNestedMessage")); } + public void testOneofEquals() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TestAllTypes message1 = builder.build(); + // Set message2's oneof_uint32 field to defalut value. The two + // messages should be different when check with oneof case. + builder.setOneofUint32(0); + TestAllTypes message2 = builder.build(); + assertFalse(message1.equals(message2)); + } + public void testFieldPresence() { // Optional non-message fields set to their default value are treated the // same way as not set. diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 2bd8d1a9de1d6..70812b953f57f 100644 --- a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -187,8 +187,7 @@ public void testRepeatedArraysAreImmutable() throws Exception { } public void testParsedMessagesAreImmutable() throws Exception { - TestAllTypes value = TestAllTypes.PARSER.parseFrom( - TestUtil.getAllSet().toByteString()); + TestAllTypes value = TestAllTypes.parser().parseFrom(TestUtil.getAllSet().toByteString()); assertIsUnmodifiable(value.getRepeatedInt32List()); assertIsUnmodifiable(value.getRepeatedInt64List()); assertIsUnmodifiable(value.getRepeatedUint32List()); diff --git a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java b/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java index acd180036abf4..0ef414aac60fa 100644 --- a/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java +++ b/java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java @@ -89,7 +89,7 @@ public void testParseAndWrite() throws IOException { TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, ByteString.copyFrom(sink)); } - + public void testCaching() { String a = "a"; String b = "b"; @@ -106,24 +106,13 @@ public void testCaching() { assertSame(c, proto.getRepeatedString(1)); - // There's no way to directly observe that the ByteString is cached - // correctly on serialization, but we can observe that it had to recompute - // the string after serialization. + // Ensure serialization keeps strings cached. proto.toByteString(); - String aPrime = proto.getOptionalString(); - assertNotSame(a, aPrime); - assertEquals(a, aPrime); - String bPrime = proto.getRepeatedString(0); - assertNotSame(b, bPrime); - assertEquals(b, bPrime); - String cPrime = proto.getRepeatedString(1); - assertNotSame(c, cPrime); - assertEquals(c, cPrime); // And now the string should stay cached. - assertSame(aPrime, proto.getOptionalString()); - assertSame(bPrime, proto.getRepeatedString(0)); - assertSame(cPrime, proto.getRepeatedString(1)); + assertSame(a, proto.getOptionalString()); + assertSame(b, proto.getRepeatedString(0)); + assertSame(c, proto.getRepeatedString(1)); } public void testNoStringCachingIfOnlyBytesAccessed() throws Exception { diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java index 8c3b5e5c72b1a..b1f298ff40c5d 100644 --- a/java/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/src/test/java/com/google/protobuf/LiteTest.java @@ -42,6 +42,7 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase; import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup; import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup; +import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder; import com.google.protobuf.UnittestLite.TestNestedExtensionLite; import junit.framework.TestCase; @@ -1400,6 +1401,8 @@ public void testSanityCopyOnWrite() throws InvalidProtocolBufferException { assertEquals("hi", messageAfterBuild.getOneofString()); assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase()); assertEquals(1, builder.getOneofUint32()); + TestAllTypesLiteOrBuilder messageOrBuilder = builder; + assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase()); TestAllExtensionsLite.Builder extendableMessageBuilder = TestAllExtensionsLite.newBuilder(); diff --git a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java index 958b6a7ecd231..7dfda2ae05d51 100644 --- a/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java +++ b/java/src/test/java/com/google/protobuf/LiteralByteStringTest.java @@ -34,6 +34,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; @@ -209,6 +210,62 @@ public void testCopyTo_ByteBuffer() { Arrays.equals(referenceBytes, myBuffer.array())); } + public void testMarkSupported() { + InputStream stream = stringUnderTest.newInput(); + assertTrue(classUnderTest + ".newInput() must support marking", stream.markSupported()); + } + + public void testMarkAndReset() throws IOException { + int fraction = stringUnderTest.size() / 3; + + InputStream stream = stringUnderTest.newInput(); + stream.mark(stringUnderTest.size()); // First, mark() the end. + + skipFully(stream, fraction); // Skip a large fraction, but not all. + int available = stream.available(); + assertTrue( + classUnderTest + ": after skipping to the 'middle', half the bytes are available", + (stringUnderTest.size() - fraction) == available); + stream.reset(); + + skipFully(stream, stringUnderTest.size()); // Skip to the end. + available = stream.available(); + assertTrue( + classUnderTest + ": after skipping to the end, no more bytes are available", + 0 == available); + } + + /** + * Discards {@code n} bytes of data from the input stream. This method + * will block until the full amount has been skipped. Does not close the + * stream. + *

Copied from com.google.common.io.ByteStreams to avoid adding dependency. + * + * @param in the input stream to read from + * @param n the number of bytes to skip + * @throws EOFException if this stream reaches the end before skipping all + * the bytes + * @throws IOException if an I/O error occurs, or the stream does not + * support skipping + */ + static void skipFully(InputStream in, long n) throws IOException { + long toSkip = n; + while (n > 0) { + long amt = in.skip(n); + if (amt == 0) { + // Force a blocking read to avoid infinite loop + if (in.read() == -1) { + long skipped = toSkip - n; + throw new EOFException("reached end of stream after skipping " + + skipped + " bytes; " + toSkip + " bytes expected"); + } + n--; + } else { + n -= amt; + } + } + } + public void testAsReadOnlyByteBuffer() { ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer(); byte[] roundTripBytes = new byte[referenceBytes.length]; @@ -305,13 +362,13 @@ public void testCharsetToString() throws UnsupportedEncodingException { assertEquals(classUnderTest + " unicode must match", testString, roundTripString); } - public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException{ + public void testToString_returnsCanonicalEmptyString() { assertSame(classUnderTest + " must be the same string references", ByteString.EMPTY.toString(Internal.UTF_8), new LiteralByteString(new byte[]{}).toString(Internal.UTF_8)); } - public void testToString_raisesException() throws UnsupportedEncodingException{ + public void testToString_raisesException() { try { ByteString.EMPTY.toString("invalid"); fail("Should have thrown an exception."); diff --git a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java index 6cff689ffa8b2..3d8c9bc4bf849 100644 --- a/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java +++ b/java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java @@ -74,6 +74,16 @@ private void setMapValues(TestMap.Builder builder) { builder.getMutableStringToInt32Field().put("3", 33); } + private void copyMapValues(TestMap source, TestMap.Builder destination) { + destination + .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) + .putAllInt32ToStringField(source.getInt32ToStringField()) + .putAllInt32ToBytesField(source.getInt32ToBytesField()) + .putAllInt32ToEnumField(source.getInt32ToEnumField()) + .putAllInt32ToMessageField(source.getInt32ToMessageField()) + .putAllStringToInt32Field(source.getStringToInt32Field()); + } + private void assertMapValuesSet(TestMap message) { assertEquals(3, message.getInt32ToInt32Field().size()); assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); @@ -330,26 +340,36 @@ public void testGettersAndSetters() throws Exception { assertMapValuesCleared(message); } + public void testPutAll() throws Exception { + TestMap.Builder sourceBuilder = TestMap.newBuilder(); + setMapValues(sourceBuilder); + TestMap source = sourceBuilder.build(); + + TestMap.Builder destination = TestMap.newBuilder(); + copyMapValues(source, destination); + assertMapValuesSet(destination.build()); + } + public void testSerializeAndParse() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); setMapValues(builder); TestMap message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesSet(message); builder = message.toBuilder(); updateMapValues(builder); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesUpdated(message); builder = message.toBuilder(); builder.clear(); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesCleared(message); } diff --git a/java/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/src/test/java/com/google/protobuf/MapForProto2Test.java index 7e984040f63bd..1fa3cbdbae774 100644 --- a/java/src/test/java/com/google/protobuf/MapForProto2Test.java +++ b/java/src/test/java/com/google/protobuf/MapForProto2Test.java @@ -78,6 +78,16 @@ private void setMapValues(TestMap.Builder builder) { builder.getMutableStringToInt32Field().put("3", 33); } + private void copyMapValues(TestMap source, TestMap.Builder destination) { + destination + .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) + .putAllInt32ToStringField(source.getInt32ToStringField()) + .putAllInt32ToBytesField(source.getInt32ToBytesField()) + .putAllInt32ToEnumField(source.getInt32ToEnumField()) + .putAllInt32ToMessageField(source.getInt32ToMessageField()) + .putAllStringToInt32Field(source.getStringToInt32Field()); + } + private void assertMapValuesSet(TestMap message) { assertEquals(3, message.getInt32ToInt32Field().size()); assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); @@ -310,26 +320,36 @@ public void testGettersAndSetters() throws Exception { assertMapValuesCleared(message); } + public void testPutAll() throws Exception { + TestMap.Builder sourceBuilder = TestMap.newBuilder(); + setMapValues(sourceBuilder); + TestMap source = sourceBuilder.build(); + + TestMap.Builder destination = TestMap.newBuilder(); + copyMapValues(source, destination); + assertMapValuesSet(destination.build()); + } + public void testSerializeAndParse() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); setMapValues(builder); TestMap message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesSet(message); builder = message.toBuilder(); updateMapValues(builder); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesUpdated(message); builder = message.toBuilder(); builder.clear(); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesCleared(message); } diff --git a/java/src/test/java/com/google/protobuf/MapTest.java b/java/src/test/java/com/google/protobuf/MapTest.java index 0509be152b4d5..0e5c12840c163 100644 --- a/java/src/test/java/com/google/protobuf/MapTest.java +++ b/java/src/test/java/com/google/protobuf/MapTest.java @@ -79,6 +79,16 @@ private void setMapValues(TestMap.Builder builder) { builder.getMutableStringToInt32Field().put("3", 33); } + private void copyMapValues(TestMap source, TestMap.Builder destination) { + destination + .putAllInt32ToInt32Field(source.getInt32ToInt32Field()) + .putAllInt32ToStringField(source.getInt32ToStringField()) + .putAllInt32ToBytesField(source.getInt32ToBytesField()) + .putAllInt32ToEnumField(source.getInt32ToEnumField()) + .putAllInt32ToMessageField(source.getInt32ToMessageField()) + .putAllStringToInt32Field(source.getStringToInt32Field()); + } + private void assertMapValuesSet(TestMap message) { assertEquals(3, message.getInt32ToInt32Field().size()); assertEquals(11, message.getInt32ToInt32Field().get(1).intValue()); @@ -311,26 +321,52 @@ public void testGettersAndSetters() throws Exception { assertMapValuesCleared(message); } + public void testPutAll() throws Exception { + TestMap.Builder sourceBuilder = TestMap.newBuilder(); + setMapValues(sourceBuilder); + TestMap source = sourceBuilder.build(); + + TestMap.Builder destination = TestMap.newBuilder(); + copyMapValues(source, destination); + assertMapValuesSet(destination.build()); + } + + public void testPutAllForUnknownEnumValues() throws Exception { + TestMap.Builder sourceBuilder = TestMap.newBuilder(); + sourceBuilder.getMutableInt32ToEnumFieldValue().put(0, 0); + sourceBuilder.getMutableInt32ToEnumFieldValue().put(1, 1); + sourceBuilder.getMutableInt32ToEnumFieldValue().put(2, 1000); // unknown value. + TestMap source = sourceBuilder.build(); + + TestMap.Builder destinationBuilder = TestMap.newBuilder(); + destinationBuilder.putAllInt32ToEnumFieldValue(source.getInt32ToEnumFieldValue()); + TestMap destination = destinationBuilder.build(); + + assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue()); + assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue()); + assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue()); + } + public void testSerializeAndParse() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); setMapValues(builder); TestMap message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesSet(message); builder = message.toBuilder(); updateMapValues(builder); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesUpdated(message); builder = message.toBuilder(); builder.clear(); message = builder.build(); assertEquals(message.getSerializedSize(), message.toByteString().size()); - message = TestMap.PARSER.parseFrom(message.toByteString()); + message = TestMap.parser().parseFrom(message.toByteString()); assertMapValuesCleared(message); } diff --git a/java/src/test/java/com/google/protobuf/ParserTest.java b/java/src/test/java/com/google/protobuf/ParserTest.java index b11d8cb96b376..5a92bacfbf535 100644 --- a/java/src/test/java/com/google/protobuf/ParserTest.java +++ b/java/src/test/java/com/google/protobuf/ParserTest.java @@ -58,8 +58,7 @@ public class ParserTest extends TestCase { public void testGeneratedMessageParserSingleton() throws Exception { for (int i = 0; i < 10; i++) { - assertEquals(TestAllTypes.PARSER, - TestUtil.getAllSet().getParserForType()); + assertEquals(TestAllTypes.parser(), TestUtil.getAllSet().getParserForType()); } } @@ -125,8 +124,7 @@ public void testNormalMessage() throws Exception { public void testParsePartial() throws Exception { - assertParsePartial(TestRequired.PARSER, - TestRequired.newBuilder().setA(1).buildPartial()); + assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial()); } private void assertParsePartial( @@ -216,8 +214,8 @@ public void testParseDelimitedTo() throws Exception { public void testParseUnknownFields() throws Exception { // All fields will be treated as unknown fields in emptyMessage. - TestEmptyMessage emptyMessage = TestEmptyMessage.PARSER.parseFrom( - TestUtil.getAllSet().toByteString()); + TestEmptyMessage emptyMessage = + TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString()); assertEquals( TestUtil.getAllSet().toByteString(), emptyMessage.toByteString()); @@ -298,8 +296,7 @@ public void testParsingMerge() throws Exception { // Parse TestParsingMerge. ExtensionRegistry registry = ExtensionRegistry.newInstance(); UnittestProto.registerAllExtensions(registry); - TestParsingMerge parsingMerge = - TestParsingMerge.PARSER.parseFrom(data, registry); + TestParsingMerge parsingMerge = TestParsingMerge.parser().parseFrom(data, registry); // Required and optional fields should be merged. assertMessageMerged(parsingMerge.getRequiredAllTypes()); @@ -361,8 +358,7 @@ public void testParsingMergeLite() throws Exception { // Parse TestParsingMergeLite. ExtensionRegistry registry = ExtensionRegistry.newInstance(); UnittestLite.registerAllExtensions(registry); - TestParsingMergeLite parsingMerge = - TestParsingMergeLite.PARSER.parseFrom(data, registry); + TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry); // Required and optional fields should be merged. assertMessageMerged(parsingMerge.getRequiredAllTypes()); diff --git a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java b/java/src/test/java/com/google/protobuf/RopeByteStringTest.java index bd0d15e3413e3..4ec3a409882cd 100644 --- a/java/src/test/java/com/google/protobuf/RopeByteStringTest.java +++ b/java/src/test/java/com/google/protobuf/RopeByteStringTest.java @@ -119,7 +119,7 @@ public void testToString() throws UnsupportedEncodingException { } @Override - public void testCharsetToString() throws UnsupportedEncodingException { + public void testCharsetToString() { String sourceString = "I love unicode \u1234\u5678 characters"; ByteString sourceByteString = ByteString.copyFromUtf8(sourceString); int copies = 250; @@ -145,14 +145,15 @@ public void testCharsetToString() throws UnsupportedEncodingException { } @Override - public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException { + public void testToString_returnsCanonicalEmptyString() { RopeByteString ropeByteString = RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY); assertSame(classUnderTest + " must be the same string references", ByteString.EMPTY.toString(Internal.UTF_8), ropeByteString.toString(Internal.UTF_8)); } - public void testToString_raisesException() throws UnsupportedEncodingException{ + @Override + public void testToString_raisesException() { try { ByteString byteString = RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY); @@ -172,6 +173,7 @@ public void testToString_raisesException() throws UnsupportedEncodingException{ } } + @Override public void testJavaSerialization() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java index 19a96d0e479ec..792e86658087f 100644 --- a/java/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/src/test/java/com/google/protobuf/TestUtil.java @@ -732,6 +732,7 @@ public static void assertAllFieldsSet(TestAllTypesOrBuilder message) { Assert.assertEquals("424", message.getDefaultStringPiece()); Assert.assertEquals("425", message.getDefaultCord()); + Assert.assertEquals(TestAllTypes.OneofFieldCase.ONEOF_BYTES, message.getOneofFieldCase()); Assert.assertFalse(message.hasOneofUint32()); Assert.assertFalse(message.hasOneofNestedMessage()); Assert.assertFalse(message.hasOneofString()); diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java index 5d8466465b084..8294b8655d87c 100644 --- a/java/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java @@ -32,7 +32,6 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; -import protobuf_unittest.UnittestMset.TestMessageSet; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; import protobuf_unittest.UnittestMset.TestMessageSetExtension2; import protobuf_unittest.UnittestProto.OneString; @@ -41,6 +40,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestOneof2; +import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; import junit.framework.TestCase; diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java index 93a5ee22ad922..8c9dcafeedaf9 100644 --- a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java +++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java @@ -461,7 +461,7 @@ public void testAllExtensionsLite() throws Exception { TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet(); ByteString allExtensionsData = allExtensions.toByteString(); UnittestLite.TestEmptyMessageLite emptyMessageLite = - UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData); + UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData); ByteString data = emptyMessageLite.toByteString(); TestAllExtensions message = TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry()); diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java index 6858524eac52c..0175005d2ca9f 100644 --- a/java/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java @@ -44,10 +44,10 @@ import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; -import protobuf_unittest.UnittestMset.TestMessageSet; import protobuf_unittest.UnittestMset.RawMessageSet; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; import protobuf_unittest.UnittestMset.TestMessageSetExtension2; +import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; import com.google.protobuf.UnittestLite.TestAllExtensionsLite; import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py index 72c2fa01bc0a6..9c8275ebb439e 100755 --- a/python/google/protobuf/internal/containers.py +++ b/python/google/protobuf/internal/containers.py @@ -41,6 +41,7 @@ __author__ = 'petar@google.com (Petar Petrov)' +import collections import sys if sys.version_info[0] < 3: @@ -63,7 +64,6 @@ # Note: deriving from object is critical. It is the only thing that makes # this a true type, allowing us to derive from it in C++ cleanly and making # __slots__ properly disallow arbitrary element assignment. - from collections import Mapping as _Mapping class Mapping(object): __slots__ = () @@ -106,7 +106,7 @@ def values(self): __hash__ = None def __eq__(self, other): - if not isinstance(other, _Mapping): + if not isinstance(other, collections.Mapping): return NotImplemented return dict(self.items()) == dict(other.items()) @@ -173,12 +173,13 @@ def setdefault(self, key, default=None): self[key] = default return default - _Mapping.register(Mapping) + collections.Mapping.register(Mapping) + collections.MutableMapping.register(MutableMapping) else: # In Python 3 we can just use MutableMapping directly, because it defines # __slots__. - from collections import MutableMapping + MutableMapping = collections.MutableMapping class BaseContainer(object): @@ -336,6 +337,8 @@ def __eq__(self, other): # We are presumably comparing against some other sequence type. return other == self._values +collections.MutableSequence.register(BaseContainer) + class RepeatedCompositeFieldContainer(BaseContainer): diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 5c07cbe6b17f8..c30f633d38e36 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -47,6 +47,7 @@ from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_import_public_pb2 from google.protobuf import unittest_mset_pb2 +from google.protobuf import unittest_mset_wire_format_pb2 from google.protobuf import unittest_no_generic_services_pb2 from google.protobuf import unittest_pb2 from google.protobuf import service @@ -142,7 +143,7 @@ def testIsExtension(self): self.assertTrue(not non_extension_descriptor.is_extension) def testOptions(self): - proto = unittest_mset_pb2.TestMessageSet() + proto = unittest_mset_wire_format_pb2.TestMessageSet() self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format) def testMessageWithCustomOptions(self): diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 320ff0d27b0a9..62abf1be6337d 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -43,6 +43,7 @@ __author__ = 'gps@google.com (Gregory P. Smith)' +import collections import copy import math import operator @@ -56,6 +57,7 @@ from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf.internal import api_implementation +from google.protobuf.internal import packed_field_test_pb2 from google.protobuf.internal import test_util from google.protobuf import message @@ -421,6 +423,31 @@ def testSortingRepeatedCompositeFieldsCustomComparator(self, message_module): self.assertEqual(message.repeated_nested_message[4].bb, 5) self.assertEqual(message.repeated_nested_message[5].bb, 6) + def testSortingRepeatedCompositeFieldsStable(self, message_module): + """Check passing a custom comparator to sort a repeated composite field.""" + message = message_module.TestAllTypes() + + message.repeated_nested_message.add().bb = 21 + message.repeated_nested_message.add().bb = 20 + message.repeated_nested_message.add().bb = 13 + message.repeated_nested_message.add().bb = 33 + message.repeated_nested_message.add().bb = 11 + message.repeated_nested_message.add().bb = 24 + message.repeated_nested_message.add().bb = 10 + message.repeated_nested_message.sort(key=lambda z: z.bb // 10) + self.assertEquals( + [13, 11, 10, 21, 20, 24, 33], + [n.bb for n in message.repeated_nested_message]) + + # Make sure that for the C++ implementation, the underlying fields + # are actually reordered. + pb = message.SerializeToString() + message.Clear() + message.MergeFromString(pb) + self.assertEquals( + [13, 11, 10, 21, 20, 24, 33], + [n.bb for n in message.repeated_nested_message]) + def testRepeatedCompositeFieldSortArguments(self, message_module): """Check sorting a repeated composite field using list.sort() arguments.""" message = message_module.TestAllTypes() @@ -514,6 +541,12 @@ def testRepeatedFieldsComparable(self, message_module): # TODO(anuraag): Implement extensiondict comparison in C++ and then add test + def testRepeatedFieldsAreSequences(self, message_module): + m = message_module.TestAllTypes() + self.assertIsInstance(m.repeated_int32, collections.MutableSequence) + self.assertIsInstance(m.repeated_nested_message, + collections.MutableSequence) + def ensureNestedMessageExists(self, msg, attribute): """Make sure that a nested message object exists. @@ -556,6 +589,18 @@ def testOneofSemantics(self, message_module): self.assertFalse(m.HasField('oneof_uint32')) self.assertTrue(m.HasField('oneof_string')) + # Read nested message accessor without accessing submessage. + m.oneof_nested_message + self.assertEqual('oneof_string', m.WhichOneof('oneof_field')) + self.assertTrue(m.HasField('oneof_string')) + self.assertFalse(m.HasField('oneof_nested_message')) + + # Read accessor of nested message without accessing submessage. + m.oneof_nested_message.bb + self.assertEqual('oneof_string', m.WhichOneof('oneof_field')) + self.assertTrue(m.HasField('oneof_string')) + self.assertFalse(m.HasField('oneof_nested_message')) + m.oneof_nested_message.bb = 11 self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field')) self.assertFalse(m.HasField('oneof_string')) @@ -1583,6 +1628,21 @@ def testMapDelete(self): del msg.map_int32_int32[4] self.assertEqual(0, len(msg.map_int32_int32)) + def testMapsAreMapping(self): + msg = map_unittest_pb2.TestMap() + self.assertIsInstance(msg.map_int32_int32, collections.Mapping) + self.assertIsInstance(msg.map_int32_int32, collections.MutableMapping) + self.assertIsInstance(msg.map_int32_foreign_message, collections.Mapping) + self.assertIsInstance(msg.map_int32_foreign_message, + collections.MutableMapping) + + def testMapFindInitializationErrorsSmokeTest(self): + msg = map_unittest_pb2.TestMap() + msg.map_string_string['abc'] = '123' + msg.map_int32_int32[35] = 64 + msg.map_string_foreign_message['foo'].c = 5 + self.assertEqual(0, len(msg.FindInitializationErrors())) + class ValidTypeNamesTest(unittest.TestCase): @@ -1606,6 +1666,61 @@ def testTypeNamesCanBeImported(self): self.assertImportFromName(pb.repeated_int32, 'Scalar') self.assertImportFromName(pb.repeated_nested_message, 'Composite') +class PackedFieldTest(unittest.TestCase): + + def setMessage(self, message): + message.repeated_int32.append(1) + message.repeated_int64.append(1) + message.repeated_uint32.append(1) + message.repeated_uint64.append(1) + message.repeated_sint32.append(1) + message.repeated_sint64.append(1) + message.repeated_fixed32.append(1) + message.repeated_fixed64.append(1) + message.repeated_sfixed32.append(1) + message.repeated_sfixed64.append(1) + message.repeated_float.append(1.0) + message.repeated_double.append(1.0) + message.repeated_bool.append(True) + message.repeated_nested_enum.append(1) + + def testPackedFields(self): + message = packed_field_test_pb2.TestPackedTypes() + self.setMessage(message) + golden_data = (b'\x0A\x01\x01' + b'\x12\x01\x01' + b'\x1A\x01\x01' + b'\x22\x01\x01' + b'\x2A\x01\x02' + b'\x32\x01\x02' + b'\x3A\x04\x01\x00\x00\x00' + b'\x42\x08\x01\x00\x00\x00\x00\x00\x00\x00' + b'\x4A\x04\x01\x00\x00\x00' + b'\x52\x08\x01\x00\x00\x00\x00\x00\x00\x00' + b'\x5A\x04\x00\x00\x80\x3f' + b'\x62\x08\x00\x00\x00\x00\x00\x00\xf0\x3f' + b'\x6A\x01\x01' + b'\x72\x01\x01') + self.assertEqual(golden_data, message.SerializeToString()) + + def testUnpackedFields(self): + message = packed_field_test_pb2.TestUnpackedTypes() + self.setMessage(message) + golden_data = (b'\x08\x01' + b'\x10\x01' + b'\x18\x01' + b'\x20\x01' + b'\x28\x02' + b'\x30\x02' + b'\x3D\x01\x00\x00\x00' + b'\x41\x01\x00\x00\x00\x00\x00\x00\x00' + b'\x4D\x01\x00\x00\x00' + b'\x51\x01\x00\x00\x00\x00\x00\x00\x00' + b'\x5D\x00\x00\x80\x3f' + b'\x61\x00\x00\x00\x00\x00\x00\xf0\x3f' + b'\x68\x01' + b'\x70\x01') + self.assertEqual(golden_data, message.SerializeToString()) if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/internal/packed_field_test.proto b/python/google/protobuf/internal/packed_field_test.proto index e69de29bb2d1d..0dfdc10a87ca3 100644 --- a/python/google/protobuf/internal/packed_field_test.proto +++ b/python/google/protobuf/internal/packed_field_test.proto @@ -0,0 +1,73 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf.python.internal; + +message TestPackedTypes { + enum NestedEnum { + FOO = 0; + BAR = 1; + BAZ = 2; + } + + repeated int32 repeated_int32 = 1; + repeated int64 repeated_int64 = 2; + repeated uint32 repeated_uint32 = 3; + repeated uint64 repeated_uint64 = 4; + repeated sint32 repeated_sint32 = 5; + repeated sint64 repeated_sint64 = 6; + repeated fixed32 repeated_fixed32 = 7; + repeated fixed64 repeated_fixed64 = 8; + repeated sfixed32 repeated_sfixed32 = 9; + repeated sfixed64 repeated_sfixed64 = 10; + repeated float repeated_float = 11; + repeated double repeated_double = 12; + repeated bool repeated_bool = 13; + repeated NestedEnum repeated_nested_enum = 14; +} + +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestPackedTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py index ca9f76753b725..a3e98467fa969 100755 --- a/python/google/protobuf/internal/python_message.py +++ b/python/google/protobuf/internal/python_message.py @@ -85,34 +85,108 @@ _FieldDescriptor = descriptor_mod.FieldDescriptor -def NewMessage(bases, descriptor, dictionary): - _AddClassAttributesForNestedExtensions(descriptor, dictionary) - _AddSlots(descriptor, dictionary) - return bases - - -def InitMessage(descriptor, cls): - cls._decoders_by_tag = {} - cls._extensions_by_name = {} - cls._extensions_by_number = {} - if (descriptor.has_options and - descriptor.GetOptions().message_set_wire_format): - cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( - decoder.MessageSetItemDecoder(cls._extensions_by_number), None) - - # Attach stuff to each FieldDescriptor for quick lookup later on. - for field in descriptor.fields: - _AttachFieldHelpers(cls, field) +class GeneratedProtocolMessageType(type): + + """Metaclass for protocol message classes created at runtime from Descriptors. + + We add implementations for all methods described in the Message class. We + also create properties to allow getting/setting all fields in the protocol + message. Finally, we create slots to prevent users from accidentally + "setting" nonexistent fields in the protocol message, which then wouldn't get + serialized / deserialized properly. + + The protocol compiler currently uses this metaclass to create protocol + message classes at runtime. Clients can also manually create their own + classes at runtime, as in this example: + + mydescriptor = Descriptor(.....) + class MyProtoClass(Message): + __metaclass__ = GeneratedProtocolMessageType + DESCRIPTOR = mydescriptor + myproto_instance = MyProtoClass() + myproto.foo_field = 23 + ... + + The above example will not work for nested types. If you wish to include them, + use reflection.MakeClass() instead of manually instantiating the class in + order to create the appropriate class structure. + """ + + # Must be consistent with the protocol-compiler code in + # proto2/compiler/internal/generator.*. + _DESCRIPTOR_KEY = 'DESCRIPTOR' + + def __new__(cls, name, bases, dictionary): + """Custom allocation for runtime-generated class types. + + We override __new__ because this is apparently the only place + where we can meaningfully set __slots__ on the class we're creating(?). + (The interplay between metaclasses and slots is not very well-documented). + + Args: + name: Name of the class (ignored, but required by the + metaclass protocol). + bases: Base classes of the class we're constructing. + (Should be message.Message). We ignore this field, but + it's required by the metaclass protocol + dictionary: The class dictionary of the class we're + constructing. dictionary[_DESCRIPTOR_KEY] must contain + a Descriptor object describing this protocol message + type. + + Returns: + Newly-allocated class. + """ + descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] + _AddClassAttributesForNestedExtensions(descriptor, dictionary) + _AddSlots(descriptor, dictionary) + + superclass = super(GeneratedProtocolMessageType, cls) + new_class = superclass.__new__(cls, name, bases, dictionary) + return new_class + + def __init__(cls, name, bases, dictionary): + """Here we perform the majority of our work on the class. + We add enum getters, an __init__ method, implementations + of all Message methods, and properties for all fields + in the protocol type. - descriptor._concrete_class = cls # pylint: disable=protected-access - _AddEnumValues(descriptor, cls) - _AddInitMethod(descriptor, cls) - _AddPropertiesForFields(descriptor, cls) - _AddPropertiesForExtensions(descriptor, cls) - _AddStaticMethods(cls) - _AddMessageMethods(descriptor, cls) - _AddPrivateHelperMethods(descriptor, cls) - copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__())) + Args: + name: Name of the class (ignored, but required by the + metaclass protocol). + bases: Base classes of the class we're constructing. + (Should be message.Message). We ignore this field, but + it's required by the metaclass protocol + dictionary: The class dictionary of the class we're + constructing. dictionary[_DESCRIPTOR_KEY] must contain + a Descriptor object describing this protocol message + type. + """ + descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] + cls._decoders_by_tag = {} + cls._extensions_by_name = {} + cls._extensions_by_number = {} + if (descriptor.has_options and + descriptor.GetOptions().message_set_wire_format): + cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = ( + decoder.MessageSetItemDecoder(cls._extensions_by_number), None) + + # Attach stuff to each FieldDescriptor for quick lookup later on. + for field in descriptor.fields: + _AttachFieldHelpers(cls, field) + + descriptor._concrete_class = cls # pylint: disable=protected-access + _AddEnumValues(descriptor, cls) + _AddInitMethod(descriptor, cls) + _AddPropertiesForFields(descriptor, cls) + _AddPropertiesForExtensions(descriptor, cls) + _AddStaticMethods(cls) + _AddMessageMethods(descriptor, cls) + _AddPrivateHelperMethods(descriptor, cls) + copyreg.pickle(cls, lambda obj: (cls, (), obj.__getstate__())) + + superclass = super(GeneratedProtocolMessageType, cls) + superclass.__init__(name, bases, dictionary) # Stateless helpers for GeneratedProtocolMessageType below. @@ -362,9 +436,10 @@ def MakeRepeatedScalarDefault(message): message_type = field.message_type def MakeSubMessageDefault(message): result = message_type._concrete_class() - result._SetListener(message._listener_for_children) - if field.containing_oneof: - message._UpdateOneofState(field) + result._SetListener( + _OneofListener(message, field) + if field.containing_oneof is not None + else message._listener_for_children) return result return MakeSubMessageDefault @@ -634,21 +709,11 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls): proto_field_name = field.name property_name = _PropertyName(proto_field_name) - # TODO(komarek): Can anyone explain to me why we cache the message_type this - # way, instead of referring to field.message_type inside of getter(self)? - # What if someone sets message_type later on (which makes for simpler - # dyanmic proto descriptor and class creation code). - message_type = field.message_type - def getter(self): field_value = self._fields.get(field) if field_value is None: # Construct a new object to represent this field. - field_value = message_type._concrete_class() # use field.message_type? - field_value._SetListener( - _OneofListener(self, field) - if field.containing_oneof is not None - else self._listener_for_children) + field_value = field._default_constructor(self) # Atomically check if another thread has preempted us and, if not, swap # in the new object we just created. If someone has preempted us, we @@ -1121,7 +1186,7 @@ def FindInitializationErrors(self): if _IsMessageMapField(field): for key in value: element = value[key] - prefix = "%s[%d]." % (name, key) + prefix = "%s[%s]." % (name, key) sub_errors = element.FindInitializationErrors() errors += [prefix + error for error in sub_errors] else: @@ -1173,8 +1238,6 @@ def MergeFrom(self, msg): # Construct a new object to represent this field. field_value = field._default_constructor(self) fields[field] = field_value - if field.containing_oneof: - self._UpdateOneofState(field) field_value.MergeFrom(value) else: self._fields[field] = value diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 4eca4989ea2fb..ef1ced4ea4208 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -52,6 +52,7 @@ from google.protobuf.internal import api_implementation from google.protobuf.internal import more_extensions_pb2 from google.protobuf.internal import more_messages_pb2 +from google.protobuf.internal import message_set_extensions_pb2 from google.protobuf.internal import wire_format from google.protobuf.internal import test_util from google.protobuf.internal import decoder @@ -1682,8 +1683,8 @@ def testStringUTF8Encoding(self): proto.optional_string = 'abc' def testStringUTF8Serialization(self): - proto = unittest_mset_pb2.TestMessageSet() - extension_message = unittest_mset_pb2.TestMessageSetExtension2 + proto = message_set_extensions_pb2.TestMessageSet() + extension_message = message_set_extensions_pb2.TestMessageSetExtension2 extension = extension_message.message_set_extension test_utf8 = u'Тест' @@ -1703,15 +1704,14 @@ def testStringUTF8Serialization(self): bytes_read = raw.MergeFromString(serialized) self.assertEqual(len(serialized), bytes_read) - message2 = unittest_mset_pb2.TestMessageSetExtension2() + message2 = message_set_extensions_pb2.TestMessageSetExtension2() self.assertEqual(1, len(raw.item)) # Check that the type_id is the same as the tag ID in the .proto file. - self.assertEqual(raw.item[0].type_id, 1547769) + self.assertEqual(raw.item[0].type_id, 98418634) # Check the actual bytes on the wire. - self.assertTrue( - raw.item[0].message.endswith(test_utf8_bytes)) + self.assertTrue(raw.item[0].message.endswith(test_utf8_bytes)) bytes_read = message2.MergeFromString(raw.item[0].message) self.assertEqual(len(raw.item[0].message), bytes_read) @@ -2395,9 +2395,9 @@ def testMergeFromStringWhenFieldsAlreadySet(self): self.assertEqual(42, second_proto.optional_nested_message.bb) def testMessageSetWireFormat(self): - proto = unittest_mset_pb2.TestMessageSet() - extension_message1 = unittest_mset_pb2.TestMessageSetExtension1 - extension_message2 = unittest_mset_pb2.TestMessageSetExtension2 + proto = message_set_extensions_pb2.TestMessageSet() + extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1 + extension_message2 = message_set_extensions_pb2.TestMessageSetExtension2 extension1 = extension_message1.message_set_extension extension2 = extension_message2.message_set_extension proto.Extensions[extension1].i = 123 @@ -2415,20 +2415,20 @@ def testMessageSetWireFormat(self): raw.MergeFromString(serialized)) self.assertEqual(2, len(raw.item)) - message1 = unittest_mset_pb2.TestMessageSetExtension1() + message1 = message_set_extensions_pb2.TestMessageSetExtension1() self.assertEqual( len(raw.item[0].message), message1.MergeFromString(raw.item[0].message)) self.assertEqual(123, message1.i) - message2 = unittest_mset_pb2.TestMessageSetExtension2() + message2 = message_set_extensions_pb2.TestMessageSetExtension2() self.assertEqual( len(raw.item[1].message), message2.MergeFromString(raw.item[1].message)) self.assertEqual('foo', message2.str) # Deserialize using the MessageSet wire format. - proto2 = unittest_mset_pb2.TestMessageSet() + proto2 = message_set_extensions_pb2.TestMessageSet() self.assertEqual( len(serialized), proto2.MergeFromString(serialized)) @@ -2446,37 +2446,37 @@ def testMessageSetWireFormatUnknownExtension(self): # Add an item. item = raw.item.add() - item.type_id = 1545008 - extension_message1 = unittest_mset_pb2.TestMessageSetExtension1 - message1 = unittest_mset_pb2.TestMessageSetExtension1() + item.type_id = 98418603 + extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1 + message1 = message_set_extensions_pb2.TestMessageSetExtension1() message1.i = 12345 item.message = message1.SerializeToString() # Add a second, unknown extension. item = raw.item.add() - item.type_id = 1545009 - extension_message1 = unittest_mset_pb2.TestMessageSetExtension1 - message1 = unittest_mset_pb2.TestMessageSetExtension1() + item.type_id = 98418604 + extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1 + message1 = message_set_extensions_pb2.TestMessageSetExtension1() message1.i = 12346 item.message = message1.SerializeToString() # Add another unknown extension. item = raw.item.add() - item.type_id = 1545010 - message1 = unittest_mset_pb2.TestMessageSetExtension2() + item.type_id = 98418605 + message1 = message_set_extensions_pb2.TestMessageSetExtension2() message1.str = 'foo' item.message = message1.SerializeToString() serialized = raw.SerializeToString() # Parse message using the message set wire format. - proto = unittest_mset_pb2.TestMessageSet() + proto = message_set_extensions_pb2.TestMessageSet() self.assertEqual( len(serialized), proto.MergeFromString(serialized)) # Check that the message parsed well. - extension_message1 = unittest_mset_pb2.TestMessageSetExtension1 + extension_message1 = message_set_extensions_pb2.TestMessageSetExtension1 extension1 = extension_message1.message_set_extension self.assertEquals(12345, proto.Extensions[extension1].i) @@ -2805,7 +2805,7 @@ def testInitRepeatedKwargs(self): class OptionsTest(unittest.TestCase): def testMessageOptions(self): - proto = unittest_mset_pb2.TestMessageSet() + proto = message_set_extensions_pb2.TestMessageSet() self.assertEqual(True, proto.DESCRIPTOR.GetOptions().message_set_wire_format) proto = unittest_pb2.TestAllTypes() @@ -2824,7 +2824,7 @@ def testPackedOptions(self): proto.packed_double.append(3.0) for field_descriptor, _ in proto.ListFields(): self.assertEqual(True, field_descriptor.GetOptions().packed) - self.assertEqual(reflection._FieldDescriptor.LABEL_REPEATED, + self.assertEqual(descriptor.FieldDescriptor.LABEL_REPEATED, field_descriptor.label) diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py index fec6538204e69..ac88fa81d823a 100755 --- a/python/google/protobuf/internal/test_util.py +++ b/python/google/protobuf/internal/test_util.py @@ -604,7 +604,8 @@ def GoldenFile(filename): # Search internally. path = '.' - full_path = os.path.join(path, 'third_party/py/google/protobuf/testdata', filename) + full_path = os.path.join(path, 'third_party/py/google/protobuf/testdata', + filename) if os.path.exists(full_path): # Found it. Load the golden file from the testdata directory. return open(full_path, 'rb') diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index 06bd1ee55837d..00e67654d9ee3 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -35,6 +35,7 @@ __author__ = 'kenton@google.com (Kenton Varda)' import re +import string import unittest import unittest @@ -497,6 +498,36 @@ def testPrintMap(self): ' }\n' '}\n') + def testMapOrderEnforcement(self): + message = map_unittest_pb2.TestMap() + for letter in string.ascii_uppercase[13:26]: + message.map_string_string[letter] = 'dummy' + for letter in reversed(string.ascii_uppercase[0:13]): + message.map_string_string[letter] = 'dummy' + golden = ''.join(( + 'map_string_string {\n key: "%c"\n value: "dummy"\n}\n' % (letter,) + for letter in string.ascii_uppercase)) + self.CompareToGoldenText(text_format.MessageToString(message), golden) + + def testMapOrderSemantics(self): + golden_lines = self.ReadGolden('map_test_data.txt') + # The C++ implementation emits defaulted-value fields, while the Python + # implementation does not. Adjusting for this is awkward, but it is + # valuable to test against a common golden file. + line_blacklist = (' key: 0\n', + ' value: 0\n', + ' key: false\n', + ' value: false\n') + golden_lines = [line for line in golden_lines if line not in line_blacklist] + + message = map_unittest_pb2.TestMap() + text_format.ParseLines(golden_lines, message) + candidate = text_format.MessageToString(message) + # The Python implementation emits "1.0" for the double value that the C++ + # implementation emits as "1". + candidate = candidate.replace('1.0', '1', 2) + self.assertMultiLineEqual(candidate, ''.join(golden_lines)) + # Tests of proto2-only features (MessageSet, extensions, etc.). class Proto2Tests(TextFormatBase): diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 1b81ae79bf084..0dda805bcaf09 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -41,11 +41,18 @@ from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf.internal import api_implementation from google.protobuf.internal import encoder +from google.protobuf.internal import message_set_extensions_pb2 from google.protobuf.internal import missing_enum_values_pb2 from google.protobuf.internal import test_util from google.protobuf.internal import type_checkers +def SkipIfCppImplementation(func): + return unittest.skipIf( + api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, + 'C++ implementation does not expose unknown fields to Python')(func) + + class UnknownFieldsTest(unittest.TestCase): def setUp(self): @@ -83,15 +90,15 @@ def testSerializeMessageSetWireFormatUnknownExtension(self): # Add an unknown extension. item = raw.item.add() - item.type_id = 1545009 - message1 = unittest_mset_pb2.TestMessageSetExtension1() + item.type_id = 98418603 + message1 = message_set_extensions_pb2.TestMessageSetExtension1() message1.i = 12345 item.message = message1.SerializeToString() serialized = raw.SerializeToString() # Parse message using the message set wire format. - proto = unittest_mset_pb2.TestMessageSet() + proto = message_set_extensions_pb2.TestMessageSet() proto.MergeFromString(serialized) # Verify that the unknown extension is serialized unchanged @@ -100,13 +107,6 @@ def testSerializeMessageSetWireFormatUnknownExtension(self): new_raw.MergeFromString(reserialized) self.assertEqual(raw, new_raw) - # C++ implementation for proto2 does not currently take into account unknown - # fields when checking equality. - # - # TODO(haberman): fix this. - @unittest.skipIf( - api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, - 'C++ implementation does not expose unknown fields to Python') def testEquals(self): message = unittest_pb2.TestEmptyMessage() message.ParseFromString(self.all_fields_data) @@ -117,9 +117,6 @@ def testEquals(self): self.assertNotEqual(self.empty_message, message) -@unittest.skipIf( - api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, - 'C++ implementation does not expose unknown fields to Python') class UnknownFieldsAccessorsTest(unittest.TestCase): def setUp(self): @@ -129,7 +126,14 @@ def setUp(self): self.all_fields_data = self.all_fields.SerializeToString() self.empty_message = unittest_pb2.TestEmptyMessage() self.empty_message.ParseFromString(self.all_fields_data) - self.unknown_fields = self.empty_message._unknown_fields + if api_implementation.Type() != 'cpp': + # _unknown_fields is an implementation detail. + self.unknown_fields = self.empty_message._unknown_fields + + # All the tests that use GetField() check an implementation detail of the + # Python implementation, which stores unknown fields as serialized strings. + # These tests are skipped by the C++ implementation: it's enough to check that + # the message is correctly serialized. def GetField(self, name): field_descriptor = self.descriptor.fields_by_name[name] @@ -142,30 +146,37 @@ def GetField(self, name): decoder(value, 0, len(value), self.all_fields, result_dict) return result_dict[field_descriptor] + @SkipIfCppImplementation def testEnum(self): value = self.GetField('optional_nested_enum') self.assertEqual(self.all_fields.optional_nested_enum, value) + @SkipIfCppImplementation def testRepeatedEnum(self): value = self.GetField('repeated_nested_enum') self.assertEqual(self.all_fields.repeated_nested_enum, value) + @SkipIfCppImplementation def testVarint(self): value = self.GetField('optional_int32') self.assertEqual(self.all_fields.optional_int32, value) + @SkipIfCppImplementation def testFixed32(self): value = self.GetField('optional_fixed32') self.assertEqual(self.all_fields.optional_fixed32, value) + @SkipIfCppImplementation def testFixed64(self): value = self.GetField('optional_fixed64') self.assertEqual(self.all_fields.optional_fixed64, value) + @SkipIfCppImplementation def testLengthDelimited(self): value = self.GetField('optional_string') self.assertEqual(self.all_fields.optional_string, value) + @SkipIfCppImplementation def testGroup(self): value = self.GetField('optionalgroup') self.assertEqual(self.all_fields.optionalgroup, value) @@ -173,7 +184,7 @@ def testGroup(self): def testCopyFrom(self): message = unittest_pb2.TestEmptyMessage() message.CopyFrom(self.empty_message) - self.assertEqual(self.unknown_fields, message._unknown_fields) + self.assertEqual(message.SerializeToString(), self.all_fields_data) def testMergeFrom(self): message = unittest_pb2.TestAllTypes() @@ -187,27 +198,26 @@ def testMergeFrom(self): message.optional_uint32 = 4 destination = unittest_pb2.TestEmptyMessage() destination.ParseFromString(message.SerializeToString()) - unknown_fields = destination._unknown_fields[:] destination.MergeFrom(source) - self.assertEqual(unknown_fields + source._unknown_fields, - destination._unknown_fields) + # Check that the fields where correctly merged, even stored in the unknown + # fields set. + message.ParseFromString(destination.SerializeToString()) + self.assertEqual(message.optional_int32, 1) + self.assertEqual(message.optional_uint32, 2) + self.assertEqual(message.optional_int64, 3) def testClear(self): self.empty_message.Clear() - self.assertEqual(0, len(self.empty_message._unknown_fields)) + # All cleared, even unknown fields. + self.assertEqual(self.empty_message.SerializeToString(), b'') def testUnknownExtensions(self): message = unittest_pb2.TestEmptyMessageWithExtensions() message.ParseFromString(self.all_fields_data) - self.assertEqual(self.empty_message._unknown_fields, - message._unknown_fields) - + self.assertEqual(message.SerializeToString(), self.all_fields_data) -@unittest.skipIf( - api_implementation.Type() == 'cpp' and api_implementation.Version() == 2, - 'C++ implementation does not expose unknown fields to Python') class UnknownEnumValuesTest(unittest.TestCase): def setUp(self): @@ -227,7 +237,14 @@ def setUp(self): self.message_data = self.message.SerializeToString() self.missing_message = missing_enum_values_pb2.TestMissingEnumValues() self.missing_message.ParseFromString(self.message_data) - self.unknown_fields = self.missing_message._unknown_fields + if api_implementation.Type() != 'cpp': + # _unknown_fields is an implementation detail. + self.unknown_fields = self.missing_message._unknown_fields + + # All the tests that use GetField() check an implementation detail of the + # Python implementation, which stores unknown fields as serialized strings. + # These tests are skipped by the C++ implementation: it's enough to check that + # the message is correctly serialized. def GetField(self, name): field_descriptor = self.descriptor.fields_by_name[name] @@ -241,15 +258,18 @@ def GetField(self, name): decoder(value, 0, len(value), self.message, result_dict) return result_dict[field_descriptor] + @SkipIfCppImplementation def testUnknownEnumValue(self): self.assertFalse(self.missing_message.HasField('optional_nested_enum')) value = self.GetField('optional_nested_enum') self.assertEqual(self.message.optional_nested_enum, value) + @SkipIfCppImplementation def testUnknownRepeatedEnumValue(self): value = self.GetField('repeated_nested_enum') self.assertEqual(self.message.repeated_nested_enum, value) + @SkipIfCppImplementation def testUnknownPackedEnumValue(self): value = self.GetField('packed_nested_enum') self.assertEqual(self.message.packed_nested_enum, value) diff --git a/python/google/protobuf/pyext/cpp_message.py b/python/google/protobuf/pyext/cpp_message.py index 037bb72c7df8e..b215211ee581f 100644 --- a/python/google/protobuf/pyext/cpp_message.py +++ b/python/google/protobuf/pyext/cpp_message.py @@ -37,21 +37,29 @@ __author__ = 'tibell@google.com (Johan Tibell)' from google.protobuf.pyext import _message -from google.protobuf import message -def NewMessage(bases, message_descriptor, dictionary): - """Creates a new protocol message *class*.""" - new_bases = [] - for base in bases: - if base is message.Message: - # _message.Message must come before message.Message as it - # overrides methods in that class. - new_bases.append(_message.Message) - new_bases.append(base) - return tuple(new_bases) +class GeneratedProtocolMessageType(_message.MessageMeta): + """Metaclass for protocol message classes created at runtime from Descriptors. -def InitMessage(message_descriptor, cls): - """Finalizes the creation of a message class.""" - cls.AddDescriptors(message_descriptor) + The protocol compiler currently uses this metaclass to create protocol + message classes at runtime. Clients can also manually create their own + classes at runtime, as in this example: + + mydescriptor = Descriptor(.....) + class MyProtoClass(Message): + __metaclass__ = GeneratedProtocolMessageType + DESCRIPTOR = mydescriptor + myproto_instance = MyProtoClass() + myproto.foo_field = 23 + ... + + The above example will not work for nested types. If you wish to include them, + use reflection.MakeClass() instead of manually instantiating the class in + order to create the appropriate class structure. + """ + + # Must be consistent with the protocol-compiler code in + # proto2/compiler/internal/generator.*. + _DESCRIPTOR_KEY = 'DESCRIPTOR' diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index 2160757b3bae4..8581f529e2bb3 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -193,7 +193,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) { io::CodedInputStream input( reinterpret_cast(serialized.c_str()), serialized.size()); input.SetExtensionRegistry(GetDescriptorPool()->pool, - cmessage::GetMessageFactory()); + GetDescriptorPool()->message_factory); bool success = cmsg->message->MergePartialFromCodedStream(&input); if (!success) { PyErr_Format(PyExc_ValueError, "Error parsing Options message"); diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc index ecd9084720c55..d5ba2b6ffb9fd 100644 --- a/python/google/protobuf/pyext/descriptor_pool.cc +++ b/python/google/protobuf/pyext/descriptor_pool.cc @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -67,6 +68,11 @@ PyDescriptorPool* NewDescriptorPool() { // as underlay. cdescriptor_pool->pool = new DescriptorPool(DescriptorPool::generated_pool()); + DynamicMessageFactory* message_factory = new DynamicMessageFactory(); + // This option might be the default some day. + message_factory->SetDelegateToGeneratedFactory(true); + cdescriptor_pool->message_factory = message_factory; + // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same // storage. cdescriptor_pool->classes_by_descriptor = @@ -93,6 +99,7 @@ static void Dealloc(PyDescriptorPool* self) { Py_DECREF(it->second); } delete self->descriptor_options; + delete self->message_factory; Py_TYPE(self)->tp_free(reinterpret_cast(self)); } diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h index efb1abeb0e847..6f6c5cdb5252d 100644 --- a/python/google/protobuf/pyext/descriptor_pool.h +++ b/python/google/protobuf/pyext/descriptor_pool.h @@ -38,6 +38,8 @@ namespace google { namespace protobuf { +class MessageFactory; + namespace python { // Wraps operations to the global DescriptorPool which contains information @@ -55,6 +57,14 @@ typedef struct PyDescriptorPool { DescriptorPool* pool; + // DynamicMessageFactory used to create C++ instances of messages. + // This object cache the descriptors that were used, so the DescriptorPool + // needs to get rid of it before it can delete itself. + // + // Note: A C++ MessageFactory is different from the Python MessageFactory. + // The C++ one creates messages, when the Python one creates classes. + MessageFactory* message_factory; + // Make our own mapping to retrieve Python classes from C++ descriptors. // // Descriptor pointers stored here are owned by the DescriptorPool above. diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc index b8d18f8d92cf0..8ebbb27c4694b 100644 --- a/python/google/protobuf/pyext/extension_dict.cc +++ b/python/google/protobuf/pyext/extension_dict.cc @@ -33,6 +33,7 @@ #include +#include #include #include #include @@ -183,7 +184,8 @@ PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) { return NULL; } } - if (cmessage::ClearFieldByDescriptor(self->parent, descriptor) == NULL) { + if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor( + self->parent, descriptor)) == NULL) { return NULL; } if (PyDict_DelItem(self->values, extension) < 0) { @@ -268,7 +270,7 @@ PyTypeObject ExtensionDict_Type = { 0, // tp_as_number 0, // tp_as_sequence &extension_dict::MpMethods, // tp_as_mapping - 0, // tp_hash + PyObject_HashNotImplemented, // tp_hash 0, // tp_call 0, // tp_str 0, // tp_getattro diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index a4843e8d3d1a1..aa3ab97a671df 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -49,9 +49,10 @@ #endif #include #include +#include #include +#include #include -#include #include #include #include @@ -88,12 +89,308 @@ namespace google { namespace protobuf { namespace python { +static PyObject* kDESCRIPTOR; +static PyObject* k_extensions_by_name; +static PyObject* k_extensions_by_number; +PyObject* EnumTypeWrapper_class; +static PyObject* PythonMessage_class; +static PyObject* kEmptyWeakref; + +// Defines the Metaclass of all Message classes. +// It allows us to cache some C++ pointers in the class object itself, they are +// faster to extract than from the type's dictionary. + +struct PyMessageMeta { + // This is how CPython subclasses C structures: the base structure must be + // the first member of the object. + PyHeapTypeObject super; + + // C++ descriptor of this message. + const Descriptor* message_descriptor; + // Owned reference, used to keep the pointer above alive. + PyObject* py_message_descriptor; +}; + +namespace message_meta { + +static int InsertEmptyWeakref(PyTypeObject* base); + +// Add the number of a field descriptor to the containing message class. +// Equivalent to: +// _cls._FIELD_NUMBER = +static bool AddFieldNumberToClass( + PyObject* cls, const FieldDescriptor* field_descriptor) { + string constant_name = field_descriptor->name() + "_FIELD_NUMBER"; + UpperString(&constant_name); + ScopedPyObjectPtr attr_name(PyString_FromStringAndSize( + constant_name.c_str(), constant_name.size())); + if (attr_name == NULL) { + return false; + } + ScopedPyObjectPtr number(PyInt_FromLong(field_descriptor->number())); + if (number == NULL) { + return false; + } + if (PyObject_SetAttr(cls, attr_name, number) == -1) { + return false; + } + return true; +} + + +// Finalize the creation of the Message class. +// Called from its metaclass: GeneratedProtocolMessageType.__init__(). +static int AddDescriptors(PyObject* cls, PyObject* descriptor) { + const Descriptor* message_descriptor = + cdescriptor_pool::RegisterMessageClass( + GetDescriptorPool(), cls, descriptor); + if (message_descriptor == NULL) { + return -1; + } + + // If there are extension_ranges, the message is "extendable", and extension + // classes will register themselves in this class. + if (message_descriptor->extension_range_count() > 0) { + ScopedPyObjectPtr by_name(PyDict_New()); + if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) { + return -1; + } + ScopedPyObjectPtr by_number(PyDict_New()); + if (PyObject_SetAttr(cls, k_extensions_by_number, by_number) < 0) { + return -1; + } + } + + // For each field set: cls._FIELD_NUMBER = + for (int i = 0; i < message_descriptor->field_count(); ++i) { + if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) { + return -1; + } + } + + // For each enum set cls. = EnumTypeWrapper(). + // + // The enum descriptor we get from + // .enum_types_by_name[name] + // which was built previously. + for (int i = 0; i < message_descriptor->enum_type_count(); ++i) { + const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i); + ScopedPyObjectPtr enum_type( + PyEnumDescriptor_FromDescriptor(enum_descriptor)); + if (enum_type == NULL) { + return -1; + } + // Add wrapped enum type to message class. + ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs( + EnumTypeWrapper_class, enum_type.get(), NULL)); + if (wrapped == NULL) { + return -1; + } + if (PyObject_SetAttrString( + cls, enum_descriptor->name().c_str(), wrapped) == -1) { + return -1; + } + + // For each enum value add cls. = + for (int j = 0; j < enum_descriptor->value_count(); ++j) { + const EnumValueDescriptor* enum_value_descriptor = + enum_descriptor->value(j); + ScopedPyObjectPtr value_number(PyInt_FromLong( + enum_value_descriptor->number())); + if (value_number == NULL) { + return -1; + } + if (PyObject_SetAttrString( + cls, enum_value_descriptor->name().c_str(), value_number) == -1) { + return -1; + } + } + } + + // For each extension set cls. = . + // + // Extension descriptors come from + // .extensions_by_name[name] + // which was defined previously. + for (int i = 0; i < message_descriptor->extension_count(); ++i) { + const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i); + ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); + if (extension_field == NULL) { + return -1; + } + + // Add the extension field to the message class. + if (PyObject_SetAttrString( + cls, field->name().c_str(), extension_field) == -1) { + return -1; + } + + // For each extension set cls._FIELD_NUMBER = . + if (!AddFieldNumberToClass(cls, field)) { + return -1; + } + } + + return 0; +} + +static PyObject* New(PyTypeObject* type, + PyObject* args, PyObject* kwargs) { + static char *kwlist[] = {"name", "bases", "dict", 0}; + PyObject *bases, *dict; + const char* name; + + // Check arguments: (name, bases, dict) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!O!:type", kwlist, + &name, + &PyTuple_Type, &bases, + &PyDict_Type, &dict)) { + return NULL; + } + + // Check bases: only (), or (message.Message,) are allowed + if (!(PyTuple_GET_SIZE(bases) == 0 || + (PyTuple_GET_SIZE(bases) == 1 && + PyTuple_GET_ITEM(bases, 0) == PythonMessage_class))) { + PyErr_SetString(PyExc_TypeError, + "A Message class can only inherit from Message"); + return NULL; + } + + // Check dict['DESCRIPTOR'] + PyObject* descriptor = PyDict_GetItem(dict, kDESCRIPTOR); + if (descriptor == NULL) { + PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); + return NULL; + } + if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) { + PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s", + descriptor->ob_type->tp_name); + return NULL; + } + + // Build the arguments to the base metaclass. + // We change the __bases__ classes. + ScopedPyObjectPtr new_args(Py_BuildValue( + "s(OO)O", name, &CMessage_Type, PythonMessage_class, dict)); + if (new_args == NULL) { + return NULL; + } + // Call the base metaclass. + ScopedPyObjectPtr result(PyType_Type.tp_new(type, new_args, NULL)); + if (result == NULL) { + return NULL; + } + PyMessageMeta* newtype = reinterpret_cast(result.get()); + + // Insert the empty weakref into the base classes. + if (InsertEmptyWeakref( + reinterpret_cast(PythonMessage_class)) < 0 || + InsertEmptyWeakref(&CMessage_Type) < 0) { + return NULL; + } + + // Cache the descriptor, both as Python object and as C++ pointer. + const Descriptor* message_descriptor = + PyMessageDescriptor_AsDescriptor(descriptor); + if (message_descriptor == NULL) { + return NULL; + } + Py_INCREF(descriptor); + newtype->py_message_descriptor = descriptor; + newtype->message_descriptor = message_descriptor; + + // Continue with type initialization: add other descriptors, enum values... + if (AddDescriptors(result, descriptor) < 0) { + return NULL; + } + return result.release(); +} + +static void Dealloc(PyMessageMeta *self) { + Py_DECREF(self->py_message_descriptor); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* GetDescriptor(PyMessageMeta *self, void *closure) { + Py_INCREF(self->py_message_descriptor); + return self->py_message_descriptor; +} + + +// This function inserts and empty weakref at the end of the list of +// subclasses for the main protocol buffer Message class. +// +// This eliminates a O(n^2) behaviour in the internal add_subclass +// routine. +static int InsertEmptyWeakref(PyTypeObject *base_type) { +#if PY_MAJOR_VERSION >= 3 + // Python 3.4 has already included the fix for the issue that this + // hack addresses. For further background and the fix please see + // https://bugs.python.org/issue17936. + return 0; +#else + PyObject *subclasses = base_type->tp_subclasses; + if (subclasses && PyList_CheckExact(subclasses)) { + return PyList_Append(subclasses, kEmptyWeakref); + } + return 0; +#endif // PY_MAJOR_VERSION >= 3 +} + +} // namespace message_meta + +PyTypeObject PyMessageMeta_Type { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + FULL_MODULE_NAME ".MessageMeta", // tp_name + sizeof(PyMessageMeta), // tp_basicsize + 0, // tp_itemsize + (destructor)message_meta::Dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags + "The metaclass of ProtocolMessages", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + 0, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + message_meta::New, // tp_new +}; + +static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { + if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) { + PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name); + return NULL; + } + return reinterpret_cast(cls)->message_descriptor; +} + // Forward declarations namespace cmessage { -static const FieldDescriptor* GetFieldDescriptor( - CMessage* self, PyObject* name); -static const Descriptor* GetMessageDescriptor(PyTypeObject* cls); -static string GetMessageName(CMessage* self); int InternalReleaseFieldByDescriptor( CMessage* self, const FieldDescriptor* field_descriptor, @@ -180,7 +477,7 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { if (self->composite_fields) { // Never use self->message in this function, it may be already freed. const Descriptor* message_descriptor = - cmessage::GetMessageDescriptor(Py_TYPE(self)); + GetMessageDescriptor(Py_TYPE(self)); while (PyDict_Next(self->composite_fields, &pos, &key, &field)) { Py_ssize_t key_str_size; char *key_str_data; @@ -213,8 +510,6 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) { // --------------------------------------------------------------------- -static DynamicMessageFactory* message_factory; - // Constants used for integer type range checking. PyObject* kPythonZero; PyObject* kint32min_py; @@ -224,17 +519,13 @@ PyObject* kint64min_py; PyObject* kint64max_py; PyObject* kuint64max_py; -PyObject* EnumTypeWrapper_class; PyObject* EncodeError_class; PyObject* DecodeError_class; PyObject* PickleError_class; // Constant PyString values used for GetAttr/GetItem. -static PyObject* kDESCRIPTOR; static PyObject* k_cdescriptor; static PyObject* kfull_name; -static PyObject* k_extensions_by_name; -static PyObject* k_extensions_by_number; /* Is 64bit */ void FormatTypeError(PyObject* arg, char* expected_types) { @@ -432,10 +723,6 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor, namespace cmessage { -DynamicMessageFactory* GetMessageFactory() { - return message_factory; -} - static int MaybeReleaseOverlappingOneofField( CMessage* cmessage, const FieldDescriptor* field) { @@ -486,7 +773,7 @@ static Message* GetMutableMessage( return NULL; } return reflection->MutableMessage( - parent_message, parent_field, message_factory); + parent_message, parent_field, GetDescriptorPool()->message_factory); } struct FixupMessageReference : public ChildVisitor { @@ -527,8 +814,9 @@ int AssureWritable(CMessage* self) { // If parent is NULL but we are trying to modify a read-only message, this // is a reference to a constant default instance that needs to be replaced // with a mutable top-level message. - const Message* prototype = message_factory->GetPrototype( - self->message->GetDescriptor()); + const Message* prototype = + GetDescriptorPool()->message_factory->GetPrototype( + self->message->GetDescriptor()); self->message = prototype->New(); self->owner.reset(self->message); // Cascade the new owner to eventual children: even if this message is @@ -567,23 +855,6 @@ int AssureWritable(CMessage* self) { // --- Globals: -// Retrieve the C++ Descriptor of a message class. -// On error, returns NULL with an exception set. -static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { - ScopedPyObjectPtr descriptor(PyObject_GetAttr( - reinterpret_cast(cls), kDESCRIPTOR)); - if (descriptor == NULL) { - PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR"); - return NULL; - } - if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) { - PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s", - descriptor->ob_type->tp_name); - return NULL; - } - return PyMessageDescriptor_AsDescriptor(descriptor); -} - // Retrieve a C++ FieldDescriptor for a message attribute. // The C++ message must be valid. // TODO(amauryfa): This function should stay internal, because exception @@ -846,9 +1117,9 @@ int InitAttributes(CMessage* self, PyObject* kwargs) { return -1; } } else { - if (repeated_scalar_container::Extend( + if (ScopedPyObjectPtr(repeated_scalar_container::Extend( reinterpret_cast(container.get()), - value) == + value)) == NULL) { return -1; } @@ -927,7 +1198,7 @@ static PyObject* New(PyTypeObject* type, return NULL; } const Message* default_message = - message_factory->GetPrototype(message_descriptor); + GetDescriptorPool()->message_factory->GetPrototype(message_descriptor); if (default_message == NULL) { PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str()); return NULL; @@ -1257,6 +1528,7 @@ int SetOwner(CMessage* self, const shared_ptr& new_owner) { Message* ReleaseMessage(CMessage* self, const Descriptor* descriptor, const FieldDescriptor* field_descriptor) { + MessageFactory* message_factory = GetDescriptorPool()->message_factory; Message* released_message = self->message->GetReflection()->ReleaseMessage( self->message, field_descriptor, message_factory); // ReleaseMessage will return NULL which differs from @@ -1492,34 +1764,35 @@ static PyObject* SerializePartialToString(CMessage* self) { // appropriate. class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter { public: - PythonFieldValuePrinter() : float_holder_(PyFloat_FromDouble(0)) {} - // Python has some differences from C++ when printing floating point numbers. // // 1) Trailing .0 is always printed. - // 2) Outputted is rounded to 12 digits. + // 2) (Python2) Output is rounded to 12 digits. + // 3) (Python3) The full precision of the double is preserved (and Python uses + // David M. Gay's dtoa(), when the C++ code uses SimpleDtoa. There are some + // differences, but they rarely happen) // // We override floating point printing with the C-API function for printing // Python floats to ensure consistency. string PrintFloat(float value) const { return PrintDouble(value); } string PrintDouble(double value) const { - reinterpret_cast(float_holder_.get())->ob_fval = value; - ScopedPyObjectPtr s(PyObject_Str(float_holder_.get())); - if (s == NULL) return string(); + // Same as float.__str__() + char* buf = PyOS_double_to_string( + value, #if PY_MAJOR_VERSION < 3 - char *cstr = PyBytes_AS_STRING(static_cast(s)); + 'g', PyFloat_STR_PRECISION, // Output is rounded to 12 digits. #else - char *cstr = PyUnicode_AsUTF8(s); + 'r', 0, #endif - return string(cstr); + Py_DTSF_ADD_DOT_0, // Trailing .0 is always printed. + NULL); + if (!buf) { + return string(); + } + string result(buf); + PyMem_Free(buf); + return result; } - - private: - // Holder for a python float object which we use to allow us to use - // the Python API for printing doubles. We initialize once and then - // directly modify it for every float printed to save on allocations - // and refcounting. - ScopedPyObjectPtr float_holder_; }; static PyObject* ToStr(CMessage* self) { @@ -1590,7 +1863,7 @@ static PyObject* CopyFrom(CMessage* self, PyObject* arg) { // CopyFrom on the message will not clean up self->composite_fields, // which can leave us in an inconsistent state, so clear it out here. - Clear(self); + (void)ScopedPyObjectPtr(Clear(self)); self->message->CopyFrom(*other_message->message); @@ -1607,7 +1880,8 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { AssureWritable(self); io::CodedInputStream input( reinterpret_cast(data), data_length); - input.SetExtensionRegistry(GetDescriptorPool()->pool, message_factory); + input.SetExtensionRegistry(GetDescriptorPool()->pool, + GetDescriptorPool()->message_factory); bool success = self->message->MergePartialFromCodedStream(&input); if (success) { return PyInt_FromLong(input.CurrentPosition()); @@ -1618,7 +1892,7 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { } static PyObject* ParseFromString(CMessage* self, PyObject* arg) { - if (Clear(self) == NULL) { + if (ScopedPyObjectPtr(Clear(self)) == NULL) { return NULL; } return MergeFromString(self, arg); @@ -1790,6 +2064,7 @@ static PyObject* ListFields(CMessage* self) { // Steals reference to 'extension' PyTuple_SET_ITEM(t.get(), 1, extension); } else { + // Normal field const string& field_name = fields[i]->name(); ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize( field_name.c_str(), field_name.length())); @@ -1841,28 +2116,34 @@ PyObject* FindInitializationErrors(CMessage* self) { } static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) { - if (!PyObject_TypeCheck(other, &CMessage_Type)) { - if (opid == Py_EQ) { - Py_RETURN_FALSE; - } else if (opid == Py_NE) { - Py_RETURN_TRUE; - } - } - if (opid == Py_EQ || opid == Py_NE) { - ScopedPyObjectPtr self_fields(ListFields(self)); - if (!self_fields) { - return NULL; - } - ScopedPyObjectPtr other_fields(ListFields( - reinterpret_cast(other))); - if (!other_fields) { - return NULL; - } - return PyObject_RichCompare(self_fields, other_fields, opid); - } else { + // Only equality comparisons are implemented. + if (opid != Py_EQ && opid != Py_NE) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } + bool equals = true; + // If other is not a message, it cannot be equal. + if (!PyObject_TypeCheck(other, &CMessage_Type)) { + equals = false; + } + const google::protobuf::Message* other_message = + reinterpret_cast(other)->message; + // If messages don't have the same descriptors, they are not equal. + if (equals && + self->message->GetDescriptor() != other_message->GetDescriptor()) { + equals = false; + } + // Check the message contents. + if (equals && !google::protobuf::util::MessageDifferencer::Equals( + *self->message, + *reinterpret_cast(other)->message)) { + equals = false; + } + if (equals ^ (opid == Py_EQ)) { + Py_RETURN_FALSE; + } else { + Py_RETURN_TRUE; + } } PyObject* InternalGetScalar(const Message* message, @@ -1950,7 +2231,7 @@ PyObject* InternalGetSubMessage( CMessage* self, const FieldDescriptor* field_descriptor) { const Reflection* reflection = self->message->GetReflection(); const Message& sub_message = reflection->GetMessage( - *self->message, field_descriptor, message_factory); + *self->message, field_descriptor, GetDescriptorPool()->message_factory); PyObject *message_class = cdescriptor_pool::GetMessageClass( GetDescriptorPool(), field_descriptor->message_type()); @@ -2085,125 +2366,6 @@ PyObject* FromString(PyTypeObject* cls, PyObject* serialized) { return py_cmsg; } -// Add the number of a field descriptor to the containing message class. -// Equivalent to: -// _cls._FIELD_NUMBER = -static bool AddFieldNumberToClass( - PyObject* cls, const FieldDescriptor* field_descriptor) { - string constant_name = field_descriptor->name() + "_FIELD_NUMBER"; - UpperString(&constant_name); - ScopedPyObjectPtr attr_name(PyString_FromStringAndSize( - constant_name.c_str(), constant_name.size())); - if (attr_name == NULL) { - return false; - } - ScopedPyObjectPtr number(PyInt_FromLong(field_descriptor->number())); - if (number == NULL) { - return false; - } - if (PyObject_SetAttr(cls, attr_name, number) == -1) { - return false; - } - return true; -} - - -// Finalize the creation of the Message class. -// Called from its metaclass: GeneratedProtocolMessageType.__init__(). -static PyObject* AddDescriptors(PyObject* cls, PyObject* descriptor) { - const Descriptor* message_descriptor = - cdescriptor_pool::RegisterMessageClass( - GetDescriptorPool(), cls, descriptor); - if (message_descriptor == NULL) { - return NULL; - } - - // If there are extension_ranges, the message is "extendable", and extension - // classes will register themselves in this class. - if (message_descriptor->extension_range_count() > 0) { - ScopedPyObjectPtr by_name(PyDict_New()); - if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) { - return NULL; - } - ScopedPyObjectPtr by_number(PyDict_New()); - if (PyObject_SetAttr(cls, k_extensions_by_number, by_number) < 0) { - return NULL; - } - } - - // For each field set: cls._FIELD_NUMBER = - for (int i = 0; i < message_descriptor->field_count(); ++i) { - if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) { - return NULL; - } - } - - // For each enum set cls. = EnumTypeWrapper(). - // - // The enum descriptor we get from - // .enum_types_by_name[name] - // which was built previously. - for (int i = 0; i < message_descriptor->enum_type_count(); ++i) { - const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i); - ScopedPyObjectPtr enum_type( - PyEnumDescriptor_FromDescriptor(enum_descriptor)); - if (enum_type == NULL) { - return NULL; - } - // Add wrapped enum type to message class. - ScopedPyObjectPtr wrapped(PyObject_CallFunctionObjArgs( - EnumTypeWrapper_class, enum_type.get(), NULL)); - if (wrapped == NULL) { - return NULL; - } - if (PyObject_SetAttrString( - cls, enum_descriptor->name().c_str(), wrapped) == -1) { - return NULL; - } - - // For each enum value add cls. = - for (int j = 0; j < enum_descriptor->value_count(); ++j) { - const EnumValueDescriptor* enum_value_descriptor = - enum_descriptor->value(j); - ScopedPyObjectPtr value_number(PyInt_FromLong( - enum_value_descriptor->number())); - if (value_number == NULL) { - return NULL; - } - if (PyObject_SetAttrString( - cls, enum_value_descriptor->name().c_str(), value_number) == -1) { - return NULL; - } - } - } - - // For each extension set cls. = . - // - // Extension descriptors come from - // .extensions_by_name[name] - // which was defined previously. - for (int i = 0; i < message_descriptor->extension_count(); ++i) { - const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i); - ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field)); - if (extension_field == NULL) { - return NULL; - } - - // Add the extension field to the message class. - if (PyObject_SetAttrString( - cls, field->name().c_str(), extension_field) == -1) { - return NULL; - } - - // For each extension set cls._FIELD_NUMBER = . - if (!AddFieldNumberToClass(cls, field)) { - return NULL; - } - } - - Py_RETURN_NONE; -} - PyObject* DeepCopy(CMessage* self, PyObject* arg) { PyObject* clone = PyObject_CallObject( reinterpret_cast(Py_TYPE(self)), NULL); @@ -2214,8 +2376,9 @@ PyObject* DeepCopy(CMessage* self, PyObject* arg) { Py_DECREF(clone); return NULL; } - if (MergeFrom(reinterpret_cast(clone), - reinterpret_cast(self)) == NULL) { + if (ScopedPyObjectPtr(MergeFrom( + reinterpret_cast(clone), + reinterpret_cast(self))) == NULL) { Py_DECREF(clone); return NULL; } @@ -2281,7 +2444,7 @@ PyObject* SetState(CMessage* self, PyObject* state) { if (serialized == NULL) { return NULL; } - if (ParseFromString(self, serialized) == NULL) { + if (ScopedPyObjectPtr(ParseFromString(self, serialized)) == NULL) { return NULL; } Py_RETURN_NONE; @@ -2314,8 +2477,6 @@ static PyMethodDef Methods[] = { "Inputs picklable representation of the message." }, { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS, "Outputs a unicode representation of the message." }, - { "AddDescriptors", (PyCFunction)AddDescriptors, METH_O | METH_CLASS, - "Adds field descriptors to the class" }, { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS, "Returns the size of the message in bytes." }, { "Clear", (PyCFunction)Clear, METH_NOARGS, @@ -2441,6 +2602,9 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { PyObject* sub_message = InternalGetSubMessage(self, field_descriptor); + if (sub_message == NULL) { + return NULL; + } if (!SetCompositeField(self, name, sub_message)) { Py_DECREF(sub_message); return NULL; @@ -2484,7 +2648,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { } // namespace cmessage PyTypeObject CMessage_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(&PyMessageMeta_Type, 0) FULL_MODULE_NAME ".CMessage", // tp_name sizeof(CMessage), // tp_basicsize 0, // tp_itemsize @@ -2497,7 +2661,7 @@ PyTypeObject CMessage_Type = { 0, // tp_as_number 0, // tp_as_sequence 0, // tp_as_mapping - 0, // tp_hash + PyObject_HashNotImplemented, // tp_hash 0, // tp_call (reprfunc)cmessage::ToStr, // tp_str (getattrofunc)cmessage::GetAttr, // tp_getattro @@ -2580,8 +2744,9 @@ void InitGlobals() { k_extensions_by_name = PyString_FromString("_extensions_by_name"); k_extensions_by_number = PyString_FromString("_extensions_by_number"); - message_factory = new DynamicMessageFactory(); - message_factory->SetDelegateToGeneratedFactory(true); + PyObject *dummy_obj = PySet_New(NULL); + kEmptyWeakref = PyWeakref_NewRef(dummy_obj, NULL); + Py_DECREF(dummy_obj); } bool InitProto2MessageModule(PyObject *m) { @@ -2598,7 +2763,13 @@ bool InitProto2MessageModule(PyObject *m) { // Initialize constants defined in this file. InitGlobals(); - CMessage_Type.tp_hash = PyObject_HashNotImplemented; + PyMessageMeta_Type.tp_base = &PyType_Type; + if (PyType_Ready(&PyMessageMeta_Type) < 0) { + return false; + } + PyModule_AddObject(m, "MessageMeta", + reinterpret_cast(&PyMessageMeta_Type)); + if (PyType_Ready(&CMessage_Type) < 0) { return false; } @@ -2628,86 +2799,106 @@ bool InitProto2MessageModule(PyObject *m) { PyModule_AddObject(m, "Message", reinterpret_cast(&CMessage_Type)); - RepeatedScalarContainer_Type.tp_hash = - PyObject_HashNotImplemented; - if (PyType_Ready(&RepeatedScalarContainer_Type) < 0) { - return false; - } + // Initialize Repeated container types. + { + if (PyType_Ready(&RepeatedScalarContainer_Type) < 0) { + return false; + } - PyModule_AddObject(m, "RepeatedScalarContainer", - reinterpret_cast( - &RepeatedScalarContainer_Type)); + PyModule_AddObject(m, "RepeatedScalarContainer", + reinterpret_cast( + &RepeatedScalarContainer_Type)); - RepeatedCompositeContainer_Type.tp_hash = PyObject_HashNotImplemented; - if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) { - return false; - } + if (PyType_Ready(&RepeatedCompositeContainer_Type) < 0) { + return false; + } - PyModule_AddObject( - m, "RepeatedCompositeContainer", - reinterpret_cast( - &RepeatedCompositeContainer_Type)); - - // ScalarMapContainer_Type derives from our MutableMapping type. - PyObject* containers = - PyImport_ImportModule("google.protobuf.internal.containers"); - if (containers == NULL) { - return false; + PyModule_AddObject( + m, "RepeatedCompositeContainer", + reinterpret_cast( + &RepeatedCompositeContainer_Type)); + + // Register them as collections.Sequence + ScopedPyObjectPtr collections(PyImport_ImportModule("collections")); + if (collections == NULL) { + return false; + } + ScopedPyObjectPtr mutable_sequence(PyObject_GetAttrString( + collections, "MutableSequence")); + if (mutable_sequence == NULL) { + return false; + } + if (ScopedPyObjectPtr(PyObject_CallMethod(mutable_sequence, "register", "O", + &RepeatedScalarContainer_Type)) + == NULL) { + return false; + } + if (ScopedPyObjectPtr(PyObject_CallMethod(mutable_sequence, "register", "O", + &RepeatedCompositeContainer_Type)) + == NULL) { + return false; + } } - PyObject* mutable_mapping = - PyObject_GetAttrString(containers, "MutableMapping"); - Py_DECREF(containers); + // Initialize Map container types. + { + // ScalarMapContainer_Type derives from our MutableMapping type. + ScopedPyObjectPtr containers(PyImport_ImportModule( + "google.protobuf.internal.containers")); + if (containers == NULL) { + return false; + } - if (mutable_mapping == NULL) { - return false; - } + ScopedPyObjectPtr mutable_mapping( + PyObject_GetAttrString(containers, "MutableMapping")); + if (mutable_mapping == NULL) { + return false; + } - if (!PyObject_TypeCheck(mutable_mapping, &PyType_Type)) { - Py_DECREF(mutable_mapping); - return false; - } + if (!PyObject_TypeCheck(mutable_mapping, &PyType_Type)) { + return false; + } - ScalarMapContainer_Type.tp_base = - reinterpret_cast(mutable_mapping); + Py_INCREF(mutable_mapping); + ScalarMapContainer_Type.tp_base = + reinterpret_cast(mutable_mapping.get()); - if (PyType_Ready(&ScalarMapContainer_Type) < 0) { - return false; - } + if (PyType_Ready(&ScalarMapContainer_Type) < 0) { + return false; + } - PyModule_AddObject(m, "ScalarMapContainer", - reinterpret_cast(&ScalarMapContainer_Type)); + PyModule_AddObject(m, "ScalarMapContainer", + reinterpret_cast(&ScalarMapContainer_Type)); - if (PyType_Ready(&ScalarMapIterator_Type) < 0) { - return false; - } + if (PyType_Ready(&ScalarMapIterator_Type) < 0) { + return false; + } - PyModule_AddObject(m, "ScalarMapIterator", - reinterpret_cast(&ScalarMapIterator_Type)); + PyModule_AddObject(m, "ScalarMapIterator", + reinterpret_cast(&ScalarMapIterator_Type)); - Py_INCREF(mutable_mapping); - MessageMapContainer_Type.tp_base = - reinterpret_cast(mutable_mapping); + Py_INCREF(mutable_mapping); + MessageMapContainer_Type.tp_base = + reinterpret_cast(mutable_mapping.get()); - if (PyType_Ready(&MessageMapContainer_Type) < 0) { - return false; - } + if (PyType_Ready(&MessageMapContainer_Type) < 0) { + return false; + } - PyModule_AddObject(m, "MessageMapContainer", - reinterpret_cast(&MessageMapContainer_Type)); + PyModule_AddObject(m, "MessageMapContainer", + reinterpret_cast(&MessageMapContainer_Type)); - if (PyType_Ready(&MessageMapIterator_Type) < 0) { - return false; - } + if (PyType_Ready(&MessageMapIterator_Type) < 0) { + return false; + } - PyModule_AddObject(m, "MessageMapIterator", - reinterpret_cast(&MessageMapIterator_Type)); + PyModule_AddObject(m, "MessageMapIterator", + reinterpret_cast(&MessageMapIterator_Type)); + } - ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented; if (PyType_Ready(&ExtensionDict_Type) < 0) { return false; } - PyModule_AddObject( m, "ExtensionDict", reinterpret_cast(&ExtensionDict_Type)); @@ -2751,6 +2942,7 @@ bool InitProto2MessageModule(PyObject *m) { } EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError"); DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError"); + PythonMessage_class = PyObject_GetAttrString(message_module, "Message"); Py_DECREF(message_module); PyObject* pickle_module = PyImport_ImportModule("pickle"); diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index 7360b207746dc..f147d433ef0d2 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -49,7 +49,6 @@ class Message; class Reflection; class FieldDescriptor; class Descriptor; -class DynamicMessageFactory; using internal::shared_ptr; @@ -221,9 +220,6 @@ PyObject* FindInitializationErrors(CMessage* self); int SetOwner(CMessage* self, const shared_ptr& new_owner); int AssureWritable(CMessage* self); - -DynamicMessageFactory* GetMessageFactory(); - } // namespace cmessage diff --git a/python/google/protobuf/pyext/message_map_container.cc b/python/google/protobuf/pyext/message_map_container.cc index ab8d8fb9f0827..a4a7fbfe0e05d 100644 --- a/python/google/protobuf/pyext/message_map_container.cc +++ b/python/google/protobuf/pyext/message_map_container.cc @@ -32,6 +32,7 @@ #include +#include #include #include #include diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc index 86b75d0f7ceab..fe2e600b8f3da 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.cc +++ b/python/google/protobuf/pyext/repeated_composite_container.cc @@ -38,11 +38,13 @@ #include #endif +#include #include #include #include #include #include +#include #include #include @@ -74,125 +76,6 @@ namespace repeated_composite_container { GOOGLE_CHECK((self)->parent == NULL); \ } while (0); -// Returns a new reference. -static PyObject* GetKey(PyObject* x) { - // Just the identity function. - Py_INCREF(x); - return x; -} - -#define GET_KEY(keyfunc, value) \ - ((keyfunc) == NULL ? \ - GetKey((value)) : \ - PyObject_CallFunctionObjArgs((keyfunc), (value), NULL)) - -// Converts a comparison function that returns -1, 0, or 1 into a -// less-than predicate. -// -// Returns -1 on error, 1 if x < y, 0 if x >= y. -static int islt(PyObject *x, PyObject *y, PyObject *compare) { - if (compare == NULL) - return PyObject_RichCompareBool(x, y, Py_LT); - - ScopedPyObjectPtr res(PyObject_CallFunctionObjArgs(compare, x, y, NULL)); - if (res == NULL) - return -1; - if (!PyInt_Check(res)) { - PyErr_Format(PyExc_TypeError, - "comparison function must return int, not %.200s", - Py_TYPE(res)->tp_name); - return -1; - } - return PyInt_AsLong(res) < 0; -} - -// Copied from uarrsort.c but swaps memcpy swaps with protobuf/python swaps -// TODO(anuraag): Is there a better way to do this then reinventing the wheel? -static int InternalQuickSort(RepeatedCompositeContainer* self, - Py_ssize_t start, - Py_ssize_t limit, - PyObject* cmp, - PyObject* keyfunc) { - if (limit - start <= 1) - return 0; // Nothing to sort. - - GOOGLE_CHECK_ATTACHED(self); - - Message* message = self->message; - const Reflection* reflection = message->GetReflection(); - const FieldDescriptor* descriptor = self->parent_field_descriptor; - Py_ssize_t left; - Py_ssize_t right; - - PyObject* children = self->child_messages; - - do { - left = start; - right = limit; - ScopedPyObjectPtr mid( - GET_KEY(keyfunc, PyList_GET_ITEM(children, (start + limit) / 2))); - do { - ScopedPyObjectPtr key(GET_KEY(keyfunc, PyList_GET_ITEM(children, left))); - int is_lt = islt(key, mid, cmp); - if (is_lt == -1) - return -1; - /* array[left]SwapElements(message, descriptor, left, right); - PyObject* tmp = PyList_GET_ITEM(children, left); - PyList_SET_ITEM(children, left, PyList_GET_ITEM(children, right)); - PyList_SET_ITEM(children, right, tmp); - } - ++left; - } - } while (left < right); - - if ((right - start) < (limit - left)) { - /* sort [start..right[ */ - if (start < (right - 1)) { - InternalQuickSort(self, start, right, cmp, keyfunc); - } - - /* sort [left..limit[ */ - start = left; - } else { - /* sort [left..limit[ */ - if (left < (limit - 1)) { - InternalQuickSort(self, left, limit, cmp, keyfunc); - } - - /* sort [start..right[ */ - limit = right; - } - } while (start < (limit - 1)); - - return 0; -} - -#undef GET_KEY - // --------------------------------------------------------------------- // len() @@ -329,7 +212,7 @@ PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) { return NULL; } CMessage* new_cmessage = reinterpret_cast(new_message.get()); - if (cmessage::MergeFrom(new_cmessage, next) == NULL) { + if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next)) == NULL) { return NULL; } } @@ -455,58 +338,39 @@ static PyObject* RichCompare(RepeatedCompositeContainer* self, // --------------------------------------------------------------------- // sort() -static PyObject* SortAttached(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwds) { - // Sort the underlying Message array. - PyObject *compare = NULL; - int reverse = 0; - PyObject *keyfunc = NULL; - static char *kwlist[] = {"cmp", "key", "reverse", 0}; - - if (args != NULL) { - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort", - kwlist, &compare, &keyfunc, &reverse)) - return NULL; - } - if (compare == Py_None) - compare = NULL; - if (keyfunc == Py_None) - keyfunc = NULL; - +static void ReorderAttached(RepeatedCompositeContainer* self) { + Message* message = self->message; + const Reflection* reflection = message->GetReflection(); + const FieldDescriptor* descriptor = self->parent_field_descriptor; const Py_ssize_t length = Length(self); - if (InternalQuickSort(self, 0, length, compare, keyfunc) < 0) - return NULL; - - // Finally reverse the result if requested. - if (reverse) { - Message* message = self->message; - const Reflection* reflection = message->GetReflection(); - const FieldDescriptor* descriptor = self->parent_field_descriptor; - // Reverse the Message array. - for (int i = 0; i < length / 2; ++i) - reflection->SwapElements(message, descriptor, i, length - i - 1); + // Since Python protobuf objects are never arena-allocated, adding and + // removing message pointers to the underlying array is just updating + // pointers. + for (Py_ssize_t i = 0; i < length; ++i) + reflection->ReleaseLast(message, descriptor); - // Reverse the Python list. - ScopedPyObjectPtr res(PyObject_CallMethod(self->child_messages, - "reverse", NULL)); - if (res == NULL) - return NULL; + for (Py_ssize_t i = 0; i < length; ++i) { + CMessage* py_cmsg = reinterpret_cast( + PyList_GET_ITEM(self->child_messages, i)); + reflection->AddAllocatedMessage(message, descriptor, py_cmsg->message); } - - Py_RETURN_NONE; } -static PyObject* SortReleased(RepeatedCompositeContainer* self, - PyObject* args, - PyObject* kwds) { +// Returns 0 if successful; returns -1 and sets an exception if +// unsuccessful. +static int SortPythonMessages(RepeatedCompositeContainer* self, + PyObject* args, + PyObject* kwds) { ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort")); if (m == NULL) - return NULL; + return -1; if (PyObject_Call(m, args, kwds) == NULL) - return NULL; - Py_RETURN_NONE; + return -1; + if (self->message != NULL) { + ReorderAttached(self); + } + return 0; } static PyObject* Sort(RepeatedCompositeContainer* self, @@ -527,11 +391,10 @@ static PyObject* Sort(RepeatedCompositeContainer* self, if (UpdateChildMessages(self) < 0) { return NULL; } - if (self->message == NULL) { - return SortReleased(self, args, kwds); - } else { - return SortAttached(self, args, kwds); + if (SortPythonMessages(self, args, kwds) < 0) { + return NULL; } + Py_RETURN_NONE; } // --------------------------------------------------------------------- @@ -584,18 +447,6 @@ void ReleaseLastTo(CMessage* parent, parent->message->GetReflection()->ReleaseLast(parent->message, field)); // TODO(tibell): Deal with proto1. - // ReleaseMessage will return NULL which differs from - // child_cmessage->message, if the field does not exist. In this case, - // the latter points to the default instance via a const_cast<>, so we - // have to reset it to a new mutable object since we are taking ownership. - if (released_message.get() == NULL) { - const Message* prototype = - cmessage::GetMessageFactory()->GetPrototype( - target->message->GetDescriptor()); - GOOGLE_CHECK_NOTNULL(prototype); - released_message.reset(prototype->New()); - } - target->parent = NULL; target->parent_field_descriptor = NULL; target->message = released_message.get(); @@ -732,7 +583,7 @@ PyTypeObject RepeatedCompositeContainer_Type = { 0, // tp_as_number &repeated_composite_container::SqMethods, // tp_as_sequence &repeated_composite_container::MpMethods, // tp_as_mapping - 0, // tp_hash + PyObject_HashNotImplemented, // tp_hash 0, // tp_call 0, // tp_str 0, // tp_getattro diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc index fd19683604747..7565c6fd9026f 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.cc +++ b/python/google/protobuf/pyext/repeated_scalar_container.cc @@ -39,10 +39,12 @@ #endif #include +#include #include #include #include #include +#include #include #include @@ -68,7 +70,7 @@ static int InternalAssignRepeatedField( self->parent_field_descriptor); for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) { PyObject* value = PyList_GET_ITEM(list, i); - if (Append(self, value) == NULL) { + if (ScopedPyObjectPtr(Append(self, value)) == NULL) { return -1; } } @@ -510,7 +512,7 @@ PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) { } ScopedPyObjectPtr next; while ((next.reset(PyIter_Next(iter))) != NULL) { - if (Append(self, next) == NULL) { + if (ScopedPyObjectPtr(Append(self, next)) == NULL) { return NULL; } } @@ -690,8 +692,7 @@ static int InitializeAndCopyToParentContainer( if (values == NULL) { return -1; } - Message* new_message = cmessage::GetMessageFactory()->GetPrototype( - from->message->GetDescriptor())->New(); + Message* new_message = from->message->New(); to->parent = NULL; to->parent_field_descriptor = from->parent_field_descriptor; to->message = new_message; @@ -781,7 +782,7 @@ PyTypeObject RepeatedScalarContainer_Type = { 0, // tp_as_number &repeated_scalar_container::SqMethods, // tp_as_sequence &repeated_scalar_container::MpMethods, // tp_as_mapping - 0, // tp_hash + PyObject_HashNotImplemented, // tp_hash 0, // tp_call 0, // tp_str 0, // tp_getattro diff --git a/python/google/protobuf/pyext/scalar_map_container.cc b/python/google/protobuf/pyext/scalar_map_container.cc index 6f731d27152bd..80d294253ecd9 100644 --- a/python/google/protobuf/pyext/scalar_map_container.cc +++ b/python/google/protobuf/pyext/scalar_map_container.cc @@ -32,6 +32,7 @@ #include +#include #include #include #include diff --git a/python/google/protobuf/pyext/scoped_pyobject_ptr.h b/python/google/protobuf/pyext/scoped_pyobject_ptr.h index 18ddd5cd4d59b..9979b83b499ff 100644 --- a/python/google/protobuf/pyext/scoped_pyobject_ptr.h +++ b/python/google/protobuf/pyext/scoped_pyobject_ptr.h @@ -51,16 +51,22 @@ class ScopedPyObjectPtr { // Reset. Deletes the current owned object, if any. // Then takes ownership of a new object, if given. - // this->reset(this->get()) works. + // This function must be called with a reference that you own. + // this->reset(this->get()) is wrong! + // this->reset(this->release()) is OK. PyObject* reset(PyObject* p = NULL) { - if (p != ptr_) { - Py_XDECREF(ptr_); - ptr_ = p; - } + Py_XDECREF(ptr_); + ptr_ = p; return ptr_; } + // ScopedPyObjectPtr should not be copied. + // We explicitly list and delete this overload to avoid automatic conversion + // to PyObject*, which is wrong in this case. + PyObject* reset(const ScopedPyObjectPtr& other) = delete; + // Releases ownership of the object. + // The caller now owns the returned reference. PyObject* release() { PyObject* p = ptr_; ptr_ = NULL; diff --git a/python/google/protobuf/reflection.py b/python/google/protobuf/reflection.py index 82fca66198203..0c757264f440f 100755 --- a/python/google/protobuf/reflection.py +++ b/python/google/protobuf/reflection.py @@ -49,101 +49,23 @@ from google.protobuf.internal import api_implementation -from google.protobuf import descriptor as descriptor_mod from google.protobuf import message -_FieldDescriptor = descriptor_mod.FieldDescriptor - if api_implementation.Type() == 'cpp': from google.protobuf.pyext import cpp_message as message_impl else: from google.protobuf.internal import python_message as message_impl -_NewMessage = message_impl.NewMessage -_InitMessage = message_impl.InitMessage - - -class GeneratedProtocolMessageType(type): - - """Metaclass for protocol message classes created at runtime from Descriptors. - - We add implementations for all methods described in the Message class. We - also create properties to allow getting/setting all fields in the protocol - message. Finally, we create slots to prevent users from accidentally - "setting" nonexistent fields in the protocol message, which then wouldn't get - serialized / deserialized properly. - - The protocol compiler currently uses this metaclass to create protocol - message classes at runtime. Clients can also manually create their own - classes at runtime, as in this example: - - mydescriptor = Descriptor(.....) - class MyProtoClass(Message): - __metaclass__ = GeneratedProtocolMessageType - DESCRIPTOR = mydescriptor - myproto_instance = MyProtoClass() - myproto.foo_field = 23 - ... - - The above example will not work for nested types. If you wish to include them, - use reflection.MakeClass() instead of manually instantiating the class in - order to create the appropriate class structure. - """ - - # Must be consistent with the protocol-compiler code in - # proto2/compiler/internal/generator.*. - _DESCRIPTOR_KEY = 'DESCRIPTOR' - - def __new__(cls, name, bases, dictionary): - """Custom allocation for runtime-generated class types. - - We override __new__ because this is apparently the only place - where we can meaningfully set __slots__ on the class we're creating(?). - (The interplay between metaclasses and slots is not very well-documented). - - Args: - name: Name of the class (ignored, but required by the - metaclass protocol). - bases: Base classes of the class we're constructing. - (Should be message.Message). We ignore this field, but - it's required by the metaclass protocol - dictionary: The class dictionary of the class we're - constructing. dictionary[_DESCRIPTOR_KEY] must contain - a Descriptor object describing this protocol message - type. - - Returns: - Newly-allocated class. - """ - descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] - bases = _NewMessage(bases, descriptor, dictionary) - superclass = super(GeneratedProtocolMessageType, cls) - - new_class = superclass.__new__(cls, name, bases, dictionary) - return new_class - - def __init__(cls, name, bases, dictionary): - """Here we perform the majority of our work on the class. - We add enum getters, an __init__ method, implementations - of all Message methods, and properties for all fields - in the protocol type. - - Args: - name: Name of the class (ignored, but required by the - metaclass protocol). - bases: Base classes of the class we're constructing. - (Should be message.Message). We ignore this field, but - it's required by the metaclass protocol - dictionary: The class dictionary of the class we're - constructing. dictionary[_DESCRIPTOR_KEY] must contain - a Descriptor object describing this protocol message - type. - """ - descriptor = dictionary[GeneratedProtocolMessageType._DESCRIPTOR_KEY] - _InitMessage(descriptor, cls) - superclass = super(GeneratedProtocolMessageType, cls) - superclass.__init__(name, bases, dictionary) +# The type of all Message classes. +# Part of the public interface. +# +# Used by generated files, but clients can also use it at runtime: +# mydescriptor = pool.FindDescriptor(.....) +# class MyProtoClass(Message): +# __metaclass__ = GeneratedProtocolMessageType +# DESCRIPTOR = mydescriptor +GeneratedProtocolMessageType = message_impl.GeneratedProtocolMessageType def ParseMessage(descriptor, byte_str): diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index 8cbd68222e2ed..82133765f9476 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -113,7 +113,7 @@ def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False, fields.sort(key=lambda x: x[0].index) for field, value in fields: if _IsMapEntry(field): - for key in value: + for key in sorted(value): # This is slow for maps with submessage entires because it copies the # entire tree. Unfortunately this would take significant refactoring # of this file to work around. diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index c66fdfadec565..c6ed37ae38b3d 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -50,7 +50,7 @@ AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) void AnyMetadata::PackFrom(const Message& message) { type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(), - GetTypeUrl(message.GetDescriptor())); + GetTypeUrl(message.GetDescriptor())); message.SerializeToString(value_->MutableNoArena( &::google::protobuf::internal::GetEmptyStringAlreadyInited())); } @@ -76,7 +76,7 @@ bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { type_url.size() - prefix_len); return true; } - return true; + return false; } diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index f681eceb69a8e..7eeb6b707afce 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -34,9 +34,9 @@ #include #include -#include #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index ed1c5ef2e0c72..907a6a20c50d7 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -66,8 +66,12 @@ void Arena::Init() { first_block->size = options_.initial_block_size; first_block->pos = kHeaderSize; first_block->next = NULL; - first_block->owner = &first_block->owner; - AddBlock(first_block); + // Thread which calls Init() owns the first block. This allows the + // single-threaded case to allocate on the first block without taking any + // locks. + first_block->owner = &thread_cache(); + SetThreadCacheBlock(first_block); + AddBlockInternal(first_block); owns_first_block_ = false; } @@ -80,7 +84,7 @@ void Arena::Init() { } Arena::~Arena() { - uint64 space_allocated = Reset(); + uint64 space_allocated = ResetInternal(); // Call the destruction hook if (options_.on_arena_destruction != NULL) { @@ -89,10 +93,14 @@ Arena::~Arena() { } uint64 Arena::Reset() { - CleanupList(); - uint64 space_allocated = FreeBlocks(); // Invalidate any ThreadCaches pointing to any blocks we just destroyed. lifecycle_id_ = lifecycle_id_generator_.GetNext(); + return ResetInternal(); +} + +uint64 Arena::ResetInternal() { + CleanupList(); + uint64 space_allocated = FreeBlocks(); // Call the reset hook if (options_.on_arena_reset != NULL) { @@ -137,6 +145,10 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n, void Arena::AddBlock(Block* b) { MutexLock l(&blocks_lock_); + AddBlockInternal(b); +} + +void Arena::AddBlockInternal(Block* b) { b->next = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast(b)); if (b->avail() != 0) { @@ -181,16 +193,6 @@ void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) { void* me = &thread_cache(); Block* b = reinterpret_cast(google::protobuf::internal::Acquire_Load(&hint_)); if (!b || b->owner != me || b->avail() < n) { - // If the next block to allocate from is the first block, try to claim it - // for this thread. - if (!owns_first_block_ && b->next == NULL) { - MutexLock l(&blocks_lock_); - if (b->owner == &b->owner && b->avail() >= n) { - b->owner = me; - SetThreadCacheBlock(b); - return AllocFromBlock(b, n); - } - } return SlowAlloc(n); } return AllocFromBlock(b, n); @@ -267,8 +269,12 @@ uint64 Arena::FreeBlocks() { // Make the first block that was passed in through ArenaOptions // available for reuse. first_block->pos = kHeaderSize; - first_block->owner = &first_block->owner; - AddBlock(first_block); + // Thread which calls Reset() owns the first block. This allows the + // single-threaded case to allocate on the first block without taking any + // locks. + first_block->owner = &thread_cache(); + SetThreadCacheBlock(first_block); + AddBlockInternal(first_block); } return space_allocated; } diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index 51149bae522ac..f06be4a3d7584 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -31,6 +31,7 @@ #ifndef GOOGLE_PROTOBUF_ARENA_H__ #define GOOGLE_PROTOBUF_ARENA_H__ +#include #if __cplusplus >= 201103L #include #endif @@ -39,7 +40,8 @@ #include #include #include -#include +#include +#include #include namespace google { @@ -414,6 +416,9 @@ class LIBPROTOBUF_EXPORT Arena { // trivially destructible. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) { + GOOGLE_CHECK_LE(num_elements, + std::numeric_limits::max() / sizeof(T)) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { return static_cast(::operator new[](num_elements * sizeof(T))); } else { @@ -425,16 +430,16 @@ class LIBPROTOBUF_EXPORT Arena { // of the underlying blocks. The total space used may not include the new // blocks that are allocated by this arena from other threads concurrently // with the call to this method. - uint64 SpaceAllocated() const GOOGLE_ATTRIBUTE_NOINLINE; + GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceAllocated() const; // As above, but does not include any free space in underlying blocks. - uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE; + GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() const; // Frees all storage allocated by this arena after calling destructors // registered with OwnDestructor() and freeing objects registered with Own(). // Any objects allocated on this arena are unusable after this call. It also // returns the total space used by the arena which is the sums of the sizes // of the allocated blocks. This method is not thread-safe. - uint64 Reset() GOOGLE_ATTRIBUTE_NOINLINE; + GOOGLE_ATTRIBUTE_NOINLINE uint64 Reset(); // Adds |object| to a list of heap-allocated objects to be freed with |delete| // when the arena is destroyed or reset. @@ -459,8 +464,8 @@ class LIBPROTOBUF_EXPORT Arena { // will be manually called when the arena is destroyed or reset. This differs // from OwnDestructor() in that any member function may be specified, not only // the class destructor. - void OwnCustomDestructor(void* object, void (*destruct)(void*)) - GOOGLE_ATTRIBUTE_NOINLINE { + GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object, + void (*destruct)(void*)) { AddListNode(object, destruct); } @@ -469,7 +474,7 @@ class LIBPROTOBUF_EXPORT Arena { // latter is a virtual call, while this method is a templated call that // resolves at compile-time. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - static inline ::google::protobuf::Arena* GetArena(const T* value) { + static ::google::protobuf::Arena* GetArena(const T* value) { return GetArenaInternal(value, static_cast(0)); } @@ -507,7 +512,7 @@ class LIBPROTOBUF_EXPORT Arena { // aligned at a multiple of 8 bytes. size_t pos; size_t size; // total size of the block. - size_t avail() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { return size - pos; } + GOOGLE_ATTRIBUTE_ALWAYS_INLINE size_t avail() const { return size - pos; } // data follows }; @@ -555,6 +560,33 @@ class LIBPROTOBUF_EXPORT Arena { return google::protobuf::internal::has_trivial_destructor::value; } + // Helper typetrait that indicates whether the desctructor of type T should be + // called when arena is destroyed at compile time. This is only to allow + // construction of higher-level templated utilities. + // is_destructor_skippable::value is an instance of google::protobuf::internal::true_type if the + // destructor of the message type T should not be called when arena is + // destroyed or google::protobuf::internal::has_trivial_destructor::value == true, and + // google::protobuf::internal::false_type otherwise. + // + // This is inside Arena because only Arena has the friend relationships + // necessary to see the underlying generated code traits. + template + struct is_destructor_skippable { + template + static char DestructorSkippable( + const typename U::DestructorSkippable_*); + template + static double DestructorSkippable(...); + + // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. + typedef google::protobuf::internal::integral_constant(static_cast(0))) == + sizeof(char) || google::protobuf::internal::has_trivial_destructor::value == true> + type; + static const type value; + }; + + // CreateMessage requires that T supports arenas, but this private method // works whether or not T supports arenas. These are not exposed to user code // as it can cause confusing API usages, and end up having double free in @@ -574,14 +606,16 @@ class LIBPROTOBUF_EXPORT Arena { // Just allocate the required size for the given type assuming the // type has a trivial constructor. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternalRawArray(size_t num_elements) { + T* CreateInternalRawArray(size_t num_elements) { + GOOGLE_CHECK_LE(num_elements, + std::numeric_limits::max() / sizeof(T)) + << "Requested size is too large to fit into size_t."; return static_cast( AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements)); } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( - bool skip_explicit_ownership) { + T* CreateInternal(bool skip_explicit_ownership) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); @@ -590,8 +624,7 @@ class LIBPROTOBUF_EXPORT Arena { } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( - bool skip_explicit_ownership, const Arg& arg) { + T* CreateInternal(bool skip_explicit_ownership, const Arg& arg) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object); @@ -600,7 +633,7 @@ class LIBPROTOBUF_EXPORT Arena { } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( + T* CreateInternal( bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2); if (!skip_explicit_ownership) { @@ -610,10 +643,10 @@ class LIBPROTOBUF_EXPORT Arena { } template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3); if (!skip_explicit_ownership) { @@ -624,11 +657,11 @@ class LIBPROTOBUF_EXPORT Arena { template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4); if (!skip_explicit_ownership) { @@ -639,12 +672,12 @@ class LIBPROTOBUF_EXPORT Arena { template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5); if (!skip_explicit_ownership) { @@ -655,13 +688,13 @@ class LIBPROTOBUF_EXPORT Arena { template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6); if (!skip_explicit_ownership) { @@ -672,14 +705,14 @@ class LIBPROTOBUF_EXPORT Arena { template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6, - const Arg7& arg7) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6, arg7); if (!skip_explicit_ownership) { @@ -691,15 +724,15 @@ class LIBPROTOBUF_EXPORT Arena { template - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6, - const Arg7& arg7, - const Arg8& arg8) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7, + const Arg8& arg8) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); if (!skip_explicit_ownership) { @@ -709,21 +742,21 @@ class LIBPROTOBUF_EXPORT Arena { } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*) { return CreateInternal(SkipDeleteList(static_cast(0)), this); } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, - const Arg& arg) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg& arg) { return CreateInternal(SkipDeleteList(static_cast(0)), this, arg); } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, - const Arg1& arg1, const Arg2& arg2) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg1& arg1, const Arg2& arg2) { return CreateInternal(SkipDeleteList(static_cast(0)), this, arg1, arg2); } @@ -734,19 +767,29 @@ class LIBPROTOBUF_EXPORT Arena { template static void CreateInArenaStorage(T* ptr, Arena* arena) { CreateInArenaStorageInternal(ptr, arena, is_arena_constructable::value); + RegisterDestructorInternal(ptr, arena, is_destructor_skippable::value); } + template static void CreateInArenaStorageInternal( T* ptr, Arena* arena, google::protobuf::internal::true_type) { new (ptr) T(arena); } - template static void CreateInArenaStorageInternal( T* ptr, Arena* arena, google::protobuf::internal::false_type) { new (ptr) T; } + template + static void RegisterDestructorInternal( + T* ptr, Arena* arena, google::protobuf::internal::true_type) {} + template + static void RegisterDestructorInternal( + T* ptr, Arena* arena, google::protobuf::internal::false_type) { + arena->OwnDestructor(ptr); + } + // These implement Own(), which registers an object for deletion (destructor // call and operator delete()). The second parameter has type 'true_type' if T // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing @@ -769,13 +812,13 @@ class LIBPROTOBUF_EXPORT Arena { // InternalArenaConstructable_ tags can be associated with an arena, and such // objects must implement a GetArenaNoVirtual() method. template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, - typename T::InternalArenaConstructable_*) { + static ::google::protobuf::Arena* GetArenaInternal( + const T* value, typename T::InternalArenaConstructable_*) { return value->GetArenaNoVirtual(); } template GOOGLE_ATTRIBUTE_ALWAYS_INLINE - static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) { + static ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) { return NULL; } @@ -785,7 +828,7 @@ class LIBPROTOBUF_EXPORT Arena { void* AllocateAligned(const std::type_info* allocated, size_t n); // Allocate an internal allocation, avoiding optional typed monitoring. - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline void* AllocateAligned(size_t n) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* AllocateAligned(size_t n) { return AllocateAligned(NULL, n); } @@ -803,6 +846,7 @@ class LIBPROTOBUF_EXPORT Arena { void AddListNode(void* elem, void (*cleanup)(void*)); // Delete or Destruct all objects owned by the arena. void CleanupList(); + uint64 ResetInternal(); inline void SetThreadCacheBlock(Block* block) { thread_cache().last_block_used_ = block; @@ -829,6 +873,9 @@ class LIBPROTOBUF_EXPORT Arena { Mutex blocks_lock_; void AddBlock(Block* b); + // Access must be synchronized, either by blocks_lock_ or by being called from + // Init()/Reset(). + void AddBlockInternal(Block* b); void* SlowAlloc(size_t n); Block* FindBlock(void* me); Block* NewBlock(void* me, Block* my_last_block, size_t n, @@ -854,6 +901,11 @@ const typename Arena::is_arena_constructable::type Arena::is_arena_constructable::value = typename Arena::is_arena_constructable::type(); +template +const typename Arena::is_destructor_skippable::type + Arena::is_destructor_skippable::value = + typename Arena::is_destructor_skippable::type(); + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/arena_test_util.cc b/src/google/protobuf/arena_test_util.cc index 21f55c6e47fcc..df9c5bd6b488c 100644 --- a/src/google/protobuf/arena_test_util.cc +++ b/src/google/protobuf/arena_test_util.cc @@ -28,6 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include #include #include diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 6c185695caf05..c9ca1fd18d7d1 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -40,7 +40,9 @@ #include #include +#include #include +#include #include #include #include @@ -619,8 +621,6 @@ TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) { } } -// N.B.: no reflection version of this test because all the arena-specific code -// is in RepeatedPtrField, and the reflection works implicitly based on that. TEST(ArenaTest, AddAllocatedToRepeatedField) { // Heap->arena case. Arena arena1; @@ -680,6 +680,55 @@ TEST(ArenaTest, AddAllocatedToRepeatedField) { } } +TEST(ArenaTest, AddAllocatedToRepeatedFieldViaReflection) { + // Heap->arena case. + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + const Reflection* r = arena1_message->GetReflection(); + const Descriptor* d = arena1_message->GetDescriptor(); + const FieldDescriptor* fd = + d->FindFieldByName("repeated_nested_message"); + for (int i = 0; i < 10; i++) { + TestAllTypes::NestedMessage* heap_submessage = + new TestAllTypes::NestedMessage; + heap_submessage->set_bb(42); + r->AddAllocatedMessage(arena1_message, fd, heap_submessage); + // Should not copy object -- will use arena_->Own(). + EXPECT_EQ(heap_submessage, + &arena1_message->repeated_nested_message(i)); + EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb()); + } + + // Arena1->Arena2 case. + arena1_message->Clear(); + for (int i = 0; i < 10; i++) { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + r->AddAllocatedMessage(arena1_message, fd, arena2_submessage); + // Should copy object. + EXPECT_NE(arena2_submessage, + &arena1_message->repeated_nested_message(i)); + EXPECT_EQ(42, arena1_message->repeated_nested_message(i).bb()); + } + + // Arena->heap case. + TestAllTypes* heap_message = new TestAllTypes; + for (int i = 0; i < 10; i++) { + Arena arena2; + TestAllTypes::NestedMessage* arena2_submessage = + Arena::CreateMessage(&arena2); + arena2_submessage->set_bb(42); + r->AddAllocatedMessage(heap_message, fd, arena2_submessage); + // Should copy object. + EXPECT_NE(arena2_submessage, + &heap_message->repeated_nested_message(i)); + EXPECT_EQ(42, heap_message->repeated_nested_message(i).bb()); + } + delete heap_message; +} + TEST(ArenaTest, ReleaseLastRepeatedField) { // Release from arena-allocated repeated field and ensure that returned object // is heap-allocated. @@ -1230,7 +1279,7 @@ TEST(ArenaTest, ArenaHooksSanity) { EXPECT_EQ(1, ArenaHooksTestUtil::num_init); EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations); ::google::protobuf::Arena::Create(&arena); - if (::google::protobuf::internal::has_trivial_destructor::value) { + if (google::protobuf::internal::has_trivial_destructor::value) { EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations); } else { EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations); diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h index d829ed9191dcb..1dacdc68c02ee 100755 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -33,6 +33,7 @@ #include +#include #include #include @@ -145,7 +146,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // Swaps internal pointers. Arena-safety semantics: this is guarded by the // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is // 'unsafe' if called directly. - inline void Swap(ArenaStringPtr* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) { std::swap(ptr_, other->ptr_); } @@ -283,9 +284,8 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { private: ::std::string* ptr_; - inline void CreateInstance(::google::protobuf::Arena* arena, - const ::std::string* initial_value) - GOOGLE_ATTRIBUTE_NOINLINE { + GOOGLE_ATTRIBUTE_NOINLINE void CreateInstance(::google::protobuf::Arena* arena, + const ::std::string* initial_value) { // Assumes ptr_ is not NULL. if (initial_value != NULL) { ptr_ = new ::std::string(*initial_value); @@ -296,8 +296,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { arena->Own(ptr_); } } - inline void CreateInstanceNoArena(const ::std::string* initial_value) - GOOGLE_ATTRIBUTE_NOINLINE { + GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) { if (initial_value != NULL) { ptr_ = new ::std::string(*initial_value); } else { diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc index 8ebd4b9cca111..3fb582be1d18e 100644 --- a/src/google/protobuf/arenastring_unittest.cc +++ b/src/google/protobuf/arenastring_unittest.cc @@ -42,6 +42,7 @@ #endif #include +#include #include #include diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0039b00a78e91..473eb4e6fba5b 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include +#include #include #include diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index e88718615aa88..26a4f0b066e3f 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -1657,7 +1658,11 @@ bool CommandLineInterface::WriteDescriptorSet( &already_seen, file_set.mutable_file()); } } else { + set already_seen; for (int i = 0; i < parsed_files.size(); i++) { + if (!already_seen.insert(parsed_files[i]).second) { + continue; + } FileDescriptorProto* file_proto = file_set.add_file(); parsed_files[i]->CopyTo(file_proto); if (source_info_in_descriptor_set_) { diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index e5b77c3363609..46ea5c4e42a6d 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -886,6 +886,39 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); } +TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Baz {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(3, descriptor_set.file_size()); + EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); + EXPECT_EQ("foo.proto", descriptor_set.file(1).name()); + EXPECT_EQ("baz.proto", descriptor_set.file(2).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); +} + TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 13ed0b64b40bb..c3e9fe7448661 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -133,8 +133,7 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { CppGenerator generator; MockGeneratorContext context; string error; - string parameter; - parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; + string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &context, &error)); parameter = "dllexport_decl=LIBPROTOC_EXPORT"; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 70d3a6006178d..de4d7cc73b6af 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -32,7 +32,6 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include #include #include @@ -70,14 +69,11 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} -void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) { +void EnumGenerator::FillForwardDeclaration(set* enum_names) { if (!options_.proto_h) { return; } - map vars; - vars["classname"] = classname_; - printer->Print(vars, "enum $classname$ : int;\n"); - printer->Print(vars, "bool $classname$_IsValid(int value);\n"); + enum_names->insert(classname_); } void EnumGenerator::GenerateDefinition(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 3e930856bd84b..f3aa72e4409ad 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -35,6 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#include #include #include #include @@ -60,11 +61,11 @@ class EnumGenerator { // Header stuff. - // Generate header code to forward-declare the enum. This is for use when + // Fills the name to use when declaring the enum. This is for use when // generating other .proto.h files. This code should be placed within the // enum's package namespace, but NOT within any class, even for nested // enums. - void GenerateForwardDeclaration(io::Printer* printer); + void FillForwardDeclaration(set* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 965327b1887fa..824e2205e43c6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -35,7 +35,6 @@ #include #include #include -#include #include namespace google { diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 43df1d88924ef..8d47d4e086999 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -47,6 +47,7 @@ #include #include #include +#include #include #include diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 1f0a8205ebff4..5dae4cdd6ce71 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include #include #ifndef _SHARED_PTR_H #include @@ -93,22 +94,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateHeader(io::Printer* printer) { - GenerateTopHeaderGuard(printer); +void FileGenerator::GenerateProtoHeader(io::Printer* printer) { + if (!options_.proto_h) { + return; + } + + string filename_identifier = FilenameIdentifier(file_->name()); + GenerateTopHeaderGuard(printer, filename_identifier); + GenerateLibraryIncludes(printer); - GenerateDependencyIncludes(printer); + + for (int i = 0; i < file_->public_dependency_count(); i++) { + const FileDescriptor* dep = file_->public_dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\" // IWYU pragma: export\n", + "dependency", dependency); + } printer->Print( "// @@protoc_insertion_point(includes)\n"); + GenerateForwardDeclarations(printer); // Open namespace. GenerateNamespaceOpeners(printer); GenerateGlobalStateFunctionDeclarations(printer); - GenerateMessageForwardDeclarations(printer); printer->Print("\n"); @@ -133,6 +148,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { GenerateInlineFunctionDefinitions(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -144,19 +164,89 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n" "\n"); - GenerateBottomHeaderGuard(printer); + GenerateBottomHeaderGuard(printer, filename_identifier); +} + +void FileGenerator::GeneratePBHeader(io::Printer* printer) { + string filename_identifier = + FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); + GenerateTopHeaderGuard(printer, filename_identifier); + + if (options_.proto_h) { + printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", + "basename", StripProto(file_->name())); + } else { + GenerateLibraryIncludes(printer); + } + GenerateDependencyIncludes(printer); + + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + + + + // Open namespace. + GenerateNamespaceOpeners(printer); + + if (!options_.proto_h) { + GenerateGlobalStateFunctionDeclarations(printer); + GenerateMessageForwardDeclarations(printer); + + printer->Print("\n"); + + GenerateEnumDefinitions(printer); + + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateMessageDefinitions(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateServiceDefinitions(printer); + + GenerateExtensionIdentifiers(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateInlineFunctionDefinitions(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + + // Close up namespace. + GenerateNamespaceClosers(printer); + + if (!options_.proto_h) { + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + + GenerateBottomHeaderGuard(printer, filename_identifier); } void FileGenerator::GenerateSource(io::Printer* printer) { + string header = + StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" - // The generated code calls accessors that might be deprecated. We don't // want the compiler to warn in generated code. "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" - "#include \"$basename$.pb.h\"\n" + "#include \"$header$\"\n" "\n" "#include \n" // for swap() "\n" @@ -165,7 +255,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include \n" "#include \n", "filename", file_->name(), - "basename", StripProto(file_->name())); + "header", header); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { @@ -181,6 +271,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include \n"); } + if (options_.proto_h) { + // Use the smaller .proto.h files. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dep = file_->dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\"\n", + "dependency", dependency); + } + } + printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -276,6 +378,59 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n"); } +class FileGenerator::ForwardDeclarations { + public: + ~ForwardDeclarations() { + for (map::iterator it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + delete it->second; + } + namespaces_.clear(); + } + + ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { + ForwardDeclarations*& ns = namespaces_[ns_name]; + if (ns == NULL) { + ns = new ForwardDeclarations; + } + return ns; + } + + set& classes() { return classes_; } + set& enums() { return enums_; } + + void Print(io::Printer* printer) const { + for (set::const_iterator it = enums_.begin(), end = enums_.end(); + it != end; ++it) { + printer->Print("enum $enumname$ : int;\n" + "bool $enumname$_IsValid(int value);\n", + "enumname", it->c_str()); + } + for (set::const_iterator it = classes_.begin(), + end = classes_.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); + } + for (map::const_iterator + it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + printer->Print("namespace $nsname$ {\n", + "nsname", it->first); + it->second->Print(printer); + printer->Print("} // namespace $nsname$\n", + "nsname", it->first); + } + } + + + private: + map namespaces_; + set classes_; + set enums_; +}; + void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for @@ -434,12 +589,17 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); +#ifdef _MSC_VER + bool breakdown_large_file = true; +#else + bool breakdown_large_file = false; +#endif // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 // bytes in length". Declare a static array of characters rather than use a // string literal. - if (file_data.size() > 65535) { + if (breakdown_large_file && file_data.size() > 65535) { printer->Print( - "static const char descriptor[] = {\n"); + "static const char descriptor[] = {\n"); printer->Indent(); // Only write 25 bytes per line. @@ -447,26 +607,25 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_data.size();) { for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { printer->Print( - "$char$, ", - "char", SimpleItoa(file_data[i])); + "$char$, ", + "char", SimpleItoa(file_data[i])); } printer->Print( - "\n"); + "\n"); } printer->Outdent(); printer->Print( - "};\n"); + "};\n"); printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", - "size", SimpleItoa(file_data.size())); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", + "size", SimpleItoa(file_data.size())); } else { - printer->Print( "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); - + // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { @@ -474,11 +633,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", EscapeTrigraphs( CEscape(file_data.substr(i, kBytesPerLine)))); - } - printer->Print( - ", $size$);\n", + } + printer->Print( + ", $size$);\n", "size", SimpleItoa(file_data.size())); - } // Call MessageFactory::InternalRegisterGeneratedFile(). @@ -548,8 +706,40 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { } } -void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { + ForwardDeclarations decls; + for (int i = 0; i < file_->dependency_count(); i++) { + FileGenerator dependency(file_->dependency(i), options_); + dependency.FillForwardDeclarations(&decls); + } + FillForwardDeclarations(&decls); + decls.Print(printer); +} + +void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { + for (int i = 0; i < file_->public_dependency_count(); i++) { + FileGenerator dependency(file_->public_dependency(i), options_); + dependency.FillForwardDeclarations(decls); + } + for (int i = 0; i < package_parts_.size(); i++) { + decls = decls->AddOrGetNamespace(package_parts_[i]); + } + // Generate enum definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillEnumForwardDeclarations(&decls->enums()); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->FillForwardDeclaration(&decls->enums()); + } + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillMessageForwardDeclarations( + &decls->classes()); + } +} + +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" @@ -564,8 +754,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { "filename_identifier", filename_identifier); } -void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateBottomHeaderGuard( + io::Printer* printer, const string& filename_identifier) { printer->Print( "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", "filename_identifier", filename_identifier); @@ -696,9 +886,13 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( } void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - // Generate forward declarations of classes. + set classes; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateMessageForwardDeclaration(printer); + message_generators_[i]->FillMessageForwardDeclarations(&classes); + } + for (set::const_iterator it = classes.begin(), end = classes.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); } } @@ -804,10 +998,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { // Methods of the dependent base class must always be inline in the header. message_generators_[i]->GenerateDependentInlineMethods(printer); } - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); } void FileGenerator::GenerateProto2NamespaceEnumSpecializations( diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index e68f67bb53c6c..29cdaea53d25b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -69,10 +69,14 @@ class FileGenerator { const Options& options); ~FileGenerator(); - void GenerateHeader(io::Printer* printer); + void GenerateProtoHeader(io::Printer* printer); + void GeneratePBHeader(io::Printer* printer); void GenerateSource(io::Printer* printer); private: + // Internal type used by GenerateForwardDeclarations (defined in file.cc). + class ForwardDeclarations; + // Generate the BuildDescriptors() procedure, which builds all descriptors // for types defined in the file. void GenerateBuildDescriptors(io::Printer* printer); @@ -80,9 +84,19 @@ class FileGenerator { void GenerateNamespaceOpeners(io::Printer* printer); void GenerateNamespaceClosers(io::Printer* printer); + // For other imports, generates their forward-declarations. + void GenerateForwardDeclarations(io::Printer* printer); + + // Internal helper used by GenerateForwardDeclarations: fills 'decls' + // with all necessary forward-declarations for this file and its + // transient depednencies. + void FillForwardDeclarations(ForwardDeclarations* decls); + // Generates top or bottom of a header file. - void GenerateTopHeaderGuard(io::Printer* printer); - void GenerateBottomHeaderGuard(io::Printer* printer); + void GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier); + void GenerateBottomHeaderGuard(io::Printer* printer, + const string& filename_identifier); // Generates #include directives. void GenerateLibraryIncludes(io::Printer* printer); @@ -92,10 +106,20 @@ class FileGenerator { void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); // Generates types for classes. - void GenerateMessageForwardDeclarations(io::Printer* printer); void GenerateMessageDefinitions(io::Printer* printer); + // Generates forward-declarations for just this file's classes. This is + // used for .pb.h headers, but not in proto_h mode. + void GenerateMessageForwardDeclarations(io::Printer* printer); + + // Fills in types for forward declarations. This is used internally, and + // also by other FileGenerators to determine imports' declarations. + void FillMessageForwardDeclarations(ForwardDeclarations* decls); + void FillMessageDefinitions(ForwardDeclarations* decls); + // Generates enum definitions. + void GenerateEnumForwardDeclarations(io::Printer* printer); + void FillEnumForwardDeclarations(ForwardDeclarations* decls); void GenerateEnumDefinitions(io::Printer* printer); // Generates generic service definitions. diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 99416372000e2..781526b505cb9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -100,16 +100,23 @@ bool CppGenerator::Generate(const FileDescriptor* file, string basename = StripProto(file->name()); - basename.append(".pb"); FileGenerator file_generator(file, file_options); - // Generate header. + // Generate header(s). + if (file_options.proto_h) { + google::protobuf::scoped_ptr output( + generator_context->Open(basename + ".proto.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateProtoHeader(&printer); + } + + basename.append(".pb"); { google::protobuf::scoped_ptr output( generator_context->Open(basename + ".h")); io::Printer printer(output.get(), '$'); - file_generator.GenerateHeader(&printer); + file_generator.GeneratePBHeader(&printer); } // Generate cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 0f3688d03081e..678a995aeb74a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ const char* const kKeywordList[] = { "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", + "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", @@ -174,6 +175,14 @@ string SuperClassName(const Descriptor* descriptor) { "::google::protobuf::Message" : "::google::protobuf::MessageLite"; } +string DependentBaseDownCast() { + return "reinterpret_cast(this)->"; +} + +string DependentBaseConstDownCast() { + return "reinterpret_cast(this)->"; +} + string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -208,6 +217,19 @@ string FieldConstantName(const FieldDescriptor *field) { } bool IsFieldDependent(const FieldDescriptor* field) { + if (field->containing_oneof() != NULL && + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + return true; + } + if (field->is_map()) { + const Descriptor* map_descriptor = field->message_type(); + for (int i = 0; i < map_descriptor->field_count(); i++) { + if (IsFieldDependent(map_descriptor->field(i))) { + return true; + } + } + return false; + } if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { return false; } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 4bbf8303455d5..29c1f90bf71e9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -70,8 +70,15 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); // This is a class name, like "ProtoName_InternalBase". string DependentBaseClassTemplateName(const Descriptor* descriptor); +// Name of the base class: either the dependent base class (for use with +// proto_h) or google::protobuf::Message. string SuperClassName(const Descriptor* descriptor); +// Returns a string that down-casts from the dependent base class to the +// derived class. +string DependentBaseDownCast(); +string DependentBaseConstDownCast(); + // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0ff0d27c3a6ed..a14d8986395d5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -100,8 +100,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MapFieldGenerator:: MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { + const Options& options) + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -152,7 +153,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MapFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void MapFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index d27d485162b24..5e205623b808c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -63,6 +63,7 @@ class MapFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; + const bool dependent_field_; map variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index b0e38755a2bc8..aa10b0bb0dc60 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -39,7 +39,6 @@ #ifndef _SHARED_PTR_H #include #endif -#include #include #include #include @@ -415,31 +414,34 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, use_dependent_base_ = true; } } + if (options.proto_h && descriptor->oneof_decl_count() > 0) { + // Always make oneofs dependent. + use_dependent_base_ = true; + } } MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -GenerateMessageForwardDeclaration(io::Printer* printer) { - printer->Print("class $classname$;\n", - "classname", classname_); +FillMessageForwardDeclarations(set* class_names) { + class_names->insert(classname_); for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need forward declaration. Since map entry // message cannot be a top level class, we just need to avoid calling // GenerateForwardDeclaration here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateMessageForwardDeclaration(printer); + nested_generators_[i]->FillMessageForwardDeclarations(class_names); } } void MessageGenerator:: -GenerateEnumForwardDeclaration(io::Printer* printer) { +FillEnumForwardDeclarations(set* enum_names) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateEnumForwardDeclaration(printer); + nested_generators_[i]->FillEnumForwardDeclarations(enum_names); } for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateForwardDeclaration(printer); + enum_generators_[i]->FillForwardDeclaration(enum_names); } } @@ -484,13 +486,6 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); printer->Print("\n"); } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - PrintFieldComment(printer, oneof); - printer->Print( - "void clear_$oneof_name$();\n", - "oneof_name", oneof->name()); - } } void MessageGenerator:: @@ -505,7 +500,9 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { vars["constant_name"] = FieldConstantName(field); bool dependent_field = use_dependent_base_ && IsFieldDependent(field); - if (dependent_field) { + if (dependent_field && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_map()) { // If this field is dependent, the dependent base class determines // the message type from the derived class (which is a template // parameter). This typedef is for that: @@ -594,8 +591,8 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { vars["tmpl"] = "template\n"; vars["dependent_classname"] = DependentBaseClassTemplateName(descriptor_) + ""; - vars["this_message"] = "reinterpret_cast(this)->"; - vars["this_const_message"] = "reinterpret_cast(this)->"; + vars["this_message"] = DependentBaseDownCast(); + vars["this_const_message"] = DependentBaseConstDownCast(); GenerateFieldClear(field, vars, printer); } @@ -721,13 +718,15 @@ GenerateFieldClear(const FieldDescriptor* field, printer->Print(vars, "if ($this_message$has_$name$()) {\n"); printer->Indent(); - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); printer->Print(vars, "$this_message$clear_has_$oneof_name$();\n"); printer->Outdent(); printer->Print("}\n"); } else { - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); if (HasFieldPresence(descriptor_->file())) { if (!field->is_repeated()) { printer->Print(vars, @@ -752,6 +751,18 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { map vars; SetCommonFieldVariables(field, &vars, options_); vars["inline"] = is_inline ? "inline " : ""; + if (use_dependent_base_ && IsFieldDependent(field)) { + vars["tmpl"] = "template\n"; + vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + ""; + vars["this_message"] = "reinterpret_cast(this)->"; + vars["this_const_message"] = "reinterpret_cast(this)->"; + } else { + vars["tmpl"] = ""; + vars["dependent_classname"] = vars["classname"]; + vars["this_message"] = ""; + vars["this_const_message"] = ""; + } // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -775,10 +786,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { } if (!use_dependent_base_ || !IsFieldDependent(field)) { - vars["tmpl"] = ""; - vars["dependent_classname"] = vars["classname"]; - vars["this_message"] = ""; - vars["this_const_message"] = ""; GenerateFieldClear(field, vars, printer); } @@ -915,15 +922,32 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "\n"); } else { - printer->Print( - "inline const ::std::string& unknown_fields() const {\n" - " return _unknown_fields_;\n" - "}\n" - "\n" - "inline ::std::string* mutable_unknown_fields() {\n" - " return &_unknown_fields_;\n" - "}\n" - "\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.Get(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.Mutable(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n" + "}\n" + "\n"); + } else { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.GetNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.MutableNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n"); + } } } @@ -1068,6 +1092,10 @@ GenerateClassDefinition(io::Printer* printer) { } } uses_string_ = false; + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + uses_string_ = true; + } for (int i = 0; i < descriptors.size(); i++) { const FieldDescriptor* field = descriptors[i]; if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { @@ -1201,18 +1229,11 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - if (use_dependent_base_) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } else { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "void clear_$oneof_name$();\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); } if (HasGeneratedMethods(descriptor_->file()) && @@ -1262,7 +1283,7 @@ GenerateClassDefinition(io::Printer* printer) { "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { printer->Print( - "::std::string _unknown_fields_;\n" + "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n" "::google::protobuf::Arena* _arena_ptr_;\n" "\n"); } @@ -1919,6 +1940,13 @@ GenerateSharedConstructorCode(io::Printer* printer) { uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", "_cached_size_ = 0;\n").c_str()); + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "_unknown_fields_.UnsafeSetDefault(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { field_generators_.get(descriptor_->field(i)) @@ -1955,6 +1983,22 @@ GenerateSharedDestructorCode(io::Printer* printer) { "}\n" "\n"); } + + // Write the desctructor for _unknown_fields_ in lite runtime. + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.Destroy(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.DestroyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + } + // Write the destructors for each field except oneof members. for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { @@ -2463,8 +2507,16 @@ GenerateClear(io::Printer* printer) { " mutable_unknown_fields()->Clear();\n" "}\n"); } else { - printer->Print( - "mutable_unknown_fields()->clear();\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.ClearToEmpty(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.ClearToEmptyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } } } @@ -2481,33 +2533,22 @@ GenerateOneofClear(io::Printer* printer) { oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); string message_class; - if (use_dependent_base_) { - oneof_vars["tmpl"] = "template\n"; - oneof_vars["inline"] = "inline "; - oneof_vars["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_) + ""; - oneof_vars["this_message"] = "reinterpret_cast(this)->"; - message_class = "T::"; - } else { - oneof_vars["tmpl"] = ""; - oneof_vars["inline"] = ""; - oneof_vars["dependent_classname"] = classname_; - oneof_vars["this_message"] = ""; - } - printer->Print(oneof_vars, - "$tmpl$" - "$inline$" - "void $dependent_classname$::clear_$oneofname$() {\n"); + "void $classname$::clear_$oneofname$() {\n"); printer->Indent(); + // In .proto.h mode, fields with a dependent type will generate + // clearing code that down casts from the dependent base class. + // However, clear_oneof() methods are always in the .cc file, and thus + // must remain in the derived base. So, to make the clearing code work, + // we add a typedef so that the down cast works (it will be a no-op). printer->Print(oneof_vars, - "switch($this_message$$oneofname$_case()) {\n"); + "typedef $classname$ T;\n" + "switch($oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "case $message_class$k$field_name$: {\n", - "message_class", message_class, + "case k$field_name$: {\n", "field_name", UnderscoresToCamelCase(field->name(), true)); printer->Indent(); // We clear only allocated objects in oneofs @@ -2524,20 +2565,16 @@ GenerateOneofClear(io::Printer* printer) { "}\n"); } printer->Print( - "case $message_class$$cap_oneof_name$_NOT_SET: {\n" + "case $cap_oneof_name$_NOT_SET: {\n" " break;\n" "}\n", - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n" - "$this_message$_oneof_case_[$oneof_index$] = " - "$message_class$$cap_oneof_name$_NOT_SET;\n", - "this_message", oneof_vars["this_message"], + "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", "oneof_index", SimpleItoa(i), - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); @@ -2612,7 +2649,7 @@ GenerateSwap(io::Printer* printer) { printer->Print( "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); } else { - printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n"); + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } } else { // Still swap internal_metadata as it may contain more than just diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 23dad10c1d777..8e19a3f055737 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -39,8 +39,8 @@ #ifndef _SHARED_PTR_H #include #endif +#include #include -#include #include #include @@ -66,9 +66,10 @@ class MessageGenerator { // Header stuff. - // Generate foward declarations for this class and all its nested types. - void GenerateMessageForwardDeclaration(io::Printer* printer); - void GenerateEnumForwardDeclaration(io::Printer* printer); + // Return names for foward declarations of this class and all its nested + // types. + void FillMessageForwardDeclarations(set* class_names); + void FillEnumForwardDeclarations(set* enum_names); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index ba318d10bc1cf..b454589203134 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -63,6 +63,14 @@ void SetMessageVariables(const FieldDescriptor* descriptor, SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); + if (options.proto_h && IsFieldDependent(descriptor)) { + (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor); + (*variables)["dependent_typename"] = + "typename T::" + DependentTypeName(descriptor); + } else { + (*variables)["dependent_type"] = FieldMessageTypeName(descriptor); + (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor); + } } } // namespace @@ -84,8 +92,22 @@ GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "$type$* $name$_;\n"); } +void MessageFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + void MessageFieldGenerator:: GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + // Arena manipulation code is out-of-line in the derived message class. + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); } void MessageFieldGenerator:: @@ -103,11 +125,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$type$* _slow_$release_name$()$deprecation$;\n" "public:\n"); } - printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n" - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + GenerateGetterDeclaration(printer); + if (!dependent_field_) { + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + } if (SupportsArenas(descriptor_)) { printer->Print(variables_, "$type$* unsafe_arena_release_$name$()$deprecation$;\n" @@ -123,12 +147,12 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( "void $classname$::_slow_mutable_$name$() {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); } else { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); } printer->Print(variables_, "}\n" @@ -151,7 +175,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( if (SupportsArenas(descriptor_->message_type())) { // NOTE: the same logic is mirrored in weak_message_field.cc. Any // arena-related semantics changes should be made in both places. - printer->Print(variables_, + printer->Print(variables_, "void $classname$::_slow_set_allocated_$name$(\n" " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n" " if (message_arena != NULL && \n" @@ -189,15 +213,139 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( void MessageFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + + map variables(variables_); + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + ""; + variables["this_message"] = DependentBaseDownCast(); + if (!variables["set_hasbit"].empty()) { + variables["set_hasbit"] = + variables["this_message"] + variables["set_hasbit"]; + } + if (!variables["clear_hasbit"].empty()) { + variables["clear_hasbit"] = + variables["this_message"] + variables["clear_hasbit"]; + } + + if (SupportsArenas(descriptor_)) { + printer->Print(variables, + "template \n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if ($name$_ == NULL) {\n" + " $this_message$_slow_mutable_$name$();\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template \n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $clear_hasbit$\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " return $this_message$_slow_$release_name$();\n" + " } else {\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + "}\n" + "template \n" + "inline void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " ::google::protobuf::Arena* message_arena = $this_message$GetArenaNoVirtual();\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if (message_arena == NULL) {\n" + " delete $name$_;\n" + " }\n" + " if ($name$ != NULL) {\n"); + if (SupportsArenas(descriptor_->message_type())) { + // If we're on an arena and the incoming message is not, simply Own() it + // rather than copy to the arena -- either way we need a heap dealloc, + // so we might as well defer it. Otherwise, if incoming message is on a + // different ownership domain (specific arena, or the heap) than we are, + // copy to our arena (or heap, as the case may be). + printer->Print(variables, + " $this_message$_slow_set_allocated_$name$(message_arena, " + "&$name$);\n"); + } else { + printer->Print(variables, + " if (message_arena != NULL) {\n" + " message_arena->Own($name$);\n" + " }\n"); + } + printer->Print(variables, + " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + // TODO(dlj): move insertion points to message class. + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } else { + printer->Print(variables, + "template \n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if ($name$_ == NULL) {\n" + " $name$_ = new $dependent_typename$;\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template \n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n" + "template \n" + "inline void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " delete $name$_;\n"); + + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables, + " if ($name$ != NULL && static_cast< $dependent_typename$* >($name$)" + "->GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } + + printer->Print(variables, + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } } void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" + "$inline$const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( @@ -206,19 +354,25 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", // Without. " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); + printer->Print(variables, "}\n"); + + if (dependent_field_) { + return; + } if (SupportsArenas(descriptor_)) { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" - " _slow_mutable_$name$();" + " _slow_mutable_$name$();\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" @@ -228,7 +382,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return temp;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ " + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n" " if (message_arena == NULL) {\n" " delete $name$_;\n" @@ -260,8 +415,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " $name$_ = new $type$;\n" @@ -269,13 +424,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$" + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " delete $name$_;\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -301,15 +458,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n" - "$name$_ = NULL;\n"); + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL && " + "$this_message$$name$_ != NULL) delete $this_message$$name$_;\n" + "$this_message$$name$_ = NULL;\n"); } else { - printer->Print(variables_, - "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); + printer->Print(variables, + "if ($this_message$$name$_ != NULL) $this_message$$name$_->" + "$dependent_type$::Clear();\n"); } } @@ -370,79 +531,149 @@ GenerateByteSize(io::Printer* printer) const { MessageOneofFieldGenerator:: MessageOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : MessageFieldGenerator(descriptor, options) { + : MessageFieldGenerator(descriptor, options), + dependent_base_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} + +void MessageOneofFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Otherwise, the logic is the same as MessageFields. + if (!dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); + MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer); +} + +void MessageOneofFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Unlike MessageField, this means there is no (non-dependent) getter to + // generate. + if (dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + void MessageOneofFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + if (!dependent_base_) { + return; + } + map variables(variables_); + variables["inline"] = "inline "; + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + ""; + variables["this_message"] = "reinterpret_cast(this)->"; + // Const message access is needed for the dependent getter. + variables["this_const_message"] = "reinterpret_cast(this)->"; + variables["tmpl"] = "template \n"; + variables["field_member"] = variables["this_message"] + + variables["oneof_prefix"] + variables["name"] + + "_"; + InternalGenerateInlineAccessorDefinitions(variables, printer); } void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + if (dependent_base_) { + return; + } map variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; + variables["dependent_classname"] = variables["classname"]; + variables["this_message"] = ""; + variables["this_const_message"] = ""; + variables["tmpl"] = ""; + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + variables["dependent_type"] = variables["type"]; + InternalGenerateInlineAccessorDefinitions(variables, printer); +} + +void MessageOneofFieldGenerator:: +GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { + map variables(variables_); + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + + //printer->Print(variables, +} + +void MessageOneofFieldGenerator:: +InternalGenerateInlineAccessorDefinitions(const map& variables, + io::Printer* printer) const { + printer->Print(variables, + "$tmpl$" + "$inline$ " + "const $type$& $dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$has_$name$()\n" + " ? *$this_const_message$$oneof_prefix$$name$_\n" + " : $dependent_type$::default_instance();\n" + "}\n"); + if (SupportsArenas(descriptor_)) { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n"); + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $field_member$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } else { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $this_message$$oneof_prefix$$name$_ = \n" + " ::google::protobuf::Arena::Create< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " if (GetArenaNoVirtual() != NULL) {\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" // N.B.: safe to use the underlying field pointer here because we are sure // that it is non-NULL (because has_$name$() returned true). - " $type$* temp = new $type$;\n" - " temp->MergeFrom(*$oneof_prefix$$name$_);\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = new $dependent_typename$;\n" + " temp->MergeFrom(*$field_member$);\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " }\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" - " return temp;\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -450,32 +681,42 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, // If incoming message is on the heap and we are on an arena, just Own() // it (see above). If it's on a different arena than we are or one of us // is on the heap, we make a copy to our arena/heap. - " if (GetArenaNoVirtual() != NULL &&\n" + " if ($this_message$GetArenaNoVirtual() != NULL &&\n" " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" - " } else if (GetArenaNoVirtual() !=\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" + " } else if ($this_message$GetArenaNoVirtual() !=\n" " ::google::protobuf::Arena::GetArena($name$)) {\n" - " $type$* new_$name$ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n" + " $dependent_typename$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } else { printer->Print(variables, - " if (GetArenaNoVirtual() != NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" - "$type$* $name$) {\n" + "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $oneof_prefix$$name$_;\n" + " $oneof_prefix$$name$_ = NULL;\n" + " return temp;\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$" + "($type$* $name$) {\n" // We rely on the oneof clear method to free the earlier contents of this // oneof. We can directly use the pointer we're given to set the new // value. @@ -489,44 +730,47 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new $type$;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = new $dependent_typename$;\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " if ($name$->GetArena() != NULL) {\n" - " $type$* new_$name$ = new $type$;\n" + " if (static_cast< $dependent_typename$*>($name$)->" + "GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -535,14 +779,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL) {\n" - " delete $oneof_prefix$$name$_;\n" + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL) {\n" + " delete $this_message$$oneof_prefix$$name$_;\n" "}\n"); } else { - printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + printer->Print(variables, + "delete $this_message$$oneof_prefix$$name$_;\n"); } } @@ -562,7 +808,9 @@ GenerateConstructorCode(io::Printer* printer) const { RepeatedMessageFieldGenerator:: RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + dependent_getter_(dependent_field_ && options.safe_boundary_check) { SetMessageVariables(descriptor, &variables_, options); } @@ -575,60 +823,160 @@ GeneratePrivateMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -GenerateDependentAccessorDeclarations(io::Printer* printer) const { -} - -void RepeatedMessageFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { +InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n" "$type$* mutable_$name$(int index)$deprecation$;\n" "$type$* add_$name$()$deprecation$;\n"); + if (dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n" "::google::protobuf::RepeatedPtrField< $type$ >*\n" " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } } void RepeatedMessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer, - bool is_inline) const { +GenerateAccessorDeclarations(io::Printer* printer) const { + if (!dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (!dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } + if (!dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } map variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + ""; + variables["this_message"] = DependentBaseDownCast(); + variables["this_const_message"] = DependentBaseConstDownCast(); + + if (dependent_getter_) { + printer->Print(variables, + "template \n" + "inline const $type$& $dependent_classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$$name$_.$cppget$(index);\n" + "}\n"); + } + + // Generate per-element accessors: printer->Print(variables, - "$inline$ const $type$& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.$cppget$(index);\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$(int index) {\n" + "template \n" + "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" + " return $this_message$$name$_.Mutable(index);\n" "}\n" - "$inline$ $type$* $classname$::add_$name$() {\n" + "template \n" + "inline $type$* $dependent_classname$::add_$name$() {\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $name$_.Add();\n" + " return $this_message$$name$_.Add();\n" "}\n"); + + + if (dependent_getter_) { + printer->Print(variables, + "template \n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $this_const_message$$name$_;\n" + "}\n"); + } + + // Generate mutable access to the entire list: printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" + "template \n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$dependent_classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" + " return &$this_message$$name$_;\n" "}\n"); } +void RepeatedMessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map variables(variables_); + variables["inline"] = is_inline ? "inline " : ""; + + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.$cppget$(index);\n" + "}\n"); + } + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "$type$* $classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable(index);\n" + "}\n" + "$inline$" + "$type$* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + " return $name$_.Add();\n" + "}\n"); + } + + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); + } + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n"); + } +} + void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void RepeatedMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 9ddf9643953b6..35efd0fa7c06c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -68,6 +68,11 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; protected: + void GenerateArenaManipulationCode(const map& variables, + io::Printer* printer) const; + + virtual void GenerateGetterDeclaration(io::Printer* printer) const; + const FieldDescriptor* descriptor_; const bool dependent_field_; map variables_; @@ -83,15 +88,23 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {} + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + protected: + void GenerateGetterDeclaration(io::Printer* printer) const; + private: + void InternalGenerateInlineAccessorDefinitions( + const map& variables, io::Printer* printer) const; + + const bool dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); }; @@ -118,7 +131,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: + void InternalGenerateTypeDependentAccessorDeclarations( + io::Printer* printer) const; + const FieldDescriptor* descriptor_; + const bool dependent_field_; + const bool dependent_getter_; map variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 1a3896a15be3b..d1af6ddaf7f13 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -421,7 +421,8 @@ GenerateByteSize(io::Printer* printer) const { StringOneofFieldGenerator:: StringOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : StringFieldGenerator(descriptor, options) { + : StringFieldGenerator(descriptor, options), + dependent_field_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -604,13 +605,29 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map variables(variables_); + if (dependent_field_) { + variables["this_message"] = DependentBaseDownCast(); + // This clearing code may be in the dependent base class. If the default + // value is an empty string, then the $default_variable$ is a global + // singleton. If the default is not empty, we need to down-cast to get the + // default value's global singleton instance. See SetStringVariables() for + // possible values of default_variable. + if (!descriptor_->default_value_string().empty()) { + variables["default_variable"] = + DependentBaseDownCast() + variables["default_variable"]; + } + } else { + variables["this_message"] = ""; + } if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "$oneof_prefix$$name$_.Destroy($default_variable$,\n" - " GetArenaNoVirtual());\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_.Destroy($default_variable$,\n" + " $this_message$GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_." + "DestroyNoArena($default_variable$);\n"); } } @@ -664,7 +681,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { RepeatedStringFieldGenerator:: RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index d1f19cd942b44..616e20674f70d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -93,6 +93,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateMergeFromCodedStream(io::Printer* printer) const; private: + const bool dependent_field_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index bd1c0fde03096..e5ef6ecd48854 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -67,7 +67,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 43eb0ed58302f..33c9328fe33d3 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -44,6 +44,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 0353b6072e0f7..8a09f3a83ecf2 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -181,8 +181,8 @@ void EnumGenerator::Generate(io::Printer* printer) { " internalGetValueMap() {\n" " return internalValueMap;\n" "}\n" - "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" - " internalValueMap =\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" " return $classname$.valueOf(number);\n" diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 39318a192a86c..558da968ee2a8 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 697a07a73306f..2c3608c290150 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index e69de29bb2d1d..621863861f6ce 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -0,0 +1,226 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool EnumHasCustomOptions(const EnumDescriptor* descriptor) { + if (descriptor->options().unknown_fields().field_count() > 0) return true; + for (int i = 0; i < descriptor->value_count(); ++i) { + const EnumValueDescriptor* value = descriptor->value(i); + if (value->options().unknown_fields().field_count() > 0) return true; + } + return false; +} +} // namespace + +EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context) + : descriptor_(descriptor), immutable_api_(immutable_api), + name_resolver_(context->GetNameResolver()) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumLiteGenerator::~EnumLiteGenerator() {} + +void EnumLiteGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.Internal.EnumLite {\n", + "classname", descriptor_->name()); + } + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + map vars; + vars["name"] = canonical_values_[i]->name(); + vars["index"] = SimpleItoa(canonical_values_[i]->index()); + vars["number"] = SimpleItoa(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } + printer->Print(vars, + "$name$($index$, $number$),\n"); + } + + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } + + printer->Print( + ";\n" + "\n"); + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + map vars; + vars["classname"] = descriptor_->name(); + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); + printer->Print(vars, + "public static final $classname$ $name$ = $canonical_name$;\n"); + } + + for (int i = 0; i < descriptor_->value_count(); i++) { + map vars; + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = SimpleItoa(descriptor_->value(i)->number()); + WriteEnumValueDocComment(printer, descriptor_->value(i)); + printer->Print(vars, + "public static final int $name$_VALUE = $number$;\n"); + } + printer->Print("\n"); + + // ----------------------------------------------------------------- + + printer->Print( + "\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + printer->Print( + " return value;\n" + "}\n" + "\n" + "public static $classname$ valueOf(int value) {\n" + " switch (value) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print( + "case $number$: return $name$;\n", + "name", canonical_values_[i]->name(), + "number", SimpleItoa(canonical_values_[i]->number())); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " default: return null;\n" + " }\n" + "}\n" + "\n" + "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" + " internalGetValueMap() {\n" + " return internalValueMap;\n" + "}\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" + " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" + " public $classname$ findValueByNumber(int number) {\n" + " return $classname$.valueOf(number);\n" + " }\n" + " };\n" + "\n", + "classname", descriptor_->name()); + + printer->Print( + "private final int value;\n\n" + "private $classname$(int index, int value) {\n", + "classname", descriptor_->name()); + printer->Print( + " this.value = value;\n" + "}\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +bool EnumLiteGenerator::CanUseEnumValues() { + if (canonical_values_.size() != descriptor_->value_count()) { + return false; + } + for (int i = 0; i < descriptor_->value_count(); i++) { + if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { + return false; + } + } + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h index e69de29bb2d1d..ee2f5f7a88c79 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.h +++ b/src/google/protobuf/compiler/java/java_enum_lite.h @@ -0,0 +1,99 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class EnumLiteGenerator { + public: + explicit EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context); + ~EnumLiteGenerator(); + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same numeric + // value. Java, however, does not allow multiple enum constants to be + // considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + vector canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector aliases_; + + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + + bool CanUseEnumValues(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index 3f0fa11fe3543..c54347677b394 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -39,6 +39,7 @@ #include #endif +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 00f3c601e864d..0e24da24c643b 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -44,6 +44,7 @@ #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 96d2545f31b95..99ba6a187d9ea 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -332,6 +332,10 @@ inline bool PreserveUnknownFields(const Descriptor* descriptor) { return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } +inline bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->full_name() == "google.protobuf.Any"; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 44b86cd74d16e..3e035c89b9123 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -314,6 +314,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " internalGetMutable$capitalized_name$().getMutableMap(),\n" " $name$ValueConverter);\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -331,6 +339,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$Value() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -346,6 +362,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index cd1698f0b38d1..4fe656d3bbbbf 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -303,6 +303,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -321,6 +329,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$Value();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -337,6 +353,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 09b0fd945c86e..80d6e9ade1bbd 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -255,6 +255,18 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName( + descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -292,8 +304,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { " com.google.protobuf.GeneratedMessage implements\n" " $extra_interfaces$\n" " $classname$OrBuilder {\n"); - - builder_type = "com.google.protobuf.GeneratedMessage.Builder"; + builder_type = "com.google.protobuf.GeneratedMessage.Builder"; } printer->Indent(); // Using builder_type, instead of Builder, prevents the Builder class from @@ -435,6 +446,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "\n"); } + if (IsAnyMessage(descriptor_)) { + GenerateAnyMethods(printer); + } + // Fields for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("public static final int $constant_name$ = $number$;\n", @@ -578,9 +593,8 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Print( "}\n" "\n" - "private int memoizedSerializedSize = -1;\n" "public int getSerializedSize() {\n" - " int size = memoizedSerializedSize;\n" + " int size = memoizedSize;\n" " if (size != -1) return size;\n" "\n" " size = 0;\n"); @@ -612,7 +626,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Outdent(); printer->Print( - " memoizedSerializedSize = size;\n" + " memoizedSize = size;\n" " return size;\n" "}\n" "\n"); @@ -948,22 +962,58 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("boolean result = true;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "result = result && (has$name$() == other.has$name$());\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print( + "}\n"); + } + } + } + + // Compare oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "result = result && get$oneof_capitalized_name$Case().equals(\n" + " other.get$oneof_capitalized_name$Case());\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Print( + "if (!result) return false;\n" + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { + field_generators_.get(field).GenerateEqualsCode(printer); + printer->Print("break;\n"); printer->Outdent(); - printer->Print( - "}\n"); } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); } + if (PreserveUnknownFields(descriptor_)) { // Always consider unknown fields for equality. This will sometimes return // false for non-canonical ordering when running in LITE_RUNTIME but it's @@ -1198,7 +1248,7 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" + "private static final com.google.protobuf.Parser<$classname$> PARSER =\n" " new com.google.protobuf.AbstractParser<$classname$>() {\n", "classname", descriptor_->name()); printer->Indent(); @@ -1250,6 +1300,10 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { "\n"); printer->Print( + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return PARSER;\n" + "}\n" + "\n" "@java.lang.Override\n" "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" " return PARSER;\n" @@ -1269,6 +1323,50 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { } +void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { + printer->Print( + "private static String getTypeUrl(\n" + " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" + " return \"type.googleapis.com/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "public static Any pack(\n" + " T message) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "public boolean is(\n" + " java.lang.Class clazz) {\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " return getTypeUrl().equals(\n" + " getTypeUrl(defaultInstance.getDescriptorForType()));\n" + "}\n" + "\n" + "private volatile com.google.protobuf.Message cachedUnpackValue;\n" + "\n" + "public T unpack(\n" + " java.lang.Class clazz)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " if (!is(clazz)) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " \"Type of the Any messsage does not match the given class.\");\n" + " }\n" + " if (cachedUnpackValue != null) {\n" + " return (T) cachedUnpackValue;\n" + " }\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " T result = (T) defaultInstance.getParserForType()\n" + " .parseFrom(getValue());\n" + " cachedUnpackValue = result;\n" + " return result;\n" + "}\n"); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index c3c37765142dc..be5bfb07546e9 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -122,6 +122,7 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); void GenerateParsingConstructor(io::Printer* printer); + void GenerateAnyMethods(io::Printer* printer); Context* context_; ClassNameResolver* name_resolver_; diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b180b4a7183eb..b5f8e626fdd54 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -452,11 +452,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -736,11 +736,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -1232,11 +1233,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 8332202c5e0cc..356520ec6570a 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -310,11 +310,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -521,11 +521,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -885,11 +886,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(\n" + " input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 3accee92c7395..8b6c75b8ba3f0 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include #include @@ -143,6 +143,17 @@ void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName(descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -190,7 +201,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator(descriptor_->enum_type(i), true, context_) + EnumLiteGenerator(descriptor_->enum_type(i), true, context_) .Generate(printer); } @@ -321,12 +332,12 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "protected final Object dynamicMethod(\n" " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" - " Object... args) {\n" + " Object arg0, Object arg1) {\n" " switch (method) {\n" " case PARSE_PARTIAL_FROM: {\n" " return new $classname$(" - " (com.google.protobuf.CodedInputStream) args[0],\n" - " (com.google.protobuf.ExtensionRegistryLite) args[1]);\n" + " (com.google.protobuf.CodedInputStream) arg0,\n" + " (com.google.protobuf.ExtensionRegistryLite) arg1);\n" " }\n" " case NEW_INSTANCE: {\n" " return new $classname$(\n" @@ -370,7 +381,25 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "case GET_DEFAULT_INSTANCE: {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "case GET_PARSER: {\n" + // Generally one would use the lazy initialization holder pattern for + // manipulating static fields but that has exceptional cost on Android as + // it will generate an extra class for every message. Instead, use the + // double-check locking pattern which works just as well. + " if (PARSER == null) {" + " synchronized ($classname$.class) {\n" + " if (PARSER == null) {\n" + " PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" + " }\n" + " }\n" + " }\n" + " return PARSER;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Outdent(); printer->Outdent(); @@ -413,18 +442,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateParser(printer); - // LITE_RUNTIME uses this to implement the *ForType methods at the - // GeneratedMessageLite level. - printer->Print( - "static {\n" - " com.google.protobuf.GeneratedMessageLite.onLoad(\n" - " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n" - " .PrototypeHolder<$classname$, Builder>(\n" - " DEFAULT_INSTANCE, PARSER));" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - // Extensions must be declared after the DEFAULT_INSTANCE is initialized // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. @@ -554,54 +571,54 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input);\n" + " return parser().parseDelimitedFrom(input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n" + " return parser().parseDelimitedFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -652,7 +669,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( "if (isInitialized == 1) return DEFAULT_INSTANCE;\n" "if (isInitialized == 0) return null;\n" "\n" - "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n"); + "boolean shouldMemoize = ((Boolean) arg0).booleanValue();\n"); // Check that all required fields in this message are set. // TODO(kenton): We can optimize this when we switch to putting all the @@ -778,7 +795,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( .GenerateDynamicMethodMakeImmutableCode(printer); } printer->Print( - "return null;"); + "return null;\n"); } // =================================================================== @@ -786,7 +803,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( io::Printer* printer) { printer->Print( - "return new Builder();"); + "return new Builder();\n"); } // =================================================================== @@ -796,9 +813,8 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( printer->Print( // Optimization: If other is the default instance, we know none of its // fields are set so we can skip the merge. - "Object arg = args[0];\n" - "if (arg == $classname$.getDefaultInstance()) return this;\n" - "$classname$ other = ($classname$) arg;\n", + "if (arg0 == $classname$.getDefaultInstance()) return this;\n" + "$classname$ other = ($classname$) arg0;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1151,9 +1167,11 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" - " new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" - "\n", + "private static volatile com.google.protobuf.Parser<$classname$> PARSER;\n" + "\n" + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return DEFAULT_INSTANCE.getParserForType();\n" + "}\n", "classname", descriptor_->name()); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 7bebe12a94de2..178bbe1900463 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 217ff9b69ce14..392333b8cbb76 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 7baead153a334..11bfc12d1b306 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -39,7 +39,6 @@ #include #include #include -#include #include namespace google { diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 68e863ccc396c..47e046598381f 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, " if (value == null) {\n" " throw new NullPointerException();\n" " }\n"; + (*variables)["writeString"] = + "com.google.protobuf.GeneratedMessage.writeString"; + (*variables)["computeStringSize"] = + "com.google.protobuf.GeneratedMessage.computeStringSize"; // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported // by the proto compiler @@ -433,7 +438,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $name$_);\n" "}\n"); } @@ -441,8 +446,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $name$_);\n" "}\n"); } @@ -689,7 +693,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $oneof_name$_);\n" "}\n"); } @@ -697,8 +701,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $oneof_name$_);\n" "}\n"); } @@ -1007,12 +1010,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " writeStringNoTag(output, $name$_.getRaw(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " $writeString$(output, $number$, $name$_.getRaw(i));\n" "}\n"); } } @@ -1026,8 +1029,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index 51bb245c493ea..032715b7b53fb 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -64,7 +65,8 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, map* variables) { SetCommonFieldVariables(descriptor, info, variables); - (*variables)["empty_list"] = "emptyLazyStringArrayList()"; + (*variables)["empty_list"] = + "com.google.protobuf.GeneratedMessageLite.emptyProtobufList()"; (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_init"] = @@ -101,7 +103,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_message"] = ""; (*variables)["is_field_present_message"] = - "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()"; + "!get" + (*variables)["capitalized_name"] + ".isEmpty()"; } // For repeated builders, the underlying list tracks mutability state. @@ -144,8 +146,9 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { return 0; } -// A note about how strings are handled. This code used to just store a String -// in the Message. This had two issues: +// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes, +// strings are not stored as java.lang.String in the Message because of two +// issues: // // 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded // strings, but rather fields that were raw bytes incorrectly marked @@ -160,22 +163,14 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { // it many cases, the field is never even read by the application code. This // avoids unnecessary conversions in the common use cases. // -// So now, the field for String is maintained as an Object reference which can -// either store a String or a ByteString. The code uses an instanceof check -// to see which one it has and converts to the other one if needed. It remembers -// the last value requested (in a thread safe manner) as this is most likely -// the one needed next. The thread safety is such that if two threads both -// convert the field because the changes made by each thread were not visible to -// the other, they may cause a conversion to happen more times than would -// otherwise be necessary. This was deemed better than adding synchronization -// overhead. It will not cause any corruption issues or affect the behavior of -// the API. The instanceof check is also highly optimized in the JVM and we -// decided it was better to reduce the memory overhead by not having two -// separate fields but rather use dynamic type checking. -// -// For single fields, the logic for this is done inside the generated code. For -// repeated fields, the logic is done in LazyStringArrayList and -// UnmodifiableLazyStringList. +// In the LITE_RUNTIME, we store strings as java.lang.String because we assume +// that the users of this runtime are not subject to proto1 constraints and are +// running code on devices that are user facing. That is, the developers are +// properly incentivized to only fetch the data they need to read and wish to +// reduce the number of allocations incurred when running on a user's device. + +// TODO(dweis): Consider dropping all of the *Bytes() methods. They really +// shouldn't be necessary or used on devices. void ImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { @@ -195,7 +190,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_;\n"); + "private java.lang.String $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { @@ -209,40 +204,13 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " $name$_ = s;\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8()) {\n" - " $name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" - " }\n" + " return $name$_;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " $name$_ = b;\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" - " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -273,7 +241,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_has_field_bit_message$\n" - " $name$_ = value;\n" + " $name$_ = value.toStringUtf8();\n" "}\n"); } @@ -368,7 +336,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -377,11 +345,6 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_has_field_bit_message$\n" - "$name$_ = bs;\n"); } } @@ -392,18 +355,24 @@ GenerateParsingDoneCode(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -458,51 +427,22 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return ref;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = b;\n" - " }\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8(ref);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -533,7 +473,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" + " $oneof_name$_ = value.toStringUtf8();\n" "}\n"); } @@ -603,7 +543,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -612,28 +552,29 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_oneof_case_message$;\n" - "$oneof_name$_ = bs;\n"); } } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -667,7 +608,7 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$com.google.protobuf.ProtocolStringList\n" + "$deprecation$java.util.List\n" " get$capitalized_name$List();\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -685,12 +626,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private com.google.protobuf.LazyStringArrayList $name$_;\n"); + "private com.google.protobuf.Internal.ProtobufList $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" - " get$capitalized_name$List() {\n" + "$deprecation$public java.util.List get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -707,7 +647,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes(int index) {\n" - " return $name$_.getByteString(index);\n" + " return com.google.protobuf.ByteString.copyFromUtf8(\n" + " $name$_.get(index));\n" "}\n"); if (descriptor_->options().packed() && @@ -719,7 +660,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n" + " $name$_);\n" " }\n" "}\n"); @@ -764,7 +706,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.add(value.toStringUtf8());\n" "}\n"); } @@ -772,10 +714,10 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" + "$deprecation$public java.util.List\n" " get$capitalized_name$List() {\n" - " return ((com.google.protobuf.LazyStringList)\n" - " instance.get$capitalized_name$List()).getUnmodifiableView();\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -875,20 +817,17 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "String s = input.readStringRequireUtf8();\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, "String s = input.readString();\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n"); } printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n"); if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, @@ -905,7 +844,7 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n" "while (input.getBytesUntilLimit() > 0) {\n"); if (CheckUtf8(descriptor_)) { @@ -932,6 +871,9 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. if (descriptor_->options().packed()) { printer->Print(variables_, "if (get$capitalized_name$List().size() > 0) {\n" @@ -939,18 +881,21 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " output.writeStringNoTag($name$_.get(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " output.writeString($number$, $name$_.get(i));\n" "}\n"); } } void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "{\n" " int dataSize = 0;\n"); @@ -959,7 +904,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " .computeStringSizeNoTag($name$_.get(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index a2eeee2d31d0c..895ff34a10a6b 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 16012e960399c..007b001c3554e 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -323,7 +323,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& service_location, const FileDescriptorProto* containing_file); - // Parse one statement within a message, enum, or service block, inclunding + // Parse one statement within a message, enum, or service block, including // final semicolon. bool ParseMessageStatement(DescriptorProto* message, const LocationRecorder& message_location, @@ -364,7 +364,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& extensions_location, const FileDescriptorProto* containing_file); - // Parse an "reserved" declaration. + // Parse a "reserved" declaration. bool ParseReserved(DescriptorProto* message, const LocationRecorder& message_location); bool ParseReservedNames(DescriptorProto* message, @@ -415,7 +415,7 @@ class LIBPROTOBUF_EXPORT Parser { Message* mutable_options); // Parse "required", "optional", or "repeated" and fill in "label" - // with the value. Returns true if shuch a label is consumed. + // with the value. Returns true if such a label is consumed. bool ParseLabel(FieldDescriptorProto::Label* label, const FileDescriptorProto* containing_file); diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index cdcaffde9774c..2bebf1f3ad8b8 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -48,6 +48,7 @@ #include #endif +#include #include #include #include diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index e7890fae050b3..994bc392fd4c1 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -629,28 +629,28 @@ int CodeGeneratorRequest::proto_file_size() const { void CodeGeneratorRequest::clear_proto_file() { proto_file_.Clear(); } - const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { +const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Get(index); } - ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { +::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Mutable(index); } - ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { +::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -CodeGeneratorRequest::proto_file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* CodeGeneratorRequest::mutable_proto_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return &proto_file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -1535,28 +1535,28 @@ int CodeGeneratorResponse::file_size() const { void CodeGeneratorResponse::clear_file() { file_.Clear(); } - const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { +const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Get(index); } - ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { +::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Mutable(index); } - ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { +::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* CodeGeneratorResponse::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) return &file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 6fcaea2e8002c..ab79bdae45f88 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -144,10 +144,10 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); ::google::protobuf::FileDescriptorProto* add_proto_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& - proto_file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_proto_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + proto_file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) private: @@ -378,10 +378,10 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& - file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* mutable_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& + file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) private: @@ -534,16 +534,16 @@ inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -CodeGeneratorRequest::proto_file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* CodeGeneratorRequest::mutable_proto_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return &proto_file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_; +} // ------------------------------------------------------------------- @@ -784,16 +784,16 @@ inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorRe // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* CodeGeneratorResponse::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) return &file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 7b3b5fa3cd4a5..4d500f90e9cc5 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -58,6 +58,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 2ddac6015b9af..aa0f5fced68e0 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -38,6 +38,7 @@ #include #include +#include #include namespace google { diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index a3cff1f8b8029..85429924ca856 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -42,6 +42,7 @@ #include #endif +#include #include #include #include diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 2855c377e1698..5256b83c44e1c 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -53,6 +53,8 @@ #include #include #include +#include +#include #include #include #include @@ -1092,6 +1094,7 @@ const DescriptorPool* DescriptorPool::generated_pool() { return generated_pool_; } + DescriptorPool* DescriptorPool::internal_generated_pool() { InitGeneratedPoolOnce(); return generated_pool_; @@ -3699,6 +3702,14 @@ static bool ExistingFileMatchesProto(const FileDescriptor* existing_file, const FileDescriptorProto& proto) { FileDescriptorProto existing_proto; existing_file->CopyTo(&existing_proto); + // TODO(liujisi): Remove it when CopyTo supports copying syntax params when + // syntax="proto2". + if (existing_file->syntax() == FileDescriptor::SYNTAX_PROTO2 && + proto.has_syntax()) { + existing_proto.set_syntax( + existing_file->SyntaxName(existing_file->syntax())); + } + return existing_proto.SerializeAsString() == proto.SerializeAsString(); } @@ -4649,7 +4660,7 @@ void DescriptorBuilder::CrossLinkMessage( // safe. if (oneof_decl->field_count() > 0 && message->field(i - 1)->containing_oneof() != oneof_decl) { - AddWarning( + AddError( message->full_name() + "." + message->field(i - 1)->name(), proto.field(i - 1), DescriptorPool::ErrorCollector::OTHER, strings::Substitute( @@ -5088,8 +5099,7 @@ void DescriptorBuilder::ValidateProto3Field( field->containing_type()->full_name() + "\" which is a proto3 message type."); } - bool allow_groups = false; - if (field->type() == FieldDescriptor::TYPE_GROUP && !allow_groups) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, "Groups are not supported in proto3 syntax."); @@ -5307,6 +5317,14 @@ bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field, // are added. } + if (value->type() == FieldDescriptor::TYPE_ENUM) { + if (value->enum_type()->value(0)->number() != 0) { + AddError( + field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Enum value in map must define 0 as the first value."); + } + } + return true; } diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index ca87d6341566e..2ab316a521389 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -58,6 +58,7 @@ #include #include #include +#include // TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. #ifdef TYPE_BOOL @@ -860,7 +861,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { friend class FieldDescriptor; friend class EnumValueDescriptor; friend class FileDescriptor; - friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection; + friend class internal::GeneratedMessageReflection; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); }; @@ -1332,6 +1333,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // this pool. Do not add your own descriptors to this pool. static const DescriptorPool* generated_pool(); + // Find a FileDescriptor in the pool by file name. Returns NULL if not // found. const FileDescriptor* FindFileByName(const string& name) const; diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 5e7eeaa786dc7..6f9905aa979c6 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -755,9 +755,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s" "pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022" "\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de" - "tached_comments\030\006 \003(\tB[\n\023com.google.prot" + "tached_comments\030\006 \003(\tB;\n\023com.google.prot" "obufB\020DescriptorProtosH\001Z\ndescriptor\242\002\003G" - "PB\252\002\032Google.Protobuf.Reflection\260\002\001", 4994); + "PB", 4962); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -1066,28 +1066,28 @@ int FileDescriptorSet::file_size() const { void FileDescriptorSet::clear_file() { file_.Clear(); } - const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { +const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorSet.file) return file_.Get(index); } - ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) { +::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorSet.file) return file_.Mutable(index); } - ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { +::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file) return file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -FileDescriptorSet::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) - return file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* FileDescriptorSet::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file) return &file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) + return file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -2091,28 +2091,28 @@ int FileDescriptorProto::message_type_size() const { void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } - const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { +const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.message_type) return message_type_.Get(index); } - ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) { +::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message_type(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.message_type) return message_type_.Mutable(index); } - ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { +::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type) return message_type_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -FileDescriptorProto::message_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type) - return message_type_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* FileDescriptorProto::mutable_message_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type) return &message_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type) + return message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; int FileDescriptorProto::enum_type_size() const { @@ -2121,28 +2121,28 @@ int FileDescriptorProto::enum_type_size() const { void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } - const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { +const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.enum_type) return enum_type_.Get(index); } - ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) { +::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enum_type(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.enum_type) return enum_type_.Mutable(index); } - ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { +::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type) return enum_type_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -FileDescriptorProto::enum_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type) - return enum_type_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* FileDescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type) return &enum_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; int FileDescriptorProto::service_size() const { @@ -2151,28 +2151,28 @@ int FileDescriptorProto::service_size() const { void FileDescriptorProto::clear_service() { service_.Clear(); } - const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { +const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.service) return service_.Get(index); } - ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) { +::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_service(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.service) return service_.Mutable(index); } - ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { +::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service) return service_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& -FileDescriptorProto::service() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) - return service_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* FileDescriptorProto::mutable_service() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service) return &service_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) + return service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; int FileDescriptorProto::extension_size() const { @@ -2181,28 +2181,28 @@ int FileDescriptorProto::extension_size() const { void FileDescriptorProto::clear_extension() { extension_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { +const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.extension) return extension_.Get(index); } - ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) { +::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_extension(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.extension) return extension_.Mutable(index); } - ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { +::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension) return extension_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -FileDescriptorProto::extension() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) - return extension_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* FileDescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension) return &extension_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) + return extension_; +} // optional .google.protobuf.FileOptions options = 8; bool FileDescriptorProto::has_options() const { @@ -2218,11 +2218,11 @@ void FileDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); clear_has_options(); } - const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { +const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { +::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::FileOptions; @@ -2230,13 +2230,13 @@ void FileDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options) return options_; } - ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { +::google::protobuf::FileOptions* FileDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; return temp; } - void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) { +void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) { delete options_; options_ = options; if (options) { @@ -2261,11 +2261,11 @@ void FileDescriptorProto::clear_source_code_info() { if (source_code_info_ != NULL) source_code_info_->::google::protobuf::SourceCodeInfo::Clear(); clear_has_source_code_info(); } - const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const { +const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info() const { // @@protoc_insertion_point(field_get:google.protobuf.FileDescriptorProto.source_code_info) return source_code_info_ != NULL ? *source_code_info_ : *default_instance_->source_code_info_; } - ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() { +::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_code_info() { set_has_source_code_info(); if (source_code_info_ == NULL) { source_code_info_ = new ::google::protobuf::SourceCodeInfo; @@ -2273,13 +2273,13 @@ void FileDescriptorProto::clear_source_code_info() { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info) return source_code_info_; } - ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { +::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; return temp; } - void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) { +void FileDescriptorProto::set_allocated_source_code_info(::google::protobuf::SourceCodeInfo* source_code_info) { delete source_code_info_; source_code_info_ = source_code_info; if (source_code_info) { @@ -3720,28 +3720,28 @@ int DescriptorProto::field_size() const { void DescriptorProto::clear_field() { field_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { +const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.field) return field_.Get(index); } - ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) { +::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.field) return field_.Mutable(index); } - ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { +::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field) return field_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::field() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) - return field_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_field() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field) return &field_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) + return field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; int DescriptorProto::extension_size() const { @@ -3750,28 +3750,28 @@ int DescriptorProto::extension_size() const { void DescriptorProto::clear_extension() { extension_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { +const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension) return extension_.Get(index); } - ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) { +::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extension(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension) return extension_.Mutable(index); } - ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { +::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension) return extension_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::extension() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) - return extension_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension) return &extension_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) + return extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; int DescriptorProto::nested_type_size() const { @@ -3780,28 +3780,28 @@ int DescriptorProto::nested_type_size() const { void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } - const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { +const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.nested_type) return nested_type_.Get(index); } - ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) { +::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.nested_type) return nested_type_.Mutable(index); } - ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { +::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type) return nested_type_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -DescriptorProto::nested_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type) - return nested_type_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* DescriptorProto::mutable_nested_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type) return &nested_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type) + return nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; int DescriptorProto::enum_type_size() const { @@ -3810,28 +3810,28 @@ int DescriptorProto::enum_type_size() const { void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } - const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { +const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.enum_type) return enum_type_.Get(index); } - ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) { +::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_type(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.enum_type) return enum_type_.Mutable(index); } - ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { +::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type) return enum_type_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -DescriptorProto::enum_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type) - return enum_type_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* DescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type) return &enum_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; int DescriptorProto::extension_range_size() const { @@ -3840,28 +3840,28 @@ int DescriptorProto::extension_range_size() const { void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } - const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { +const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.extension_range) return extension_range_.Get(index); } - ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) { +::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::mutable_extension_range(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.extension_range) return extension_range_.Mutable(index); } - ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { +::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range) return extension_range_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& -DescriptorProto::extension_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range) - return extension_range_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* DescriptorProto::mutable_extension_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range) return &extension_range_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range) + return extension_range_; +} // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; int DescriptorProto::oneof_decl_size() const { @@ -3870,28 +3870,28 @@ int DescriptorProto::oneof_decl_size() const { void DescriptorProto::clear_oneof_decl() { oneof_decl_.Clear(); } - const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const { +const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.oneof_decl) return oneof_decl_.Get(index); } - ::google::protobuf::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) { +::google::protobuf::OneofDescriptorProto* DescriptorProto::mutable_oneof_decl(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.oneof_decl) return oneof_decl_.Mutable(index); } - ::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() { +::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl) return oneof_decl_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& -DescriptorProto::oneof_decl() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl) - return oneof_decl_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >* DescriptorProto::mutable_oneof_decl() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl) return &oneof_decl_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& +DescriptorProto::oneof_decl() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl) + return oneof_decl_; +} // optional .google.protobuf.MessageOptions options = 7; bool DescriptorProto::has_options() const { @@ -3907,11 +3907,11 @@ void DescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); clear_has_options(); } - const ::google::protobuf::MessageOptions& DescriptorProto::options() const { +const ::google::protobuf::MessageOptions& DescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { +::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::MessageOptions; @@ -3919,13 +3919,13 @@ void DescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options) return options_; } - ::google::protobuf::MessageOptions* DescriptorProto::release_options() { +::google::protobuf::MessageOptions* DescriptorProto::release_options() { clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; return temp; } - void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) { +void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) { delete options_; options_ = options; if (options) { @@ -3943,28 +3943,28 @@ int DescriptorProto::reserved_range_size() const { void DescriptorProto::clear_reserved_range() { reserved_range_.Clear(); } - const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { +const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Get(index); } - ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { +::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Mutable(index); } - ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { +::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& -DescriptorProto::reserved_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) - return reserved_range_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* DescriptorProto::mutable_reserved_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) return &reserved_range_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} // repeated string reserved_name = 10; int DescriptorProto::reserved_name_size() const { @@ -5062,11 +5062,11 @@ void FieldDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); clear_has_options(); } - const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { +const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.FieldDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { +::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::FieldOptions; @@ -5074,13 +5074,13 @@ void FieldDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options) return options_; } - ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { +::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; return temp; } - void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) { +void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) { delete options_; options_ = options; if (options) { @@ -5804,28 +5804,28 @@ int EnumDescriptorProto::value_size() const { void EnumDescriptorProto::clear_value() { value_.Clear(); } - const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { +const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.value) return value_.Get(index); } - ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) { +::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutable_value(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.value) return value_.Mutable(index); } - ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { +::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value) return value_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& -EnumDescriptorProto::value() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) - return value_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* EnumDescriptorProto::mutable_value() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value) return &value_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) + return value_; +} // optional .google.protobuf.EnumOptions options = 3; bool EnumDescriptorProto::has_options() const { @@ -5841,11 +5841,11 @@ void EnumDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); clear_has_options(); } - const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { +const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.EnumDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { +::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::EnumOptions; @@ -5853,13 +5853,13 @@ void EnumDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options) return options_; } - ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { +::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; return temp; } - void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) { +void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) { delete options_; options_ = options; if (options) { @@ -6304,11 +6304,11 @@ void EnumValueDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); clear_has_options(); } - const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const { +const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.EnumValueDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { +::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::EnumValueOptions; @@ -6316,13 +6316,13 @@ void EnumValueDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options) return options_; } - ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { +::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; return temp; } - void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) { +void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) { delete options_; options_ = options; if (options) { @@ -6740,28 +6740,28 @@ int ServiceDescriptorProto::method_size() const { void ServiceDescriptorProto::clear_method() { method_.Clear(); } - const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { +const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.method) return method_.Get(index); } - ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) { +::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutable_method(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.method) return method_.Mutable(index); } - ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { +::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method) return method_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& -ServiceDescriptorProto::method() const { - // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) - return method_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* ServiceDescriptorProto::mutable_method() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method) return &method_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) + return method_; +} // optional .google.protobuf.ServiceOptions options = 3; bool ServiceDescriptorProto::has_options() const { @@ -6777,11 +6777,11 @@ void ServiceDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); clear_has_options(); } - const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const { +const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.ServiceDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { +::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::ServiceOptions; @@ -6789,13 +6789,13 @@ void ServiceDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options) return options_; } - ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { +::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; return temp; } - void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) { +void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) { delete options_; options_ = options; if (options) { @@ -7480,11 +7480,11 @@ void MethodDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); clear_has_options(); } - const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const { +const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const { // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.options) return options_ != NULL ? *options_ : *default_instance_->options_; } - ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { +::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::MethodOptions; @@ -7492,13 +7492,13 @@ void MethodDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options) return options_; } - ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { +::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; return temp; } - void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) { +void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) { delete options_; options_ = options; if (options) { @@ -9025,28 +9025,28 @@ int FileOptions::uninterpreted_option_size() const { void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FileOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FileOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -9568,28 +9568,28 @@ int MessageOptions::uninterpreted_option_size() const { void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.MessageOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.MessageOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MessageOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MessageOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -10298,28 +10298,28 @@ int FieldOptions::uninterpreted_option_size() const { void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.FieldOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.FieldOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FieldOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FieldOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -10721,28 +10721,28 @@ int EnumOptions::uninterpreted_option_size() const { void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.EnumOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11070,28 +11070,28 @@ int EnumValueOptions::uninterpreted_option_size() const { void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.EnumValueOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumValueOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumValueOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11419,28 +11419,28 @@ int ServiceOptions::uninterpreted_option_size() const { void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.ServiceOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -ServiceOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* ServiceOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11768,28 +11768,28 @@ int MethodOptions::uninterpreted_option_size() const { void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { +const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.MethodOptions.uninterpreted_option) return uninterpreted_option_.Get(index); } - ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) { +::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpreted_option(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.MethodOptions.uninterpreted_option) return uninterpreted_option_.Mutable(index); } - ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { +::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option) return uninterpreted_option_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MethodOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option) - return uninterpreted_option_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MethodOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -12710,28 +12710,28 @@ int UninterpretedOption::name_size() const { void UninterpretedOption::clear_name() { name_.Clear(); } - const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { +const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.UninterpretedOption.name) return name_.Get(index); } - ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) { +::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mutable_name(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.UninterpretedOption.name) return name_.Mutable(index); } - ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { +::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name) return name_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& -UninterpretedOption::name() const { - // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) - return name_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* UninterpretedOption::mutable_name() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name) return &name_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) + return name_; +} // optional string identifier_value = 3; bool UninterpretedOption::has_identifier_value() const { @@ -13916,28 +13916,28 @@ int SourceCodeInfo::location_size() const { void SourceCodeInfo::clear_location() { location_.Clear(); } - const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { +const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.SourceCodeInfo.location) return location_.Get(index); } - ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) { +::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::mutable_location(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.SourceCodeInfo.location) return location_.Mutable(index); } - ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() { +::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location() { // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location) return location_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& -SourceCodeInfo::location() const { - // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) - return location_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* SourceCodeInfo::mutable_location() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location) return &location_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) + return location_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 2aa076ae34858..931ff02d61d21 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -38,28 +38,28 @@ void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto( void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); -class FileDescriptorSet; -class FileDescriptorProto; class DescriptorProto; class DescriptorProto_ExtensionRange; class DescriptorProto_ReservedRange; -class FieldDescriptorProto; -class OneofDescriptorProto; class EnumDescriptorProto; +class EnumOptions; class EnumValueDescriptorProto; -class ServiceDescriptorProto; -class MethodDescriptorProto; +class EnumValueOptions; +class FieldDescriptorProto; +class FieldOptions; +class FileDescriptorProto; +class FileDescriptorSet; class FileOptions; class MessageOptions; -class FieldOptions; -class EnumOptions; -class EnumValueOptions; -class ServiceOptions; +class MethodDescriptorProto; class MethodOptions; -class UninterpretedOption; -class UninterpretedOption_NamePart; +class OneofDescriptorProto; +class ServiceDescriptorProto; +class ServiceOptions; class SourceCodeInfo; class SourceCodeInfo_Location; +class UninterpretedOption; +class UninterpretedOption_NamePart; enum FieldDescriptorProto_Type { FieldDescriptorProto_Type_TYPE_DOUBLE = 1, @@ -249,10 +249,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message const ::google::protobuf::FileDescriptorProto& file(int index) const; ::google::protobuf::FileDescriptorProto* mutable_file(int index); ::google::protobuf::FileDescriptorProto* add_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& - file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: @@ -405,10 +405,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag const ::google::protobuf::DescriptorProto& message_type(int index) const; ::google::protobuf::DescriptorProto* mutable_message_type(int index); ::google::protobuf::DescriptorProto* add_message_type(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& - message_type() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; int enum_type_size() const; @@ -417,10 +417,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); ::google::protobuf::EnumDescriptorProto* add_enum_type(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& - enum_type() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; // repeated .google.protobuf.ServiceDescriptorProto service = 6; int service_size() const; @@ -429,10 +429,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag const ::google::protobuf::ServiceDescriptorProto& service(int index) const; ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); ::google::protobuf::ServiceDescriptorProto* add_service(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& - service() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; // repeated .google.protobuf.FieldDescriptorProto extension = 7; int extension_size() const; @@ -441,10 +441,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag const ::google::protobuf::FieldDescriptorProto& extension(int index) const; ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); ::google::protobuf::FieldDescriptorProto* add_extension(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& - extension() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; // optional .google.protobuf.FileOptions options = 8; bool has_options() const; @@ -797,10 +797,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::FieldDescriptorProto& field(int index) const; ::google::protobuf::FieldDescriptorProto* mutable_field(int index); ::google::protobuf::FieldDescriptorProto* add_field(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& - field() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; // repeated .google.protobuf.FieldDescriptorProto extension = 6; int extension_size() const; @@ -809,10 +809,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::FieldDescriptorProto& extension(int index) const; ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); ::google::protobuf::FieldDescriptorProto* add_extension(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& - extension() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; // repeated .google.protobuf.DescriptorProto nested_type = 3; int nested_type_size() const; @@ -821,10 +821,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::DescriptorProto& nested_type(int index) const; ::google::protobuf::DescriptorProto* mutable_nested_type(int index); ::google::protobuf::DescriptorProto* add_nested_type(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& - nested_type() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; int enum_type_size() const; @@ -833,10 +833,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); ::google::protobuf::EnumDescriptorProto* add_enum_type(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& - enum_type() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; int extension_range_size() const; @@ -845,10 +845,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& - extension_range() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; int oneof_decl_size() const; @@ -857,10 +857,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::OneofDescriptorProto& oneof_decl(int index) const; ::google::protobuf::OneofDescriptorProto* mutable_oneof_decl(int index); ::google::protobuf::OneofDescriptorProto* add_oneof_decl(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& - oneof_decl() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >* mutable_oneof_decl(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& + oneof_decl() const; // optional .google.protobuf.MessageOptions options = 7; bool has_options() const; @@ -878,10 +878,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::DescriptorProto_ReservedRange& reserved_range(int index) const; ::google::protobuf::DescriptorProto_ReservedRange* mutable_reserved_range(int index); ::google::protobuf::DescriptorProto_ReservedRange* add_reserved_range(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& - reserved_range() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* mutable_reserved_range(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& + reserved_range() const; // repeated string reserved_name = 10; int reserved_name_size() const; @@ -1361,10 +1361,10 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); ::google::protobuf::EnumValueDescriptorProto* add_value(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& - value() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; // optional .google.protobuf.EnumOptions options = 3; bool has_options() const; @@ -1596,10 +1596,10 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes const ::google::protobuf::MethodDescriptorProto& method(int index) const; ::google::protobuf::MethodDescriptorProto* mutable_method(int index); ::google::protobuf::MethodDescriptorProto* add_method(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& - method() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; // optional .google.protobuf.ServiceOptions options = 3; bool has_options() const; @@ -2014,10 +2014,10 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) @@ -2182,10 +2182,10 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) @@ -2381,10 +2381,10 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) @@ -2508,10 +2508,10 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) @@ -2616,10 +2616,10 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) @@ -2721,10 +2721,10 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) @@ -2826,10 +2826,10 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& - uninterpreted_option() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) @@ -3033,10 +3033,10 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); ::google::protobuf::UninterpretedOption_NamePart* add_name(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& - name() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* mutable_name(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; // optional string identifier_value = 3; bool has_identifier_value() const; @@ -3356,10 +3356,10 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { const ::google::protobuf::SourceCodeInfo_Location& location(int index) const; ::google::protobuf::SourceCodeInfo_Location* mutable_location(int index); ::google::protobuf::SourceCodeInfo_Location* add_location(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& - location() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* mutable_location(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& + location() const; // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo) private: @@ -3402,16 +3402,16 @@ inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorSet.file) return file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -FileDescriptorSet::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) - return file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* FileDescriptorSet::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file) return &file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) + return file_; +} // ------------------------------------------------------------------- @@ -3656,16 +3656,16 @@ inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_typ // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.message_type) return message_type_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -FileDescriptorProto::message_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type) - return message_type_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* FileDescriptorProto::mutable_message_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type) return &message_type_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type) + return message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int FileDescriptorProto::enum_type_size() const { @@ -3686,16 +3686,16 @@ inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_ty // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.enum_type) return enum_type_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -FileDescriptorProto::enum_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type) - return enum_type_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* FileDescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type) return &enum_type_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int FileDescriptorProto::service_size() const { @@ -3716,16 +3716,16 @@ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_serv // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.service) return service_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& -FileDescriptorProto::service() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) - return service_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* FileDescriptorProto::mutable_service() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service) return &service_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) + return service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int FileDescriptorProto::extension_size() const { @@ -3746,16 +3746,16 @@ inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extens // @@protoc_insertion_point(field_add:google.protobuf.FileDescriptorProto.extension) return extension_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -FileDescriptorProto::extension() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) - return extension_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* FileDescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension) return &extension_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) + return extension_; +} // optional .google.protobuf.FileOptions options = 8; inline bool FileDescriptorProto::has_options() const { @@ -4076,16 +4076,16 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.field) return field_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::field() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) - return field_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_field() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field) return &field_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) + return field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int DescriptorProto::extension_size() const { @@ -4106,16 +4106,16 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension( // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension) return extension_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::extension() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) - return extension_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension) return &extension_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) + return extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int DescriptorProto::nested_type_size() const { @@ -4136,16 +4136,16 @@ inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.nested_type) return nested_type_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -DescriptorProto::nested_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type) - return nested_type_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* DescriptorProto::mutable_nested_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type) return &nested_type_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type) + return nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int DescriptorProto::enum_type_size() const { @@ -4166,16 +4166,16 @@ inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.enum_type) return enum_type_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -DescriptorProto::enum_type() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type) - return enum_type_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* DescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type) return &enum_type_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int DescriptorProto::extension_range_size() const { @@ -4196,16 +4196,16 @@ inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_ // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.extension_range) return extension_range_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& -DescriptorProto::extension_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range) - return extension_range_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* DescriptorProto::mutable_extension_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension_range) return &extension_range_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension_range) + return extension_range_; +} // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; inline int DescriptorProto::oneof_decl_size() const { @@ -4226,16 +4226,16 @@ inline ::google::protobuf::OneofDescriptorProto* DescriptorProto::add_oneof_decl // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.oneof_decl) return oneof_decl_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& -DescriptorProto::oneof_decl() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl) - return oneof_decl_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >* DescriptorProto::mutable_oneof_decl() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl) return &oneof_decl_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& +DescriptorProto::oneof_decl() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl) + return oneof_decl_; +} // optional .google.protobuf.MessageOptions options = 7; inline bool DescriptorProto::has_options() const { @@ -4299,16 +4299,16 @@ inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_r // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& -DescriptorProto::reserved_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) - return reserved_range_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* DescriptorProto::mutable_reserved_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) return &reserved_range_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} // repeated string reserved_name = 10; inline int DescriptorProto::reserved_name_size() const { @@ -4854,16 +4854,16 @@ inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_va // @@protoc_insertion_point(field_add:google.protobuf.EnumDescriptorProto.value) return value_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& -EnumDescriptorProto::value() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) - return value_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* EnumDescriptorProto::mutable_value() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value) return &value_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) + return value_; +} // optional .google.protobuf.EnumOptions options = 3; inline bool EnumDescriptorProto::has_options() const { @@ -5108,16 +5108,16 @@ inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_me // @@protoc_insertion_point(field_add:google.protobuf.ServiceDescriptorProto.method) return method_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& -ServiceDescriptorProto::method() const { - // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) - return method_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* ServiceDescriptorProto::mutable_method() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method) return &method_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) + return method_; +} // optional .google.protobuf.ServiceOptions options = 3; inline bool ServiceDescriptorProto::has_options() const { @@ -5945,16 +5945,16 @@ inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_o // @@protoc_insertion_point(field_add:google.protobuf.FileOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FileOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FileOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6075,16 +6075,16 @@ inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterprete // @@protoc_insertion_point(field_add:google.protobuf.MessageOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MessageOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MessageOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6255,16 +6255,16 @@ inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_ // @@protoc_insertion_point(field_add:google.protobuf.FieldOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FieldOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FieldOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6337,16 +6337,16 @@ inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_o // @@protoc_insertion_point(field_add:google.protobuf.EnumOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6395,16 +6395,16 @@ inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpre // @@protoc_insertion_point(field_add:google.protobuf.EnumValueOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumValueOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumValueOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6453,16 +6453,16 @@ inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterprete // @@protoc_insertion_point(field_add:google.protobuf.ServiceOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -ServiceOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* ServiceOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6511,16 +6511,16 @@ inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted // @@protoc_insertion_point(field_add:google.protobuf.MethodOptions.uninterpreted_option) return uninterpreted_option_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MethodOptions::uninterpreted_option() const { - // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option) - return uninterpreted_option_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MethodOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option) return &uninterpreted_option_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option) + return uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -6626,16 +6626,16 @@ inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::ad // @@protoc_insertion_point(field_add:google.protobuf.UninterpretedOption.name) return name_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& -UninterpretedOption::name() const { - // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) - return name_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* UninterpretedOption::mutable_name() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name) return &name_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) + return name_; +} // optional string identifier_value = 3; inline bool UninterpretedOption::has_identifier_value() const { @@ -7115,16 +7115,16 @@ inline ::google::protobuf::SourceCodeInfo_Location* SourceCodeInfo::add_location // @@protoc_insertion_point(field_add:google.protobuf.SourceCodeInfo.location) return location_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& -SourceCodeInfo::location() const { - // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) - return location_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* SourceCodeInfo::mutable_location() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location) return &location_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) + return location_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 9d3dd8fbae43e..8f90a956cf92f 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -42,9 +42,9 @@ syntax = "proto2"; package google.protobuf; option go_package = "descriptor"; option java_package = "com.google.protobuf"; -option javanano_use_deprecated_package = true; option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; +// Re-enable this once the tools have picked up the csharp_namespace option. +// option csharp_namespace = "Google.ProtocolBuffers.DescriptorProtos"; option objc_class_prefix = "GPB"; // descriptor.proto must be optimized for speed because reflection-based @@ -301,10 +301,12 @@ message FileOptions { // If set true, then the Java code generator will generate equals() and // hashCode() methods for all messages defined in the .proto file. - // - In the full runtime, this is purely a speed optimization, as the + // This increases generated code size, potentially substantially for large + // protos, which may harm a memory-constrained application. + // - In the full runtime this is a speed optimization, as the // AbstractMessage base class includes reflection-based implementations of // these methods. - //- In the lite runtime, setting this option changes the semantics of + // - In the lite runtime, setting this option changes the semantics of // equals() and hashCode() to more closely match those of the full runtime; // the generated methods compute their results based on field values rather // than object identity. (Implementations should not assume that hashcodes @@ -525,6 +527,7 @@ message FieldOptions { // For Google-internal migration only. Do not use. optional bool weak = 10 [default=false]; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index 1c03c4438efde..a87fa04915e60 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -42,7 +42,9 @@ #include #include +#include #include +#include #include #include diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 760df097e67b8..e9b027dbb6bee 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -49,6 +49,8 @@ #include #include +#include +#include #include #include @@ -368,6 +370,37 @@ TEST_F(FileDescriptorTest, BuildAgain) { EXPECT_TRUE(pool_.BuildFile(file) == NULL); } +TEST_F(FileDescriptorTest, BuildAgainWithSyntax) { + // Test that if te call BuildFile again on the same input we get the same + // FileDescriptor back even if syntax param is specified. + FileDescriptorProto proto_syntax2; + proto_syntax2.set_name("foo_syntax2"); + proto_syntax2.set_syntax("proto2"); + + const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2); + EXPECT_TRUE(proto2_descriptor != NULL); + EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2)); + + FileDescriptorProto implicit_proto2; + implicit_proto2.set_name("foo_implicit_syntax2"); + + const FileDescriptor* implicit_proto2_descriptor = + pool_.BuildFile(implicit_proto2); + EXPECT_TRUE(implicit_proto2_descriptor != NULL); + // We get the same FileDescriptor back if syntax param is explicitly + // specified. + implicit_proto2.set_syntax("proto2"); + EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2)); + + FileDescriptorProto proto_syntax3; + proto_syntax3.set_name("foo_syntax3"); + proto_syntax3.set_syntax("proto3"); + + const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3); + EXPECT_TRUE(proto3_descriptor != NULL); + EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3)); +} + TEST_F(FileDescriptorTest, Syntax) { FileDescriptorProto proto; proto.set_name("foo"); @@ -3583,7 +3616,7 @@ TEST_F(ValidationErrorTest, FieldOneofIndexNegative) { TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { // Fields belonging to the same oneof must be defined consecutively. - BuildFileWithWarnings( + BuildFileWithErrors( "name: \"foo.proto\" " "message_type {" " name: \"Foo\"" @@ -3600,7 +3633,7 @@ TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { "\"foos\" oneof definition.\n"); // Prevent interleaved fields, which belong to different oneofs. - BuildFileWithWarnings( + BuildFileWithErrors( "name: \"foo2.proto\" " "message_type {" " name: \"Foo2\"" @@ -3621,6 +3654,25 @@ TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined " "consecutively. \"foo2\" cannot be defined before the completion of the " "\"bars\" oneof definition.\n"); + + // Another case for normal fields and different oneof fields interleave. + BuildFileWithErrors( + "name: \"foo3.proto\" " + "message_type {" + " name: \"Foo3\"" + " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 1 }" + " field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " oneof_decl { name:\"foos\" }" + " oneof_decl { name:\"bars\" }" + "}", + "foo3.proto: Foo3.baz: OTHER: Fields in the same oneof must be defined " + "consecutively. \"baz\" cannot be defined before the completion of the " + "\"foos\" oneof definition.\n"); } TEST_F(ValidationErrorTest, FieldNumberConflict) { @@ -5369,6 +5421,35 @@ TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) { "with an existing oneof type.\n"); } +TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "enum_type {" + " name: \"Bar\"" + " value { name:\"ENUM_A\" number:1 }" + " value { name:\"ENUM_B\" number:2 }" + "}" + "message_type {" + " name: 'Foo' " + " field { " + " name: 'foo_map' number: 1 label:LABEL_REPEATED " + " type_name: 'FooMapEntry' " + " } " + " nested_type { " + " name: 'FooMapEntry' " + " options { map_entry: true } " + " field { " + " name: 'key' number: 1 type:TYPE_INT32 label:LABEL_OPTIONAL " + " } " + " field { " + " name: 'value' number: 2 type_name:\"Bar\" label:LABEL_OPTIONAL " + " } " + " } " + "}", + "foo.proto: Foo.foo_map: " + "TYPE: Enum value in map must define 0 as the first value.\n"); +} + TEST_F(ValidationErrorTest, Proto3RequiredFields) { BuildFileWithErrors( "name: 'foo.proto' " diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 318ce6f9fb6a8..2324d9525d680 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -65,6 +65,7 @@ #include #include +#include #include #include @@ -79,6 +80,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -87,7 +89,7 @@ using internal::WireFormat; using internal::ExtensionSet; using internal::GeneratedMessageReflection; using internal::MapField; -using internal::MapFieldBase; +using internal::DynamicMapField; using internal::ArenaStringPtr; @@ -116,7 +118,7 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_ENUM : return sizeof(RepeatedField); case FD::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - return sizeof(MapFieldBase); + return sizeof(DynamicMapField); } else { return sizeof(RepeatedPtrField); } @@ -389,7 +391,8 @@ void DynamicMessage::SharedCtor() { new(field_ptr) Message*(NULL); } else { if (IsMapFieldInApi(field)) { - new (field_ptr) MapFieldBase(); + new (field_ptr) DynamicMapField( + type_info_->factory->GetPrototypeNoLock(field->message_type())); } else { new (field_ptr) RepeatedPtrField(); } @@ -437,8 +440,8 @@ DynamicMessage::~DynamicMessage() { &(reinterpret_cast( type_info_->prototype->OffsetToPointer( type_info_->offsets[i]))->Get(NULL)); - reinterpret_cast(field_ptr)->Destroy(default_value, - NULL); + reinterpret_cast(field_ptr)->Destroy( + default_value, NULL); break; } } @@ -480,7 +483,7 @@ DynamicMessage::~DynamicMessage() { case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - reinterpret_cast(field_ptr)->~MapFieldBase(); + reinterpret_cast(field_ptr)->~DynamicMapField(); } else { reinterpret_cast*>(field_ptr) ->~RepeatedPtrField(); @@ -496,8 +499,8 @@ DynamicMessage::~DynamicMessage() { &(reinterpret_cast( type_info_->prototype->OffsetToPointer( type_info_->offsets[i]))->Get(NULL)); - reinterpret_cast(field_ptr)->Destroy(default_value, - NULL); + reinterpret_cast(field_ptr)->Destroy( + default_value, NULL); break; } } @@ -723,8 +726,14 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( // Allocate the prototype. void* base = operator new(size); memset(base, 0, size); + // The prototype in type_info has to be set before creating the prototype + // instance on memory. e.g., message Foo { map a = 1; }. When + // creating prototype for Foo, prototype of the map entry will also be + // created, which needs the address of the prototype of Foo (the value in + // map). To break the cyclic dependency, we have to assgin the address of + // prototype into type_info first. + type_info->prototype = static_cast(base); DynamicMessage* prototype = new(base) DynamicMessage(type_info); - type_info->prototype = prototype; // Construct the reflection object. if (type->oneof_decl_count() > 0) { diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index b5928a5260e63..f74cd7dd25154 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -45,6 +45,7 @@ #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index 522a092aa82d7..b9796c764ff5a 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -40,6 +40,7 @@ // reflection_ops_unittest, cover the rest of the functionality used by // DynamicMessage. +#include #include #include #include @@ -48,6 +49,7 @@ #include #include +#include #include #include diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index c371e011e7de3..9ef4e27d10a25 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -45,6 +45,7 @@ #include +#include #include @@ -330,6 +331,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& prototype, desc); MessageLite* AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory); + void AddAllocatedMessage(const FieldDescriptor* descriptor, + MessageLite* new_entry); #undef desc void RemoveLast(int number); @@ -578,6 +581,10 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, Extension** result); + // Gets the repeated extension for the given descriptor, creating it if + // it does not exist. + Extension* MaybeNewRepeatedExtension(const FieldDescriptor* descriptor); + // Parse a single MessageSet item -- called just after the item group start // tag has been read. bool ParseMessageSetItem(io::CodedInputStream* input, diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 330bd8287daae..82e3e099631ab 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -213,8 +213,7 @@ MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, } } -MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, - MessageFactory* factory) { +ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) { Extension* extension; if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { extension->type = descriptor->type(); @@ -225,6 +224,12 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } + return extension; +} + +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, + MessageFactory* factory) { + Extension* extension = MaybeNewRepeatedExtension(descriptor); // RepeatedPtrField does not know how to Add() since it cannot // allocate an abstract object, so we have to be tricky. @@ -244,6 +249,13 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, return result; } +void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor, + MessageLite* new_entry) { + Extension* extension = MaybeNewRepeatedExtension(descriptor); + + extension->repeated_message_value->AddAllocated(new_entry); +} + static bool ValidateEnumUsingDescriptor(const void* arg, int number) { return reinterpret_cast(arg) ->FindValueByNumber(number) != NULL; diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 684ce002553f2..1569120d15513 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -173,7 +174,7 @@ TEST(ExtensionSetTest, SetAllocatedExtension) { } TEST(ExtensionSetTest, ReleaseExtension) { - unittest::TestMessageSet message; + proto2_wireformat_unittest::TestMessageSet message; EXPECT_FALSE(message.HasExtension( unittest::TestMessageSetExtension1::message_set_extension)); // Add a extension using SetAllocatedExtension diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 412c48a1e664f..b9957e7517e97 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -818,7 +819,16 @@ void GeneratedMessageReflection::ClearField( } case FieldDescriptor::CPPTYPE_MESSAGE: - (*MutableRaw(message, field))->Clear(); + if (has_bits_offset_ == -1) { + // Proto3 does not have has-bits and we need to set a message field + // to NULL in order to indicate its un-presence. + if (GetArena(message) == NULL) { + delete *MutableRaw(message, field); + } + *MutableRaw(message, field) = NULL; + } else { + (*MutableRaw(message, field))->Clear(); + } break; } } @@ -1649,6 +1659,25 @@ Message* GeneratedMessageReflection::AddMessage( } } +void GeneratedMessageReflection::AddAllocatedMessage( + Message* message, const FieldDescriptor* field, + Message* new_entry) const { + USAGE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE); + + if (field->is_extension()) { + MutableExtensionSet(message)->AddAllocatedMessage(field, new_entry); + } else { + RepeatedPtrFieldBase* repeated = NULL; + if (IsMapFieldInApi(field)) { + repeated = + MutableRaw(message, field)->MutableRepeatedField(); + } else { + repeated = MutableRaw(message, field); + } + repeated->AddAllocated >(new_entry); + } +} + void* GeneratedMessageReflection::MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpptype, @@ -1675,6 +1704,37 @@ void* GeneratedMessageReflection::MutableRawRepeatedField( } } +const void* GeneratedMessageReflection::GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType cpptype, + int ctype, const Descriptor* desc) const { + USAGE_CHECK_REPEATED("GetRawRepeatedField"); + if (field->cpp_type() != cpptype) + ReportReflectionUsageTypeError(descriptor_, + field, "GetRawRepeatedField", cpptype); + if (ctype >= 0) + GOOGLE_CHECK_EQ(field->options().ctype(), ctype) << "subtype mismatch"; + if (desc != NULL) + GOOGLE_CHECK_EQ(field->message_type(), desc) << "wrong submessage type"; + if (field->is_extension()) { + // Should use extension_set::GetRawRepeatedField. However, the required + // parameter "default repeated value" is not very easy to get here. + // Map is not supported in extensions, it is acceptable to use + // extension_set::MutableRawRepeatedField which does not change the message. + return MutableExtensionSet(const_cast(&message)) + ->MutableRawRepeatedField( + field->number(), field->type(), field->is_packed(), field); + } else { + // Trigger transform for MapField + if (IsMapFieldInApi(field)) { + return &(reinterpret_cast( + reinterpret_cast(&message) + + offsets_[field->index()])->GetRepeatedField()); + } + return reinterpret_cast(&message) + offsets_[field->index()]; + } +} + const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor( const Message& message, const OneofDescriptor* oneof_descriptor) const { @@ -1685,6 +1745,69 @@ const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor( return descriptor_->FindFieldByNumber(field_number); } +bool GeneratedMessageReflection::ContainsMapKey( + const Message& message, + const FieldDescriptor* field, + const MapKey& key) const { + USAGE_CHECK(IsMapFieldInApi(field), + "LookupMapValue", + "Field is not a map field."); + return GetRaw(message, field).ContainsMapKey(key); +} + +bool GeneratedMessageReflection::InsertOrLookupMapValue( + Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const { + USAGE_CHECK(IsMapFieldInApi(field), + "InsertOrLookupMapValue", + "Field is not a map field."); + val->SetType(field->message_type()->FindFieldByName("value")->cpp_type()); + return MutableRaw(message, field)->InsertMapValue(key, val); +} + +bool GeneratedMessageReflection::DeleteMapValue( + Message* message, + const FieldDescriptor* field, + const MapKey& key) const { + USAGE_CHECK(IsMapFieldInApi(field), + "DeleteMapValue", + "Field is not a map field."); + return MutableRaw(message, field)->DeleteMapValue(key); +} + +MapIterator GeneratedMessageReflection::MapBegin( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapBegin", + "Field is not a map field."); + MapIterator iter(message, field); + GetRaw(*message, field).MapBegin(&iter); + return iter; +} + +MapIterator GeneratedMessageReflection::MapEnd( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapEnd", + "Field is not a map field."); + MapIterator iter(message, field); + GetRaw(*message, field).MapEnd(&iter); + return iter; +} + +int GeneratedMessageReflection::MapSize( + const Message& message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapSize", + "Field is not a map field."); + return GetRaw(message, field).size(); +} + // ----------------------------------------------------------------------------- const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName( @@ -2098,6 +2221,14 @@ void* GeneratedMessageReflection::RepeatedFieldData( } } +MapFieldBase* GeneratedMessageReflection::MapData( + Message* message, const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "GetMapData", + "Field is not a map field."); + return MutableRaw(message, field); +} + GeneratedMessageReflection* GeneratedMessageReflection::NewGeneratedMessageReflection( const Descriptor* descriptor, diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index dc8abb98a031f..85ce6e2eec262 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -58,7 +58,9 @@ class GMR_Handlers; } // namespace upb namespace protobuf { - class DescriptorPool; +class DescriptorPool; +class MapKey; +class MapValueRef; } namespace protobuf { @@ -261,6 +263,25 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const Message& message, const OneofDescriptor* oneof_descriptor) const; + private: + bool ContainsMapKey(const Message& message, + const FieldDescriptor* field, + const MapKey& key) const; + bool InsertOrLookupMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const; + bool DeleteMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key) const; + MapIterator MapBegin( + Message* message, + const FieldDescriptor* field) const; + MapIterator MapEnd( + Message* message, + const FieldDescriptor* field) const; + int MapSize(const Message& message, const FieldDescriptor* field) const; + public: void SetInt32 (Message* message, const FieldDescriptor* field, int32 value) const; @@ -371,6 +392,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int value) const; Message* AddMessage(Message* message, const FieldDescriptor* field, MessageFactory* factory = NULL) const; + void AddAllocatedMessage( + Message* message, const FieldDescriptor* field, + Message* new_entry) const; const FieldDescriptor* FindKnownExtensionByName(const string& name) const; const FieldDescriptor* FindKnownExtensionByNumber(int number) const; @@ -391,9 +415,14 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { static const int kUnknownFieldSetInMetadata = -1; protected: - virtual void* MutableRawRepeatedField( + void* MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, - int ctype, const Descriptor* desc) const; + int ctype, const Descriptor* desc) const override; + + const void* GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType, int ctype, + const Descriptor* desc) const override; virtual MessageFactory* GetMessageFactory() const; @@ -407,7 +436,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { // To parse directly into a proto2 generated class, the class GMR_Handlers // needs access to member offsets and hasbits. - friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers; + friend class upb::google_opensource::GMR_Handlers; const Descriptor* descriptor_; const Message* default_instance_; @@ -539,6 +568,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { Message* sub_message, const FieldDescriptor* field) const; + internal::MapFieldBase* MapData( + Message* message, const FieldDescriptor* field) const; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection); }; diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc index ca1a2918bb5e0..df043844818c0 100644 --- a/src/google/protobuf/generated_message_reflection_unittest.cc +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -546,6 +547,57 @@ TEST(GeneratedMessageReflectionTest, SetAllocatedExtensionMessageTest) { &to_message, TestUtil::ReflectionTester::IS_NULL); } +TEST(GeneratedMessageReflectionTest, AddRepeatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + const Reflection* nested_reflection = + unittest::TestAllTypes::NestedMessage::default_instance().GetReflection(); + + const FieldDescriptor* nested_bb = + unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName( + "bb"); + + Message* nested = reflection->AddMessage( + &message, F("repeated_nested_message")); + nested_reflection->SetInt32(nested, nested_bb, 11); + + EXPECT_EQ(11, message.repeated_nested_message(0).bb()); +} + +TEST(GeneratedMessageReflectionTest, MutableRepeatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + const Reflection* nested_reflection = + unittest::TestAllTypes::NestedMessage::default_instance().GetReflection(); + + const FieldDescriptor* nested_bb = + unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName( + "bb"); + + message.add_repeated_nested_message()->set_bb(12); + + Message* nested = reflection->MutableRepeatedMessage( + &message, F("repeated_nested_message"), 0); + EXPECT_EQ(12, nested_reflection->GetInt32(*nested, nested_bb)); + nested_reflection->SetInt32(nested, nested_bb, 13); + EXPECT_EQ(13, message.repeated_nested_message(0).bb()); +} + +TEST(GeneratedMessageReflectionTest, AddAllocatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + + unittest::TestAllTypes::NestedMessage* nested = + new unittest::TestAllTypes::NestedMessage(); + nested->set_bb(11); + reflection->AddAllocatedMessage(&message, F("repeated_nested_message"), nested); + EXPECT_EQ(1, message.repeated_nested_message_size()); + EXPECT_EQ(11, message.repeated_nested_message(0).bb()); +} + TEST(GeneratedMessageReflectionTest, ListFieldsOneOf) { unittest::TestOneof2 message; TestUtil::SetOneof1(&message); diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 3b8650d627c33..4bcd354fe6de4 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -338,9 +339,9 @@ namespace { // The first part of the pair is true iff the read was successful. The second // part is buffer + (number of bytes read). This function is always inlined, // so returning a pair is costless. -inline ::std::pair ReadVarint32FromArray( +GOOGLE_ATTRIBUTE_ALWAYS_INLINE ::std::pair ReadVarint32FromArray( uint32 first_byte, const uint8* buffer, - uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + uint32* value); inline ::std::pair ReadVarint32FromArray( uint32 first_byte, const uint8* buffer, uint32* value) { // Fast path: We have enough bytes left in the buffer to guarantee that diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index ad351dc3aeaf4..361c406b5b68c 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -191,16 +191,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Like GetDirectBufferPointer, but this method is inlined, and does not // attempt to Refresh() if the buffer is currently empty. - inline void GetDirectBufferPointerInline(const void** data, - int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void GetDirectBufferPointerInline(const void** data, + int* size); // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); // Like the above, with inlined optimizations. This should only be used // by the protobuf implementation. - inline bool InternalReadRawInline(void* buffer, - int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadRawInline(void* buffer, int size); // Like ReadRaw, but reads into a string. // @@ -212,8 +211,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream { bool ReadString(string* buffer, int size); // Like the above, with inlined optimizations. This should only be used // by the protobuf implementation. - inline bool InternalReadStringInline(string* buffer, - int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadStringInline(string* buffer, + int size); // Read a 32-bit little-endian integer. @@ -243,7 +242,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Always inline because this is only called in one place per parse loop // but it is called for every iteration of said loop, so it should be fast. // GCC doesn't want to inline this by default. - uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTag(); // This usually a faster alternative to ReadTag() when cutoff is a manifest // constant. It does particularly well for cutoff >= 127. The first part @@ -253,8 +252,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // above cutoff or is 0. (There's intentional wiggle room when tag is 0, // because that can arise in several ways, and for best performance we want // to avoid an extra "is tag == 0?" check here.) - inline std::pair ReadTagWithCutoff(uint32 cutoff) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE std::pair ReadTagWithCutoff( + uint32 cutoff); // Usually returns true if calling ReadVarint32() now would produce the given // value. Will always return false if ReadVarint32() would not return the @@ -263,7 +262,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // parameter. // Always inline because this collapses to a small number of instructions // when given a constant parameter, but GCC doesn't want to inline by default. - bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool ExpectTag(uint32 expected); // Like above, except this reads from the specified buffer. The caller is // responsible for ensuring that the buffer is large enough to read a varint @@ -272,9 +271,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // // Returns a pointer beyond the expected tag if it was found, or NULL if it // was not. - static const uint8* ExpectTagFromArray( + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static const uint8* ExpectTagFromArray( const uint8* buffer, - uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + uint32 expected); // Usually returns true if no more bytes can be read. Always returns false // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent @@ -766,8 +765,8 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // but GCC by default doesn't want to inline this. void WriteTag(uint32 value); // Like WriteTag() but writing directly to the target array. - static uint8* WriteTagToArray( - uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteTagToArray(uint32 value, + uint8* target); // Returns the number of bytes needed to encode the given value as a varint. static int VarintSize32(uint32 value); @@ -831,8 +830,8 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already // out-of-line, so it should just invoke this directly to avoid any extra // function call overhead. - static uint8* WriteVarint64ToArrayInline( - uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target); static int VarintSize32Fallback(uint32 value); }; diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h index fa20f208862a3..d95b06e04e531 100644 --- a/src/google/protobuf/io/coded_stream_inl.h +++ b/src/google/protobuf/io/coded_stream_inl.h @@ -36,6 +36,7 @@ #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ #define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ +#include #include #include #include diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 02d5bad3b5990..630c908690353 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -41,6 +41,8 @@ #include #include +#include +#include #include #include #include diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc index dd7c036e30e2c..1be6c86359524 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -33,10 +33,12 @@ // This file contains the implementation of classes GzipInputStream and // GzipOutputStream. + #if HAVE_ZLIB #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 3ae8c26831651..7d886506265fc 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -34,6 +34,7 @@ #include #include +#include #include namespace google { diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 1331a8d99602c..258dd9861f7d2 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc index 56973439d953e..579de9aa795e5 100644 --- a/src/google/protobuf/io/strtod.cc +++ b/src/google/protobuf/io/strtod.cc @@ -34,6 +34,7 @@ #include #include +#include #include namespace google { diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 60bd7957d4a17..7ccd633da2b38 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -90,6 +90,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 98576f56cb6b1..49885eda9c6d0 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -40,6 +40,7 @@ #include #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index de096fb9d82a4..6526056a3ea4b 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -41,6 +41,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/io/zero_copy_stream.cc b/src/google/protobuf/io/zero_copy_stream.cc index f77c768fc990c..186de00141d54 100644 --- a/src/google/protobuf/io/zero_copy_stream.cc +++ b/src/google/protobuf/io/zero_copy_stream.cc @@ -34,6 +34,7 @@ #include +#include #include namespace google { diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc index f7901b2797eb1..7ec2b5da5cb9d 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl.cc @@ -46,6 +46,7 @@ #include #include +#include #include diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 97b73b88e7791..686e63f2528a3 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -39,6 +39,7 @@ #include #include +#include #include namespace google { diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index 4360b18f5e918..9cdf03785428b 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -48,6 +48,7 @@ #include #include #include +#include #include diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index f2e5b629dfcf3..3850e76c40740 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -46,6 +46,7 @@ // "parametized tests" so that one set of tests can be used on all the // implementations. + #ifdef _MSC_VER #include #else @@ -66,6 +67,8 @@ #endif #include +#include +#include #include #include #include diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index 5af8b24deeb7d..d1948ab5cc3d4 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -376,13 +377,6 @@ int main(int argc, char* argv[]) { google::protobuf::MapLiteTestUtil::ExpectMapFieldsSetInitialized(message); } - { - // Proto2SetMapFieldsInitialized - protobuf_unittest::TestEnumStartWithNonZeroMapLite message; - EXPECT_EQ(protobuf_unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE, - (*message.mutable_map_field())[0]); - } - { // Clear protobuf_unittest::TestMapLite message; @@ -692,37 +686,6 @@ int main(int argc, char* argv[]) { EXPECT_TRUE(map_message.IsInitialized()); } - // arena support for map ========================================= - - { - // ParsingAndSerializingNoHeapAllocation - - // Allocate a large initial block to avoid mallocs during hooked test. - std::vector arena_block(128 * 1024); - google::protobuf::ArenaOptions options; - options.initial_block = &arena_block[0]; - options.initial_block_size = arena_block.size(); - google::protobuf::Arena arena(options); - string data; - data.reserve(128 * 1024); - - { - google::protobuf::internal::NoHeapChecker no_heap; - - protobuf_unittest::TestArenaMapLite* from = - google::protobuf::Arena::CreateMessage( - &arena); - google::protobuf::MapLiteTestUtil::SetArenaMapFields(from); - from->SerializeToString(&data); - - protobuf_unittest::TestArenaMapLite* to = - google::protobuf::Arena::CreateMessage( - &arena); - to->ParseFromString(data); - google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to); - } - } - std::cout << "PASS" << std::endl; return 0; } diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index d928b7a7593c2..c43df13ed7cde 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -35,9 +35,12 @@ #include #include // To support Visual Studio 2008 +#include #include #include #include +#include +#include namespace google { namespace protobuf { @@ -47,13 +50,379 @@ class Map; template struct is_proto_enum; +class MapIterator; + namespace internal { template class MapFieldLite; -} + +template +class MapField; + +template +class TypeDefinedMapFieldBase; + +class DynamicMapField; + +class GeneratedMessageReflection; +} // namespace internal + +#define TYPE_CHECK(EXPECTEDTYPE, METHOD) \ + if (type() != EXPECTEDTYPE) { \ + GOOGLE_LOG(FATAL) \ + << "Protocol Buffer map usage error:\n" \ + << METHOD << " type does not match\n" \ + << " Expected : " \ + << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n" \ + << " Actual : " \ + << FieldDescriptor::CppTypeName(type()); \ + } + +// MapKey is an union type for representing any possible +// map key. +class LIBPROTOBUF_EXPORT MapKey { + public: + MapKey() : type_(0) { + } + MapKey(const MapKey& other) : type_(0) { + CopyFrom(other); + } + + ~MapKey() { + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + delete val_.string_value_; + } + } + + FieldDescriptor::CppType type() const { + if (type_ == 0) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer map usage error:\n" + << "MapKey::type MapKey is not initialized. " + << "Call set methods to initialize MapKey."; + } + return (FieldDescriptor::CppType)type_; + } + + void SetInt64Value(int64 value) { + SetType(FieldDescriptor::CPPTYPE_INT64); + val_.int64_value_ = value; + } + void SetUInt64Value(uint64 value) { + SetType(FieldDescriptor::CPPTYPE_UINT64); + val_.uint64_value_ = value; + } + void SetInt32Value(int32 value) { + SetType(FieldDescriptor::CPPTYPE_INT32); + val_.int32_value_ = value; + } + void SetUInt32Value(uint32 value) { + SetType(FieldDescriptor::CPPTYPE_UINT32); + val_.uint32_value_ = value; + } + void SetBoolValue(bool value) { + SetType(FieldDescriptor::CPPTYPE_BOOL); + val_.bool_value_ = value; + } + void SetStringValue(const string& val) { + SetType(FieldDescriptor::CPPTYPE_STRING); + *val_.string_value_ = val; + } + + int64 GetInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapKey::GetInt64Value"); + return val_.int64_value_; + } + uint64 GetUInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapKey::GetUInt64Value"); + return val_.uint64_value_; + } + int32 GetInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapKey::GetInt32Value"); + return val_.int32_value_; + } + uint32 GetUInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapKey::GetUInt32Value"); + return val_.uint32_value_; + } + int32 GetBoolValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapKey::GetBoolValue"); + return val_.bool_value_; + } + const string& GetStringValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapKey::GetStringValue"); + return *val_.string_value_; + } + + bool operator==(const MapKey& other) const { + if (type_ != other.type_) { + return false; + } + switch (type()) { + case FieldDescriptor::CPPTYPE_STRING: + return *val_.string_value_ == *other.val_.string_value_; + case FieldDescriptor::CPPTYPE_INT64: + return val_.int64_value_ == other.val_.int64_value_; + case FieldDescriptor::CPPTYPE_INT32: + return val_.int32_value_ == other.val_.int32_value_; + case FieldDescriptor::CPPTYPE_UINT64: + return val_.uint64_value_ == other.val_.uint64_value_; + case FieldDescriptor::CPPTYPE_UINT32: + return val_.uint32_value_ == other.val_.uint32_value_; + case FieldDescriptor::CPPTYPE_BOOL: + return val_.bool_value_ == other.val_.bool_value_; + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; + } + } + + void CopyFrom(const MapKey& other) { + SetType(other.type()); + switch (type_) { + case FieldDescriptor::CPPTYPE_STRING: + *val_.string_value_ = *other.val_.string_value_; + break; + case FieldDescriptor::CPPTYPE_INT64: + val_.int64_value_ = other.val_.int64_value_; + break; + case FieldDescriptor::CPPTYPE_INT32: + val_.int32_value_ = other.val_.int32_value_; + break; + case FieldDescriptor::CPPTYPE_UINT64: + val_.uint64_value_ = other.val_.uint64_value_; + break; + case FieldDescriptor::CPPTYPE_UINT32: + val_.uint32_value_ = other.val_.uint32_value_; + break; + case FieldDescriptor::CPPTYPE_BOOL: + val_.bool_value_ = other.val_.bool_value_; + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + } + + private: + template + friend class internal::TypeDefinedMapFieldBase; + friend class MapIterator; + friend class internal::DynamicMapField; + + union KeyValue { + KeyValue() {} + string* string_value_; + int64 int64_value_; + int32 int32_value_; + uint64 uint64_value_; + uint32 uint32_value_; + bool bool_value_; + } val_; + + void SetType(FieldDescriptor::CppType type) { + if (type_ == type) return; + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + delete val_.string_value_; + } + type_ = type; + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + val_.string_value_ = new string; + } + } + + // type_ is 0 or a valid FieldDescriptor::CppType. + int type_; +}; + +// MapValueRef points to a map value. +class LIBPROTOBUF_EXPORT MapValueRef { + public: + MapValueRef() : data_(NULL), type_(0) {} + + void SetInt64Value(int64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapValueRef::SetInt64Value"); + *reinterpret_cast(data_) = value; + } + void SetUInt64Value(uint64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapValueRef::SetUInt64Value"); + *reinterpret_cast(data_) = value; + } + void SetInt32Value(int32 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapValueRef::SetInt32Value"); + *reinterpret_cast(data_) = value; + } + void SetUInt32Value(uint64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapValueRef::SetUInt32Value"); + *reinterpret_cast(data_) = value; + } + void SetBoolValue(bool value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapValueRef::SetBoolValue"); + *reinterpret_cast(data_) = value; + } + // TODO(jieluo) - Checks that enum is member. + void SetEnumValue(int value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, + "MapValueRef::SetEnumValue"); + *reinterpret_cast(data_) = value; + } + void SetStringValue(const string& value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapValueRef::SetStringValue"); + *reinterpret_cast(data_) = value; + } + void SetFloatValue(float value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, + "MapValueRef::SetFloatValue"); + *reinterpret_cast(data_) = value; + } + void SetDoubleValue(double value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, + "MapValueRef::SetDoubleValue"); + *reinterpret_cast(data_) = value; + } + + int64 GetInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapValueRef::GetInt64Value"); + return *reinterpret_cast(data_); + } + uint64 GetUInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapValueRef::GetUInt64Value"); + return *reinterpret_cast(data_); + } + int32 GetInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapValueRef::GetInt32Value"); + return *reinterpret_cast(data_); + } + uint32 GetUInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapValueRef::GetUInt32Value"); + return *reinterpret_cast(data_); + } + bool GetBoolValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapValueRef::GetBoolValue"); + return *reinterpret_cast(data_); + } + int GetEnumValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, + "MapValueRef::GetEnumValue"); + return *reinterpret_cast(data_); + } + const string& GetStringValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapValueRef::GetStringValue"); + return *reinterpret_cast(data_); + } + float GetFloatValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, + "MapValueRef::GetFloatValue"); + return *reinterpret_cast(data_); + } + double GetDoubleValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, + "MapValueRef::GetDoubleValue"); + return *reinterpret_cast(data_); + } + + const Message& GetMessageValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, + "MapValueRef::GetMessageValue"); + return *reinterpret_cast(data_); + } + + Message* MutableMessageValue() { + TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, + "MapValueRef::MutableMessageValue"); + return reinterpret_cast(data_); + } + + private: + template + friend class internal::MapField; + template + friend class internal::TypeDefinedMapFieldBase; + friend class MapIterator; + friend class internal::GeneratedMessageReflection; + friend class internal::DynamicMapField; + + void SetType(FieldDescriptor::CppType type) { + type_ = type; + } + + FieldDescriptor::CppType type() const { + if (type_ == 0 || data_ == NULL) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer map usage error:\n" + << "MapValueRef::type MapValueRef is not initialized."; + } + return (FieldDescriptor::CppType)type_; + } + void SetValue(const void* val) { + data_ = const_cast(val); + } + void CopyFrom(const MapValueRef& other) { + type_ = other.type_; + data_ = other.data_; + } + // Only used in DynamicMapField + void DeleteData() { + switch (type_) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + delete reinterpret_cast(data_); \ + break; \ + } + HANDLE_TYPE(INT32, int32); + HANDLE_TYPE(INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE(FLOAT, float); + HANDLE_TYPE(BOOL, bool); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); + HANDLE_TYPE(MESSAGE, Message); +#undef HANDLE_TYPE + } + } + // data_ point to a map value. MapValueRef does not + // own this value. + void* data_; + // type_ is 0 or a valid FieldDescriptor::CppType. + int type_; +}; + +#undef TYPE_CHECK // This is the class for google::protobuf::Map's internal value_type. Instead of using // std::pair as value_type, we use this class which provides us more control of @@ -82,7 +451,6 @@ class MapPair { T second; private: - typedef void DestructorSkippable_; friend class ::google::protobuf::Arena; friend class Map; }; @@ -92,9 +460,6 @@ class MapPair { // interface directly to visit or change map fields. template class Map { - typedef internal::MapCppTypeHandler KeyTypeHandler; - typedef internal::MapCppTypeHandler ValueTypeHandler; - public: typedef Key key_type; typedef T mapped_type; @@ -118,7 +483,9 @@ class Map { : arena_(arena), allocator_(arena_), elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) {} + default_enum_value_(0) { + arena_->OwnDestructor(&elements_); + } Map(const Map& other) : arena_(NULL), @@ -127,6 +494,14 @@ class Map { default_enum_value_(other.default_enum_value_) { insert(other.begin(), other.end()); } + template + explicit Map(const InputIt& first, const InputIt& last) + : arena_(NULL), + allocator_(arena_), + elements_(0, hasher(), key_equal(), allocator_), + default_enum_value_(0) { + insert(first, last); + } ~Map() { clear(); } @@ -172,7 +547,7 @@ class Map { !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) template void construct(NodeType* p, Args&&... args) { - new ((void*)p) NodeType(std::forward(args)...); + new (static_cast(p)) NodeType(std::forward(args)...); } template @@ -206,6 +581,7 @@ class Map { } private: + typedef void DestructorSkippable_; Arena* arena_; template @@ -216,7 +592,7 @@ class Map { typedef MapAllocator*> > Allocator; // Iterators - class const_iterator + class LIBPROTOBUF_EXPORT const_iterator : public std::iterator { typedef typename hash_map, equal_to, @@ -449,6 +825,35 @@ class Map { }; } // namespace protobuf - } // namespace google + +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START +template<> +struct hash { + size_t + operator()(const google::protobuf::MapKey& map_key) const { + switch (map_key.type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + return hash()(map_key.GetStringValue()); + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + return hash< ::google::protobuf::int64>()(map_key.GetInt64Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + return hash< ::google::protobuf::int32>()(map_key.GetInt32Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + return hash< ::google::protobuf::uint64>()(map_key.GetUInt64Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + return hash< ::google::protobuf::uint32>()(map_key.GetUInt32Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + return hash()(map_key.GetBoolValue()); + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + return 0; + } + } +}; +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END + #endif // GOOGLE_PROTOBUF_MAP_H__ diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h index e93d0348f545e..987c4e297c8aa 100644 --- a/src/google/protobuf/map_entry.h +++ b/src/google/protobuf/map_entry.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -79,40 +80,46 @@ class LIBPROTOBUF_EXPORT MapEntryBase : public Message { // MapEntry is the returned google::protobuf::Message when calling AddMessage of // google::protobuf::Reflection. In order to let it work with generated message -// reflection, its internal layout is the same as generated message with the -// same fields. However, in order to decide the internal layout of key/value, we -// need to know both their cpp type in generated api and proto type. +// reflection, its in-memory type is the same as generated message with the same +// fields. However, in order to decide the in-memory type of key/value, we need +// to know both their cpp type in generated api and proto type. In +// implmentation, all in-memory types have related wire format functions to +// support except ArenaStringPtr. Therefore, we need to define another type with +// supporting wire format functions. Since this type is only used as return type +// of MapEntry accessors, it's named MapEntry accessor type. // -// cpp type | proto type | internal layout -// int32 TYPE_INT32 int32 -// int32 TYPE_FIXED32 int32 -// FooEnum TYPE_ENUM int -// FooMessage TYPE_MESSAGE FooMessage* +// cpp type: the type visible to users in public API. +// proto type: WireFormatLite::FieldType of the field. +// in-memory type: type of the data member used to stored this field. +// MapEntry accessor type: type used in MapEntry getters/mutators to access the +// field. // -// The internal layouts of primitive types can be inferred from its proto type, -// while we need to explicitly tell cpp type if proto type is TYPE_MESSAGE to -// get internal layout. -// Moreover, default_enum_value is used to initialize enum field in proto2. +// cpp type | proto type | in-memory type | MapEntry accessor type +// int32 TYPE_INT32 int32 int32 +// int32 TYPE_FIXED32 int32 int32 +// string TYPE_STRING ArenaStringPtr string +// FooEnum TYPE_ENUM int int +// FooMessage TYPE_MESSAGE FooMessage* FooMessage +// +// The in-memory types of primitive types can be inferred from its proto type, +// while we need to explicitly specify the cpp type if proto type is +// TYPE_MESSAGE to infer the in-memory type. Moreover, default_enum_value is +// used to initialize enum field in proto2. template class MapEntry : public MapEntryBase { - // Handlers for key/value wire type. Provide utilities to parse/serialize - // key/value. - typedef MapWireFieldTypeHandler KeyWireHandler; - typedef MapWireFieldTypeHandler ValueWireHandler; - - // Define key/value's internal stored type. Message is the only one whose - // internal stored type cannot be inferred from its proto type. - static const bool kIsKeyMessage = KeyWireHandler::kIsMessage; - static const bool kIsValueMessage = ValueWireHandler::kIsMessage; - typedef typename KeyWireHandler::CppType KeyInternalType; - typedef typename ValueWireHandler::CppType ValueInternalType; - typedef typename MapIf::type - KeyCppType; - typedef typename MapIf::type - ValCppType; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler KeyTypeHandler; + typedef MapTypeHandler ValueTypeHandler; + + // Enum type cannot be used for MapTypeHandler::Read. Define a type + // which will replace Enum with int. + typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; + typedef typename ValueTypeHandler::MapEntryAccessorType + ValueMapEntryAccessorType; // Abbreviation for MapEntry typedef typename google::protobuf::internal::MapEntry< @@ -132,16 +139,16 @@ class MapEntry : public MapEntryBase { // accessors ====================================================== - virtual inline const KeyCppType& key() const { + virtual inline const KeyMapEntryAccessorType& key() const { return entry_lite_.key(); } - inline KeyCppType* mutable_key() { + inline KeyMapEntryAccessorType* mutable_key() { return entry_lite_.mutable_key(); } - virtual inline const ValCppType& value() const { + virtual inline const ValueMapEntryAccessorType& value() const { return entry_lite_.value(); } - inline ValCppType* mutable_value() { + inline ValueMapEntryAccessorType* mutable_value() { return entry_lite_.mutable_value(); } @@ -240,7 +247,9 @@ class MapEntry : public MapEntryBase { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, entry_lite_._has_bits_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _unknown_fields_), -1, DescriptorPool::generated_pool(), - ::google::protobuf::MessageFactory::generated_factory(), sizeof(MapEntry), -1); + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(MapEntry), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _internal_metadata_)); entry->descriptor_ = descriptor; entry->reflection_ = reflection; entry->set_default_instance(entry); @@ -250,10 +259,13 @@ class MapEntry : public MapEntryBase { } private: - MapEntry() : default_instance_(NULL), entry_lite_() {} + MapEntry() + : _internal_metadata_(NULL), default_instance_(NULL), entry_lite_() {} explicit MapEntry(Arena* arena) - : default_instance_(NULL), entry_lite_(arena) {} + : _internal_metadata_(arena), + default_instance_(NULL), + entry_lite_(arena) {} inline Arena* GetArenaNoVirtual() const { return entry_lite_.GetArenaNoVirtual(); @@ -266,6 +278,7 @@ class MapEntry : public MapEntryBase { static int offsets_[2]; UnknownFieldSet _unknown_fields_; + InternalMetadataWithArena _internal_metadata_; MapEntry* default_instance_; EntryLiteType entry_lite_; diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h index 52746da5954fc..0e6ee013e32ee 100644 --- a/src/google/protobuf/map_entry_lite.h +++ b/src/google/protobuf/map_entry_lite.h @@ -61,38 +61,21 @@ template class MapEntryLite : public MessageLite { - // Handlers for key/value wire type. Provide utilities to parse/serialize - // key/value. - typedef MapWireFieldTypeHandler KeyWireHandler; - typedef MapWireFieldTypeHandler ValueWireHandler; - - // Define key/value's internal stored type. Message is the only one whose - // internal stored type cannot be inferred from its proto type - static const bool kIsKeyMessage = KeyWireHandler::kIsMessage; - static const bool kIsValueMessage = ValueWireHandler::kIsMessage; - typedef typename KeyWireHandler::CppType KeyInternalType; - typedef typename ValueWireHandler::CppType ValueInternalType; - typedef typename MapIf::type - KeyCppType; - typedef typename MapIf::type - ValCppType; - - // Handlers for key/value's internal stored type. Provide utilities to - // manipulate internal stored type. We need it because some types are stored - // as values and others are stored as pointers (Message and string), but we - // need to keep the code in MapEntry unified instead of providing different - // codes for each type. - typedef MapCppTypeHandler KeyCppHandler; - typedef MapCppTypeHandler ValueCppHandler; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler KeyTypeHandler; + typedef MapTypeHandler ValueTypeHandler; // Define internal memory layout. Strings and messages are stored as // pointers, while other types are stored as values. - static const bool kKeyIsStringOrMessage = KeyCppHandler::kIsStringOrMessage; - static const bool kValIsStringOrMessage = ValueCppHandler::kIsStringOrMessage; - typedef typename MapIf::type - KeyBase; - typedef typename MapIf::type - ValueBase; + typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory; + typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory; + + // Enum type cannot be used for MapTypeHandler::Read. Define a type + // which will replace Enum with int. + typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; + typedef typename ValueTypeHandler::MapEntryAccessorType + ValueMapEntryAccessorType; // Constants for field number. static const int kKeyFieldNumber = 1; @@ -100,38 +83,37 @@ class MapEntryLite : public MessageLite { // Constants for field tag. static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( - kKeyFieldNumber, KeyWireHandler::kWireType); + kKeyFieldNumber, KeyTypeHandler::kWireType); static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( - kValueFieldNumber, ValueWireHandler::kWireType); + kValueFieldNumber, ValueTypeHandler::kWireType); static const int kTagSize = 1; public: ~MapEntryLite() { if (this != default_instance_) { - KeyCppHandler::Delete(key_); - ValueCppHandler::Delete(value_); + if (GetArenaNoVirtual() != NULL) return; + KeyTypeHandler::DeleteNoArena(key_); + ValueTypeHandler::DeleteNoArena(value_); } } // accessors ====================================================== - virtual inline const KeyCppType& key() const { - return KeyCppHandler::Reference(key_); - } - inline KeyCppType* mutable_key() { - set_has_key(); - KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual()); - return KeyCppHandler::Pointer(key_); + virtual inline const KeyMapEntryAccessorType& key() const { + return KeyTypeHandler::GetExternalReference(key_); } - virtual inline const ValCppType& value() const { + virtual inline const ValueMapEntryAccessorType& value() const { GOOGLE_CHECK(default_instance_ != NULL); - return ValueCppHandler::DefaultIfNotInitialized(value_, + return ValueTypeHandler::DefaultIfNotInitialized(value_, default_instance_->value_); } - inline ValCppType* mutable_value() { + inline KeyMapEntryAccessorType* mutable_key() { + set_has_key(); + return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); + } + inline ValueMapEntryAccessorType* mutable_value() { set_has_value(); - ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual()); - return ValueCppHandler::Pointer(value_); + return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); } // implements MessageLite ========================================= @@ -159,13 +141,17 @@ class MapEntryLite : public MessageLite { tag = input->ReadTag(); switch (tag) { case kKeyTag: - if (!KeyWireHandler::Read(input, mutable_key())) return false; + if (!KeyTypeHandler::Read(input, mutable_key())) { + return false; + } set_has_key(); if (!input->ExpectTag(kValueTag)) break; GOOGLE_FALLTHROUGH_INTENDED; case kValueTag: - if (!ValueWireHandler::Read(input, mutable_value())) return false; + if (!ValueTypeHandler::Read(input, mutable_value())) { + return false; + } set_has_value(); if (input->ExpectAtEnd()) return true; break; @@ -184,32 +170,35 @@ class MapEntryLite : public MessageLite { int ByteSize() const { int size = 0; - size += has_key() ? kTagSize + KeyWireHandler::ByteSize(key()) : 0; - size += has_value() ? kTagSize + ValueWireHandler::ByteSize(value()) : 0; + size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; + size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; return size; } void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const { - KeyWireHandler::Write(kKeyFieldNumber, key(), output); - ValueWireHandler::Write(kValueFieldNumber, value(), output); + KeyTypeHandler::Write(kKeyFieldNumber, key(), output); + ValueTypeHandler::Write(kValueFieldNumber, value(), output); } ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - output = KeyWireHandler::WriteToArray(kKeyFieldNumber, key(), output); - output = - ValueWireHandler::WriteToArray(kValueFieldNumber, value(), output); + output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output); + output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output); return output; } int GetCachedSize() const { int size = 0; - size += has_key() ? kTagSize + KeyWireHandler::GetCachedSize(key()) : 0; - size += - has_value() ? kTagSize + ValueWireHandler::GetCachedSize(value()) : 0; + size += has_key() + ? kTagSize + KeyTypeHandler::GetCachedSize(key()) + : 0; + size += has_value() + ? kTagSize + ValueTypeHandler::GetCachedSize( + value()) + : 0; return size; } - bool IsInitialized() const { return ValueCppHandler::IsInitialized(value_); } + bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); } MessageLite* New() const { MapEntryLite* entry = new MapEntryLite; @@ -225,36 +214,37 @@ class MapEntryLite : public MessageLite { int SpaceUsed() const { int size = sizeof(MapEntryLite); - size += KeyCppHandler::SpaceUsedInMapEntry(key_); - size += ValueCppHandler::SpaceUsedInMapEntry(value_); + size += KeyTypeHandler::SpaceUsedInMapEntry(key_); + size += ValueTypeHandler::SpaceUsedInMapEntry(value_); return size; } void MergeFrom(const MapEntryLite& from) { if (from._has_bits_[0]) { if (from.has_key()) { - KeyCppHandler::EnsureMutable(&key_, GetArenaNoVirtual()); - KeyCppHandler::Merge(from.key(), &key_); + KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); + KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual()); set_has_key(); } if (from.has_value()) { - ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual()); - ValueCppHandler::Merge(from.value(), &value_); + ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); + ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual()); set_has_value(); } } } void Clear() { - KeyCppHandler::Clear(&key_); - ValueCppHandler::ClearMaybeByDefaultEnum(&value_, default_enum_value); + KeyTypeHandler::Clear(&key_, GetArenaNoVirtual()); + ValueTypeHandler::ClearMaybeByDefaultEnum( + &value_, GetArenaNoVirtual(), default_enum_value); clear_has_key(); clear_has_value(); } void InitAsDefaultInstance() { - KeyCppHandler::AssignDefaultValue(&key_); - ValueCppHandler::AssignDefaultValue(&value_); + KeyTypeHandler::AssignDefaultValue(&key_); + ValueTypeHandler::AssignDefaultValue(&value_); } Arena* GetArena() const { @@ -302,11 +292,11 @@ class MapEntryLite : public MessageLite { // only takes references of given key and value. template - class MapEntryWrapper + class LIBPROTOBUF_EXPORT MapEntryWrapper : public MapEntryLite { typedef MapEntryLite Base; - typedef typename Base::KeyCppType KeyCppType; - typedef typename Base::ValCppType ValCppType; + typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: MapEntryWrapper(Arena* arena, const K& key, const V& value) @@ -316,8 +306,8 @@ class MapEntryLite : public MessageLite { Base::set_has_key(); Base::set_has_value(); } - inline const KeyCppType& key() const { return key_; } - inline const ValCppType& value() const { return value_; } + inline const KeyMapEntryAccessorType& key() const { return key_; } + inline const ValueMapEntryAccessorType& value() const { return value_; } private: const Key& key_; @@ -336,11 +326,11 @@ class MapEntryLite : public MessageLite { // the temporary. template - class MapEnumEntryWrapper + class LIBPROTOBUF_EXPORT MapEnumEntryWrapper : public MapEntryLite { typedef MapEntryLite Base; - typedef typename Base::KeyCppType KeyCppType; - typedef typename Base::ValCppType ValCppType; + typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: MapEnumEntryWrapper(Arena* arena, const K& key, const V& value) @@ -350,28 +340,28 @@ class MapEntryLite : public MessageLite { Base::set_has_key(); Base::set_has_value(); } - inline const KeyCppType& key() const { return key_; } - inline const ValCppType& value() const { return value_; } + inline const KeyMapEntryAccessorType& key() const { return key_; } + inline const ValueMapEntryAccessorType& value() const { return value_; } private: - const KeyCppType& key_; - const ValCppType value_; + const KeyMapEntryAccessorType& key_; + const ValueMapEntryAccessorType value_; friend class google::protobuf::Arena; typedef void DestructorSkippable_; }; MapEntryLite() : default_instance_(NULL), arena_(NULL) { - KeyCppHandler::Initialize(&key_, NULL); - ValueCppHandler::InitializeMaybeByDefaultEnum( + KeyTypeHandler::Initialize(&key_, NULL); + ValueTypeHandler::InitializeMaybeByDefaultEnum( &value_, default_enum_value, NULL); _has_bits_[0] = 0; } explicit MapEntryLite(Arena* arena) : default_instance_(NULL), arena_(arena) { - KeyCppHandler::Initialize(&key_, arena); - ValueCppHandler::InitializeMaybeByDefaultEnum( + KeyTypeHandler::Initialize(&key_, arena); + ValueTypeHandler::InitializeMaybeByDefaultEnum( &value_, default_enum_value, arena); _has_bits_[0] = 0; } @@ -386,8 +376,8 @@ class MapEntryLite : public MessageLite { MapEntryLite* default_instance_; - KeyBase key_; - ValueBase value_; + KeyOnMemory key_; + ValueOnMemory value_; Arena* arena_; uint32 _has_bits_[1]; diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index 6ff1936eb45b5..d8879f24e9f24 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -29,6 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include @@ -145,6 +146,321 @@ void MapFieldBase::SyncMapWithRepeatedField() const { } } +// ------------------DynamicMapField------------------ +DynamicMapField::DynamicMapField(const Message* default_entry) + : default_entry_(default_entry) { +} + +DynamicMapField::DynamicMapField(const Message* default_entry, + Arena* arena) + : TypeDefinedMapFieldBase(arena), + default_entry_(default_entry) { +} + +DynamicMapField::~DynamicMapField() { + // DynamicMapField owns map values. Need to delete them before clearing + // the map. + for (typename Map::iterator iter = map_.begin(); + iter != map_.end(); ++iter) { + iter->second.DeleteData(); + } + map_.clear(); +} + +int DynamicMapField::size() const { + return GetMap().size(); +} + +bool DynamicMapField::ContainsMapKey( + const MapKey& map_key) const { + const Map& map = GetMap(); + typename Map::const_iterator iter = map.find(map_key); + return iter != map.end(); +} + +bool DynamicMapField::InsertMapValue( + const MapKey& map_key, MapValueRef* val) { + bool result = false; + + MapValueRef& map_val = (*MutableMap())[map_key]; + // If map_val.data_ is not set, it is newly inserted by map_[map_key]. + if (map_val.data_ == NULL) { + result = true; + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + map_val.SetType(val_des->cpp_type()); + // Allocate momery for the inserted MapValueRef, and initialize to + // default value. + switch (val_des->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + TYPE * value = new TYPE(); \ + map_val.SetValue(value); \ + break; \ + } + HANDLE_TYPE(INT32, int32); + HANDLE_TYPE(INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE(FLOAT, float); + HANDLE_TYPE(BOOL, bool); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = default_entry_->GetReflection()->GetMessage( + *default_entry_, val_des); + Message* value = message.New(); + map_val.SetValue(value); + break; + } + } + } + val->CopyFrom(map_val); + return result; +} + +bool DynamicMapField::DeleteMapValue(const MapKey& map_key) { + MapFieldBase::SyncMapWithRepeatedField(); + Map::iterator iter = map_.find(map_key); + if (iter == map_.end()) { + return false; + } + // Set map dirty only if the delete is successful. + MapFieldBase::SetMapDirty(); + iter->second.DeleteData(); + map_.erase(iter); + return true; +} + +const Map& DynamicMapField::GetMap() const { + MapFieldBase::SyncMapWithRepeatedField(); + return map_; +} + +Map* DynamicMapField::MutableMap() { + MapFieldBase::SyncMapWithRepeatedField(); + MapFieldBase::SetMapDirty(); + return &map_; +} + +void DynamicMapField::SetMapIteratorValue(MapIterator* map_iter) const { + typename Map::const_iterator iter = + TypeDefinedMapFieldBase::InternalGetIterator( + map_iter); + if (iter == map_.end()) return; + map_iter->key_.CopyFrom(iter->first); + map_iter->value_.CopyFrom(iter->second); +} + +void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const { + const Reflection* reflection = default_entry_->GetReflection(); + const FieldDescriptor* key_des = + default_entry_->GetDescriptor()->FindFieldByName("key"); + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + if (MapFieldBase::repeated_field_ == NULL) { + if (MapFieldBase::arena_ == NULL) { + MapFieldBase::repeated_field_ = new RepeatedPtrField(); + } else { + MapFieldBase::repeated_field_ = + Arena::CreateMessage >( + MapFieldBase::arena_); + } + } + + MapFieldBase::repeated_field_->Clear(); + + for (typename Map::const_iterator it = map_.begin(); + it != map_.end(); ++it) { + Message* new_entry = default_entry_->New(); + MapFieldBase::repeated_field_->AddAllocated(new_entry); + const MapKey& map_key = it->first; + switch (key_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(new_entry, key_des, map_key.GetStringValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(new_entry, key_des, map_key.GetBoolValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + const MapValueRef& map_val = it->second; + switch (val_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(new_entry, val_des, map_val.GetStringValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(new_entry, val_des, map_val.GetBoolValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = map_val.GetMessageValue(); + reflection->MutableMessage(new_entry, val_des)->CopyFrom(message); + break; + } + } + } +} + +void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const { + Map* map = &const_cast(this)->map_; + const Reflection* reflection = default_entry_->GetReflection(); + const FieldDescriptor* key_des = + default_entry_->GetDescriptor()->FindFieldByName("key"); + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + // DynamicMapField owns map values. Need to delete them before clearing + // the map. + for (typename Map::iterator iter = map->begin(); + iter != map->end(); ++iter) { + iter->second.DeleteData(); + } + map->clear(); + for (typename RepeatedPtrField::iterator it = + MapFieldBase::repeated_field_->begin(); + it != MapFieldBase::repeated_field_->end(); ++it) { + MapKey map_key; + switch (key_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + map_key.SetStringValue(reflection->GetString(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + map_key.SetInt64Value(reflection->GetInt64(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + map_key.SetInt32Value(reflection->GetInt32(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + map_key.SetBoolValue(reflection->GetBool(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + MapValueRef& map_val = (*map)[map_key]; + map_val.SetType(val_des->cpp_type()); + switch (val_des->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + TYPE * value = new TYPE; \ + *value = reflection->Get##METHOD(*it, val_des); \ + map_val.SetValue(value); \ + break; \ + } + HANDLE_TYPE(INT32, int32, Int32); + HANDLE_TYPE(INT64, int64, Int64); + HANDLE_TYPE(UINT32, uint32, UInt32); + HANDLE_TYPE(UINT64, uint64, UInt64); + HANDLE_TYPE(DOUBLE, double, Double); + HANDLE_TYPE(FLOAT, float, Float); + HANDLE_TYPE(BOOL, bool, Bool); + HANDLE_TYPE(STRING, string, String); + HANDLE_TYPE(ENUM, int32, EnumValue); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = reflection->GetMessage(*it, val_des); + Message* value = message.New(); + value->CopyFrom(message); + map_val.SetValue(value); + break; + } + } + } +} + +int DynamicMapField::SpaceUsedExcludingSelfNoLock() const { + int size = 0; + if (MapFieldBase::repeated_field_ != NULL) { + size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelf(); + } + size += sizeof(map_); + int map_size = map_.size(); + if (map_size) { + typename Map::const_iterator it = map_.begin(); + size += sizeof(it->first) * map_size; + size += sizeof(it->second) * map_size; + // If key is string, add the allocated space. + if (it->first.type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING) { + size += sizeof(string) * map_size; + } + // Add the allocated space in MapValueRef. + switch (it->second.type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + size += sizeof(TYPE) * map_size; \ + break; \ + } + HANDLE_TYPE(INT32, int32); + HANDLE_TYPE(INT64, int64); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(DOUBLE, double); + HANDLE_TYPE(FLOAT, float); + HANDLE_TYPE(BOOL, bool); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + while (it != map_.end()) { + const Message& message = it->second.GetMessageValue(); + size += message.GetReflection()->SpaceUsed(message); + ++it; + } + break; + } + } + } + return size; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 56d3d0f461987..9130166b85940 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -32,6 +32,7 @@ #define GOOGLE_PROTOBUF_MAP_FIELD_H__ #include +#include #include #include #include @@ -45,7 +46,8 @@ namespace google { namespace protobuf { - +class DynamicMessage; +class MapKey; namespace internal { class ContendedMapCleanTest; @@ -83,6 +85,17 @@ class LIBPROTOBUF_EXPORT MapFieldBase { // Like above. Returns mutable pointer to the internal repeated field. RepeatedPtrFieldBase* MutableRepeatedField(); + // Pure virtual map APIs for Map Reflection. + virtual bool ContainsMapKey(const MapKey& map_key) const = 0; + virtual bool InsertMapValue(const MapKey& map_key, MapValueRef* val) = 0; + virtual bool DeleteMapValue(const MapKey& map_key) = 0; + virtual bool EqualIterator(const MapIterator& a, + const MapIterator& b) const = 0; + virtual void MapBegin(MapIterator* map_iter) const = 0; + virtual void MapEnd(MapIterator* map_iter) const = 0; + // Sync Map with repeated field and returns the size of map. + virtual int size() const = 0; + // Returns the number of bytes used by the repeated field, excluding // sizeof(*this) int SpaceUsedExcludingSelf() const; @@ -141,6 +154,57 @@ class LIBPROTOBUF_EXPORT MapFieldBase { friend class ContendedMapCleanTest; friend class GeneratedMessageReflection; friend class MapFieldAccessor; + friend class ::google::protobuf::DynamicMessage; + + // Virtual helper methods for MapIterator. MapIterator doesn't have the + // type helper for key and value. Call these help methods to deal with + // different types. Real helper methods are implemented in + // TypeDefinedMapFieldBase. + friend class ::google::protobuf::MapIterator; + // Allocate map<...>::iterator for MapIterator. + virtual void InitializeIterator(MapIterator* map_iter) const = 0; + + // DeleteIterator() is called by the destructor of MapIterator only. + // It deletes map<...>::iterator for MapIterator. + virtual void DeleteIterator(MapIterator* map_iter) const = 0; + + // Copy the map<...>::iterator from other_iterator to + // this_iterator. + virtual void CopyIterator(MapIterator* this_iterator, + const MapIterator& other_iterator) const = 0; + + // IncreaseIterator() is called by operator++() of MapIterator only. + // It implements the ++ operator of MapIterator. + virtual void IncreaseIterator(MapIterator* map_iter) const = 0; +}; + +// This class provides common Map Reflection implementations for generated +// message and dynamic message. +template +class TypeDefinedMapFieldBase : public MapFieldBase { + public: + TypeDefinedMapFieldBase() {} + explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {} + ~TypeDefinedMapFieldBase() {} + void MapBegin(MapIterator* map_iter) const; + void MapEnd(MapIterator* map_iter) const; + bool EqualIterator(const MapIterator& a, const MapIterator& b) const; + + virtual const Map& GetMap() const = 0; + virtual Map* MutableMap() = 0; + + protected: + typename Map::const_iterator& InternalGetIterator( + const MapIterator* map_iter) const; + + private: + void InitializeIterator(MapIterator* map_iter) const; + void DeleteIterator(MapIterator* map_iter) const; + void CopyIterator(MapIterator* this_iteratorm, + const MapIterator& that_iterator) const; + void IncreaseIterator(MapIterator* map_iter) const; + + virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0; }; // This class provides accesss to map field using generated api. It is used for @@ -150,25 +214,13 @@ template -class MapField : public MapFieldBase, +class MapField : public TypeDefinedMapFieldBase, public MapFieldLite { - // Handlers for key/value wire type. Provide utilities to parse/serialize - // key/value. - typedef MapWireFieldTypeHandler KeyWireHandler; - typedef MapWireFieldTypeHandler ValueWireHandler; - - // Define key/value's internal stored type. - static const bool kIsKeyMessage = KeyWireHandler::kIsMessage; - static const bool kIsValMessage = ValueWireHandler::kIsMessage; - typedef typename KeyWireHandler::CppType KeyInternalType; - typedef typename ValueWireHandler::CppType ValueInternalType; - typedef typename MapIf::type KeyCpp; - typedef typename MapIf::type ValCpp; - - // Handlers for key/value's internal stored type. - typedef MapCppTypeHandler KeyHandler; - typedef MapCppTypeHandler ValHandler; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler KeyTypeHandler; + typedef MapTypeHandler ValueTypeHandler; // Define message type for internal repeated field. typedef MapEntry @@ -183,8 +235,8 @@ class MapField : public MapFieldBase, // Enum needs to be handled differently from other types because it has // different exposed type in google::protobuf::Map's api and repeated field's api. For // details see the comment in the implementation of - // SyncMapWithRepeatedFieldNoLocki. - static const bool kIsValueEnum = ValueWireHandler::kIsEnum; + // SyncMapWithRepeatedFieldNoLock. + static const bool kIsValueEnum = ValueTypeHandler::kIsEnum; typedef typename MapIf::type CastValueType; public: @@ -197,6 +249,11 @@ class MapField : public MapFieldBase, MapField(Arena* arena, const Message* default_entry); ~MapField(); + // Implement MapFieldBase + bool ContainsMapKey(const MapKey& map_key) const; + bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool DeleteMapValue(const MapKey& map_key); + // Accessors const Map& GetMap() const; Map* MutableMap(); @@ -230,12 +287,109 @@ class MapField : public MapFieldBase, void SyncMapWithRepeatedFieldNoLock() const; int SpaceUsedExcludingSelfNoLock() const; + void SetMapIteratorValue(MapIterator* map_iter) const; + mutable const EntryType* default_entry_; friend class ::google::protobuf::Arena; }; +class LIBPROTOBUF_EXPORT DynamicMapField: public TypeDefinedMapFieldBase { + public: + explicit DynamicMapField(const Message* default_entry); + DynamicMapField(const Message* default_entry, Arena* arena); + ~DynamicMapField(); + + // Implement MapFieldBase + bool ContainsMapKey(const MapKey& map_key) const; + bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool DeleteMapValue(const MapKey& map_key); + + const Map& GetMap() const; + Map* MutableMap(); + + int size() const; + + private: + Map map_; + const Message* default_entry_; + + // Implements MapFieldBase + void SyncRepeatedFieldWithMapNoLock() const; + void SyncMapWithRepeatedFieldNoLock() const; + int SpaceUsedExcludingSelfNoLock() const; + void SetMapIteratorValue(MapIterator* map_iter) const; +}; + } // namespace internal + +class LIBPROTOBUF_EXPORT MapIterator { + public: + MapIterator(Message* message, const FieldDescriptor* field) { + const Reflection* reflection = message->GetReflection(); + map_ = reflection->MapData(message, field); + key_.SetType(field->message_type()->FindFieldByName("key")->cpp_type()); + value_.SetType(field->message_type()->FindFieldByName("value")->cpp_type()); + map_->InitializeIterator(this); + } + MapIterator(const MapIterator& other) { + map_ = other.map_; + map_->InitializeIterator(this); + map_->CopyIterator(this, other); + } + ~MapIterator() { + map_->DeleteIterator(this); + } + friend bool operator==(const MapIterator& a, const MapIterator& b) { + return a.map_->EqualIterator(a, b); + } + friend bool operator!=(const MapIterator& a, const MapIterator& b) { + return !a.map_->EqualIterator(a, b); + } + MapIterator& operator++() { + map_->IncreaseIterator(this); + return *this; + } + MapIterator operator++(int) { + // iter_ is copied from Map<...>::iterator, no need to + // copy from its self again. Use the same implementation + // with operator++() + map_->IncreaseIterator(this); + return *this; + } + const MapKey& GetKey() { + return key_; + } + const MapValueRef& GetValueRef() { + return value_; + } + MapValueRef* MutableValueRef() { + map_->SetMapDirty(); + return &value_; + } + + private: + template + friend class internal::TypeDefinedMapFieldBase; + friend class internal::DynamicMapField; + template + friend class internal::MapField; + + // reinterpret_cast from heap-allocated Map<...>::iterator*. MapIterator owns + // the iterator. It is allocated by MapField<...>::InitializeIterator() called + // in constructor and deleted by MapField<...>::DeleteIterator() called in + // destructor. + void* iter_; + // Point to a MapField to call helper methods implemented in MapField. + // MapIterator does not own this object. + internal::MapFieldBase* map_; + MapKey key_; + MapValueRef value_; +}; + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 5b4305f90edc5..1a4ce9376894e 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -36,12 +36,128 @@ #include #endif +#include #include #include namespace google { namespace protobuf { namespace internal { +// UnwrapMapKey template +template +T UnwrapMapKey(const MapKey& map_key); +template<> +inline int32 UnwrapMapKey(const MapKey& map_key) { + return map_key.GetInt32Value(); +} +template<> +inline uint32 UnwrapMapKey(const MapKey& map_key) { + return map_key.GetUInt32Value(); +} +template<> +inline int64 UnwrapMapKey(const MapKey& map_key) { + return map_key.GetInt64Value(); +} +template<> +inline uint64 UnwrapMapKey(const MapKey& map_key) { + return map_key.GetUInt64Value(); +} +template<> +inline bool UnwrapMapKey(const MapKey& map_key) { + return map_key.GetBoolValue(); +} +template<> +inline string UnwrapMapKey(const MapKey& map_key) { + return map_key.GetStringValue(); +} + +// SetMapKey template +template +inline void SetMapKey(MapKey* map_key, const T& value); +template<> +inline void SetMapKey(MapKey* map_key, const int32& value) { + map_key->SetInt32Value(value); +} +template<> +inline void SetMapKey(MapKey* map_key, const uint32& value) { + map_key->SetUInt32Value(value); +} +template<> +inline void SetMapKey(MapKey* map_key, const int64& value) { + map_key->SetInt64Value(value); +} +template<> +inline void SetMapKey(MapKey* map_key, const uint64& value) { + map_key->SetUInt64Value(value); +} +template<> +inline void SetMapKey(MapKey* map_key, const bool& value) { + map_key->SetBoolValue(value); +} +template<> +inline void SetMapKey(MapKey* map_key, const string& value) { + map_key->SetStringValue(value); +} + +// ------------------------TypeDefinedMapFieldBase--------------- +template +typename Map::const_iterator& +TypeDefinedMapFieldBase::InternalGetIterator( + const MapIterator* map_iter) const { + return *reinterpret_cast::const_iterator *>( + map_iter->iter_); +} + +template +void TypeDefinedMapFieldBase::MapBegin(MapIterator* map_iter) const { + InternalGetIterator(map_iter) = GetMap().begin(); + SetMapIteratorValue(map_iter); +} + +template +void TypeDefinedMapFieldBase::MapEnd(MapIterator* map_iter) const { + InternalGetIterator(map_iter) = GetMap().end(); +} + +template +bool TypeDefinedMapFieldBase::EqualIterator(const MapIterator& a, + const MapIterator& b) + const { + return InternalGetIterator(&a) == InternalGetIterator(&b); +} + +template +void TypeDefinedMapFieldBase::IncreaseIterator(MapIterator* map_iter) + const { + ++InternalGetIterator(map_iter); + SetMapIteratorValue(map_iter); +} + +template +void TypeDefinedMapFieldBase::InitializeIterator( + MapIterator* map_iter) const { + map_iter->iter_ = new typename Map::const_iterator; + GOOGLE_CHECK(map_iter->iter_ != NULL); +} + +template +void TypeDefinedMapFieldBase::DeleteIterator(MapIterator* map_iter) + const { + delete reinterpret_cast::const_iterator *>( + map_iter->iter_); +} + +template +void TypeDefinedMapFieldBase::CopyIterator( + MapIterator* this_iter, + const MapIterator& that_iter) const { + InternalGetIterator(this_iter) = InternalGetIterator(&that_iter); + this_iter->key_.SetType(that_iter.key_.type()); + this_iter->value_.SetType(that_iter.value_.type()); + SetMapIteratorValue(this_iter); +} + +// ---------------------------------------------------------------------- template MapField::MapField( Arena* arena) - : MapFieldBase(arena), + : TypeDefinedMapFieldBase(arena), MapFieldLite( arena), default_entry_(NULL) {} @@ -75,7 +191,7 @@ template MapField::MapField( Arena* arena, const Message* default_entry) - : MapFieldBase(arena), + : TypeDefinedMapFieldBase(arena), MapFieldLite( arena), default_entry_(down_cast(default_entry)) {} @@ -94,7 +210,7 @@ template ::size() const { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); return MapFieldLiteType::GetInternalMap().size(); } @@ -105,9 +221,65 @@ template ::Clear() { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); MapFieldLiteType::MutableInternalMap()->clear(); - SetMapDirty(); + MapFieldBase::SetMapDirty(); +} + +template +void MapField::SetMapIteratorValue( + MapIterator* map_iter) const { + const Map& map = GetMap(); + typename Map::const_iterator iter = + TypeDefinedMapFieldBase::InternalGetIterator(map_iter); + if (iter == map.end()) return; + SetMapKey(&map_iter->key_, iter->first); + map_iter->value_.SetValue(&iter->second); +} + +template +bool MapField::ContainsMapKey( + const MapKey& map_key) const { + const Map& map = GetMap(); + const Key& key = UnwrapMapKey(map_key); + typename Map::const_iterator iter = map.find(key); + return iter != map.end(); +} + +template +bool MapField::InsertMapValue(const MapKey& map_key, + MapValueRef* val) { + Map* map = MutableMap(); + bool result = false; + const Key& key = UnwrapMapKey(map_key); + if (map->end() == map->find(key)) { + result = true; + } + val->SetValue(&((*map)[key])); + return result; +} + +template +bool MapField::DeleteMapValue( + const MapKey& map_key) { + const Key& key = UnwrapMapKey(map_key); + return MutableMap()->erase(key); } template & MapField::GetMap() const { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); return MapFieldLiteType::GetInternalMap(); } @@ -128,9 +300,9 @@ template * MapField::MutableMap() { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); Map* result = MapFieldLiteType::MutableInternalMap(); - SetMapDirty(); + MapFieldBase::SetMapDirty(); return result; } @@ -143,10 +315,10 @@ MapField::MergeFrom( const MapFieldLiteType& other) { const MapField& down_other = down_cast(other); - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); down_other.SyncMapWithRepeatedField(); MapFieldLiteType::MergeFrom(other); - SetMapDirty(); + MapFieldBase::SetMapDirty(); } template ::Swap( MapFieldLiteType* other) { MapField* down_other = down_cast(other); - std::swap(repeated_field_, down_other->repeated_field_); + std::swap(MapFieldBase::repeated_field_, down_other->repeated_field_); MapFieldLiteType::Swap(other); - std::swap(state_, down_other->state_); + std::swap(MapFieldBase::state_, down_other->state_); } template ::SetEntryDescriptor( const Descriptor** descriptor) { - entry_descriptor_ = descriptor; + MapFieldBase::entry_descriptor_ = descriptor; } template ::SetAssignDescriptorCallback(void (*callback)()) { - assign_descriptor_callback_ = callback; + MapFieldBase::assign_descriptor_callback_ = callback; } template ::SyncRepeatedFieldWithMapNoLock() const { - if (repeated_field_ == NULL) { + if (MapFieldBase::repeated_field_ == NULL) { if (MapFieldBase::arena_ == NULL) { - repeated_field_ = new RepeatedPtrField(); + MapFieldBase::repeated_field_ = new RepeatedPtrField(); } else { - repeated_field_ = Arena::CreateMessage >( - MapFieldBase::arena_); + MapFieldBase::repeated_field_ = + Arena::CreateMessage >( + MapFieldBase::arena_); } } const Map& map = GetInternalMap(); RepeatedPtrField* repeated_field = - reinterpret_cast*>(repeated_field_); + reinterpret_cast*>( + MapFieldBase::repeated_field_); repeated_field->Clear(); @@ -246,7 +420,9 @@ MapField::SyncMapWithRepeatedFieldNoLock() const { Map* map = const_cast(this)->MutableInternalMap(); RepeatedPtrField* repeated_field = - reinterpret_cast*>(repeated_field_); + reinterpret_cast*>( + MapFieldBase::repeated_field_); + GOOGLE_CHECK(MapFieldBase::repeated_field_ != NULL); map->clear(); for (typename RepeatedPtrField::iterator it = repeated_field->begin(); it != repeated_field->end(); ++it) { @@ -267,15 +443,15 @@ int MapField::SpaceUsedExcludingSelfNoLock() const { int size = 0; - if (repeated_field_ != NULL) { - size += repeated_field_->SpaceUsedExcludingSelf(); + if (MapFieldBase::repeated_field_ != NULL) { + size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelf(); } Map* map = const_cast(this)->MutableInternalMap(); size += sizeof(*map); for (typename Map::iterator it = map->begin(); it != map->end(); ++it) { - size += KeyHandler::SpaceUsedInMap(it->first); - size += ValHandler::SpaceUsedInMap(it->second); + size += KeyTypeHandler::SpaceUsedInMap(it->first); + size += ValueTypeHandler::SpaceUsedInMap(it->second); } return size; } @@ -289,10 +465,11 @@ MapField::InitDefaultEntryOnce() const { if (default_entry_ == NULL) { - InitMetadataOnce(); - GOOGLE_CHECK(*entry_descriptor_ != NULL); + MapFieldBase::InitMetadataOnce(); + GOOGLE_CHECK(*MapFieldBase::entry_descriptor_ != NULL); default_entry_ = down_cast( - MessageFactory::generated_factory()->GetPrototype(*entry_descriptor_)); + MessageFactory::generated_factory()->GetPrototype( + *MapFieldBase::entry_descriptor_)); } } diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index e3a640795d8f7..2ff1d6bbc4f0a 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc @@ -34,6 +34,7 @@ #include #endif +#include #include #include #include @@ -74,6 +75,28 @@ class MapFieldBaseStub : public MapFieldBase { bool IsRepeatedClean() { return state_ != 1; } void SetMapDirty() { state_ = 0; } void SetRepeatedDirty() { state_ = 1; } + bool ContainsMapKey(const MapKey& map_key) const { + return false; + } + bool InsertMapValue(const MapKey& map_key, MapValueRef* val) { + return false; + } + bool DeleteMapValue(const MapKey& map_key) { + return false; + } + bool EqualIterator(const MapIterator& a, const MapIterator& b) const { + return false; + } + int size() const { return 0; } + void MapBegin(MapIterator* map_iter) const {} + void MapEnd(MapIterator* map_iter) const {} + void InitializeIterator(MapIterator* map_iter) const {} + void DeleteIterator(MapIterator* map_iter) const {} + void CopyIterator(MapIterator* this_iterator, + const MapIterator& other_iterator) const {} + void IncreaseIterator(MapIterator* map_iter) const {} + void SetDefaultMessageEntry(const Message* message) const {} + const Message* GetDefaultMessageEntry() const { return NULL; } }; class MapFieldBasePrimitiveTest : public ::testing::Test { diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto index c69e8d9456354..0592dd7a6348b 100644 --- a/src/google/protobuf/map_lite_unittest.proto +++ b/src/google/protobuf/map_lite_unittest.proto @@ -34,6 +34,7 @@ option cc_enable_arenas = true; option optimize_for = LITE_RUNTIME; import "google/protobuf/unittest_lite.proto"; +import "google/protobuf/unittest_no_arena_lite.proto"; package protobuf_unittest; @@ -72,8 +73,12 @@ message TestArenaMapLite { map map_int32_float = 11; map map_int32_double = 12; map map_bool_bool = 13; - map map_int32_enum = 14; - map map_int32_foreign_message = 15; + map map_string_string = 14; + map map_int32_bytes = 15; + map map_int32_enum = 16; + map map_int32_foreign_message = 17; + map + map_int32_foreign_message_no_arena = 18; } // Test embeded message with required fields @@ -81,10 +86,6 @@ message TestRequiredMessageMapLite { map map_field = 1; } -message TestEnumStartWithNonZeroMapLite { - map map_field = 101; -} - message TestEnumMapLite { map known_map_field = 101; map unknown_map_field = 102; @@ -112,10 +113,6 @@ enum Proto2MapEnumPlusExtraLite { E_PROTO2_MAP_ENUM_EXTRA_LITE = 3; } -enum Proto2MapEnumStartWithNonZeroLite { - PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE = 1; -} - enum MapEnumLite { MAP_ENUM_FOO_LITE = 0; MAP_ENUM_BAR_LITE = 1; diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto index 3d4af28efed0f..6f9d6165c6fbe 100644 --- a/src/google/protobuf/map_proto2_unittest.proto +++ b/src/google/protobuf/map_proto2_unittest.proto @@ -49,10 +49,6 @@ enum Proto2MapEnumPlusExtra { E_PROTO2_MAP_ENUM_EXTRA = 3; } -enum Proto2MapEnumStartWithNonZero { - PROTO2_NON_ZERO_MAP_ENUM_FOO = 1; -} - message TestEnumMap { map known_map_field = 101; map unknown_map_field = 102; @@ -62,7 +58,3 @@ message TestEnumMapPlusExtra { map known_map_field = 101; map unknown_map_field = 102; } - -message TestEnumStartWithNonZeroMap { - map map_field = 101; -} diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index d62ec85f3c49a..a74801d92d2be 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -36,7 +36,9 @@ #include #include +#include #include +#include #include #include #include @@ -70,6 +72,7 @@ namespace google { using google::protobuf::unittest::ForeignMessage; using google::protobuf::unittest::TestAllTypes; using google::protobuf::unittest::TestMap; +using google::protobuf::unittest::TestRecursiveMapMessage; namespace protobuf { namespace internal { @@ -200,6 +203,21 @@ TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) { EXPECT_DEATH(const_map_.at(0), ""); } +TEST_F(MapImplTest, UsageErrors) { + MapKey key; + key.SetInt64Value(1); + EXPECT_DEATH(key.GetUInt64Value(), + "Protocol Buffer map usage error:\n" + "MapKey::GetUInt64Value type does not match\n" + " Expected : uint64\n" + " Actual : int64"); + + MapValueRef value; + EXPECT_DEATH(value.SetFloatValue(0.1), + "Protocol Buffer map usage error:\n" + "MapValueRef::type MapValueRef is not initialized."); +} + #endif // PROTOBUF_HAS_DEATH_TEST TEST_F(MapImplTest, CountNonExist) { @@ -475,6 +493,23 @@ TEST_F(MapImplTest, CopyConstructor) { EXPECT_EQ(value2, other.at(key2)); } +TEST_F(MapImplTest, IterConstructor) { + int32 key1 = 0; + int32 key2 = 1; + int32 value1 = 100; + int32 value2 = 101; + + std::map map; + map[key1] = value1; + map[key2] = value2; + + Map new_map(map.begin(), map.end()); + + EXPECT_EQ(2, new_map.size()); + EXPECT_EQ(value1, new_map.at(key1)); + EXPECT_EQ(value2, new_map.at(key2)); +} + TEST_F(MapImplTest, Assigner) { int32 key1 = 0; int32 key2 = 1; @@ -1140,6 +1175,19 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { mmf_int32_foreign_message.Add(*entry_int32_foreign_message); EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c()); + // Test Reflection::AddAllocatedMessage + Message* free_entry_string_string = MessageFactory::generated_factory() + ->GetPrototype(fd_map_string_string->message_type()) + ->New(); + entry_string_string->GetReflection()->SetString( + free_entry_string_string, + fd_map_string_string->message_type()->field(0), "4321"); + entry_string_string->GetReflection()->SetString( + free_entry_string_string, fd_map_string_string->message_type()->field(1), + "1234"); + refl->AddAllocatedMessage(&message, fd_map_string_string, + free_entry_string_string); + // Test MutableRepeatedFieldRef::RemoveLast() mmf_int32_int32.RemoveLast(); mmf_int32_double.RemoveLast(); @@ -1147,7 +1195,7 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { mmf_int32_foreign_message.RemoveLast(); EXPECT_EQ(10, message.map_int32_int32().size()); EXPECT_EQ(10, message.map_int32_double().size()); - EXPECT_EQ(10, message.map_string_string().size()); + EXPECT_EQ(11, message.map_string_string().size()); EXPECT_EQ(10, message.map_int32_foreign_message().size()); // Test MutableRepeatedFieldRef::SwapElements() @@ -1398,9 +1446,9 @@ TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) { } TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) { - unittest::TestEnumStartWithNonZeroMap message; - EXPECT_EQ(unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO, - (*message.mutable_map_field())[0]); + unittest::TestEnumMap message; + EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO, + (*message.mutable_known_map_field())[0]); } TEST(GeneratedMapFieldTest, Clear) { @@ -1526,12 +1574,28 @@ TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) { google::protobuf::scoped_ptr message1; message1.reset( factory.GetPrototype(unittest::TestMap::descriptor())->New()); - - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(message1.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); + message2.CopyFrom(*message1); + MapTestUtil::ExpectMapFieldsSet(message2); +} + +TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) { + unittest::TestMap message2; + // Construct a new version of the dynamic message via the factory. + DynamicMessageFactory factory; + google::protobuf::scoped_ptr message1; + message1.reset( + factory.GetPrototype(unittest::TestMap::descriptor())->New()); + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(message1.get()); + reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); message2.CopyFrom(*message1); MapTestUtil::ExpectMapFieldsSet(message2); } @@ -1547,12 +1611,43 @@ TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) { message1.reset( factory.GetPrototype(unittest::TestMap::descriptor())->New()); - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + message1->MergeFrom(message2); + reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); +} + +TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) { + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); + unittest::TestMap message2; + reflection_tester.SetMapFieldsViaMapReflection(&message2); + + // Construct a dynamic message via the factory. + DynamicMessageFactory factory; + google::protobuf::scoped_ptr message1; + message1.reset( + factory.GetPrototype(unittest::TestMap::descriptor())->New()); + message1->MergeFrom(message2); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message1); } +TEST(GeneratedMapFieldTest, SyncDynamicMapWithRepeatedField) { + // Construct a dynamic message via the factory. + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + DynamicMessageFactory factory; + google::protobuf::scoped_ptr message; + message.reset( + factory.GetPrototype(unittest::TestMap::descriptor())->New()); + reflection_tester.SetMapFieldsViaReflection(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflection(*message); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) { @@ -1779,7 +1874,7 @@ TEST(GeneratedMapFieldTest, IsInitialized) { TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(&message); @@ -1790,11 +1885,12 @@ TEST(GeneratedMapFieldReflectionTest, Accessors) { // Set every field to a unique value then go back and check all those // values. unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(&message); MapTestUtil::ExpectMapFieldsSet(message); reflection_tester.ExpectMapFieldsSetViaReflection(message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message); reflection_tester.ModifyMapFieldsViaReflection(&message); MapTestUtil::ExpectMapFieldsModified(message); @@ -1848,15 +1944,16 @@ TEST(GeneratedMapFieldReflectionTest, ClearField) { MapTestUtil::SetMapFields(&message); MapTestUtil::ExpectMapFieldsSet(message); - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.ClearMapFieldsViaReflection(&message); - MapTestUtil::ExpectClear(message); + reflection_tester.ExpectClearViaReflection(message); + reflection_tester.ExpectClearViaReflectionIterator(&message); } TEST(GeneratedMapFieldReflectionTest, RemoveLast) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); MapTestUtil::SetMapFields(&message); @@ -1875,7 +1972,7 @@ TEST(GeneratedMapFieldReflectionTest, RemoveLast) { TEST(GeneratedMapFieldReflectionTest, ReleaseLast) { unittest::TestMap message; const Descriptor* descriptor = message.GetDescriptor(); - MapTestUtil::MapReflectionTester reflection_tester(descriptor); + MapReflectionTester reflection_tester(descriptor); MapTestUtil::SetMapFields(&message); @@ -1904,7 +2001,7 @@ TEST(GeneratedMapFieldReflectionTest, ReleaseLast) { TEST(GeneratedMapFieldReflectionTest, SwapElements) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); MapTestUtil::SetMapFields(&message); @@ -1944,7 +2041,7 @@ TEST(GeneratedMapFieldReflectionTest, SwapElements) { TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message); } @@ -2000,24 +2097,35 @@ TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) { TEST(GeneratedMapFieldReflectionTest, MapEntryClear) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message); } TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) { - unittest::TestEnumStartWithNonZeroMap message; + unittest::TestEnumMap message; const Descriptor* descriptor = message.GetDescriptor(); const FieldDescriptor* field_descriptor = - descriptor->FindFieldByName("map_field"); + descriptor->FindFieldByName("known_map_field"); const FieldDescriptor* value_descriptor = field_descriptor->message_type()->FindFieldByName("value"); Message* sub_message = message.GetReflection()->AddMessage(&message, field_descriptor); - EXPECT_EQ(1, sub_message->GetReflection()->GetEnumValue(*sub_message, + EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message, value_descriptor)); } +// Map Reflection API Test ========================================= + +TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) { + unittest::TestMap message; + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message); + reflection_tester.ExpectMapFieldsSetViaReflection(message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message); +} + // Dynamic Message Test ============================================= class MapFieldInDynamicMessageTest : public testing::Test { @@ -2025,6 +2133,7 @@ class MapFieldInDynamicMessageTest : public testing::Test { const DescriptorPool* pool_; DynamicMessageFactory factory_; const Descriptor* map_descriptor_; + const Descriptor* recursive_map_descriptor_; const Message* map_prototype_; MapFieldInDynamicMessageTest() @@ -2033,7 +2142,10 @@ class MapFieldInDynamicMessageTest : public testing::Test { virtual void SetUp() { map_descriptor_ = pool_->FindMessageTypeByName("protobuf_unittest.TestMap"); + recursive_map_descriptor_ = + pool_->FindMessageTypeByName("protobuf_unittest.TestRecursiveMapMessage"); ASSERT_TRUE(map_descriptor_ != NULL); + ASSERT_TRUE(recursive_map_descriptor_ != NULL); map_prototype_ = factory_.GetPrototype(map_descriptor_); } }; @@ -2043,19 +2155,19 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) { // one to a unique value then checking that they all still have those // unique values (i.e. they don't stomp each other). scoped_ptr message(map_prototype_->New()); - MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_); + MapReflectionTester reflection_tester(map_descriptor_); reflection_tester.SetMapFieldsViaReflection(message.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message); } -TEST_F(MapFieldInDynamicMessageTest, Map) { +TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) { // Check that map fields work properly. scoped_ptr message(map_prototype_->New()); // Check set functions. - MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_); - reflection_tester.SetMapFieldsViaReflection(message.get()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(message.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message); } @@ -2066,7 +2178,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { // to test very much here. Just make sure it appears to be working. scoped_ptr message(map_prototype_->New()); - MapTestUtil::MapReflectionTester reflection_tester(map_descriptor_); + MapReflectionTester reflection_tester(map_descriptor_); int initial_space_used = message->SpaceUsed(); @@ -2074,6 +2186,15 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { EXPECT_LT(initial_space_used, message->SpaceUsed()); } +TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) { + TestRecursiveMapMessage from; + (*from.mutable_a())[0]; + string data = from.SerializeAsString(); + google::protobuf::scoped_ptr to( + factory_.GetPrototype(recursive_map_descriptor_)->New()); + ASSERT_TRUE(to->ParseFromString(data)); +} + // ReflectionOps Test =============================================== TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) { @@ -2260,7 +2381,7 @@ TEST(TextFormatMapTest, SerializeAndParse) { TEST(TextFormatMapTest, Sorted) { unittest::TestMap message; - MapTestUtil::MapReflectionTester tester(message.GetDescriptor()); + MapReflectionTester tester(message.GetDescriptor()); tester.SetMapFieldsViaReflection(&message); string expected_text; @@ -2292,7 +2413,8 @@ TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) { data.reserve(128 * 1024); { - NoHeapChecker no_heap; + // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map. + // NoHeapChecker no_heap; unittest::TestArenaMap* from = Arena::CreateMessage(&arena); @@ -2326,6 +2448,22 @@ TEST(ArenaTest, RelfectionInTextFormat) { MapTestUtil::ExpectArenaMapFieldsSet(*to); } +// Make sure the memory allocated for string in map is deallocated. +TEST(ArenaTest, StringMapNoLeak) { + Arena arena; + unittest::TestArenaMap* message = + Arena::CreateMessage(&arena); + string data; + // String with length less than 16 will not be allocated from heap. + int original_capacity = data.capacity(); + while (data.capacity() <= original_capacity) { + data.append("a"); + } + (*message->mutable_map_string_string())[data] = data; + // We rely on heap checkers to detect memory leak for us. + ASSERT_FALSE(message == NULL); +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_test_util.cc b/src/google/protobuf/map_test_util.cc index 1713e3736470c..ae094647bbc3a 100644 --- a/src/google/protobuf/map_test_util.cc +++ b/src/google/protobuf/map_test_util.cc @@ -209,7 +209,7 @@ std::vector MapTestUtil::GetMapEntriesFromRelease( return result; } -MapTestUtil::MapReflectionTester::MapReflectionTester( +MapReflectionTester::MapReflectionTester( const Descriptor* base_descriptor) : base_descriptor_(base_descriptor) { const DescriptorPool* pool = base_descriptor->file()->pool(); @@ -329,14 +329,14 @@ MapTestUtil::MapReflectionTester::MapReflectionTester( } // Shorthand to get a FieldDescriptor for a field of unittest::TestMap. -const FieldDescriptor* MapTestUtil::MapReflectionTester::F(const string& name) { +const FieldDescriptor* MapReflectionTester::F(const string& name) { const FieldDescriptor* result = NULL; result = base_descriptor_->FindFieldByName(name); GOOGLE_CHECK(result != NULL); return result; } -void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection( +void MapReflectionTester::SetMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); Message* sub_message = NULL; @@ -555,7 +555,196 @@ void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection( SetInt32(sub_foreign_message, foreign_c_, 1); } -void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection( +void MapReflectionTester::SetMapFieldsViaMapReflection( + Message* message) { + const Reflection* reflection = message->GetReflection(); + + Message* sub_foreign_message = NULL; + MapValueRef map_val; + + // Add first element. + MapKey map_key; + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetUInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val)); + map_val.SetUInt32Value(0); + + map_key.SetUInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val)); + map_val.SetUInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetUInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val)); + map_val.SetUInt32Value(0); + + map_key.SetUInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val)); + map_val.SetUInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val)); + map_val.SetFloatValue(0.0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val)); + map_val.SetDoubleValue(0.0); + + map_key.SetBoolValue(false); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val)); + map_val.SetBoolValue(false); + + map_key.SetStringValue("0"); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val)); + map_val.SetStringValue("0"); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val)); + map_val.SetStringValue("0"); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val)); + map_val.SetEnumValue(map_enum_bar_->number()); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 0); + + // Add second element + map_key.SetInt32Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + + map_key.SetInt64Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val); + map_val.SetUInt32Value(1); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val); + map_val.SetUInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val); + map_val.SetInt32Value(1); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val); + map_val.SetInt64Value(1); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val); + map_val.SetUInt32Value(1); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val); + map_val.SetUInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val); + map_val.SetInt32Value(1); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val); + map_val.SetInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val); + map_val.SetFloatValue(1.0); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val); + map_val.SetDoubleValue(1.0); + + map_key.SetBoolValue(true); + reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val); + map_val.SetBoolValue(true); + + map_key.SetStringValue("1"); + reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val); + map_val.SetStringValue("1"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val); + map_val.SetStringValue("1"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val); + map_val.SetEnumValue(map_enum_baz_->number()); + + map_key.SetInt32Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 1); +} + +void MapReflectionTester::ClearMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -578,97 +767,103 @@ void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection( reflection->ClearField(message, F("map_int32_foreign_message")); } -void MapTestUtil::MapReflectionTester::ModifyMapFieldsViaReflection( +void MapReflectionTester::ModifyMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); - Message* sub_message; + MapValueRef map_val; Message* sub_foreign_message; - // Find out which one's key is 0. - int size = reflection->FieldSize(*message, F("map_int32_int32")); - int target = 0; - for (int i = 0; i < size; i++) { - const Message& temp_message = reflection - ->GetRepeatedMessage(*message, F("map_int32_int32"), i); - if (temp_message.GetReflection() - ->GetInt32(temp_message, map_int32_int32_key_) == 1) { - target = i; - } - } - - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_int32"), target); - sub_message->GetReflection() - ->SetInt32(sub_message, map_int32_int32_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int64_int64"), target); - sub_message->GetReflection() - ->SetInt64(sub_message, map_int64_int64_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_uint32_uint32"), target); - sub_message->GetReflection() - ->SetUInt32(sub_message, map_uint32_uint32_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_uint64_uint64"), target); - sub_message->GetReflection() - ->SetUInt64(sub_message, map_uint64_uint64_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_sint32_sint32"), target); - sub_message->GetReflection() - ->SetInt32(sub_message, map_sint32_sint32_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_sint64_sint64"), target); - sub_message->GetReflection() - ->SetInt64(sub_message, map_sint64_sint64_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_fixed32_fixed32"), target); - sub_message->GetReflection() - ->SetUInt32(sub_message, map_fixed32_fixed32_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_fixed64_fixed64"), target); - sub_message->GetReflection() - ->SetUInt64(sub_message, map_fixed64_fixed64_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_sfixed32_sfixed32"), target); - sub_message->GetReflection() - ->SetInt32(sub_message, map_sfixed32_sfixed32_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_sfixed64_sfixed64"), target); - sub_message->GetReflection() - ->SetInt64(sub_message, map_sfixed64_sfixed64_val_, 2); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_float"), target); - sub_message->GetReflection() - ->SetFloat(sub_message, map_int32_float_val_, 2.0); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_double"), target); - sub_message->GetReflection() - ->SetDouble(sub_message, map_int32_double_val_, 2.0); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_bool_bool"), target); - sub_message->GetReflection() - ->SetBool(sub_message, map_bool_bool_val_, false); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_string_string"), target); - sub_message->GetReflection() - ->SetString(sub_message, map_string_string_val_, "2"); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_bytes"), target); - sub_message->GetReflection() - ->SetString(sub_message, map_int32_bytes_val_, "2"); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_enum"), target); - sub_message->GetReflection() - ->SetEnum(sub_message, map_int32_enum_val_, map_enum_foo_); - sub_message = reflection - ->MutableRepeatedMessage(message, F("map_int32_foreign_message"), target); - sub_foreign_message = sub_message->GetReflection()-> - MutableMessage(sub_message, map_int32_foreign_message_val_, NULL); - sub_foreign_message->GetReflection()-> - SetInt32(sub_foreign_message, foreign_c_, 2); + // Modify the second element + MapKey map_key; + map_key.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(2); + + map_key.SetUInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val)); + map_val.SetUInt32Value(2); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val); + map_val.SetUInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val); + map_val.SetInt64Value(2); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val); + map_val.SetUInt32Value(2); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val); + map_val.SetUInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val); + map_val.SetInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val); + map_val.SetFloatValue(2.0); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val); + map_val.SetDoubleValue(2.0); + + map_key.SetBoolValue(true); + reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val); + map_val.SetBoolValue(false); + + map_key.SetStringValue("1"); + reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val); + map_val.SetStringValue("2"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val); + map_val.SetStringValue("2"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val); + map_val.SetEnumValue(map_enum_foo_->number()); + + map_key.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 2); } -void MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection( +void MapReflectionTester::RemoveLastMapsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -681,7 +876,7 @@ void MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection( } } -void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection( +void MapReflectionTester::ReleaseLastMapsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -699,7 +894,7 @@ void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection( } } -void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) { +void MapReflectionTester::SwapMapsViaReflection(Message* message) { const Reflection* reflection = message->GetReflection(); vector output; reflection->ListFields(*message, &output); @@ -710,7 +905,7 @@ void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) { } } -void MapTestUtil::MapReflectionTester:: +void MapReflectionTester:: MutableUnknownFieldsOfMapFieldsViaReflection(Message* message) { const Reflection* reflection = message->GetReflection(); Message* sub_message = NULL; @@ -768,11 +963,12 @@ void MapTestUtil::MapReflectionTester:: NULL); } -void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( +void MapReflectionTester::ExpectMapFieldsSetViaReflection( const Message& message) { string scratch; const Reflection* reflection = message.GetReflection(); const Message* sub_message; + MapKey map_key; // ----------------------------------------------------------------- @@ -799,6 +995,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i); int32 key = sub_message->GetReflection()->GetInt32( @@ -806,6 +1003,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_int32_int32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_int32_int32"), map_key)); } } { @@ -813,6 +1014,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i); int64 key = sub_message->GetReflection()->GetInt64( @@ -820,6 +1022,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_int64_int64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_int64_int64"), map_key)); } } { @@ -827,6 +1033,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i); uint32 key = sub_message->GetReflection()->GetUInt32( @@ -834,6 +1041,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint32 val = sub_message->GetReflection()->GetUInt32( *sub_message, map_uint32_uint32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt32Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_uint32_uint32"), map_key)); } } { @@ -848,6 +1059,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint64 val = sub_message->GetReflection()->GetUInt64( *sub_message, map_uint64_uint64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt64Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_uint64_uint64"), map_key)); } } { @@ -862,6 +1077,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_sint32_sint32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sint32_sint32"), map_key)); } } { @@ -876,6 +1095,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_sint64_sint64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sint64_sint64"), map_key)); } } { @@ -890,6 +1113,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint32 val = sub_message->GetReflection()->GetUInt32( *sub_message, map_fixed32_fixed32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_fixed32_fixed32"), map_key)); } } { @@ -904,6 +1131,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint64 val = sub_message->GetReflection()->GetUInt64( *sub_message, map_fixed64_fixed64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_fixed64_fixed64"), map_key)); } } { @@ -918,6 +1149,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_sfixed32_sfixed32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sfixed32_sfixed32"), map_key)); } } { @@ -932,6 +1167,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_sfixed64_sfixed64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sfixed64_sfixed64"), map_key)); } } { @@ -946,6 +1185,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( float val = sub_message->GetReflection()->GetFloat( *sub_message, map_int32_float_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_float"), map_key)); } } { @@ -960,6 +1203,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( double val = sub_message->GetReflection()->GetDouble( *sub_message, map_int32_double_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_double"), map_key)); } } { @@ -974,6 +1221,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( bool val = sub_message->GetReflection()->GetBool( *sub_message, map_bool_bool_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetBoolValue(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_bool_bool"), map_key)); } } { @@ -988,6 +1239,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( string val = sub_message->GetReflection()->GetString( *sub_message, map_string_string_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetStringValue(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_string_string"), map_key)); } } { @@ -1002,6 +1257,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( string val = sub_message->GetReflection()->GetString( *sub_message, map_int32_bytes_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_bytes"), map_key)); } } { @@ -1016,6 +1275,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum( *sub_message, map_int32_enum_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_enum"), map_key)); } } { @@ -1032,11 +1295,245 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = foreign_message.GetReflection()->GetInt32( foreign_message, foreign_c_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_foreign_message"), map_key)); } } } -void MapTestUtil::MapReflectionTester::ExpectClearViaReflection( +void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator( + Message* message) { + string scratch; + string serialized; + const Reflection* reflection = message->GetReflection(); + + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum"))); + ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message"))); + + { + std::map map; + map[0] = 0; + map[1] = 1; + int size = 0; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32")); + iter != reflection->MapEnd(message, F("map_int32_int32")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + EXPECT_EQ(size, 2); + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64")); + iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt64Value()], + iter.GetValueRef().GetInt64Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_uint32_uint32")); + iter != reflection->MapEnd(message, F("map_uint32_uint32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], + iter.GetValueRef().GetUInt32Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_uint64_uint64")); + iter != reflection->MapEnd(message, F("map_uint64_uint64")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], + iter.GetValueRef().GetUInt64Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sint32_sint32")); + iter != reflection->MapEnd(message, F("map_sint32_sint32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sint64_sint64")); + iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt64Value()], + iter.GetValueRef().GetInt64Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_fixed32_fixed32")); + iter != reflection->MapEnd(message, F("map_fixed32_fixed32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], + iter.GetValueRef().GetUInt32Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_fixed64_fixed64")); + iter != reflection->MapEnd(message, F("map_fixed64_fixed64")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], + iter.GetValueRef().GetUInt64Value()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sfixed32_sfixed32")); + iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + } + { + std::map map; + map[0] = 0.0; + map[1] = 1.0; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float")); + iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetFloatValue()); + } + } + { + std::map map; + map[0] = 0.0; + map[1] = 1.0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_int32_double")); + iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetDoubleValue()); + } + } + { + std::map map; + map[false] = false; + map[true] = true; + for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool")); + iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetBoolValue()], + iter.GetValueRef().GetBoolValue()); + } + } + { + std::map map; + map["0"] = "0"; + map["1"] = "1"; + int size = 0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_string_string")); + iter != reflection->MapEnd(message, F("map_string_string")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + EXPECT_EQ(map[iter.GetKey().GetStringValue()], + iter.GetValueRef().GetStringValue()); + } + EXPECT_EQ(size, 2); + } + { + std::map map; + map[0] = "0"; + map[1] = "1"; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes")); + iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetStringValue()); + } + } + { + std::map map; + map[0] = map_enum_bar_; + map[1] = map_enum_baz_; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum")); + iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(), + iter.GetValueRef().GetEnumValue()); + } + } + { + std::map map; + map[0] = 0; + map[1] = 1; + int size = 0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_int32_foreign_message")); + iter != reflection->MapEnd(message, F("map_int32_foreign_message")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + const Message& sub_message = iter.GetValueRef().GetMessageValue(); + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + sub_message.GetReflection()->GetInt32(sub_message, foreign_c_)); + } + EXPECT_EQ(size, 2); + } +} + +void MapReflectionTester::ExpectClearViaReflection( const Message& message) { const Reflection* reflection = message.GetReflection(); // Map fields are empty. @@ -1059,7 +1556,46 @@ void MapTestUtil::MapReflectionTester::ExpectClearViaReflection( EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message"))); } -void MapTestUtil::MapReflectionTester::ExpectMapEntryClearViaReflection( +void MapReflectionTester::ExpectClearViaReflectionIterator( + Message* message) { + const Reflection* reflection = message->GetReflection(); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) == + reflection->MapEnd(message, F("map_int32_int32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) == + reflection->MapEnd(message, F("map_int64_int64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) == + reflection->MapEnd(message, F("map_uint32_uint32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) == + reflection->MapEnd(message, F("map_uint64_uint64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) == + reflection->MapEnd(message, F("map_sint32_sint32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) == + reflection->MapEnd(message, F("map_sint64_sint64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) == + reflection->MapEnd(message, F("map_fixed32_fixed32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) == + reflection->MapEnd(message, F("map_fixed64_fixed64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) == + reflection->MapEnd(message, F("map_sfixed32_sfixed32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) == + reflection->MapEnd(message, F("map_sfixed64_sfixed64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) == + reflection->MapEnd(message, F("map_int32_float"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) == + reflection->MapEnd(message, F("map_int32_double"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) == + reflection->MapEnd(message, F("map_bool_bool"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) == + reflection->MapEnd(message, F("map_string_string"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) == + reflection->MapEnd(message, F("map_int32_bytes"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) == + reflection->MapEnd(message, F("map_int32_enum"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) == + reflection->MapEnd(message, F("map_int32_foreign_message"))); +} + +void MapReflectionTester::ExpectMapEntryClearViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); const Message* sub_message; diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h index f437e33ed8c70..107a639d81dca 100644 --- a/src/google/protobuf/map_test_util.h +++ b/src/google/protobuf/map_test_util.h @@ -83,71 +83,74 @@ class MapTestUtil { // Get pointers of map entries from release. static std::vector GetMapEntriesFromRelease( unittest::TestMap* message); +}; - // Like above, but use the reflection interface. - class MapReflectionTester { - public: - // base_descriptor must be a descriptor for TestMap, which is used for - // MapReflectionTester to fetch the FieldDescriptors needed to use the - // reflection interface. - explicit MapReflectionTester(const Descriptor* base_descriptor); - - void SetMapFieldsViaReflection(Message* message); - void ClearMapFieldsViaReflection(Message* message); - void ModifyMapFieldsViaReflection(Message* message); - void RemoveLastMapsViaReflection(Message* message); - void ReleaseLastMapsViaReflection(Message* message); - void SwapMapsViaReflection(Message* message); - void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message); - void ExpectMapFieldsSetViaReflection(const Message& message); - void ExpectClearViaReflection(const Message& message); - void ExpectMapEntryClearViaReflection(Message* message); - - private: - const FieldDescriptor* F(const string& name); - - const Descriptor* base_descriptor_; - - const EnumValueDescriptor* map_enum_bar_; - const EnumValueDescriptor* map_enum_baz_; - const EnumValueDescriptor* map_enum_foo_; - - const FieldDescriptor* foreign_c_; - const FieldDescriptor* map_int32_int32_key_; - const FieldDescriptor* map_int32_int32_val_; - const FieldDescriptor* map_int64_int64_key_; - const FieldDescriptor* map_int64_int64_val_; - const FieldDescriptor* map_uint32_uint32_key_; - const FieldDescriptor* map_uint32_uint32_val_; - const FieldDescriptor* map_uint64_uint64_key_; - const FieldDescriptor* map_uint64_uint64_val_; - const FieldDescriptor* map_sint32_sint32_key_; - const FieldDescriptor* map_sint32_sint32_val_; - const FieldDescriptor* map_sint64_sint64_key_; - const FieldDescriptor* map_sint64_sint64_val_; - const FieldDescriptor* map_fixed32_fixed32_key_; - const FieldDescriptor* map_fixed32_fixed32_val_; - const FieldDescriptor* map_fixed64_fixed64_key_; - const FieldDescriptor* map_fixed64_fixed64_val_; - const FieldDescriptor* map_sfixed32_sfixed32_key_; - const FieldDescriptor* map_sfixed32_sfixed32_val_; - const FieldDescriptor* map_sfixed64_sfixed64_key_; - const FieldDescriptor* map_sfixed64_sfixed64_val_; - const FieldDescriptor* map_int32_float_key_; - const FieldDescriptor* map_int32_float_val_; - const FieldDescriptor* map_int32_double_key_; - const FieldDescriptor* map_int32_double_val_; - const FieldDescriptor* map_bool_bool_key_; - const FieldDescriptor* map_bool_bool_val_; - const FieldDescriptor* map_string_string_key_; - const FieldDescriptor* map_string_string_val_; - const FieldDescriptor* map_int32_bytes_key_; - const FieldDescriptor* map_int32_bytes_val_; - const FieldDescriptor* map_int32_enum_key_; - const FieldDescriptor* map_int32_enum_val_; - const FieldDescriptor* map_int32_foreign_message_key_; - const FieldDescriptor* map_int32_foreign_message_val_; - }; +// Like above, but use the reflection interface. +class MapReflectionTester { + public: + // base_descriptor must be a descriptor for TestMap, which is used for + // MapReflectionTester to fetch the FieldDescriptors needed to use the + // reflection interface. + explicit MapReflectionTester(const Descriptor* base_descriptor); + + void SetMapFieldsViaReflection(Message* message); + void SetMapFieldsViaMapReflection(Message* message); + void ClearMapFieldsViaReflection(Message* message); + void ModifyMapFieldsViaReflection(Message* message); + void RemoveLastMapsViaReflection(Message* message); + void ReleaseLastMapsViaReflection(Message* message); + void SwapMapsViaReflection(Message* message); + void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message); + void ExpectMapFieldsSetViaReflection(const Message& message); + void ExpectMapFieldsSetViaReflectionIterator(Message* message); + void ExpectClearViaReflection(const Message& message); + void ExpectClearViaReflectionIterator(Message* message); + void ExpectMapEntryClearViaReflection(Message* message); + + private: + const FieldDescriptor* F(const string& name); + + const Descriptor* base_descriptor_; + + const EnumValueDescriptor* map_enum_bar_; + const EnumValueDescriptor* map_enum_baz_; + const EnumValueDescriptor* map_enum_foo_; + + const FieldDescriptor* foreign_c_; + const FieldDescriptor* map_int32_int32_key_; + const FieldDescriptor* map_int32_int32_val_; + const FieldDescriptor* map_int64_int64_key_; + const FieldDescriptor* map_int64_int64_val_; + const FieldDescriptor* map_uint32_uint32_key_; + const FieldDescriptor* map_uint32_uint32_val_; + const FieldDescriptor* map_uint64_uint64_key_; + const FieldDescriptor* map_uint64_uint64_val_; + const FieldDescriptor* map_sint32_sint32_key_; + const FieldDescriptor* map_sint32_sint32_val_; + const FieldDescriptor* map_sint64_sint64_key_; + const FieldDescriptor* map_sint64_sint64_val_; + const FieldDescriptor* map_fixed32_fixed32_key_; + const FieldDescriptor* map_fixed32_fixed32_val_; + const FieldDescriptor* map_fixed64_fixed64_key_; + const FieldDescriptor* map_fixed64_fixed64_val_; + const FieldDescriptor* map_sfixed32_sfixed32_key_; + const FieldDescriptor* map_sfixed32_sfixed32_val_; + const FieldDescriptor* map_sfixed64_sfixed64_key_; + const FieldDescriptor* map_sfixed64_sfixed64_val_; + const FieldDescriptor* map_int32_float_key_; + const FieldDescriptor* map_int32_float_val_; + const FieldDescriptor* map_int32_double_key_; + const FieldDescriptor* map_int32_double_val_; + const FieldDescriptor* map_bool_bool_key_; + const FieldDescriptor* map_bool_bool_val_; + const FieldDescriptor* map_string_string_key_; + const FieldDescriptor* map_string_string_val_; + const FieldDescriptor* map_int32_bytes_key_; + const FieldDescriptor* map_int32_bytes_val_; + const FieldDescriptor* map_int32_enum_key_; + const FieldDescriptor* map_int32_enum_val_; + const FieldDescriptor* map_int32_foreign_message_key_; + const FieldDescriptor* map_int32_foreign_message_val_; }; } // namespace protobuf diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h index 5e7882a1d1730..7e8757ed083ea 100644 --- a/src/google/protobuf/map_test_util_impl.h +++ b/src/google/protobuf/map_test_util_impl.h @@ -31,6 +31,7 @@ #ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__ #define GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__ +#include #include @@ -167,8 +168,11 @@ void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) { (*message->mutable_map_int32_float())[0] = 0.0; (*message->mutable_map_int32_double())[0] = 0.0; (*message->mutable_map_bool_bool())[0] = false; + (*message->mutable_map_string_string())["0"] = "0"; + (*message->mutable_map_int32_bytes())[0] = "0"; (*message->mutable_map_int32_enum())[0] = enum_value0; (*message->mutable_map_int32_foreign_message())[0].set_c(0); + (*message->mutable_map_int32_foreign_message_no_arena())[0].set_c(0); // Add second element (*message->mutable_map_int32_int32())[1] = 1; @@ -184,8 +188,11 @@ void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) { (*message->mutable_map_int32_float())[1] = 1.0; (*message->mutable_map_int32_double())[1] = 1.0; (*message->mutable_map_bool_bool())[1] = true; + (*message->mutable_map_string_string())["1"] = "1"; + (*message->mutable_map_int32_bytes())[1] = "1"; (*message->mutable_map_int32_enum())[1] = enum_value1; (*message->mutable_map_int32_foreign_message())[1].set_c(1); + (*message->mutable_map_int32_foreign_message_no_arena())[1].set_c(1); } template @@ -329,8 +336,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { EXPECT_EQ(2, message.map_int32_float().size()); EXPECT_EQ(2, message.map_int32_double().size()); EXPECT_EQ(2, message.map_bool_bool().size()); + EXPECT_EQ(2, message.map_string_string().size()); + EXPECT_EQ(2, message.map_int32_bytes().size()); EXPECT_EQ(2, message.map_int32_enum().size()); EXPECT_EQ(2, message.map_int32_foreign_message().size()); + EXPECT_EQ(2, message.map_int32_foreign_message_no_arena().size()); EXPECT_EQ(0, message.map_int32_int32().at(0)); EXPECT_EQ(0, message.map_int64_int64().at(0)); @@ -345,8 +355,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { EXPECT_EQ(0, message.map_int32_float().at(0)); EXPECT_EQ(0, message.map_int32_double().at(0)); EXPECT_EQ(false, message.map_bool_bool().at(0)); + EXPECT_EQ("0", message.map_string_string().at("0")); + EXPECT_EQ("0", message.map_int32_bytes().at(0)); EXPECT_EQ(enum_value0, message.map_int32_enum().at(0)); EXPECT_EQ(0, message.map_int32_foreign_message().at(0).c()); + EXPECT_EQ(0, message.map_int32_foreign_message_no_arena().at(0).c()); EXPECT_EQ(1, message.map_int32_int32().at(1)); EXPECT_EQ(1, message.map_int64_int64().at(1)); @@ -361,8 +374,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { EXPECT_EQ(1, message.map_int32_float().at(1)); EXPECT_EQ(1, message.map_int32_double().at(1)); EXPECT_EQ(true, message.map_bool_bool().at(1)); + EXPECT_EQ("1", message.map_string_string().at("1")); + EXPECT_EQ("1", message.map_int32_bytes().at(1)); EXPECT_EQ(enum_value1, message.map_int32_enum().at(1)); EXPECT_EQ(1, message.map_int32_foreign_message().at(1).c()); + EXPECT_EQ(1, message.map_int32_foreign_message_no_arena().at(1).c()); } template diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h index ffdb6dfbaccf3..5040e60527695 100644 --- a/src/google/protobuf/map_type_handler.h +++ b/src/google/protobuf/map_type_handler.h @@ -54,22 +54,6 @@ struct MapIf { typedef FalseType type; }; -// In MapField, string and message are stored as pointer while others are stored -// as object. However, google::protobuf::Map has unified api. Functions in this class -// convert key/value to type wanted in api regardless how it's stored -// internally. -template -class MapCommonTypeHandler { - public: - static inline Type& Reference(Type* x) { return *x; } - static inline Type& Reference(Type& x) { return x; } - static inline const Type& Reference(const Type& x) { return x; } - static inline Type* Pointer(Type* x) { return x; } - static inline Type* Pointer(Type& x) { return &x; } - static inline const Type* Pointer(const Type* x) { return x; } - static inline const Type* Pointer(const Type& x) { return &x; } -}; - // In proto2 Map, enum needs to be initialized to given default value, while // other types' default value can be inferred from the type. template @@ -110,174 +94,29 @@ template class MapArenaMessageCreator { public: static inline Type* CreateMessage(Arena* arena) { - return new Type; - } -}; - -// Handlers for key/value stored type in MapField. ================== - -// Handler for message -template -class MapCppTypeHandler : public MapCommonTypeHandler { - public: - static const bool kIsStringOrMessage = true; - // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding - // those already calculate in sizeof(MapField). - static int SpaceUsedInMapEntry(const Type* value) { - return value->SpaceUsed(); - } - // Return bytes used by value in Map. - static int SpaceUsedInMap(const Type& value) { return value.SpaceUsed(); } - static inline void Clear(Type** value) { - if (*value != NULL) (*value)->Clear(); - } - static inline void ClearMaybeByDefaultEnum(Type** value, - int default_enum_value) { - if (*value != NULL) (*value)->Clear(); - } - static inline void Merge(const Type& from, Type** to) { - (*to)->MergeFrom(from); - } - - static void Delete(const Type* ptr) { delete ptr; } - - // Assign default value to given instance. - static inline void AssignDefaultValue(Type** value) { - *value = const_cast(&Type::default_instance()); - } - // Initialize value when constructing MapEntry - static inline void Initialize(Type** x, Arena* arena) { *x = NULL; } - // Same as above, but use default_enum_value to initialize enum type value. - static inline void InitializeMaybeByDefaultEnum( - Type** x, int default_enum_value, Arena* arena) { - *x = NULL; - } - // Initialize value for the first time mutable accessor is called. - static inline void EnsureMutable(Type** value, Arena* arena) { - if (*value == NULL) { - *value = - MapArenaMessageCreator:: - type::value>::CreateMessage(arena); - } - } - // Return default instance if value is not initialized when calling const - // reference accessor. - static inline const Type& DefaultIfNotInitialized(const Type* value, - const Type* default_value) { - return value != NULL ? *value : *default_value; - } - // Check if all required fields have values set. - static inline bool IsInitialized(Type* value) { - return value->IsInitialized(); - } -}; - -// Handler for string. -template <> -class MapCppTypeHandler : public MapCommonTypeHandler { - public: - static const bool kIsStringOrMessage = true; - static inline void Merge(const string& from, string** to) { **to = from; } - static inline void Clear(string** value) { (*value)->clear(); } - static inline void ClearMaybeByDefaultEnum(string** value, int default_enum) { - (*value)->clear(); - } - static inline int SpaceUsedInMapEntry(const string* value) { - return sizeof(*value) + StringSpaceUsedExcludingSelf(*value); - } - static inline int SpaceUsedInMap(const string& value) { - return sizeof(value) + StringSpaceUsedExcludingSelf(value); - } - static void Delete(const string* ptr) { - if (ptr != &::google::protobuf::internal::GetEmptyString()) delete ptr; - } - static inline void AssignDefaultValue(string** value) {} - static inline void Initialize(string** value, Arena* arena) { - *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString()); - if (arena != NULL) arena->Own(*value); - } - static inline void InitializeMaybeByDefaultEnum( - string** value, int default_enum_value, Arena* arena) { - *value = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyString()); - if (arena != NULL) arena->Own(*value); + return Arena::Create(arena); } - static inline void EnsureMutable(string** value, Arena* arena) { - if (*value == &::google::protobuf::internal::GetEmptyString()) { - *value = Arena::Create(arena); - } - } - static inline const string& DefaultIfNotInitialized( - const string* value, - const string* default_value) { - return value != default_value ? *value : *default_value; - } - static inline bool IsInitialized(string* value) { return true; } }; -// Base class for primitive type handlers. -template -class MapPrimitiveTypeHandler : public MapCommonTypeHandler { - public: - static const bool kIsStringOrMessage = false; - static inline void Delete(const Type& x) {} - static inline void Merge(const Type& from, Type* to) { *to = from; } - static inline int SpaceUsedInMapEntry(const Type& value) { return 0; } - static inline int SpaceUsedInMap(const Type& value) { return sizeof(Type); } - static inline void AssignDefaultValue(Type* value) {} - static inline const Type& DefaultIfNotInitialized( - const Type& value, const Type& default_value) { - return value; - } - static inline bool IsInitialized(const Type& value) { return true; } -}; - -// Handlers for primitive types. -#define PRIMITIVE_HANDLER(CType) \ - template <> \ - class MapCppTypeHandler : public MapPrimitiveTypeHandler { \ - public: \ - static inline void Clear(CType* value) { *value = 0; } \ - static inline void ClearMaybeByDefaultEnum(CType* value, \ - int default_enum_value) { \ - *value = static_cast(default_enum_value); \ - } \ - static inline void Initialize(CType* value, Arena* arena) { *value = 0; } \ - static inline void InitializeMaybeByDefaultEnum(CType* value, \ - int default_enum_value, \ - Arena* arena) { \ - *value = static_cast(default_enum_value); \ - } \ - static inline void EnsureMutable(CType* value, Arena* arena) {} \ - }; - -PRIMITIVE_HANDLER(int32 ) -PRIMITIVE_HANDLER(int64 ) -PRIMITIVE_HANDLER(uint32) -PRIMITIVE_HANDLER(uint64) -PRIMITIVE_HANDLER(double) -PRIMITIVE_HANDLER(float ) -PRIMITIVE_HANDLER(bool ) - -#undef PRIMITIVE_HANDLER - // Define constants for given wire field type -template +template class MapWireFieldTypeTraits {}; -#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \ - template <> \ - class MapWireFieldTypeTraits { \ - public: \ - typedef CType CppType; \ - static const bool kIsMessage = IsMessage; \ - static const bool kIsEnum = IsEnum; \ - static const WireFormatLite::WireType kWireType = \ - WireFormatLite::WIRETYPE_##WireFormatType; \ +#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \ + template \ + class MapWireFieldTypeTraits { \ + public: \ + static const bool kIsMessage = IsMessage; \ + static const bool kIsEnum = IsEnum; \ + typedef typename MapIf::type TypeOnMemory; \ + typedef typename MapIf::type MapEntryAccessorType; \ + static const WireFormatLite::WireType kWireType = \ + WireFormatLite::WIRETYPE_##WireFormatType; \ }; -TYPE_TRAITS(MESSAGE , MessageLite, LENGTH_DELIMITED, true, false) -TYPE_TRAITS(STRING , string , LENGTH_DELIMITED, false, false) -TYPE_TRAITS(BYTES , string , LENGTH_DELIMITED, false, false) +TYPE_TRAITS(MESSAGE , Type, LENGTH_DELIMITED, true, false) +TYPE_TRAITS(STRING , ArenaStringPtr, LENGTH_DELIMITED, false, false) +TYPE_TRAITS(BYTES , ArenaStringPtr , LENGTH_DELIMITED, false, false) TYPE_TRAITS(INT64 , int64 , VARINT , false, false) TYPE_TRAITS(UINT64 , uint64 , VARINT , false, false) TYPE_TRAITS(INT32 , int32 , VARINT , false, false) @@ -295,46 +134,149 @@ TYPE_TRAITS(BOOL , bool , VARINT , false, false) #undef TYPE_TRAITS -template -class MapWireFieldTypeHandler { +template +class MapTypeHandler {}; + +template +class MapTypeHandler { public: + // Enum type cannot be used for MapTypeHandler::Read. Define a type which will + // replace Enum with int. + typedef typename MapWireFieldTypeTraits::MapEntryAccessorType MapEntryAccessorType; // Internal stored type in MapEntryLite for given wire field type. - typedef typename MapWireFieldTypeTraits::CppType CppType; + typedef typename MapWireFieldTypeTraits::TypeOnMemory TypeOnMemory; // Corresponding wire type for field type. static const WireFormatLite::WireType kWireType = - MapWireFieldTypeTraits::kWireType; + MapWireFieldTypeTraits::kWireType; // Whether wire type is for message. - static const bool kIsMessage = MapWireFieldTypeTraits::kIsMessage; + static const bool kIsMessage = + MapWireFieldTypeTraits::kIsMessage; // Whether wire type is for enum. - static const bool kIsEnum = MapWireFieldTypeTraits::kIsEnum; + static const bool kIsEnum = + MapWireFieldTypeTraits::kIsEnum; // Functions used in parsing and serialization. =================== - template - static inline int ByteSize(const ValueType& value); - template - static inline int GetCachedSize(const ValueType& value); - template - static inline bool Read(io::CodedInputStream* input, ValueType* value); - static inline void Write(int field, const CppType& value, + static inline int ByteSize(const MapEntryAccessorType& value); + static inline int GetCachedSize(const MapEntryAccessorType& value); + static inline bool Read(io::CodedInputStream* input, + MapEntryAccessorType* value); + static inline void Write(int field, const MapEntryAccessorType& value, io::CodedOutputStream* output); - static inline uint8* WriteToArray(int field, const CppType& value, + static inline uint8* WriteToArray(int field, + const MapEntryAccessorType& value, uint8* output); + + // Functions to manipulate data on memory. ======================== + static inline const Type& GetExternalReference(const Type* value); + static inline void DeleteNoArena(const Type* x); + static inline void Merge(const Type& from, Type** to, Arena* arena); + static inline void Clear(Type** value, Arena* arena); + static inline void ClearMaybeByDefaultEnum(Type** value, Arena* arena, + int default_enum_value); + static inline void Initialize(Type** x, Arena* arena); + + static inline void InitializeMaybeByDefaultEnum(Type** x, + int default_enum_value, + Arena* arena); + static inline Type* EnsureMutable(Type** value, Arena* arena); + // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding + // those already calculate in sizeof(MapField). + static inline int SpaceUsedInMapEntry(const Type* value); + // Return bytes used by value in Map. + static inline int SpaceUsedInMap(const Type& value); + // Assign default value to given instance. + static inline void AssignDefaultValue(Type** value); + // Return default instance if value is not initialized when calling const + // reference accessor. + static inline const Type& DefaultIfNotInitialized( + const Type* value, const Type* default_value); + // Check if all required fields have values set. + static inline bool IsInitialized(Type* value); }; -template <> -template -inline int MapWireFieldTypeHandler::ByteSize( - const ValueType& value) { +#define MAP_HANDLER(FieldType) \ + template \ + class MapTypeHandler { \ + public: \ + typedef typename MapWireFieldTypeTraits::MapEntryAccessorType \ + MapEntryAccessorType; \ + typedef typename MapWireFieldTypeTraits::TypeOnMemory TypeOnMemory; \ + static const WireFormatLite::WireType kWireType = \ + MapWireFieldTypeTraits::kWireType; \ + static const bool kIsMessage = \ + MapWireFieldTypeTraits::kIsMessage; \ + static const bool kIsEnum = \ + MapWireFieldTypeTraits::kIsEnum; \ + static inline int ByteSize(const MapEntryAccessorType& value); \ + static inline int GetCachedSize(const MapEntryAccessorType& value); \ + static inline bool Read(io::CodedInputStream* input, \ + MapEntryAccessorType* value); \ + static inline void Write(int field, const MapEntryAccessorType& value, \ + io::CodedOutputStream* output); \ + static inline uint8* WriteToArray(int field, \ + const MapEntryAccessorType& value, \ + uint8* output); \ + static inline const MapEntryAccessorType& GetExternalReference( \ + const TypeOnMemory& value); \ + static inline void DeleteNoArena(const TypeOnMemory& x); \ + static inline void Merge(const MapEntryAccessorType& from, \ + TypeOnMemory* to, Arena* arena); \ + static inline void Clear(TypeOnMemory* value, Arena* arena); \ + static inline void ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum); \ + static inline int SpaceUsedInMapEntry(const TypeOnMemory& value); \ + static inline int SpaceUsedInMap(const TypeOnMemory& value); \ + static inline int SpaceUsedInMap(const string& value); \ + static inline void AssignDefaultValue(TypeOnMemory* value); \ + static inline const MapEntryAccessorType& DefaultIfNotInitialized( \ + const TypeOnMemory& value, const TypeOnMemory& default_value); \ + static inline bool IsInitialized(const TypeOnMemory& value); \ + static void DeleteNoArena(TypeOnMemory& value); \ + static inline void Initialize(TypeOnMemory* value, Arena* arena); \ + static inline void InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena); \ + static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value, \ + Arena* arena); \ + }; +MAP_HANDLER(STRING) +MAP_HANDLER(BYTES) +MAP_HANDLER(INT64) +MAP_HANDLER(UINT64) +MAP_HANDLER(INT32) +MAP_HANDLER(UINT32) +MAP_HANDLER(SINT64) +MAP_HANDLER(SINT32) +MAP_HANDLER(ENUM) +MAP_HANDLER(DOUBLE) +MAP_HANDLER(FLOAT) +MAP_HANDLER(FIXED64) +MAP_HANDLER(FIXED32) +MAP_HANDLER(SFIXED64) +MAP_HANDLER(SFIXED32) +MAP_HANDLER(BOOL) +#undef MAP_HANDLER + +template +inline int +MapTypeHandler::ByteSize( + const MapEntryAccessorType& value) { return WireFormatLite::MessageSizeNoVirtual(value); } -#define BYTE_SIZE(FieldType, DeclaredType) \ - template <> \ - template \ - inline int \ - MapWireFieldTypeHandler::ByteSize( \ - const ValueType& value) { \ - return WireFormatLite::DeclaredType##Size(value); \ +#define BYTE_SIZE(FieldType, DeclaredType) \ + template \ + inline int MapTypeHandler::ByteSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::DeclaredType##Size(value); \ } BYTE_SIZE(STRING, String) @@ -349,13 +291,11 @@ BYTE_SIZE(ENUM , Enum) #undef BYTE_SIZE -#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \ - template <> \ - template \ - inline int \ - MapWireFieldTypeHandler::ByteSize( \ - const ValueType& value) { \ - return WireFormatLite::k##DeclaredType##Size; \ +#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \ + template \ + inline int MapTypeHandler::ByteSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::k##DeclaredType##Size; \ } FIXED_BYTE_SIZE(DOUBLE , Double) @@ -368,20 +308,19 @@ FIXED_BYTE_SIZE(BOOL , Bool) #undef FIXED_BYTE_SIZE -template <> -template -inline int MapWireFieldTypeHandler< - WireFormatLite::TYPE_MESSAGE>::GetCachedSize(const ValueType& value) { +template +inline int +MapTypeHandler::GetCachedSize( + const MapEntryAccessorType& value) { return WireFormatLite::LengthDelimitedSize(value.GetCachedSize()); } -#define GET_CACHED_SIZE(FieldType, DeclaredType) \ - template <> \ - template \ - inline int \ - MapWireFieldTypeHandler::GetCachedSize( \ - const ValueType& value) { \ - return WireFormatLite::DeclaredType##Size(value); \ +#define GET_CACHED_SIZE(FieldType, DeclaredType) \ + template \ + inline int \ + MapTypeHandler::GetCachedSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::DeclaredType##Size(value); \ } GET_CACHED_SIZE(STRING, String) @@ -396,13 +335,12 @@ GET_CACHED_SIZE(ENUM , Enum) #undef GET_CACHED_SIZE -#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \ - template <> \ - template \ - inline int \ - MapWireFieldTypeHandler::GetCachedSize( \ - const ValueType& value) { \ - return WireFormatLite::k##DeclaredType##Size; \ +#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \ + template \ + inline int \ + MapTypeHandler::GetCachedSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::k##DeclaredType##Size; \ } GET_FIXED_CACHED_SIZE(DOUBLE , Double) @@ -415,30 +353,31 @@ GET_FIXED_CACHED_SIZE(BOOL , Bool) #undef GET_FIXED_CACHED_SIZE -template <> -inline void MapWireFieldTypeHandler::Write( - int field, const MessageLite& value, io::CodedOutputStream* output) { +template +inline void MapTypeHandler::Write( + int field, const MapEntryAccessorType& value, + io::CodedOutputStream* output) { WireFormatLite::WriteMessageMaybeToArray(field, value, output); } -template <> +template inline uint8* -MapWireFieldTypeHandler::WriteToArray( - int field, const MessageLite& value, uint8* output) { +MapTypeHandler::WriteToArray( + int field, const MapEntryAccessorType& value, uint8* output) { return WireFormatLite::WriteMessageToArray(field, value, output); } #define WRITE_METHOD(FieldType, DeclaredType) \ - template <> \ - inline void \ - MapWireFieldTypeHandler::Write( \ - int field, const CppType& value, io::CodedOutputStream* output) { \ + template \ + inline void MapTypeHandler::Write( \ + int field, const MapEntryAccessorType& value, \ + io::CodedOutputStream* output) { \ return WireFormatLite::Write##DeclaredType(field, value, output); \ } \ - template <> \ + template \ inline uint8* \ - MapWireFieldTypeHandler::WriteToArray( \ - int field, const CppType& value, uint8* output) { \ + MapTypeHandler::WriteToArray( \ + int field, const MapEntryAccessorType& value, uint8* output) { \ return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \ } @@ -461,35 +400,31 @@ WRITE_METHOD(BOOL , Bool) #undef WRITE_METHOD -template <> -template -inline bool MapWireFieldTypeHandler::Read( - io::CodedInputStream* input, ValueType* value) { +template +inline bool MapTypeHandler::Read( + io::CodedInputStream* input, MapEntryAccessorType* value) { return WireFormatLite::ReadMessageNoVirtual(input, value); } -template <> -template -inline bool MapWireFieldTypeHandler::Read( - io::CodedInputStream* input, ValueType* value) { +template +inline bool MapTypeHandler::Read( + io::CodedInputStream* input, MapEntryAccessorType* value) { return WireFormatLite::ReadString(input, value); } -template <> -template -inline bool MapWireFieldTypeHandler::Read( - io::CodedInputStream* input, ValueType* value) { +template +inline bool MapTypeHandler::Read( + io::CodedInputStream* input, MapEntryAccessorType* value) { return WireFormatLite::ReadBytes(input, value); } -#define READ_METHOD(FieldType) \ - template <> \ - template \ - inline bool MapWireFieldTypeHandler::Read( \ - io::CodedInputStream* input, ValueType* value) { \ - return WireFormatLite::ReadPrimitive( \ - input, value); \ +#define READ_METHOD(FieldType) \ + template \ + inline bool MapTypeHandler::Read( \ + io::CodedInputStream* input, MapEntryAccessorType* value) { \ + return WireFormatLite::ReadPrimitive( \ + input, value); \ } READ_METHOD(INT64) @@ -509,6 +444,282 @@ READ_METHOD(BOOL) #undef READ_METHOD +// Definition for message handler + +template +inline const Type& +MapTypeHandler::GetExternalReference(const Type* value) { + return *value; +} + +template +inline int +MapTypeHandler::SpaceUsedInMapEntry(const Type* value) { + return value->SpaceUsed(); +} + +template +int MapTypeHandler::SpaceUsedInMap( + const Type& value) { + return value.SpaceUsed(); +} + +template +inline void MapTypeHandler::Clear( + Type** value, Arena* arena) { + if (*value != NULL) (*value)->Clear(); +} +template +inline void +MapTypeHandler::ClearMaybeByDefaultEnum(Type** value, + Arena* arena, + int default_enum_value) { + if (*value != NULL) (*value)->Clear(); +} +template +inline void MapTypeHandler::Merge( + const Type& from, Type** to, Arena* arena) { + (*to)->MergeFrom(from); +} + +template +void MapTypeHandler::DeleteNoArena( + const Type* ptr) { + delete ptr; +} + +template +inline void MapTypeHandler::AssignDefaultValue(Type** value) { + *value = const_cast(&Type::default_instance()); +} + +template +inline void MapTypeHandler::Initialize(Type** x, + Arena* arena) { + *x = NULL; +} + +template +inline void MapTypeHandler:: + InitializeMaybeByDefaultEnum(Type** x, int default_enum_value, + Arena* arena) { + *x = NULL; +} + +template +inline Type* MapTypeHandler::EnsureMutable(Type** value, + Arena* arena) { + if (*value == NULL) { + *value = + MapArenaMessageCreator:: + type::value>::CreateMessage(arena); + } + return *value; +} + +template +inline const Type& MapTypeHandler:: + DefaultIfNotInitialized(const Type* value, const Type* default_value) { + return value != NULL ? *value : *default_value; +} + +template +inline bool MapTypeHandler::IsInitialized(Type* value) { + return value->IsInitialized(); +} + +// Definition for string/bytes handler + +#define STRING_OR_BYTES_HANDLER_FUNCTIONS(FieldType) \ + template \ + inline const typename MapTypeHandler::MapEntryAccessorType& \ + MapTypeHandler::GetExternalReference(const TypeOnMemory& value) { \ + return value.Get(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template \ + inline int \ + MapTypeHandler::SpaceUsedInMapEntry( \ + const TypeOnMemory& value) { \ + return sizeof(value); \ + } \ + template \ + inline int MapTypeHandler::SpaceUsedInMap(const TypeOnMemory& value) { \ + return sizeof(value); \ + } \ + template \ + inline int MapTypeHandler::SpaceUsedInMap(const string& value) { \ + return sizeof(value); \ + } \ + template \ + inline void MapTypeHandler::Clear( \ + TypeOnMemory* value, Arena* arena) { \ + value->ClearToEmpty(&::google::protobuf::internal::GetEmptyString(), arena); \ + } \ + template \ + inline void \ + MapTypeHandler::ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum) { \ + Clear(value, arena); \ + } \ + template \ + inline void MapTypeHandler::Merge( \ + const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \ + to->Set(&::google::protobuf::internal::GetEmptyString(), from, arena); \ + } \ + template \ + void MapTypeHandler::DeleteNoArena( \ + TypeOnMemory& value) { \ + value.DestroyNoArena(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template \ + inline void MapTypeHandler::AssignDefaultValue(TypeOnMemory* value) {} \ + template \ + inline void \ + MapTypeHandler::Initialize( \ + TypeOnMemory* value, Arena* arena) { \ + value->UnsafeSetDefault(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template \ + inline void \ + MapTypeHandler::InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena) { \ + Initialize(value, arena); \ + } \ + template \ + inline typename MapTypeHandler::MapEntryAccessorType* \ + MapTypeHandler::EnsureMutable( \ + TypeOnMemory* value, Arena* arena) { \ + return value->Mutable(&::google::protobuf::internal::GetEmptyString(), arena); \ + } \ + template \ + inline const typename MapTypeHandler::MapEntryAccessorType& \ + MapTypeHandler::DefaultIfNotInitialized(const TypeOnMemory& value, \ + const TypeOnMemory& \ + default_value) { \ + return value.Get(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template \ + inline bool MapTypeHandler::IsInitialized(const TypeOnMemory& value) { \ + return true; \ + } +STRING_OR_BYTES_HANDLER_FUNCTIONS(STRING) +STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES) +#undef STRING_OR_BYTES_HANDLER_FUNCTIONS + +#define PRIMITIVE_HANDLER_FUNCTIONS(FieldType) \ + template \ + inline const typename MapTypeHandler::MapEntryAccessorType& \ + MapTypeHandler::GetExternalReference(const TypeOnMemory& value) { \ + return value; \ + } \ + template \ + inline int \ + MapTypeHandler::SpaceUsedInMapEntry( \ + const TypeOnMemory& value) { \ + return 0; \ + } \ + template \ + inline int MapTypeHandler::SpaceUsedInMap(const TypeOnMemory& value) { \ + return sizeof(Type); \ + } \ + template \ + inline void MapTypeHandler::Clear( \ + TypeOnMemory* value, Arena* arena) { \ + *value = 0; \ + } \ + template \ + inline void \ + MapTypeHandler::ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum_value) { \ + *value = static_cast(default_enum_value); \ + } \ + template \ + inline void MapTypeHandler::Merge( \ + const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \ + *to = from; \ + } \ + template \ + inline void MapTypeHandler::DeleteNoArena(TypeOnMemory& x) {} \ + template \ + inline void MapTypeHandler::AssignDefaultValue(TypeOnMemory* value) {} \ + template \ + inline void \ + MapTypeHandler::Initialize( \ + TypeOnMemory* value, Arena* arena) { \ + *value = 0; \ + } \ + template \ + inline void \ + MapTypeHandler::InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena) { \ + *value = static_cast(default_enum_value); \ + } \ + template \ + inline typename MapTypeHandler::MapEntryAccessorType* \ + MapTypeHandler::EnsureMutable( \ + TypeOnMemory* value, Arena* arena) { \ + return value; \ + } \ + template \ + inline const typename MapTypeHandler::MapEntryAccessorType& \ + MapTypeHandler::DefaultIfNotInitialized(const TypeOnMemory& value, \ + const TypeOnMemory& \ + default_value) { \ + return value; \ + } \ + template \ + inline bool MapTypeHandler::IsInitialized(const TypeOnMemory& value) { \ + return true; \ + } +PRIMITIVE_HANDLER_FUNCTIONS(INT64) +PRIMITIVE_HANDLER_FUNCTIONS(UINT64) +PRIMITIVE_HANDLER_FUNCTIONS(INT32) +PRIMITIVE_HANDLER_FUNCTIONS(UINT32) +PRIMITIVE_HANDLER_FUNCTIONS(SINT64) +PRIMITIVE_HANDLER_FUNCTIONS(SINT32) +PRIMITIVE_HANDLER_FUNCTIONS(ENUM) +PRIMITIVE_HANDLER_FUNCTIONS(DOUBLE) +PRIMITIVE_HANDLER_FUNCTIONS(FLOAT) +PRIMITIVE_HANDLER_FUNCTIONS(FIXED64) +PRIMITIVE_HANDLER_FUNCTIONS(FIXED32) +PRIMITIVE_HANDLER_FUNCTIONS(SFIXED64) +PRIMITIVE_HANDLER_FUNCTIONS(SFIXED32) +PRIMITIVE_HANDLER_FUNCTIONS(BOOL) +#undef PRIMITIVE_HANDLER_FUNCTIONS + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index b308c7ff5249d..d3b525a05604c 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -33,6 +33,7 @@ syntax = "proto3"; option cc_enable_arenas = true; import "google/protobuf/unittest.proto"; +import "google/protobuf/unittest_no_arena.proto"; // We don't put this in a package within proto2 because we need to make sure // that the generated code doesn't depend on being in the proto2 namespace. @@ -58,6 +59,7 @@ message TestMap { map map_int32_bytes = 15; map map_int32_enum = 16; map map_int32_foreign_message = 17; + map map_string_foreign_message = 18; } message TestMapSubmessage { @@ -100,8 +102,12 @@ message TestArenaMap { map map_int32_float = 11; map map_int32_double = 12; map map_bool_bool = 13; - map map_int32_enum = 14; - map map_int32_foreign_message = 15; + map map_string_string = 14; + map map_int32_bytes = 15; + map map_int32_enum = 16; + map map_int32_foreign_message = 17; + map + map_int32_foreign_message_no_arena = 18; } // Previously, message containing enum called Type cannot be used as value of @@ -117,3 +123,7 @@ message MessageContainingEnumCalledType { message MessageContainingMapCalledEntry { map entry = 1; } + +message TestRecursiveMapMessage { + map a = 1; +} diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 276d7de579760..7d69c57abfc7e 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -38,12 +38,15 @@ #include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -256,6 +259,22 @@ void Reflection::AddEnumValue(Message* message, GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; } +MapIterator Reflection::MapBegin( + Message* message, + const FieldDescriptor* field) const { + GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; + MapIterator iter(message, field); + return iter; +} + +MapIterator Reflection::MapEnd( + Message* message, + const FieldDescriptor* field) const { + GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; + MapIterator iter(message, field); + return iter; +} + // ============================================================================= // MessageFactory diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 18c092d051e66..348e7c7fc3b00 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -134,12 +134,23 @@ class Reflection; class MessageFactory; // Defined in other files. +class MapKey; +class MapValueRef; +class MapIterator; +class MapReflectionTester; + +namespace internal { +class MapFieldBase; +} class UnknownFieldSet; // unknown_field_set.h namespace io { - class ZeroCopyInputStream; // zero_copy_stream.h - class ZeroCopyOutputStream; // zero_copy_stream.h - class CodedInputStream; // coded_stream.h - class CodedOutputStream; // coded_stream.h +class ZeroCopyInputStream; // zero_copy_stream.h +class ZeroCopyOutputStream; // zero_copy_stream.h +class CodedInputStream; // coded_stream.h +class CodedOutputStream; // coded_stream.h +} +namespace python { +class MapReflectionFriend; // scalar_map_container.h } @@ -724,6 +735,14 @@ class LIBPROTOBUF_EXPORT Reflection { const FieldDescriptor* field, MessageFactory* factory = NULL) const = 0; + // Appends an already-allocated object 'new_entry' to the repeated field + // specifyed by 'field' passing ownership to the message. + // TODO(tmarek): Make virtual after all subclasses have been + // updated. + virtual void AddAllocatedMessage(Message* message, + const FieldDescriptor* field, + Message* new_entry) const {} + // Get a RepeatedFieldRef object that can be used to read the underlying // repeated field. The type parameter T must be set according to the @@ -868,11 +887,20 @@ class LIBPROTOBUF_EXPORT Reflection { // on field->cpp_type(), // on field->field_option().ctype() (if ctype >= 0) // of field->message_type() (if message_type != NULL). - // We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer). + // We use 2 routine rather than 4 (const vs mutable) x (scalar vs pointer). virtual void* MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, int ctype, const Descriptor* message_type) const = 0; + // TODO(jieluo) - make it pure virtual after updating all the subclasses. + virtual const void* GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType cpptype, int ctype, + const Descriptor* message_type) const { + return MutableRawRepeatedField( + const_cast(&message), field, cpptype, ctype, message_type); + } + // The following methods are used to implement (Mutable)RepeatedFieldRef. // A Ref object will store a raw pointer to the repeated field data (obtained // from RepeatedFieldData()) and a pointer to a Accessor (obtained from @@ -887,6 +915,8 @@ class LIBPROTOBUF_EXPORT Reflection { // "message_type" should be set to its descriptor. Otherwise "message_type" // should be set to NULL. Implementations of this method should check whether // "cpp_type"/"message_type" is consistent with the actual type of the field. + // We use 1 routine rather than 2 (const vs mutable) because it is protected + // and it doesn't change the message. virtual void* RepeatedFieldData( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpp_type, @@ -902,14 +932,73 @@ class LIBPROTOBUF_EXPORT Reflection { friend class RepeatedFieldRef; template friend class MutableRepeatedFieldRef; + friend class ::google::protobuf::python::MapReflectionFriend; // Special version for specialized implementations of string. We can't call // MutableRawRepeatedField directly here because we don't have access to // FieldOptions::* which are defined in descriptor.pb.h. Including that // file here is not possible because it would cause a circular include cycle. + // We use 1 routine rather than 2 (const vs mutable) because it is private + // and mutable a repeated string field doesn't change the message. void* MutableRawRepeatedString( Message* message, const FieldDescriptor* field, bool is_string) const; + friend class MapReflectionTester; + // TODO(jieluo) - make the map APIs pure virtual after updating + // all the subclasses. + // Returns true if key is in map. Returns false if key is not in map field. + virtual bool ContainsMapKey(const Message& message, + const FieldDescriptor* field, + const MapKey& key) const { + return false; + } + + // If key is in map field: Saves the value pointer to val and returns + // false. If key in not in map field: Insert the key into map, saves + // value pointer to val and retuns true. + virtual bool InsertOrLookupMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const { + return false; + } + + // Delete and returns true if key is in the map field. Returns false + // otherwise. + virtual bool DeleteMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key) const { + return false; + } + + // Returns a MaIterator referring to the first element in the map field. + // If the map field is empty, this function returns the same as + // reflection::MapEnd. Mutation to the field may invalidate the iterator. + virtual MapIterator MapBegin( + Message* message, + const FieldDescriptor* field) const; + + // Returns a MapIterator referring to the theoretical element that would + // follow the last element in the map field. It does not point to any + // real element. Mutation to the field may invalidate the iterator. + virtual MapIterator MapEnd( + Message* message, + const FieldDescriptor* field) const; + + // Get the number of pair of a map field. The result may be + // different from FieldSize which can have duplicate keys. + virtual int MapSize(const Message& message, + const FieldDescriptor* field) const { + return 0; + } + + // Help method for MapIterator. + friend class MapIterator; + virtual internal::MapFieldBase* MapData( + Message* message, const FieldDescriptor* field) const { + return NULL; + } + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection); }; @@ -1025,10 +1114,9 @@ inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( template<> inline const RepeatedPtrField& Reflection::GetRepeatedPtrField( const Message& message, const FieldDescriptor* field) const { - return *static_cast* >( - MutableRawRepeatedField(const_cast(&message), field, - FieldDescriptor::CPPTYPE_MESSAGE, -1, - NULL)); + return *static_cast* >( + GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, + -1, NULL)); } template<> @@ -1043,10 +1131,9 @@ inline RepeatedPtrField* Reflection::MutableRepeatedPtrField( template inline const RepeatedPtrField& Reflection::GetRepeatedPtrField( const Message& message, const FieldDescriptor* field) const { - return *static_cast* >( - MutableRawRepeatedField(const_cast(&message), field, - FieldDescriptor::CPPTYPE_MESSAGE, -1, - PB::default_instance().GetDescriptor())); + return *static_cast* >( + GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, + -1, PB::default_instance().GetDescriptor())); } template diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 4f63ad2bf945a..5bd8bcfb12f3a 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -35,7 +35,9 @@ #include #include +#include #include +#include #include #include #include @@ -98,27 +100,19 @@ string InitializationErrorMessage(const char* action, // call MergePartialFromCodedStream(). However, when parsing very small // messages, every function call introduces significant overhead. To avoid // this without reproducing code, we use these forced-inline helpers. -// -// Note: GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not -// definitions. +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray( + const void* data, int size, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray( + const void* data, int size, MessageLite* message); + inline bool InlineMergeFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParseFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParseFromArray(const void* data, int size, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParsePartialFromArray(const void* data, int size, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; - -bool InlineMergeFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { + MessageLite* message) { if (!message->MergePartialFromCodedStream(input)) return false; if (!message->IsInitialized()) { GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message); @@ -127,26 +121,27 @@ bool InlineMergeFromCodedStream(io::CodedInputStream* input, return true; } -bool InlineParseFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { +inline bool InlineParseFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { message->Clear(); return InlineMergeFromCodedStream(input, message); } -bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { +inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { message->Clear(); return message->MergePartialFromCodedStream(input); } -bool InlineParseFromArray(const void* data, int size, MessageLite* message) { +inline bool InlineParseFromArray( + const void* data, int size, MessageLite* message) { io::CodedInputStream input(reinterpret_cast(data), size); return InlineParseFromCodedStream(&input, message) && input.ConsumedEntireMessage(); } -bool InlineParsePartialFromArray(const void* data, int size, - MessageLite* message) { +inline bool InlineParsePartialFromArray( + const void* data, int size, MessageLite* message) { io::CodedInputStream input(reinterpret_cast(data), size); return InlineParsePartialFromCodedStream(&input, message) && input.ConsumedEntireMessage(); @@ -353,5 +348,18 @@ string MessageLite::SerializePartialAsString() const { return output; } +namespace internal { +template<> +MessageLite* GenericTypeHandler::NewFromPrototype( + const MessageLite* prototype, google::protobuf::Arena* arena) { + return prototype->New(arena); +} +template <> +void GenericTypeHandler::Merge(const MessageLite& from, + MessageLite* to) { + to->CheckTypeAndMergeFrom(from); +} +} // namespace internal + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index 75d60b8b4aca4..2d4780fe6de5b 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -53,6 +53,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h index 30b2a6eee56e6..fdee150b44f5c 100644 --- a/src/google/protobuf/metadata.h +++ b/src/google/protobuf/metadata.h @@ -69,8 +69,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { ptr_ = NULL; } - inline const UnknownFieldSet& unknown_fields() const - GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE const UnknownFieldSet& unknown_fields() const { if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { return PtrValue()->unknown_fields_; } else { @@ -78,7 +77,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline UnknownFieldSet* mutable_unknown_fields() GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE UnknownFieldSet* mutable_unknown_fields() { if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) { return &PtrValue()->unknown_fields_; } else { @@ -86,7 +85,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline Arena* arena() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const { if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { return PtrValue()->arena_; } else { @@ -94,11 +93,11 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline bool have_unknown_fields() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const { return PtrTag() == kTagContainer; } - inline void Swap(InternalMetadataWithArena* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(InternalMetadataWithArena* other) { // Semantics here are that we swap only the unknown fields, not the arena // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in @@ -110,7 +109,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline void* raw_arena_ptr() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const { return ptr_; } @@ -128,7 +127,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { static const intptr_t kPtrValueMask = ~kPtrTagMask; // Accessors for pointer tag and pointer value. - inline int PtrTag() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const { return reinterpret_cast(ptr_) & kPtrTagMask; } @@ -143,7 +142,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { Arena* arena_; }; - UnknownFieldSet* mutable_unknown_fields_slow() GOOGLE_ATTRIBUTE_NOINLINE { + GOOGLE_ATTRIBUTE_NOINLINE UnknownFieldSet* mutable_unknown_fields_slow() { Arena* my_arena = arena(); Container* container = Arena::Create(my_arena); ptr_ = reinterpret_cast( diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc index 4b7b31d979f13..bc41beec8131a 100644 --- a/src/google/protobuf/no_field_presence_test.cc +++ b/src/google/protobuf/no_field_presence_test.cc @@ -341,6 +341,46 @@ TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { EXPECT_EQ(false, r->HasField(message, field_string)); } +TEST(NoFieldPresenceTest, ReflectionClearFieldTest) { + proto2_nofieldpresence_unittest::TestAllTypes message; + + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* desc = message.GetDescriptor(); + + const google::protobuf::FieldDescriptor* field_int32 = desc->FindFieldByName( + "optional_int32"); + const google::protobuf::FieldDescriptor* field_double = desc->FindFieldByName( + "optional_double"); + const google::protobuf::FieldDescriptor* field_string = desc->FindFieldByName( + "optional_string"); + const google::protobuf::FieldDescriptor* field_message = desc->FindFieldByName( + "optional_nested_message"); + const google::protobuf::FieldDescriptor* field_lazy = desc->FindFieldByName( + "optional_lazy_message"); + + message.set_optional_int32(42); + r->ClearField(&message, field_int32); + EXPECT_EQ(0, message.optional_int32()); + + message.set_optional_double(42.0); + r->ClearField(&message, field_double); + EXPECT_EQ(0.0, message.optional_double()); + + message.set_optional_string("test"); + r->ClearField(&message, field_string); + EXPECT_EQ("", message.optional_string()); + + message.mutable_optional_nested_message()->set_bb(1234); + r->ClearField(&message, field_message); + EXPECT_FALSE(message.has_optional_nested_message()); + EXPECT_EQ(0, message.optional_nested_message().bb()); + + message.mutable_optional_lazy_message()->set_bb(42); + r->ClearField(&message, field_lazy); + EXPECT_FALSE(message.has_optional_lazy_message()); + EXPECT_EQ(0, message.optional_lazy_message().bb()); +} + TEST(NoFieldPresenceTest, HasFieldOneofsTest) { // check that HasField behaves properly for oneofs. proto2_nofieldpresence_unittest::TestAllTypes message; diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc index da4be67368744..2838e0fc64407 100644 --- a/src/google/protobuf/proto3_arena_unittest.cc +++ b/src/google/protobuf/proto3_arena_unittest.cc @@ -119,7 +119,7 @@ void ExpectAllFieldsSet(const TestAllTypes& m) { // proto3 and expect the arena support to be fully tested in proto2 unittests // because proto3 shares most code with proto2. -TEST(ArenaTest, Parsing) { +TEST(Proto3ArenaTest, Parsing) { TestAllTypes original; SetAllFields(&original); @@ -129,7 +129,7 @@ TEST(ArenaTest, Parsing) { ExpectAllFieldsSet(*arena_message); } -TEST(ArenaTest, UnknownFields) { +TEST(Proto3ArenaTest, UnknownFields) { TestAllTypes original; SetAllFields(&original); @@ -150,7 +150,7 @@ TEST(ArenaTest, UnknownFields) { arena_message->GetReflection()->GetUnknownFields(*arena_message).empty()); } -TEST(ArenaTest, Swap) { +TEST(Proto3ArenaTest, Swap) { Arena arena1; Arena arena2; @@ -162,7 +162,7 @@ TEST(ArenaTest, Swap) { EXPECT_EQ(&arena2, arena2_message->GetArena()); } -TEST(ArenaTest, SetAllocatedMessage) { +TEST(Proto3ArenaTest, SetAllocatedMessage) { Arena arena; TestAllTypes *arena_message = Arena::CreateMessage(&arena); TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; @@ -171,7 +171,7 @@ TEST(ArenaTest, SetAllocatedMessage) { EXPECT_EQ(118, arena_message->optional_nested_message().bb()); } -TEST(ArenaTest, ReleaseMessage) { +TEST(Proto3ArenaTest, ReleaseMessage) { Arena arena; TestAllTypes* arena_message = Arena::CreateMessage(&arena); arena_message->mutable_optional_nested_message()->set_bb(118); @@ -180,7 +180,7 @@ TEST(ArenaTest, ReleaseMessage) { EXPECT_EQ(118, nested->bb()); } -TEST(ArenaTest, MessageFieldClear) { +TEST(Proto3ArenaTest, MessageFieldClear) { // GitHub issue #310: https://github.com/google/protobuf/issues/310 Arena arena; TestAllTypes* arena_message = Arena::CreateMessage(&arena); @@ -190,6 +190,20 @@ TEST(ArenaTest, MessageFieldClear) { arena_message->Clear(); } +TEST(Proto3ArenaTest, MessageFieldClearViaReflection) { + Arena arena; + TestAllTypes* message = Arena::CreateMessage(&arena); + const Reflection* r = message->GetReflection(); + const Descriptor* d = message->GetDescriptor(); + const FieldDescriptor* msg_field = d->FindFieldByName( + "optional_nested_message"); + + message->mutable_optional_nested_message()->set_bb(1); + r->ClearField(message, msg_field); + EXPECT_FALSE(message->has_optional_nested_message()); + EXPECT_EQ(0, message->optional_nested_message().bb()); +} + } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/proto_cast.h b/src/google/protobuf/proto_cast.h index e25c219ffece2..dc0e9aca90e39 100644 --- a/src/google/protobuf/proto_cast.h +++ b/src/google/protobuf/proto_cast.h @@ -33,6 +33,7 @@ #include +#include #include // proto_cast<> is used to simulate over-the-wire conversion of one diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/proto_cast_test.cc index eb101eb633c22..a8f43ae4242dd 100644 --- a/src/google/protobuf/proto_cast_test.cc +++ b/src/google/protobuf/proto_cast_test.cc @@ -32,7 +32,7 @@ #include #include -#include +#include namespace google { using google::protobuf::util::UpRevision; diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h index 4ff0f6b40e7e8..671aafdc4e276 100755 --- a/src/google/protobuf/reflection.h +++ b/src/google/protobuf/reflection.h @@ -553,7 +553,7 @@ struct RefTypeTraits< template struct RefTypeTraits< - T, typename internal::enable_if::value>::type> { + T, typename internal::enable_if< ::google::protobuf::internal::is_same::value>::type> { typedef RepeatedFieldRefIterator iterator; typedef RepeatedFieldAccessor AccessorType; typedef string AccessorValueType; diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc index 32740ea469657..88d6bfb6106d0 100644 --- a/src/google/protobuf/reflection_ops_unittest.cc +++ b/src/google/protobuf/reflection_ops_unittest.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index e5aedadc83f81..949e0a235dffa 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -35,6 +35,7 @@ #include #include +#include #include namespace google { @@ -53,13 +54,17 @@ void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { Arena* arena = GetArenaNoVirtual(); new_size = max(kMinRepeatedFieldAllocationSize, max(total_size_ * 2, new_size)); + GOOGLE_CHECK_LE(new_size, + (std::numeric_limits::max() - kRepHeaderSize) / + sizeof(old_rep->elements[0])) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { rep_ = reinterpret_cast( - new char[kRepHeaderSize + sizeof(old_rep->elements[0])*new_size]); + new char[kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size]); } else { rep_ = reinterpret_cast( ::google::protobuf::Arena::CreateArray(arena, - kRepHeaderSize + sizeof(old_rep->elements[0])*new_size)); + kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size)); } total_size_ = new_size; if (old_rep && old_rep->allocated_size > 0) { diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 14f46298d42e2..b42d47904af2f 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -361,7 +362,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { // To parse directly into a proto2 generated class, the upb class GMR_Handlers // needs to be able to modify a RepeatedPtrFieldBase directly. - friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers; + friend class upb::google_opensource::GMR_Handlers; RepeatedPtrFieldBase(); explicit RepeatedPtrFieldBase(::google::protobuf::Arena* arena); @@ -408,7 +409,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { const typename TypeHandler::Type* const* data() const; template - inline void Swap(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(RepeatedPtrFieldBase* other); void SwapElements(int index1, int index2); @@ -458,22 +459,20 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { void AddAllocatedInternal(typename TypeHandler::Type* value, google::protobuf::internal::false_type); - template + template GOOGLE_ATTRIBUTE_NOINLINE void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value, Arena* value_arena, - Arena* my_arena) - GOOGLE_ATTRIBUTE_NOINLINE; - template - void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value) - GOOGLE_ATTRIBUTE_NOINLINE; + Arena* my_arena); + template GOOGLE_ATTRIBUTE_NOINLINE + void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value); template typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::true_type); template typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::false_type); - template - inline void SwapFallback(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_NOINLINE; + template GOOGLE_ATTRIBUTE_NOINLINE + void SwapFallback(RepeatedPtrFieldBase* other); inline Arena* GetArenaNoVirtual() const { return arena_; @@ -542,20 +541,10 @@ class GenericTypeHandler { } // We force NewFromPrototype() and Delete() to be non-inline to reduce code // size: else, several other methods get inlined copies of message types' - // constructors and destructors. Note that the GOOGLE_ATTRIBUTE_NOINLINE macro - // requires the 'inline' storage class here, which is somewhat confusing, but - // the compiler does the right thing. - static inline GenericType* NewFromPrototype(const GenericType* prototype, - ::google::protobuf::Arena* arena = NULL) - GOOGLE_ATTRIBUTE_NOINLINE { - return New(arena); - } - static inline void Delete(GenericType* value, Arena* arena) - GOOGLE_ATTRIBUTE_NOINLINE { - if (arena == NULL) { - delete value; - } - } + // constructors and destructors. + GOOGLE_ATTRIBUTE_NOINLINE static GenericType* NewFromPrototype( + const GenericType* prototype, ::google::protobuf::Arena* arena = NULL); + GOOGLE_ATTRIBUTE_NOINLINE static void Delete(GenericType* value, Arena* arena); static inline ::google::protobuf::Arena* GetArena(GenericType* value) { return ::google::protobuf::Arena::GetArena(value); } @@ -564,10 +553,8 @@ class GenericTypeHandler { } static inline void Clear(GenericType* value) { value->Clear(); } - static inline void Merge(const GenericType& from, GenericType* to) - GOOGLE_ATTRIBUTE_NOINLINE { - to->MergeFrom(from); - } + GOOGLE_ATTRIBUTE_NOINLINE static void Merge(const GenericType& from, + GenericType* to); static inline int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); } @@ -576,11 +563,31 @@ class GenericTypeHandler { } }; -template<> -inline MessageLite* GenericTypeHandler::NewFromPrototype( - const MessageLite* prototype, google::protobuf::Arena* arena) { - return prototype->New(arena); +template +GenericType* GenericTypeHandler::NewFromPrototype( + const GenericType* prototype, ::google::protobuf::Arena* arena) { + return New(arena); +} +template +void GenericTypeHandler::Delete(GenericType* value, Arena* arena) { + if (arena == NULL) { + delete value; + } } +template +void GenericTypeHandler::Merge(const GenericType& from, + GenericType* to) { + to->MergeFrom(from); +} + +// NewFromPrototype() and Merge() cannot be defined here; if they're declared +// inline the compiler will complain about not matching GOOGLE_ATTRIBUTE_NOINLINE +// above, and if not, compilation will result in multiple definitions. These +// are therefore declared as specializations here and defined in +// message_lite.cc. +template<> +MessageLite* GenericTypeHandler::NewFromPrototype( + const MessageLite* prototype, google::protobuf::Arena* arena); template<> inline google::protobuf::Arena* GenericTypeHandler::GetArena( MessageLite* value) { @@ -591,14 +598,9 @@ inline void* GenericTypeHandler::GetMaybeArenaPointer( MessageLite* value) { return value->GetMaybeArenaPointer(); } - -// Implements GenericTypeHandler specialization required by RepeatedPtrFields -// to work with MessageLite type. template <> -inline void GenericTypeHandler::Merge( - const MessageLite& from, MessageLite* to) { - to->CheckTypeAndMergeFrom(from); -} +void GenericTypeHandler::Merge(const MessageLite& from, + MessageLite* to); // Declarations of the specialization as we cannot define them here, as the // header that defines ProtocolMessage depends on types defined in this header. @@ -1221,13 +1223,17 @@ void RepeatedField::Reserve(int new_size) { Arena* arena = GetArenaNoVirtual(); new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, max(total_size_ * 2, new_size)); + GOOGLE_CHECK_LE(new_size, + (std::numeric_limits::max() - kRepHeaderSize) / + sizeof(Element)) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { rep_ = reinterpret_cast( - new char[kRepHeaderSize + sizeof(Element)*new_size]); + new char[kRepHeaderSize + sizeof(Element) * new_size]); } else { rep_ = reinterpret_cast( ::google::protobuf::Arena::CreateArray(arena, - kRepHeaderSize + sizeof(Element)*new_size)); + kRepHeaderSize + sizeof(Element) * new_size)); } rep_->arena = arena; int old_total_size = total_size_; @@ -1342,7 +1348,7 @@ inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { } template -inline void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { +void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { GOOGLE_DCHECK(other->GetArenaNoVirtual() != GetArenaNoVirtual()); // Copy semantics in this case. We try to improve efficiency by placing the diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index af39793223cd2..b45664b0bcd1d 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -42,6 +42,7 @@ #include +#include #include #include #include @@ -1429,7 +1430,6 @@ class RepeatedFieldInsertionIteratorsTest : public testing::Test { std::copy(nested_ptrs.begin(), nested_ptrs.end(), RepeatedFieldBackInserter( protobuffer.mutable_repeated_nested_message())); - } virtual void TearDown() { diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h index cc0b45d410790..ad6f968548fe6 100644 --- a/src/google/protobuf/service.h +++ b/src/google/protobuf/service.h @@ -74,12 +74,12 @@ // // To call a remote MyServiceImpl, first you need an RpcChannel connected to it. // How to construct a channel depends, again, on your RPC implementation. -// Here we use a hypothentical "MyRpcChannel" as an example: +// Here we use a hypothetical "MyRpcChannel" as an example: // MyRpcChannel channel("rpc:hostname:1234/myservice"); // MyRpcController controller; // MyServiceImpl::Stub stub(&channel); // FooRequest request; -// FooRespnose response; +// FooResponse response; // // // ... fill in request ... // @@ -102,6 +102,7 @@ #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index be1c90e0693de..07aa1d7781b55 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -42,6 +42,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc index 88eca0ad8db42..388c0cbde2051 100644 --- a/src/google/protobuf/test_util_lite.cc +++ b/src/google/protobuf/test_util_lite.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include #include diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 76ce987560197..1aafd8e6e728f 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -38,11 +38,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto index 3aa31fa9ddc53..49d9adad0b699 100644 --- a/src/google/protobuf/unittest_mset.proto +++ b/src/google/protobuf/unittest_mset.proto @@ -32,33 +32,31 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // -// This file contains messages for testing message_set_wire_format. +// This file is similar to unittest_mset_wire_format.proto, but does not +// have a TestMessageSet, so it can be downgraded to proto1. syntax = "proto2"; + +import "google/protobuf/unittest_mset_wire_format.proto"; + package protobuf_unittest; option cc_enable_arenas = true; option optimize_for = SPEED; -// A message with message_set_wire_format. -message TestMessageSet { - option message_set_wire_format = true; - extensions 4 to max; -} - message TestMessageSetContainer { - optional TestMessageSet message_set = 1; + optional proto2_wireformat_unittest.TestMessageSet message_set = 1; } message TestMessageSetExtension1 { - extend TestMessageSet { + extend proto2_wireformat_unittest.TestMessageSet { optional TestMessageSetExtension1 message_set_extension = 1545008; } optional int32 i = 15; } message TestMessageSetExtension2 { - extend TestMessageSet { + extend proto2_wireformat_unittest.TestMessageSet { optional TestMessageSetExtension2 message_set_extension = 1547769; } optional string str = 25; @@ -82,4 +80,3 @@ message RawMessageSet { required bytes message = 3; } } - diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h index 39c10cbc6f233..7c68ad6c4f19d 100644 --- a/src/google/protobuf/unknown_enum_impl.h +++ b/src/google/protobuf/unknown_enum_impl.h @@ -34,7 +34,6 @@ #include #include -#include "net/proto/tagmapper.h" #include namespace google { @@ -59,10 +58,10 @@ namespace util { // In proto2, invalid enum values will be treated as unknown fields. This // function checks that case. bool HasUnknownEnum(const Message& message, int32 field_number, - int32* unknown_value = nullptr); + int32* unknown_value = NULL); // Same as above, but returns all unknown enums. bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number, - vector* unknown_values = nullptr); + vector* unknown_values = NULL); // In proto1, invalue enum values are stored in the same way as valid enum // values. // TODO(karner): Delete this once the migration to proto2 is complete. @@ -75,7 +74,7 @@ bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number, // or proto2. template bool HasUnknownEnum_Template(const T& message, int32 field_number, - int32* unknown_value = nullptr) { + int32* unknown_value = NULL) { if (internal::is_base_of::value || !internal::is_base_of::value) { return HasUnknownEnum(message, field_number, unknown_value); @@ -88,7 +87,7 @@ bool HasUnknownEnum_Template(const T& message, int32 field_number, template bool GetRepeatedEnumUnknowns_Template( const T& message, int32 field_number, - vector* unknown_values = nullptr) { + vector* unknown_values = NULL) { if (internal::is_base_of::value || !internal::is_base_of::value) { return GetRepeatedEnumUnknowns(message, field_number, unknown_values); diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto index 0ea1ede3fff6d..3c549cc78003e 100644 --- a/src/google/protobuf/unknown_enum_test.proto +++ b/src/google/protobuf/unknown_enum_test.proto @@ -36,6 +36,8 @@ syntax = "proto2"; package google.protobuf.util; +option csharp_namespace = "Google.ProtocolBuffers.TestProtos"; + message DownRevision { enum Enum { DEFAULT_VALUE = 2; diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 93f0f206ad855..d4e383da234a0 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -34,6 +34,7 @@ #include +#include #include #include #include diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 6781cd0f121e8..612a942a771d8 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -42,6 +42,7 @@ #include #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index 9b02f0b040708..5de72630a6f32 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -43,7 +43,10 @@ #include #include +#include #include +#include +#include #include #include #include diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index 944fb2e362c33..ea36079895150 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -79,7 +79,9 @@ StatusOr NumberConvertAndCheck(From before) { // For conversion between double and float only. template StatusOr FloatingPointConvertAndCheck(From before) { - if (MathLimits::IsNaN(before)) return std::numeric_limits::quiet_NaN(); + if (MathLimits::IsNaN(before)) { + return std::numeric_limits::quiet_NaN(); + } To after = static_cast(before); if (MathUtil::AlmostEquals(after, before)) { @@ -167,7 +169,7 @@ StatusOr DataPiece::ToString() const { return str_.ToString(); case TYPE_BYTES: { string base64; - WebSafeBase64Escape(str_, &base64); + Base64Escape(str_, &base64); return base64; } default: diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 267e2cd3a0aea..97b248fff0cd4 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -46,6 +46,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, ObjectWriter* ow) : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), + own_typeinfo_(true), type_(type), disable_normalize_(false), current_(NULL), @@ -56,6 +57,9 @@ DefaultValueObjectWriter::~DefaultValueObjectWriter() { for (int i = 0; i < string_values_.size(); ++i) { delete string_values_[i]; } + if (own_typeinfo_) { + delete typeinfo_; + } } DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, @@ -197,33 +201,47 @@ void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { if (disable_normalize_) { ow->DisableCaseNormalizationForNextKey(); } + if (kind_ == PRIMITIVE) { ObjectWriter::RenderDataPieceTo(data_, name_, ow); return; } - if (is_placeholder_) { - // If is_placeholder_ = true, we didn't see this node in the response, so - // skip output. + + // Render maps. Empty maps are rendered as "{}". + if (kind_ == MAP) { + ow->StartObject(name_); + WriteChildren(ow); + ow->EndObject(); return; } + + // Write out lists. If we didn't have any list in response, write out empty + // list. if (kind_ == LIST) { ow->StartList(name_); - } else { - ow->StartObject(name_); + WriteChildren(ow); + ow->EndList(); + return; } + + // If is_placeholder_ = true, we didn't see this node in the response, so + // skip output. + if (is_placeholder_) return; + + ow->StartObject(name_); + WriteChildren(ow); + ow->EndObject(); +} + +void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) { for (int i = 0; i < children_.size(); ++i) { Node* child = children_[i]; child->WriteTo(ow); } - if (kind_ == LIST) { - ow->EndList(); - } else { - ow->EndObject(); - } } const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( - const google::protobuf::Type& found_type, TypeInfo* typeinfo) { + const google::protobuf::Type& found_type, const TypeInfo* typeinfo) { // If this field is a map, we should use the type of its "Value" as // the type of the child node. for (int i = 0; i < found_type.fields_size(); ++i) { @@ -248,7 +266,8 @@ const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( return NULL; } -void DefaultValueObjectWriter::Node::PopulateChildren(TypeInfo* typeinfo) { +void DefaultValueObjectWriter::Node::PopulateChildren( + const TypeInfo* typeinfo) { // Ignores well known types that don't require automatically populating their // primitive children. For type "Any", we only populate its children when the // "@type" field is set. @@ -310,15 +329,17 @@ void DefaultValueObjectWriter::Node::PopulateChildren(TypeInfo* typeinfo) { google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { kind = LIST; } - // If the child field is of primitive type, sets its data to the default - // value of its type. + // If oneof_index() != 0, the child field is part of a "oneof", which means // the child field is optional and we shouldn't populate its default value. + if (field.oneof_index() != 0) continue; + + // If the child field is of primitive type, sets its data to the default + // value of its type. google::protobuf::scoped_ptr child( - new Node(field.name(), field_type, kind, - ((kind == PRIMITIVE && field.oneof_index() == 0) - ? CreateDefaultDataPieceForField(field) - : DataPiece::NullData()), + new Node(field.json_name(), field_type, kind, + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field) + : DataPiece::NullData(), true)); new_children.push_back(child.release()); } @@ -338,7 +359,7 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { // have been added, populates its children. if (node != NULL && node->is_any() && node->type() != NULL && node->type()->name() != kAnyType && node->number_of_children() == 1) { - node->PopulateChildren(typeinfo_.get()); + node->PopulateChildren(typeinfo_); } } @@ -388,7 +409,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), false)); root_->set_disable_normalize(GetAndResetDisableNormalize()); - root_->PopulateChildren(typeinfo_.get()); + root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; } @@ -409,7 +430,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( child->set_is_placeholder(false); child->set_disable_normalize(GetAndResetDisableNormalize()); if (child->kind() == OBJECT && child->number_of_children() == 0) { - child->PopulateChildren(typeinfo_.get()); + child->PopulateChildren(typeinfo_); } stack_.push(current_); @@ -492,12 +513,11 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, // first value field is rendered before we populate the children, because // the "value" field of a Any message could be omitted. if (current_->number_of_children() > 1 && current_->type() != NULL) { - current_->PopulateChildren(typeinfo_.get()); + current_->PopulateChildren(typeinfo_); } } Node* child = current_->FindChild(name); if (child == NULL || child->kind() != PRIMITIVE) { - GOOGLE_LOG(WARNING) << "Cannot find primitive field '" << name << "'."; // No children are found, creates a new child. google::protobuf::scoped_ptr node( new Node(name.ToString(), NULL, PRIMITIVE, data, false)); diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 759ba91b5dbbb..2468c8d913483 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -57,7 +57,7 @@ namespace converter { // ObjectWriter when EndObject() is called on the root object. It also writes // out all non-repeated primitive fields that haven't been explicitly rendered // with their default values (0 for numbers, "" for strings, etc). -class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { +class DefaultValueObjectWriter : public ObjectWriter { public: DefaultValueObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, @@ -129,7 +129,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Populates children of this Node based on its type. If there are already // children created, they will be merged to the result. Caller should pass // in TypeInfo for looking up types of the children. - void PopulateChildren(TypeInfo* typeinfo); + void PopulateChildren(const TypeInfo* typeinfo); // If this node is a leaf (has data), writes the current node to the // ObjectWriter; if not, then recursively writes the children to the @@ -165,7 +165,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Returns the Value Type of a map given the Type of the map entry and a // TypeInfo instance. const google::protobuf::Type* GetMapValueType( - const google::protobuf::Type& entry_type, TypeInfo* typeinfo); + const google::protobuf::Type& entry_type, const TypeInfo* typeinfo); + + // Calls WriteTo() on every child in children_. + void WriteChildren(ObjectWriter* ow); // The name of this node. string name_; @@ -210,7 +213,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. - google::protobuf::scoped_ptr typeinfo_; + const TypeInfo* typeinfo_; + // Whether the TypeInfo object is owned by this class. + bool own_typeinfo_; // google::protobuf::Type of the root message type. const google::protobuf::Type& type_; // Holds copies of strings passed to RenderString. diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc index 593c7105d04c2..237d0722acb1b 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc @@ -73,15 +73,15 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, TEST_P(DefaultValueObjectWriterTest, Empty) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 0.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") - ->RenderBytes("bytes_value", "") + ->RenderDouble("doubleValue", 0.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") + ->RenderBytes("bytesValue", "") ->EndObject(); // Actual testing @@ -91,42 +91,42 @@ TEST_P(DefaultValueObjectWriterTest, Empty) { TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 1.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") + ->RenderDouble("doubleValue", 1.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") ->EndObject(); // Actual testing - testing_->StartObject("")->RenderDouble("double_value", 1.0)->EndObject(); + testing_->StartObject("")->RenderDouble("doubleValue", 1.0)->EndObject(); } TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 1.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") + ->RenderDouble("doubleValue", 1.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") ->RenderString("unknown", "abc") - ->StartObject("unknown_object") + ->StartObject("unknownObject") ->RenderString("unknown", "def") ->EndObject() ->EndObject(); // Actual testing testing_->StartObject("") - ->RenderDouble("double_value", 1.0) + ->RenderDouble("doubleValue", 1.0) ->RenderString("unknown", "abc") - ->StartObject("unknown_object") + ->StartObject("unknownObject") ->RenderString("unknown", "def") ->EndObject() ->EndObject(); diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h index 9b907df505d51..2699684d4175f 100644 --- a/src/google/protobuf/util/internal/error_listener.h +++ b/src/google/protobuf/util/internal/error_listener.h @@ -37,7 +37,9 @@ #endif #include +#include #include +#include #include #include diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc index 92468959a75f4..f0e8fc88a4f99 100644 --- a/src/google/protobuf/util/internal/field_mask_utility.cc +++ b/src/google/protobuf/util/internal/field_mask_utility.cc @@ -34,7 +34,6 @@ #include namespace google { - namespace protobuf { namespace util { namespace converter { @@ -138,7 +137,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, } // Un-escaped '"' must be followed with a ']'. if (i >= length - 1 || paths[i + 1] != ']') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be represented as [\"some_key\"].")); @@ -150,7 +149,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // Checks whether the key ends at the end of a path segment. if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' && paths[i + 1] != ')' && paths[i + 1] != '(') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be at the end of a path segment.")); @@ -162,7 +161,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // We are not in a map key, look for the start of one. if (paths[i] == '[') { if (i >= length - 1 || paths[i + 1] != '\"') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be represented as [\"some_key\"].")); @@ -198,7 +197,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // Removes the last prefix after seeing a ')'. if (i < length && paths[i] == ')') { if (prefix.empty()) { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Cannot find matching '(' for all ')'.")); @@ -208,16 +207,14 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, previous_position = i + 1; } if (in_map_key) { - return CreatePublicError( - util::error::INVALID_ARGUMENT, - StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ']' for all '['.")); + return util::Status(util::error::INVALID_ARGUMENT, + StrCat("Invalid FieldMask '", paths, + "'. Cannot find matching ']' for all '['.")); } if (!prefix.empty()) { - return CreatePublicError( - util::error::INVALID_ARGUMENT, - StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ')' for all '('.")); + return util::Status(util::error::INVALID_ARGUMENT, + StrCat("Invalid FieldMask '", paths, + "'. Cannot find matching ')' for all '('.")); } return util::Status::OK; } diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc index 5ac23421caa01..36dc8ef912056 100644 --- a/src/google/protobuf/util/internal/json_escaping.cc +++ b/src/google/protobuf/util/internal/json_escaping.cc @@ -30,6 +30,7 @@ #include +#include #include namespace google { diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index 0c41515f9ea00..d88a81f9d326a 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -142,7 +143,7 @@ JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name, StringPiece value) { WritePrefix(name); string base64; - WebSafeBase64EscapeWithPadding(value, &base64); + Base64Escape(value, &base64); WriteChar('"'); // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes // directly to the stream, rather than first putting them diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index df9a133e02ca2..dcd606011319d 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -47,7 +47,8 @@ class JsonObjectWriterTest : public ::testing::Test { JsonObjectWriterTest() : str_stream_(new StringOutputStream(&output_)), out_stream_(new CodedOutputStream(str_stream_)), - ow_(NULL) {} + ow_(NULL) { + } virtual ~JsonObjectWriterTest() { delete ow_; @@ -63,34 +64,36 @@ class JsonObjectWriterTest : public ::testing::Test { TEST_F(JsonObjectWriterTest, EmptyRootObject) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->EndObject(); + ow_->StartObject("") + ->EndObject(); EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartObject("empty") - ->EndObject() - ->EndObject(); + ->RenderString("test", "value") + ->StartObject("empty") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyRootList) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("")->EndList(); + ow_->StartList("") + ->EndList(); EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartList("empty") - ->EndList() - ->EndObject(); + ->RenderString("test", "value") + ->StartList("empty") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", output_.substr(0, out_stream_->ByteCount())); } @@ -98,10 +101,10 @@ TEST_F(JsonObjectWriterTest, EmptyList) { TEST_F(JsonObjectWriterTest, ObjectInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartObject("nested") - ->RenderString("field", "value") - ->EndObject() - ->EndObject(); + ->StartObject("nested") + ->RenderString("field", "value") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", output_.substr(0, out_stream_->ByteCount())); } @@ -109,10 +112,10 @@ TEST_F(JsonObjectWriterTest, ObjectInObject) { TEST_F(JsonObjectWriterTest, ListInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartList("nested") - ->RenderString("", "value") - ->EndList() - ->EndObject(); + ->StartList("nested") + ->RenderString("", "value") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"nested\":[\"value\"]}", output_.substr(0, out_stream_->ByteCount())); } @@ -120,10 +123,10 @@ TEST_F(JsonObjectWriterTest, ListInObject) { TEST_F(JsonObjectWriterTest, ObjectInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartObject("") - ->RenderString("field", "value") - ->EndObject() - ->EndList(); + ->StartObject("") + ->RenderString("field", "value") + ->EndObject() + ->EndList(); EXPECT_EQ("[{\"field\":\"value\"}]", output_.substr(0, out_stream_->ByteCount())); } @@ -131,10 +134,10 @@ TEST_F(JsonObjectWriterTest, ObjectInList) { TEST_F(JsonObjectWriterTest, ListInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartList("") - ->RenderString("", "value") - ->EndList() - ->EndList(); + ->StartList("") + ->RenderString("", "value") + ->EndList() + ->EndList(); EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount())); } @@ -164,97 +167,95 @@ TEST_F(JsonObjectWriterTest, RenderPrimitives) { output_.substr(0, out_stream_->ByteCount())); } -TEST_F(JsonObjectWriterTest, BytesEncodesAsWebSafeBase64) { +TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { string s; s.push_back('\377'); s.push_back('\357'); ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("")->RenderBytes("bytes", s)->EndObject(); // Non-web-safe would encode this as "/+8=" - EXPECT_EQ("{\"bytes\":\"_-8=\"}", + EXPECT_EQ("{\"bytes\":\"/+8=\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("items") - ->RenderString("", "item1") - ->RenderString("", "item2") - ->RenderString("", "item3") - ->EndList() - ->StartList("empty") - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": [\n" - " \"item1\",\n" - " \"item2\",\n" - " \"item3\"\n" - " ],\n" - " \"empty\": []\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("items") + ->RenderString("", "item1") + ->RenderString("", "item2") + ->RenderString("", "item3") + ->EndList() + ->StartList("empty") + ->EndList() + ->EndObject(); + EXPECT_EQ("{\n" + " \"items\": [\n" + " \"item1\",\n" + " \"item2\",\n" + " \"item3\"\n" + " ],\n" + " \"empty\": []\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintObject) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartObject("items") - ->RenderString("key1", "item1") - ->RenderString("key2", "item2") - ->RenderString("key3", "item3") - ->EndObject() - ->StartObject("empty") - ->EndObject() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": {\n" - " \"key1\": \"item1\",\n" - " \"key2\": \"item2\",\n" - " \"key3\": \"item3\"\n" - " },\n" - " \"empty\": {}\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartObject("items") + ->RenderString("key1", "item1") + ->RenderString("key2", "item2") + ->RenderString("key3", "item3") + ->EndObject() + ->StartObject("empty") + ->EndObject() + ->EndObject(); + EXPECT_EQ("{\n" + " \"items\": {\n" + " \"key1\": \"item1\",\n" + " \"key2\": \"item2\",\n" + " \"key3\": \"item3\"\n" + " },\n" + " \"empty\": {}\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("list") - ->StartObject("") - ->EndObject() - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"list\": [\n" - " {}\n" - " ]\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("list") + ->StartObject("") + ->EndObject() + ->EndList() + ->EndObject(); + EXPECT_EQ("{\n" + " \"list\": [\n" + " {}\n" + " ]\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->RenderBool("bool", true) - ->RenderInt32("int", 42) - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"bool\": true,\n" - " \"int\": 42\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->RenderBool("bool", true) + ->RenderInt32("int", 42) + ->EndObject(); + EXPECT_EQ("{\n" + " \"bool\": true,\n" + " \"int\": 42\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); + ow_->StartObject("") + ->RenderString("string", "'<>&\\\"\r\n") + ->EndObject(); EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", output_.substr(0, out_stream_->ByteCount())); } @@ -262,13 +263,13 @@ TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { TEST_F(JsonObjectWriterTest, Stringification) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderDouble("double_nan", std::numeric_limits::quiet_NaN()) - ->RenderFloat("float_nan", std::numeric_limits::quiet_NaN()) - ->RenderDouble("double_pos", std::numeric_limits::infinity()) - ->RenderFloat("float_pos", std::numeric_limits::infinity()) - ->RenderDouble("double_neg", -std::numeric_limits::infinity()) - ->RenderFloat("float_neg", -std::numeric_limits::infinity()) - ->EndObject(); + ->RenderDouble("double_nan", std::numeric_limits::quiet_NaN()) + ->RenderFloat("float_nan", std::numeric_limits::quiet_NaN()) + ->RenderDouble("double_pos", std::numeric_limits::infinity()) + ->RenderFloat("float_pos", std::numeric_limits::infinity()) + ->RenderDouble("double_neg", -std::numeric_limits::infinity()) + ->RenderFloat("float_neg", -std::numeric_limits::infinity()) + ->EndObject(); EXPECT_EQ( "{\"double_nan\":\"NaN\"," "\"float_nan\":\"NaN\"," diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index d439a221d89f9..a7ef7fe2905bf 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -40,6 +40,7 @@ #include #endif +#include #include #include #include @@ -104,16 +105,42 @@ JsonStreamParser::JsonStreamParser(ObjectWriter* ow) parsed_(), parsed_storage_(), string_open_(0), - utf8_storage_(), - utf8_length_(0) { + chunk_storage_(), + coerce_to_utf8_(false) { // Initialize the stack with a single value to be parsed. stack_.push(VALUE); } JsonStreamParser::~JsonStreamParser() {} + util::Status JsonStreamParser::Parse(StringPiece json) { - return ParseChunk(json); + StringPiece chunk = json; + // If we have leftovers from a previous chunk, append the new chunk to it + // and create a new StringPiece pointing at the string's data. This could + // be large but we rely on the chunks to be small, assuming they are + // fragments of a Cord. + if (!leftover_.empty()) { + // Don't point chunk to leftover_ because leftover_ will be updated in + // ParseChunk(chunk). + chunk_storage_.swap(leftover_); + json.AppendToString(&chunk_storage_); + chunk = StringPiece(chunk_storage_); + } + + // Find the structurally valid UTF8 prefix and parse only that. + int n = internal::UTF8SpnStructurallyValid(chunk); + if (n > 0) { + util::Status status = ParseChunk(chunk.substr(0, n)); + + // Any leftover characters are stashed in leftover_ for later parsing when + // there is more data available. + chunk.substr(n).AppendToString(&leftover_); + return status; + } else { + chunk.CopyToString(&leftover_); + return util::Status::OK; + } } util::Status JsonStreamParser::FinishParse() { @@ -122,9 +149,22 @@ util::Status JsonStreamParser::FinishParse() { if (stack_.empty() && leftover_.empty()) { return util::Status::OK; } + + // Storage for UTF8-coerced string. + google::protobuf::scoped_array utf8; + if (coerce_to_utf8_) { + utf8.reset(new char[leftover_.size()]); + char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' '); + p_ = json_ = StringPiece(coerced, leftover_.size()); + } else { + if (!internal::IsStructurallyValidUTF8(leftover_)) { + return ReportFailure("Encountered non UTF-8 code points."); + } + p_ = json_ = leftover_; + } + // Parse the remainder in finishing mode, which reports errors for things like // unterminated strings or unknown tokens that would normally be retried. - p_ = json_ = StringPiece(leftover_); finishing_ = true; util::Status result = RunParser(); if (result.ok()) { @@ -137,16 +177,10 @@ util::Status JsonStreamParser::FinishParse() { } util::Status JsonStreamParser::ParseChunk(StringPiece chunk) { - // If we have leftovers from a previous chunk, append the new chunk to it and - // create a new StringPiece pointing at the string's data. This could be - // large but we rely on the chunks to be small, assuming they are fragments - // of a Cord. - if (!leftover_.empty()) { - chunk.AppendToString(&leftover_); - p_ = json_ = StringPiece(leftover_); - } else { - p_ = json_ = chunk; - } + // Do not do any work if the chunk is empty. + if (chunk.empty()) return util::Status::OK; + + p_ = json_ = chunk; finishing_ = false; util::Status result = RunParser(); diff --git a/src/google/protobuf/util/internal/json_stream_parser.h b/src/google/protobuf/util/internal/json_stream_parser.h index 17b094ae11962..0278c28fbc6ab 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.h +++ b/src/google/protobuf/util/internal/json_stream_parser.h @@ -75,12 +75,14 @@ class LIBPROTOBUF_EXPORT JsonStreamParser { explicit JsonStreamParser(ObjectWriter* ow); virtual ~JsonStreamParser(); - // Parse a JSON string (UTF-8 encoded). + // Parses a UTF-8 encoded JSON string from a StringPiece. util::Status Parse(StringPiece json); + // Finish parsing the JSON string. util::Status FinishParse(); + private: enum TokenType { BEGIN_STRING, // " or ' @@ -239,11 +241,11 @@ class LIBPROTOBUF_EXPORT JsonStreamParser { // A value of 0 indicates that string parsing is not in process. char string_open_; - // Storage for utf8-coerced bytes. - google::protobuf::scoped_array utf8_storage_; + // Storage for the chunk that are being parsed in ParseChunk(). + string chunk_storage_; - // Length of the storage for utf8-coerced bytes. - int utf8_length_; + // Whether to allow non UTF-8 encoded input and replace invalid code points. + bool coerce_to_utf8_; GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser); }; diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc index b0775a2fe2fdc..c833ed1fd3277 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -30,6 +30,7 @@ #include +#include #include #include #include @@ -85,7 +86,7 @@ class JsonStreamParserTest : public ::testing::Test { JsonStreamParserTest() : mock_(), ow_(&mock_) {} virtual ~JsonStreamParserTest() {} - util::Status RunTest(StringPiece json, int split) { + util::Status RunTest(StringPiece json, int split, bool coerce_utf8 = false) { JsonStreamParser parser(&mock_); // Special case for split == length, test parsing one character at a time. @@ -115,8 +116,8 @@ class JsonStreamParserTest : public ::testing::Test { return result; } - void DoTest(StringPiece json, int split) { - util::Status result = RunTest(json, split); + void DoTest(StringPiece json, int split, bool coerce_utf8 = false) { + util::Status result = RunTest(json, split, coerce_utf8); if (!result.ok()) { GOOGLE_LOG(WARNING) << result; } @@ -337,14 +338,26 @@ TEST_F(JsonStreamParserTest, ObjectValues) { } } + +TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { + StringPiece json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}"; + for (int i = 0; i <= json.length(); ++i) { + DoErrorTest(json, i, "Encountered non UTF-8 code points."); + } + json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}"; + for (int i = 0; i <= json.length(); ++i) { + DoErrorTest(json, i, "Encountered non UTF-8 code points."); + } +} + #ifndef _MSC_VER // - unicode handling in strings TEST_F(JsonStreamParserTest, UnicodeEscaping) { StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; for (int i = 0; i <= str.length(); ++i) { // TODO(xiaofeng): Figure out what default encoding to use for JSON strings. - // In protobuf we use UTF-8 for strings, but for JSON we probably should allow - // different encodings? + // In protobuf we use UTF-8 for strings, but for JSON we probably should + // allow different encodings? ow_.StartList("")->RenderString("", "\u0639\u0631\u0628\u0649")->EndList(); DoTest(str, i); } diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 53a0e47acccd8..18bb27729fd12 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -96,7 +97,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( } ProtoStreamObjectSource::ProtoStreamObjectSource( - google::protobuf::io::CodedInputStream* stream, TypeInfo* typeinfo, + google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, const google::protobuf::Type& type) : stream_(stream), typeinfo_(typeinfo), own_typeinfo_(false), type_(type) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; @@ -156,7 +157,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, last_tag = tag; field = FindAndVerifyField(type, tag); if (field != NULL) { - field_name = field->name(); + field_name = field->json_name(); } } if (field == NULL) { @@ -214,7 +215,7 @@ StatusOr ProtoStreamObjectSource::RenderMap( const google::protobuf::Field* field, StringPiece name, uint32 list_tag, ObjectWriter* ow) const { const google::protobuf::Type* field_type = - typeinfo_->GetType(field->type_url()); + typeinfo_->GetTypeByTypeUrl(field->type_url()); uint32 tag_to_return = 0; if (IsPackable(*field) && list_tag == @@ -784,7 +785,8 @@ Status ProtoStreamObjectSource::RenderField( // Get the nested enum type for this field. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this // up. - const google::protobuf::Enum* en = typeinfo_->GetEnum(field->type_url()); + const google::protobuf::Enum* en = + typeinfo_->GetEnumByTypeUrl(field->type_url()); // Lookup the name of the enum, and render that. Skips unknown enums. if (en != NULL) { const google::protobuf::EnumValue* enum_value = @@ -819,7 +821,7 @@ Status ProtoStreamObjectSource::RenderField( int old_limit = stream_->PushLimit(buffer32); // Get the nested message type for this field. const google::protobuf::Type* type = - typeinfo_->GetType(field->type_url()); + typeinfo_->GetTypeByTypeUrl(field->type_url()); if (type == NULL) { return Status(util::error::INTERNAL, StrCat("Invalid configuration. Could not find the type: ", @@ -928,7 +930,8 @@ const string ProtoStreamObjectSource::ReadFieldValueAsString( // Get the nested enum type for this field. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this // up. - const google::protobuf::Enum* en = typeinfo_->GetEnum(field.type_url()); + const google::protobuf::Enum* en = + typeinfo_->GetEnumByTypeUrl(field.type_url()); // Lookup the name of the enum, and render that. Skips unknown enums. if (en != NULL) { const google::protobuf::EnumValue* enum_value = @@ -962,7 +965,7 @@ const string ProtoStreamObjectSource::ReadFieldValueAsString( bool ProtoStreamObjectSource::IsMap( const google::protobuf::Field& field) const { const google::protobuf::Type* field_type = - typeinfo_->GetType(field.type_url()); + typeinfo_->GetTypeByTypeUrl(field.type_url()); // TODO(xiaofeng): Unify option names. return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 4a4e6bbf0d030..845437f584446 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -46,7 +46,6 @@ #include - namespace google { namespace protobuf { class Field; @@ -61,7 +60,10 @@ namespace converter { class TypeInfo; // An ObjectSource that can parse a stream of bytes as a protocol buffer. -// This implementation uses a tech Type for tag lookup. +// Its WriteTo() method can be given an ObjectWriter. +// This implementation uses a google.protobuf.Type for tag and name lookup. +// The field names are converted into lower camel-case when writing to the +// ObjectWriter. // // Sample usage: (suppose input is: string proto) // ArrayInputStream arr_stream(proto.data(), proto.size()); @@ -93,7 +95,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { private: ProtoStreamObjectSource(google::protobuf::io::CodedInputStream* stream, - TypeInfo* typeinfo, + const TypeInfo* typeinfo, const google::protobuf::Type& type); // Function that renders a well known type with a modified behavior. typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*, @@ -226,7 +228,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Whether this class owns the typeinfo_ object. If true the typeinfo_ object // should be deleted in the destructor. bool own_typeinfo_; diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 4cc624104b2a9..f6e5ee7a17a37 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -117,61 +117,61 @@ class ProtostreamObjectSourceTest void PrepareExpectingObjectWriterForRepeatedPrimitive() { ow_.StartObject("") - ->StartList("rep_fix32") + ->StartList("repFix32") ->RenderUint32("", bit_cast(3201)) ->RenderUint32("", bit_cast(0)) ->RenderUint32("", bit_cast(3202)) ->EndList() - ->StartList("rep_u32") + ->StartList("repU32") ->RenderUint32("", bit_cast(3203)) ->RenderUint32("", bit_cast(0)) ->EndList() - ->StartList("rep_i32") + ->StartList("repI32") ->RenderInt32("", 0) ->RenderInt32("", 3204) ->RenderInt32("", 3205) ->EndList() - ->StartList("rep_sf32") + ->StartList("repSf32") ->RenderInt32("", 3206) ->RenderInt32("", 0) ->EndList() - ->StartList("rep_s32") + ->StartList("repS32") ->RenderInt32("", 0) ->RenderInt32("", 3207) ->RenderInt32("", 3208) ->EndList() - ->StartList("rep_fix64") + ->StartList("repFix64") ->RenderUint64("", bit_cast(6401LL)) ->RenderUint64("", bit_cast(0LL)) ->EndList() - ->StartList("rep_u64") + ->StartList("repU64") ->RenderUint64("", bit_cast(0LL)) ->RenderUint64("", bit_cast(6402LL)) ->RenderUint64("", bit_cast(6403LL)) ->EndList() - ->StartList("rep_i64") + ->StartList("repI64") ->RenderInt64("", 6404L) ->RenderInt64("", 0L) ->EndList() - ->StartList("rep_sf64") + ->StartList("repSf64") ->RenderInt64("", 0L) ->RenderInt64("", 6405L) ->RenderInt64("", 6406L) ->EndList() - ->StartList("rep_s64") + ->StartList("repS64") ->RenderInt64("", 6407L) ->RenderInt64("", 0L) ->EndList() - ->StartList("rep_float") + ->StartList("repFloat") ->RenderFloat("", 0.0f) ->RenderFloat("", 32.1f) ->RenderFloat("", 32.2f) ->EndList() - ->StartList("rep_double") + ->StartList("repDouble") ->RenderDouble("", 64.1L) ->RenderDouble("", 0.0L) ->EndList() - ->StartList("rep_bool") + ->StartList("repBool") ->RenderBool("", true) ->RenderBool("", false) ->EndList() @@ -317,11 +317,11 @@ TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { primitive.add_rep_str("String Two"); primitive.add_rep_bytes("Some Bytes"); - ow_.StartList("rep_str") + ow_.StartList("repStr") ->RenderString("", "String One") ->RenderString("", "String Two") ->EndList() - ->StartList("rep_bytes") + ->StartList("repBytes") ->RenderBytes("", "Some Bytes") ->EndList(); DoTest(primitive, Primitive::descriptor()); @@ -794,16 +794,16 @@ TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { ow_.StartObject("") ->RenderString("id", "1") - ->RenderString("single_mask", "path1,snakeCasePath2") - ->StartList("repeated_mask") + ->RenderString("singleMask", "path1,snakeCasePath2") + ->StartList("repeatedMask") ->RenderString("", "path3") ->RenderString("", "snakeCasePath4,path5") ->EndList() - ->StartList("nested_mask") + ->StartList("nestedMask") ->StartObject("") ->RenderString("data", "data") - ->RenderString("single_mask", "nested.path1,nestedField.snakeCasePath2") - ->StartList("repeated_mask") + ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2") + ->StartList("repeatedMask") ->RenderString("", "nestedField.path3,nested.snakeCasePath4") ->RenderString("", "nested.path5") ->RenderString("", diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index f9ddbf326d4c5..87f504e0a418f 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -74,7 +74,7 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( tracker_(new ObjectLocationTracker()) {} ProtoStreamObjectWriter::ProtoStreamObjectWriter( - TypeInfo* typeinfo, const google::protobuf::Type& type, + const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener) : master_type_(type), typeinfo_(typeinfo), @@ -91,14 +91,19 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( tracker_(new ObjectLocationTracker()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { - // Cleanup explicitly in order to avoid destructor stack overflow when input - // is deeply nested. - while (element_ != NULL) { - element_.reset(element_->pop()); - } if (own_typeinfo_) { delete typeinfo_; } + if (element_ == NULL) return; + // Cleanup explicitly in order to avoid destructor stack overflow when input + // is deeply nested. + // Cast to BaseElement to avoid doing additional checks (like missing fields) + // during pop(). + google::protobuf::scoped_ptr element( + static_cast(element_.get())->pop()); + while (element != NULL) { + element.reset(element->pop()); + } } namespace { @@ -454,7 +459,7 @@ void ProtoStreamObjectWriter::AnyWriter::WriteAny() { } ProtoStreamObjectWriter::ProtoElement::ProtoElement( - TypeInfo* typeinfo, const google::protobuf::Type& type, + const TypeInfo* typeinfo, const google::protobuf::Type& type, ProtoStreamObjectWriter* enclosing) : BaseElement(NULL), ow_(enclosing), @@ -586,6 +591,14 @@ string ProtoStreamObjectWriter::ProtoElement::ToString() const { return loc.empty() ? "." : loc; } +bool ProtoStreamObjectWriter::ProtoElement::OneofIndexTaken(int32 index) { + return ContainsKey(oneof_indices_, index); +} + +void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) { + InsertIfNotPresent(&oneof_indices_, index); +} + inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name, StringPiece message) { listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); @@ -655,6 +668,13 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( return this; } + // Check to see if this field is a oneof and that no oneof in that group has + // already been set. + if (!ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + if (field->type_url() == GetFullTypeWithUrl(kStructType)) { // Start a struct object. StartStruct(field); @@ -932,6 +952,14 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Also we ignore if the field is not found here as it is caught later. field = typeinfo_->FindField(&element_->type(), name); + // Only check for oneof collisions on the first StartList call. We identify + // the first call with !name.empty() check. Subsequent list element calls + // will not have the name filled. + if (!name.empty() && field && !ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + // It is an error to try to bind to map, which behind the scenes is a list. if (field && IsMap(*field)) { // Push field to stack for error location tracking & reporting. @@ -1080,9 +1108,9 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, data.ValueAsStringOrDefault(""))); } - // TODO(tsun): figure out how to do proto descriptor based snake case - // conversions as much as possible. Because ToSnakeCase sometimes returns the - // wrong value. +// TODO(tsun): figure out how to do proto descriptor based snake case +// conversions as much as possible. Because ToSnakeCase sometimes returns the +// wrong value. google::protobuf::scoped_ptr > callback( NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); @@ -1154,6 +1182,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( const google::protobuf::Field* field = NULL; string type_url; bool is_map_entry = false; + // We are at the root when element_ == NULL. if (element_ == NULL) { type_url = GetFullTypeWithUrl(master_type_.name()); } else { @@ -1166,6 +1195,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( if (field == NULL) { return this; } + + // Check to see if this field is a oneof and that no oneof in that group has + // already been set. + if (!ValidOneof(*field, name)) return this; + type_url = field->type_url(); } @@ -1314,7 +1348,8 @@ void ProtoStreamObjectWriter::RenderSimpleDataPiece( } case google::protobuf::Field_Kind_TYPE_ENUM: { status = WriteEnum(field.number(), data, - typeinfo_->GetEnum(field.type_url()), stream_.get()); + typeinfo_->GetEnumByTypeUrl(field.type_url()), + stream_.get()); break; } default: // TYPE_GROUP or TYPE_MESSAGE @@ -1401,6 +1436,24 @@ ProtoStreamObjectWriter::GetElementType(const google::protobuf::Type& type) { } } +bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name) { + if (element_ == NULL) return true; + + if (field.oneof_index() > 0) { + if (element_->OneofIndexTaken(field.oneof_index())) { + InvalidValue( + "oneof", + StrCat("oneof field '", + element_->type().oneofs(field.oneof_index() - 1), + "' is already set. Cannot set '", unnormalized_name, "'")); + return false; + } + element_->TakeOneofIndex(field.oneof_index()); + } + return true; +} + const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed( StringPiece name, bool is_list) { if (invalid_depth_ > 0) { @@ -1450,7 +1503,7 @@ const google::protobuf::Field* ProtoStreamObjectWriter::Lookup( const google::protobuf::Type* ProtoStreamObjectWriter::LookupType( const google::protobuf::Field* field) { return (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE - ? typeinfo_->GetType(field->type_url()) + ? typeinfo_->GetTypeByTypeUrl(field->type_url()) : &element_->type()); } @@ -1539,7 +1592,7 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { return false; } const google::protobuf::Type* field_type = - typeinfo_->GetType(field.type_url()); + typeinfo_->GetTypeByTypeUrl(field.type_url()); return GetBoolOptionOrDefault(field_type->options(), "google.protobuf.MessageOptions.map_entry", false); diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index eb4a59f917257..f11c47c0a5f86 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -71,7 +71,7 @@ class ObjectLocationTracker; // It also supports streaming. class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter { public: - // Constructor. Does not take ownership of any parameter passed in. +// Constructor. Does not take ownership of any parameter passed in. ProtoStreamObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); @@ -82,20 +82,17 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter virtual ProtoStreamObjectWriter* EndObject(); virtual ProtoStreamObjectWriter* StartList(StringPiece name); virtual ProtoStreamObjectWriter* EndList(); - virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, - bool value) { + virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, bool value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, - int32 value) { + virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, int32 value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name, uint32 value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, - int64 value) { + virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, int64 value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name, @@ -106,8 +103,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter double value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, - float value) { + virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, float value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderString(StringPiece name, @@ -217,7 +213,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter }; // Constructor for the root element. No parent nor field. - ProtoElement(TypeInfo* typeinfo, const google::protobuf::Type& type, + ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, ProtoStreamObjectWriter* enclosing); // Constructor for a field of an element. @@ -256,6 +252,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter return static_cast(BaseElement::parent()); } + // Returns true if the index is already taken by a preceeding oneof input. + bool OneofIndexTaken(int32 index); + + // Marks the oneof 'index' as taken. Future inputs to this oneof will + // generate an error. + void TakeOneofIndex(int32 index); + private: // Used for access to variables of the enclosing instance of // ProtoStreamObjectWriter. @@ -269,7 +272,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter const google::protobuf::Field* field_; // TypeInfo to lookup types. - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Additional variables if this element is a message: // (Root element is always a message). @@ -289,6 +292,10 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // The type of this element, see enum for permissible types. ElementType element_type_; + // Set of oneof indices already seen for the type_. Used to validate + // incoming messages so no more than one oneof is set. + hash_set oneof_indices_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); }; @@ -298,7 +305,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter int size; }; - ProtoStreamObjectWriter(TypeInfo* typeinfo, + ProtoStreamObjectWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); @@ -407,11 +414,19 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter static ProtoElement::ElementType GetElementType( const google::protobuf::Type& type); + // Returns true if the field for type_ can be set as a oneof. If field is not + // a oneof type, this function does nothing and returns true. + // If another field for this oneof is already set, this function returns + // false. It also calls the appropriate error callback. + // unnormalized_name is used for error string. + bool ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name); + // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. // typeinfo_ : the TypeInfo object to lookup types. const google::protobuf::Type& master_type_; - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Whether we own the typeinfo_ object. bool own_typeinfo_; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index bd4f29f5baa53..96e5ccfbf8915 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ using ::testing::_; using ::testing::Args; using google::protobuf::testing::anys::AnyM; using google::protobuf::testing::anys::AnyOut; +using google::protobuf::testing::oneofs::OneOfsRequest; using google::protobuf::testing::FieldMaskTest; using google::protobuf::testing::maps::MapIn; using google::protobuf::testing::structs::StructType; @@ -143,7 +145,7 @@ class BaseProtoStreamObjectWriterTest void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } const google::protobuf::Type* GetType(const Descriptor* descriptor) { - return helper_.GetTypeInfo()->GetType(GetTypeUrl(descriptor)); + return helper_.GetTypeInfo()->GetTypeByTypeUrl(GetTypeUrl(descriptor)); } testing::TypeInfoTestHelper helper_; @@ -854,11 +856,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z'"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Illegal timestamp format; timestamps " + "must end with 'Z'"))); ow_->StartObject("")->RenderString("ts", "")->EndObject(); CheckOutput(timestamp); @@ -883,11 +884,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format, failed to parse nano " + "seconds"))); ow_->StartObject("") ->RenderString("ts", "1970-01-01T00:00:00.ABZ") @@ -919,11 +919,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Illegal duration format; duration must " - "end with 's'"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Illegal duration format; duration must " + "end with 's'"))); ow_->StartObject("")->RenderString("dur", "")->EndObject(); CheckOutput(duration); @@ -934,11 +933,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Invalid duration format, failed to parse " - "seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Invalid duration format, failed to parse " + "seconds"))); ow_->StartObject("")->RenderString("dur", "s")->EndObject(); CheckOutput(duration); @@ -949,11 +947,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Invalid duration format, failed to " - "parse nanos seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Invalid duration format, failed to " + "parse nanos seconds"))); ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject(); CheckOutput(duration); @@ -1174,10 +1171,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1192,10 +1189,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1210,10 +1207,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1227,13 +1224,12 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithInvalidTypeUrlFails) { AnyOut any; - EXPECT_CALL( - listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Invalid type URL, type URLs must be of the form " - "'type.googleapis.com/', got: " - "type.other.com/some.Type"))); + EXPECT_CALL(listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Invalid type URL, type URLs must be of the form " + "'type.googleapis.com/', got: " + "type.other.com/some.Type"))); ow_->StartObject("") ->StartObject("any") @@ -1401,11 +1397,10 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MaskUsingApiaryStyleShouldWork) { TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreCloseThanOpenParentheses) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask 'a(b,c))'. " - "Cannot find matching '(' for all ')'."))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), + StringPiece("Field 'single_mask', Invalid FieldMask 'a(b,c))'. " + "Cannot find matching '(' for all ')'."))); ow_->StartObject(""); ow_->RenderString("id", "1"); @@ -1448,12 +1443,11 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeAtTheEndOfAPathSegment) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " - "Map keys should be at the end of a path segment."))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " + "Map keys should be at the end of a path segment."))); ow_->StartObject(""); ow_->RenderString("single_mask", @@ -1466,10 +1460,9 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustEnd) { listener_, InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"'. Map keys should be " - "represented as [\"some_key\"]."))); + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"key1\"'. Map keys should be " + "represented as [\"some_key\"]."))); ow_->StartObject(""); ow_->RenderString("single_mask", "path.to.map[\"key1\""); @@ -1481,10 +1474,9 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) { listener_, InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"ke\"y1\"]'. Map keys should be " - "represented as [\"some_key\"]."))); + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"ke\"y1\"]'. Map keys should be " + "represented as [\"some_key\"]."))); ow_->StartObject(""); ow_->RenderString("single_mask", "path.to.map[\"ke\"y1\"]"); @@ -1507,6 +1499,192 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { CheckOutput(expected); } +class ProtoStreamObjectWriterOneOfsTest + : public BaseProtoStreamObjectWriterTest { + protected: + ProtoStreamObjectWriterOneOfsTest() { + vector descriptors; + descriptors.push_back(OneOfsRequest::descriptor()); + descriptors.push_back(google::protobuf::Struct::descriptor()); + ResetTypeInfo(descriptors); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterOneOfsTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForPrimitiveTypesTest) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("oneof"), + StringPiece( + "oneof field 'data' is already set. Cannot set 'intData'"))); + + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->RenderString("intData", "123"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForMessageTypesPrimitiveFirstTest) { + // Test for setting primitive oneof field first and then message field. + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'messageData'"))); + + // JSON: { "strData": "blah", "messageData": { "dataValue": 123 } } + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForMessageTypesMessageFirstTest) { + // Test for setting message oneof field first and then primitive field. + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'strData'"))); + + // JSON: { "messageData": { "dataValue": 123 }, "strData": "blah" } + ow_->StartObject(""); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->RenderString("strData", "blah"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructTypesPrimitiveFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'structData'"))); + + // JSON: { "strData": "blah", "structData": { "a": "b" } } + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->StartObject("structData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructTypesStructFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'strData'"))); + + // JSON: { "structData": { "a": "b" }, "strData": "blah" } + ow_->StartObject(""); + ow_->StartObject("structData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->RenderString("strData", "blah"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructValueTypesTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'valueData'"))); + + // JSON: { "messageData": { "dataValue": 123 }, "valueData": { "a": "b" } } + ow_->StartObject(""); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->StartObject("valueData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesPrimitiveFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'tsData'"))); + + // JSON: { "intData": 123, "tsData": "1970-01-02T01:00:00.000Z" } + ow_->StartObject(""); + ow_->RenderInt32("intData", 123); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesWktFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'intData'"))); + + // JSON: { "tsData": "1970-01-02T01:00:00.000Z", "intData": 123 } + ow_->StartObject(""); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->RenderInt32("intData", 123); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesAndMessageTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'messageData'"))); + + // JSON: { "tsData": "1970-01-02T01:00:00.000Z", + // "messageData": { "dataValue": 123 } } + ow_->StartObject(""); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForOneofWithinAnyTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'intData'"))); + + using google::protobuf::testing::oneofs::OneOfsRequest; + // JSON: + // { "anyData": + // { "@type": + // "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest", + // "strData": "blah", + // "intData": 123 + // } + // } + ow_->StartObject(""); + ow_->StartObject("anyData"); + ow_->RenderString( + "@type", + "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest"); + ow_->RenderString("strData", "blah"); + ow_->RenderInt32("intData", 123); + ow_->EndObject(); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter.h b/src/google/protobuf/util/internal/snake2camel_objectwriter.h index 1a32bc5624368..9b4ab8a385321 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter.h +++ b/src/google/protobuf/util/internal/snake2camel_objectwriter.h @@ -58,9 +58,7 @@ class Snake2CamelObjectWriter : public ObjectWriter { // ObjectWriter methods. virtual Snake2CamelObjectWriter* StartObject(StringPiece name) { - ow_->StartObject(ShouldNormalizeCase(name) - ? StringPiece(StringPiece(ToCamelCase(name))) - : name); + ow_->StartObject(name); return this; } @@ -70,8 +68,7 @@ class Snake2CamelObjectWriter : public ObjectWriter { } virtual Snake2CamelObjectWriter* StartList(StringPiece name) { - ow_->StartList(ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) - : name); + ow_->StartList(name); return this; } @@ -81,76 +78,57 @@ class Snake2CamelObjectWriter : public ObjectWriter { } virtual Snake2CamelObjectWriter* RenderBool(StringPiece name, bool value) { - ow_->RenderBool( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderBool(name, value); return this; } virtual Snake2CamelObjectWriter* RenderInt32(StringPiece name, int32 value) { - ow_->RenderInt32( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderInt32(name, value); return this; } virtual Snake2CamelObjectWriter* RenderUint32(StringPiece name, uint32 value) { - ow_->RenderUint32( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderUint32(name, value); return this; } virtual Snake2CamelObjectWriter* RenderInt64(StringPiece name, int64 value) { - ow_->RenderInt64( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderInt64(name, value); return this; } virtual Snake2CamelObjectWriter* RenderUint64(StringPiece name, uint64 value) { - ow_->RenderUint64( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderUint64(name, value); return this; } virtual Snake2CamelObjectWriter* RenderDouble(StringPiece name, double value) { - ow_->RenderDouble( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderDouble(name, value); return this; } virtual Snake2CamelObjectWriter* RenderFloat(StringPiece name, float value) { - ow_->RenderFloat( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderFloat(name, value); return this; } virtual Snake2CamelObjectWriter* RenderString(StringPiece name, StringPiece value) { - ow_->RenderString( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderString(name, value); return this; } virtual Snake2CamelObjectWriter* RenderBytes(StringPiece name, StringPiece value) { - ow_->RenderBytes( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderBytes(name, value); return this; } virtual Snake2CamelObjectWriter* RenderNull(StringPiece name) { - ow_->RenderNull(ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) - : name); + ow_->RenderNull(name); return this; } diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc index 67388c3b57bf9..e5db844c574d8 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc @@ -47,263 +47,9 @@ class Snake2CamelObjectWriterTest : public ::testing::Test { Snake2CamelObjectWriter testing_; }; -TEST_F(Snake2CamelObjectWriterTest, Empty) { - // Set expectation - expects_.StartObject("")->EndObject(); - - // Actual testing - testing_.StartObject("")->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, UnderscoresOnly) { - // Set expectation - expects_.StartObject("") - ->RenderInt32("", 1) - ->RenderInt32("", 2) - ->RenderInt32("", 3) - ->RenderInt32("", 4) - ->RenderInt32("", 5) - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderInt32("_", 1) - ->RenderInt32("__", 2) - ->RenderInt32("___", 3) - ->RenderInt32("____", 4) - ->RenderInt32("_____", 5) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LowercaseOnly) { - // Set expectation - expects_.StartObject("") - ->RenderString("key", "value") - ->RenderString("abracadabra", "magic") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("key", "value") - ->RenderString("abracadabra", "magic") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, UppercaseOnly) { - // Set expectation - expects_.StartObject("") - ->RenderString("key", "VALUE") - ->RenderString("abracadabra", "MAGIC") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("KEY", "VALUE") - ->RenderString("ABRACADABRA", "MAGIC") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, CamelCase) { - // Set expectation - expects_.StartObject("") - ->RenderString("camelCase", "camelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "theQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("camelCase", "camelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "theQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, FirstCapCamelCase) { - // Sets expectation - expects_.StartObject("camel") - ->RenderString("camelCase", "CamelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "TheQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); - - // Actual testing - testing_.StartObject("Camel") - ->RenderString("CamelCase", "CamelCase") - ->RenderString("TheQuickBrownFoxJumpsOverTheLazyDog", - "TheQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LastCapCamelCase) { - // Sets expectation - expects_.StartObject("lastCapCamelCasE")->EndObject(); - - // Actual testing - testing_.StartObject("lastCapCamelCasE")->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, MixedCapCamelCase) { - // Sets expectation - expects_.StartObject("googleIsTheBest") - ->RenderFloat("iLoveGOOGLE", 1.61803f) - ->RenderFloat("goGoogleGO", 2.71828f) - ->RenderFloat("gBikeISCool", 3.14159f) - ->EndObject(); - - // Actual testing - testing_.StartObject("GOOGLEIsTheBest") - ->RenderFloat("ILoveGOOGLE", 1.61803f) - ->RenderFloat("GOGoogleGO", 2.71828f) - ->RenderFloat("GBikeISCool", 3.14159f) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, MixedCase) { - // Sets expectation - expects_.StartObject("snakeCaseCamelCase") - ->RenderBool("camelCaseSnakeCase", false) - ->RenderBool("mixedCamelAndUnderScores", false) - ->RenderBool("goGOOGLEGo", true) - ->EndObject(); - - // Actual testing - testing_.StartObject("snake_case_camelCase") - ->RenderBool("camelCase_snake_case", false) - ->RenderBool("MixedCamel_And_UnderScores", false) - ->RenderBool("Go_GOOGLEGo", true) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, SnakeCase) { - // Sets expectation - expects_.StartObject("") - ->RenderString("snakeCase", "snake_case") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("snake_case", "snake_case") - ->RenderString("the_quick_brown_fox_jumps_over_the_lazy_dog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, FirstCapSnakeCase) { - // Sets expectation - expects_.StartObject("firstCapSnakeCase") - ->RenderBool("helloWorld", true) - ->EndObject(); - - // Actual testing - testing_.StartObject("First_Cap_Snake_Case") - ->RenderBool("Hello_World", true) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, AllCapSnakeCase) { - // Sets expectation - expects_.StartObject("allCAPSNAKECASE") - ->RenderDouble("nyseGOOGL", 600.0L) - ->RenderDouble("aBCDE", 1.0L) - ->RenderDouble("klMNOP", 2.0L) - ->RenderDouble("abcIJKPQRXYZ", 3.0L) - ->EndObject(); - - // Actual testing - testing_.StartObject("ALL_CAP_SNAKE_CASE") - ->RenderDouble("NYSE_GOOGL", 600.0L) - ->RenderDouble("A_B_C_D_E", 1.0L) - ->RenderDouble("KL_MN_OP", 2.0L) - ->RenderDouble("ABC_IJK_PQR_XYZ", 3.0L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, RepeatedUnderScoreSnakeCase) { - // Sets expectation - expects_.StartObject("") - ->RenderInt32("doubleUnderscoreSnakeCase", 2) - ->RenderInt32("tripleUnderscoreFirstCap", 3) - ->RenderInt32("quadrupleUNDERSCOREALLCAP", 4) - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderInt32("double__underscore__snake__case", 2) - ->RenderInt32("Triple___Underscore___First___Cap", 3) - ->RenderInt32("QUADRUPLE____UNDERSCORE____ALL____CAP", 4) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LeadingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("leadingUnderscoreSnakeCase") - ->RenderUint32("leadingDoubleUnderscore", 2) - ->RenderUint32("leadingTripleUnderscoreFirstCap", 3) - ->RenderUint32("leadingQUADRUPLEUNDERSCOREALLCAP", 4) - ->EndObject(); - - // Actual testing - testing_.StartObject("_leading_underscore_snake_case") - ->RenderUint32("__leading_double_underscore", 2) - ->RenderUint32("___Leading_Triple_Underscore_First_Cap", 3) - ->RenderUint32("____LEADING_QUADRUPLE_UNDERSCORE_ALL_CAP", 4) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, TrailingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("trailingUnderscoreSnakeCase") - ->RenderInt64("trailingDoubleUnderscore", 2L) - ->RenderInt64("trailingTripleUnderscoreFirstCap", 3L) - ->RenderInt64("trailingQUADRUPLEUNDERSCOREALLCAP", 4L) - ->EndObject(); - - // Actual testing - testing_.StartObject("trailing_underscore_snake_case") - ->RenderInt64("trailing_double_underscore__", 2L) - ->RenderInt64("Trailing_Triple_Underscore_First_Cap___", 3L) - ->RenderInt64("TRAILING_QUADRUPLE_UNDERSCORE_ALL_CAP____", 4L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, EnclosingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("enclosingUnderscoreSnakeCase") - ->RenderUint64("enclosingDoubleUnderscore", 2L) - ->RenderUint64("enclosingTripleUnderscoreFirstCap", 3L) - ->RenderUint64("enclosingQUADRUPLEUNDERSCOREALLCAP", 4L) - ->EndObject(); - - // Actual testing - testing_.StartObject("_enclosing_underscore_snake_case_") - ->RenderUint64("__enclosing_double_underscore__", 2L) - ->RenderUint64("___Enclosing_Triple_Underscore_First_Cap___", 3L) - ->RenderUint64("____ENCLOSING_QUADRUPLE_UNDERSCORE_ALL_CAP____", 4L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, DisableCaseNormalizationOnlyDisablesFirst) { - // Sets expectation - expects_.StartObject("") - ->RenderString("snakeCase", "snake_case") - ->RenderString( - "the_quick_brown_fox_jumps_over_the_lazy_dog", // case retained - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->RenderBool("theSlowFox", true) // disable case not in effect - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("snake_case", "snake_case") - ->DisableCaseNormalizationForNextKey() - ->RenderString("the_quick_brown_fox_jumps_over_the_lazy_dog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->RenderBool("the_slow_fox", true) - ->EndObject(); -} +// All tests are deleted as they are no longer needed. This file will be removed +// after the component dependecies are cleaned up. +// TODO(skarvaje): Remove this file. } // namespace converter } // namespace util diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto index ecfc811908095..ebbdf6ab20dd7 100644 --- a/src/google/protobuf/util/internal/testdata/default_value.proto +++ b/src/google/protobuf/util/internal/testdata/default_value.proto @@ -43,6 +43,7 @@ message DefaultValueTestCases { DoubleMessage repeated_double = 4; DoubleMessage nested_message = 5; DoubleMessage repeated_nested_message = 6; + DoubleMessage double_message_with_oneof = 7; StructMessage empty_struct = 201; StructMessage empty_struct2 = 202; StructMessage struct_with_null_value = 203; @@ -75,6 +76,8 @@ message DefaultValueTestCases { MixedMap mixed1 = 404; MixedMap2 mixed2 = 405; MessageMap map_of_objects = 406; + MixedMap mixed_empty = 407; + MessageMap message_map_empty = 408; DoubleValueMessage double_value = 501; DoubleValueMessage double_value_default = 502; } @@ -85,6 +88,10 @@ message DoubleMessage { DoubleMessage nested_message = 3; repeated DoubleMessage repeated_nested_message = 4; google.protobuf.DoubleValue double_wrapper = 100; + oneof value { + string str_value = 112; + int64 num_value = 113; + } } message StructMessage { diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc index 6392e18c9859c..a45a76e37da3f 100644 --- a/src/google/protobuf/util/internal/type_info.cc +++ b/src/google/protobuf/util/internal/type_info.cc @@ -35,11 +35,11 @@ #include #include +#include #include #include #include #include -#include namespace google { namespace protobuf { @@ -47,7 +47,6 @@ namespace util { namespace converter { namespace { - // A TypeInfo that looks up information provided by a TypeResolver. class TypeInfoForTypeResolver : public TypeInfo { public: @@ -60,7 +59,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual util::StatusOr ResolveTypeUrl( - StringPiece type_url) { + StringPiece type_url) const { map::iterator it = cached_types_.find(type_url); if (it != cached_types_.end()) { return it->second; @@ -78,12 +77,14 @@ class TypeInfoForTypeResolver : public TypeInfo { return result; } - virtual const google::protobuf::Type* GetType(StringPiece type_url) { + virtual const google::protobuf::Type* GetTypeByTypeUrl( + StringPiece type_url) const { StatusOrType result = ResolveTypeUrl(type_url); return result.ok() ? result.ValueOrDie() : NULL; } - virtual const google::protobuf::Enum* GetEnum(StringPiece type_url) { + virtual const google::protobuf::Enum* GetEnumByTypeUrl( + StringPiece type_url) const { map::iterator it = cached_enums_.find(type_url); if (it != cached_enums_.end()) { return it->second.ok() ? it->second.ValueOrDie() : NULL; @@ -103,7 +104,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, StringPiece camel_case_name) { + const google::protobuf::Type* type, StringPiece camel_case_name) const { if (indexed_types_.find(type) == indexed_types_.end()) { PopulateNameLookupTable(type); indexed_types_.insert(type); @@ -131,7 +132,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } } - void PopulateNameLookupTable(const google::protobuf::Type* type) { + void PopulateNameLookupTable(const google::protobuf::Type* type) const { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); StringPiece name = field.name(); @@ -151,13 +152,13 @@ class TypeInfoForTypeResolver : public TypeInfo { // Stores string values that will be referenced by StringPieces in // cached_types_, cached_enums_ and camel_case_name_table_. - set string_storage_; + mutable set string_storage_; - map cached_types_; - map cached_enums_; + mutable map cached_types_; + mutable map cached_enums_; - set indexed_types_; - map camel_case_name_table_; + mutable set indexed_types_; + mutable map camel_case_name_table_; }; } // namespace diff --git a/src/google/protobuf/util/internal/type_info.h b/src/google/protobuf/util/internal/type_info.h index 67403fff6db61..e394e8cfde38c 100644 --- a/src/google/protobuf/util/internal/type_info.h +++ b/src/google/protobuf/util/internal/type_info.h @@ -44,7 +44,7 @@ namespace util { namespace converter { // Internal helper class for type resolving. Note that this class is not // thread-safe and should only be accessed in one thread. -class LIBPROTOBUF_EXPORT TypeInfo { +class TypeInfo { public: TypeInfo() {} virtual ~TypeInfo() {} @@ -55,24 +55,29 @@ class LIBPROTOBUF_EXPORT TypeInfo { // // This TypeInfo class retains the ownership of the returned pointer. virtual util::StatusOr ResolveTypeUrl( - StringPiece type_url) = 0; + StringPiece type_url) const = 0; // Resolves a type url into a Type. Like ResolveTypeUrl() but returns // NULL if the type url is invalid or the type cannot be found. // // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Type* GetType(StringPiece type_url) = 0; + virtual const google::protobuf::Type* GetTypeByTypeUrl( + StringPiece type_url) const = 0; // Resolves a type url for an enum. Returns NULL if the type url is // invalid or the type cannot be found. // // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Enum* GetEnum(StringPiece type_url) = 0; + virtual const google::protobuf::Enum* GetEnumByTypeUrl( + StringPiece type_url) const = 0; // Looks up a field in the specified type given a CamelCase name. virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, StringPiece camel_case_name) = 0; + const google::protobuf::Type* type, + StringPiece camel_case_name) const = 0; + // Creates a TypeInfo object that looks up type information from a + // TypeResolver. Caller takes ownership of the returned pointer. static TypeInfo* NewTypeInfo(TypeResolver* type_resolver); private: diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc index 177b96e206de6..1b9c5154ed6ab 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ b/src/google/protobuf/util/internal/type_info_test_helper.cc @@ -36,6 +36,7 @@ #endif #include +#include #include #include #include @@ -89,7 +90,7 @@ TypeInfo* TypeInfoTestHelper::GetTypeInfo() { return typeinfo_.get(); } ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( io::CodedInputStream* coded_input, const string& type_url) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectSource(coded_input, type_resolver_.get(), @@ -103,7 +104,7 @@ ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( const string& type_url, strings::ByteSink* output, ErrorListener* listener) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output, @@ -116,7 +117,7 @@ ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( DefaultValueObjectWriter* TypeInfoTestHelper::NewDefaultValueWriter( const string& type_url, ObjectWriter* writer) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new DefaultValueObjectWriter(type_resolver_.get(), *type, writer); diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 794777d44de2d..2d63de00e923d 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -34,7 +34,9 @@ #include #include +#include #include +#include #include #include #include @@ -303,7 +305,7 @@ bool IsMap(const google::protobuf::Field& field, string DoubleAsString(double value) { if (value == std::numeric_limits::infinity()) return "Infinity"; if (value == -std::numeric_limits::infinity()) return "-Infinity"; - if (google::protobuf::MathLimits::IsNaN(value)) return "NaN"; + if (MathLimits::IsNaN(value)) return "NaN"; return SimpleDtoa(value); } diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h index d0d88c1985d73..87f7602a9ce51 100644 --- a/src/google/protobuf/util/internal/utility.h +++ b/src/google/protobuf/util/internal/utility.h @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -117,23 +118,23 @@ LIBPROTOBUF_EXPORT const string GetFullTypeWithUrl(StringPiece simple_type); // Finds and returns option identified by name and option_name within the // provided map. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::Option* FindOptionOrNull( +const google::protobuf::Option* FindOptionOrNull( const google::protobuf::RepeatedPtrField& options, const string& option_name); // Finds and returns the field identified by field_name in the passed tech Type // object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::Field* FindFieldInTypeOrNull( +const google::protobuf::Field* FindFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece field_name); // Finds and returns the EnumValue identified by enum_name in the passed tech // Enum object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::EnumValue* FindEnumValueByNameOrNull( +const google::protobuf::EnumValue* FindEnumValueByNameOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name); // Finds and returns the EnumValue identified by value in the passed tech // Enum object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( +const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( const google::protobuf::Enum* enum_type, int32 value); // Converts input to camel-case and returns it. @@ -153,7 +154,7 @@ LIBPROTOBUF_EXPORT bool IsWellKnownType(const string& type_name); LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string); // Returns true if "field" is a protobuf map field based on its type. -bool IsMap(const google::protobuf::Field& field, +LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field, const google::protobuf::Type& type); // Infinity/NaN-aware conversion to string. diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h index 6796ea089fb8a..614564cc1abfe 100644 --- a/src/google/protobuf/util/json_util.h +++ b/src/google/protobuf/util/json_util.h @@ -44,7 +44,7 @@ class ZeroCopyOutputStream; } // namespace io namespace util { -struct LIBPROTOBUF_EXPORT JsonOptions { +struct JsonOptions { // Whether to add spaces, line breaks and indentation to make the JSON output // easy to read. bool add_whitespace; @@ -65,7 +65,7 @@ struct LIBPROTOBUF_EXPORT JsonOptions { // 2. input is not valid protobuf wire format, or conflicts with the type // information returned by TypeResolver. // Note that unknown fields will be discarded silently. -LIBPROTOBUF_EXPORT util::Status BinaryToJsonStream( +util::Status BinaryToJsonStream( TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* binary_input, @@ -80,7 +80,7 @@ inline util::Status BinaryToJsonStream( JsonOptions()); } -LIBPROTOBUF_EXPORT util::Status BinaryToJsonString( +util::Status BinaryToJsonString( TypeResolver* resolver, const string& type_url, const string& binary_input, @@ -101,13 +101,13 @@ inline util::Status BinaryToJsonString(TypeResolver* resolver, // 2. input is not valid JSON format, or conflicts with the type // information returned by TypeResolver. // 3. input has unknown fields. -LIBPROTOBUF_EXPORT util::Status JsonToBinaryStream( +util::Status JsonToBinaryStream( TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* json_input, io::ZeroCopyOutputStream* binary_output); -LIBPROTOBUF_EXPORT util::Status JsonToBinaryString( +util::Status JsonToBinaryString( TypeResolver* resolver, const string& type_url, const string& json_input, diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 8399b4080b1a0..7f88e6724d325 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -98,27 +98,28 @@ TEST_F(JsonUtilTest, TestWhitespaces) { ToJson(m, options)); } -TEST_F(JsonUtilTest, TestDefaultValues) { - TestMessage m; - JsonOptions options; - EXPECT_EQ("{}", ToJson(m, options)); - options.always_print_primitive_fields = true; - EXPECT_EQ( - "{\"boolValue\":false," - "\"int32Value\":0," - "\"int64Value\":\"0\"," - "\"uint32Value\":0," - "\"uint64Value\":\"0\"," - "\"floatValue\":0," - "\"doubleValue\":0," - "\"stringValue\":\"\"," - "\"bytesValue\":\"\"," - // TODO(xiaofeng): The default enum value should be FOO. I believe - // this is a bug in DefaultValueObjectWriter. - "\"enumValue\":null" - "}", - ToJson(m, options)); -} +// TODO(skarvaje): Uncomment after cl/96232915 is submitted. +// TEST_F(JsonUtilTest, TestDefaultValues) { + // TestMessage m; + // JsonOptions options; + // EXPECT_EQ("{}", ToJson(m, options)); + // options.always_print_primitive_fields = true; + // EXPECT_EQ( + // "{\"boolValue\":false," + // "\"int32Value\":0," + // "\"int64Value\":\"0\"," + // "\"uint32Value\":0," + // "\"uint64Value\":\"0\"," + // "\"floatValue\":0," + // "\"doubleValue\":0," + // "\"stringValue\":\"\"," + // "\"bytesValue\":\"\"," + // // TODO(xiaofeng): The default enum value should be FOO. I believe + // // this is a bug in DefaultValueObjectWriter. + // "\"enumValue\":null" + // "}", + // ToJson(m, options)); +// } TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 057b414aa6118..d709da57d87c0 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -45,6 +45,7 @@ #endif #include +#include #include #include #include diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index bd19f6958e791..701b94ae10154 100755 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -52,6 +52,7 @@ #include #include +#include #include #include #include @@ -131,7 +132,7 @@ TEST(MessageDifferencerTest, MapFieldEqualityTest) { unittest::TestMap msg1; unittest::TestMap msg2; - MapTestUtil::MapReflectionTester tester(unittest::TestMap::descriptor()); + MapReflectionTester tester(unittest::TestMap::descriptor()); tester.SetMapFieldsViaReflection(&msg1); tester.SetMapFieldsViaReflection(&msg2); tester.SwapMapsViaReflection(&msg1); diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index 053a4ed77bb24..908634ebbdb74 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include namespace google { @@ -64,6 +65,47 @@ bool SplitTypeUrl(const string& type_url, return true; } +// This code is originally defined in +// //google/protobuf/util/converter/utility.h. Copied here due to component +// dependency. +// TODO(xiaofeng): Remove this when converter code is in components. +string ToCamelCase(const StringPiece input) { + bool capitalize_next = false; + bool was_cap = true; + bool is_cap = false; + bool first_word = true; + string result; + result.reserve(input.size()); + + for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) { + is_cap = ascii_isupper(input[i]); + if (input[i] == '_') { + capitalize_next = true; + if (!result.empty()) first_word = false; + continue; + } else if (first_word) { + // Consider when the current character B is capitalized, + // first word ends when: + // 1) following a lowercase: "...aB..." + // 2) followed by a lowercase: "...ABc..." + if (!result.empty() && is_cap && + (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { + first_word = false; + } else { + result.push_back(ascii_tolower(input[i])); + continue; + } + } else if (capitalize_next) { + capitalize_next = false; + if (ascii_islower(input[i])) { + result.push_back(ascii_toupper(input[i])); + continue; + } + } + result.push_back(input[i]); + } + return result; +} class DescriptorPoolTypeResolver : public TypeResolver { public: @@ -155,6 +197,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { } field->set_number(descriptor->number()); field->set_name(descriptor->name()); + field->set_json_name(ToCamelCase(descriptor->name())); if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { field->set_type_url(GetTypeUrl(descriptor->message_type())); } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { diff --git a/src/google/protobuf/util/type_resolver_util.h b/src/google/protobuf/util/type_resolver_util.h index c0ef3c1af9379..00cf9c1348232 100644 --- a/src/google/protobuf/util/type_resolver_util.h +++ b/src/google/protobuf/util/type_resolver_util.h @@ -42,7 +42,7 @@ class TypeResolver; // Creates a TypeResolver that serves type information in the given descriptor // pool. Caller takes ownership of the returned TypeResolver. -LIBPROTOBUF_EXPORT TypeResolver* NewTypeResolverForDescriptorPool( +TypeResolver* NewTypeResolverForDescriptorPool( const string& url_prefix, const DescriptorPool* pool); } // namespace util diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index c5db963b91042..8fbd116b33e36 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -38,6 +38,7 @@ #include +#include #include #include #include diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 2ce4920c7efad..dade41afd547b 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -484,9 +485,9 @@ void WireFormatLite::WriteMessageMaybeToArray(int field_number, } } -static inline bool ReadBytesToString(io::CodedInputStream* input, - string* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -static inline bool ReadBytesToString(io::CodedInputStream* input, +GOOGLE_ATTRIBUTE_ALWAYS_INLINE static bool ReadBytesToString( + io::CodedInputStream* input, string* value); +inline static bool ReadBytesToString(io::CodedInputStream* input, string* value) { uint32 length; return input->ReadVarint32(&length) && diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index ac83abdc0d63b..19fbc2c591451 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -250,17 +250,17 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // For primitive fields, we just use a templatized routine parameterized by // the represented type and the FieldType. These are specialized with the // appropriate definition for each declared type. - template - static inline bool ReadPrimitive(input, CType* value) INL; + template INL + static bool ReadPrimitive(input, CType* value); // Reads repeated primitive values, with optimizations for repeats. // tag_size and tag should both be compile-time constants provided by the // protocol compiler. - template - static inline bool ReadRepeatedPrimitive(int tag_size, - uint32 tag, - input, - RepeatedField* value) INL; + template INL + static bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField* value); // Identical to ReadRepeatedPrimitive, except will not inline the // implementation. @@ -275,16 +275,14 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // // This is only implemented for the types with fixed wire size, e.g. // float, double, and the (s)fixed* types. - template - static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, - CType* value) INL; + template INL + static const uint8* ReadPrimitiveFromArray(const uint8* buffer, CType* value); // Reads a primitive packed field. // // This is only implemented for packable types. - template - static inline bool ReadPackedPrimitive(input, - RepeatedField* value) INL; + template INL + static bool ReadPackedPrimitive(input, RepeatedField* value); // Identical to ReadPackedPrimitive, except will not inline the // implementation. @@ -344,23 +342,23 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // 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 void WriteTag(field_number, WireType type, output) INL; + INL static void WriteTag(field_number, WireType type, output); // Write fields, without tags. - 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; + INL static void WriteInt32NoTag (int32 value, output); + INL static void WriteInt64NoTag (int64 value, output); + INL static void WriteUInt32NoTag (uint32 value, output); + INL static void WriteUInt64NoTag (uint64 value, output); + INL static void WriteSInt32NoTag (int32 value, output); + INL static void WriteSInt64NoTag (int64 value, output); + INL static void WriteFixed32NoTag (uint32 value, output); + INL static void WriteFixed64NoTag (uint64 value, output); + INL static void WriteSFixed32NoTag(int32 value, output); + INL static void WriteSFixed64NoTag(int64 value, output); + INL static void WriteFloatNoTag (float value, output); + INL static void WriteDoubleNoTag (double value, output); + INL static void WriteBoolNoTag (bool value, output); + INL static void WriteEnumNoTag (int value, output); // Write fields, including tags. static void WriteInt32 (field_number, int32 value, output); @@ -410,73 +408,59 @@ class LIBPROTOBUF_EXPORT WireFormatLite { #define output uint8* target // Like above, but use only *ToArray methods of CodedOutputStream. - static inline uint8* WriteTagToArray(field_number, WireType type, output) INL; + INL static uint8* WriteTagToArray(field_number, WireType type, output); // 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; + INL static uint8* WriteInt32NoTagToArray (int32 value, output); + INL static uint8* WriteInt64NoTagToArray (int64 value, output); + INL static uint8* WriteUInt32NoTagToArray (uint32 value, output); + INL static uint8* WriteUInt64NoTagToArray (uint64 value, output); + INL static uint8* WriteSInt32NoTagToArray (int32 value, output); + INL static uint8* WriteSInt64NoTagToArray (int64 value, output); + INL static uint8* WriteFixed32NoTagToArray (uint32 value, output); + INL static uint8* WriteFixed64NoTagToArray (uint64 value, output); + INL static uint8* WriteSFixed32NoTagToArray(int32 value, output); + INL static uint8* WriteSFixed64NoTagToArray(int64 value, output); + INL static uint8* WriteFloatNoTagToArray (float value, output); + INL static uint8* WriteDoubleNoTagToArray (double value, output); + INL static uint8* WriteBoolNoTagToArray (bool value, output); + INL static uint8* WriteEnumNoTagToArray (int value, output); // 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 MessageLite& value, output) INL; - static inline uint8* WriteMessageToArray( - field_number, const MessageLite& value, output) INL; + INL static uint8* WriteInt32ToArray(field_number, int32 value, output); + INL static uint8* WriteInt64ToArray(field_number, int64 value, output); + INL static uint8* WriteUInt32ToArray(field_number, uint32 value, output); + INL static uint8* WriteUInt64ToArray(field_number, uint64 value, output); + INL static uint8* WriteSInt32ToArray(field_number, int32 value, output); + INL static uint8* WriteSInt64ToArray(field_number, int64 value, output); + INL static uint8* WriteFixed32ToArray(field_number, uint32 value, output); + INL static uint8* WriteFixed64ToArray(field_number, uint64 value, output); + INL static uint8* WriteSFixed32ToArray(field_number, int32 value, output); + INL static uint8* WriteSFixed64ToArray(field_number, int64 value, output); + INL static uint8* WriteFloatToArray(field_number, float value, output); + INL static uint8* WriteDoubleToArray(field_number, double value, output); + INL static uint8* WriteBoolToArray(field_number, bool value, output); + INL static uint8* WriteEnumToArray(field_number, int value, output); + + INL static uint8* WriteStringToArray( + field_number, const string& value, output); + INL static uint8* WriteBytesToArray( + field_number, const string& value, output); + + INL static uint8* WriteGroupToArray( + field_number, const MessageLite& value, output); + INL static uint8* WriteMessageToArray( + field_number, const MessageLite& value, output); // 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; + INL static uint8* WriteGroupNoVirtualToArray( + field_number, const MessageType& value, output); template - static inline uint8* WriteMessageNoVirtualToArray( - field_number, const MessageType& value, output) INL; + INL static uint8* WriteMessageNoVirtualToArray( + field_number, const MessageType& value, output); #undef output #undef input @@ -527,18 +511,17 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // A helper method for the repeated primitive reader. This method has // optimizations for primitive types that have fixed size on the wire, and // can be read using potentially faster paths. - template - static inline bool ReadRepeatedFixedSizePrimitive( + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static bool ReadRepeatedFixedSizePrimitive( int tag_size, uint32 tag, google::protobuf::io::CodedInputStream* input, - RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + RepeatedField* value); // Like ReadRepeatedFixedSizePrimitive but for packed primitive fields. - template - static inline bool ReadPackedFixedSizePrimitive( - google::protobuf::io::CodedInputStream* input, - RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + template GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static bool ReadPackedFixedSizePrimitive(google::protobuf::io::CodedInputStream* input, + RepeatedField* value); static const CppType kFieldTypeToCppTypeMap[]; static const WireFormatLite::WireType kWireTypeForFieldType[]; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index d073ff923202a..991c3d041b80c 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -43,6 +43,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index aef22b2936d8f..15c37556eb166 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -40,8 +40,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -419,7 +421,7 @@ const int kUnknownTypeId = 1550055; TEST(WireFormatTest, SerializeMessageSet) { // Set up a TestMessageSet with two known messages and an unknown one. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; message_set.MutableExtension( unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); message_set.MutableExtension( @@ -462,7 +464,7 @@ TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) { // Set up a TestMessageSet with two known messages and an unknown one, as // above. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; message_set.MutableExtension( unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); message_set.MutableExtension( @@ -539,7 +541,7 @@ TEST(WireFormatTest, ParseMessageSet) { ASSERT_TRUE(raw.SerializeToString(&data)); // Parse as a TestMessageSet and check the contents. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; ASSERT_TRUE(message_set.ParseFromString(data)); EXPECT_EQ(123, message_set.GetExtension( @@ -553,7 +555,7 @@ TEST(WireFormatTest, ParseMessageSet) { EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited()); // Also parse using WireFormat. - unittest::TestMessageSet dynamic_message_set; + proto2_wireformat_unittest::TestMessageSet dynamic_message_set; io::CodedInputStream input(reinterpret_cast(data.data()), data.size()); ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set)); @@ -583,7 +585,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag); } { - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; ASSERT_TRUE(message_set.ParseFromString(data)); EXPECT_EQ(123, message_set.GetExtension( @@ -591,7 +593,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { } { // Test parse the message via Reflection. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; io::CodedInputStream input( reinterpret_cast(data.data()), data.size()); EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set)); @@ -603,7 +605,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { } TEST(WireFormatTest, ParseBrokenMessageSet) { - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; string input("goodbye"); // Invalid wire format data. EXPECT_FALSE(message_set.ParseFromString(input)); }