Jelajahi Sumber

Down-integrate from google3.

Feng Xiao 10 tahun lalu
induk
melakukan
eee38b0c01
100 mengubah file dengan 3669 tambahan dan 1429 penghapusan
  1. 103 103
      cmake/install.cmake
  2. 1 1
      cmake/protobuf-config-version.cmake.in
  3. 27 27
      cmake/protobuf-config.cmake.in
  4. 11 11
      java/src/main/java/com/google/protobuf/ByteString.java
  5. 98 5
      java/src/main/java/com/google/protobuf/CodedOutputStream.java
  6. 3 3
      java/src/main/java/com/google/protobuf/Descriptors.java
  7. 97 18
      java/src/main/java/com/google/protobuf/GeneratedMessage.java
  8. 33 76
      java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
  9. 12 0
      java/src/main/java/com/google/protobuf/Internal.java
  10. 1 1
      java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
  11. 5 0
      java/src/main/java/com/google/protobuf/LazyStringArrayList.java
  12. 12 1
      java/src/main/java/com/google/protobuf/LazyStringList.java
  13. 3 0
      java/src/main/java/com/google/protobuf/Message.java
  14. 1 1
      java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
  15. 177 80
      java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
  16. 5 0
      java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java
  17. 132 0
      java/src/main/java/com/google/protobuf/Utf8.java
  18. 1 1
      java/src/main/java/com/google/protobuf/WireFormat.java
  19. 1 0
      java/src/test/java/com/google/protobuf/BoundedByteStringTest.java
  20. 3 4
      java/src/test/java/com/google/protobuf/CheckUtf8Test.java
  21. 109 1
      java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  22. 10 0
      java/src/test/java/com/google/protobuf/FieldPresenceTest.java
  23. 1 2
      java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
  24. 5 16
      java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java
  25. 3 0
      java/src/test/java/com/google/protobuf/LiteTest.java
  26. 59 2
      java/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  27. 23 3
      java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
  28. 23 3
      java/src/test/java/com/google/protobuf/MapForProto2Test.java
  29. 39 3
      java/src/test/java/com/google/protobuf/MapTest.java
  30. 6 10
      java/src/test/java/com/google/protobuf/ParserTest.java
  31. 5 3
      java/src/test/java/com/google/protobuf/RopeByteStringTest.java
  32. 1 0
      java/src/test/java/com/google/protobuf/TestUtil.java
  33. 1 1
      java/src/test/java/com/google/protobuf/TextFormatTest.java
  34. 1 1
      java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
  35. 1 1
      java/src/test/java/com/google/protobuf/WireFormatTest.java
  36. 7 4
      python/google/protobuf/internal/containers.py
  37. 2 1
      python/google/protobuf/internal/generator_test.py
  38. 115 0
      python/google/protobuf/internal/message_test.py
  39. 73 0
      python/google/protobuf/internal/packed_field_test.proto
  40. 107 44
      python/google/protobuf/internal/python_message.py
  41. 24 24
      python/google/protobuf/internal/reflection_test.py
  42. 2 1
      python/google/protobuf/internal/test_util.py
  43. 31 0
      python/google/protobuf/internal/text_format_test.py
  44. 46 26
      python/google/protobuf/internal/unknown_fields_test.py
  45. 22 14
      python/google/protobuf/pyext/cpp_message.py
  46. 1 1
      python/google/protobuf/pyext/descriptor.cc
  47. 7 0
      python/google/protobuf/pyext/descriptor_pool.cc
  48. 10 0
      python/google/protobuf/pyext/descriptor_pool.h
  49. 4 2
      python/google/protobuf/pyext/extension_dict.cc
  50. 458 266
      python/google/protobuf/pyext/message.cc
  51. 0 4
      python/google/protobuf/pyext/message.h
  52. 1 0
      python/google/protobuf/pyext/message_map_container.cc
  53. 31 180
      python/google/protobuf/pyext/repeated_composite_container.cc
  54. 6 5
      python/google/protobuf/pyext/repeated_scalar_container.cc
  55. 1 0
      python/google/protobuf/pyext/scalar_map_container.cc
  56. 11 5
      python/google/protobuf/pyext/scoped_pyobject_ptr.h
  57. 9 87
      python/google/protobuf/reflection.py
  58. 1 1
      python/google/protobuf/text_format.py
  59. 2 2
      src/google/protobuf/any.cc
  60. 1 1
      src/google/protobuf/any.h
  61. 23 17
      src/google/protobuf/arena.cc
  62. 115 63
      src/google/protobuf/arena.h
  63. 1 0
      src/google/protobuf/arena_test_util.cc
  64. 52 3
      src/google/protobuf/arena_unittest.cc
  65. 5 6
      src/google/protobuf/arenastring.h
  66. 1 0
      src/google/protobuf/arenastring_unittest.cc
  67. 1 0
      src/google/protobuf/compiler/code_generator.cc
  68. 5 0
      src/google/protobuf/compiler/command_line_interface.cc
  69. 33 0
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  70. 1 2
      src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc
  71. 2 6
      src/google/protobuf/compiler/cpp/cpp_enum.cc
  72. 3 2
      src/google/protobuf/compiler/cpp/cpp_enum.h
  73. 0 1
      src/google/protobuf/compiler/cpp/cpp_enum_field.cc
  74. 1 0
      src/google/protobuf/compiler/cpp/cpp_field.cc
  75. 222 32
      src/google/protobuf/compiler/cpp/cpp_file.cc
  76. 28 4
      src/google/protobuf/compiler/cpp/cpp_file.h
  77. 10 3
      src/google/protobuf/compiler/cpp/cpp_generator.cc
  78. 23 1
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  79. 7 0
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  80. 6 3
      src/google/protobuf/compiler/cpp/cpp_map_field.cc
  81. 1 0
      src/google/protobuf/compiler/cpp/cpp_map_field.h
  82. 112 75
      src/google/protobuf/compiler/cpp/cpp_message.cc
  83. 5 4
      src/google/protobuf/compiler/cpp/cpp_message.h
  84. 482 134
      src/google/protobuf/compiler/cpp/cpp_message_field.cc
  85. 19 1
      src/google/protobuf/compiler/cpp/cpp_message_field.h
  86. 24 7
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  87. 1 0
      src/google/protobuf/compiler/cpp/cpp_string_field.h
  88. 2 0
      src/google/protobuf/compiler/cpp/cpp_unittest.cc
  89. 1 0
      src/google/protobuf/compiler/importer_unittest.cc
  90. 2 2
      src/google/protobuf/compiler/java/java_enum.cc
  91. 1 0
      src/google/protobuf/compiler/java/java_enum_field.cc
  92. 1 0
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  93. 226 0
      src/google/protobuf/compiler/java/java_enum_lite.cc
  94. 99 0
      src/google/protobuf/compiler/java/java_enum_lite.h
  95. 1 0
      src/google/protobuf/compiler/java/java_field.cc
  96. 1 0
      src/google/protobuf/compiler/java/java_field.h
  97. 4 0
      src/google/protobuf/compiler/java/java_helpers.h
  98. 24 0
      src/google/protobuf/compiler/java/java_map_field.cc
  99. 24 0
      src/google/protobuf/compiler/java/java_map_field_lite.cc
  100. 115 17
      src/google/protobuf/compiler/java/java_message.cc

+ 103 - 103
cmake/install.cmake

@@ -1,103 +1,103 @@
-include(GNUInstallDirs)
-
-foreach(_library
-  libprotobuf-lite
-  libprotobuf
-  libprotoc)
-  set_property(TARGET ${_library}
-    PROPERTY INTERFACE_INCLUDE_DIRECTORIES
-    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
-  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_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
+  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)

+ 1 - 1
cmake/protobuf-config-version.cmake.in

@@ -1 +1 @@
-set(PACKAGE_VERSION @protobuf_VERSION@)
+set(PACKAGE_VERSION @protobuf_VERSION@)

+ 27 - 27
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)

+ 11 - 11
java/src/main/java/com/google/protobuf/ByteString.java

@@ -294,10 +294,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    * <b>Performance notes:</b> The returned {@code ByteString} is an
    * <b>Performance notes:</b> The returned {@code ByteString} is an
    * immutable tree of byte arrays ("chunks") of the stream data.  The
    * immutable tree of byte arrays ("chunks") of the stream data.  The
    * first chunk is small, with subsequent chunks each being double
    * 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.
+   * 
+   * <p>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
    * @param streamToDrain The source stream, which is read completely
    *     but not closed.
    *     but not closed.
@@ -320,12 +320,10 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    *
    *
    * <b>Performance notes:</b> The returned {@code ByteString} is an
    * <b>Performance notes:</b> The returned {@code ByteString} is an
    * immutable tree of byte arrays ("chunks") of the stream data.  The
    * 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.
+   *
+   * <p>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
    * @param streamToDrain The source stream, which is read completely
    *     but not closed.
    *     but not closed.
@@ -386,6 +384,7 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
       if (bytesRead == 0) {
       if (bytesRead == 0) {
         return null;
         return null;
       } else {
       } else {
+        // Always make a copy since InputStream could steal a reference to buf.
         return ByteString.copyFrom(buf, 0, bytesRead);
         return ByteString.copyFrom(buf, 0, bytesRead);
       }
       }
   }
   }
@@ -736,7 +735,8 @@ public abstract class ByteString implements Iterable<Byte>, Serializable {
    * returns the number of bytes remaining in the stream. The methods
    * returns the number of bytes remaining in the stream. The methods
    * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)}
    * {@link InputStream#read(byte[])}, {@link InputStream#read(byte[],int,int)}
    * and {@link InputStream#skip(long)} will read/skip as many bytes as are
    * and {@link InputStream#skip(long)} will read/skip as many bytes as are
-   * available.
+   * available.  The method {@link InputStream#markSupported()} returns
+   * {@code true}.
    * <p>
    * <p>
    * The methods in the returned {@link InputStream} might <b>not</b> be
    * The methods in the returned {@link InputStream} might <b>not</b> be
    * thread safe.
    * thread safe.

+ 98 - 5
java/src/main/java/com/google/protobuf/CodedOutputStream.java

@@ -30,9 +30,13 @@
 
 
 package com.google.protobuf;
 package com.google.protobuf;
 
 
+import com.google.protobuf.Utf8.UnpairedSurrogateException;
+
 import java.io.IOException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 
 /**
 /**
  * Encodes and writes protocol message fields.
  * Encodes and writes protocol message fields.
@@ -49,6 +53,10 @@ import java.nio.ByteBuffer;
  * @author kneton@google.com Kenton Varda
  * @author kneton@google.com Kenton Varda
  */
  */
 public final class CodedOutputStream {
 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 byte[] buffer;
   private final int limit;
   private final int limit;
   private int position;
   private int position;
@@ -415,15 +423,87 @@ public final class CodedOutputStream {
   }
   }
 
 
   /** Write a {@code string} field to the stream. */
   /** 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 {
   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
     // 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
     // UTF-8 directly into our buffer, so we have to let it create its own byte
     // array and then copy.
     // array and then copy.
+    // TODO(dweis): Consider using nio Charset methods instead.
     final byte[] bytes = value.getBytes(Internal.UTF_8);
     final byte[] bytes = value.getBytes(Internal.UTF_8);
     writeRawVarint32(bytes.length);
     writeRawVarint32(bytes.length);
     writeRawBytes(bytes);
     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. */
   /** Write a {@code group} field to the stream. */
   public void writeGroupNoTag(final MessageLite value) throws IOException {
   public void writeGroupNoTag(final MessageLite value) throws IOException {
     value.writeTo(this);
     value.writeTo(this);
@@ -826,9 +906,16 @@ public final class CodedOutputStream {
    * {@code string} field.
    * {@code string} field.
    */
    */
   public static int computeStringSizeNoTag(final String value) {
   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 final class CodedOutputStream {
   public static class OutOfSpaceException extends IOException {
   public static class OutOfSpaceException extends IOException {
     private static final long serialVersionUID = -6947486886997889499L;
     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() {
     OutOfSpaceException() {
-      super("CodedOutputStream was writing to a flat byte array and ran " +
-            "out of space.");
+      super(MESSAGE);
+    }
+
+    OutOfSpaceException(Throwable cause) {
+      super(MESSAGE, cause);
     }
     }
   }
   }
 
 

+ 3 - 3
java/src/main/java/com/google/protobuf/Descriptors.java

@@ -1118,9 +1118,9 @@ public final class Descriptors {
     static {
     static {
       // Refuse to init if someone added a new declared type.
       // Refuse to init if someone added a new declared type.
       if (Type.values().length != FieldDescriptorProto.Type.values().length) {
       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.");
       }
       }
     }
     }
 
 

+ 97 - 18
java/src/main/java/com/google/protobuf/GeneratedMessage.java

@@ -121,22 +121,44 @@ public abstract class GeneratedMessage extends AbstractMessage
     final TreeMap<FieldDescriptor, Object> result =
     final TreeMap<FieldDescriptor, Object> result =
       new TreeMap<FieldDescriptor, Object>();
       new TreeMap<FieldDescriptor, Object>();
     final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
     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<FieldDescriptor> 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 {
       } 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;
     return result;
   }
   }
@@ -398,17 +420,40 @@ public abstract class GeneratedMessage extends AbstractMessage
       final TreeMap<FieldDescriptor, Object> result =
       final TreeMap<FieldDescriptor, Object> result =
         new TreeMap<FieldDescriptor, Object>();
         new TreeMap<FieldDescriptor, Object>();
       final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
       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<FieldDescriptor> 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 {
         } 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;
       return result;
     }
     }
@@ -2696,4 +2741,38 @@ public abstract class GeneratedMessage extends AbstractMessage
 
 
     return (Extension<MessageType, T>) extension;
     return (Extension<MessageType, T>) 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);
+    }
+  }
 }
 }

+ 33 - 76
java/src/main/java/com/google/protobuf/GeneratedMessageLite.java

@@ -48,7 +48,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 
 /**
 /**
  * Lite version of {@link GeneratedMessage}.
  * Lite version of {@link GeneratedMessage}.
@@ -60,24 +59,6 @@ public abstract class GeneratedMessageLite<
     BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
     BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
         extends AbstractMessageLite
         extends AbstractMessageLite
         implements Serializable {
         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<Class<?>, PrototypeHolder<?, ?>> PROTOTYPE_MAP =
-      new ConcurrentHashMap<Class<?>, PrototypeHolder<?, ?>>();
-  
-  // For use by generated code only.
-  protected static <
-      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-      BuilderType extends GeneratedMessageLite.Builder<
-          MessageType, BuilderType>> void onLoad(Class<MessageType> clazz,
-              PrototypeHolder<MessageType, BuilderType> protoTypeHolder) {
-    PROTOTYPE_MAP.put(clazz, protoTypeHolder);
-  }
 
 
   private static final long serialVersionUID = 1L;
   private static final long serialVersionUID = 1L;
 
 
@@ -90,20 +71,17 @@ public abstract class GeneratedMessageLite<
   
   
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final Parser<MessageType> getParserForType() {
   public final Parser<MessageType> getParserForType() {
-    return (Parser<MessageType>) PROTOTYPE_MAP
-        .get(getClass()).getParserForType();
+    return (Parser<MessageType>) dynamicMethod(MethodToInvoke.GET_PARSER);
   }
   }
 
 
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final MessageType getDefaultInstanceForType() {
   public final MessageType getDefaultInstanceForType() {
-    return (MessageType) PROTOTYPE_MAP
-        .get(getClass()).getDefaultInstanceForType();
+    return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE);
   }
   }
 
 
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final BuilderType newBuilderForType() {
   public final BuilderType newBuilderForType() {
-    return (BuilderType) PROTOTYPE_MAP
-        .get(getClass()).newBuilderForType();
+    return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
   }
   }
 
 
   /**
   /**
@@ -141,7 +119,9 @@ public abstract class GeneratedMessageLite<
     MERGE_FROM,
     MERGE_FROM,
     MAKE_IMMUTABLE,
     MAKE_IMMUTABLE,
     NEW_INSTANCE,
     NEW_INSTANCE,
-    NEW_BUILDER;
+    NEW_BUILDER,
+    GET_DEFAULT_INSTANCE,
+    GET_PARSER;
   }
   }
 
 
   /**
   /**
@@ -168,9 +148,21 @@ public abstract class GeneratedMessageLite<
    * <p>
    * <p>
    * For use by generated code only.
    * 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
    * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
@@ -1059,18 +1051,22 @@ public abstract class GeneratedMessageLite<
     @SuppressWarnings("unchecked")
     @SuppressWarnings("unchecked")
     protected Object readResolve() throws ObjectStreamException {
     protected Object readResolve() throws ObjectStreamException {
       try {
       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) {
       } 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) {
       } 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) {
       } 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) {
       } catch (IllegalAccessException e) {
-        throw new RuntimeException("Unable to call parseFrom method", e);
+        throw new RuntimeException("Unable to call parsePartialFrom", e);
       } catch (InvalidProtocolBufferException e) {
       } catch (InvalidProtocolBufferException e) {
         throw new RuntimeException("Unable to understand proto buffer", e);
         throw new RuntimeException("Unable to understand proto buffer", e);
       }
       }
@@ -1103,45 +1099,6 @@ public abstract class GeneratedMessageLite<
     
     
     return (GeneratedExtension<MessageType, T>) extension;
     return (GeneratedExtension<MessageType, T>) 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.
-   * <ul>
-   * <li>{@link #getDefaultInstanceForType()}
-   * <li>{@link #getParserForType()}
-   * <li>{@link #newBuilderForType()}
-   * </ul>
-   * This allows us to trade three generated methods for a static Map.
-   */
-  protected static class PrototypeHolder<
-      MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-      BuilderType extends GeneratedMessageLite.Builder<
-          MessageType, BuilderType>> {
-    
-    private final MessageType defaultInstance;
-    private final Parser<MessageType> parser;
-    
-    public PrototypeHolder(
-        MessageType defaultInstance, Parser<MessageType> parser) {
-      this.defaultInstance = defaultInstance;
-      this.parser = parser;
-    }
-    
-    public MessageType getDefaultInstanceForType() {
-      return defaultInstance;
-    }
-
-    public Parser<MessageType> 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.
    * A static helper method for checking if a message is initialized, optionally memoizing.

+ 12 - 0
java/src/main/java/com/google/protobuf/Internal.java

@@ -31,6 +31,7 @@
 package com.google.protobuf;
 package com.google.protobuf;
 
 
 import java.io.IOException;
 import java.io.IOException;
+import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.Charset;
 import java.util.AbstractList;
 import java.util.AbstractList;
@@ -358,6 +359,17 @@ public class Internal {
     }
     }
   }
   }
 
 
+  @SuppressWarnings("unchecked")
+  public static <T extends MessageLite> T getDefaultInstance(Class<T> 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.
    * An empty byte array constant used in generated code.
    */
    */

+ 1 - 1
java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java

@@ -69,7 +69,7 @@ public class InvalidProtocolBufferException extends IOException {
   static InvalidProtocolBufferException truncatedMessage() {
   static InvalidProtocolBufferException truncatedMessage() {
     return new InvalidProtocolBufferException(
     return new InvalidProtocolBufferException(
       "While parsing a protocol message, the input ended unexpectedly " +
       "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 " +
       "input has been truncated or that an embedded message " +
       "misreported its own length.");
       "misreported its own length.");
   }
   }

+ 5 - 0
java/src/main/java/com/google/protobuf/LazyStringArrayList.java

@@ -215,6 +215,11 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
     modCount++;
     modCount++;
   }
   }
 
 
+  @Override
+  public Object getRaw(int index) {
+    return list.get(index);
+  }
+  
   // @Override
   // @Override
   public ByteString getByteString(int index) {
   public ByteString getByteString(int index) {
     Object o = list.get(index);
     Object o = list.get(index);

+ 12 - 1
java/src/main/java/com/google/protobuf/LazyStringList.java

@@ -56,7 +56,18 @@ public interface LazyStringList extends ProtocolStringList {
    *         ({@code index < 0 || index >= size()})
    *         ({@code index < 0 || index >= size()})
    */
    */
   ByteString getByteString(int index);
   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[].
    * Returns the element at the specified position in this list as byte[].
    *
    *

+ 3 - 0
java/src/main/java/com/google/protobuf/Message.java

@@ -121,6 +121,9 @@ public interface Message extends MessageLite, MessageOrBuilder {
      *   using the same merging rules.<br>
      *   using the same merging rules.<br>
      * * For repeated fields, the elements in {@code other} are concatenated
      * * For repeated fields, the elements in {@code other} are concatenated
      *   with the elements in this message.
      *   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++.
      * This is equivalent to the {@code Message::MergeFrom} method in C++.
      */
      */

+ 1 - 1
java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java

@@ -73,7 +73,7 @@ public class RepeatedFieldBuilder
   private GeneratedMessage.BuilderParent parent;
   private GeneratedMessage.BuilderParent parent;
 
 
   // List of messages. Never null. It may be immutable, in which case
   // 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<MType> messages;
   private List<MType> messages;
 
 
   // Whether messages is an mutable array that can be modified.
   // Whether messages is an mutable array that can be modified.

+ 177 - 80
java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java

@@ -31,6 +31,7 @@
 package com.google.protobuf;
 package com.google.protobuf;
 
 
 import java.io.IOException;
 import java.io.IOException;
+import java.util.Arrays;
 
 
 /**
 /**
  * {@code UnknownFieldSetLite} is used to keep track of fields which were seen
  * {@code UnknownFieldSetLite} is used to keep track of fields which were seen
@@ -45,8 +46,11 @@ import java.io.IOException;
  */
  */
 public final class UnknownFieldSetLite {
 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 =
   private static final UnknownFieldSetLite DEFAULT_INSTANCE =
-      new UnknownFieldSetLite(ByteString.EMPTY);
+      new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY);
 
 
   /**
   /**
    * Get an empty {@code UnknownFieldSetLite}.
    * Get an empty {@code UnknownFieldSetLite}.
@@ -71,19 +75,41 @@ public final class UnknownFieldSetLite {
    * {@code second}.
    * {@code second}.
    */
    */
   static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite 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 @@ public final class UnknownFieldSetLite {
    * <p>For use by generated code only.
    * <p>For use by generated code only.
    */
    */
   public void writeTo(CodedOutputStream output) throws IOException {
   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.
    * Get the number of bytes required to encode this set.
    *
    *
    * <p>For use by generated code only.
    * <p>For use by generated code only.
    */
    */
   public int getSerializedSize() {
   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
   @Override
@@ -111,16 +193,34 @@ public final class UnknownFieldSetLite {
       return true;
       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
   @Override
   public int hashCode() {
   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 final class UnknownFieldSetLite {
    * <p>For use by generated code only.
    * <p>For use by generated code only.
    */
    */
   public static final class Builder {
   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;
     private boolean built;
 
 
     /**
     /**
-     * Constructs a {@code Builder}. Lazily initialized by
-     * {@link #ensureInitializedButNotBuilt()}.
+     * Constructs a {@code Builder}.
      */
      */
     private Builder() {}
     private Builder() {}
 
 
     /**
     /**
      * Ensures internal state is initialized for use.
      * Ensures internal state is initialized for use.
      */
      */
-    private void ensureInitializedButNotBuilt() {
+    private void ensureNotBuilt() {
       if (built) {
       if (built) {
         throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
         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 @@ public final class UnknownFieldSetLite {
      */
      */
     public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
     public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
                                   throws IOException {
                                   throws IOException {
-      ensureInitializedButNotBuilt();
+      ensureNotBuilt();
 
 
       final int fieldNumber = WireFormat.getTagFieldNumber(tag);
       final int fieldNumber = WireFormat.getTagFieldNumber(tag);
       switch (WireFormat.getTagWireType(tag)) {
       switch (WireFormat.getTagWireType(tag)) {
         case WireFormat.WIRETYPE_VARINT:
         case WireFormat.WIRETYPE_VARINT:
-          output.writeUInt64(fieldNumber, input.readInt64());
+          storeField(tag, input.readInt64());
           return true;
           return true;
         case WireFormat.WIRETYPE_FIXED32:
         case WireFormat.WIRETYPE_FIXED32:
-          output.writeFixed32(fieldNumber, input.readFixed32());
+          storeField(tag, input.readFixed32());
           return true;
           return true;
         case WireFormat.WIRETYPE_FIXED64:
         case WireFormat.WIRETYPE_FIXED64:
-          output.writeFixed64(fieldNumber, input.readFixed64());
+          storeField(tag, input.readFixed64());
           return true;
           return true;
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
         case WireFormat.WIRETYPE_LENGTH_DELIMITED:
-          output.writeBytes(fieldNumber, input.readBytes());
+          storeField(tag, input.readBytes());
           return true;
           return true;
         case WireFormat.WIRETYPE_START_GROUP:
         case WireFormat.WIRETYPE_START_GROUP:
           final Builder subBuilder = newBuilder();
           final Builder subBuilder = newBuilder();
           subBuilder.mergeFrom(input);
           subBuilder.mergeFrom(input);
           input.checkLastTagWas(
           input.checkLastTagWas(
               WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
               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;
           return true;
         case WireFormat.WIRETYPE_END_GROUP:
         case WireFormat.WIRETYPE_END_GROUP:
           return false;
           return false;
@@ -210,12 +328,10 @@ public final class UnknownFieldSetLite {
       if (fieldNumber == 0) {
       if (fieldNumber == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
         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;
       return this;
     }
     }
 
 
@@ -229,11 +345,24 @@ public final class UnknownFieldSetLite {
       if (fieldNumber == 0) {
       if (fieldNumber == 0) {
         throw new IllegalArgumentException("Zero is not a valid field number.");
         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;
       return this;
     }
     }
@@ -254,44 +383,12 @@ public final class UnknownFieldSetLite {
       }
       }
 
 
       built = true;
       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);
     }
     }
   }
   }
 }
 }

+ 5 - 0
java/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java

@@ -57,6 +57,11 @@ public class UnmodifiableLazyStringList extends AbstractList<String>
   public String get(int index) {
   public String get(int index) {
     return list.get(index);
     return list.get(index);
   }
   }
+  
+  @Override
+  public Object getRaw(int index) {
+    return list.getRaw(index);
+  }
 
 
   @Override
   @Override
   public int size() {
   public int size() {

+ 132 - 0
java/src/main/java/com/google/protobuf/Utf8.java

@@ -66,6 +66,12 @@ package com.google.protobuf;
  */
  */
 final class Utf8 {
 final class Utf8 {
   private 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
    * State value indicating that the byte sequence is well-formed and
@@ -346,4 +352,130 @@ final class Utf8 {
       default: throw new AssertionError();
       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.
 }
 }

+ 1 - 1
java/src/main/java/com/google/protobuf/WireFormat.java

@@ -58,7 +58,7 @@ public final class WireFormat {
   static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
   static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
 
 
   /** Given a tag value, determines the wire type (the lower 3 bits). */
   /** 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;
     return tag & TAG_TYPE_MASK;
   }
   }
 
 

+ 1 - 0
java/src/test/java/com/google/protobuf/BoundedByteStringTest.java

@@ -85,6 +85,7 @@ public class BoundedByteStringTest extends LiteralByteStringTest {
         testString.substring(2, testString.length() - 6), roundTripString);
         testString.substring(2, testString.length() - 6), roundTripString);
   }
   }
 
 
+  @Override
   public void testJavaSerialization() throws Exception {
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
     ObjectOutputStream oos = new ObjectOutputStream(out);

+ 3 - 4
java/src/test/java/com/google/protobuf/CheckUtf8Test.java

@@ -58,8 +58,7 @@ public class CheckUtf8Test extends TestCase {
   public void testParseRequiredStringWithGoodUtf8() throws Exception {
   public void testParseRequiredStringWithGoodUtf8() throws Exception {
     ByteString serialized =
     ByteString serialized =
         BytesWrapper.newBuilder().setReq(UTF8_BYTE_STRING).build().toByteString();
         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 {
   public void testBuildRequiredStringWithBadUtf8() throws Exception {
@@ -93,7 +92,7 @@ public class CheckUtf8Test extends TestCase {
     ByteString serialized =
     ByteString serialized =
         BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
         BytesWrapper.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
     try {
     try {
-      StringWrapper.PARSER.parseFrom(serialized);
+      StringWrapper.parser().parseFrom(serialized);
       fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
       fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
     } catch (InvalidProtocolBufferException exception) {
     } catch (InvalidProtocolBufferException exception) {
       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
@@ -131,7 +130,7 @@ public class CheckUtf8Test extends TestCase {
     ByteString serialized =
     ByteString serialized =
         BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
         BytesWrapperSize.newBuilder().setReq(NON_UTF8_BYTE_STRING).build().toByteString();
     try {
     try {
-      StringWrapperSize.PARSER.parseFrom(serialized);
+      StringWrapperSize.parser().parseFrom(serialized);
       fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
       fail("Expected InvalidProtocolBufferException for non UTF-8 byte string.");
     } catch (InvalidProtocolBufferException exception) {
     } catch (InvalidProtocolBufferException exception) {
       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());

+ 109 - 1
java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java

@@ -40,6 +40,7 @@ import junit.framework.TestCase;
 import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
@@ -325,10 +326,41 @@ public class CodedOutputStreamTest extends TestCase {
     for (int i = 0; i < 1024; ++i) {
     for (int i = 0; i < 1024; ++i) {
       codedStream.writeRawBytes(value, 0, value.length);
       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
     // Make sure we have written more bytes than the buffer could hold. This is
     // to make the test complete.
     // to make the test complete.
     assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE);
     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 {
   public void testWriteToByteBuffer() throws Exception {
@@ -398,4 +430,80 @@ public class CodedOutputStreamTest extends TestCase {
     assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
     assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination);
     assertEquals(3, codedStream.getTotalBytesWritten());
     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);
+  }
 }
 }

+ 10 - 0
java/src/test/java/com/google/protobuf/FieldPresenceTest.java

@@ -142,6 +142,16 @@ public class FieldPresenceTest extends TestCase {
         "OneofNestedMessage"));
         "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() {
   public void testFieldPresence() {
     // Optional non-message fields set to their default value are treated the
     // Optional non-message fields set to their default value are treated the
     // same way as not set.
     // same way as not set.

+ 1 - 2
java/src/test/java/com/google/protobuf/GeneratedMessageTest.java

@@ -187,8 +187,7 @@ public class GeneratedMessageTest extends TestCase {
   }
   }
 
 
   public void testParsedMessagesAreImmutable() 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.getRepeatedInt32List());
     assertIsUnmodifiable(value.getRepeatedInt64List());
     assertIsUnmodifiable(value.getRepeatedInt64List());
     assertIsUnmodifiable(value.getRepeatedUint32List());
     assertIsUnmodifiable(value.getRepeatedUint32List());

+ 5 - 16
java/src/test/java/com/google/protobuf/LazyStringEndToEndTest.java

@@ -89,7 +89,7 @@ public class LazyStringEndToEndTest extends TestCase {
         TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
         TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
         ByteString.copyFrom(sink));
         ByteString.copyFrom(sink));
   }
   }
-
+  
   public void testCaching() {
   public void testCaching() {
     String a = "a";
     String a = "a";
     String b = "b";
     String b = "b";
@@ -106,24 +106,13 @@ public class LazyStringEndToEndTest extends TestCase {
     assertSame(c, proto.getRepeatedString(1));
     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();
     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.
     // 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 {
   public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {

+ 3 - 0
java/src/test/java/com/google/protobuf/LiteTest.java

@@ -42,6 +42,7 @@ import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
 import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup;
+import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder;
 import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
 import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
 
 
 import junit.framework.TestCase;
 import junit.framework.TestCase;
@@ -1400,6 +1401,8 @@ public class LiteTest extends TestCase {
     assertEquals("hi", messageAfterBuild.getOneofString());
     assertEquals("hi", messageAfterBuild.getOneofString());
     assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
     assertEquals(OneofFieldCase.ONEOF_UINT32, builder.getOneofFieldCase());
     assertEquals(1, builder.getOneofUint32());
     assertEquals(1, builder.getOneofUint32());
+    TestAllTypesLiteOrBuilder messageOrBuilder = builder;
+    assertEquals(OneofFieldCase.ONEOF_UINT32, messageOrBuilder.getOneofFieldCase());
     
     
     TestAllExtensionsLite.Builder extendableMessageBuilder =
     TestAllExtensionsLite.Builder extendableMessageBuilder =
         TestAllExtensionsLite.newBuilder();
         TestAllExtensionsLite.newBuilder();

+ 59 - 2
java/src/test/java/com/google/protobuf/LiteralByteStringTest.java

@@ -34,6 +34,7 @@ import junit.framework.TestCase;
 
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectInputStream;
@@ -209,6 +210,62 @@ public class LiteralByteStringTest extends TestCase {
         Arrays.equals(referenceBytes, myBuffer.array()));
         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.
+   * <p>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() {
   public void testAsReadOnlyByteBuffer() {
     ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
     ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
     byte[] roundTripBytes = new byte[referenceBytes.length];
     byte[] roundTripBytes = new byte[referenceBytes.length];
@@ -305,13 +362,13 @@ public class LiteralByteStringTest extends TestCase {
     assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
     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",
     assertSame(classUnderTest + " must be the same string references",
         ByteString.EMPTY.toString(Internal.UTF_8),
         ByteString.EMPTY.toString(Internal.UTF_8),
         new LiteralByteString(new byte[]{}).toString(Internal.UTF_8));
         new LiteralByteString(new byte[]{}).toString(Internal.UTF_8));
   }
   }
 
 
-  public void testToString_raisesException() throws UnsupportedEncodingException{
+  public void testToString_raisesException() {
     try {
     try {
       ByteString.EMPTY.toString("invalid");
       ByteString.EMPTY.toString("invalid");
       fail("Should have thrown an exception.");
       fail("Should have thrown an exception.");

+ 23 - 3
java/src/test/java/com/google/protobuf/MapForProto2LiteTest.java

@@ -74,6 +74,16 @@ public class MapForProto2LiteTest extends TestCase {
     builder.getMutableStringToInt32Field().put("3", 33);
     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) {
   private void assertMapValuesSet(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
@@ -330,26 +340,36 @@ public class MapForProto2LiteTest extends TestCase {
     assertMapValuesCleared(message);
     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 {
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     setMapValues(builder);
     TestMap message = builder.build();
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
     assertMapValuesSet(message);
     
     
     builder = message.toBuilder();
     builder = message.toBuilder();
     updateMapValues(builder);
     updateMapValues(builder);
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
     assertMapValuesUpdated(message);
     
     
     builder = message.toBuilder();
     builder = message.toBuilder();
     builder.clear();
     builder.clear();
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
     assertMapValuesCleared(message);
   }
   }
   
   

+ 23 - 3
java/src/test/java/com/google/protobuf/MapForProto2Test.java

@@ -78,6 +78,16 @@ public class MapForProto2Test extends TestCase {
     builder.getMutableStringToInt32Field().put("3", 33);
     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) {
   private void assertMapValuesSet(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
@@ -310,26 +320,36 @@ public class MapForProto2Test extends TestCase {
     assertMapValuesCleared(message);
     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 {
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     setMapValues(builder);
     TestMap message = builder.build();
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
     assertMapValuesSet(message);
     
     
     builder = message.toBuilder();
     builder = message.toBuilder();
     updateMapValues(builder);
     updateMapValues(builder);
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
     assertMapValuesUpdated(message);
     
     
     builder = message.toBuilder();
     builder = message.toBuilder();
     builder.clear();
     builder.clear();
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
     assertMapValuesCleared(message);
   }
   }
   
   

+ 39 - 3
java/src/test/java/com/google/protobuf/MapTest.java

@@ -79,6 +79,16 @@ public class MapTest extends TestCase {
     builder.getMutableStringToInt32Field().put("3", 33);
     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) {
   private void assertMapValuesSet(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
@@ -311,26 +321,52 @@ public class MapTest extends TestCase {
     assertMapValuesCleared(message);
     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 {
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     setMapValues(builder);
     TestMap message = builder.build();
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
     assertMapValuesSet(message);
 
 
     builder = message.toBuilder();
     builder = message.toBuilder();
     updateMapValues(builder);
     updateMapValues(builder);
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
     assertMapValuesUpdated(message);
 
 
     builder = message.toBuilder();
     builder = message.toBuilder();
     builder.clear();
     builder.clear();
     message = builder.build();
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     assertEquals(message.getSerializedSize(), message.toByteString().size());
-    message = TestMap.PARSER.parseFrom(message.toByteString());
+    message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
     assertMapValuesCleared(message);
   }
   }
 
 

+ 6 - 10
java/src/test/java/com/google/protobuf/ParserTest.java

@@ -58,8 +58,7 @@ import java.io.InputStream;
 public class ParserTest extends TestCase {
 public class ParserTest extends TestCase {
   public void testGeneratedMessageParserSingleton() throws Exception {
   public void testGeneratedMessageParserSingleton() throws Exception {
     for (int i = 0; i < 10; i++) {
     for (int i = 0; i < 10; i++) {
-      assertEquals(TestAllTypes.PARSER,
-                   TestUtil.getAllSet().getParserForType());
+      assertEquals(TestAllTypes.parser(), TestUtil.getAllSet().getParserForType());
     }
     }
   }
   }
 
 
@@ -125,8 +124,7 @@ public class ParserTest extends TestCase {
 
 
 
 
   public void testParsePartial() throws Exception {
   public void testParsePartial() throws Exception {
-    assertParsePartial(TestRequired.PARSER,
-        TestRequired.newBuilder().setA(1).buildPartial());
+    assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial());
   }
   }
 
 
   private <T extends MessageLite> void assertParsePartial(
   private <T extends MessageLite> void assertParsePartial(
@@ -216,8 +214,8 @@ public class ParserTest extends TestCase {
 
 
   public void testParseUnknownFields() throws Exception {
   public void testParseUnknownFields() throws Exception {
     // All fields will be treated as unknown fields in emptyMessage.
     // 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(
     assertEquals(
         TestUtil.getAllSet().toByteString(),
         TestUtil.getAllSet().toByteString(),
         emptyMessage.toByteString());
         emptyMessage.toByteString());
@@ -298,8 +296,7 @@ public class ParserTest extends TestCase {
     // Parse TestParsingMerge.
     // Parse TestParsingMerge.
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     UnittestProto.registerAllExtensions(registry);
     UnittestProto.registerAllExtensions(registry);
-    TestParsingMerge parsingMerge =
-        TestParsingMerge.PARSER.parseFrom(data, registry);
+    TestParsingMerge parsingMerge = TestParsingMerge.parser().parseFrom(data, registry);
 
 
     // Required and optional fields should be merged.
     // Required and optional fields should be merged.
     assertMessageMerged(parsingMerge.getRequiredAllTypes());
     assertMessageMerged(parsingMerge.getRequiredAllTypes());
@@ -361,8 +358,7 @@ public class ParserTest extends TestCase {
     // Parse TestParsingMergeLite.
     // Parse TestParsingMergeLite.
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     ExtensionRegistry registry = ExtensionRegistry.newInstance();
     UnittestLite.registerAllExtensions(registry);
     UnittestLite.registerAllExtensions(registry);
-    TestParsingMergeLite parsingMerge =
-        TestParsingMergeLite.PARSER.parseFrom(data, registry);
+    TestParsingMergeLite parsingMerge = TestParsingMergeLite.parser().parseFrom(data, registry);
 
 
     // Required and optional fields should be merged.
     // Required and optional fields should be merged.
     assertMessageMerged(parsingMerge.getRequiredAllTypes());
     assertMessageMerged(parsingMerge.getRequiredAllTypes());

+ 5 - 3
java/src/test/java/com/google/protobuf/RopeByteStringTest.java

@@ -119,7 +119,7 @@ public class RopeByteStringTest extends LiteralByteStringTest {
   }
   }
 
 
   @Override
   @Override
-  public void testCharsetToString() throws UnsupportedEncodingException {
+  public void testCharsetToString() {
     String sourceString = "I love unicode \u1234\u5678 characters";
     String sourceString = "I love unicode \u1234\u5678 characters";
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
     ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
     int copies = 250;
     int copies = 250;
@@ -145,14 +145,15 @@ public class RopeByteStringTest extends LiteralByteStringTest {
   }
   }
 
 
   @Override
   @Override
-  public void testToString_returnsCanonicalEmptyString() throws UnsupportedEncodingException {
+  public void testToString_returnsCanonicalEmptyString() {
     RopeByteString ropeByteString =
     RopeByteString ropeByteString =
         RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
         RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
     assertSame(classUnderTest + " must be the same string references",
     assertSame(classUnderTest + " must be the same string references",
         ByteString.EMPTY.toString(Internal.UTF_8), ropeByteString.toString(Internal.UTF_8));
         ByteString.EMPTY.toString(Internal.UTF_8), ropeByteString.toString(Internal.UTF_8));
   }
   }
 
 
-  public void testToString_raisesException() throws UnsupportedEncodingException{
+  @Override
+  public void testToString_raisesException() {
     try {
     try {
       ByteString byteString =
       ByteString byteString =
           RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
           RopeByteString.newInstanceForTest(ByteString.EMPTY, ByteString.EMPTY);
@@ -172,6 +173,7 @@ public class RopeByteStringTest extends LiteralByteStringTest {
     }
     }
   }
   }
 
 
+  @Override
   public void testJavaSerialization() throws Exception {
   public void testJavaSerialization() throws Exception {
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     ObjectOutputStream oos = new ObjectOutputStream(out);
     ObjectOutputStream oos = new ObjectOutputStream(out);

+ 1 - 0
java/src/test/java/com/google/protobuf/TestUtil.java

@@ -732,6 +732,7 @@ public final class TestUtil {
     Assert.assertEquals("424", message.getDefaultStringPiece());
     Assert.assertEquals("424", message.getDefaultStringPiece());
     Assert.assertEquals("425", message.getDefaultCord());
     Assert.assertEquals("425", message.getDefaultCord());
 
 
+    Assert.assertEquals(TestAllTypes.OneofFieldCase.ONEOF_BYTES, message.getOneofFieldCase());
     Assert.assertFalse(message.hasOneofUint32());
     Assert.assertFalse(message.hasOneofUint32());
     Assert.assertFalse(message.hasOneofNestedMessage());
     Assert.assertFalse(message.hasOneofNestedMessage());
     Assert.assertFalse(message.hasOneofString());
     Assert.assertFalse(message.hasOneofString());

+ 1 - 1
java/src/test/java/com/google/protobuf/TextFormatTest.java

@@ -32,7 +32,6 @@ package com.google.protobuf;
 
 
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
 import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
-import protobuf_unittest.UnittestMset.TestMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import protobuf_unittest.UnittestProto.OneString;
 import protobuf_unittest.UnittestProto.OneString;
@@ -41,6 +40,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestEmptyMessage;
 import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneof2;
+import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 
 
 import junit.framework.TestCase;
 import junit.framework.TestCase;
 
 

+ 1 - 1
java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java

@@ -461,7 +461,7 @@ public class UnknownFieldSetTest extends TestCase {
     TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
     TestAllExtensions allExtensions = TestUtil.getAllExtensionsSet();
     ByteString allExtensionsData = allExtensions.toByteString();
     ByteString allExtensionsData = allExtensions.toByteString();
     UnittestLite.TestEmptyMessageLite emptyMessageLite =
     UnittestLite.TestEmptyMessageLite emptyMessageLite =
-        UnittestLite.TestEmptyMessageLite.PARSER.parseFrom(allExtensionsData);
+        UnittestLite.TestEmptyMessageLite.parser().parseFrom(allExtensionsData);
     ByteString data = emptyMessageLite.toByteString();
     ByteString data = emptyMessageLite.toByteString();
     TestAllExtensions message =
     TestAllExtensions message =
         TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
         TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());

+ 1 - 1
java/src/test/java/com/google/protobuf/WireFormatTest.java

@@ -44,10 +44,10 @@ import protobuf_unittest.UnittestProto.TestOneof2;
 import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
 import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedExtensions;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
 import protobuf_unittest.UnittestProto.TestPackedTypes;
-import protobuf_unittest.UnittestMset.TestMessageSet;
 import protobuf_unittest.UnittestMset.RawMessageSet;
 import protobuf_unittest.UnittestMset.RawMessageSet;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
 import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
 import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
 import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
 
 

+ 7 - 4
python/google/protobuf/internal/containers.py

@@ -41,6 +41,7 @@ are:
 
 
 __author__ = 'petar@google.com (Petar Petrov)'
 __author__ = 'petar@google.com (Petar Petrov)'
 
 
+import collections
 import sys
 import sys
 
 
 if sys.version_info[0] < 3:
 if sys.version_info[0] < 3:
@@ -63,7 +64,6 @@ if sys.version_info[0] < 3:
   # Note: deriving from object is critical.  It is the only thing that makes
   # 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
   # this a true type, allowing us to derive from it in C++ cleanly and making
   # __slots__ properly disallow arbitrary element assignment.
   # __slots__ properly disallow arbitrary element assignment.
-  from collections import Mapping as _Mapping
 
 
   class Mapping(object):
   class Mapping(object):
     __slots__ = ()
     __slots__ = ()
@@ -106,7 +106,7 @@ if sys.version_info[0] < 3:
     __hash__ = None
     __hash__ = None
 
 
     def __eq__(self, other):
     def __eq__(self, other):
-      if not isinstance(other, _Mapping):
+      if not isinstance(other, collections.Mapping):
         return NotImplemented
         return NotImplemented
       return dict(self.items()) == dict(other.items())
       return dict(self.items()) == dict(other.items())
 
 
@@ -173,12 +173,13 @@ if sys.version_info[0] < 3:
         self[key] = default
         self[key] = default
       return default
       return default
 
 
-  _Mapping.register(Mapping)
+  collections.Mapping.register(Mapping)
+  collections.MutableMapping.register(MutableMapping)
 
 
 else:
 else:
   # In Python 3 we can just use MutableMapping directly, because it defines
   # In Python 3 we can just use MutableMapping directly, because it defines
   # __slots__.
   # __slots__.
-  from collections import MutableMapping
+  MutableMapping = collections.MutableMapping
 
 
 
 
 class BaseContainer(object):
 class BaseContainer(object):
@@ -336,6 +337,8 @@ class RepeatedScalarFieldContainer(BaseContainer):
     # We are presumably comparing against some other sequence type.
     # We are presumably comparing against some other sequence type.
     return other == self._values
     return other == self._values
 
 
+collections.MutableSequence.register(BaseContainer)
+
 
 
 class RepeatedCompositeFieldContainer(BaseContainer):
 class RepeatedCompositeFieldContainer(BaseContainer):
 
 

+ 2 - 1
python/google/protobuf/internal/generator_test.py

@@ -47,6 +47,7 @@ from google.protobuf import unittest_custom_options_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_import_pb2
 from google.protobuf import unittest_import_public_pb2
 from google.protobuf import unittest_import_public_pb2
 from google.protobuf import unittest_mset_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_no_generic_services_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import service
 from google.protobuf import service
@@ -142,7 +143,7 @@ class GeneratorTest(unittest.TestCase):
     self.assertTrue(not non_extension_descriptor.is_extension)
     self.assertTrue(not non_extension_descriptor.is_extension)
 
 
   def testOptions(self):
   def testOptions(self):
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = unittest_mset_wire_format_pb2.TestMessageSet()
     self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
     self.assertTrue(proto.DESCRIPTOR.GetOptions().message_set_wire_format)
 
 
   def testMessageWithCustomOptions(self):
   def testMessageWithCustomOptions(self):

+ 115 - 0
python/google/protobuf/internal/message_test.py

@@ -43,6 +43,7 @@ abstract interface.
 
 
 __author__ = 'gps@google.com (Gregory P. Smith)'
 __author__ = 'gps@google.com (Gregory P. Smith)'
 
 
+import collections
 import copy
 import copy
 import math
 import math
 import operator
 import operator
@@ -56,6 +57,7 @@ from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 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.internal import test_util
 from google.protobuf import message
 from google.protobuf import message
 
 
@@ -421,6 +423,31 @@ class MessageTest(unittest.TestCase):
     self.assertEqual(message.repeated_nested_message[4].bb, 5)
     self.assertEqual(message.repeated_nested_message[4].bb, 5)
     self.assertEqual(message.repeated_nested_message[5].bb, 6)
     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):
   def testRepeatedCompositeFieldSortArguments(self, message_module):
     """Check sorting a repeated composite field using list.sort() arguments."""
     """Check sorting a repeated composite field using list.sort() arguments."""
     message = message_module.TestAllTypes()
     message = message_module.TestAllTypes()
@@ -514,6 +541,12 @@ class MessageTest(unittest.TestCase):
 
 
     # TODO(anuraag): Implement extensiondict comparison in C++ and then add test
     # 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):
   def ensureNestedMessageExists(self, msg, attribute):
     """Make sure that a nested message object exists.
     """Make sure that a nested message object exists.
 
 
@@ -556,6 +589,18 @@ class MessageTest(unittest.TestCase):
     self.assertFalse(m.HasField('oneof_uint32'))
     self.assertFalse(m.HasField('oneof_uint32'))
     self.assertTrue(m.HasField('oneof_string'))
     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
     m.oneof_nested_message.bb = 11
     self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
     self.assertEqual('oneof_nested_message', m.WhichOneof('oneof_field'))
     self.assertFalse(m.HasField('oneof_string'))
     self.assertFalse(m.HasField('oneof_string'))
@@ -1583,6 +1628,21 @@ class Proto3Test(unittest.TestCase):
     del msg.map_int32_int32[4]
     del msg.map_int32_int32[4]
     self.assertEqual(0, len(msg.map_int32_int32))
     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):
 class ValidTypeNamesTest(unittest.TestCase):
@@ -1606,6 +1666,61 @@ class ValidTypeNamesTest(unittest.TestCase):
     self.assertImportFromName(pb.repeated_int32, 'Scalar')
     self.assertImportFromName(pb.repeated_int32, 'Scalar')
     self.assertImportFromName(pb.repeated_nested_message, 'Composite')
     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__':
 if __name__ == '__main__':
   unittest.main()
   unittest.main()

+ 73 - 0
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];
+}

+ 107 - 44
python/google/protobuf/internal/python_message.py

@@ -85,34 +85,108 @@ from google.protobuf import text_format
 _FieldDescriptor = descriptor_mod.FieldDescriptor
 _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.
 # Stateless helpers for GeneratedProtocolMessageType below.
@@ -362,9 +436,10 @@ def _DefaultValueConstructorForField(field):
     message_type = field.message_type
     message_type = field.message_type
     def MakeSubMessageDefault(message):
     def MakeSubMessageDefault(message):
       result = message_type._concrete_class()
       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 result
     return MakeSubMessageDefault
     return MakeSubMessageDefault
 
 
@@ -634,21 +709,11 @@ def _AddPropertiesForNonRepeatedCompositeField(field, cls):
   proto_field_name = field.name
   proto_field_name = field.name
   property_name = _PropertyName(proto_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):
   def getter(self):
     field_value = self._fields.get(field)
     field_value = self._fields.get(field)
     if field_value is None:
     if field_value is None:
       # Construct a new object to represent this field.
       # 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
       # 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
       # in the new object we just created.  If someone has preempted us, we
@@ -1121,7 +1186,7 @@ def _AddIsInitializedMethod(message_descriptor, cls):
           if _IsMessageMapField(field):
           if _IsMessageMapField(field):
             for key in value:
             for key in value:
               element = value[key]
               element = value[key]
-              prefix = "%s[%d]." % (name, key)
+              prefix = "%s[%s]." % (name, key)
               sub_errors = element.FindInitializationErrors()
               sub_errors = element.FindInitializationErrors()
               errors += [prefix + error for error in sub_errors]
               errors += [prefix + error for error in sub_errors]
           else:
           else:
@@ -1173,8 +1238,6 @@ def _AddMergeFromMethod(cls):
             # Construct a new object to represent this field.
             # Construct a new object to represent this field.
             field_value = field._default_constructor(self)
             field_value = field._default_constructor(self)
             fields[field] = field_value
             fields[field] = field_value
-            if field.containing_oneof:
-              self._UpdateOneofState(field)
           field_value.MergeFrom(value)
           field_value.MergeFrom(value)
       else:
       else:
         self._fields[field] = value
         self._fields[field] = value

+ 24 - 24
python/google/protobuf/internal/reflection_test.py

@@ -52,6 +52,7 @@ from google.protobuf import text_format
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import more_extensions_pb2
 from google.protobuf.internal import more_extensions_pb2
 from google.protobuf.internal import more_messages_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 wire_format
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf.internal import decoder
 from google.protobuf.internal import decoder
@@ -1682,8 +1683,8 @@ class ReflectionTest(unittest.TestCase):
     proto.optional_string = 'abc'
     proto.optional_string = 'abc'
 
 
   def testStringUTF8Serialization(self):
   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
     extension = extension_message.message_set_extension
 
 
     test_utf8 = u'Тест'
     test_utf8 = u'Тест'
@@ -1703,15 +1704,14 @@ class ReflectionTest(unittest.TestCase):
     bytes_read = raw.MergeFromString(serialized)
     bytes_read = raw.MergeFromString(serialized)
     self.assertEqual(len(serialized), bytes_read)
     self.assertEqual(len(serialized), bytes_read)
 
 
-    message2 = unittest_mset_pb2.TestMessageSetExtension2()
+    message2 = message_set_extensions_pb2.TestMessageSetExtension2()
 
 
     self.assertEqual(1, len(raw.item))
     self.assertEqual(1, len(raw.item))
     # Check that the type_id is the same as the tag ID in the .proto file.
     # 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.
     # 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)
     bytes_read = message2.MergeFromString(raw.item[0].message)
     self.assertEqual(len(raw.item[0].message), bytes_read)
     self.assertEqual(len(raw.item[0].message), bytes_read)
 
 
@@ -2395,9 +2395,9 @@ class SerializationTest(unittest.TestCase):
     self.assertEqual(42, second_proto.optional_nested_message.bb)
     self.assertEqual(42, second_proto.optional_nested_message.bb)
 
 
   def testMessageSetWireFormat(self):
   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
     extension1 = extension_message1.message_set_extension
     extension2 = extension_message2.message_set_extension
     extension2 = extension_message2.message_set_extension
     proto.Extensions[extension1].i = 123
     proto.Extensions[extension1].i = 123
@@ -2415,20 +2415,20 @@ class SerializationTest(unittest.TestCase):
         raw.MergeFromString(serialized))
         raw.MergeFromString(serialized))
     self.assertEqual(2, len(raw.item))
     self.assertEqual(2, len(raw.item))
 
 
-    message1 = unittest_mset_pb2.TestMessageSetExtension1()
+    message1 = message_set_extensions_pb2.TestMessageSetExtension1()
     self.assertEqual(
     self.assertEqual(
         len(raw.item[0].message),
         len(raw.item[0].message),
         message1.MergeFromString(raw.item[0].message))
         message1.MergeFromString(raw.item[0].message))
     self.assertEqual(123, message1.i)
     self.assertEqual(123, message1.i)
 
 
-    message2 = unittest_mset_pb2.TestMessageSetExtension2()
+    message2 = message_set_extensions_pb2.TestMessageSetExtension2()
     self.assertEqual(
     self.assertEqual(
         len(raw.item[1].message),
         len(raw.item[1].message),
         message2.MergeFromString(raw.item[1].message))
         message2.MergeFromString(raw.item[1].message))
     self.assertEqual('foo', message2.str)
     self.assertEqual('foo', message2.str)
 
 
     # Deserialize using the MessageSet wire format.
     # Deserialize using the MessageSet wire format.
-    proto2 = unittest_mset_pb2.TestMessageSet()
+    proto2 = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(
     self.assertEqual(
         len(serialized),
         len(serialized),
         proto2.MergeFromString(serialized))
         proto2.MergeFromString(serialized))
@@ -2446,37 +2446,37 @@ class SerializationTest(unittest.TestCase):
 
 
     # Add an item.
     # Add an item.
     item = raw.item.add()
     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
     message1.i = 12345
     item.message = message1.SerializeToString()
     item.message = message1.SerializeToString()
 
 
     # Add a second, unknown extension.
     # Add a second, unknown extension.
     item = raw.item.add()
     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
     message1.i = 12346
     item.message = message1.SerializeToString()
     item.message = message1.SerializeToString()
 
 
     # Add another unknown extension.
     # Add another unknown extension.
     item = raw.item.add()
     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'
     message1.str = 'foo'
     item.message = message1.SerializeToString()
     item.message = message1.SerializeToString()
 
 
     serialized = raw.SerializeToString()
     serialized = raw.SerializeToString()
 
 
     # Parse message using the message set wire format.
     # Parse message using the message set wire format.
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(
     self.assertEqual(
         len(serialized),
         len(serialized),
         proto.MergeFromString(serialized))
         proto.MergeFromString(serialized))
 
 
     # Check that the message parsed well.
     # 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
     extension1 = extension_message1.message_set_extension
     self.assertEquals(12345, proto.Extensions[extension1].i)
     self.assertEquals(12345, proto.Extensions[extension1].i)
 
 
@@ -2805,7 +2805,7 @@ class SerializationTest(unittest.TestCase):
 class OptionsTest(unittest.TestCase):
 class OptionsTest(unittest.TestCase):
 
 
   def testMessageOptions(self):
   def testMessageOptions(self):
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     self.assertEqual(True,
     self.assertEqual(True,
                      proto.DESCRIPTOR.GetOptions().message_set_wire_format)
                      proto.DESCRIPTOR.GetOptions().message_set_wire_format)
     proto = unittest_pb2.TestAllTypes()
     proto = unittest_pb2.TestAllTypes()
@@ -2824,7 +2824,7 @@ class OptionsTest(unittest.TestCase):
     proto.packed_double.append(3.0)
     proto.packed_double.append(3.0)
     for field_descriptor, _ in proto.ListFields():
     for field_descriptor, _ in proto.ListFields():
       self.assertEqual(True, field_descriptor.GetOptions().packed)
       self.assertEqual(True, field_descriptor.GetOptions().packed)
-      self.assertEqual(reflection._FieldDescriptor.LABEL_REPEATED,
+      self.assertEqual(descriptor.FieldDescriptor.LABEL_REPEATED,
                        field_descriptor.label)
                        field_descriptor.label)
 
 
 
 

+ 2 - 1
python/google/protobuf/internal/test_util.py

@@ -604,7 +604,8 @@ def GoldenFile(filename):
 
 
   # Search internally.
   # Search internally.
   path = '.'
   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):
   if os.path.exists(full_path):
     # Found it.  Load the golden file from the testdata directory.
     # Found it.  Load the golden file from the testdata directory.
     return open(full_path, 'rb')
     return open(full_path, 'rb')

+ 31 - 0
python/google/protobuf/internal/text_format_test.py

@@ -35,6 +35,7 @@
 __author__ = 'kenton@google.com (Kenton Varda)'
 __author__ = 'kenton@google.com (Kenton Varda)'
 
 
 import re
 import re
+import string
 import unittest
 import unittest
 
 
 import unittest
 import unittest
@@ -497,6 +498,36 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase):
         '  }\n'
         '  }\n'
         '}\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.).
 # Tests of proto2-only features (MessageSet, extensions, etc.).
 class Proto2Tests(TextFormatBase):
 class Proto2Tests(TextFormatBase):

+ 46 - 26
python/google/protobuf/internal/unknown_fields_test.py

@@ -41,11 +41,18 @@ from google.protobuf import unittest_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf import unittest_proto3_arena_pb2
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import encoder
 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 missing_enum_values_pb2
 from google.protobuf.internal import test_util
 from google.protobuf.internal import test_util
 from google.protobuf.internal import type_checkers
 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):
 class UnknownFieldsTest(unittest.TestCase):
 
 
   def setUp(self):
   def setUp(self):
@@ -83,15 +90,15 @@ class UnknownFieldsTest(unittest.TestCase):
 
 
     # Add an unknown extension.
     # Add an unknown extension.
     item = raw.item.add()
     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
     message1.i = 12345
     item.message = message1.SerializeToString()
     item.message = message1.SerializeToString()
 
 
     serialized = raw.SerializeToString()
     serialized = raw.SerializeToString()
 
 
     # Parse message using the message set wire format.
     # Parse message using the message set wire format.
-    proto = unittest_mset_pb2.TestMessageSet()
+    proto = message_set_extensions_pb2.TestMessageSet()
     proto.MergeFromString(serialized)
     proto.MergeFromString(serialized)
 
 
     # Verify that the unknown extension is serialized unchanged
     # Verify that the unknown extension is serialized unchanged
@@ -100,13 +107,6 @@ class UnknownFieldsTest(unittest.TestCase):
     new_raw.MergeFromString(reserialized)
     new_raw.MergeFromString(reserialized)
     self.assertEqual(raw, new_raw)
     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):
   def testEquals(self):
     message = unittest_pb2.TestEmptyMessage()
     message = unittest_pb2.TestEmptyMessage()
     message.ParseFromString(self.all_fields_data)
     message.ParseFromString(self.all_fields_data)
@@ -117,9 +117,6 @@ class UnknownFieldsTest(unittest.TestCase):
     self.assertNotEqual(self.empty_message, message)
     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):
 class UnknownFieldsAccessorsTest(unittest.TestCase):
 
 
   def setUp(self):
   def setUp(self):
@@ -129,7 +126,14 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
     self.all_fields_data = self.all_fields.SerializeToString()
     self.all_fields_data = self.all_fields.SerializeToString()
     self.empty_message = unittest_pb2.TestEmptyMessage()
     self.empty_message = unittest_pb2.TestEmptyMessage()
     self.empty_message.ParseFromString(self.all_fields_data)
     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):
   def GetField(self, name):
     field_descriptor = self.descriptor.fields_by_name[name]
     field_descriptor = self.descriptor.fields_by_name[name]
@@ -142,30 +146,37 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
         decoder(value, 0, len(value), self.all_fields, result_dict)
         decoder(value, 0, len(value), self.all_fields, result_dict)
     return result_dict[field_descriptor]
     return result_dict[field_descriptor]
 
 
+  @SkipIfCppImplementation
   def testEnum(self):
   def testEnum(self):
     value = self.GetField('optional_nested_enum')
     value = self.GetField('optional_nested_enum')
     self.assertEqual(self.all_fields.optional_nested_enum, value)
     self.assertEqual(self.all_fields.optional_nested_enum, value)
 
 
+  @SkipIfCppImplementation
   def testRepeatedEnum(self):
   def testRepeatedEnum(self):
     value = self.GetField('repeated_nested_enum')
     value = self.GetField('repeated_nested_enum')
     self.assertEqual(self.all_fields.repeated_nested_enum, value)
     self.assertEqual(self.all_fields.repeated_nested_enum, value)
 
 
+  @SkipIfCppImplementation
   def testVarint(self):
   def testVarint(self):
     value = self.GetField('optional_int32')
     value = self.GetField('optional_int32')
     self.assertEqual(self.all_fields.optional_int32, value)
     self.assertEqual(self.all_fields.optional_int32, value)
 
 
+  @SkipIfCppImplementation
   def testFixed32(self):
   def testFixed32(self):
     value = self.GetField('optional_fixed32')
     value = self.GetField('optional_fixed32')
     self.assertEqual(self.all_fields.optional_fixed32, value)
     self.assertEqual(self.all_fields.optional_fixed32, value)
 
 
+  @SkipIfCppImplementation
   def testFixed64(self):
   def testFixed64(self):
     value = self.GetField('optional_fixed64')
     value = self.GetField('optional_fixed64')
     self.assertEqual(self.all_fields.optional_fixed64, value)
     self.assertEqual(self.all_fields.optional_fixed64, value)
 
 
+  @SkipIfCppImplementation
   def testLengthDelimited(self):
   def testLengthDelimited(self):
     value = self.GetField('optional_string')
     value = self.GetField('optional_string')
     self.assertEqual(self.all_fields.optional_string, value)
     self.assertEqual(self.all_fields.optional_string, value)
 
 
+  @SkipIfCppImplementation
   def testGroup(self):
   def testGroup(self):
     value = self.GetField('optionalgroup')
     value = self.GetField('optionalgroup')
     self.assertEqual(self.all_fields.optionalgroup, value)
     self.assertEqual(self.all_fields.optionalgroup, value)
@@ -173,7 +184,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
   def testCopyFrom(self):
   def testCopyFrom(self):
     message = unittest_pb2.TestEmptyMessage()
     message = unittest_pb2.TestEmptyMessage()
     message.CopyFrom(self.empty_message)
     message.CopyFrom(self.empty_message)
-    self.assertEqual(self.unknown_fields, message._unknown_fields)
+    self.assertEqual(message.SerializeToString(), self.all_fields_data)
 
 
   def testMergeFrom(self):
   def testMergeFrom(self):
     message = unittest_pb2.TestAllTypes()
     message = unittest_pb2.TestAllTypes()
@@ -187,27 +198,26 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
     message.optional_uint32 = 4
     message.optional_uint32 = 4
     destination = unittest_pb2.TestEmptyMessage()
     destination = unittest_pb2.TestEmptyMessage()
     destination.ParseFromString(message.SerializeToString())
     destination.ParseFromString(message.SerializeToString())
-    unknown_fields = destination._unknown_fields[:]
 
 
     destination.MergeFrom(source)
     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):
   def testClear(self):
     self.empty_message.Clear()
     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):
   def testUnknownExtensions(self):
     message = unittest_pb2.TestEmptyMessageWithExtensions()
     message = unittest_pb2.TestEmptyMessageWithExtensions()
     message.ParseFromString(self.all_fields_data)
     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):
 class UnknownEnumValuesTest(unittest.TestCase):
 
 
   def setUp(self):
   def setUp(self):
@@ -227,7 +237,14 @@ class UnknownEnumValuesTest(unittest.TestCase):
     self.message_data = self.message.SerializeToString()
     self.message_data = self.message.SerializeToString()
     self.missing_message = missing_enum_values_pb2.TestMissingEnumValues()
     self.missing_message = missing_enum_values_pb2.TestMissingEnumValues()
     self.missing_message.ParseFromString(self.message_data)
     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):
   def GetField(self, name):
     field_descriptor = self.descriptor.fields_by_name[name]
     field_descriptor = self.descriptor.fields_by_name[name]
@@ -241,15 +258,18 @@ class UnknownEnumValuesTest(unittest.TestCase):
         decoder(value, 0, len(value), self.message, result_dict)
         decoder(value, 0, len(value), self.message, result_dict)
     return result_dict[field_descriptor]
     return result_dict[field_descriptor]
 
 
+  @SkipIfCppImplementation
   def testUnknownEnumValue(self):
   def testUnknownEnumValue(self):
     self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
     self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
     value = self.GetField('optional_nested_enum')
     value = self.GetField('optional_nested_enum')
     self.assertEqual(self.message.optional_nested_enum, value)
     self.assertEqual(self.message.optional_nested_enum, value)
 
 
+  @SkipIfCppImplementation
   def testUnknownRepeatedEnumValue(self):
   def testUnknownRepeatedEnumValue(self):
     value = self.GetField('repeated_nested_enum')
     value = self.GetField('repeated_nested_enum')
     self.assertEqual(self.message.repeated_nested_enum, value)
     self.assertEqual(self.message.repeated_nested_enum, value)
 
 
+  @SkipIfCppImplementation
   def testUnknownPackedEnumValue(self):
   def testUnknownPackedEnumValue(self):
     value = self.GetField('packed_nested_enum')
     value = self.GetField('packed_nested_enum')
     self.assertEqual(self.message.packed_nested_enum, value)
     self.assertEqual(self.message.packed_nested_enum, value)

+ 22 - 14
python/google/protobuf/pyext/cpp_message.py

@@ -37,21 +37,29 @@ Descriptor objects at runtime backed by the protocol buffer C++ API.
 __author__ = 'tibell@google.com (Johan Tibell)'
 __author__ = 'tibell@google.com (Johan Tibell)'
 
 
 from google.protobuf.pyext import _message
 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'

+ 1 - 1
python/google/protobuf/pyext/descriptor.cc

@@ -193,7 +193,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
     io::CodedInputStream input(
     io::CodedInputStream input(
         reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
         reinterpret_cast<const uint8*>(serialized.c_str()), serialized.size());
     input.SetExtensionRegistry(GetDescriptorPool()->pool,
     input.SetExtensionRegistry(GetDescriptorPool()->pool,
-                               cmessage::GetMessageFactory());
+                               GetDescriptorPool()->message_factory);
     bool success = cmsg->message->MergePartialFromCodedStream(&input);
     bool success = cmsg->message->MergePartialFromCodedStream(&input);
     if (!success) {
     if (!success) {
       PyErr_Format(PyExc_ValueError, "Error parsing Options message");
       PyErr_Format(PyExc_ValueError, "Error parsing Options message");

+ 7 - 0
python/google/protobuf/pyext/descriptor_pool.cc

@@ -33,6 +33,7 @@
 #include <Python.h>
 #include <Python.h>
 
 
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>
@@ -67,6 +68,11 @@ PyDescriptorPool* NewDescriptorPool() {
   // as underlay.
   // as underlay.
   cdescriptor_pool->pool = new DescriptorPool(DescriptorPool::generated_pool());
   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
   // TODO(amauryfa): Rewrite the SymbolDatabase in C so that it uses the same
   // storage.
   // storage.
   cdescriptor_pool->classes_by_descriptor =
   cdescriptor_pool->classes_by_descriptor =
@@ -93,6 +99,7 @@ static void Dealloc(PyDescriptorPool* self) {
     Py_DECREF(it->second);
     Py_DECREF(it->second);
   }
   }
   delete self->descriptor_options;
   delete self->descriptor_options;
+  delete self->message_factory;
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
   Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
 }
 }
 
 

+ 10 - 0
python/google/protobuf/pyext/descriptor_pool.h

@@ -38,6 +38,8 @@
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {
+class MessageFactory;
+
 namespace python {
 namespace python {
 
 
 // Wraps operations to the global DescriptorPool which contains information
 // Wraps operations to the global DescriptorPool which contains information
@@ -55,6 +57,14 @@ typedef struct PyDescriptorPool {
 
 
   DescriptorPool* pool;
   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.
   // Make our own mapping to retrieve Python classes from C++ descriptors.
   //
   //
   // Descriptor pointers stored here are owned by the DescriptorPool above.
   // Descriptor pointers stored here are owned by the DescriptorPool above.

+ 4 - 2
python/google/protobuf/pyext/extension_dict.cc

@@ -33,6 +33,7 @@
 
 
 #include <google/protobuf/pyext/extension_dict.h>
 #include <google/protobuf/pyext/extension_dict.h>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/dynamic_message.h>
@@ -183,7 +184,8 @@ PyObject* ClearExtension(ExtensionDict* self, PyObject* extension) {
       return NULL;
       return NULL;
     }
     }
   }
   }
-  if (cmessage::ClearFieldByDescriptor(self->parent, descriptor) == NULL) {
+  if (ScopedPyObjectPtr(cmessage::ClearFieldByDescriptor(
+          self->parent, descriptor)) == NULL) {
     return NULL;
     return NULL;
   }
   }
   if (PyDict_DelItem(self->values, extension) < 0) {
   if (PyDict_DelItem(self->values, extension) < 0) {
@@ -268,7 +270,7 @@ PyTypeObject ExtensionDict_Type = {
   0,                                   //  tp_as_number
   0,                                   //  tp_as_number
   0,                                   //  tp_as_sequence
   0,                                   //  tp_as_sequence
   &extension_dict::MpMethods,          //  tp_as_mapping
   &extension_dict::MpMethods,          //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_str
   0,                                   //  tp_getattro
   0,                                   //  tp_getattro

+ 458 - 266
python/google/protobuf/pyext/message.cc

@@ -49,9 +49,10 @@
 #endif
 #endif
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/util/message_differencer.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
-#include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor.h>
@@ -88,12 +89,308 @@ namespace google {
 namespace protobuf {
 namespace protobuf {
 namespace python {
 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>_FIELD_NUMBER = <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>_FIELD_NUMBER = <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.<enum name> = EnumTypeWrapper(<enum descriptor>).
+  //
+  // The enum descriptor we get from
+  // <messagedescriptor>.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.<name> = <number>
+    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 name> = <extension descriptor>.
+  //
+  // Extension descriptors come from
+  // <message descriptor>.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.<extension name>_FIELD_NUMBER = <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<PyMessageMeta*>(result.get());
+
+  // Insert the empty weakref into the base classes.
+  if (InsertEmptyWeakref(
+          reinterpret_cast<PyTypeObject*>(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<PyObject*>(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<PyMessageMeta*>(cls)->message_descriptor;
+}
+
 // Forward declarations
 // Forward declarations
 namespace cmessage {
 namespace cmessage {
-static const FieldDescriptor* GetFieldDescriptor(
-    CMessage* self, PyObject* name);
-static const Descriptor* GetMessageDescriptor(PyTypeObject* cls);
-static string GetMessageName(CMessage* self);
 int InternalReleaseFieldByDescriptor(
 int InternalReleaseFieldByDescriptor(
     CMessage* self,
     CMessage* self,
     const FieldDescriptor* field_descriptor,
     const FieldDescriptor* field_descriptor,
@@ -180,7 +477,7 @@ int ForEachCompositeField(CMessage* self, Visitor visitor) {
   if (self->composite_fields) {
   if (self->composite_fields) {
     // Never use self->message in this function, it may be already freed.
     // Never use self->message in this function, it may be already freed.
     const Descriptor* message_descriptor =
     const Descriptor* message_descriptor =
-        cmessage::GetMessageDescriptor(Py_TYPE(self));
+        GetMessageDescriptor(Py_TYPE(self));
     while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
     while (PyDict_Next(self->composite_fields, &pos, &key, &field)) {
       Py_ssize_t key_str_size;
       Py_ssize_t key_str_size;
       char *key_str_data;
       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.
 // Constants used for integer type range checking.
 PyObject* kPythonZero;
 PyObject* kPythonZero;
 PyObject* kint32min_py;
 PyObject* kint32min_py;
@@ -224,17 +519,13 @@ PyObject* kint64min_py;
 PyObject* kint64max_py;
 PyObject* kint64max_py;
 PyObject* kuint64max_py;
 PyObject* kuint64max_py;
 
 
-PyObject* EnumTypeWrapper_class;
 PyObject* EncodeError_class;
 PyObject* EncodeError_class;
 PyObject* DecodeError_class;
 PyObject* DecodeError_class;
 PyObject* PickleError_class;
 PyObject* PickleError_class;
 
 
 // Constant PyString values used for GetAttr/GetItem.
 // Constant PyString values used for GetAttr/GetItem.
-static PyObject* kDESCRIPTOR;
 static PyObject* k_cdescriptor;
 static PyObject* k_cdescriptor;
 static PyObject* kfull_name;
 static PyObject* kfull_name;
-static PyObject* k_extensions_by_name;
-static PyObject* k_extensions_by_number;
 
 
 /* Is 64bit */
 /* Is 64bit */
 void FormatTypeError(PyObject* arg, char* expected_types) {
 void FormatTypeError(PyObject* arg, char* expected_types) {
@@ -432,10 +723,6 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
 
 
 namespace cmessage {
 namespace cmessage {
 
 
-DynamicMessageFactory* GetMessageFactory() {
-  return message_factory;
-}
-
 static int MaybeReleaseOverlappingOneofField(
 static int MaybeReleaseOverlappingOneofField(
     CMessage* cmessage,
     CMessage* cmessage,
     const FieldDescriptor* field) {
     const FieldDescriptor* field) {
@@ -486,7 +773,7 @@ static Message* GetMutableMessage(
     return NULL;
     return NULL;
   }
   }
   return reflection->MutableMessage(
   return reflection->MutableMessage(
-      parent_message, parent_field, message_factory);
+      parent_message, parent_field, GetDescriptorPool()->message_factory);
 }
 }
 
 
 struct FixupMessageReference : public ChildVisitor {
 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
     // 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
     // is a reference to a constant default instance that needs to be replaced
     // with a mutable top-level message.
     // 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->message = prototype->New();
     self->owner.reset(self->message);
     self->owner.reset(self->message);
     // Cascade the new owner to eventual children: even if this message is
     // Cascade the new owner to eventual children: even if this message is
@@ -567,23 +855,6 @@ int AssureWritable(CMessage* self) {
 
 
 // --- Globals:
 // --- 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<PyObject*>(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.
 // Retrieve a C++ FieldDescriptor for a message attribute.
 // The C++ message must be valid.
 // The C++ message must be valid.
 // TODO(amauryfa): This function should stay internal, because exception
 // TODO(amauryfa): This function should stay internal, because exception
@@ -846,9 +1117,9 @@ int InitAttributes(CMessage* self, PyObject* kwargs) {
           return -1;
           return -1;
         }
         }
       } else {
       } else {
-        if (repeated_scalar_container::Extend(
+        if (ScopedPyObjectPtr(repeated_scalar_container::Extend(
                 reinterpret_cast<RepeatedScalarContainer*>(container.get()),
                 reinterpret_cast<RepeatedScalarContainer*>(container.get()),
-                value) ==
+                value)) ==
             NULL) {
             NULL) {
           return -1;
           return -1;
         }
         }
@@ -927,7 +1198,7 @@ static PyObject* New(PyTypeObject* type,
     return NULL;
     return NULL;
   }
   }
   const Message* default_message =
   const Message* default_message =
-      message_factory->GetPrototype(message_descriptor);
+      GetDescriptorPool()->message_factory->GetPrototype(message_descriptor);
   if (default_message == NULL) {
   if (default_message == NULL) {
     PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
     PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
     return NULL;
     return NULL;
@@ -1257,6 +1528,7 @@ int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner) {
 Message* ReleaseMessage(CMessage* self,
 Message* ReleaseMessage(CMessage* self,
                         const Descriptor* descriptor,
                         const Descriptor* descriptor,
                         const FieldDescriptor* field_descriptor) {
                         const FieldDescriptor* field_descriptor) {
+  MessageFactory* message_factory = GetDescriptorPool()->message_factory;
   Message* released_message = self->message->GetReflection()->ReleaseMessage(
   Message* released_message = self->message->GetReflection()->ReleaseMessage(
       self->message, field_descriptor, message_factory);
       self->message, field_descriptor, message_factory);
   // ReleaseMessage will return NULL which differs from
   // ReleaseMessage will return NULL which differs from
@@ -1492,34 +1764,35 @@ static PyObject* SerializePartialToString(CMessage* self) {
 // appropriate.
 // appropriate.
 class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter {
 class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter {
  public:
  public:
-  PythonFieldValuePrinter() : float_holder_(PyFloat_FromDouble(0)) {}
-
   // Python has some differences from C++ when printing floating point numbers.
   // Python has some differences from C++ when printing floating point numbers.
   //
   //
   // 1) Trailing .0 is always printed.
   // 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
   // We override floating point printing with the C-API function for printing
   // Python floats to ensure consistency.
   // Python floats to ensure consistency.
   string PrintFloat(float value) const { return PrintDouble(value); }
   string PrintFloat(float value) const { return PrintDouble(value); }
   string PrintDouble(double value) const {
   string PrintDouble(double value) const {
-    reinterpret_cast<PyFloatObject*>(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
 #if PY_MAJOR_VERSION < 3
-    char *cstr = PyBytes_AS_STRING(static_cast<PyObject*>(s));
+        'g', PyFloat_STR_PRECISION,  // Output is rounded to 12 digits.
 #else
 #else
-    char *cstr = PyUnicode_AsUTF8(s);
+        'r', 0,
 #endif
 #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) {
 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,
   // CopyFrom on the message will not clean up self->composite_fields,
   // which can leave us in an inconsistent state, so clear it out here.
   // 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);
   self->message->CopyFrom(*other_message->message);
 
 
@@ -1607,7 +1880,8 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
   AssureWritable(self);
   AssureWritable(self);
   io::CodedInputStream input(
   io::CodedInputStream input(
       reinterpret_cast<const uint8*>(data), data_length);
       reinterpret_cast<const uint8*>(data), data_length);
-  input.SetExtensionRegistry(GetDescriptorPool()->pool, message_factory);
+  input.SetExtensionRegistry(GetDescriptorPool()->pool,
+                             GetDescriptorPool()->message_factory);
   bool success = self->message->MergePartialFromCodedStream(&input);
   bool success = self->message->MergePartialFromCodedStream(&input);
   if (success) {
   if (success) {
     return PyInt_FromLong(input.CurrentPosition());
     return PyInt_FromLong(input.CurrentPosition());
@@ -1618,7 +1892,7 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
 }
 }
 
 
 static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
 static PyObject* ParseFromString(CMessage* self, PyObject* arg) {
-  if (Clear(self) == NULL) {
+  if (ScopedPyObjectPtr(Clear(self)) == NULL) {
     return NULL;
     return NULL;
   }
   }
   return MergeFromString(self, arg);
   return MergeFromString(self, arg);
@@ -1790,6 +2064,7 @@ static PyObject* ListFields(CMessage* self) {
       // Steals reference to 'extension'
       // Steals reference to 'extension'
       PyTuple_SET_ITEM(t.get(), 1, extension);
       PyTuple_SET_ITEM(t.get(), 1, extension);
     } else {
     } else {
+      // Normal field
       const string& field_name = fields[i]->name();
       const string& field_name = fields[i]->name();
       ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize(
       ScopedPyObjectPtr py_field_name(PyString_FromStringAndSize(
           field_name.c_str(), field_name.length()));
           field_name.c_str(), field_name.length()));
@@ -1841,28 +2116,34 @@ PyObject* FindInitializationErrors(CMessage* self) {
 }
 }
 
 
 static PyObject* RichCompare(CMessage* self, PyObject* other, int opid) {
 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<CMessage*>(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);
     Py_INCREF(Py_NotImplemented);
     return 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<CMessage*>(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<CMessage*>(other)->message)) {
+    equals = false;
+  }
+  if (equals ^ (opid == Py_EQ)) {
+    Py_RETURN_FALSE;
+  } else {
+    Py_RETURN_TRUE;
+  }
 }
 }
 
 
 PyObject* InternalGetScalar(const Message* message,
 PyObject* InternalGetScalar(const Message* message,
@@ -1950,7 +2231,7 @@ PyObject* InternalGetSubMessage(
     CMessage* self, const FieldDescriptor* field_descriptor) {
     CMessage* self, const FieldDescriptor* field_descriptor) {
   const Reflection* reflection = self->message->GetReflection();
   const Reflection* reflection = self->message->GetReflection();
   const Message& sub_message = reflection->GetMessage(
   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(
   PyObject *message_class = cdescriptor_pool::GetMessageClass(
       GetDescriptorPool(), field_descriptor->message_type());
       GetDescriptorPool(), field_descriptor->message_type());
@@ -2085,125 +2366,6 @@ PyObject* FromString(PyTypeObject* cls, PyObject* serialized) {
   return py_cmsg;
   return py_cmsg;
 }
 }
 
 
-// Add the number of a field descriptor to the containing message class.
-// Equivalent to:
-//   _cls.<field>_FIELD_NUMBER = <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>_FIELD_NUMBER = <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.<enum name> = EnumTypeWrapper(<enum descriptor>).
-  //
-  // The enum descriptor we get from
-  // <messagedescriptor>.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.<name> = <number>
-    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 name> = <extension descriptor>.
-  //
-  // Extension descriptors come from
-  // <message descriptor>.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.<extension name>_FIELD_NUMBER = <number>.
-    if (!AddFieldNumberToClass(cls, field)) {
-      return NULL;
-    }
-  }
-
-  Py_RETURN_NONE;
-}
-
 PyObject* DeepCopy(CMessage* self, PyObject* arg) {
 PyObject* DeepCopy(CMessage* self, PyObject* arg) {
   PyObject* clone = PyObject_CallObject(
   PyObject* clone = PyObject_CallObject(
       reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
       reinterpret_cast<PyObject*>(Py_TYPE(self)), NULL);
@@ -2214,8 +2376,9 @@ PyObject* DeepCopy(CMessage* self, PyObject* arg) {
     Py_DECREF(clone);
     Py_DECREF(clone);
     return NULL;
     return NULL;
   }
   }
-  if (MergeFrom(reinterpret_cast<CMessage*>(clone),
-                reinterpret_cast<PyObject*>(self)) == NULL) {
+  if (ScopedPyObjectPtr(MergeFrom(
+          reinterpret_cast<CMessage*>(clone),
+          reinterpret_cast<PyObject*>(self))) == NULL) {
     Py_DECREF(clone);
     Py_DECREF(clone);
     return NULL;
     return NULL;
   }
   }
@@ -2281,7 +2444,7 @@ PyObject* SetState(CMessage* self, PyObject* state) {
   if (serialized == NULL) {
   if (serialized == NULL) {
     return NULL;
     return NULL;
   }
   }
-  if (ParseFromString(self, serialized) == NULL) {
+  if (ScopedPyObjectPtr(ParseFromString(self, serialized)) == NULL) {
     return NULL;
     return NULL;
   }
   }
   Py_RETURN_NONE;
   Py_RETURN_NONE;
@@ -2314,8 +2477,6 @@ static PyMethodDef Methods[] = {
     "Inputs picklable representation of the message." },
     "Inputs picklable representation of the message." },
   { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
   { "__unicode__", (PyCFunction)ToUnicode, METH_NOARGS,
     "Outputs a unicode representation of the message." },
     "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,
   { "ByteSize", (PyCFunction)ByteSize, METH_NOARGS,
     "Returns the size of the message in bytes." },
     "Returns the size of the message in bytes." },
   { "Clear", (PyCFunction)Clear, METH_NOARGS,
   { "Clear", (PyCFunction)Clear, METH_NOARGS,
@@ -2441,6 +2602,9 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
 
 
   if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
   if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     PyObject* sub_message = InternalGetSubMessage(self, field_descriptor);
     PyObject* sub_message = InternalGetSubMessage(self, field_descriptor);
+    if (sub_message == NULL) {
+      return NULL;
+    }
     if (!SetCompositeField(self, name, sub_message)) {
     if (!SetCompositeField(self, name, sub_message)) {
       Py_DECREF(sub_message);
       Py_DECREF(sub_message);
       return NULL;
       return NULL;
@@ -2484,7 +2648,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) {
 }  // namespace cmessage
 }  // namespace cmessage
 
 
 PyTypeObject CMessage_Type = {
 PyTypeObject CMessage_Type = {
-  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  PyVarObject_HEAD_INIT(&PyMessageMeta_Type, 0)
   FULL_MODULE_NAME ".CMessage",        // tp_name
   FULL_MODULE_NAME ".CMessage",        // tp_name
   sizeof(CMessage),                    // tp_basicsize
   sizeof(CMessage),                    // tp_basicsize
   0,                                   //  tp_itemsize
   0,                                   //  tp_itemsize
@@ -2497,7 +2661,7 @@ PyTypeObject CMessage_Type = {
   0,                                   //  tp_as_number
   0,                                   //  tp_as_number
   0,                                   //  tp_as_sequence
   0,                                   //  tp_as_sequence
   0,                                   //  tp_as_mapping
   0,                                   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_call
   (reprfunc)cmessage::ToStr,           //  tp_str
   (reprfunc)cmessage::ToStr,           //  tp_str
   (getattrofunc)cmessage::GetAttr,     //  tp_getattro
   (getattrofunc)cmessage::GetAttr,     //  tp_getattro
@@ -2580,8 +2744,9 @@ void InitGlobals() {
   k_extensions_by_name = PyString_FromString("_extensions_by_name");
   k_extensions_by_name = PyString_FromString("_extensions_by_name");
   k_extensions_by_number = PyString_FromString("_extensions_by_number");
   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) {
 bool InitProto2MessageModule(PyObject *m) {
@@ -2598,7 +2763,13 @@ bool InitProto2MessageModule(PyObject *m) {
   // Initialize constants defined in this file.
   // Initialize constants defined in this file.
   InitGlobals();
   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<PyObject*>(&PyMessageMeta_Type));
+
   if (PyType_Ready(&CMessage_Type) < 0) {
   if (PyType_Ready(&CMessage_Type) < 0) {
     return false;
     return false;
   }
   }
@@ -2628,86 +2799,106 @@ bool InitProto2MessageModule(PyObject *m) {
 
 
   PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&CMessage_Type));
   PyModule_AddObject(m, "Message", reinterpret_cast<PyObject*>(&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<PyObject*>(
-                         &RepeatedScalarContainer_Type));
+    PyModule_AddObject(m, "RepeatedScalarContainer",
+                       reinterpret_cast<PyObject*>(
+                           &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<PyObject*>(
-          &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<PyObject*>(
+            &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<PyTypeObject*>(mutable_mapping);
+    Py_INCREF(mutable_mapping);
+    ScalarMapContainer_Type.tp_base =
+        reinterpret_cast<PyTypeObject*>(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<PyObject*>(&ScalarMapContainer_Type));
+    PyModule_AddObject(m, "ScalarMapContainer",
+                       reinterpret_cast<PyObject*>(&ScalarMapContainer_Type));
 
 
-  if (PyType_Ready(&ScalarMapIterator_Type) < 0) {
-    return false;
-  }
+    if (PyType_Ready(&ScalarMapIterator_Type) < 0) {
+      return false;
+    }
 
 
-  PyModule_AddObject(m, "ScalarMapIterator",
-                     reinterpret_cast<PyObject*>(&ScalarMapIterator_Type));
+    PyModule_AddObject(m, "ScalarMapIterator",
+                       reinterpret_cast<PyObject*>(&ScalarMapIterator_Type));
 
 
-  Py_INCREF(mutable_mapping);
-  MessageMapContainer_Type.tp_base =
-      reinterpret_cast<PyTypeObject*>(mutable_mapping);
+    Py_INCREF(mutable_mapping);
+    MessageMapContainer_Type.tp_base =
+        reinterpret_cast<PyTypeObject*>(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<PyObject*>(&MessageMapContainer_Type));
+    PyModule_AddObject(m, "MessageMapContainer",
+                       reinterpret_cast<PyObject*>(&MessageMapContainer_Type));
 
 
-  if (PyType_Ready(&MessageMapIterator_Type) < 0) {
-    return false;
-  }
+    if (PyType_Ready(&MessageMapIterator_Type) < 0) {
+      return false;
+    }
 
 
-  PyModule_AddObject(m, "MessageMapIterator",
-                     reinterpret_cast<PyObject*>(&MessageMapIterator_Type));
+    PyModule_AddObject(m, "MessageMapIterator",
+                       reinterpret_cast<PyObject*>(&MessageMapIterator_Type));
+  }
 
 
-  ExtensionDict_Type.tp_hash = PyObject_HashNotImplemented;
   if (PyType_Ready(&ExtensionDict_Type) < 0) {
   if (PyType_Ready(&ExtensionDict_Type) < 0) {
     return false;
     return false;
   }
   }
-
   PyModule_AddObject(
   PyModule_AddObject(
       m, "ExtensionDict",
       m, "ExtensionDict",
       reinterpret_cast<PyObject*>(&ExtensionDict_Type));
       reinterpret_cast<PyObject*>(&ExtensionDict_Type));
@@ -2751,6 +2942,7 @@ bool InitProto2MessageModule(PyObject *m) {
   }
   }
   EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
   EncodeError_class = PyObject_GetAttrString(message_module, "EncodeError");
   DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError");
   DecodeError_class = PyObject_GetAttrString(message_module, "DecodeError");
+  PythonMessage_class = PyObject_GetAttrString(message_module, "Message");
   Py_DECREF(message_module);
   Py_DECREF(message_module);
 
 
   PyObject* pickle_module = PyImport_ImportModule("pickle");
   PyObject* pickle_module = PyImport_ImportModule("pickle");

+ 0 - 4
python/google/protobuf/pyext/message.h

@@ -49,7 +49,6 @@ class Message;
 class Reflection;
 class Reflection;
 class FieldDescriptor;
 class FieldDescriptor;
 class Descriptor;
 class Descriptor;
-class DynamicMessageFactory;
 
 
 using internal::shared_ptr;
 using internal::shared_ptr;
 
 
@@ -221,9 +220,6 @@ PyObject* FindInitializationErrors(CMessage* self);
 int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
 int SetOwner(CMessage* self, const shared_ptr<Message>& new_owner);
 
 
 int AssureWritable(CMessage* self);
 int AssureWritable(CMessage* self);
-
-DynamicMessageFactory* GetMessageFactory();
-
 }  // namespace cmessage
 }  // namespace cmessage
 
 
 
 

+ 1 - 0
python/google/protobuf/pyext/message_map_container.cc

@@ -32,6 +32,7 @@
 
 
 #include <google/protobuf/pyext/message_map_container.h>
 #include <google/protobuf/pyext/message_map_container.h>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>

+ 31 - 180
python/google/protobuf/pyext/repeated_composite_container.cc

@@ -38,11 +38,13 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #endif
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
 
@@ -74,125 +76,6 @@ namespace repeated_composite_container {
     GOOGLE_CHECK((self)->parent == NULL);       \
     GOOGLE_CHECK((self)->parent == NULL);       \
   } while (0);
   } 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]<x */
-      while (is_lt) {
-        ++left;
-        ScopedPyObjectPtr key(GET_KEY(keyfunc,
-                                      PyList_GET_ITEM(children, left)));
-        is_lt = islt(key, mid, cmp);
-        if (is_lt == -1)
-          return -1;
-      }
-      key.reset(GET_KEY(keyfunc, PyList_GET_ITEM(children, right - 1)));
-      is_lt = islt(mid, key, cmp);
-      if (is_lt == -1)
-        return -1;
-      while (is_lt) {
-        --right;
-        ScopedPyObjectPtr key(GET_KEY(keyfunc,
-                                      PyList_GET_ITEM(children, right - 1)));
-        is_lt = islt(mid, key, cmp);
-        if (is_lt == -1)
-          return -1;
-      }
-      if (left < right) {
-        --right;
-        if (left < right) {
-          reflection->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()
 // len()
 
 
@@ -329,7 +212,7 @@ PyObject* Extend(RepeatedCompositeContainer* self, PyObject* value) {
       return NULL;
       return NULL;
     }
     }
     CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
     CMessage* new_cmessage = reinterpret_cast<CMessage*>(new_message.get());
-    if (cmessage::MergeFrom(new_cmessage, next) == NULL) {
+    if (ScopedPyObjectPtr(cmessage::MergeFrom(new_cmessage, next)) == NULL) {
       return NULL;
       return NULL;
     }
     }
   }
   }
@@ -455,58 +338,39 @@ static PyObject* RichCompare(RepeatedCompositeContainer* self,
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 // sort()
 // 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);
   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<CMessage*>(
+        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"));
   ScopedPyObjectPtr m(PyObject_GetAttrString(self->child_messages, "sort"));
   if (m == NULL)
   if (m == NULL)
-    return NULL;
+    return -1;
   if (PyObject_Call(m, args, kwds) == NULL)
   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,
 static PyObject* Sort(RepeatedCompositeContainer* self,
@@ -527,11 +391,10 @@ static PyObject* Sort(RepeatedCompositeContainer* self,
   if (UpdateChildMessages(self) < 0) {
   if (UpdateChildMessages(self) < 0) {
     return NULL;
     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));
       parent->message->GetReflection()->ReleaseLast(parent->message, field));
   // TODO(tibell): Deal with proto1.
   // 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 = NULL;
   target->parent_field_descriptor = NULL;
   target->parent_field_descriptor = NULL;
   target->message = released_message.get();
   target->message = released_message.get();
@@ -732,7 +583,7 @@ PyTypeObject RepeatedCompositeContainer_Type = {
   0,                                   //  tp_as_number
   0,                                   //  tp_as_number
   &repeated_composite_container::SqMethods,   //  tp_as_sequence
   &repeated_composite_container::SqMethods,   //  tp_as_sequence
   &repeated_composite_container::MpMethods,   //  tp_as_mapping
   &repeated_composite_container::MpMethods,   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_str
   0,                                   //  tp_getattro
   0,                                   //  tp_getattro

+ 6 - 5
python/google/protobuf/pyext/repeated_scalar_container.cc

@@ -39,10 +39,12 @@
 #endif
 #endif
 
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/descriptor.h>
 #include <google/protobuf/pyext/descriptor.h>
+#include <google/protobuf/pyext/descriptor_pool.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 #include <google/protobuf/pyext/scoped_pyobject_ptr.h>
 
 
@@ -68,7 +70,7 @@ static int InternalAssignRepeatedField(
                                              self->parent_field_descriptor);
                                              self->parent_field_descriptor);
   for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
   for (Py_ssize_t i = 0; i < PyList_GET_SIZE(list); ++i) {
     PyObject* value = PyList_GET_ITEM(list, i);
     PyObject* value = PyList_GET_ITEM(list, i);
-    if (Append(self, value) == NULL) {
+    if (ScopedPyObjectPtr(Append(self, value)) == NULL) {
       return -1;
       return -1;
     }
     }
   }
   }
@@ -510,7 +512,7 @@ PyObject* Extend(RepeatedScalarContainer* self, PyObject* value) {
   }
   }
   ScopedPyObjectPtr next;
   ScopedPyObjectPtr next;
   while ((next.reset(PyIter_Next(iter))) != NULL) {
   while ((next.reset(PyIter_Next(iter))) != NULL) {
-    if (Append(self, next) == NULL) {
+    if (ScopedPyObjectPtr(Append(self, next)) == NULL) {
       return NULL;
       return NULL;
     }
     }
   }
   }
@@ -690,8 +692,7 @@ static int InitializeAndCopyToParentContainer(
   if (values == NULL) {
   if (values == NULL) {
     return -1;
     return -1;
   }
   }
-  Message* new_message = cmessage::GetMessageFactory()->GetPrototype(
-      from->message->GetDescriptor())->New();
+  Message* new_message = from->message->New();
   to->parent = NULL;
   to->parent = NULL;
   to->parent_field_descriptor = from->parent_field_descriptor;
   to->parent_field_descriptor = from->parent_field_descriptor;
   to->message = new_message;
   to->message = new_message;
@@ -781,7 +782,7 @@ PyTypeObject RepeatedScalarContainer_Type = {
   0,                                   //  tp_as_number
   0,                                   //  tp_as_number
   &repeated_scalar_container::SqMethods,   //  tp_as_sequence
   &repeated_scalar_container::SqMethods,   //  tp_as_sequence
   &repeated_scalar_container::MpMethods,   //  tp_as_mapping
   &repeated_scalar_container::MpMethods,   //  tp_as_mapping
-  0,                                   //  tp_hash
+  PyObject_HashNotImplemented,         //  tp_hash
   0,                                   //  tp_call
   0,                                   //  tp_call
   0,                                   //  tp_str
   0,                                   //  tp_str
   0,                                   //  tp_getattro
   0,                                   //  tp_getattro

+ 1 - 0
python/google/protobuf/pyext/scalar_map_container.cc

@@ -32,6 +32,7 @@
 
 
 #include <google/protobuf/pyext/scalar_map_container.h>
 #include <google/protobuf/pyext/scalar_map_container.h>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/pyext/message.h>
 #include <google/protobuf/pyext/message.h>

+ 11 - 5
python/google/protobuf/pyext/scoped_pyobject_ptr.h

@@ -51,16 +51,22 @@ class ScopedPyObjectPtr {
 
 
   // Reset.  Deletes the current owned object, if any.
   // Reset.  Deletes the current owned object, if any.
   // Then takes ownership of a new object, if given.
   // 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) {
   PyObject* reset(PyObject* p = NULL) {
-    if (p != ptr_) {
-      Py_XDECREF(ptr_);
-      ptr_ = p;
-    }
+    Py_XDECREF(ptr_);
+    ptr_ = p;
     return ptr_;
     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.
   // Releases ownership of the object.
+  // The caller now owns the returned reference.
   PyObject* release() {
   PyObject* release() {
     PyObject* p = ptr_;
     PyObject* p = ptr_;
     ptr_ = NULL;
     ptr_ = NULL;

+ 9 - 87
python/google/protobuf/reflection.py

@@ -49,101 +49,23 @@ __author__ = 'robinson@google.com (Will Robinson)'
 
 
 
 
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import api_implementation
-from google.protobuf import descriptor as descriptor_mod
 from google.protobuf import message
 from google.protobuf import message
 
 
-_FieldDescriptor = descriptor_mod.FieldDescriptor
-
 
 
 if api_implementation.Type() == 'cpp':
 if api_implementation.Type() == 'cpp':
   from google.protobuf.pyext import cpp_message as message_impl
   from google.protobuf.pyext import cpp_message as message_impl
 else:
 else:
   from google.protobuf.internal import python_message as message_impl
   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):
 def ParseMessage(descriptor, byte_str):

+ 1 - 1
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)
     fields.sort(key=lambda x: x[0].index)
   for field, value in fields:
   for field, value in fields:
     if _IsMapEntry(field):
     if _IsMapEntry(field):
-      for key in value:
+      for key in sorted(value):
         # This is slow for maps with submessage entires because it copies the
         # This is slow for maps with submessage entires because it copies the
         # entire tree.  Unfortunately this would take significant refactoring
         # entire tree.  Unfortunately this would take significant refactoring
         # of this file to work around.
         # of this file to work around.

+ 2 - 2
src/google/protobuf/any.cc

@@ -50,7 +50,7 @@ AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
 
 
 void AnyMetadata::PackFrom(const Message& message) {
 void AnyMetadata::PackFrom(const Message& message) {
   type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
   type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(),
-      GetTypeUrl(message.GetDescriptor()));
+                        GetTypeUrl(message.GetDescriptor()));
   message.SerializeToString(value_->MutableNoArena(
   message.SerializeToString(value_->MutableNoArena(
       &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
       &::google::protobuf::internal::GetEmptyStringAlreadyInited()));
 }
 }
@@ -76,7 +76,7 @@ bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
                            type_url.size() - prefix_len);
                            type_url.size() - prefix_len);
     return true;
     return true;
   }
   }
-  return true;
+  return false;
 }
 }
 
 
 
 

+ 1 - 1
src/google/protobuf/any.h

@@ -34,9 +34,9 @@
 #include <string>
 #include <string>
 
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/arenastring.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/message.h>
 #include <google/protobuf/message.h>
+#include <google/protobuf/arenastring.h>
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {

+ 23 - 17
src/google/protobuf/arena.cc

@@ -66,8 +66,12 @@ void Arena::Init() {
     first_block->size = options_.initial_block_size;
     first_block->size = options_.initial_block_size;
     first_block->pos = kHeaderSize;
     first_block->pos = kHeaderSize;
     first_block->next = NULL;
     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;
     owns_first_block_ = false;
   }
   }
 
 
@@ -80,7 +84,7 @@ void Arena::Init() {
 }
 }
 
 
 Arena::~Arena() {
 Arena::~Arena() {
-  uint64 space_allocated = Reset();
+  uint64 space_allocated = ResetInternal();
 
 
   // Call the destruction hook
   // Call the destruction hook
   if (options_.on_arena_destruction != NULL) {
   if (options_.on_arena_destruction != NULL) {
@@ -89,10 +93,14 @@ Arena::~Arena() {
 }
 }
 
 
 uint64 Arena::Reset() {
 uint64 Arena::Reset() {
-  CleanupList();
-  uint64 space_allocated = FreeBlocks();
   // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
   // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
   lifecycle_id_ = lifecycle_id_generator_.GetNext();
+  return ResetInternal();
+}
+
+uint64 Arena::ResetInternal() {
+  CleanupList();
+  uint64 space_allocated = FreeBlocks();
 
 
   // Call the reset hook
   // Call the reset hook
   if (options_.on_arena_reset != NULL) {
   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) {
 void Arena::AddBlock(Block* b) {
   MutexLock l(&blocks_lock_);
   MutexLock l(&blocks_lock_);
+  AddBlockInternal(b);
+}
+
+void Arena::AddBlockInternal(Block* b) {
   b->next = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   b->next = reinterpret_cast<Block*>(google::protobuf::internal::NoBarrier_Load(&blocks_));
   google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
   google::protobuf::internal::Release_Store(&blocks_, reinterpret_cast<google::protobuf::internal::AtomicWord>(b));
   if (b->avail() != 0) {
   if (b->avail() != 0) {
@@ -181,16 +193,6 @@ void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) {
   void* me = &thread_cache();
   void* me = &thread_cache();
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
   if (!b || b->owner != me || b->avail() < n) {
   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 SlowAlloc(n);
   }
   }
   return AllocFromBlock(b, n);
   return AllocFromBlock(b, n);
@@ -267,8 +269,12 @@ uint64 Arena::FreeBlocks() {
     // Make the first block that was passed in through ArenaOptions
     // Make the first block that was passed in through ArenaOptions
     // available for reuse.
     // available for reuse.
     first_block->pos = kHeaderSize;
     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;
   return space_allocated;
 }
 }

+ 115 - 63
src/google/protobuf/arena.h

@@ -31,6 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_ARENA_H__
 #ifndef GOOGLE_PROTOBUF_ARENA_H__
 #define GOOGLE_PROTOBUF_ARENA_H__
 #define GOOGLE_PROTOBUF_ARENA_H__
 
 
+#include <limits>
 #if __cplusplus >= 201103L
 #if __cplusplus >= 201103L
 #include <google/protobuf/stubs/type_traits.h>
 #include <google/protobuf/stubs/type_traits.h>
 #endif
 #endif
@@ -39,7 +40,8 @@
 #include <google/protobuf/stubs/atomic_sequence_num.h>
 #include <google/protobuf/stubs/atomic_sequence_num.h>
 #include <google/protobuf/stubs/atomicops.h>
 #include <google/protobuf/stubs/atomicops.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/platform_macros.h>
+#include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/mutex.h>
 #include <google/protobuf/stubs/type_traits.h>
 #include <google/protobuf/stubs/type_traits.h>
 
 
 namespace google {
 namespace google {
@@ -414,6 +416,9 @@ class LIBPROTOBUF_EXPORT Arena {
   // trivially destructible.
   // trivially destructible.
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
   static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
+    GOOGLE_CHECK_LE(num_elements,
+             std::numeric_limits<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
     if (arena == NULL) {
     if (arena == NULL) {
       return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
       return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
     } else {
     } else {
@@ -425,16 +430,16 @@ class LIBPROTOBUF_EXPORT Arena {
   // of the underlying blocks. The total space used may not include the new
   // of the underlying blocks. The total space used may not include the new
   // blocks that are allocated by this arena from other threads concurrently
   // blocks that are allocated by this arena from other threads concurrently
   // with the call to this method.
   // 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.
   // 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
   // Frees all storage allocated by this arena after calling destructors
   // registered with OwnDestructor() and freeing objects registered with Own().
   // registered with OwnDestructor() and freeing objects registered with Own().
   // Any objects allocated on this arena are unusable after this call. It also
   // 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
   // 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.
   // 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|
   // Adds |object| to a list of heap-allocated objects to be freed with |delete|
   // when the arena is destroyed or reset.
   // 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
   // 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
   // from OwnDestructor() in that any member function may be specified, not only
   // the class destructor.
   // 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);
     AddListNode(object, destruct);
   }
   }
 
 
@@ -469,7 +474,7 @@ class LIBPROTOBUF_EXPORT Arena {
   // latter is a virtual call, while this method is a templated call that
   // latter is a virtual call, while this method is a templated call that
   // resolves at compile-time.
   // resolves at compile-time.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> 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<T*>(0));
     return GetArenaInternal(value, static_cast<T*>(0));
   }
   }
 
 
@@ -507,7 +512,7 @@ class LIBPROTOBUF_EXPORT Arena {
     // aligned at a multiple of 8 bytes.
     // aligned at a multiple of 8 bytes.
     size_t pos;
     size_t pos;
     size_t size;  // total size of the block.
     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
     // data follows
   };
   };
 
 
@@ -555,6 +560,33 @@ class LIBPROTOBUF_EXPORT Arena {
     return google::protobuf::internal::has_trivial_destructor<T>::value;
     return google::protobuf::internal::has_trivial_destructor<T>::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<T>::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<T>::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<typename T>
+  struct is_destructor_skippable {
+    template<typename U>
+    static char DestructorSkippable(
+        const typename U::DestructorSkippable_*);
+    template<typename U>
+    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<bool,
+              sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) ==
+              sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true>
+              type;
+    static const type value;
+  };
+
+
   // CreateMessage<T> requires that T supports arenas, but this private method
   // CreateMessage<T> requires that T supports arenas, but this private method
   // works whether or not T supports arenas. These are not exposed to user code
   // 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
   // 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
   // Just allocate the required size for the given type assuming the
   // type has a trivial constructor.
   // type has a trivial constructor.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> 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<size_t>::max() / sizeof(T))
+        << "Requested size is too large to fit into size_t.";
     return static_cast<T*>(
     return static_cast<T*>(
         AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements));
         AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements));
   }
   }
 
 
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> 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();
     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T();
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
       AddListNode(t, &internal::arena_destruct_object<T>);
@@ -590,8 +624,7 @@ class LIBPROTOBUF_EXPORT Arena {
   }
   }
 
 
   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T, typename Arg> 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);
     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
       AddListNode(t, &internal::arena_destruct_object<T>);
       AddListNode(t, &internal::arena_destruct_object<T>);
@@ -600,7 +633,7 @@ class LIBPROTOBUF_EXPORT Arena {
   }
   }
 
 
   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateInternal(
+  T* CreateInternal(
       bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
       bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2);
     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -610,10 +643,10 @@ class LIBPROTOBUF_EXPORT Arena {
   }
   }
 
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3>
   template <typename T, typename Arg1, typename Arg2, typename Arg3>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3);
         T(arg1, arg2, arg3);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -624,11 +657,11 @@ class LIBPROTOBUF_EXPORT Arena {
 
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4>
             typename Arg4>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3, arg4);
         T(arg1, arg2, arg3, arg4);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -639,12 +672,12 @@ class LIBPROTOBUF_EXPORT Arena {
 
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4, typename Arg5>
             typename Arg4, typename Arg5>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3, arg4, arg5);
         T(arg1, arg2, arg3, arg4, arg5);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -655,13 +688,13 @@ class LIBPROTOBUF_EXPORT Arena {
 
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4, typename Arg5, typename Arg6>
             typename Arg4, typename Arg5, typename Arg6>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3, arg4, arg5, arg6);
         T(arg1, arg2, arg3, arg4, arg5, arg6);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -672,14 +705,14 @@ class LIBPROTOBUF_EXPORT Arena {
 
 
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4, typename Arg5, typename Arg6, typename Arg7>
             typename Arg4, typename Arg5, typename Arg6, typename Arg7>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -691,15 +724,15 @@ class LIBPROTOBUF_EXPORT Arena {
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
   template <typename T, typename Arg1, typename Arg2, typename Arg3,
             typename Arg4, typename Arg5, typename Arg6, typename Arg7,
             typename Arg4, typename Arg5, typename Arg6, typename Arg7,
             typename Arg8>
             typename Arg8>
-  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* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
     if (!skip_explicit_ownership) {
     if (!skip_explicit_ownership) {
@@ -709,21 +742,21 @@ class LIBPROTOBUF_EXPORT Arena {
   }
   }
 
 
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
+  T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
                                      this);
                                      this);
   }
   }
 
 
   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
-                                  const Arg& arg) {
+  T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
+                           const Arg& arg) {
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
                                      this, arg);
                                      this, arg);
   }
   }
 
 
   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template <typename T, typename Arg1, typename Arg2> 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<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
                                      this, arg1, arg2);
                                      this, arg1, arg2);
   }
   }
@@ -734,19 +767,29 @@ class LIBPROTOBUF_EXPORT Arena {
   template <typename T>
   template <typename T>
   static void CreateInArenaStorage(T* ptr, Arena* arena) {
   static void CreateInArenaStorage(T* ptr, Arena* arena) {
     CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
     CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
+    RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>::value);
   }
   }
+
   template <typename T>
   template <typename T>
   static void CreateInArenaStorageInternal(
   static void CreateInArenaStorageInternal(
       T* ptr, Arena* arena, google::protobuf::internal::true_type) {
       T* ptr, Arena* arena, google::protobuf::internal::true_type) {
     new (ptr) T(arena);
     new (ptr) T(arena);
   }
   }
-
   template <typename T>
   template <typename T>
   static void CreateInArenaStorageInternal(
   static void CreateInArenaStorageInternal(
       T* ptr, Arena* arena, google::protobuf::internal::false_type) {
       T* ptr, Arena* arena, google::protobuf::internal::false_type) {
     new (ptr) T;
     new (ptr) T;
   }
   }
 
 
+  template <typename T>
+  static void RegisterDestructorInternal(
+      T* ptr, Arena* arena, google::protobuf::internal::true_type) {}
+  template <typename T>
+  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
   // These implement Own(), which registers an object for deletion (destructor
   // call and operator delete()). The second parameter has type 'true_type' if T
   // 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
   // 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
   // InternalArenaConstructable_ tags can be associated with an arena, and such
   // objects must implement a GetArenaNoVirtual() method.
   // objects must implement a GetArenaNoVirtual() method.
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> 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();
     return value->GetArenaNoVirtual();
   }
   }
 
 
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
-  static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
+  static ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
     return NULL;
     return NULL;
   }
   }
 
 
@@ -785,7 +828,7 @@ class LIBPROTOBUF_EXPORT Arena {
   void* AllocateAligned(const std::type_info* allocated, size_t n);
   void* AllocateAligned(const std::type_info* allocated, size_t n);
 
 
   // Allocate an internal allocation, avoiding optional typed monitoring.
   // 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);
     return AllocateAligned(NULL, n);
   }
   }
 
 
@@ -803,6 +846,7 @@ class LIBPROTOBUF_EXPORT Arena {
   void AddListNode(void* elem, void (*cleanup)(void*));
   void AddListNode(void* elem, void (*cleanup)(void*));
   // Delete or Destruct all objects owned by the arena.
   // Delete or Destruct all objects owned by the arena.
   void CleanupList();
   void CleanupList();
+  uint64 ResetInternal();
 
 
   inline void SetThreadCacheBlock(Block* block) {
   inline void SetThreadCacheBlock(Block* block) {
     thread_cache().last_block_used_ = block;
     thread_cache().last_block_used_ = block;
@@ -829,6 +873,9 @@ class LIBPROTOBUF_EXPORT Arena {
   Mutex blocks_lock_;
   Mutex blocks_lock_;
 
 
   void AddBlock(Block* b);
   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);
   void* SlowAlloc(size_t n);
   Block* FindBlock(void* me);
   Block* FindBlock(void* me);
   Block* NewBlock(void* me, Block* my_last_block, size_t n,
   Block* NewBlock(void* me, Block* my_last_block, size_t n,
@@ -854,6 +901,11 @@ const typename Arena::is_arena_constructable<T>::type
     Arena::is_arena_constructable<T>::value =
     Arena::is_arena_constructable<T>::value =
         typename Arena::is_arena_constructable<T>::type();
         typename Arena::is_arena_constructable<T>::type();
 
 
+template<typename T>
+const typename Arena::is_destructor_skippable<T>::type
+    Arena::is_destructor_skippable<T>::value =
+        typename Arena::is_destructor_skippable<T>::type();
+
 }  // namespace protobuf
 }  // namespace protobuf
 
 
 }  // namespace google
 }  // namespace google

+ 1 - 0
src/google/protobuf/arena_test_util.cc

@@ -28,6 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/arena_test_util.h>
 
 

+ 52 - 3
src/google/protobuf/arena_unittest.cc

@@ -40,7 +40,9 @@
 #include <typeinfo>
 #include <typeinfo>
 #include <vector>
 #include <vector>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
 #include <google/protobuf/unittest.pb.h>
@@ -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) {
 TEST(ArenaTest, AddAllocatedToRepeatedField) {
   // Heap->arena case.
   // Heap->arena case.
   Arena arena1;
   Arena arena1;
@@ -680,6 +680,55 @@ TEST(ArenaTest, AddAllocatedToRepeatedField) {
   }
   }
 }
 }
 
 
+TEST(ArenaTest, AddAllocatedToRepeatedFieldViaReflection) {
+  // Heap->arena case.
+  Arena arena1;
+  TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&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<TestAllTypes::NestedMessage>(&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<TestAllTypes::NestedMessage>(&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) {
 TEST(ArenaTest, ReleaseLastRepeatedField) {
   // Release from arena-allocated repeated field and ensure that returned object
   // Release from arena-allocated repeated field and ensure that returned object
   // is heap-allocated.
   // is heap-allocated.
@@ -1230,7 +1279,7 @@ TEST(ArenaTest, ArenaHooksSanity) {
     EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
     EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
     EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations);
     EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations);
     ::google::protobuf::Arena::Create<uint64>(&arena);
     ::google::protobuf::Arena::Create<uint64>(&arena);
-    if (::google::protobuf::internal::has_trivial_destructor<uint64>::value) {
+    if (google::protobuf::internal::has_trivial_destructor<uint64>::value) {
       EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations);
       EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations);
     } else {
     } else {
       EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations);
       EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations);

+ 5 - 6
src/google/protobuf/arenastring.h

@@ -33,6 +33,7 @@
 
 
 #include <string>
 #include <string>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/fastmem.h>
 #include <google/protobuf/stubs/fastmem.h>
 
 
@@ -145,7 +146,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
   // Swaps internal pointers. Arena-safety semantics: this is guarded by the
   // Swaps internal pointers. Arena-safety semantics: this is guarded by the
   // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
   // logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
   // 'unsafe' if called directly.
   // '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_);
     std::swap(ptr_, other->ptr_);
   }
   }
 
 
@@ -283,9 +284,8 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
  private:
  private:
   ::std::string* ptr_;
   ::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.
     // Assumes ptr_ is not NULL.
     if (initial_value != NULL) {
     if (initial_value != NULL) {
       ptr_ = new ::std::string(*initial_value);
       ptr_ = new ::std::string(*initial_value);
@@ -296,8 +296,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr {
       arena->Own(ptr_);
       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) {
     if (initial_value != NULL) {
       ptr_ = new ::std::string(*initial_value);
       ptr_ = new ::std::string(*initial_value);
     } else {
     } else {

+ 1 - 0
src/google/protobuf/arenastring_unittest.cc

@@ -42,6 +42,7 @@
 #endif
 #endif
 #include <cstdlib>
 #include <cstdlib>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 

+ 1 - 0
src/google/protobuf/compiler/code_generator.cc

@@ -34,6 +34,7 @@
 
 
 #include <google/protobuf/compiler/code_generator.h>
 #include <google/protobuf/compiler/code_generator.h>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 
 

+ 5 - 0
src/google/protobuf/compiler/command_line_interface.cc

@@ -70,6 +70,7 @@
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/map_util.h>
@@ -1657,7 +1658,11 @@ bool CommandLineInterface::WriteDescriptorSet(
                                 &already_seen, file_set.mutable_file());
                                 &already_seen, file_set.mutable_file());
     }
     }
   } else {
   } else {
+    set<const FileDescriptor*> already_seen;
     for (int i = 0; i < parsed_files.size(); i++) {
     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();
       FileDescriptorProto* file_proto = file_set.add_file();
       parsed_files[i]->CopyTo(file_proto);
       parsed_files[i]->CopyTo(file_proto);
       if (source_info_in_descriptor_set_) {
       if (source_info_in_descriptor_set_) {

+ 33 - 0
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());
   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) {
 TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) {
   CreateTempFile("foo.proto",
   CreateTempFile("foo.proto",
     "syntax = \"proto2\";\n"
     "syntax = \"proto2\";\n"

+ 1 - 2
src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc

@@ -133,8 +133,7 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) {
   CppGenerator generator;
   CppGenerator generator;
   MockGeneratorContext context;
   MockGeneratorContext context;
   string error;
   string error;
-  string parameter;
-  parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
+  string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT";
   ASSERT_TRUE(generator.Generate(proto_file, parameter,
   ASSERT_TRUE(generator.Generate(proto_file, parameter,
                                  &context, &error));
                                  &context, &error));
   parameter = "dllexport_decl=LIBPROTOC_EXPORT";
   parameter = "dllexport_decl=LIBPROTOC_EXPORT";

+ 2 - 6
src/google/protobuf/compiler/cpp/cpp_enum.cc

@@ -32,7 +32,6 @@
 //  Based on original Protocol Buffers design by
 //  Based on original Protocol Buffers design by
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 
-#include <set>
 #include <map>
 #include <map>
 
 
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
 #include <google/protobuf/compiler/cpp/cpp_enum.h>
@@ -70,14 +69,11 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
 
 
 EnumGenerator::~EnumGenerator() {}
 EnumGenerator::~EnumGenerator() {}
 
 
-void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) {
+void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) {
   if (!options_.proto_h) {
   if (!options_.proto_h) {
     return;
     return;
   }
   }
-  map<string, string> 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) {
 void EnumGenerator::GenerateDefinition(io::Printer* printer) {

+ 3 - 2
src/google/protobuf/compiler/cpp/cpp_enum.h

@@ -35,6 +35,7 @@
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
 
 
+#include <set>
 #include <string>
 #include <string>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
@@ -60,11 +61,11 @@ class EnumGenerator {
 
 
   // Header stuff.
   // 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
   // generating other .proto.h files. This code should be placed within the
   // enum's package namespace, but NOT within any class, even for nested
   // enum's package namespace, but NOT within any class, even for nested
   // enums.
   // enums.
-  void GenerateForwardDeclaration(io::Printer* printer);
+  void FillForwardDeclaration(set<string>* enum_names);
 
 
   // Generate header code defining the enum.  This code should be placed
   // Generate header code defining the enum.  This code should be placed
   // within the enum's package namespace, but NOT within any class, even for
   // within the enum's package namespace, but NOT within any class, even for

+ 0 - 1
src/google/protobuf/compiler/cpp/cpp_enum_field.cc

@@ -35,7 +35,6 @@
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 
 
 namespace google {
 namespace google {

+ 1 - 0
src/google/protobuf/compiler/cpp/cpp_field.cc

@@ -47,6 +47,7 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/wire_format.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 
 

+ 222 - 32
src/google/protobuf/compiler/cpp/cpp_file.cc

@@ -33,6 +33,7 @@
 //  Sanjay Ghemawat, Jeff Dean, and others.
 //  Sanjay Ghemawat, Jeff Dean, and others.
 
 
 #include <google/protobuf/compiler/cpp/cpp_file.h>
 #include <google/protobuf/compiler/cpp/cpp_file.h>
+#include <map>
 #include <memory>
 #include <memory>
 #ifndef _SHARED_PTR_H
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
@@ -93,22 +94,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
 
 
 FileGenerator::~FileGenerator() {}
 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);
   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(
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
     "// @@protoc_insertion_point(includes)\n");
 
 
 
 
+  GenerateForwardDeclarations(printer);
 
 
   // Open namespace.
   // Open namespace.
   GenerateNamespaceOpeners(printer);
   GenerateNamespaceOpeners(printer);
 
 
   GenerateGlobalStateFunctionDeclarations(printer);
   GenerateGlobalStateFunctionDeclarations(printer);
-  GenerateMessageForwardDeclarations(printer);
 
 
   printer->Print("\n");
   printer->Print("\n");
 
 
@@ -133,6 +148,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
 
 
   GenerateInlineFunctionDefinitions(printer);
   GenerateInlineFunctionDefinitions(printer);
 
 
+  printer->Print(
+    "\n"
+    "// @@protoc_insertion_point(namespace_scope)\n"
+    "\n");
+
   // Close up namespace.
   // Close up namespace.
   GenerateNamespaceClosers(printer);
   GenerateNamespaceClosers(printer);
 
 
@@ -144,19 +164,89 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
     "// @@protoc_insertion_point(global_scope)\n"
     "// @@protoc_insertion_point(global_scope)\n"
     "\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) {
 void FileGenerator::GenerateSource(io::Printer* printer) {
+  string header =
+      StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h");
   printer->Print(
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "// source: $filename$\n"
     "// source: $filename$\n"
     "\n"
     "\n"
-
     // The generated code calls accessors that might be deprecated. We don't
     // The generated code calls accessors that might be deprecated. We don't
     // want the compiler to warn in generated code.
     // want the compiler to warn in generated code.
     "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
     "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
-    "#include \"$basename$.pb.h\"\n"
+    "#include \"$header$\"\n"
     "\n"
     "\n"
     "#include <algorithm>\n"    // for swap()
     "#include <algorithm>\n"    // for swap()
     "\n"
     "\n"
@@ -165,7 +255,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     "#include <google/protobuf/io/coded_stream.h>\n"
     "#include <google/protobuf/io/coded_stream.h>\n"
     "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "#include <google/protobuf/wire_format_lite_inl.h>\n",
     "filename", file_->name(),
     "filename", file_->name(),
-    "basename", StripProto(file_->name()));
+    "header", header);
 
 
   // Unknown fields implementation in lite mode uses StringOutputStream
   // Unknown fields implementation in lite mode uses StringOutputStream
   if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
   if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) {
@@ -181,6 +271,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
       "#include <google/protobuf/wire_format.h>\n");
       "#include <google/protobuf/wire_format.h>\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(
   printer->Print(
     "// @@protoc_insertion_point(includes)\n");
     "// @@protoc_insertion_point(includes)\n");
 
 
@@ -276,6 +378,59 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
     "// @@protoc_insertion_point(global_scope)\n");
     "// @@protoc_insertion_point(global_scope)\n");
 }
 }
 
 
+class FileGenerator::ForwardDeclarations {
+ public:
+  ~ForwardDeclarations() {
+    for (map<string, ForwardDeclarations *>::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<string>& classes() { return classes_; }
+  set<string>& enums() { return enums_; }
+
+  void Print(io::Printer* printer) const {
+    for (set<string>::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<string>::const_iterator it = classes_.begin(),
+                                     end = classes_.end();
+         it != end; ++it) {
+      printer->Print("class $classname$;\n", "classname", it->c_str());
+    }
+    for (map<string, ForwardDeclarations *>::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<string, ForwardDeclarations*> namespaces_;
+  set<string> classes_;
+  set<string> enums_;
+};
+
 void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
 void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
   // AddDescriptors() is a file-level procedure which adds the encoded
   // AddDescriptors() is a file-level procedure which adds the encoded
   // FileDescriptorProto for this .proto file to the global DescriptorPool for
   // FileDescriptorProto for this .proto file to the global DescriptorPool for
@@ -434,12 +589,17 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
     string file_data;
     string file_data;
     file_proto.SerializeToString(&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
     // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535
     // bytes in length". Declare a static array of characters rather than use a
     // bytes in length". Declare a static array of characters rather than use a
     // string literal.
     // string literal.
-    if (file_data.size() > 65535) {
+    if (breakdown_large_file && file_data.size() > 65535) {
       printer->Print(
       printer->Print(
-        "static const char descriptor[] = {\n");
+          "static const char descriptor[] = {\n");
       printer->Indent();
       printer->Indent();
 
 
       // Only write 25 bytes per line.
       // 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 i = 0; i < file_data.size();) {
           for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
           for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) {
             printer->Print(
             printer->Print(
-              "$char$, ",
-              "char", SimpleItoa(file_data[i]));
+                "$char$, ",
+                "char", SimpleItoa(file_data[i]));
           }
           }
           printer->Print(
           printer->Print(
-            "\n");
+              "\n");
       }
       }
 
 
       printer->Outdent();
       printer->Outdent();
       printer->Print(
       printer->Print(
-        "};\n");
+          "};\n");
 
 
       printer->Print(
       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 {
     } else {
-
       printer->Print(
       printer->Print(
         "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
         "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
-  
+
       // Only write 40 bytes per line.
       // Only write 40 bytes per line.
       static const int kBytesPerLine = 40;
       static const int kBytesPerLine = 40;
       for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
       for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
@@ -474,11 +633,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
                        "data",
                        "data",
                        EscapeTrigraphs(
                        EscapeTrigraphs(
                            CEscape(file_data.substr(i, kBytesPerLine))));
                            CEscape(file_data.substr(i, kBytesPerLine))));
-      }
-      printer->Print(
-          ", $size$);\n",
+    }
+    printer->Print(
+        ", $size$);\n",
         "size", SimpleItoa(file_data.size()));
         "size", SimpleItoa(file_data.size()));
-  
     }
     }
 
 
     // Call MessageFactory::InternalRegisterGeneratedFile().
     // 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.
   // Generate top of header.
   printer->Print(
   printer->Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
@@ -564,8 +754,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) {
     "filename_identifier", filename_identifier);
     "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(
   printer->Print(
     "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
     "#endif  // PROTOBUF_$filename_identifier$__INCLUDED\n",
     "filename_identifier", filename_identifier);
     "filename_identifier", filename_identifier);
@@ -696,9 +886,13 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations(
 }
 }
 
 
 void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
 void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) {
-  // Generate forward declarations of classes.
+  set<string> classes;
   for (int i = 0; i < file_->message_type_count(); i++) {
   for (int i = 0; i < file_->message_type_count(); i++) {
-    message_generators_[i]->GenerateMessageForwardDeclaration(printer);
+    message_generators_[i]->FillMessageForwardDeclarations(&classes);
+  }
+  for (set<string>::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.
     // Methods of the dependent base class must always be inline in the header.
     message_generators_[i]->GenerateDependentInlineMethods(printer);
     message_generators_[i]->GenerateDependentInlineMethods(printer);
   }
   }
-
-  printer->Print(
-    "\n"
-    "// @@protoc_insertion_point(namespace_scope)\n");
 }
 }
 
 
 void FileGenerator::GenerateProto2NamespaceEnumSpecializations(
 void FileGenerator::GenerateProto2NamespaceEnumSpecializations(

+ 28 - 4
src/google/protobuf/compiler/cpp/cpp_file.h

@@ -69,10 +69,14 @@ class FileGenerator {
                          const Options& options);
                          const Options& options);
   ~FileGenerator();
   ~FileGenerator();
 
 
-  void GenerateHeader(io::Printer* printer);
+  void GenerateProtoHeader(io::Printer* printer);
+  void GeneratePBHeader(io::Printer* printer);
   void GenerateSource(io::Printer* printer);
   void GenerateSource(io::Printer* printer);
 
 
  private:
  private:
+  // Internal type used by GenerateForwardDeclarations (defined in file.cc).
+  class ForwardDeclarations;
+
   // Generate the BuildDescriptors() procedure, which builds all descriptors
   // Generate the BuildDescriptors() procedure, which builds all descriptors
   // for types defined in the file.
   // for types defined in the file.
   void GenerateBuildDescriptors(io::Printer* printer);
   void GenerateBuildDescriptors(io::Printer* printer);
@@ -80,9 +84,19 @@ class FileGenerator {
   void GenerateNamespaceOpeners(io::Printer* printer);
   void GenerateNamespaceOpeners(io::Printer* printer);
   void GenerateNamespaceClosers(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.
   // 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.
   // Generates #include directives.
   void GenerateLibraryIncludes(io::Printer* printer);
   void GenerateLibraryIncludes(io::Printer* printer);
@@ -92,10 +106,20 @@ class FileGenerator {
   void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
   void GenerateGlobalStateFunctionDeclarations(io::Printer* printer);
 
 
   // Generates types for classes.
   // Generates types for classes.
-  void GenerateMessageForwardDeclarations(io::Printer* printer);
   void GenerateMessageDefinitions(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.
   // Generates enum definitions.
+  void GenerateEnumForwardDeclarations(io::Printer* printer);
+  void FillEnumForwardDeclarations(ForwardDeclarations* decls);
   void GenerateEnumDefinitions(io::Printer* printer);
   void GenerateEnumDefinitions(io::Printer* printer);
 
 
   // Generates generic service definitions.
   // Generates generic service definitions.

+ 10 - 3
src/google/protobuf/compiler/cpp/cpp_generator.cc

@@ -100,16 +100,23 @@ bool CppGenerator::Generate(const FileDescriptor* file,
 
 
 
 
   string basename = StripProto(file->name());
   string basename = StripProto(file->name());
-  basename.append(".pb");
 
 
   FileGenerator file_generator(file, file_options);
   FileGenerator file_generator(file, file_options);
 
 
-  // Generate header.
+  // Generate header(s).
+  if (file_options.proto_h) {
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
+        generator_context->Open(basename + ".proto.h"));
+    io::Printer printer(output.get(), '$');
+    file_generator.GenerateProtoHeader(&printer);
+  }
+
+  basename.append(".pb");
   {
   {
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         generator_context->Open(basename + ".h"));
         generator_context->Open(basename + ".h"));
     io::Printer printer(output.get(), '$');
     io::Printer printer(output.get(), '$');
-    file_generator.GenerateHeader(&printer);
+    file_generator.GeneratePBHeader(&printer);
   }
   }
 
 
   // Generate cc file.
   // Generate cc file.

+ 23 - 1
src/google/protobuf/compiler/cpp/cpp_helpers.cc

@@ -39,6 +39,7 @@
 
 
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/substitute.h>
@@ -68,7 +69,7 @@ const char* const kKeywordList[] = {
   "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
   "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
   "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
   "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
   "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
   "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",
   "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
   "return", "short", "signed", "sizeof", "static", "static_assert",
   "return", "short", "signed", "sizeof", "static", "static_assert",
   "static_cast", "struct", "switch", "template", "this", "thread_local",
   "static_cast", "struct", "switch", "template", "this", "thread_local",
@@ -174,6 +175,14 @@ string SuperClassName(const Descriptor* descriptor) {
       "::google::protobuf::Message" : "::google::protobuf::MessageLite";
       "::google::protobuf::Message" : "::google::protobuf::MessageLite";
 }
 }
 
 
+string DependentBaseDownCast() {
+  return "reinterpret_cast<T*>(this)->";
+}
+
+string DependentBaseConstDownCast() {
+  return "reinterpret_cast<const T*>(this)->";
+}
+
 string FieldName(const FieldDescriptor* field) {
 string FieldName(const FieldDescriptor* field) {
   string result = field->name();
   string result = field->name();
   LowerString(&result);
   LowerString(&result);
@@ -208,6 +217,19 @@ string FieldConstantName(const FieldDescriptor *field) {
 }
 }
 
 
 bool IsFieldDependent(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) {
   if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
     return false;
     return false;
   }
   }

+ 7 - 0
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".
 // This is a class name, like "ProtoName_InternalBase".
 string DependentBaseClassTemplateName(const Descriptor* descriptor);
 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);
 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.
 // 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
 // The name is coerced to lower-case to emulate proto1 behavior.  People
 // should be using lowercase-with-underscores style for proto field names
 // should be using lowercase-with-underscores style for proto field names

+ 6 - 3
src/google/protobuf/compiler/cpp/cpp_map_field.cc

@@ -100,8 +100,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
 
 
 MapFieldGenerator::
 MapFieldGenerator::
 MapFieldGenerator(const FieldDescriptor* descriptor,
 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);
   SetMessageVariables(descriptor, &variables_, options);
 }
 }
 
 
@@ -152,7 +153,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Clear();\n");
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  printer->Print(variables, "$this_message$$name$_.Clear();\n");
 }
 }
 
 
 void MapFieldGenerator::
 void MapFieldGenerator::

+ 1 - 0
src/google/protobuf/compiler/cpp/cpp_map_field.h

@@ -63,6 +63,7 @@ class MapFieldGenerator : public FieldGenerator {
 
 
  private:
  private:
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
   map<string, string> variables_;
   map<string, string> variables_;
 
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);

+ 112 - 75
src/google/protobuf/compiler/cpp/cpp_message.cc

@@ -39,7 +39,6 @@
 #ifndef _SHARED_PTR_H
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #endif
-#include <set>
 #include <utility>
 #include <utility>
 #include <vector>
 #include <vector>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
 #include <google/protobuf/compiler/cpp/cpp_message.h>
@@ -415,31 +414,34 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
       use_dependent_base_ = true;
       use_dependent_base_ = true;
     }
     }
   }
   }
+  if (options.proto_h && descriptor->oneof_decl_count() > 0) {
+    // Always make oneofs dependent.
+    use_dependent_base_ = true;
+  }
 }
 }
 
 
 MessageGenerator::~MessageGenerator() {}
 MessageGenerator::~MessageGenerator() {}
 
 
 void MessageGenerator::
 void MessageGenerator::
-GenerateMessageForwardDeclaration(io::Printer* printer) {
-  printer->Print("class $classname$;\n",
-                 "classname", classname_);
+FillMessageForwardDeclarations(set<string>* class_names) {
+  class_names->insert(classname_);
 
 
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
     // map entry message doesn't need forward declaration. Since map entry
     // map entry message doesn't need forward declaration. Since map entry
     // message cannot be a top level class, we just need to avoid calling
     // message cannot be a top level class, we just need to avoid calling
     // GenerateForwardDeclaration here.
     // GenerateForwardDeclaration here.
     if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
     if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
-    nested_generators_[i]->GenerateMessageForwardDeclaration(printer);
+    nested_generators_[i]->FillMessageForwardDeclarations(class_names);
   }
   }
 }
 }
 
 
 void MessageGenerator::
 void MessageGenerator::
-GenerateEnumForwardDeclaration(io::Printer* printer) {
+FillEnumForwardDeclarations(set<string>* enum_names) {
   for (int i = 0; i < descriptor_->nested_type_count(); i++) {
   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++) {
   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);
     field_generators_.get(field).GenerateDependentAccessorDeclarations(printer);
     printer->Print("\n");
     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::
 void MessageGenerator::
@@ -505,7 +500,9 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
     vars["constant_name"] = FieldConstantName(field);
     vars["constant_name"] = FieldConstantName(field);
 
 
     bool dependent_field = use_dependent_base_ && IsFieldDependent(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
       // If this field is dependent, the dependent base class determines
       // the message type from the derived class (which is a template
       // the message type from the derived class (which is a template
       // parameter). This typedef is for that:
       // parameter). This typedef is for that:
@@ -594,8 +591,8 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) {
       vars["tmpl"] = "template<class T>\n";
       vars["tmpl"] = "template<class T>\n";
       vars["dependent_classname"] =
       vars["dependent_classname"] =
           DependentBaseClassTemplateName(descriptor_) + "<T>";
           DependentBaseClassTemplateName(descriptor_) + "<T>";
-      vars["this_message"] = "reinterpret_cast<T*>(this)->";
-      vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+      vars["this_message"] = DependentBaseDownCast();
+      vars["this_const_message"] = DependentBaseConstDownCast();
       GenerateFieldClear(field, vars, printer);
       GenerateFieldClear(field, vars, printer);
     }
     }
 
 
@@ -721,13 +718,15 @@ GenerateFieldClear(const FieldDescriptor* field,
     printer->Print(vars,
     printer->Print(vars,
       "if ($this_message$has_$name$()) {\n");
       "if ($this_message$has_$name$()) {\n");
     printer->Indent();
     printer->Indent();
-    field_generators_.get(field).GenerateClearingCode(printer);
+    field_generators_.get(field)
+        .GenerateClearingCode(printer);
     printer->Print(vars,
     printer->Print(vars,
       "$this_message$clear_has_$oneof_name$();\n");
       "$this_message$clear_has_$oneof_name$();\n");
     printer->Outdent();
     printer->Outdent();
     printer->Print("}\n");
     printer->Print("}\n");
   } else {
   } else {
-    field_generators_.get(field).GenerateClearingCode(printer);
+    field_generators_.get(field)
+        .GenerateClearingCode(printer);
     if (HasFieldPresence(descriptor_->file())) {
     if (HasFieldPresence(descriptor_->file())) {
       if (!field->is_repeated()) {
       if (!field->is_repeated()) {
         printer->Print(vars,
         printer->Print(vars,
@@ -752,6 +751,18 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
     map<string, string> vars;
     map<string, string> vars;
     SetCommonFieldVariables(field, &vars, options_);
     SetCommonFieldVariables(field, &vars, options_);
     vars["inline"] = is_inline ? "inline " : "";
     vars["inline"] = is_inline ? "inline " : "";
+    if (use_dependent_base_ && IsFieldDependent(field)) {
+      vars["tmpl"] = "template<class T>\n";
+      vars["dependent_classname"] =
+          DependentBaseClassTemplateName(descriptor_) + "<T>";
+      vars["this_message"] = "reinterpret_cast<T*>(this)->";
+      vars["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+    } else {
+      vars["tmpl"] = "";
+      vars["dependent_classname"] = vars["classname"];
+      vars["this_message"] = "";
+      vars["this_const_message"] = "";
+    }
 
 
     // Generate has_$name$() or $name$_size().
     // Generate has_$name$() or $name$_size().
     if (field->is_repeated()) {
     if (field->is_repeated()) {
@@ -775,10 +786,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) {
     }
     }
 
 
     if (!use_dependent_base_ || !IsFieldDependent(field)) {
     if (!use_dependent_base_ || !IsFieldDependent(field)) {
-      vars["tmpl"] = "";
-      vars["dependent_classname"] = vars["classname"];
-      vars["this_message"] = "";
-      vars["this_const_message"] = "";
       GenerateFieldClear(field, vars, printer);
       GenerateFieldClear(field, vars, printer);
     }
     }
 
 
@@ -915,15 +922,32 @@ GenerateClassDefinition(io::Printer* printer) {
         "}\n"
         "}\n"
         "\n");
         "\n");
     } else {
     } 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;
   uses_string_ = false;
+  if (PreserveUnknownFields(descriptor_) &&
+      !UseUnknownFieldSet(descriptor_->file())) {
+    uses_string_ = true;
+  }
   for (int i = 0; i < descriptors.size(); i++) {
   for (int i = 0; i < descriptors.size(); i++) {
     const FieldDescriptor* field = descriptors[i];
     const FieldDescriptor* field = descriptors[i];
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
     if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
@@ -1201,18 +1229,11 @@ GenerateClassDefinition(io::Printer* printer) {
 
 
   // Generate oneof function declarations
   // Generate oneof function declarations
   for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
   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()) &&
   if (HasGeneratedMethods(descriptor_->file()) &&
@@ -1262,7 +1283,7 @@ GenerateClassDefinition(io::Printer* printer) {
       "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n");
       "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n");
   } else {
   } else {
     printer->Print(
     printer->Print(
-      "::std::string _unknown_fields_;\n"
+      "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n"
       "::google::protobuf::Arena* _arena_ptr_;\n"
       "::google::protobuf::Arena* _arena_ptr_;\n"
       "\n");
       "\n");
   }
   }
@@ -1919,6 +1940,13 @@ GenerateSharedConstructorCode(io::Printer* printer) {
       uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "",
       uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "",
       "_cached_size_ = 0;\n").c_str());
       "_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++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     if (!descriptor_->field(i)->containing_oneof()) {
     if (!descriptor_->field(i)->containing_oneof()) {
       field_generators_.get(descriptor_->field(i))
       field_generators_.get(descriptor_->field(i))
@@ -1955,6 +1983,22 @@ GenerateSharedDestructorCode(io::Printer* printer) {
       "}\n"
       "}\n"
       "\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.
   // Write the destructors for each field except oneof members.
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     if (!descriptor_->field(i)->containing_oneof()) {
     if (!descriptor_->field(i)->containing_oneof()) {
@@ -2463,8 +2507,16 @@ GenerateClear(io::Printer* printer) {
         "  mutable_unknown_fields()->Clear();\n"
         "  mutable_unknown_fields()->Clear();\n"
         "}\n");
         "}\n");
     } else {
     } 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();
     oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name();
     string message_class;
     string message_class;
 
 
-    if (use_dependent_base_) {
-      oneof_vars["tmpl"] = "template<class T>\n";
-      oneof_vars["inline"] = "inline ";
-      oneof_vars["dependent_classname"] =
-          DependentBaseClassTemplateName(descriptor_) + "<T>";
-      oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->";
-      message_class = "T::";
-    } else {
-      oneof_vars["tmpl"] = "";
-      oneof_vars["inline"] = "";
-      oneof_vars["dependent_classname"] = classname_;
-      oneof_vars["this_message"] = "";
-    }
-
     printer->Print(oneof_vars,
     printer->Print(oneof_vars,
-        "$tmpl$"
-        "$inline$"
-        "void $dependent_classname$::clear_$oneofname$() {\n");
+        "void $classname$::clear_$oneofname$() {\n");
     printer->Indent();
     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,
     printer->Print(oneof_vars,
-        "switch($this_message$$oneofname$_case()) {\n");
+        "typedef $classname$ T;\n"
+        "switch($oneofname$_case()) {\n");
     printer->Indent();
     printer->Indent();
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
     for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
       const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
       printer->Print(
       printer->Print(
-          "case $message_class$k$field_name$: {\n",
-          "message_class", message_class,
+          "case k$field_name$: {\n",
           "field_name", UnderscoresToCamelCase(field->name(), true));
           "field_name", UnderscoresToCamelCase(field->name(), true));
       printer->Indent();
       printer->Indent();
       // We clear only allocated objects in oneofs
       // We clear only allocated objects in oneofs
@@ -2524,20 +2565,16 @@ GenerateOneofClear(io::Printer* printer) {
           "}\n");
           "}\n");
     }
     }
     printer->Print(
     printer->Print(
-        "case $message_class$$cap_oneof_name$_NOT_SET: {\n"
+        "case $cap_oneof_name$_NOT_SET: {\n"
         "  break;\n"
         "  break;\n"
         "}\n",
         "}\n",
-        "message_class", message_class,
         "cap_oneof_name",
         "cap_oneof_name",
         ToUpper(descriptor_->oneof_decl(i)->name()));
         ToUpper(descriptor_->oneof_decl(i)->name()));
     printer->Outdent();
     printer->Outdent();
     printer->Print(
     printer->Print(
         "}\n"
         "}\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),
         "oneof_index", SimpleItoa(i),
-        "message_class", message_class,
         "cap_oneof_name",
         "cap_oneof_name",
         ToUpper(descriptor_->oneof_decl(i)->name()));
         ToUpper(descriptor_->oneof_decl(i)->name()));
     printer->Outdent();
     printer->Outdent();
@@ -2612,7 +2649,7 @@ GenerateSwap(io::Printer* printer) {
         printer->Print(
         printer->Print(
           "_internal_metadata_.Swap(&other->_internal_metadata_);\n");
           "_internal_metadata_.Swap(&other->_internal_metadata_);\n");
       } else {
       } else {
-        printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n");
+        printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
       }
       }
     } else {
     } else {
       // Still swap internal_metadata as it may contain more than just
       // Still swap internal_metadata as it may contain more than just

+ 5 - 4
src/google/protobuf/compiler/cpp/cpp_message.h

@@ -39,8 +39,8 @@
 #ifndef _SHARED_PTR_H
 #ifndef _SHARED_PTR_H
 #include <google/protobuf/stubs/shared_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #endif
+#include <set>
 #include <string>
 #include <string>
-#include <vector>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_field.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 #include <google/protobuf/compiler/cpp/cpp_options.h>
 
 
@@ -66,9 +66,10 @@ class MessageGenerator {
 
 
   // Header stuff.
   // 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<string>* class_names);
+  void FillEnumForwardDeclarations(set<string>* enum_names);
 
 
   // Generate definitions of all nested enums (must come before class
   // Generate definitions of all nested enums (must come before class
   // definitions because those classes use the enums definitions).
   // definitions because those classes use the enums definitions).

+ 482 - 134
src/google/protobuf/compiler/cpp/cpp_message_field.cc

@@ -63,6 +63,14 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
       SafeFunctionName(descriptor->containing_type(),
       SafeFunctionName(descriptor->containing_type(),
                        descriptor, "release_");
                        descriptor, "release_");
   (*variables)["full_name"] = descriptor->full_name();
   (*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
 }  // namespace
@@ -84,8 +92,22 @@ GeneratePrivateMembers(io::Printer* printer) const {
   printer->Print(variables_, "$type$* $name$_;\n");
   printer->Print(variables_, "$type$* $name$_;\n");
 }
 }
 
 
+void MessageFieldGenerator::
+GenerateGetterDeclaration(io::Printer* printer) const {
+  printer->Print(variables_,
+      "const $type$& $name$() const$deprecation$;\n");
+}
+
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateDependentAccessorDeclarations(io::Printer* printer) const {
 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::
 void MessageFieldGenerator::
@@ -103,11 +125,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
        "$type$* _slow_$release_name$()$deprecation$;\n"
        "$type$* _slow_$release_name$()$deprecation$;\n"
        "public:\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_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables_,
     printer->Print(variables_,
       "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
       "$type$* unsafe_arena_release_$name$()$deprecation$;\n"
@@ -123,12 +147,12 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
       "void $classname$::_slow_mutable_$name$() {\n");
       "void $classname$::_slow_mutable_$name$() {\n");
       if (SupportsArenas(descriptor_->message_type())) {
       if (SupportsArenas(descriptor_->message_type())) {
         printer->Print(variables_,
         printer->Print(variables_,
-        "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
-      "        GetArenaNoVirtual());\n");
+          "  $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
       } else {
       } else {
         printer->Print(variables_,
         printer->Print(variables_,
-         "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
-         "     GetArenaNoVirtual());\n");
+          "  $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+          "      GetArenaNoVirtual());\n");
       }
       }
     printer->Print(variables_,
     printer->Print(variables_,
       "}\n"
       "}\n"
@@ -151,7 +175,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
       // NOTE: the same logic is mirrored in weak_message_field.cc. Any
       // NOTE: the same logic is mirrored in weak_message_field.cc. Any
       // arena-related semantics changes should be made in both places.
       // arena-related semantics changes should be made in both places.
-        printer->Print(variables_,
+      printer->Print(variables_,
           "void $classname$::_slow_set_allocated_$name$(\n"
           "void $classname$::_slow_set_allocated_$name$(\n"
           "    ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
           "    ::google::protobuf::Arena* message_arena, $type$** $name$) {\n"
           "    if (message_arena != NULL && \n"
           "    if (message_arena != NULL && \n"
@@ -189,15 +213,139 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions(
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
 GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
+  if (!dependent_field_) {
+    return;
+  }
+
+  map<string, string> 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()) + "<T>";
+  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 <class T>\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 <class T>\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 <class T>\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 <class T>\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 <class T>\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 <class T>\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::
 void MessageFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
                                   bool is_inline) const {
   map<string, string> variables(variables_);
   map<string, string> variables(variables_);
-  variables["inline"] = is_inline ? "inline" : "";
+  variables["inline"] = is_inline ? "inline " : "";
   printer->Print(variables,
   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");
     "  // @@protoc_insertion_point(field_get:$full_name$)\n");
 
 
   PrintHandlingOptionalStaticInitializers(
   PrintHandlingOptionalStaticInitializers(
@@ -206,19 +354,25 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
     "  return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n",
     // Without.
     // Without.
     "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
     "  return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
+  printer->Print(variables, "}\n");
+
+  if (dependent_field_) {
+    return;
+  }
 
 
   if (SupportsArenas(descriptor_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables,
     printer->Print(variables,
-      "}\n"
-      "$inline$ $type$* $classname$::mutable_$name$() {\n"
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  if ($name$_ == NULL) {\n"
       "  if ($name$_ == NULL) {\n"
-      "    _slow_mutable_$name$();"
+      "    _slow_mutable_$name$();\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "  return $name$_;\n"
       "}\n"
       "}\n"
-      "$inline$ $type$* $classname$::$release_name$() {\n"
+      "$inline$"
+      "$type$* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "  if (GetArenaNoVirtual() != NULL) {\n"
       "    return _slow_$release_name$();\n"
       "    return _slow_$release_name$();\n"
@@ -228,7 +382,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
       "    return temp;\n"
       "    return temp;\n"
       "  }\n"
       "  }\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"
       "  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n"
       "  if (message_arena == NULL) {\n"
       "  if (message_arena == NULL) {\n"
       "    delete $name$_;\n"
       "    delete $name$_;\n"
@@ -260,8 +415,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
       "}\n");
       "}\n");
   } else {
   } else {
     printer->Print(variables,
     printer->Print(variables,
-      "}\n"
-      "$inline$ $type$* $classname$::mutable_$name$() {\n"
+      "$inline$"
+      "$type$* $classname$::mutable_$name$() {\n"
       "  $set_hasbit$\n"
       "  $set_hasbit$\n"
       "  if ($name$_ == NULL) {\n"
       "  if ($name$_ == NULL) {\n"
       "    $name$_ = new $type$;\n"
       "    $name$_ = new $type$;\n"
@@ -269,13 +424,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  return $name$_;\n"
       "  return $name$_;\n"
       "}\n"
       "}\n"
-      "$inline$ $type$* $classname$::$release_name$() {\n"
+      "$inline$"
+      "$type$* $classname$::$release_name$() {\n"
       "  $clear_hasbit$\n"
       "  $clear_hasbit$\n"
       "  $type$* temp = $name$_;\n"
       "  $type$* temp = $name$_;\n"
       "  $name$_ = NULL;\n"
       "  $name$_ = NULL;\n"
       "  return temp;\n"
       "  return temp;\n"
       "}\n"
       "}\n"
-      "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n"
+      "$inline$"
+      "void $classname$::set_allocated_$name$($type$* $name$) {\n"
       "  delete $name$_;\n");
       "  delete $name$_;\n");
 
 
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
@@ -301,15 +458,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
 
 
 void MessageFieldGenerator::
 void MessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
   if (!HasFieldPresence(descriptor_->file())) {
   if (!HasFieldPresence(descriptor_->file())) {
     // If we don't have has-bits, message presence is indicated only by ptr !=
     // If we don't have has-bits, message presence is indicated only by ptr !=
     // NULL. Thus on clear, we need to delete the object.
     // 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 {
   } 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::
 MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
 MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
                            const Options& options)
                            const Options& options)
-  : MessageFieldGenerator(descriptor, options) {
+  : MessageFieldGenerator(descriptor, options),
+    dependent_base_(options.proto_h) {
   SetCommonOneofFieldVariables(descriptor, &variables_);
   SetCommonOneofFieldVariables(descriptor, &variables_);
 }
 }
 
 
 MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
 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::
 void MessageOneofFieldGenerator::
 GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const {
 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<string, string> variables(variables_);
+  variables["inline"] = "inline ";
+  variables["dependent_classname"] =
+      DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>";
+  variables["this_message"] = "reinterpret_cast<T*>(this)->";
+  // Const message access is needed for the dependent getter.
+  variables["this_const_message"] = "reinterpret_cast<const T*>(this)->";
+  variables["tmpl"] = "template <class T>\n";
+  variables["field_member"] = variables["this_message"] +
+                              variables["oneof_prefix"] + variables["name"] +
+                              "_";
+  InternalGenerateInlineAccessorDefinitions(variables, printer);
 }
 }
 
 
 void MessageOneofFieldGenerator::
 void MessageOneofFieldGenerator::
 GenerateInlineAccessorDefinitions(io::Printer* printer,
 GenerateInlineAccessorDefinitions(io::Printer* printer,
                                   bool is_inline) const {
                                   bool is_inline) const {
+  if (dependent_base_) {
+    return;
+  }
   map<string, string> variables(variables_);
   map<string, string> 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<string, string> variables(variables_);
+  variables["field_member"] =
+      variables["oneof_prefix"] + variables["name"] + "_";
+
+  //printer->Print(variables,
+}
+
+void MessageOneofFieldGenerator::
+InternalGenerateInlineAccessorDefinitions(const map<string, string>& 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_)) {
   if (SupportsArenas(descriptor_)) {
     printer->Print(variables,
     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())) {
     if (SupportsArenas(descriptor_->message_type())) {
       printer->Print(variables,
       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 {
     } else {
       printer->Print(variables,
       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,
     printer->Print(variables,
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $oneof_prefix$$name$_;\n"
+      "  return $field_member$;\n"
       "}\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
       // N.B.: safe to use the underlying field pointer here because we are sure
       // that it is non-NULL (because has_$name$() returned true).
       // 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"
       "      return temp;\n"
       "    } else {\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"
       "      return temp;\n"
       "    }\n"
       "    }\n"
       "  } else {\n"
       "  } else {\n"
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\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 ($name$) {\n");
 
 
     if (SupportsArenas(descriptor_->message_type())) {
     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()
         // 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
         // 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.
         // 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"
         "        ::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"
         "               ::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"
         "      new_$name$->CopyFrom(*$name$);\n"
         "      $name$ = new_$name$;\n"
         "      $name$ = new_$name$;\n"
         "    }\n");
         "    }\n");
     } else {
     } else {
       printer->Print(variables,
       printer->Print(variables,
-        "    if (GetArenaNoVirtual() != NULL) {\n"
-        "      GetArenaNoVirtual()->Own($name$);\n"
+        "    if ($this_message$GetArenaNoVirtual() != NULL) {\n"
+        "      $this_message$GetArenaNoVirtual()->Own($name$);\n"
         "    }\n");
         "    }\n");
     }
     }
 
 
     printer->Print(variables,
     printer->Print(variables,
-      "    set_has_$name$();\n"
-      "    $oneof_prefix$$name$_ = $name$;\n"
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = $name$;\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\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
       // 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
       // oneof. We can directly use the pointer we're given to set the new
       // value.
       // value.
@@ -489,44 +730,47 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
       "}\n");
       "}\n");
   } else {
   } else {
     printer->Print(variables,
     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"
       "  }\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
       "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-      "  return $oneof_prefix$$name$_;\n"
+      "  return $field_member$;\n"
       "}\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"
       "    return temp;\n"
       "  } else {\n"
       "  } else {\n"
       "    return NULL;\n"
       "    return NULL;\n"
       "  }\n"
       "  }\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 ($name$) {\n");
     if (SupportsArenas(descriptor_->message_type())) {
     if (SupportsArenas(descriptor_->message_type())) {
       printer->Print(variables,
       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"
         "      new_$name$->CopyFrom(*$name$);\n"
         "      $name$ = new_$name$;\n"
         "      $name$ = new_$name$;\n"
         "    }\n");
         "    }\n");
     }
     }
     printer->Print(variables,
     printer->Print(variables,
-      "    set_has_$name$();\n"
-      "    $oneof_prefix$$name$_ = $name$;\n"
+      "    $this_message$set_has_$name$();\n"
+      "    $field_member$ = $name$;\n"
       "  }\n"
       "  }\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "  // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
       "}\n");
       "}\n");
@@ -535,14 +779,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
 
 
 void MessageOneofFieldGenerator::
 void MessageOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
   if (SupportsArenas(descriptor_)) {
   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");
       "}\n");
   } else {
   } 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::
 RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
 RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
                               const Options& options)
                               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);
   SetMessageVariables(descriptor, &variables_, options);
 }
 }
 
 
@@ -575,60 +823,160 @@ GeneratePrivateMembers(io::Printer* printer) const {
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::
-GenerateDependentAccessorDeclarations(io::Printer* printer) const {
-}
-
-void RepeatedMessageFieldGenerator::
-GenerateAccessorDeclarations(io::Printer* printer) const {
+InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const {
   printer->Print(variables_,
   printer->Print(variables_,
-    "const $type$& $name$(int index) const$deprecation$;\n"
     "$type$* mutable_$name$(int index)$deprecation$;\n"
     "$type$* mutable_$name$(int index)$deprecation$;\n"
     "$type$* add_$name$()$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_,
   printer->Print(variables_,
-    "const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
-    "    $name$() const$deprecation$;\n"
     "::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "::google::protobuf::RepeatedPtrField< $type$ >*\n"
     "    mutable_$name$()$deprecation$;\n");
     "    mutable_$name$()$deprecation$;\n");
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 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::
 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<string, string> variables(variables_);
   map<string, string> 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()) + "<T>";
+  variables["this_message"] = DependentBaseDownCast();
+  variables["this_const_message"] = DependentBaseConstDownCast();
+
+  if (dependent_getter_) {
+    printer->Print(variables,
+      "template <class T>\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,
   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 <class T>\n"
+    "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n"
+    // TODO(dlj): move insertion points
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable:$full_name$)\n"
-    "  return $name$_.Mutable(index);\n"
+    "  return $this_message$$name$_.Mutable(index);\n"
     "}\n"
     "}\n"
-    "$inline$ $type$* $classname$::add_$name$() {\n"
+    "template <class T>\n"
+    "inline $type$* $dependent_classname$::add_$name$() {\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
     "  // @@protoc_insertion_point(field_add:$full_name$)\n"
-    "  return $name$_.Add();\n"
+    "  return $this_message$$name$_.Add();\n"
     "}\n");
     "}\n");
+
+
+  if (dependent_getter_) {
+    printer->Print(variables,
+      "template <class T>\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,
   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 <class T>\n"
+    "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
+    "$dependent_classname$::mutable_$name$() {\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
     "  // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
-    "  return &$name$_;\n"
+    "  return &$this_message$$name$_;\n"
     "}\n");
     "}\n");
 }
 }
 
 
+void RepeatedMessageFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer,
+                                  bool is_inline) const {
+  map<string, string> 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::
 void RepeatedMessageFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.Clear();\n");
+  map<string, string> variables(variables_);
+  variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
+  printer->Print(variables, "$this_message$$name$_.Clear();\n");
 }
 }
 
 
 void RepeatedMessageFieldGenerator::
 void RepeatedMessageFieldGenerator::

+ 19 - 1
src/google/protobuf/compiler/cpp/cpp_message_field.h

@@ -68,6 +68,11 @@ class MessageFieldGenerator : public FieldGenerator {
   void GenerateByteSize(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
 
  protected:
  protected:
+  void GenerateArenaManipulationCode(const map<string, string>& variables,
+                                     io::Printer* printer) const;
+
+  virtual void GenerateGetterDeclaration(io::Printer* printer) const;
+
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
   const bool dependent_field_;
   const bool dependent_field_;
   map<string, string> variables_;
   map<string, string> variables_;
@@ -83,15 +88,23 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator {
   ~MessageOneofFieldGenerator();
   ~MessageOneofFieldGenerator();
 
 
   // implements FieldGenerator ---------------------------------------
   // implements FieldGenerator ---------------------------------------
+  void GenerateDependentAccessorDeclarations(io::Printer* printer) const;
   void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateInlineAccessorDefinitions(io::Printer* printer,
   void GenerateInlineAccessorDefinitions(io::Printer* printer,
                                          bool is_inline) const;
                                          bool is_inline) const;
-  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {}
+  void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateClearingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateSwappingCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
   void GenerateConstructorCode(io::Printer* printer) const;
 
 
+ protected:
+  void GenerateGetterDeclaration(io::Printer* printer) const;
+
  private:
  private:
+  void InternalGenerateInlineAccessorDefinitions(
+      const map<string, string>& variables, io::Printer* printer) const;
+
+  const bool dependent_base_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator);
 };
 };
 
 
@@ -118,7 +131,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
   void GenerateByteSize(io::Printer* printer) const;
   void GenerateByteSize(io::Printer* printer) const;
 
 
  private:
  private:
+  void InternalGenerateTypeDependentAccessorDeclarations(
+      io::Printer* printer) const;
+
   const FieldDescriptor* descriptor_;
   const FieldDescriptor* descriptor_;
+  const bool dependent_field_;
+  const bool dependent_getter_;
   map<string, string> variables_;
   map<string, string> variables_;
 
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);

+ 24 - 7
src/google/protobuf/compiler/cpp/cpp_string_field.cc

@@ -421,7 +421,8 @@ GenerateByteSize(io::Printer* printer) const {
 StringOneofFieldGenerator::
 StringOneofFieldGenerator::
 StringOneofFieldGenerator(const FieldDescriptor* descriptor,
 StringOneofFieldGenerator(const FieldDescriptor* descriptor,
                           const Options& options)
                           const Options& options)
-  : StringFieldGenerator(descriptor, options) {
+    : StringFieldGenerator(descriptor, options),
+      dependent_field_(options.proto_h) {
   SetCommonOneofFieldVariables(descriptor, &variables_);
   SetCommonOneofFieldVariables(descriptor, &variables_);
 }
 }
 
 
@@ -604,13 +605,29 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
 
 
 void StringOneofFieldGenerator::
 void StringOneofFieldGenerator::
 GenerateClearingCode(io::Printer* printer) const {
 GenerateClearingCode(io::Printer* printer) const {
+  map<string, string> 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_)) {
   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 {
   } 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::
 RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
 RepeatedStringFieldGenerator(const FieldDescriptor* descriptor,
                              const Options& options)
                              const Options& options)
-  : descriptor_(descriptor) {
+    : descriptor_(descriptor) {
   SetStringVariables(descriptor, &variables_, options);
   SetStringVariables(descriptor, &variables_, options);
 }
 }
 
 

+ 1 - 0
src/google/protobuf/compiler/cpp/cpp_string_field.h

@@ -93,6 +93,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
   void GenerateMergeFromCodedStream(io::Printer* printer) const;
 
 
  private:
  private:
+  const bool dependent_field_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
 };
 };
 
 

+ 2 - 0
src/google/protobuf/compiler/cpp/cpp_unittest.cc

@@ -67,7 +67,9 @@
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/dynamic_message.h>
 
 
+#include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/stubs/substitute.h>
 #include <google/protobuf/testing/googletest.h>
 #include <google/protobuf/testing/googletest.h>

+ 1 - 0
src/google/protobuf/compiler/importer_unittest.cc

@@ -44,6 +44,7 @@
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
 
 #include <google/protobuf/stubs/map_util.h>
 #include <google/protobuf/stubs/map_util.h>
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/strutil.h>

+ 2 - 2
src/google/protobuf/compiler/java/java_enum.cc

@@ -181,8 +181,8 @@ void EnumGenerator::Generate(io::Printer* printer) {
     "    internalGetValueMap() {\n"
     "    internalGetValueMap() {\n"
     "  return internalValueMap;\n"
     "  return internalValueMap;\n"
     "}\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"
     "      new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n"
     "        public $classname$ findValueByNumber(int number) {\n"
     "        public $classname$ findValueByNumber(int number) {\n"
     "          return $classname$.valueOf(number);\n"
     "          return $classname$.valueOf(number);\n"

+ 1 - 0
src/google/protobuf/compiler/java/java_enum_field.cc

@@ -35,6 +35,7 @@
 #include <map>
 #include <map>
 #include <string>
 #include <string>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>

+ 1 - 0
src/google/protobuf/compiler/java/java_enum_field_lite.cc

@@ -35,6 +35,7 @@
 #include <map>
 #include <map>
 #include <string>
 #include <string>
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>
 #include <google/protobuf/compiler/java/java_doc_comment.h>

+ 226 - 0
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 <map>
+#include <string>
+
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/compiler/java/java_enum_lite.h>
+#include <google/protobuf/compiler/java/java_doc_comment.h>
+#include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_name_resolver.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+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<string, string> 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<string, string> 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<string, string> 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

+ 99 - 0
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 <string>
+#include <vector>
+#include <google/protobuf/descriptor.h>
+
+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<const EnumValueDescriptor*> canonical_values_;
+
+  struct Alias {
+    const EnumValueDescriptor* value;
+    const EnumValueDescriptor* canonical_value;
+  };
+  vector<Alias> 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__

+ 1 - 0
src/google/protobuf/compiler/java/java_field.cc

@@ -39,6 +39,7 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 #endif
 
 
+#include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_context.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>
 #include <google/protobuf/compiler/java/java_enum_field.h>

+ 1 - 0
src/google/protobuf/compiler/java/java_field.h

@@ -44,6 +44,7 @@
 
 
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.h>
+#include <google/protobuf/stubs/logging.h>
 
 
 namespace google {
 namespace google {
 namespace protobuf {
 namespace protobuf {

+ 4 - 0
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;
   return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
 }
 }
 
 
+inline bool IsAnyMessage(const Descriptor* descriptor) {
+  return descriptor->full_name() == "google.protobuf.Any";
+}
+
 }  // namespace java
 }  // namespace java
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf

+ 24 - 0
src/google/protobuf/compiler/java/java_map_field.cc

@@ -314,6 +314,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
         "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
         "          $name$ValueConverter);\n"
         "          $name$ValueConverter);\n"
         "}\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())) {
     if (SupportUnknownEnumValue(descriptor_->file())) {
       WriteFieldDocComment(printer, descriptor_);
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
       printer->Print(
@@ -331,6 +339,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
           "getMutable$capitalized_name$Value() {\n"
           "getMutable$capitalized_name$Value() {\n"
           "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
           "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
           "}\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 {
   } else {
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
@@ -346,6 +362,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "getMutable$capitalized_name$() {\n"
         "getMutable$capitalized_name$() {\n"
         "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
         "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
         "}\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");
   }
   }
 }
 }
 
 

+ 24 - 0
src/google/protobuf/compiler/java/java_map_field_lite.cc

@@ -303,6 +303,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "  copyOnWrite();\n"
         "  copyOnWrite();\n"
         "  return instance.getMutable$capitalized_name$();\n"
         "  return instance.getMutable$capitalized_name$();\n"
         "}\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())) {
     if (SupportUnknownEnumValue(descriptor_->file())) {
       WriteFieldDocComment(printer, descriptor_);
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
       printer->Print(
@@ -321,6 +329,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
           "  copyOnWrite();\n"
           "  copyOnWrite();\n"
           "  return instance.getMutable$capitalized_name$Value();\n"
           "  return instance.getMutable$capitalized_name$Value();\n"
           "}\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 {
   } else {
     WriteFieldDocComment(printer, descriptor_);
     WriteFieldDocComment(printer, descriptor_);
@@ -337,6 +353,14 @@ GenerateBuilderMembers(io::Printer* printer) const {
         "  copyOnWrite();\n"
         "  copyOnWrite();\n"
         "  return instance.getMutable$capitalized_name$();\n"
         "  return instance.getMutable$capitalized_name$();\n"
         "}\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");
   }
   }
 }
 }
 
 

+ 115 - 17
src/google/protobuf/compiler/java/java_message.cc

@@ -255,6 +255,18 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
       field_generators_.get(descriptor_->field(i))
       field_generators_.get(descriptor_->field(i))
                        .GenerateInterfaceMembers(printer);
                        .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->Outdent();
 
 
   printer->Print("}\n");
   printer->Print("}\n");
@@ -292,8 +304,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
       "    com.google.protobuf.GeneratedMessage implements\n"
       "    com.google.protobuf.GeneratedMessage implements\n"
       "    $extra_interfaces$\n"
       "    $extra_interfaces$\n"
       "    $classname$OrBuilder {\n");
       "    $classname$OrBuilder {\n");
-
-    builder_type = "com.google.protobuf.GeneratedMessage.Builder";
+    builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>";
   }
   }
   printer->Indent();
   printer->Indent();
   // Using builder_type, instead of Builder, prevents the Builder class from
   // Using builder_type, instead of Builder, prevents the Builder class from
@@ -435,6 +446,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
       "\n");
       "\n");
   }
   }
 
 
+  if (IsAnyMessage(descriptor_)) {
+    GenerateAnyMethods(printer);
+  }
+
   // Fields
   // Fields
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     printer->Print("public static final int $constant_name$ = $number$;\n",
     printer->Print("public static final int $constant_name$ = $number$;\n",
@@ -578,9 +593,8 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
   printer->Print(
   printer->Print(
     "}\n"
     "}\n"
     "\n"
     "\n"
-    "private int memoizedSerializedSize = -1;\n"
     "public int getSerializedSize() {\n"
     "public int getSerializedSize() {\n"
-    "  int size = memoizedSerializedSize;\n"
+    "  int size = memoizedSize;\n"
     "  if (size != -1) return size;\n"
     "  if (size != -1) return size;\n"
     "\n"
     "\n"
     "  size = 0;\n");
     "  size = 0;\n");
@@ -612,7 +626,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
 
 
   printer->Outdent();
   printer->Outdent();
   printer->Print(
   printer->Print(
-    "  memoizedSerializedSize = size;\n"
+    "  memoizedSize = size;\n"
     "  return size;\n"
     "  return size;\n"
     "}\n"
     "}\n"
     "\n");
     "\n");
@@ -948,22 +962,58 @@ GenerateEqualsAndHashCode(io::Printer* printer) {
   printer->Print("boolean result = true;\n");
   printer->Print("boolean result = true;\n");
   for (int i = 0; i < descriptor_->field_count(); i++) {
   for (int i = 0; i < descriptor_->field_count(); i++) {
     const FieldDescriptor* field = descriptor_->field(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(
       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();
       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->Outdent();
-      printer->Print(
-        "}\n");
     }
     }
+    printer->Print(
+      "case 0:\n"
+      "default:\n");
+    printer->Outdent();
+    printer->Print("}\n");
   }
   }
+
   if (PreserveUnknownFields(descriptor_)) {
   if (PreserveUnknownFields(descriptor_)) {
     // Always consider unknown fields for equality. This will sometimes return
     // Always consider unknown fields for equality. This will sometimes return
     // false for non-canonical ordering when running in LITE_RUNTIME but it's
     // 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) {
 void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
   printer->Print(
   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",
       "    new com.google.protobuf.AbstractParser<$classname$>() {\n",
       "classname", descriptor_->name());
       "classname", descriptor_->name());
   printer->Indent();
   printer->Indent();
@@ -1250,6 +1300,10 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) {
       "\n");
       "\n");
 
 
   printer->Print(
   printer->Print(
+      "public static com.google.protobuf.Parser<$classname$> parser() {\n"
+      "  return PARSER;\n"
+      "}\n"
+      "\n"
       "@java.lang.Override\n"
       "@java.lang.Override\n"
       "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
       "public com.google.protobuf.Parser<$classname$> getParserForType() {\n"
       "  return PARSER;\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 <T extends com.google.protobuf.Message> Any pack(\n"
+    "    T message) {\n"
+    "  return Any.newBuilder()\n"
+    "      .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n"
+    "      .setValue(message.toByteString())\n"
+    "      .build();\n"
+    "}\n"
+    "\n"
+    "public <T extends com.google.protobuf.Message> boolean is(\n"
+    "    java.lang.Class<T> 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 extends com.google.protobuf.Message> T unpack(\n"
+    "    java.lang.Class<T> 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 java
 }  // namespace compiler
 }  // namespace compiler
 }  // namespace protobuf
 }  // namespace protobuf

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini