Merge tag 'refs/tags/sync-piper' into sync-stage

# Conflicts:
#	conformance/failure_list_js.txt
#	src/google/protobuf/generated_message_reflection.h
pull/7925/head
Joshua Haberman 4 years ago
commit aefc1e7670
  1. 1
      cmake/extract_includes.bat.in
  2. 1
      cmake/libprotobuf-lite.cmake
  3. 1
      cmake/libprotobuf.cmake
  4. 1
      conformance/failure_list_js.txt
  5. 79
      conformance/text_format_conformance_suite.cc
  6. 20
      conformance/text_format_failure_list_cpp.txt
  7. 15
      conformance/text_format_failure_list_java.txt
  8. 29
      conformance/text_format_failure_list_python.txt
  9. 28
      conformance/text_format_failure_list_python_cpp.txt
  10. 7
      java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
  11. 14
      java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
  12. 14
      java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
  13. 14
      java/core/src/main/java/com/google/protobuf/FloatArrayList.java
  14. 14
      java/core/src/main/java/com/google/protobuf/IntArrayList.java
  15. 1
      java/core/src/main/java/com/google/protobuf/Internal.java
  16. 14
      java/core/src/main/java/com/google/protobuf/LongArrayList.java
  17. 2
      java/core/src/main/java/com/google/protobuf/MessageSchema.java
  18. 7
      java/core/src/main/java/com/google/protobuf/Protobuf.java
  19. 14
      java/core/src/main/java/com/google/protobuf/RopeByteString.java
  20. 14
      java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java
  21. 5
      java/lite/src/test/java/com/google/protobuf/Proto2MessageLiteInfoFactory.java
  22. 1
      js/binary/constants.js
  23. 1
      js/binary/decoder.js
  24. 1
      js/binary/reader.js
  25. 1
      js/binary/utils.js
  26. 1
      js/binary/writer.js
  27. 5
      js/map.js
  28. 1
      js/message.js
  29. 3
      python/google/protobuf/internal/containers.py
  30. 5
      python/google/protobuf/internal/message_test.py
  31. 5
      python/google/protobuf/pyext/map_container.cc
  32. 3
      src/Makefile.am
  33. 5
      src/google/protobuf/any.cc
  34. 8
      src/google/protobuf/any.pb.cc
  35. 27
      src/google/protobuf/any.pb.h
  36. 4
      src/google/protobuf/any_lite.cc
  37. 28
      src/google/protobuf/api.pb.cc
  38. 92
      src/google/protobuf/api.pb.h
  39. 240
      src/google/protobuf/arena.cc
  40. 122
      src/google/protobuf/arena.h
  41. 162
      src/google/protobuf/arena_impl.h
  42. 201
      src/google/protobuf/arena_unittest.cc
  43. 254
      src/google/protobuf/arenastring.cc
  44. 478
      src/google/protobuf/arenastring.h
  45. 116
      src/google/protobuf/arenastring_unittest.cc
  46. 26
      src/google/protobuf/compiler/command_line_interface.cc
  47. 3
      src/google/protobuf/compiler/command_line_interface.h
  48. 35
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  49. 5
      src/google/protobuf/compiler/cpp/cpp_field.h
  50. 2
      src/google/protobuf/compiler/cpp/cpp_file.cc
  51. 22
      src/google/protobuf/compiler/cpp/cpp_helpers.cc
  52. 10
      src/google/protobuf/compiler/cpp/cpp_helpers.h
  53. 17
      src/google/protobuf/compiler/cpp/cpp_message.cc
  54. 207
      src/google/protobuf/compiler/cpp/cpp_string_field.cc
  55. 10
      src/google/protobuf/compiler/cpp/cpp_string_field.h
  56. 4
      src/google/protobuf/compiler/java/java_enum_field.cc
  57. 4
      src/google/protobuf/compiler/java/java_enum_field_lite.cc
  58. 1
      src/google/protobuf/compiler/java/java_message.cc
  59. 4
      src/google/protobuf/compiler/java/java_primitive_field.cc
  60. 4
      src/google/protobuf/compiler/java/java_primitive_field_lite.cc
  61. 4
      src/google/protobuf/compiler/java/java_string_field.cc
  62. 4
      src/google/protobuf/compiler/java/java_string_field_lite.cc
  63. 8
      src/google/protobuf/compiler/mock_code_generator.cc
  64. 12
      src/google/protobuf/compiler/plugin.pb.cc
  65. 79
      src/google/protobuf/compiler/plugin.pb.h
  66. 3
      src/google/protobuf/descriptor.cc
  67. 66
      src/google/protobuf/descriptor.pb.cc
  68. 430
      src/google/protobuf/descriptor.pb.h
  69. 1
      src/google/protobuf/descriptor_database.cc
  70. 3
      src/google/protobuf/descriptor_database.h
  71. 1
      src/google/protobuf/duration.pb.h
  72. 29
      src/google/protobuf/dynamic_message.cc
  73. 1
      src/google/protobuf/empty.pb.h
  74. 1
      src/google/protobuf/field_mask.pb.h
  75. 85
      src/google/protobuf/generated_message_reflection.cc
  76. 37
      src/google/protobuf/generated_message_reflection.h
  77. 7
      src/google/protobuf/generated_message_table_driven.h
  78. 86
      src/google/protobuf/generated_message_table_driven_lite.h
  79. 36
      src/google/protobuf/generated_message_util.cc
  80. 260
      src/google/protobuf/inlined_string_field.h
  81. 19
      src/google/protobuf/io/zero_copy_stream_impl.cc
  82. 14
      src/google/protobuf/io/zero_copy_stream_impl.h
  83. 31
      src/google/protobuf/io/zero_copy_stream_impl_lite.cc
  84. 2
      src/google/protobuf/io/zero_copy_stream_impl_lite.h
  85. 81
      src/google/protobuf/lite_unittest.cc
  86. 34
      src/google/protobuf/map.h
  87. 61
      src/google/protobuf/map_test.cc
  88. 4
      src/google/protobuf/map_type_handler.h
  89. 6
      src/google/protobuf/message.cc
  90. 2
      src/google/protobuf/message.h
  91. 6
      src/google/protobuf/message_lite.cc
  92. 7
      src/google/protobuf/message_lite.h
  93. 48
      src/google/protobuf/parse_context.cc
  94. 114
      src/google/protobuf/parse_context.h
  95. 11
      src/google/protobuf/port_def.inc
  96. 1
      src/google/protobuf/port_undef.inc
  97. 1
      src/google/protobuf/reflection_ops.cc
  98. 4
      src/google/protobuf/source_context.pb.cc
  99. 14
      src/google/protobuf/source_context.pb.h
  100. 2
      src/google/protobuf/struct.pb.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -53,7 +53,6 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_tab
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\generated_message_util.h" include\google\protobuf\generated_message_util.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\has_bits.h" include\google\protobuf\has_bits.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\implicit_weak_message.h" include\google\protobuf\implicit_weak_message.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\inlined_string_field.h" include\google\protobuf\inlined_string_field.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\coded_stream.h" include\google\protobuf\io\coded_stream.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\gzip_stream.h" include\google\protobuf\io\gzip_stream.h
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\io\io_win32.h" include\google\protobuf\io\io_win32.h

@ -1,6 +1,7 @@
set(libprotobuf_lite_files
${protobuf_source_dir}/src/google/protobuf/any_lite.cc
${protobuf_source_dir}/src/google/protobuf/arena.cc
${protobuf_source_dir}/src/google/protobuf/arenastring.cc
${protobuf_source_dir}/src/google/protobuf/extension_set.cc
${protobuf_source_dir}/src/google/protobuf/generated_enum_util.cc
${protobuf_source_dir}/src/google/protobuf/generated_message_table_driven_lite.cc

@ -2,6 +2,7 @@ set(libprotobuf_files
${protobuf_source_dir}/src/google/protobuf/any.cc
${protobuf_source_dir}/src/google/protobuf/any.pb.cc
${protobuf_source_dir}/src/google/protobuf/api.pb.cc
${protobuf_source_dir}/src/google/protobuf/arenastring.cc
${protobuf_source_dir}/src/google/protobuf/compiler/importer.cc
${protobuf_source_dir}/src/google/protobuf/compiler/parser.cc
${protobuf_source_dir}/src/google/protobuf/descriptor.cc

@ -258,6 +258,85 @@ void TextFormatConformanceTestSuite::RunSuiteImpl() {
RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
"optional_float: 18446744073709551616");
// String literals x {Strings, Bytes}
for (const auto& field_type :
std::vector<const std::string>{"String", "Bytes"}) {
const std::string field_name =
field_type == "String" ? "optional_string" : "optional_bytes";
RunValidTextFormatTest(
StrCat("StringLiteralConcat", field_type), REQUIRED,
StrCat(field_name, ": 'first' \"second\"\n'third'"));
RunValidTextFormatTest(
StrCat("StringLiteralBasicEscapes", field_type), REQUIRED,
StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'"));
RunValidTextFormatTest(
StrCat("StringLiteralOctalEscapes", field_type), REQUIRED,
StrCat(field_name, ": '\\341\\210\\264'"));
RunValidTextFormatTest(StrCat("StringLiteralHexEscapes", field_type),
REQUIRED,
StrCat(field_name, ": '\\xe1\\x88\\xb4'"));
RunValidTextFormatTest(
StrCat("StringLiteralShortUnicodeEscape", field_type),
RECOMMENDED, StrCat(field_name, ": '\\u1234'"));
RunValidTextFormatTest(
StrCat("StringLiteralLongUnicodeEscapes", field_type),
RECOMMENDED, StrCat(field_name, ": '\\U00001234\\U00010437'"));
// String literals don't include line feeds.
ExpectParseFailure(StrCat("StringLiteralIncludesLF", field_type),
REQUIRED,
StrCat(field_name, ": 'first line\nsecond line'"));
// Unicode escapes don't include code points that lie beyond the planes
// (> 0x10ffff).
ExpectParseFailure(
StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type),
REQUIRED, StrCat(field_name, ": '\\U00110000'"));
// Unicode escapes don't include surrogates.
ExpectParseFailure(
StrCat("StringLiteralShortUnicodeEscapeSurrogatePair",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\ud801\\udc37'"));
ExpectParseFailure(
StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\ud800'"));
ExpectParseFailure(
StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\udc00'"));
ExpectParseFailure(
StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\U0000d800'"));
ExpectParseFailure(
StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\U0000dc00'"));
ExpectParseFailure(
StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", field_type),
RECOMMENDED, StrCat(field_name, ": '\\U0000d801\\U00000dc37'"));
ExpectParseFailure(
StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\U0000d801\\udc37'"));
ExpectParseFailure(
StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong",
field_type),
RECOMMENDED, StrCat(field_name, ": '\\ud801\\U0000dc37'"));
// The following method depend on the type of field, as strings have extra
// validation.
const auto test_method =
field_type == "String"
? &TextFormatConformanceTestSuite::ExpectParseFailure
: &TextFormatConformanceTestSuite::RunValidTextFormatTest;
// String fields reject invalid UTF-8 byte sequences; bytes fields don't.
(this->*test_method)(StrCat(field_type, "FieldBadUTF8Octal"),
REQUIRED, StrCat(field_name, ": '\\300'"));
(this->*test_method)(StrCat(field_type, "FieldBadUTF8Hex"), REQUIRED,
StrCat(field_name, ": '\\xc0'"));
}
// Group fields
RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
"Data { group_int32: 1 }");

@ -0,0 +1,20 @@
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongString
Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeBytes
Required.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeTooLargeString

@ -4,3 +4,18 @@ Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Proto3.TextFormatInput.AnyField.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.TextFormatOutput
Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput

@ -3,3 +3,32 @@
# TODO: These should be fixed.
Required.Proto3.TextFormatInput.FloatFieldMaxValue.ProtobufOutput
Required.Proto3.TextFormatInput.FloatFieldMaxValue.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongString
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput

@ -0,0 +1,28 @@
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralLongUnicodeEscapesString.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeBytes.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.ProtobufOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeString.TextFormatOutput
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateFirstOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogatePairString
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyBytes
Recommended.Proto3.TextFormatInput.StringLiteralShortUnicodeEscapeSurrogateSecondOnlyString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairLongShortString
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongBytes
Recommended.Proto3.TextFormatInput.StringLiteralUnicodeEscapeSurrogatePairShortLongString
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesBytes.TextFormatOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.ProtobufOutput
Required.Proto3.TextFormatInput.StringLiteralBasicEscapesString.TextFormatOutput

@ -142,7 +142,12 @@ abstract class AbstractProtobufList<E> extends AbstractList<E> implements Protob
@Override
public boolean remove(Object o) {
ensureIsMutable();
return super.remove(o);
int index = indexOf(o);
if (index == -1) {
return false;
}
remove(index);
return true;
}
@Override

@ -267,20 +267,6 @@ final class BooleanArrayList extends AbstractProtobufList<Boolean>
return true;
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
}
}
return false;
}
@Override
public Boolean remove(int index) {
ensureIsMutable();

@ -267,20 +267,6 @@ final class DoubleArrayList extends AbstractProtobufList<Double>
return true;
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
}
}
return false;
}
@Override
public Double remove(int index) {
ensureIsMutable();

@ -266,20 +266,6 @@ final class FloatArrayList extends AbstractProtobufList<Float>
return true;
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
}
}
return false;
}
@Override
public Float remove(int index) {
ensureIsMutable();

@ -266,20 +266,6 @@ final class IntArrayList extends AbstractProtobufList<Integer>
return true;
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
}
}
return false;
}
@Override
public Integer remove(int index) {
ensureIsMutable();

@ -30,7 +30,6 @@
package com.google.protobuf;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

@ -266,20 +266,6 @@ final class LongArrayList extends AbstractProtobufList<Long>
return true;
}
@Override
public boolean remove(Object o) {
ensureIsMutable();
for (int i = 0; i < size; i++) {
if (o.equals(array[i])) {
System.arraycopy(array, i + 1, array, i, size - i - 1);
size--;
modCount++;
return true;
}
}
return false;
}
@Override
public Long remove(int index) {
ensureIsMutable();

@ -2572,7 +2572,7 @@ final class MessageSchema<T> implements Schema<T> {
int presenceMaskAndOffset = 0;
int presenceMask = 0;
if (!proto3 && fieldType <= 17) {
if (fieldType <= 17) {
presenceMaskAndOffset = buffer[pos + 2];
final int presenceFieldOffset = presenceMaskAndOffset & OFFSET_MASK;
if (presenceFieldOffset != currentPresenceFieldOffset) {

@ -76,11 +76,8 @@ final class Protobuf {
schemaFor(message).makeImmutable(message);
}
/**
* Checks if all required fields are set. TODO(xiaofeng): Make this package private when the tests
* are moved to protobuf package.
*/
public <T> boolean isInitialized(T message) {
/** Checks if all required fields are set. */
<T> boolean isInitialized(T message) {
return schemaFor(message).isInitialized(message);
}

@ -845,7 +845,10 @@ final class RopeByteString extends ByteString {
throw new IndexOutOfBoundsException();
}
int bytesRead = readSkipInternal(b, offset, length);
if (bytesRead == 0) {
if (bytesRead == 0 && (length > 0 || availableInternal() == 0)) {
// Modeling ByteArrayInputStream.read(byte[], int, int) behavior noted above:
// It's ok to read 0 bytes on purpose (length == 0) from a stream that isn't at EOF.
// It's not ok to try to read bytes (even 0 bytes) from a stream that is at EOF.
return -1;
} else {
return bytesRead;
@ -905,8 +908,7 @@ final class RopeByteString extends ByteString {
@Override
public int available() throws IOException {
int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
return RopeByteString.this.size() - bytesRead;
return availableInternal();
}
@Override
@ -955,5 +957,11 @@ final class RopeByteString extends ByteString {
}
}
}
/** Computes the number of bytes still available to read. */
private int availableInternal() {
int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
return RopeByteString.this.size() - bytesRead;
}
}
}

@ -514,6 +514,20 @@ public class LiteralByteStringTest extends TestCase {
assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
}
public void testNewInput_readZeroBytes() throws IOException {
InputStream input = stringUnderTest.newInput();
assertEquals(
classUnderTest + " InputStream.read() returns 0 when told to read 0 bytes and not at EOF",
0,
input.read(new byte[0]));
input.skip(input.available());
assertEquals(
classUnderTest + " InputStream.read() returns -1 when told to read 0 bytes at EOF",
-1,
input.read(new byte[0]));
}
public void testNewInput_skip() throws IOException {
InputStream input = stringUnderTest.newInput();
int stringSize = stringUnderTest.size();

@ -174,8 +174,9 @@ public final class Proto2MessageLiteInfoFactory implements MessageInfoFactory {
"fieldRequiredSint6487_",
"fieldRequiredGroup88_",
};
// To update this after a proto change, run protoc on proto2_message_lite.proto and copy over
// the content of the generated buildMessageInfo() method here.
// To update this after a proto change, run blaze build on proto2_message_lite.proto and copy
// over the String info from the proto2_message_lite_proto-lite-src.jar file in the
// blaze-genfiles directory.
java.lang.String info =
"\u0001U\u0001\u0002\u0001XU\u0000 \u0015\u0001\u1000\u0000\u0002\u1001\u0001\u0003"
+ "\u1002\u0002\u0004\u1003\u0003\u0005\u1004\u0004\u0006\u1005\u0005\u0007\u1006\u0006\b\u1007\u0007"

@ -31,6 +31,7 @@
/**
* @fileoverview This file contains constants and typedefs used by
* jspb.BinaryReader and BinaryWriter.
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
*
* @author aappleby@google.com (Austin Appleby)
*/

@ -40,6 +40,7 @@
* intact, you _must_ read them using one of the Hash64 methods, which return
* an 8-character string.
*
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
* @author aappleby@google.com (Austin Appleby)
*/

@ -41,6 +41,7 @@
* using the typed jspb code generator, but if you bypass that you'll need
* to keep things in sync by hand.
*
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
* @author aappleby@google.com (Austin Appleby)
*/

@ -32,6 +32,7 @@
* @fileoverview This file contains helper code used by jspb.BinaryReader
* and BinaryWriter.
*
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
* @author aappleby@google.com (Austin Appleby)
*/

@ -52,6 +52,7 @@
* Major caveat 3 - This class uses typed arrays and must not be used on older
* browsers that do not support them.
*
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
* @author aappleby@google.com (Austin Appleby)
*/

@ -1,3 +1,4 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
@ -28,6 +29,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
*/
goog.provide('jspb.Map');
goog.require('goog.asserts');

@ -31,6 +31,7 @@
/**
* @fileoverview Definition of jspb.Message.
*
* @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
* @author mwr@google.com (Mark Rawling)
*/

@ -629,7 +629,8 @@ class MessageMap(MutableMapping):
return repr(self._values)
def MergeFrom(self, other):
for key in other:
# pylint: disable=protected-access
for key in other._values:
# According to documentation: "When parsing from the wire or when merging,
# if there are duplicate map keys the last key seen is used".
if key in self:

@ -2107,6 +2107,11 @@ class Proto3Test(unittest.TestCase):
self.assertEqual(msg.map_int32_foreign_message[222].d, 20)
self.assertNotEqual(msg.map_int32_foreign_message[222].c, 123)
# Merge a dict to map field is not accepted
with self.assertRaises(AttributeError):
m1.map_int32_all_types.MergeFrom(
{1: unittest_proto3_arena_pb2.TestAllTypes()})
def testMergeFromBadType(self):
msg = map_unittest_pb2.TestMap()
with self.assertRaisesRegexp(

@ -339,6 +339,11 @@ PyObject* GetEntryClass(PyObject* _self) {
PyObject* MapReflectionFriend::MergeFrom(PyObject* _self, PyObject* arg) {
MapContainer* self = GetMap(_self);
if (!PyObject_TypeCheck(arg, ScalarMapContainer_Type) &&
!PyObject_TypeCheck(arg, MessageMapContainer_Type)) {
PyErr_SetString(PyExc_AttributeError, "Not a map field");
return nullptr;
}
MapContainer* other_map = GetMap(arg);
Message* message = self->GetMutableMessage();
const Message* other_message = other_map->parent->message;

@ -68,7 +68,6 @@ nobase_include_HEADERS = \
google/protobuf/stubs/bytestream.h \
google/protobuf/stubs/casts.h \
google/protobuf/stubs/common.h \
google/protobuf/stubs/fastmem.h \
google/protobuf/stubs/hash.h \
google/protobuf/stubs/logging.h \
google/protobuf/stubs/macros.h \
@ -104,7 +103,6 @@ nobase_include_HEADERS = \
google/protobuf/generated_message_util.h \
google/protobuf/has_bits.h \
google/protobuf/implicit_weak_message.h \
google/protobuf/inlined_string_field.h \
google/protobuf/io/io_win32.h \
google/protobuf/map_entry.h \
google/protobuf/map_entry_lite.h \
@ -202,6 +200,7 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/stubs/time.h \
google/protobuf/any_lite.cc \
google/protobuf/arena.cc \
google/protobuf/arenastring.cc \
google/protobuf/extension_set.cc \
google/protobuf/generated_enum_util.cc \
google/protobuf/generated_message_util.cc \

@ -51,9 +51,8 @@ void AnyMetadata::PackFrom(const Message& message,
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyString(),
GetTypeUrl(message.GetDescriptor()->full_name(), type_url_prefix),
nullptr);
message.SerializeToString(value_->Mutable(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(),
nullptr));
message.SerializeToString(
value_->Mutable(ArenaStringPtr::EmptyDefault{}, nullptr));
}
bool AnyMetadata::UnpackTo(Message* message) const {

@ -112,12 +112,12 @@ Any::Any(const Any& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_type_url().empty()) {
type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_type_url(),
type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_type_url(),
GetArena());
}
value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_value().empty()) {
value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_value(),
value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_value(),
GetArena());
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.Any)
@ -162,8 +162,8 @@ void Any::Clear() {
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
value_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
type_url_.ClearToEmpty();
value_.ClearToEmpty();
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
}

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>
@ -272,7 +271,7 @@ class PROTOBUF_EXPORT Any PROTOBUF_FINAL :
// string type_url = 1;
inline void Any::clear_type_url() {
type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
type_url_.ClearToEmpty();
}
inline const std::string& Any::type_url() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.type_url)
@ -291,31 +290,30 @@ inline const std::string& Any::_internal_type_url() const {
}
inline void Any::_internal_set_type_url(const std::string& value) {
type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Any::set_type_url(std::string&& value) {
type_url_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.type_url)
}
inline void Any::set_type_url(const char* value) {
GOOGLE_DCHECK(value != nullptr);
type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.type_url)
}
inline void Any::set_type_url(const char* value,
size_t size) {
type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.type_url)
}
inline std::string* Any::_internal_mutable_type_url() {
return type_url_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return type_url_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Any::release_type_url() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.type_url)
@ -334,7 +332,7 @@ inline void Any::set_allocated_type_url(std::string* type_url) {
// bytes value = 2;
inline void Any::clear_value() {
value_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
value_.ClearToEmpty();
}
inline const std::string& Any::value() const {
// @@protoc_insertion_point(field_get:google.protobuf.Any.value)
@ -353,31 +351,30 @@ inline const std::string& Any::_internal_value() const {
}
inline void Any::_internal_set_value(const std::string& value) {
value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Any::set_value(std::string&& value) {
value_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Any.value)
}
inline void Any::set_value(const char* value) {
GOOGLE_DCHECK(value != nullptr);
value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Any.value)
}
inline void Any::set_value(const void* value,
size_t size) {
value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Any.value)
}
inline std::string* Any::_internal_mutable_value() {
return value_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return value_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Any::release_value() {
// @@protoc_insertion_point(field_release:google.protobuf.Any.value)

@ -61,8 +61,8 @@ void AnyMetadata::InternalPackFrom(const MessageLite& message,
StringPiece type_name) {
type_url_->Set(&::google::protobuf::internal::GetEmptyString(),
GetTypeUrl(type_name, type_url_prefix), nullptr);
message.SerializeToString(value_->Mutable(
&::google::protobuf::internal::GetEmptyStringAlreadyInited(), nullptr));
message.SerializeToString(
value_->Mutable(ArenaStringPtr::EmptyDefault{}, nullptr));
}
bool AnyMetadata::InternalUnpackTo(StringPiece type_name,

@ -204,12 +204,12 @@ Api::Api(const Api& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_name().empty()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
version_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_version().empty()) {
version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_version(),
version_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_version(),
GetArena());
}
if (from._internal_has_source_context()) {
@ -267,8 +267,8 @@ void Api::Clear() {
methods_.Clear();
options_.Clear();
mixins_.Clear();
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
version_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
version_.ClearToEmpty();
if (GetArena() == nullptr && source_context_ != nullptr) {
delete source_context_;
}
@ -613,17 +613,17 @@ Method::Method(const Method& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_name().empty()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
request_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_request_type_url().empty()) {
request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_request_type_url(),
request_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_request_type_url(),
GetArena());
}
response_type_url_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_response_type_url().empty()) {
response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_response_type_url(),
response_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_response_type_url(),
GetArena());
}
::memcpy(&request_streaming_, &from.request_streaming_,
@ -677,9 +677,9 @@ void Method::Clear() {
(void) cached_has_bits;
options_.Clear();
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
request_type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
response_type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
request_type_url_.ClearToEmpty();
response_type_url_.ClearToEmpty();
::memset(&request_streaming_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&syntax_) -
reinterpret_cast<char*>(&request_streaming_)) + sizeof(syntax_));
@ -1006,12 +1006,12 @@ Mixin::Mixin(const Mixin& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_name().empty()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
root_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_root().empty()) {
root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_root(),
root_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_root(),
GetArena());
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin)
@ -1056,8 +1056,8 @@ void Mixin::Clear() {
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
root_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
root_.ClearToEmpty();
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
}

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>
@ -732,7 +731,7 @@ class PROTOBUF_EXPORT Mixin PROTOBUF_FINAL :
// string name = 1;
inline void Api::clear_name() {
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
}
inline const std::string& Api::name() const {
// @@protoc_insertion_point(field_get:google.protobuf.Api.name)
@ -751,31 +750,30 @@ inline const std::string& Api::_internal_name() const {
}
inline void Api::_internal_set_name(const std::string& value) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Api::set_name(std::string&& value) {
name_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Api.name)
}
inline void Api::set_name(const char* value) {
GOOGLE_DCHECK(value != nullptr);
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Api.name)
}
inline void Api::set_name(const char* value,
size_t size) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.name)
}
inline std::string* Api::_internal_mutable_name() {
return name_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Api::release_name() {
// @@protoc_insertion_point(field_release:google.protobuf.Api.name)
@ -869,7 +867,7 @@ Api::options() const {
// string version = 4;
inline void Api::clear_version() {
version_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
version_.ClearToEmpty();
}
inline const std::string& Api::version() const {
// @@protoc_insertion_point(field_get:google.protobuf.Api.version)
@ -888,31 +886,30 @@ inline const std::string& Api::_internal_version() const {
}
inline void Api::_internal_set_version(const std::string& value) {
version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
version_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Api::set_version(std::string&& value) {
version_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Api.version)
}
inline void Api::set_version(const char* value) {
GOOGLE_DCHECK(value != nullptr);
version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
version_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Api.version)
}
inline void Api::set_version(const char* value,
size_t size) {
version_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
version_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Api.version)
}
inline std::string* Api::_internal_mutable_version() {
return version_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return version_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Api::release_version() {
// @@protoc_insertion_point(field_release:google.protobuf.Api.version)
@ -1071,7 +1068,7 @@ inline void Api::set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value) {
// string name = 1;
inline void Method::clear_name() {
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
}
inline const std::string& Method::name() const {
// @@protoc_insertion_point(field_get:google.protobuf.Method.name)
@ -1090,31 +1087,30 @@ inline const std::string& Method::_internal_name() const {
}
inline void Method::_internal_set_name(const std::string& value) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Method::set_name(std::string&& value) {
name_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Method.name)
}
inline void Method::set_name(const char* value) {
GOOGLE_DCHECK(value != nullptr);
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Method.name)
}
inline void Method::set_name(const char* value,
size_t size) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.name)
}
inline std::string* Method::_internal_mutable_name() {
return name_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Method::release_name() {
// @@protoc_insertion_point(field_release:google.protobuf.Method.name)
@ -1133,7 +1129,7 @@ inline void Method::set_allocated_name(std::string* name) {
// string request_type_url = 2;
inline void Method::clear_request_type_url() {
request_type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
request_type_url_.ClearToEmpty();
}
inline const std::string& Method::request_type_url() const {
// @@protoc_insertion_point(field_get:google.protobuf.Method.request_type_url)
@ -1152,31 +1148,30 @@ inline const std::string& Method::_internal_request_type_url() const {
}
inline void Method::_internal_set_request_type_url(const std::string& value) {
request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
request_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Method::set_request_type_url(std::string&& value) {
request_type_url_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Method.request_type_url)
}
inline void Method::set_request_type_url(const char* value) {
GOOGLE_DCHECK(value != nullptr);
request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
request_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Method.request_type_url)
}
inline void Method::set_request_type_url(const char* value,
size_t size) {
request_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
request_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.request_type_url)
}
inline std::string* Method::_internal_mutable_request_type_url() {
return request_type_url_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return request_type_url_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Method::release_request_type_url() {
// @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url)
@ -1215,7 +1210,7 @@ inline void Method::set_request_streaming(bool value) {
// string response_type_url = 4;
inline void Method::clear_response_type_url() {
response_type_url_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
response_type_url_.ClearToEmpty();
}
inline const std::string& Method::response_type_url() const {
// @@protoc_insertion_point(field_get:google.protobuf.Method.response_type_url)
@ -1234,31 +1229,30 @@ inline const std::string& Method::_internal_response_type_url() const {
}
inline void Method::_internal_set_response_type_url(const std::string& value) {
response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
response_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Method::set_response_type_url(std::string&& value) {
response_type_url_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Method.response_type_url)
}
inline void Method::set_response_type_url(const char* value) {
GOOGLE_DCHECK(value != nullptr);
response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
response_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Method.response_type_url)
}
inline void Method::set_response_type_url(const char* value,
size_t size) {
response_type_url_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
response_type_url_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Method.response_type_url)
}
inline std::string* Method::_internal_mutable_response_type_url() {
return response_type_url_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return response_type_url_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Method::release_response_type_url() {
// @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url)
@ -1357,7 +1351,7 @@ inline void Method::set_syntax(PROTOBUF_NAMESPACE_ID::Syntax value) {
// string name = 1;
inline void Mixin::clear_name() {
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
}
inline const std::string& Mixin::name() const {
// @@protoc_insertion_point(field_get:google.protobuf.Mixin.name)
@ -1376,31 +1370,30 @@ inline const std::string& Mixin::_internal_name() const {
}
inline void Mixin::_internal_set_name(const std::string& value) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Mixin::set_name(std::string&& value) {
name_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Mixin.name)
}
inline void Mixin::set_name(const char* value) {
GOOGLE_DCHECK(value != nullptr);
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.name)
}
inline void Mixin::set_name(const char* value,
size_t size) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name)
}
inline std::string* Mixin::_internal_mutable_name() {
return name_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Mixin::release_name() {
// @@protoc_insertion_point(field_release:google.protobuf.Mixin.name)
@ -1419,7 +1412,7 @@ inline void Mixin::set_allocated_name(std::string* name) {
// string root = 2;
inline void Mixin::clear_root() {
root_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
root_.ClearToEmpty();
}
inline const std::string& Mixin::root() const {
// @@protoc_insertion_point(field_get:google.protobuf.Mixin.root)
@ -1438,31 +1431,30 @@ inline const std::string& Mixin::_internal_root() const {
}
inline void Mixin::_internal_set_root(const std::string& value) {
root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
root_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Mixin::set_root(std::string&& value) {
root_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.Mixin.root)
}
inline void Mixin::set_root(const char* value) {
GOOGLE_DCHECK(value != nullptr);
root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
root_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.root)
}
inline void Mixin::set_root(const char* value,
size_t size) {
root_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
root_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root)
}
inline std::string* Mixin::_internal_mutable_root() {
return root_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return root_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Mixin::release_root() {
// @@protoc_insertion_point(field_release:google.protobuf.Mixin.root)

@ -49,6 +49,10 @@ namespace google {
namespace protobuf {
namespace internal {
const size_t ArenaImpl::kBlockHeaderSize;
const size_t ArenaImpl::kSerialArenaSize;
const size_t ArenaImpl::kOptionsSize;
std::atomic<LifecycleId> ArenaImpl::lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
@ -67,43 +71,143 @@ PROTOBUF_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1,
NULL};
#endif
void ArenaImpl::Init() {
lifecycle_id_ =
lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed);
void ArenaFree(void* object, size_t size) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(object, size);
#else
(void)size;
::operator delete(object);
#endif
}
ArenaImpl::ArenaImpl(const ArenaOptions& options) {
ArenaMetricsCollector* collector = nullptr;
bool record_allocs = false;
if (options.make_metrics_collector != nullptr) {
collector = (*options.make_metrics_collector)();
record_allocs = (collector && collector->RecordAllocs());
}
// Get memory where we can store non-default options if needed.
// Use supplied initial_block if it is large enough.
size_t min_block_size = kOptionsSize + kBlockHeaderSize + kSerialArenaSize;
char* mem = options.initial_block;
size_t mem_size = options.initial_block_size;
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0);
if (mem == nullptr || mem_size < min_block_size) {
// Supplied initial block is not big enough.
mem_size = std::max(min_block_size, options.start_block_size);
mem = reinterpret_cast<char*>((*options.block_alloc)(mem_size));
}
// Create the special block.
const bool special = true;
const bool user_owned = (mem == options.initial_block);
auto block = new (mem) Block(mem_size, nullptr, special, user_owned);
// Options occupy the beginning of the initial block.
options_ = new (block->Pointer(block->pos())) Options;
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(options_, kOptionsSize);
#endif // ADDRESS_SANITIZER
options_->start_block_size = options.start_block_size;
options_->max_block_size = options.max_block_size;
options_->block_alloc = options.block_alloc;
options_->block_dealloc = options.block_dealloc;
options_->metrics_collector = collector;
block->set_pos(block->pos() + kOptionsSize);
Init(record_allocs);
SetInitialBlock(block);
}
void ArenaImpl::Init(bool record_allocs) {
// We store "record_allocs" in the low bit of lifecycle_id_.
auto id = lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed);
lifecycle_id_ = (id << 1) | (record_allocs ? 1 : 0);
hint_.store(nullptr, std::memory_order_relaxed);
threads_.store(nullptr, std::memory_order_relaxed);
space_allocated_.store(0, std::memory_order_relaxed);
}
if (initial_block_) {
// Thread which calls Init() owns the first block. This allows the
// single-threaded case to allocate on the first block without having to
// perform atomic operations.
new (initial_block_) Block(options_.initial_block_size, NULL);
SerialArena* serial =
SerialArena::New(initial_block_, &thread_cache(), this);
serial->set_next(NULL);
threads_.store(serial, std::memory_order_relaxed);
space_allocated_.store(options_.initial_block_size,
std::memory_order_relaxed);
CacheSerialArena(serial);
} else {
space_allocated_.store(0, std::memory_order_relaxed);
}
void ArenaImpl::SetInitialBlock(Block* block) {
// Calling thread owns the first block. This allows the single-threaded case
// to allocate on the first block without having to perform atomic operations.
SerialArena* serial = SerialArena::New(block, &thread_cache(), this);
serial->set_next(NULL);
threads_.store(serial, std::memory_order_relaxed);
space_allocated_.store(block->size(), std::memory_order_relaxed);
CacheSerialArena(serial);
}
ArenaImpl::~ArenaImpl() {
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
FreeBlocks();
ArenaMetricsCollector* collector = nullptr;
auto deallocator = &ArenaFree;
if (options_) {
collector = options_->metrics_collector;
deallocator = options_->block_dealloc;
}
PerBlock([deallocator](Block* b) {
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned, so
// return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size());
#endif // ADDRESS_SANITIZER
if (!b->user_owned()) {
(*deallocator)(b, b->size());
}
});
if (collector) {
collector->OnDestroy(SpaceAllocated());
}
}
uint64 ArenaImpl::Reset() {
if (options_ && options_->metrics_collector) {
options_->metrics_collector->OnReset(SpaceAllocated());
}
// Have to do this in a first pass, because some of the destructors might
// refer to memory in other blocks.
CleanupList();
uint64 space_allocated = FreeBlocks();
Init();
// Discard all blocks except the special block (if present).
uint64 space_allocated = 0;
Block* special_block = nullptr;
auto deallocator = (options_ ? options_->block_dealloc : &ArenaFree);
PerBlock([&space_allocated, &special_block, deallocator](Block* b) {
space_allocated += b->size();
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned, so
// return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size());
#endif // ADDRESS_SANITIZER
if (!b->special()) {
(*deallocator)(b, b->size());
} else {
// Prepare special block for reuse.
// Note: if options_ is present, it occupies the beginning of the
// block and therefore pos is advanced past it.
GOOGLE_DCHECK(special_block == nullptr);
special_block = b;
}
});
Init(record_allocs());
if (special_block != nullptr) {
// next() should still be nullptr since we are using a stack discipline, but
// clear it anyway to reduce fragility.
GOOGLE_DCHECK_EQ(special_block->next(), nullptr);
special_block->clear_next();
special_block->set_pos(kBlockHeaderSize + (options_ ? kOptionsSize : 0));
SetInitialBlock(special_block);
}
return space_allocated;
}
@ -111,23 +215,21 @@ ArenaImpl::Block* ArenaImpl::NewBlock(Block* last_block, size_t min_bytes) {
size_t size;
if (last_block) {
// Double the current block size, up to a limit.
size = std::min(2 * last_block->size(), options_.max_block_size);
auto max_size = options_ ? options_->max_block_size : kDefaultMaxBlockSize;
size = std::min(2 * last_block->size(), max_size);
} else {
size = options_.start_block_size;
size = options_ ? options_->start_block_size : kDefaultStartBlockSize;
}
// Verify that min_bytes + kBlockHeaderSize won't overflow.
GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kBlockHeaderSize);
size = std::max(size, kBlockHeaderSize + min_bytes);
void* mem = options_.block_alloc(size);
Block* b = new (mem) Block(size, last_block);
void* mem = options_ ? (*options_->block_alloc)(size) : ::operator new(size);
Block* b = new (mem) Block(size, last_block, false, false);
space_allocated_.fetch_add(size, std::memory_order_relaxed);
return b;
}
ArenaImpl::Block::Block(size_t size, Block* next)
: next_(next), pos_(kBlockHeaderSize), size_(size) {}
PROTOBUF_NOINLINE
void ArenaImpl::SerialArena::AddCleanupFallback(void* elem,
void (*cleanup)(void*)) {
@ -207,6 +309,10 @@ uint64 ArenaImpl::SpaceUsed() const {
for (; serial; serial = serial->next()) {
space_used += serial->SpaceUsed();
}
// Remove the overhead of Options structure, if any.
if (options_) {
space_used -= kOptionsSize;
}
return space_used;
}
@ -222,53 +328,6 @@ uint64 ArenaImpl::SerialArena::SpaceUsed() const {
return space_used;
}
uint64 ArenaImpl::FreeBlocks() {
uint64 space_allocated = 0;
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial = threads_.load(std::memory_order_relaxed);
while (serial) {
// This is inside a block we are freeing, so we need to read it now.
SerialArena* next = serial->next();
space_allocated += ArenaImpl::SerialArena::Free(serial, initial_block_,
options_.block_dealloc);
// serial is dead now.
serial = next;
}
return space_allocated;
}
uint64 ArenaImpl::SerialArena::Free(ArenaImpl::SerialArena* serial,
Block* initial_block,
void (*block_dealloc)(void*, size_t)) {
uint64 space_allocated = 0;
// We have to be careful in this function, since we will be freeing the Block
// that contains this SerialArena. Be careful about accessing |serial|.
for (Block* b = serial->head_; b;) {
// This is inside the block we are freeing, so we need to read it now.
Block* next_block = b->next();
space_allocated += (b->size());
#ifdef ADDRESS_SANITIZER
// This memory was provided by the underlying allocator as unpoisoned, so
// return it in an unpoisoned state.
ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size());
#endif // ADDRESS_SANITIZER
if (b != initial_block) {
block_dealloc(b, b->size());
}
b = next_block;
}
return space_allocated;
}
void ArenaImpl::CleanupList() {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
@ -307,11 +366,10 @@ void ArenaImpl::SerialArena::CleanupListFallback() {
ArenaImpl::SerialArena* ArenaImpl::SerialArena::New(Block* b, void* owner,
ArenaImpl* arena) {
GOOGLE_DCHECK_EQ(b->pos(), kBlockHeaderSize); // Should be a fresh block
GOOGLE_DCHECK_LE(kBlockHeaderSize + kSerialArenaSize, b->size());
SerialArena* serial =
reinterpret_cast<SerialArena*>(b->Pointer(kBlockHeaderSize));
b->set_pos(kBlockHeaderSize + kSerialArenaSize);
auto pos = b->pos();
GOOGLE_DCHECK_LE(pos + kSerialArenaSize, b->size());
SerialArena* serial = reinterpret_cast<SerialArena*>(b->Pointer(pos));
b->set_pos(pos + kSerialArenaSize);
serial->arena_ = arena;
serial->owner_ = owner;
serial->head_ = b;
@ -350,6 +408,8 @@ ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) {
return serial;
}
ArenaMetricsCollector::~ArenaMetricsCollector() {}
} // namespace internal
PROTOBUF_FUNC_ALIGN(32)
@ -357,25 +417,5 @@ void* Arena::AllocateAlignedNoHook(size_t n) {
return impl_.AllocateAligned(n);
}
void Arena::CallDestructorHooks() {
uint64 space_allocated = impl_.SpaceAllocated();
// Call the reset hook
if (on_arena_reset_ != NULL) {
on_arena_reset_(this, hooks_cookie_, space_allocated);
}
// Call the destruction hook
if (on_arena_destruction_ != NULL) {
on_arena_destruction_(this, hooks_cookie_, space_allocated);
}
}
void Arena::OnArenaAllocation(const std::type_info* allocated_type,
size_t n) const {
if (on_arena_allocation_ != NULL) {
on_arena_allocation_(allocated_type, n, hooks_cookie_);
}
}
} // namespace protobuf
} // namespace google

@ -102,15 +102,6 @@ template <typename T>
void arena_delete_object(void* object) {
delete reinterpret_cast<T*>(object);
}
inline void arena_free(void* object, size_t size) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(object, size);
#else
(void)size;
::operator delete(object);
#endif
}
} // namespace internal
// ArenaOptions provides optional additional parameters to arena construction
@ -152,43 +143,27 @@ struct ArenaOptions {
initial_block(NULL),
initial_block_size(0),
block_alloc(&::operator new),
block_dealloc(&internal::arena_free),
on_arena_init(NULL),
on_arena_reset(NULL),
on_arena_destruction(NULL),
on_arena_allocation(NULL) {}
block_dealloc(&internal::ArenaFree),
make_metrics_collector(nullptr) {}
private:
// Hooks for adding external functionality such as user-specific metrics
// collection, specific debugging abilities, etc.
// Init hook (if set) will always be called at Arena init time. Init hook may
// return a pointer to a cookie to be stored in the arena. Reset and
// destruction hooks will then be called with the same cookie pointer. This
// allows us to save an external object per arena instance and use it on the
// other hooks (Note: If init hook returns NULL, the other hooks will NOT be
// called on this arena instance).
// on_arena_reset and on_arena_destruction also receive the space used in the
// arena just before the reset.
void* (*on_arena_init)(Arena* arena);
void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
// type_info is promised to be static - its lifetime extends to
// match program's lifetime (It is given by typeid operator).
// Note: typeid(void) will be passed as allocated_type every time we
// intentionally want to avoid monitoring an allocation. (i.e. internal
// allocations for managing the arena)
void (*on_arena_allocation)(const std::type_info* allocated_type,
uint64 alloc_size, void* cookie);
// If make_metrics_collector is not nullptr, it will be called at Arena init
// time. It may return a pointer to a collector instance that will be notified
// of interesting events related to the arena.
internal::ArenaMetricsCollector* (*make_metrics_collector)();
// Constants define default starting block size and max block size for
// arena allocator behavior -- see descriptions above.
static const size_t kDefaultStartBlockSize = 256;
static const size_t kDefaultMaxBlockSize = 8192;
static const size_t kDefaultStartBlockSize =
internal::ArenaImpl::kDefaultStartBlockSize;
static const size_t kDefaultMaxBlockSize =
internal::ArenaImpl::kDefaultMaxBlockSize;
friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
friend class Arena;
friend class ArenaOptionsTestFriend;
friend class internal::ArenaImpl;
};
// Support for non-RTTI environments. (The metrics hooks API uses type
@ -246,11 +221,20 @@ struct ArenaOptions {
// should not rely on this protocol.
class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
public:
// Arena constructor taking custom options. See ArenaOptions below for
// Default constructor with sensible default options, tuned for average
// use-cases.
inline Arena() : impl_() {}
// Construct an arena with default options, except for the supplied
// initial block. It is more efficient to use this constructor
// instead of passing ArenaOptions if the only configuration needed
// by the caller is supplying an initial block.
inline Arena(char* initial_block, size_t initial_block_size)
: impl_(initial_block, initial_block_size) {}
// Arena constructor taking custom options. See ArenaOptions above for
// descriptions of the options available.
explicit Arena(const ArenaOptions& options) : impl_(options) {
Init(options);
}
explicit Arena(const ArenaOptions& options) : impl_(options) {}
// Block overhead. Use this as a guide for how much to over-allocate the
// initial block if you want an allocation of size N to fit inside it.
@ -261,27 +245,10 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
internal::ArenaImpl::kSerialArenaSize;
// Default constructor with sensible default options, tuned for average
// use-cases.
Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
inline ~Arena() {}
~Arena() {
if (hooks_cookie_) {
CallDestructorHooks();
}
}
void Init(const ArenaOptions& options) {
on_arena_allocation_ = options.on_arena_allocation;
on_arena_reset_ = options.on_arena_reset;
on_arena_destruction_ = options.on_arena_destruction;
// Call the initialization hook
if (options.on_arena_init != NULL) {
hooks_cookie_ = options.on_arena_init(this);
} else {
hooks_cookie_ = NULL;
}
}
// TODO(protobuf-team): Fix callers to use constructor and delete this method.
void Init(const ArenaOptions&) {}
// API to create proto2 message objects on the arena. If the arena passed in
// is NULL, then a heap allocated object is returned. Type T must be a message
@ -362,13 +329,7 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
// Any objects allocated on this arena are unusable after this call. It also
// returns the total space used by the arena which is the sums of the sizes
// of the allocated blocks. This method is not thread-safe.
PROTOBUF_NOINLINE uint64 Reset() {
// Call the reset hook
if (on_arena_reset_ != NULL) {
on_arena_reset_(this, hooks_cookie_, impl_.SpaceAllocated());
}
return impl_.Reset();
}
uint64 Reset() { return impl_.Reset(); }
// Adds |object| to a list of heap-allocated objects to be freed with |delete|
// when the arena is destroyed or reset.
@ -515,22 +476,17 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
}
}
void CallDestructorHooks();
void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
if (PROTOBUF_PREDICT_FALSE(hooks_cookie_ != NULL)) {
OnArenaAllocation(allocated_type, n);
}
impl_.RecordAlloc(allocated_type, n);
}
// Allocate and also optionally call on_arena_allocation callback with the
// allocated type info when the hooks are in place in ArenaOptions and
// the cookie is not null.
// Allocate and also optionally call collector with the allocated type info
// when allocation recording is enabled.
template <typename T>
PROTOBUF_ALWAYS_INLINE void* AllocateInternal(bool skip_explicit_ownership) {
static_assert(alignof(T) <= 8, "T is overaligned, see b/151247138");
const size_t n = internal::AlignUpTo8(sizeof(T));
AllocHook(RTTI_TYPE_ID(T), n);
impl_.RecordAlloc(RTTI_TYPE_ID(T), n);
// Monitor allocation if needed.
if (skip_explicit_ownership) {
return AllocateAlignedNoHook(n);
@ -593,7 +549,7 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
<< "Requested size is too large to fit into size_t.";
const size_t n = internal::AlignUpTo8(sizeof(T) * num_elements);
// Monitor allocation if needed.
AllocHook(RTTI_TYPE_ID(T), n);
impl_.RecordAlloc(RTTI_TYPE_ID(T), n);
return static_cast<T*>(AllocateAlignedNoHook(n));
}
@ -687,7 +643,6 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
// For friends of arena.
void* AllocateAligned(size_t n) {
AllocHook(NULL, n);
return AllocateAlignedNoHook(internal::AlignUpTo8(n));
}
template<size_t Align>
@ -706,15 +661,6 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final {
internal::ArenaImpl impl_;
void (*on_arena_allocation_)(const std::type_info* allocated_type,
uint64 alloc_size, void* cookie);
void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);
void (*on_arena_destruction_)(Arena* arena, void* cookie, uint64 space_used);
// The arena may save a cookie it receives from the external on_init hook
// and then use it when calling the on_reset and on_destruction hooks.
void* hooks_cookie_;
template <typename Type>
friend class internal::GenericTypeHandler;
friend struct internal::ArenaStringPtr; // For AllocateAligned.

@ -48,6 +48,9 @@
namespace google {
namespace protobuf {
struct ArenaOptions;
namespace internal {
inline size_t AlignUpTo8(size_t n) {
@ -57,6 +60,36 @@ inline size_t AlignUpTo8(size_t n) {
using LifecycleId = int64_t;
void PROTOBUF_EXPORT ArenaFree(void* object, size_t size);
// MetricsCollector collects stats for a particular arena.
class PROTOBUF_EXPORT ArenaMetricsCollector {
public:
virtual ~ArenaMetricsCollector();
// Invoked when the arena is about to be destroyed. This method will
// typically finalize any metric collection and delete the collector.
// space_allocated is the space used by the arena.
virtual void OnDestroy(uint64 space_allocated) = 0;
// OnReset() is called when the associated arena is reset.
// space_allocated is the space used by the arena just before the reset.
virtual void OnReset(uint64 space_allocated) = 0;
// Does OnAlloc() need to be called? If false, metric collection overhead
// will be reduced since we will not do extra work per allocation.
virtual bool RecordAllocs() = 0;
// OnAlloc is called when an allocation happens.
// type_info is promised to be static - its lifetime extends to
// match program's lifetime (It is given by typeid operator).
// Note: typeid(void) will be passed as allocated_type every time we
// intentionally want to avoid monitoring an allocation. (i.e. internal
// allocations for managing the arena)
virtual void OnAlloc(const std::type_info* allocated_type,
uint64 alloc_size) = 0;
};
// This class provides the core Arena memory allocation library. Different
// implementations only need to implement the public interface below.
// Arena is not a template type as that would only be useful if all protos
@ -65,37 +98,23 @@ using LifecycleId = int64_t;
// use #ifdef the select the best implementation based on hardware / OS.
class PROTOBUF_EXPORT ArenaImpl {
public:
struct Options {
size_t start_block_size;
size_t max_block_size;
char* initial_block;
size_t initial_block_size;
void* (*block_alloc)(size_t);
void (*block_dealloc)(void*, size_t);
static const size_t kDefaultStartBlockSize = 256;
static const size_t kDefaultMaxBlockSize = 8192;
template <typename O>
explicit Options(const O& options)
: start_block_size(options.start_block_size),
max_block_size(options.max_block_size),
initial_block(options.initial_block),
initial_block_size(options.initial_block_size),
block_alloc(options.block_alloc),
block_dealloc(options.block_dealloc) {}
};
ArenaImpl() { Init(false); }
template <typename O>
explicit ArenaImpl(const O& options) : options_(options) {
if (options_.initial_block != NULL && options_.initial_block_size > 0) {
GOOGLE_CHECK_GE(options_.initial_block_size, sizeof(Block))
<< ": Initial block size too small for header.";
initial_block_ = reinterpret_cast<Block*>(options_.initial_block);
} else {
initial_block_ = NULL;
}
ArenaImpl(char* mem, size_t size) {
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(mem) & 7, 0u);
Init(false);
Init();
// Ignore initial block if it is too small.
if (mem != nullptr && size >= kBlockHeaderSize + kSerialArenaSize) {
SetInitialBlock(new (mem) Block(size, nullptr, true, true));
}
}
explicit ArenaImpl(const ArenaOptions& options);
// Destructor deletes all owned heap allocated objects, and destructs objects
// that have non-trivial destructors, except for proto2 message objects whose
// destructors can be skipped. Also, frees all blocks except the initial block
@ -134,6 +153,13 @@ class PROTOBUF_EXPORT ArenaImpl {
// Add object pointer and cleanup function pointer to the list.
void AddCleanup(void* elem, void (*cleanup)(void*));
inline void RecordAlloc(const std::type_info* allocated_type,
size_t n) const {
if (PROTOBUF_PREDICT_FALSE(record_allocs())) {
options_->metrics_collector->OnAlloc(allocated_type, n);
}
}
private:
friend class ArenaBenchmark;
@ -170,11 +196,6 @@ class PROTOBUF_EXPORT ArenaImpl {
// Creates a new SerialArena inside Block* and returns it.
static SerialArena* New(Block* b, void* owner, ArenaImpl* arena);
// Destroys this SerialArena, freeing all blocks with the given dealloc
// function, except any block equal to |initial_block|.
static uint64 Free(SerialArena* serial, Block* initial_block,
void (*block_dealloc)(void*, size_t));
void CleanupList();
uint64 SpaceUsed() const;
@ -224,6 +245,7 @@ class PROTOBUF_EXPORT ArenaImpl {
return ret;
}
Block* head() const { return head_; }
void* owner() const { return owner_; }
SerialArena* next() const { return next_; }
void set_next(SerialArena* next) { next_ = next; }
@ -254,25 +276,58 @@ class PROTOBUF_EXPORT ArenaImpl {
// describes the common header for all blocks.
class PROTOBUF_EXPORT Block {
public:
Block(size_t size, Block* next);
Block(size_t size, Block* next, bool special, bool user_owned)
: next_and_bits_(reinterpret_cast<uintptr_t>(next) | (special ? 1 : 0) |
(user_owned ? 2 : 0)),
pos_(kBlockHeaderSize),
size_(size) {
GOOGLE_DCHECK_EQ(reinterpret_cast<uintptr_t>(next) & 3, 0u);
}
char* Pointer(size_t n) {
GOOGLE_DCHECK(n <= size_);
return reinterpret_cast<char*>(this) + n;
}
Block* next() const { return next_; }
// One of the blocks may be special. This is either a user-supplied
// initial block, or a block we created at startup to hold Options info.
// A special block is not deleted by Reset.
bool special() const { return (next_and_bits_ & 1) != 0; }
// Whether or not this current block is owned by the user.
// Only special blocks can be user_owned.
bool user_owned() const { return (next_and_bits_ & 2) != 0; }
Block* next() const {
const uintptr_t bottom_bits = 3;
return reinterpret_cast<Block*>(next_and_bits_ & ~bottom_bits);
}
void clear_next() {
next_and_bits_ &= 3; // Set next to nullptr, preserve bottom bits.
}
size_t pos() const { return pos_; }
size_t size() const { return size_; }
void set_pos(size_t pos) { pos_ = pos; }
private:
Block* next_; // Next block for this thread.
// Holds pointer to next block for this thread + special/user_owned bits.
uintptr_t next_and_bits_;
size_t pos_;
size_t size_;
// data follows
};
struct Options {
size_t start_block_size;
size_t max_block_size;
void* (*block_alloc)(size_t);
void (*block_dealloc)(void*, size_t);
ArenaMetricsCollector* metrics_collector;
};
struct ThreadCache {
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// If we are using the ThreadLocalStorage class to store the ThreadCache,
@ -301,11 +356,30 @@ class PROTOBUF_EXPORT ArenaImpl {
static ThreadCache& thread_cache() { return thread_cache_; }
#endif
void Init();
void Init(bool record_allocs);
void SetInitialBlock(Block* block); // Can be called right after Init()
// Return true iff allocations should be recorded in a metrics collector.
inline bool record_allocs() const { return lifecycle_id_ & 1; }
// Invoke fn(b) for every Block* b.
template <typename Functor>
void PerBlock(Functor fn) {
// By omitting an Acquire barrier we ensure that any user code that doesn't
// properly synchronize Reset() or the destructor will throw a TSAN warning.
SerialArena* serial = threads_.load(std::memory_order_relaxed);
while (serial) {
// fn() may delete blocks and arenas, so fetch next pointers before fn();
SerialArena* cur = serial;
serial = serial->next();
for (Block* block = cur->head(); block != nullptr;) {
Block* b = block;
block = b->next();
fn(b);
}
}
}
// Free all blocks and return the total space used which is the sums of sizes
// of the all the allocated blocks.
uint64 FreeBlocks();
// Delete or Destruct all objects owned by the arena.
void CleanupList();
@ -324,9 +398,6 @@ class PROTOBUF_EXPORT ArenaImpl {
std::atomic<SerialArena*> hint_; // Fast thread-local block access
std::atomic<size_t> space_allocated_; // Total size of all allocated blocks.
Block* initial_block_; // If non-NULL, points to the block that came from
// user data.
Block* NewBlock(Block* last_block, size_t min_bytes);
PROTOBUF_ALWAYS_INLINE bool GetSerialArenaFast(SerialArena** arena) {
@ -356,9 +427,12 @@ class PROTOBUF_EXPORT ArenaImpl {
return false;
}
SerialArena* GetSerialArenaFallback(void* me);
LifecycleId lifecycle_id_; // Unique for each arena. Changes on Reset().
Options options_;
// Unique for each arena. Changes on Reset().
// Least-significant-bit is 1 iff allocations should be recorded.
LifecycleId lifecycle_id_;
Options* options_ = nullptr;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArenaImpl);
// All protos have pointers back to the arena hence Arena must have
@ -373,6 +447,8 @@ class PROTOBUF_EXPORT ArenaImpl {
(sizeof(Block) + 7) & static_cast<size_t>(-8);
static const size_t kSerialArenaSize =
(sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
static const size_t kOptionsSize =
(sizeof(Options) + 7) & static_cast<size_t>(-8);
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,

@ -272,28 +272,36 @@ TEST(ArenaTest, CreateWithMoveArguments) {
}
TEST(ArenaTest, InitialBlockTooSmall) {
// Construct a small (64 byte) initial block of memory to be used by the
// arena allocator; then, allocate an object which will not fit in the
// initial block.
std::vector<char> arena_block(96);
ArenaOptions options;
options.initial_block = &arena_block[0];
options.initial_block_size = arena_block.size();
Arena arena(options);
// Construct a small blocks of memory to be used by the arena allocator; then,
// allocate an object which will not fit in the initial block.
for (int size = 0; size <= Arena::kBlockOverhead + 32; size++) {
std::vector<char> arena_block(size);
ArenaOptions options;
options.initial_block = arena_block.data();
options.initial_block_size = arena_block.size();
// Try sometimes with non-default block sizes so that we exercise paths
// with and without ArenaImpl::Options.
if ((size % 2) != 0) {
options.start_block_size += 8;
}
char* p = Arena::CreateArray<char>(&arena, 96);
uintptr_t allocation = reinterpret_cast<uintptr_t>(p);
Arena arena(options);
char* p = Arena::CreateArray<char>(&arena, 96);
uintptr_t allocation = reinterpret_cast<uintptr_t>(p);
// Ensure that the arena allocator did not return memory pointing into the
// initial block of memory.
uintptr_t arena_start = reinterpret_cast<uintptr_t>(&arena_block[0]);
uintptr_t arena_end = arena_start + arena_block.size();
EXPECT_FALSE(allocation >= arena_start && allocation < arena_end);
// Ensure that the arena allocator did not return memory pointing into the
// initial block of memory.
uintptr_t arena_start = reinterpret_cast<uintptr_t>(arena_block.data());
uintptr_t arena_end = arena_start + arena_block.size();
EXPECT_FALSE(allocation >= arena_start && allocation < arena_end);
// Write to the memory we allocated; this should (but is not guaranteed to)
// trigger a check for heap corruption if the object was allocated from the
// initially-provided block.
memset(p, '\0', 96);
// Write to the memory we allocated; this should (but is not guaranteed to)
// trigger a check for heap corruption if the object was allocated from the
// initially-provided block.
memset(p, '\0', 96);
}
}
TEST(ArenaTest, Parsing) {
@ -988,10 +996,7 @@ TEST(ArenaTest, ExtensionsOnArena) {
TEST(ArenaTest, RepeatedFieldOnArena) {
// Preallocate an initial arena block to avoid mallocs during hooked region.
std::vector<char> arena_block(1024 * 1024);
ArenaOptions options;
options.initial_block = &arena_block[0];
options.initial_block_size = arena_block.size();
Arena arena(options);
Arena arena(arena_block.data(), arena_block.size());
{
internal::NoHeapChecker no_heap;
@ -1189,10 +1194,7 @@ TEST(ArenaTest, RepeatedFieldWithNonPODType) {
uint64 Align8(uint64 n) { return (n + 7) & -8; }
TEST(ArenaTest, SpaceAllocated_and_Used) {
ArenaOptions options;
options.start_block_size = 256;
options.max_block_size = 8192;
Arena arena_1(options);
Arena arena_1;
EXPECT_EQ(0, arena_1.SpaceAllocated());
EXPECT_EQ(0, arena_1.SpaceUsed());
EXPECT_EQ(0, arena_1.Reset());
@ -1204,6 +1206,9 @@ TEST(ArenaTest, SpaceAllocated_and_Used) {
// Test with initial block.
std::vector<char> arena_block(1024);
ArenaOptions options;
options.start_block_size = 256;
options.max_block_size = 8192;
options.initial_block = &arena_block[0];
options.initial_block_size = arena_block.size();
Arena arena_2(options);
@ -1214,19 +1219,25 @@ TEST(ArenaTest, SpaceAllocated_and_Used) {
EXPECT_EQ(1024, arena_2.SpaceAllocated());
EXPECT_EQ(Align8(55), arena_2.SpaceUsed());
EXPECT_EQ(1024, arena_2.Reset());
}
// Reset options to test doubling policy explicitly.
options.initial_block = NULL;
options.initial_block_size = 0;
Arena arena_3(options);
EXPECT_EQ(0, arena_3.SpaceUsed());
Arena::CreateArray<char>(&arena_3, 160);
EXPECT_EQ(256, arena_3.SpaceAllocated());
EXPECT_EQ(Align8(160), arena_3.SpaceUsed());
Arena::CreateArray<char>(&arena_3, 70);
EXPECT_EQ(256 + 512, arena_3.SpaceAllocated());
EXPECT_EQ(Align8(160) + Align8(70), arena_3.SpaceUsed());
EXPECT_EQ(256 + 512, arena_3.Reset());
TEST(ArenaTest, BlockSizeDoubling) {
Arena arena;
EXPECT_EQ(0, arena.SpaceUsed());
EXPECT_EQ(0, arena.SpaceAllocated());
// Allocate something to get initial block size.
Arena::CreateArray<char>(&arena, 1);
auto first_block_size = arena.SpaceAllocated();
// Keep allocating until space used increases.
while (arena.SpaceAllocated() == first_block_size) {
Arena::CreateArray<char>(&arena, 1);
}
ASSERT_GT(arena.SpaceAllocated(), first_block_size);
auto second_block_size = (arena.SpaceAllocated() - first_block_size);
EXPECT_EQ(second_block_size, 2*first_block_size);
}
TEST(ArenaTest, Alignment) {
@ -1304,81 +1315,93 @@ TEST(ArenaTest, AddCleanup) {
}
}
// A helper utility class to only contain static hook functions, some
// counters to be used to verify the counters have been called and a cookie
// value to be verified.
class ArenaHooksTestUtil {
namespace {
uint32 hooks_num_init = 0;
uint32 hooks_num_allocations = 0;
uint32 hooks_num_reset = 0;
uint32 hooks_num_destruct = 0;
void ClearHookCounts() {
hooks_num_init = 0;
hooks_num_allocations = 0;
hooks_num_reset = 0;
hooks_num_destruct = 0;
}
} // namespace
// A helper utility class that handles arena callbacks.
class ArenaOptionsTestFriend : public internal::ArenaMetricsCollector {
public:
static void* on_init(Arena* arena) {
++num_init;
int* cookie = new int(kCookieValue);
return static_cast<void*>(cookie);
static internal::ArenaMetricsCollector* NewWithAllocs() {
return new ArenaOptionsTestFriend(true);
}
static void on_allocation(const std::type_info* /*unused*/, uint64 alloc_size,
void* cookie) {
++num_allocations;
int cookie_value = *static_cast<int*>(cookie);
EXPECT_EQ(kCookieValue, cookie_value);
static internal::ArenaMetricsCollector* NewWithoutAllocs() {
return new ArenaOptionsTestFriend(false);
}
static void on_reset(Arena* arena, void* cookie, uint64 space_used) {
++num_reset;
int cookie_value = *static_cast<int*>(cookie);
EXPECT_EQ(kCookieValue, cookie_value);
static void Enable(ArenaOptions* options) {
ClearHookCounts();
options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithAllocs;
}
static void on_destruction(Arena* arena, void* cookie, uint64 space_used) {
++num_destruct;
int cookie_value = *static_cast<int*>(cookie);
EXPECT_EQ(kCookieValue, cookie_value);
delete static_cast<int*>(cookie);
static void EnableWithoutAllocs(ArenaOptions* options) {
ClearHookCounts();
options->make_metrics_collector = &ArenaOptionsTestFriend::NewWithoutAllocs;
}
static const int kCookieValue = 999;
static uint32 num_init;
static uint32 num_allocations;
static uint32 num_reset;
static uint32 num_destruct;
};
uint32 ArenaHooksTestUtil::num_init = 0;
uint32 ArenaHooksTestUtil::num_allocations = 0;
uint32 ArenaHooksTestUtil::num_reset = 0;
uint32 ArenaHooksTestUtil::num_destruct = 0;
const int ArenaHooksTestUtil::kCookieValue;
class ArenaOptionsTestFriend {
public:
static void Set(ArenaOptions* options) {
options->on_arena_init = ArenaHooksTestUtil::on_init;
options->on_arena_allocation = ArenaHooksTestUtil::on_allocation;
options->on_arena_reset = ArenaHooksTestUtil::on_reset;
options->on_arena_destruction = ArenaHooksTestUtil::on_destruction;
explicit ArenaOptionsTestFriend(bool record_allocs)
: record_allocs_(record_allocs) {
++hooks_num_init;
}
void OnDestroy(uint64 space_allocated) override {
++hooks_num_destruct;
delete this;
}
void OnReset(uint64 space_allocated) override { ++hooks_num_reset; }
bool RecordAllocs() override { return record_allocs_; }
void OnAlloc(const std::type_info* allocated_type,
uint64 alloc_size) override {
++hooks_num_allocations;
}
private:
bool record_allocs_;
};
// Test the hooks are correctly called and that the cookie is passed.
// Test the hooks are correctly called.
TEST(ArenaTest, ArenaHooksSanity) {
ArenaOptions options;
ArenaOptionsTestFriend::Set(&options);
ArenaOptionsTestFriend::Enable(&options);
// Scope for defining the arena
{
Arena arena(options);
EXPECT_EQ(1, ArenaHooksTestUtil::num_init);
EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations);
EXPECT_EQ(1, hooks_num_init);
EXPECT_EQ(0, hooks_num_allocations);
Arena::Create<uint64>(&arena);
if (std::is_trivially_destructible<uint64>::value) {
EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations);
EXPECT_EQ(1, hooks_num_allocations);
} else {
EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations);
EXPECT_EQ(2, hooks_num_allocations);
}
arena.Reset();
arena.Reset();
EXPECT_EQ(2, ArenaHooksTestUtil::num_reset);
EXPECT_EQ(2, hooks_num_reset);
}
EXPECT_EQ(3, ArenaHooksTestUtil::num_reset);
EXPECT_EQ(1, ArenaHooksTestUtil::num_destruct);
EXPECT_EQ(2, hooks_num_reset);
EXPECT_EQ(1, hooks_num_destruct);
}
// Test that allocation hooks are not called when we don't need them.
TEST(ArenaTest, ArenaHooksWhenAllocationsNotNeeded) {
ArenaOptions options;
ArenaOptionsTestFriend::EnableWithoutAllocs(&options);
Arena arena(options);
EXPECT_EQ(0, hooks_num_allocations);
Arena::Create<uint64>(&arena);
EXPECT_EQ(0, hooks_num_allocations);
}

@ -0,0 +1,254 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <google/protobuf/arenastring.h>
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/stubs/mutex.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/stl_util.h>
// clang-format off
#include <google/protobuf/port_def.inc>
// clang-format on
namespace google {
namespace protobuf {
namespace internal {
const std::string& LazyString::Init() const {
static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
mu.Lock();
const std::string* res = inited_.load(std::memory_order_acquire);
if (res == nullptr) {
auto init_value = init_value_;
res = ::new (static_cast<void*>(string_buf_))
std::string(init_value.ptr, init_value.size);
inited_.store(res, std::memory_order_release);
}
mu.Unlock();
return *res;
}
void ArenaStringPtr::Set(const std::string* default_value,
ConstStringParam value, ::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
tagged_ptr_.Set(Arena::Create<std::string>(arena, value));
} else {
UnsafeMutablePointer()->assign(value.data(), value.length());
}
}
void ArenaStringPtr::Set(const std::string* default_value, std::string&& value,
::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
if (arena == nullptr) {
tagged_ptr_.Set(new std::string(std::move(value)));
} else {
tagged_ptr_.Set(Arena::Create<std::string>(arena, std::move(value)));
}
} else if (IsDonatedString()) {
std::string* current = tagged_ptr_.Get();
auto* s = new (current) std::string(std::move(value));
arena->OwnDestructor(s);
tagged_ptr_.Set(s);
} else /* !IsDonatedString() */ {
*UnsafeMutablePointer() = std::move(value);
}
}
void ArenaStringPtr::Set(EmptyDefault, ConstStringParam value,
::google::protobuf::Arena* arena) {
Set(&GetEmptyStringAlreadyInited(), value, arena);
}
void ArenaStringPtr::Set(EmptyDefault, std::string&& value,
::google::protobuf::Arena* arena) {
Set(&GetEmptyStringAlreadyInited(), std::move(value), arena);
}
void ArenaStringPtr::Set(NonEmptyDefault, ConstStringParam value,
::google::protobuf::Arena* arena) {
Set(nullptr, value, arena);
}
void ArenaStringPtr::Set(NonEmptyDefault, std::string&& value,
::google::protobuf::Arena* arena) {
Set(nullptr, std::move(value), arena);
}
std::string* ArenaStringPtr::Mutable(EmptyDefault, ::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(&GetEmptyStringAlreadyInited())) {
return UnsafeMutablePointer();
} else {
return MutableSlow(arena);
}
}
std::string* ArenaStringPtr::Mutable(const LazyString& default_value,
::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(nullptr)) {
return UnsafeMutablePointer();
} else {
return MutableSlow(arena, default_value);
}
}
std::string* ArenaStringPtr::MutableNoCopy(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (!IsDonatedString() && !IsDefault(default_value)) {
return UnsafeMutablePointer();
} else {
GOOGLE_DCHECK(IsDefault(default_value));
// Allocate empty. The contents are not relevant.
std::string* new_string = Arena::Create<std::string>(arena);
tagged_ptr_.Set(new_string);
return new_string;
}
}
template <typename... Lazy>
std::string* ArenaStringPtr::MutableSlow(::google::protobuf::Arena* arena,
const Lazy&... lazy_default) {
const std::string* const default_value =
sizeof...(Lazy) == 0 ? &GetEmptyStringAlreadyInited() : nullptr;
GOOGLE_DCHECK(IsDefault(default_value));
std::string* new_string =
Arena::Create<std::string>(arena, lazy_default.get()...);
tagged_ptr_.Set(new_string);
return new_string;
}
std::string* ArenaStringPtr::Release(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (IsDefault(default_value)) {
return nullptr;
} else {
return ReleaseNonDefault(default_value, arena);
}
}
std::string* ArenaStringPtr::ReleaseNonDefault(const std::string* default_value,
::google::protobuf::Arena* arena) {
GOOGLE_DCHECK(!IsDefault(default_value));
if (!IsDonatedString()) {
std::string* released;
if (arena != nullptr) {
released = new std::string;
released->swap(*UnsafeMutablePointer());
} else {
released = UnsafeMutablePointer();
}
tagged_ptr_.Set(const_cast<std::string*>(default_value));
return released;
} else /* IsDonatedString() */ {
GOOGLE_DCHECK(arena != nullptr);
std::string* released = new std::string(Get());
tagged_ptr_.Set(const_cast<std::string*>(default_value));
return released;
}
}
void ArenaStringPtr::SetAllocated(const std::string* default_value,
std::string* value, ::google::protobuf::Arena* arena) {
// Release what we have first.
if (arena == nullptr && !IsDefault(default_value)) {
delete UnsafeMutablePointer();
}
if (value == nullptr) {
tagged_ptr_.Set(const_cast<std::string*>(default_value));
} else {
#ifdef NDEBUG
tagged_ptr_.Set(value);
if (arena != nullptr) {
arena->Own(value);
}
#else
// On debug builds, copy the string so the address differs. delete will
// fail if value was a stack-allocated temporary/etc., which would have
// failed when arena ran its cleanup list.
std::string* new_value = Arena::Create<std::string>(arena, *value);
delete value;
tagged_ptr_.Set(new_value);
#endif
}
}
void ArenaStringPtr::Destroy(const std::string* default_value,
::google::protobuf::Arena* arena) {
if (arena == nullptr) {
GOOGLE_DCHECK(!IsDonatedString());
if (!IsDefault(default_value)) {
delete UnsafeMutablePointer();
}
}
}
void ArenaStringPtr::Destroy(EmptyDefault, ::google::protobuf::Arena* arena) {
Destroy(&GetEmptyStringAlreadyInited(), arena);
}
void ArenaStringPtr::Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena) {
Destroy(nullptr, arena);
}
void ArenaStringPtr::ClearToEmpty() {
if (IsDefault(&GetEmptyStringAlreadyInited())) {
// Already set to default -- do nothing.
} else {
// Unconditionally mask away the tag.
//
// UpdateDonatedString uses assign when capacity is larger than the new
// value, which is trivially true in the donated string case.
// const_cast<std::string*>(PtrValue<std::string>())->clear();
tagged_ptr_.Get()->clear();
}
}
void ArenaStringPtr::ClearToDefault(const LazyString& default_value,
::google::protobuf::Arena* arena) {
(void)arena;
if (IsDefault(nullptr)) {
// Already set to default -- do nothing.
} else if (!IsDonatedString()) {
UnsafeMutablePointer()->assign(default_value.get());
}
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -37,7 +37,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/fastmem.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/port.h>
@ -48,23 +47,57 @@
#endif
// This is the implementation of arena string fields written for the open-source
// release. The ArenaStringPtr struct below is an internal implementation class
// and *should not be used* by user code. It is used to collect string
// operations together into one place and abstract away the underlying
// string-field pointer representation, so that (for example) an alternate
// implementation that knew more about ::std::string's internals could integrate
// more closely with the arena allocator.
namespace google {
namespace protobuf {
namespace internal {
// Lazy string instance to support string fields with non-empty default.
// These are initialized on the first call to .get().
class PROTOBUF_EXPORT LazyString {
public:
// We explicitly make LazyString an aggregate so that MSVC can do constant
// initialization on it without marking it `constexpr`.
// We do not want to use `constexpr` because it makes it harder to have extern
// storage for it and causes library bloat.
struct InitValue {
const char* ptr;
size_t size;
};
// We keep a union of the initialization value and the std::string to save on
// space. We don't need the string array after Init() is done.
union {
mutable InitValue init_value_;
alignas(std::string) mutable char string_buf_[sizeof(std::string)];
};
mutable std::atomic<const std::string*> inited_;
const std::string& get() const {
// This check generates less code than a call-once invocation.
auto* res = inited_.load(std::memory_order_acquire);
if (PROTOBUF_PREDICT_FALSE(res == nullptr)) return Init();
return *res;
}
private:
// Initialize the string in `string_buf_`, update `inited_` and return it.
// We return it here to avoid having to read it again in the inlined code.
const std::string& Init() const;
};
template <typename T>
class TaggedPtr {
public:
void SetTagged(T* p) {
Set(p);
ptr_ |= 1;
}
void Set(T* p) { ptr_ = reinterpret_cast<uintptr_t>(p); }
T* Get() const { return reinterpret_cast<T*>(ptr_); }
T* Get() const { return reinterpret_cast<T*>(ptr_ & -2); }
bool IsTagged() const { return ptr_ & 1; }
// Returned value is only safe to dereference if IsTagged() == false.
// It is safe to compare.
T* UnsafeGet() const { return reinterpret_cast<T*>(ptr_); }
bool IsNull() { return ptr_ == 0; }
@ -72,237 +105,266 @@ class TaggedPtr {
uintptr_t ptr_;
};
struct PROTOBUF_EXPORT ArenaStringPtr {
inline void Set(const ::std::string* default_value,
const ::std::string& value, Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, &value);
} else {
*ptr_ = value;
}
}
static_assert(std::is_trivial<TaggedPtr<std::string>>::value,
"TaggedPtr must be trivial");
inline void SetLite(const ::std::string* default_value,
const ::std::string& value, Arena* arena) {
Set(default_value, value, arena);
}
// This class encapsulates a pointer to a std::string with or without a donated
// buffer, tagged by bottom bit. It is a high-level wrapper that almost directly
// corresponds to the interface required by string fields in generated
// code. It replaces the old std::string* pointer in such cases.
//
// The object has different but similar code paths for when the default value is
// the empty string and when it is a non-empty string.
// The empty string is handled different throughout the library and there is a
// single global instance of it we can share.
//
// For fields with an empty string default value, there are three distinct
// states:
//
// - Pointer set to 'String' tag (LSB is 0), equal to
// &GetEmptyStringAlreadyInited(): field is set to its default value. Points
// to a true std::string*, but we do not own that std::string* (it's a
// globally shared instance).
//
// - Pointer set to 'String' tag (LSB is 0), but not equal to the global empty
// string: field points to a true std::string* instance that we own. This
// instance is either on the heap or on the arena (i.e. registered on
// free()/destructor-call list) as appropriate.
//
// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
// instance with a buffer on the arena (arena != NULL, always, in this case).
//
// For fields with a non-empty string default value, there are three distinct
// states:
//
// - Pointer set to 'String' tag (LSB is 0), equal to `nullptr`:
// Field is in "default" mode and does not point to any actual instance.
// Methods that might need to create an instance of the object will pass a
// `const LazyString&` for it.
//
// - Pointer set to 'String' tag (LSB is 0), but not equal to `nullptr`:
// field points to a true std::string* instance that we own. This instance is
// either on the heap or on the arena (i.e. registered on
// free()/destructor-call list) as appropriate.
//
// - Pointer set to 'DonatedString' tag (LSB is 1): points to a std::string
// instance with a buffer on the arena (arena != NULL, always, in this case).
//
// Generated code and reflection code both ensure that ptr_ is never null for
// fields with an empty default.
// Because ArenaStringPtr is used in oneof unions, its constructor is a NOP and
// so the field is always manually initialized via method calls.
//
// Side-note: why pass information about the default on every API call? Because
// we don't want to hold it in a member variable, or else this would go into
// every proto message instance. This would be a huge waste of space, since the
// default instance pointer is typically a global (static class field). We want
// the generated code to be as efficient as possible, and if we take
// the default value information as a parameter that's in practice taken from a
// static class field, and compare ptr_ to the default value, we end up with a
// single "cmp %reg, GLOBAL" in the resulting machine code. (Note that this also
// requires the String tag to be 0 so we can avoid the mask before comparing.)
struct PROTOBUF_EXPORT ArenaStringPtr {
// No default constructor or destructor -- we have to be POD because we go
// into a union when used in a oneof. Message code calls UnsafeReset() to zero
// the pointer when necessary instead.
// Some methods below are overloaded on a `default_value` and on tags.
// The tagged overloads help reduce code size in the callers in generated
// code, while the `default_value` overloads are useful from reflection.
// By-value empty struct arguments are elided in the ABI.
struct EmptyDefault {};
struct NonEmptyDefault {};
void Set(const std::string* default_value, ConstStringParam value,
::google::protobuf::Arena* arena);
void Set(const std::string* default_value, std::string&& value,
::google::protobuf::Arena* arena);
void Set(EmptyDefault, ConstStringParam value, ::google::protobuf::Arena* arena);
void Set(EmptyDefault, std::string&& value, ::google::protobuf::Arena* arena);
void Set(NonEmptyDefault, ConstStringParam value, ::google::protobuf::Arena* arena);
void Set(NonEmptyDefault, std::string&& value, ::google::protobuf::Arena* arena);
// Basic accessors.
inline const ::std::string& Get() const { return *ptr_; }
inline ::std::string* Mutable(const ::std::string* default_value,
Arena* arena) {
if (ptr_ == default_value) {
CreateInstance(arena, default_value);
}
return ptr_;
const std::string& Get() const PROTOBUF_ALWAYS_INLINE {
// Unconditionally mask away the tag.
return *tagged_ptr_.Get();
}
// Release returns a ::std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field was not set, it returns NULL. The caller
// retains ownership. Clears this field back to NULL state. Used to implement
// release_<field>() methods on generated classes.
inline ::std::string* Release(const ::std::string* default_value,
Arena* arena) {
if (ptr_ == default_value) {
return NULL;
}
return ReleaseNonDefault(default_value, arena);
const std::string* GetPointer() const PROTOBUF_ALWAYS_INLINE {
// Unconditionally mask away the tag.
return tagged_ptr_.Get();
}
// Similar to Release, but ptr_ cannot be the default_value.
inline ::std::string* ReleaseNonDefault(const ::std::string* default_value,
Arena* arena) {
GOOGLE_DCHECK(!IsDefault(default_value));
::std::string* released = NULL;
if (arena != NULL) {
// ptr_ is owned by the arena.
released = new ::std::string;
released->swap(*ptr_);
} else {
released = ptr_;
}
ptr_ = const_cast< ::std::string*>(default_value);
return released;
}
// UnsafeArenaRelease returns a ::std::string*, but it may be arena-owned
// (i.e. have its destructor already registered) if arena != NULL. If the
// field was not set, this returns NULL. This method clears this field back to
// NULL state. Used to implement unsafe_arena_release_<field>() methods on
// generated classes.
inline ::std::string* UnsafeArenaRelease(const ::std::string* default_value,
Arena* /* arena */) {
if (ptr_ == default_value) {
return NULL;
}
::std::string* released = ptr_;
ptr_ = const_cast< ::std::string*>(default_value);
return released;
}
// Takes a string that is heap-allocated, and takes ownership. The string's
// destructor is registered with the arena. Used to implement
// For fields with an empty default value.
std::string* Mutable(EmptyDefault, ::google::protobuf::Arena* arena);
// For fields with a non-empty default value.
std::string* Mutable(const LazyString& default_value, ::google::protobuf::Arena* arena);
// Release returns a std::string* instance that is heap-allocated and is not
// Own()'d by any arena. If the field is not set, this returns NULL. The
// caller retains ownership. Clears this field back to NULL state. Used to
// implement release_<field>() methods on generated classes.
std::string* Release(const std::string* default_value,
::google::protobuf::Arena* arena);
std::string* ReleaseNonDefault(const std::string* default_value,
::google::protobuf::Arena* arena);
// Takes a std::string that is heap-allocated, and takes ownership. The
// std::string's destructor is registered with the arena. Used to implement
// set_allocated_<field> in generated classes.
inline void SetAllocated(const ::std::string* default_value,
::std::string* value, Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
Destroy(default_value, arena);
}
if (value != NULL) {
ptr_ = value;
if (arena != NULL) {
arena->Own(value);
}
} else {
ptr_ = const_cast< ::std::string*>(default_value);
}
}
// Takes a string that has lifetime equal to the arena's lifetime. The arena
// must be non-null. It is safe only to pass this method a value returned by
// UnsafeArenaRelease() on another field of a message in the same arena. Used
// to implement unsafe_arena_set_allocated_<field> in generated classes.
inline void UnsafeArenaSetAllocated(const ::std::string* default_value,
::std::string* value,
Arena* /* arena */) {
if (value != NULL) {
ptr_ = value;
} else {
ptr_ = const_cast< ::std::string*>(default_value);
}
}
void SetAllocated(const std::string* default_value, std::string* value,
::google::protobuf::Arena* arena);
// Swaps internal pointers. Arena-safety semantics: this is guarded by the
// logic in Swap()/UnsafeArenaSwap() at the message level, so this method is
// 'unsafe' if called directly.
PROTOBUF_ALWAYS_INLINE void Swap(ArenaStringPtr* other) {
std::swap(ptr_, other->ptr_);
}
PROTOBUF_ALWAYS_INLINE void Swap(ArenaStringPtr* other,
const ::std::string* default_value,
Arena* arena) {
#ifndef NDEBUG
// For debug builds, we swap the contents of the string, rather than the
// string instances themselves. This invalidates previously taken const
// references that are (per our documentation) invalidated by calling Swap()
// on the message.
//
// If both strings are the default_value, swapping is uninteresting.
// Otherwise, we use ArenaStringPtr::Mutable() to access the string, to
// ensure that we do not try to mutate default_value itself.
if (IsDefault(default_value) && other->IsDefault(default_value)) {
return;
}
::std::string* this_ptr = Mutable(default_value, arena);
::std::string* other_ptr = other->Mutable(default_value, arena);
this_ptr->swap(*other_ptr);
#else
std::swap(ptr_, other->ptr_);
(void)default_value;
(void)arena;
#endif
}
inline void Swap(ArenaStringPtr* other, const std::string* default_value,
Arena* arena) PROTOBUF_ALWAYS_INLINE;
// Frees storage (if not on an arena).
inline void Destroy(const ::std::string* default_value, Arena* arena) {
if (arena == NULL && ptr_ != default_value) {
delete ptr_;
}
}
void Destroy(const std::string* default_value, ::google::protobuf::Arena* arena);
void Destroy(EmptyDefault, ::google::protobuf::Arena* arena);
void Destroy(NonEmptyDefault, ::google::protobuf::Arena* arena);
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be the empty string. Assumes that |default_value|
// is an empty string.
inline void ClearToEmpty(const ::std::string* default_value,
Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default (which is empty) -- do nothing.
} else {
ptr_->clear();
}
}
// Clears content, but keeps allocated std::string, to avoid the overhead of
// heap operations. After this returns, the content (as seen by the user) will
// always be the empty std::string. Assumes that |default_value| is an empty
// std::string.
void ClearToEmpty();
// Clears content, assuming that the current value is not the empty string
// default.
inline void ClearNonDefaultToEmpty() { ptr_->clear(); }
// Clears content, but keeps allocated string if arena != NULL, to avoid the
// overhead of heap operations. After this returns, the content (as seen by
// the user) will always be equal to |default_value|.
inline void ClearToDefault(const ::std::string* default_value,
Arena* /* arena */) {
if (ptr_ == default_value) {
// Already set to default -- do nothing.
} else {
// Have another allocated string -- rather than throwing this away and
// resetting ptr_ to the canonical default string instance, we just reuse
// this instance.
*ptr_ = *default_value;
}
}
// Clears content, assuming that the current value is not the empty
// string default.
void ClearNonDefaultToEmpty();
// Clears content, but keeps allocated std::string if arena != NULL, to avoid
// the overhead of heap operations. After this returns, the content (as seen
// by the user) will always be equal to |default_value|.
void ClearToDefault(const LazyString& default_value, ::google::protobuf::Arena* arena);
// Called from generated code / reflection runtime only. Resets value to point
// to a default string pointer, with the semantics that this ArenaStringPtr
// does not own the pointed-to memory. Disregards initial value of ptr_ (so
// this is the *ONLY* safe method to call after construction or when
// reinitializing after becoming the active field in a oneof union).
inline void UnsafeSetDefault(const ::std::string* default_value) {
// Casting away 'const' is safe here: accessors ensure that ptr_ is only
// returned as a const if it is equal to default_value.
ptr_ = const_cast< ::std::string*>(default_value);
}
// to a default string pointer, with the semantics that this
// ArenaStringPtr does not own the pointed-to memory. Disregards initial value
// of ptr_ (so this is the *ONLY* safe method to call after construction or
// when reinitializing after becoming the active field in a oneof union).
inline void UnsafeSetDefault(const std::string* default_value);
// Returns a mutable pointer, but doesn't initialize the string to the
// default value.
std::string* MutableNoArenaNoDefault(const std::string* default_value);
// Get a mutable pointer with unspecified contents.
// Similar to `MutableNoArenaNoDefault`, but also handles the arena case.
// If the value was donated, the contents are discarded.
std::string* MutableNoCopy(const std::string* default_value,
::google::protobuf::Arena* arena);
// Destroy the string. Assumes `arena == nullptr`.
inline void DestroyNoArena(const ::std::string* default_value) {
if (ptr_ != default_value) {
delete ptr_;
}
}
// Internal accessor used only at parse time to provide direct access to the
// raw pointer from the shared parse routine (in the non-arenas case). The
// parse routine does the string allocation in order to save code size in the
// generated parsing code.
inline ::std::string** UnsafeRawStringPointer() { return &ptr_; }
inline bool IsDefault(const ::std::string* default_value) const {
return ptr_ == default_value;
}
void DestroyNoArena(const std::string* default_value);
// Internal accessors!!!!
void UnsafeSetTaggedPointer(TaggedPtr< ::std::string> value) {
ptr_ = value.Get();
// Internal setter used only at parse time to directly set a donated string
// value.
void UnsafeSetTaggedPointer(TaggedPtr<std::string> value) {
tagged_ptr_ = value;
}
// Generated code only! An optimization, in certain cases the generated
// code is certain we can obtain a string with no default checks and
// code is certain we can obtain a std::string with no default checks and
// tag tests.
::std::string* UnsafeMutablePointer() { return ptr_; }
std::string* UnsafeMutablePointer() PROTOBUF_RETURNS_NONNULL;
inline bool IsDefault(const std::string* default_value) const {
// Relies on the fact that kPtrTagString == 0, so if IsString(), ptr_ is the
// actual std::string pointer (and if !IsString(), ptr_ will never be equal
// to any aligned |default_value| pointer). The key is that we want to avoid
// masking in the fastpath const-pointer Get() case for non-arena code.
return tagged_ptr_.UnsafeGet() == default_value;
}
private:
::std::string* ptr_;
TaggedPtr<std::string> tagged_ptr_;
bool IsDonatedString() const { return false; }
// Slow paths.
PROTOBUF_NOINLINE
void CreateInstance(Arena* arena, const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
// uses "new ::std::string" when arena is nullptr
ptr_ = Arena::Create< ::std::string>(arena, *initial_value);
// MutableSlow requires that !IsString() || IsDefault
// Variadic to support 0 args for EmptyDefault and 1 arg for LazyString.
template <typename... Lazy>
std::string* MutableSlow(::google::protobuf::Arena* arena, const Lazy&... lazy_default);
};
inline void ArenaStringPtr::UnsafeSetDefault(const std::string* value) {
tagged_ptr_.Set(const_cast<std::string*>(value));
}
inline void ArenaStringPtr::Swap(ArenaStringPtr* other,
const std::string* default_value,
Arena* arena) {
#ifndef NDEBUG
// For debug builds, we swap the contents of the string, rather than the
// std::string instances themselves. This invalidates previously taken const
// references that are (per our documentation) invalidated by calling Swap()
// on the message.
//
// If both strings are the default_value, swapping is uninteresting.
// Otherwise, we use ArenaStringPtr::Mutable() to access the std::string, to
// ensure that we do not try to mutate default_value itself.
if (IsDefault(default_value) && other->IsDefault(default_value)) {
return;
}
PROTOBUF_NOINLINE
void CreateInstanceNoArena(const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
ptr_ = new ::std::string(*initial_value);
if (default_value == nullptr) {
// If we have non-empty default, then `default_value` is null and we can't
// call Mutable the same way. Just do the regular swap.
std::swap(tagged_ptr_, other->tagged_ptr_);
} else {
std::string* this_ptr = Mutable(EmptyDefault{}, arena);
std::string* other_ptr = other->Mutable(EmptyDefault{}, arena);
this_ptr->swap(*other_ptr);
}
};
#else
std::swap(tagged_ptr_, other->tagged_ptr_);
#endif
}
inline void ArenaStringPtr::ClearNonDefaultToEmpty() {
// Unconditionally mask away the tag.
tagged_ptr_.Get()->clear();
}
inline std::string* ArenaStringPtr::MutableNoArenaNoDefault(
const std::string* default_value) {
// VERY IMPORTANT for performance and code size: this will reduce to a member
// variable load, a pointer check (against |default_value|, in practice a
// static global) and a branch to the slowpath (which calls operator new and
// the ctor). DO NOT add any tagged-pointer operations here.
if (IsDefault(default_value)) {
std::string* new_string = new std::string();
tagged_ptr_.Set(new_string);
return new_string;
} else {
return UnsafeMutablePointer();
}
}
inline void ArenaStringPtr::DestroyNoArena(const std::string* default_value) {
if (!IsDefault(default_value)) {
delete UnsafeMutablePointer();
}
}
inline std::string* ArenaStringPtr::UnsafeMutablePointer() {
GOOGLE_DCHECK(!tagged_ptr_.IsTagged());
GOOGLE_DCHECK(tagged_ptr_.UnsafeGet() != nullptr);
return tagged_ptr_.UnsafeGet();
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_ARENASTRING_H__

@ -28,8 +28,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Based on mvels@'s frankenstring.
#include <google/protobuf/arenastring.h>
#include <algorithm>
@ -42,6 +40,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/generated_message_util.h>
#include <gtest/gtest.h>
#include <google/protobuf/stubs/strutil.h>
@ -53,82 +52,119 @@ using internal::ArenaStringPtr;
static std::string WrapString(const char* value) { return value; }
using EmptyDefault = ArenaStringPtr::EmptyDefault;
const internal::LazyString nonempty_default{{{"default", 7}}, {nullptr}};
// Test ArenaStringPtr with arena == NULL.
TEST(ArenaStringPtrTest, ArenaStringPtrOnHeap) {
ArenaStringPtr field;
std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(std::string("default"), field.Get());
field.Set(&default_value, WrapString("Test short"), NULL);
const std::string* empty_default = &internal::GetEmptyString();
field.UnsafeSetDefault(empty_default);
EXPECT_EQ(std::string(""), field.Get());
field.Set(empty_default, WrapString("Test short"), NULL);
EXPECT_EQ(std::string("Test short"), field.Get());
field.Set(&default_value, WrapString("Test long long long long value"), NULL);
field.Set(empty_default, WrapString("Test long long long long value"), NULL);
EXPECT_EQ(std::string("Test long long long long value"), field.Get());
field.Set(&default_value, std::string(""), NULL);
field.Destroy(&default_value, NULL);
field.Set(empty_default, std::string(""), NULL);
field.Destroy(empty_default, NULL);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
std::string* mut = field2.Mutable(&default_value, NULL);
EXPECT_EQ(mut, field2.Mutable(&default_value, NULL));
field2.UnsafeSetDefault(empty_default);
std::string* mut = field2.Mutable(EmptyDefault{}, NULL);
EXPECT_EQ(mut, field2.Mutable(EmptyDefault{}, NULL));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(std::string("default"), *mut);
EXPECT_NE(empty_default, mut);
EXPECT_EQ(std::string(""), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, NULL);
field2.Destroy(empty_default, NULL);
ArenaStringPtr field3;
field3.UnsafeSetDefault(nullptr);
mut = field3.Mutable(nonempty_default, NULL);
EXPECT_EQ(mut, field3.Mutable(nonempty_default, NULL));
EXPECT_EQ(mut, &field3.Get());
EXPECT_NE(nullptr, mut);
EXPECT_EQ(std::string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field3.Get());
field3.Destroy(nullptr, NULL);
}
TEST(ArenaStringPtrTest, ArenaStringPtrOnArena) {
Arena arena;
ArenaStringPtr field;
std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(std::string("default"), field.Get());
field.Set(&default_value, WrapString("Test short"), &arena);
const std::string* empty_default = &internal::GetEmptyString();
field.UnsafeSetDefault(empty_default);
EXPECT_EQ(std::string(""), field.Get());
field.Set(empty_default, WrapString("Test short"), &arena);
EXPECT_EQ(std::string("Test short"), field.Get());
field.Set(&default_value, WrapString("Test long long long long value"),
field.Set(empty_default, WrapString("Test long long long long value"),
&arena);
EXPECT_EQ(std::string("Test long long long long value"), field.Get());
field.Set(&default_value, std::string(""), &arena);
field.Destroy(&default_value, &arena);
field.Set(empty_default, std::string(""), &arena);
field.Destroy(empty_default, &arena);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
std::string* mut = field2.Mutable(&default_value, &arena);
EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
field2.UnsafeSetDefault(empty_default);
std::string* mut = field2.Mutable(EmptyDefault{}, &arena);
EXPECT_EQ(mut, field2.Mutable(EmptyDefault{}, &arena));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(std::string("default"), *mut);
EXPECT_NE(empty_default, mut);
EXPECT_EQ(std::string(""), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, &arena);
field2.Destroy(empty_default, &arena);
ArenaStringPtr field3;
field3.UnsafeSetDefault(nullptr);
mut = field3.Mutable(nonempty_default, &arena);
EXPECT_EQ(mut, field3.Mutable(nonempty_default, &arena));
EXPECT_EQ(mut, &field3.Get());
EXPECT_NE(nullptr, mut);
EXPECT_EQ(std::string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field3.Get());
field3.Destroy(nullptr, &arena);
}
TEST(ArenaStringPtrTest, ArenaStringPtrOnArenaNoSSO) {
Arena arena;
ArenaStringPtr field;
std::string default_value = "default";
field.UnsafeSetDefault(&default_value);
EXPECT_EQ(std::string("default"), field.Get());
const std::string* empty_default = &internal::GetEmptyString();
field.UnsafeSetDefault(empty_default);
EXPECT_EQ(std::string(""), field.Get());
// Avoid triggering the SSO optimization by setting the string to something
// larger than the internal buffer.
field.Set(&default_value, WrapString("Test long long long long value"),
field.Set(empty_default, WrapString("Test long long long long value"),
&arena);
EXPECT_EQ(std::string("Test long long long long value"), field.Get());
field.Set(&default_value, std::string(""), &arena);
field.Destroy(&default_value, &arena);
field.Set(empty_default, std::string(""), &arena);
field.Destroy(empty_default, &arena);
ArenaStringPtr field2;
field2.UnsafeSetDefault(&default_value);
std::string* mut = field2.Mutable(&default_value, &arena);
EXPECT_EQ(mut, field2.Mutable(&default_value, &arena));
field2.UnsafeSetDefault(empty_default);
std::string* mut = field2.Mutable(EmptyDefault{}, &arena);
EXPECT_EQ(mut, field2.Mutable(EmptyDefault{}, &arena));
EXPECT_EQ(mut, &field2.Get());
EXPECT_NE(&default_value, mut);
EXPECT_EQ(std::string("default"), *mut);
EXPECT_NE(empty_default, mut);
EXPECT_EQ(std::string(""), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field2.Get());
field2.Destroy(&default_value, &arena);
field2.Destroy(empty_default, &arena);
ArenaStringPtr field3;
field3.UnsafeSetDefault(nullptr);
mut = field3.Mutable(nonempty_default, &arena);
EXPECT_EQ(mut, field3.Mutable(nonempty_default, &arena));
EXPECT_EQ(mut, &field3.Get());
EXPECT_NE(nullptr, mut);
EXPECT_EQ(std::string("default"), *mut);
*mut = "Test long long long long value"; // ensure string allocates storage
EXPECT_EQ(std::string("Test long long long long value"), field3.Get());
field3.Destroy(nullptr, &arena);
}

@ -1224,6 +1224,7 @@ bool CommandLineInterface::AllowProto3Optional(
return false;
}
bool CommandLineInterface::VerifyInputFilesInDescriptors(
DescriptorDatabase* database) {
for (const auto& input_file : input_files_) {
@ -1242,6 +1243,7 @@ bool CommandLineInterface::VerifyInputFilesInDescriptors(
<< std::endl;
return false;
}
}
return true;
}
@ -1292,6 +1294,7 @@ bool CommandLineInterface::ParseInputFiles(
break;
}
// Enforce --direct_dependencies
if (direct_dependencies_explicitly_set_) {
bool indirect_imports = false;
@ -1338,6 +1341,7 @@ void CommandLineInterface::Clear() {
disallow_services_ = false;
direct_dependencies_explicitly_set_ = false;
allow_proto3_optional_ = false;
deterministic_output_ = false;
}
bool CommandLineInterface::MakeProtoProtoPathRelative(
@ -1573,6 +1577,11 @@ CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments(
<< std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (mode_ != MODE_ENCODE && deterministic_output_) {
std::cerr << "Can only use --deterministic_output with --encode."
<< std::endl;
return PARSE_ARGUMENT_FAIL;
}
if (!dependency_out_name_.empty() && input_files_.size() > 1) {
std::cerr
<< "Can only process one input file when using --dependency_out=FILE."
@ -1641,7 +1650,8 @@ bool CommandLineInterface::ParseArgument(const char* arg, std::string* name,
*name == "--include_imports" || *name == "--include_source_info" ||
*name == "--version" || *name == "--decode_raw" ||
*name == "--print_free_field_numbers" ||
*name == "--experimental_allow_proto3_optional") {
*name == "--experimental_allow_proto3_optional" ||
*name == "--deterministic_output") {
// HACK: These are the only flags that don't take a value.
// They probably should not be hard-coded like this but for now it's
// not worth doing better.
@ -1848,6 +1858,7 @@ CommandLineInterface::InterpretArgument(const std::string& name,
} else if (name == "--disallow_services") {
disallow_services_ = true;
} else if (name == "--experimental_allow_proto3_optional") {
allow_proto3_optional_ = true;
@ -1881,6 +1892,9 @@ CommandLineInterface::InterpretArgument(const std::string& name,
codec_type_ = value;
} else if (name == "--deterministic_output") {
deterministic_output_ = true;
} else if (name == "--error_format") {
if (value == "gcc") {
error_format_ = ERROR_FORMAT_GCC;
@ -2023,6 +2037,12 @@ void CommandLineInterface::PrintHelpText() {
"must\n"
" be defined in PROTO_FILES or their "
"imports.\n"
" --deterministic_output When using --encode, ensure map fields "
"are\n"
" deterministically ordered. Note that"
"this order is not\n"
" canonical, and changes across builds"
"or releases of protoc.\n"
" --decode=MESSAGE_TYPE Read a binary message of the given "
"type from\n"
" standard input and write it in text "
@ -2435,7 +2455,9 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
if (mode_ == MODE_ENCODE) {
// Output is binary.
if (!message->SerializePartialToZeroCopyStream(&out)) {
io::CodedOutputStream coded_out(&out);
coded_out.SetSerializationDeterministic(deterministic_output_);
if (!message->SerializePartialToCodedStream(&coded_out)) {
std::cerr << "output: I/O error." << std::endl;
return false;
}

@ -451,6 +451,9 @@ class PROTOC_EXPORT CommandLineInterface {
// Was the --experimental_allow_proto3_optional flag used?
bool allow_proto3_optional_ = false;
// When using --encode, this will be passed to SetSerializationDeterministic.
bool deterministic_output_ = false;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface);
};

@ -40,6 +40,7 @@
#include <unistd.h>
#endif
#include <memory>
#include <string>
#include <vector>
#include <google/protobuf/stubs/stringprintf.h>
@ -59,10 +60,10 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/testing/googletest.h>
#include <gtest/gtest.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/io/io_win32.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
namespace protobuf {
@ -1387,6 +1388,7 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) {
ExpectGenerated("test_generator", "", "foo.proto", "Foo");
}
TEST_F(CommandLineInterfaceTest, DirectDependencies_Missing_EmptyList) {
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
@ -2567,7 +2569,10 @@ class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
bool Run(const std::string& command, bool specify_proto_files = true) {
std::vector<std::string> args;
args.push_back("protoc");
SplitStringUsing(command, " ", &args);
for (StringPiece split_piece :
Split(command, " ", true)) {
args.push_back(std::string(split_piece));
}
if (specify_proto_files) {
switch (GetParam()) {
case PROTO_PATH:
@ -2726,6 +2731,32 @@ TEST_P(EncodeDecodeTest, ProtoParseError) {
"net/proto2/internal/no_such_file.proto: No such file or directory\n");
}
TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) {
RedirectStdinFromFile(TestUtil::GetTestDataPath(
"net/proto2/internal/"
"testdata/text_format_unittest_data_oneof_implemented.txt"));
std::string args;
if (GetParam() != DESCRIPTOR_SET_IN) {
args.append(
TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto"));
}
EXPECT_TRUE(Run(
args + " --encode=protobuf_unittest.TestAllTypes --deterministic_output"));
ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath(
"net/proto2/internal/testdata/golden_message_oneof_implemented"));
ExpectStderrMatchesText("");
}
TEST_P(EncodeDecodeTest, DecodeDeterministicOutput) {
RedirectStdinFromFile(TestUtil::GetTestDataPath(
"net/proto2/internal/testdata/golden_message_oneof_implemented"));
EXPECT_FALSE(
Run(TestUtil::MaybeTranslatePath("net/proto2/internal/unittest.proto") +
" --decode=protobuf_unittest.TestAllTypes --deterministic_output"));
ExpectStderrMatchesText(
"Can only use --deterministic_output with --encode.\n");
}
INSTANTIATE_TEST_SUITE_P(FileDescriptorSetSource, EncodeDecodeTest,
testing::Values(PROTO_PATH, DESCRIPTOR_SET_IN));
} // anonymous namespace

@ -178,11 +178,6 @@ class FieldGenerator {
// are placed in the message's ByteSize() method.
virtual void GenerateByteSize(io::Printer* printer) const = 0;
// Any tags about field layout decisions (such as inlining) to embed in the
// offset.
virtual uint32 CalculateFieldTag() const { return 0; }
virtual bool IsInlined() const { return false; }
void SetHasBitIndex(int32 has_bit_index);
protected:

@ -1198,7 +1198,6 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
decls[Namespace(d, options_)].AddEnum(d);
}
{
NamespaceOpener ns(format);
for (const auto& pair : decls) {
@ -1281,7 +1280,6 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) {
IncludeFile("net/proto2/public/arenastring.h", printer);
IncludeFile("net/proto2/public/generated_message_table_driven.h", printer);
IncludeFile("net/proto2/public/generated_message_util.h", printer);
IncludeFile("net/proto2/public/inlined_string_field.h", printer);
IncludeFile("net/proto2/public/metadata_lite.h", printer);
if (HasDescriptorMethods(file_, options_)) {

@ -787,25 +787,6 @@ std::string SafeFunctionName(const Descriptor* descriptor,
return function_name;
}
bool IsStringInlined(const FieldDescriptor* descriptor,
const Options& options) {
if (options.opensource_runtime) return false;
// TODO(ckennelly): Handle inlining for any.proto.
if (IsAnyMessage(descriptor->containing_type(), options)) return false;
if (descriptor->containing_type()->options().map_entry()) return false;
// We rely on has bits to distinguish field presence for release_$name$. When
// there is no hasbit, we cannot use the address of the string instance when
// the field has been inlined.
if (!HasHasbit(descriptor)) return false;
if (options.access_info_map) {
if (descriptor->is_required()) return true;
}
return false;
}
static bool HasLazyFields(const Descriptor* descriptor,
const Options& options) {
for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) {
@ -1470,8 +1451,7 @@ class ParseLoopGenerator {
GetOptimizeFor(field->file(), options_) != FileOptions::LITE_RUNTIME &&
// For now only use arena string for strings with empty defaults.
field->default_value_string().empty() &&
!IsStringInlined(field, options_) && !field->real_containing_oneof() &&
ctype == FieldOptions::STRING) {
!field->real_containing_oneof() && ctype == FieldOptions::STRING) {
GenerateArenaString(field);
} else {
std::string name;

@ -318,8 +318,6 @@ inline bool IsWeak(const FieldDescriptor* field, const Options& options) {
return false;
}
bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
// For a string field, returns the effective ctype. If the actual ctype is
// not supported, returns the default of STRING.
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
@ -410,14 +408,6 @@ inline bool IsProto2MessageSet(const Descriptor* descriptor,
descriptor->full_name() == "google.protobuf.bridge.MessageSet";
}
inline bool IsProto2MessageSetFile(const FileDescriptor* file,
const Options& options) {
return !options.opensource_runtime &&
options.enforce_mode != EnforceOptimizeMode::kLiteRuntime &&
!options.lite_implicit_weak_fields &&
file->name() == "net/proto2/bridge/proto/message_set.proto";
}
inline bool IsMapEntryMessage(const Descriptor* descriptor) {
return descriptor->options().map_entry();
}

@ -1699,9 +1699,6 @@ uint32 CalcFieldNum(const FieldGenerator& generator,
int type = field->type();
if (type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
if (generator.IsInlined()) {
type = internal::FieldMetadata::kInlinedType;
}
// string field
if (IsCord(field, options)) {
type = internal::FieldMetadata::kCordType;
@ -2111,14 +2108,9 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
}
processing_type = static_cast<unsigned>(field->type());
const FieldGenerator& generator = field_generators_.get(field);
if (field->type() == FieldDescriptor::TYPE_STRING) {
switch (EffectiveStringCType(field, options_)) {
case FieldOptions::STRING:
if (generator.IsInlined()) {
processing_type = internal::TYPE_STRING_INLINED;
break;
}
break;
case FieldOptions::CORD:
processing_type = internal::TYPE_STRING_CORD;
@ -2130,10 +2122,6 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) {
} else if (field->type() == FieldDescriptor::TYPE_BYTES) {
switch (EffectiveStringCType(field, options_)) {
case FieldOptions::STRING:
if (generator.IsInlined()) {
processing_type = internal::TYPE_BYTES_INLINED;
break;
}
break;
case FieldOptions::CORD:
processing_type = internal::TYPE_BYTES_CORD;
@ -2317,11 +2305,6 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field));
}
uint32 tag = field_generators_.get(field).CalculateFieldTag();
if (tag != 0) {
format(" | $1$", tag);
}
if (!IsFieldUsed(field, options_)) {
format(" | 0x80000000u, // unused\n");
} else {

@ -55,12 +55,31 @@ void SetStringVariables(const FieldDescriptor* descriptor,
StrCat(descriptor->default_value_string().length());
std::string default_variable_string = MakeDefaultName(descriptor);
(*variables)["default_variable_name"] = default_variable_string;
(*variables)["default_variable"] =
if (!descriptor->default_value_string().empty()) {
(*variables)["lazy_variable"] =
QualifiedClassName(descriptor->containing_type(), options) +
"::" + default_variable_string;
}
(*variables)["default_string"] =
descriptor->default_value_string().empty()
? "::" + (*variables)["proto_ns"] +
"::internal::GetEmptyStringAlreadyInited()"
: (*variables)["lazy_variable"] + ".get()";
(*variables)["init_value"] =
descriptor->default_value_string().empty()
? "&::" + (*variables)["proto_ns"] +
"::internal::GetEmptyStringAlreadyInited()"
: "&" + QualifiedClassName(descriptor->containing_type(), options) +
"::" + default_variable_string + ".get()";
: "nullptr";
(*variables)["default_value_tag"] =
"::" + (*variables)["proto_ns"] + "::internal::ArenaStringPtr::" +
(descriptor->default_value_string().empty() ? "Empty" : "NonEmpty") +
"Default{}";
(*variables)["default_variable_or_tag"] =
(*variables)[descriptor->default_value_string().empty()
? "default_value_tag"
: "lazy_variable"];
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
(*variables)["null_check"] = (*variables)["DCHK"] + "(value != nullptr);\n";
@ -75,9 +94,6 @@ void SetStringVariables(const FieldDescriptor* descriptor,
} else {
(*variables)["string_piece"] = "::StringPiece";
}
(*variables)["lite"] =
HasDescriptorMethods(descriptor->file(), options) ? "" : "Lite";
}
} // namespace
@ -86,9 +102,7 @@ void SetStringVariables(const FieldDescriptor* descriptor,
StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
const Options& options)
: FieldGenerator(descriptor, options),
lite_(!HasDescriptorMethods(descriptor->file(), options)),
inlined_(IsStringInlined(descriptor, options)) {
: FieldGenerator(descriptor, options) {
SetStringVariables(descriptor, &variables_, options);
}
@ -96,23 +110,15 @@ StringFieldGenerator::~StringFieldGenerator() {}
void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
Formatter format(printer, variables_);
if (inlined_) {
format("::$proto_ns$::internal::InlinedStringField $name$_;\n");
} else {
format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
}
format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
}
void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
Formatter format(printer, variables_);
if (!descriptor_->default_value_string().empty()) {
// We make the default instance public, so it can be initialized by
// non-friend code.
format(
"public:\n"
"static ::$proto_ns$::internal::ExplicitlyConstructed<std::string>"
" $default_variable_name$;\n"
"private:\n");
"static const ::$proto_ns$::internal::LazyString"
" $default_variable_name$;\n");
}
}
@ -187,7 +193,13 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
format(
"inline const std::string& $classname$::$name$() const {\n"
"$annotate_accessor$"
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" // @@protoc_insertion_point(field_get:$full_name$)\n");
if (!descriptor_->default_value_string().empty()) {
format(
" if ($name$_.IsDefault(nullptr)) return "
"$default_variable_name$.get();\n");
}
format(
" return _internal_$name$();\n"
"}\n"
"inline void $classname$::set_$name$(const std::string& value) {\n"
@ -206,21 +218,20 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
"inline void $classname$::_internal_set_$name$(const std::string& "
"value) {\n"
" $set_hasbit$\n"
" $name$_.Set$lite$($default_variable$, value, GetArena());\n"
" $name$_.Set($default_value_tag$, value, GetArena());\n"
"}\n"
"inline void $classname$::set_$name$(std::string&& value) {\n"
"$annotate_accessor$"
" $set_hasbit$\n"
" $name$_.Set$lite$(\n"
" $default_variable$, ::std::move(value), GetArena());\n"
" $name$_.Set(\n"
" $default_value_tag$, ::std::move(value), GetArena());\n"
" // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
"}\n"
"inline void $classname$::set_$name$(const char* value) {\n"
"$annotate_accessor$"
" $null_check$"
" $set_hasbit$\n"
" $name$_.Set$lite$($default_variable$, $string_piece$(value),\n"
" GetArena());\n"
" $name$_.Set($default_value_tag$, $string_piece$(value), GetArena());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n");
if (!options_.opensource_runtime) {
@ -228,7 +239,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
"inline void $classname$::set_$name$(::StringPiece value) {\n"
"$annotate_accessor$"
" $set_hasbit$\n"
" $name$_.Set$lite$($default_variable$, value,GetArena());\n"
" $name$_.Set($default_value_tag$, value,GetArena());\n"
" // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
"}\n");
}
@ -238,13 +249,13 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
" size_t size) {\n"
"$annotate_accessor$"
" $set_hasbit$\n"
" $name$_.Set$lite$($default_variable$, $string_piece$(\n"
" $name$_.Set($default_value_tag$, $string_piece$(\n"
" reinterpret_cast<const char*>(value), size), GetArena());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
"}\n"
"inline std::string* $classname$::_internal_mutable_$name$() {\n"
" $set_hasbit$\n"
" return $name$_.Mutable($default_variable$, GetArena());\n"
" return $name$_.Mutable($default_variable_or_tag$, GetArena());\n"
"}\n"
"inline std::string* $classname$::$release_name$() {\n"
"$annotate_accessor$"
@ -256,10 +267,9 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
" return nullptr;\n"
" }\n"
" $clear_hasbit$\n"
" return $name$_.ReleaseNonDefault("
"$default_variable$, GetArena());\n");
" return $name$_.ReleaseNonDefault($init_value$, GetArena());\n");
} else {
format(" return $name$_.Release($default_variable$, GetArena());\n");
format(" return $name$_.Release($init_value$, GetArena());\n");
}
format(
@ -271,7 +281,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
" } else {\n"
" $clear_hasbit$\n"
" }\n"
" $name$_.SetAllocated($default_variable$, $name$,\n"
" $name$_.SetAllocated($init_value$, $name$,\n"
" GetArena());\n"
" // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
"}\n");
@ -281,23 +291,19 @@ void StringFieldGenerator::GenerateNonInlineAccessorDefinitions(
io::Printer* printer) const {
Formatter format(printer, variables_);
if (!descriptor_->default_value_string().empty()) {
// Initialized in GenerateDefaultInstanceAllocator.
format(
"::$proto_ns$::internal::ExplicitlyConstructed<std::string> "
"$classname$::$default_variable_name$;\n");
"const ::$proto_ns$::internal::LazyString "
"$classname$::$default_variable_name$"
"{{{$default$, $default_length$}}, {nullptr}};\n");
}
}
void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
// Two-dimension specialization here: supporting arenas or not, and default
// value is the empty string or not. Complexity here ensures the minimal
// number of branches / amount of extraneous code at runtime (given that the
// below methods are inlined one-liners)!
if (descriptor_->default_value_string().empty()) {
format("$name$_.ClearToEmpty($default_variable$, GetArena());\n");
format("$name$_.ClearToEmpty();\n");
} else {
format("$name$_.ClearToDefault($default_variable$, GetArena());\n");
format("$name$_.ClearToDefault($lazy_variable$, GetArena());\n");
}
}
@ -311,31 +317,19 @@ void StringFieldGenerator::GenerateMessageClearingCode(
// If we have a hasbit, then the Clear() method of the protocol buffer
// will have checked that this field is set. If so, we can avoid redundant
// checks against default_variable.
// checks against the default variable.
const bool must_be_present = HasHasbit(descriptor_);
if (inlined_ && must_be_present) {
// Calling mutable_$name$() gives us a string reference and sets the has bit
// for $name$ (in proto2). We may get here when the string field is inlined
// but the string's contents have not been changed by the user, so we cannot
// make an assertion about the contents of the string and could never make
// an assertion about the string instance.
//
// For non-inlined strings, we distinguish from non-default by comparing
// instances, rather than contents.
format("$DCHK$(!$name$_.IsDefault($default_variable$));\n");
}
if (descriptor_->default_value_string().empty()) {
if (must_be_present) {
format("$name$_.ClearNonDefaultToEmpty();\n");
} else {
format("$name$_.ClearToEmpty($default_variable$, GetArena());\n");
format("$name$_.ClearToEmpty();\n");
}
} else {
// Clear to a non-empty default is more involved, as we try to use the
// Arena if one is present and may need to reallocate the string.
format("$name$_.ClearToDefault($default_variable$, GetArena());\n");
format("$name$_.ClearToDefault($lazy_variable$, GetArena());\n ");
}
}
@ -347,23 +341,12 @@ void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
Formatter format(printer, variables_);
if (inlined_) {
format("$name$_.Swap(&other->$name$_);\n");
} else {
format("$name$_.Swap(&other->$name$_, $default_variable$, GetArena());\n");
}
format("$name$_.Swap(&other->$name$_, $init_value$, GetArena());\n");
}
void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
Formatter format(printer, variables_);
// TODO(ckennelly): Construct non-empty strings as part of the initializer
// list.
if (inlined_ && descriptor_->default_value_string().empty()) {
// Automatic initialization will construct the string.
return;
}
format("$name$_.UnsafeSetDefault($default_variable$);\n");
format("$name$_.UnsafeSetDefault($init_value$);\n");
}
void StringFieldGenerator::GenerateCopyConstructorCode(
@ -381,7 +364,7 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
// TODO(gpike): improve this
format(
"$name$_.Set$lite$($default_variable$, from._internal_$name$(),\n"
"$name$_.Set($default_value_tag$, from._internal_$name$(), \n"
" GetArena());\n");
format.Outdent();
@ -390,40 +373,7 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
Formatter format(printer, variables_);
if (inlined_) {
// The destructor is automatically invoked.
return;
}
format("$name$_.DestroyNoArena($default_variable$);\n");
}
bool StringFieldGenerator::GenerateArenaDestructorCode(
io::Printer* printer) const {
Formatter format(printer, variables_);
if (!inlined_) {
return false;
}
format("_this->$name$_.DestroyNoArena($default_variable$);\n");
return true;
}
void StringFieldGenerator::GenerateDefaultInstanceAllocator(
io::Printer* printer) const {
Formatter format(printer, variables_);
if (!descriptor_->default_value_string().empty()) {
format(
"$ns$::$classname$::$default_variable_name$.DefaultConstruct();\n"
"*$ns$::$classname$::$default_variable_name$.get_mutable() = "
"std::string($default$, $default_length$);\n"
"::$proto_ns$::internal::OnShutdownDestroyString(\n"
" $ns$::$classname$::$default_variable_name$.get_mutable());\n");
}
}
bool StringFieldGenerator::MergeFromCodedStreamNeedsArena() const {
return !lite_ && !inlined_ && !options_.opensource_runtime;
format("$name$_.DestroyNoArena($init_value$);\n");
}
void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
@ -449,17 +399,11 @@ void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
" this->_internal_$name$());\n");
}
uint32 StringFieldGenerator::CalculateFieldTag() const {
return inlined_ ? 1 : 0;
}
// ===================================================================
StringOneofFieldGenerator::StringOneofFieldGenerator(
const FieldDescriptor* descriptor, const Options& options)
: StringFieldGenerator(descriptor, options) {
inlined_ = false;
SetCommonOneofFieldVariables(descriptor, &variables_);
variables_["field_name"] = UnderscoresToCamelCase(descriptor->name(), true);
variables_["oneof_index"] =
@ -491,16 +435,16 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (_internal_has_$name$()) {\n"
" return $field_member$.Get();\n"
" }\n"
" return *$default_variable$;\n"
" return $default_string$;\n"
"}\n"
"inline void $classname$::_internal_set_$name$(const std::string& "
"value) {\n"
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" $field_member$.Set$lite$($default_variable$, value, GetArena());\n"
" $field_member$.Set($default_value_tag$, value, GetArena());\n"
"}\n"
"inline void $classname$::set_$name$(std::string&& value) {\n"
"$annotate_accessor$"
@ -508,10 +452,10 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" $field_member$.Set$lite$(\n"
" $default_variable$, ::std::move(value), GetArena());\n"
" $field_member$.Set(\n"
" $default_value_tag$, ::std::move(value), GetArena());\n"
" // @@protoc_insertion_point(field_set_rvalue:$full_name$)\n"
"}\n"
"inline void $classname$::set_$name$(const char* value) {\n"
@ -520,9 +464,9 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" $field_member$.Set$lite$($default_variable$,\n"
" $field_member$.Set($default_value_tag$,\n"
" $string_piece$(value), GetArena());\n"
" // @@protoc_insertion_point(field_set_char:$full_name$)\n"
"}\n");
@ -533,10 +477,9 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" $field_member$.Set$lite$($default_variable$, value,\n"
" GetArena());\n"
" $field_member$.Set($default_value_tag$, value, GetArena());\n"
" // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
"}\n");
}
@ -548,10 +491,10 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" $field_member$.Set$lite$(\n"
" $default_variable$, $string_piece$(\n"
" $field_member$.Set(\n"
" $default_value_tag$, $string_piece$(\n"
" reinterpret_cast<const char*>(value), size),\n"
" GetArena());\n"
" // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
@ -560,16 +503,17 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
" if (!_internal_has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" $field_member$.UnsafeSetDefault($default_variable$);\n"
" $field_member$.UnsafeSetDefault($init_value$);\n"
" }\n"
" return $field_member$.Mutable($default_variable$, GetArena());\n"
" return $field_member$.Mutable(\n"
" $default_variable_or_tag$, GetArena());\n"
"}\n"
"inline std::string* $classname$::$release_name$() {\n"
"$annotate_accessor$"
" // @@protoc_insertion_point(field_release:$full_name$)\n"
" if (_internal_has_$name$()) {\n"
" clear_has_$oneof_name$();\n"
" return $field_member$.Release($default_variable$, GetArena());\n"
" return $field_member$.ReleaseNonDefault($init_value$, GetArena());\n"
" } else {\n"
" return nullptr;\n"
" }\n"
@ -594,7 +538,7 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
void StringOneofFieldGenerator::GenerateClearingCode(
io::Printer* printer) const {
Formatter format(printer, variables_);
format("$field_member$.Destroy($default_variable$, GetArena());\n");
format("$field_member$.Destroy($default_value_tag$, GetArena());\n");
}
void StringOneofFieldGenerator::GenerateMessageClearingCode(
@ -609,10 +553,7 @@ void StringOneofFieldGenerator::GenerateSwappingCode(
void StringOneofFieldGenerator::GenerateConstructorCode(
io::Printer* printer) const {
Formatter format(printer, variables_);
format(
"$ns$::_$classname$_default_instance_.$name$_.UnsafeSetDefault(\n"
" $default_variable$);\n");
// Nothing required here.
}
// ===================================================================

@ -63,18 +63,8 @@ class StringFieldGenerator : public FieldGenerator {
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateCopyConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
bool GenerateArenaDestructorCode(io::Printer* printer) const;
void GenerateDefaultInstanceAllocator(io::Printer* printer) const;
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
void GenerateByteSize(io::Printer* printer) const;
uint32 CalculateFieldTag() const;
bool IsInlined() const { return inlined_; }
bool MergeFromCodedStreamNeedsArena() const;
protected:
const bool lite_;
bool inlined_;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);

@ -81,7 +81,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
// with v2.5.0/v2.6.1, and remove the @SuppressWarnings annotations.
(*variables)["for_number"] = "valueOf";
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
@ -145,7 +145,7 @@ ImmutableEnumFieldGenerator::ImmutableEnumFieldGenerator(
ImmutableEnumFieldGenerator::~ImmutableEnumFieldGenerator() {}
int ImmutableEnumFieldGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
int ImmutableEnumFieldGenerator::GetNumBitsForBuilder() const {

@ -83,7 +83,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, int messageBitIndex,
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
@ -137,7 +137,7 @@ ImmutableEnumFieldLiteGenerator::ImmutableEnumFieldLiteGenerator(
ImmutableEnumFieldLiteGenerator::~ImmutableEnumFieldLiteGenerator() {}
int ImmutableEnumFieldLiteGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
void ImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers(

@ -1355,7 +1355,6 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) {
}
}
void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) {
printer->Print(
"private static String getTypeUrl(\n"

@ -133,7 +133,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
}
(*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
@ -195,7 +195,7 @@ ImmutablePrimitiveFieldGenerator::ImmutablePrimitiveFieldGenerator(
ImmutablePrimitiveFieldGenerator::~ImmutablePrimitiveFieldGenerator() {}
int ImmutablePrimitiveFieldGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
int ImmutablePrimitiveFieldGenerator::GetNumBitsForBuilder() const {

@ -140,7 +140,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["fixed_size"] = StrCat(fixed_size);
}
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
@ -188,7 +188,7 @@ ImmutablePrimitiveFieldLiteGenerator::ImmutablePrimitiveFieldLiteGenerator(
ImmutablePrimitiveFieldLiteGenerator::~ImmutablePrimitiveFieldLiteGenerator() {}
int ImmutablePrimitiveFieldLiteGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
void ImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers(

@ -90,7 +90,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
(*variables)["on_changed"] = "onChanged();";
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex);
@ -147,7 +147,7 @@ ImmutableStringFieldGenerator::ImmutableStringFieldGenerator(
ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {}
int ImmutableStringFieldGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const {

@ -85,7 +85,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
descriptor->options().deprecated() ? "@java.lang.Deprecated " : "";
(*variables)["required"] = descriptor->is_required() ? "true" : "false";
if (SupportFieldPresence(descriptor)) {
if (HasHasbit(descriptor)) {
// For singular messages and builders, one bit is used for the hasField bit.
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex);
@ -127,7 +127,7 @@ ImmutableStringFieldLiteGenerator::ImmutableStringFieldLiteGenerator(
ImmutableStringFieldLiteGenerator::~ImmutableStringFieldLiteGenerator() {}
int ImmutableStringFieldLiteGenerator::GetNumBitsForMessage() const {
return SupportFieldPresence(descriptor_) ? 1 : 0;
return HasHasbit(descriptor_) ? 1 : 0;
}
// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes,

@ -119,7 +119,7 @@ void MockCodeGenerator::ExpectGenerated(
std::vector<std::string> insertion_list;
if (!insertions.empty()) {
SplitStringUsing(insertions, ",", &insertion_list);
insertion_list = Split(insertions, ",", true);
}
EXPECT_EQ(lines.size(), 3 + insertion_list.size() * 2);
@ -250,12 +250,10 @@ bool MockCodeGenerator::Generate(const FileDescriptor* file,
bool insert_endlines = HasPrefixString(parameter, "insert_endlines=");
if (insert_endlines || HasPrefixString(parameter, "insert=")) {
std::vector<std::string> insert_into;
SplitStringUsing(
std::vector<std::string> insert_into = Split(
StripPrefixString(
parameter, insert_endlines ? "insert_endlines=" : "insert="),
",", &insert_into);
",", true);
for (size_t i = 0; i < insert_into.size(); i++) {
{

@ -260,7 +260,7 @@ Version::Version(const Version& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
suffix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_suffix()) {
suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_suffix(),
suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_suffix(),
GetArena());
}
::memcpy(&major_, &from.major_,
@ -592,7 +592,7 @@ CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
parameter_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_parameter()) {
parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_parameter(),
parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_parameter(),
GetArena());
}
if (from._internal_has_compiler_version()) {
@ -944,17 +944,17 @@ CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorRespon
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
insertion_point_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_insertion_point()) {
insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_insertion_point(),
insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_insertion_point(),
GetArena());
}
content_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_content()) {
content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_content(),
content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_content(),
GetArena());
}
if (from._internal_has_generated_code_info()) {
@ -1299,7 +1299,7 @@ CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
error_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_error()) {
error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_error(),
error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_error(),
GetArena());
}
supported_features_ = from.supported_features_;

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>
@ -1076,7 +1075,7 @@ inline bool Version::has_suffix() const {
return _internal_has_suffix();
}
inline void Version::clear_suffix() {
suffix_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
suffix_.ClearToEmpty();
_has_bits_[0] &= ~0x00000001u;
}
inline const std::string& Version::suffix() const {
@ -1096,31 +1095,30 @@ inline const std::string& Version::_internal_suffix() const {
}
inline void Version::_internal_set_suffix(const std::string& value) {
_has_bits_[0] |= 0x00000001u;
suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void Version::set_suffix(std::string&& value) {
_has_bits_[0] |= 0x00000001u;
suffix_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.Version.suffix)
}
inline void Version::set_suffix(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000001u;
suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.Version.suffix)
}
inline void Version::set_suffix(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000001u;
suffix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
suffix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.Version.suffix)
}
inline std::string* Version::_internal_mutable_suffix() {
_has_bits_[0] |= 0x00000001u;
return suffix_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return suffix_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* Version::release_suffix() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.Version.suffix)
@ -1228,7 +1226,7 @@ inline bool CodeGeneratorRequest::has_parameter() const {
return _internal_has_parameter();
}
inline void CodeGeneratorRequest::clear_parameter() {
parameter_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
parameter_.ClearToEmpty();
_has_bits_[0] &= ~0x00000001u;
}
inline const std::string& CodeGeneratorRequest::parameter() const {
@ -1248,31 +1246,30 @@ inline const std::string& CodeGeneratorRequest::_internal_parameter() const {
}
inline void CodeGeneratorRequest::_internal_set_parameter(const std::string& value) {
_has_bits_[0] |= 0x00000001u;
parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void CodeGeneratorRequest::set_parameter(std::string&& value) {
_has_bits_[0] |= 0x00000001u;
parameter_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
inline void CodeGeneratorRequest::set_parameter(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000001u;
parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
inline void CodeGeneratorRequest::set_parameter(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000001u;
parameter_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
parameter_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.parameter)
}
inline std::string* CodeGeneratorRequest::_internal_mutable_parameter() {
_has_bits_[0] |= 0x00000001u;
return parameter_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return parameter_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* CodeGeneratorRequest::release_parameter() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter)
@ -1425,7 +1422,7 @@ inline bool CodeGeneratorResponse_File::has_name() const {
return _internal_has_name();
}
inline void CodeGeneratorResponse_File::clear_name() {
name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
name_.ClearToEmpty();
_has_bits_[0] &= ~0x00000001u;
}
inline const std::string& CodeGeneratorResponse_File::name() const {
@ -1445,31 +1442,30 @@ inline const std::string& CodeGeneratorResponse_File::_internal_name() const {
}
inline void CodeGeneratorResponse_File::_internal_set_name(const std::string& value) {
_has_bits_[0] |= 0x00000001u;
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void CodeGeneratorResponse_File::set_name(std::string&& value) {
_has_bits_[0] |= 0x00000001u;
name_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
inline void CodeGeneratorResponse_File::set_name(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000001u;
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
inline void CodeGeneratorResponse_File::set_name(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000001u;
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.name)
}
inline std::string* CodeGeneratorResponse_File::_internal_mutable_name() {
_has_bits_[0] |= 0x00000001u;
return name_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* CodeGeneratorResponse_File::release_name() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name)
@ -1499,7 +1495,7 @@ inline bool CodeGeneratorResponse_File::has_insertion_point() const {
return _internal_has_insertion_point();
}
inline void CodeGeneratorResponse_File::clear_insertion_point() {
insertion_point_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
insertion_point_.ClearToEmpty();
_has_bits_[0] &= ~0x00000002u;
}
inline const std::string& CodeGeneratorResponse_File::insertion_point() const {
@ -1519,31 +1515,30 @@ inline const std::string& CodeGeneratorResponse_File::_internal_insertion_point(
}
inline void CodeGeneratorResponse_File::_internal_set_insertion_point(const std::string& value) {
_has_bits_[0] |= 0x00000002u;
insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void CodeGeneratorResponse_File::set_insertion_point(std::string&& value) {
_has_bits_[0] |= 0x00000002u;
insertion_point_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
}
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000002u;
insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
}
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000002u;
insertion_point_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
insertion_point_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
}
inline std::string* CodeGeneratorResponse_File::_internal_mutable_insertion_point() {
_has_bits_[0] |= 0x00000002u;
return insertion_point_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return insertion_point_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* CodeGeneratorResponse_File::release_insertion_point() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point)
@ -1573,7 +1568,7 @@ inline bool CodeGeneratorResponse_File::has_content() const {
return _internal_has_content();
}
inline void CodeGeneratorResponse_File::clear_content() {
content_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
content_.ClearToEmpty();
_has_bits_[0] &= ~0x00000004u;
}
inline const std::string& CodeGeneratorResponse_File::content() const {
@ -1593,31 +1588,30 @@ inline const std::string& CodeGeneratorResponse_File::_internal_content() const
}
inline void CodeGeneratorResponse_File::_internal_set_content(const std::string& value) {
_has_bits_[0] |= 0x00000004u;
content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void CodeGeneratorResponse_File::set_content(std::string&& value) {
_has_bits_[0] |= 0x00000004u;
content_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
inline void CodeGeneratorResponse_File::set_content(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000004u;
content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
inline void CodeGeneratorResponse_File::set_content(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000004u;
content_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
content_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.File.content)
}
inline std::string* CodeGeneratorResponse_File::_internal_mutable_content() {
_has_bits_[0] |= 0x00000004u;
return content_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return content_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* CodeGeneratorResponse_File::release_content() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content)
@ -1730,7 +1724,7 @@ inline bool CodeGeneratorResponse::has_error() const {
return _internal_has_error();
}
inline void CodeGeneratorResponse::clear_error() {
error_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
error_.ClearToEmpty();
_has_bits_[0] &= ~0x00000001u;
}
inline const std::string& CodeGeneratorResponse::error() const {
@ -1750,31 +1744,30 @@ inline const std::string& CodeGeneratorResponse::_internal_error() const {
}
inline void CodeGeneratorResponse::_internal_set_error(const std::string& value) {
_has_bits_[0] |= 0x00000001u;
error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void CodeGeneratorResponse::set_error(std::string&& value) {
_has_bits_[0] |= 0x00000001u;
error_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.compiler.CodeGeneratorResponse.error)
}
inline void CodeGeneratorResponse::set_error(const char* value) {
GOOGLE_DCHECK(value != nullptr);
_has_bits_[0] |= 0x00000001u;
error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.compiler.CodeGeneratorResponse.error)
}
inline void CodeGeneratorResponse::set_error(const char* value,
size_t size) {
_has_bits_[0] |= 0x00000001u;
error_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
error_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorResponse.error)
}
inline std::string* CodeGeneratorResponse::_internal_mutable_error() {
_has_bits_[0] |= 0x00000001u;
return error_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return error_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* CodeGeneratorResponse::release_error() {
// @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error)

@ -4052,7 +4052,8 @@ bool DescriptorBuilder::AddSymbol(const std::string& full_name,
// Symbol seems to have been defined in a different file.
AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME,
"\"" + full_name + "\" is already defined in file \"" +
other_file->name() + "\".");
(other_file == nullptr ? "null" : other_file->name()) +
"\".");
}
return false;
}

@ -1604,17 +1604,17 @@ FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_package()) {
package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_package(),
package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_package(),
GetArena());
}
syntax_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_syntax()) {
syntax_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_syntax(),
syntax_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_syntax(),
GetArena());
}
if (from._internal_has_options()) {
@ -2803,7 +2803,7 @@ DescriptorProto::DescriptorProto(const DescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -3582,27 +3582,27 @@ FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
extendee_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_extendee()) {
extendee_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_extendee(),
extendee_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_extendee(),
GetArena());
}
type_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_type_name()) {
type_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_type_name(),
type_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_type_name(),
GetArena());
}
default_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_default_value()) {
default_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_default_value(),
default_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_default_value(),
GetArena());
}
json_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_json_name()) {
json_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_json_name(),
json_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_json_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -4183,7 +4183,7 @@ OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -4719,7 +4719,7 @@ EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -5097,7 +5097,7 @@ EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProt
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -5410,7 +5410,7 @@ ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& fro
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
if (from._internal_has_options()) {
@ -5730,17 +5730,17 @@ MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name()) {
name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name(),
name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name(),
GetArena());
}
input_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_input_type()) {
input_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_input_type(),
input_type_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_input_type(),
GetArena());
}
output_type_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_output_type()) {
output_type_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_output_type(),
output_type_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_output_type(),
GetArena());
}
if (from._internal_has_options()) {
@ -6202,52 +6202,52 @@ FileOptions::FileOptions(const FileOptions& from)
_extensions_.MergeFrom(from._extensions_);
java_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_java_package()) {
java_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_java_package(),
java_package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_java_package(),
GetArena());
}
java_outer_classname_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_java_outer_classname()) {
java_outer_classname_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_java_outer_classname(),
java_outer_classname_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_java_outer_classname(),
GetArena());
}
go_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_go_package()) {
go_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_go_package(),
go_package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_go_package(),
GetArena());
}
objc_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_objc_class_prefix()) {
objc_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_objc_class_prefix(),
objc_class_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_objc_class_prefix(),
GetArena());
}
csharp_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_csharp_namespace()) {
csharp_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_csharp_namespace(),
csharp_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_csharp_namespace(),
GetArena());
}
swift_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_swift_prefix()) {
swift_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_swift_prefix(),
swift_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_swift_prefix(),
GetArena());
}
php_class_prefix_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_php_class_prefix()) {
php_class_prefix_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_php_class_prefix(),
php_class_prefix_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_class_prefix(),
GetArena());
}
php_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_php_namespace()) {
php_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_php_namespace(),
php_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_namespace(),
GetArena());
}
php_metadata_namespace_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_php_metadata_namespace()) {
php_metadata_namespace_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_php_metadata_namespace(),
php_metadata_namespace_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_php_metadata_namespace(),
GetArena());
}
ruby_package_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_ruby_package()) {
ruby_package_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_ruby_package(),
ruby_package_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_ruby_package(),
GetArena());
}
::memcpy(&java_multiple_files_, &from.java_multiple_files_,
@ -9249,7 +9249,7 @@ UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOp
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
name_part_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_name_part()) {
name_part_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_name_part(),
name_part_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_name_part(),
GetArena());
}
is_extension_ = from.is_extension_;
@ -9536,17 +9536,17 @@ UninterpretedOption::UninterpretedOption(const UninterpretedOption& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
identifier_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_identifier_value()) {
identifier_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_identifier_value(),
identifier_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_identifier_value(),
GetArena());
}
string_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_string_value()) {
string_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_string_value(),
string_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_string_value(),
GetArena());
}
aggregate_value_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_aggregate_value()) {
aggregate_value_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_aggregate_value(),
aggregate_value_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_aggregate_value(),
GetArena());
}
::memcpy(&positive_int_value_, &from.positive_int_value_,
@ -9970,12 +9970,12 @@ SourceCodeInfo_Location::SourceCodeInfo_Location(const SourceCodeInfo_Location&
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
leading_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_leading_comments()) {
leading_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_leading_comments(),
leading_comments_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_leading_comments(),
GetArena());
}
trailing_comments_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_trailing_comments()) {
trailing_comments_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_trailing_comments(),
trailing_comments_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_trailing_comments(),
GetArena());
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.SourceCodeInfo.Location)
@ -10560,7 +10560,7 @@ GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeIn
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
source_file_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (from._internal_has_source_file()) {
source_file_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_source_file(),
source_file_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_source_file(),
GetArena());
}
::memcpy(&begin_, &from.begin_,

File diff suppressed because it is too large Load Diff

@ -37,7 +37,6 @@
#include <set>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>

@ -187,9 +187,6 @@ class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
bool FindAllFileNames(std::vector<std::string>* output) override;
private:
// So that it can use DescriptorIndex.
friend class EncodedDescriptorDatabase;
// An index mapping file names, symbol names, and extension numbers to
// some sort of values.
template <typename Value>

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>

@ -432,15 +432,10 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING:
if (!field->is_repeated()) {
const std::string* default_value;
if (is_prototype()) {
default_value = &field->default_value_string();
} else {
default_value = &(reinterpret_cast<const ArenaStringPtr*>(
type_info_->prototype->OffsetToPointer(
type_info_->offsets[i]))
->Get());
}
const std::string* default_value =
field->default_value_string().empty()
? &internal::GetEmptyStringAlreadyInited()
: nullptr;
ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
asp->UnsafeSetDefault(default_value);
} else {
@ -523,10 +518,10 @@ DynamicMessage::~DynamicMessage() {
default:
case FieldOptions::STRING: {
const std::string* default_value =
&(reinterpret_cast<const ArenaStringPtr*>(
reinterpret_cast<const uint8*>(type_info_->prototype) +
type_info_->offsets[i])
->Get());
reinterpret_cast<const ArenaStringPtr*>(
reinterpret_cast<const uint8*>(type_info_->prototype) +
type_info_->offsets[i])
->GetPointer();
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(
default_value, NULL);
break;
@ -583,10 +578,10 @@ DynamicMessage::~DynamicMessage() {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
const std::string* default_value =
&(reinterpret_cast<const ArenaStringPtr*>(
type_info_->prototype->OffsetToPointer(
type_info_->offsets[i]))
->Get());
reinterpret_cast<const ArenaStringPtr*>(
type_info_->prototype->OffsetToPointer(
type_info_->offsets[i]))
->GetPointer();
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value,
NULL);
break;

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>

@ -43,7 +43,6 @@
#include <google/protobuf/descriptor.h>
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/map_field.h>
#include <google/protobuf/map_field_inl.h>
#include <google/protobuf/stubs/mutex.h>
@ -62,7 +61,6 @@ using google::protobuf::internal::DescriptorTable;
using google::protobuf::internal::ExtensionSet;
using google::protobuf::internal::GenericTypeHandler;
using google::protobuf::internal::GetEmptyString;
using google::protobuf::internal::InlinedStringField;
using google::protobuf::internal::InternalMetadata;
using google::protobuf::internal::LazyField;
using google::protobuf::internal::MapFieldBase;
@ -313,15 +311,8 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
if (IsInlined(field)) {
const std::string* ptr =
&GetField<InlinedStringField>(message, field).GetNoArena();
total_size += StringSpaceUsedExcludingSelfLong(*ptr);
break;
}
const std::string* ptr =
&GetField<ArenaStringPtr>(message, field).Get();
GetField<ArenaStringPtr>(message, field).GetPointer();
// Initially, the string points to the default value stored
// in the prototype. Only count the string if it has been
@ -329,7 +320,7 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
// Except oneof fields, those never point to a default instance,
// and there is no default instance to point to.
if (schema_.InRealOneof(field) ||
ptr != &DefaultRaw<ArenaStringPtr>(field).Get()) {
ptr != DefaultRaw<ArenaStringPtr>(field).GetPointer()) {
// string fields are represented by just a pointer, so also
// include sizeof(string) as well.
total_size +=
@ -450,27 +441,27 @@ void Reflection::SwapField(Message* message1, Message* message2,
Arena* arena1 = GetArena(message1);
Arena* arena2 = GetArena(message2);
if (IsInlined(field)) {
InlinedStringField* string1 =
MutableRaw<InlinedStringField>(message1, field);
InlinedStringField* string2 =
MutableRaw<InlinedStringField>(message2, field);
string1->Swap(string2);
break;
}
ArenaStringPtr* string1 =
MutableRaw<ArenaStringPtr>(message1, field);
ArenaStringPtr* string2 =
MutableRaw<ArenaStringPtr>(message2, field);
const std::string* default_ptr =
&DefaultRaw<ArenaStringPtr>(field).Get();
DefaultRaw<ArenaStringPtr>(field).GetPointer();
if (arena1 == arena2) {
string1->Swap(string2, default_ptr, arena1);
} else if (string1->IsDefault(default_ptr) &&
string2->IsDefault(default_ptr)) {
// Nothing to do.
} else if (string1->IsDefault(default_ptr)) {
string1->Set(default_ptr, string2->Get(), arena1);
string2->UnsafeSetDefault(default_ptr);
} else if (string2->IsDefault(default_ptr)) {
string2->Set(default_ptr, string1->Get(), arena2);
string1->UnsafeSetDefault(default_ptr);
} else {
const std::string temp = string1->Get();
std::string temp = string1->Get();
string1->Set(default_ptr, string2->Get(), arena1);
string2->Set(default_ptr, temp, arena2);
string2->Set(default_ptr, std::move(temp), arena2);
}
} break;
}
@ -834,16 +825,8 @@ void Reflection::ClearField(Message* message,
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
if (IsInlined(field)) {
const std::string* default_ptr =
&DefaultRaw<InlinedStringField>(field).GetNoArena();
MutableRaw<InlinedStringField>(message, field)
->SetNoArena(default_ptr, *default_ptr);
break;
}
const std::string* default_ptr =
&DefaultRaw<ArenaStringPtr>(field).Get();
DefaultRaw<ArenaStringPtr>(field).GetPointer();
MutableRaw<ArenaStringPtr>(message, field)
->SetAllocated(default_ptr, nullptr, GetArena(message));
break;
@ -1197,11 +1180,11 @@ std::string Reflection::GetString(const Message& message,
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena();
if (auto* value =
GetField<ArenaStringPtr>(message, field).GetPointer()) {
return *value;
}
return GetField<ArenaStringPtr>(message, field).Get();
return field->default_value_string();
}
}
}
@ -1221,11 +1204,11 @@ const std::string& Reflection::GetStringReference(const Message& message,
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena();
if (auto* value =
GetField<ArenaStringPtr>(message, field).GetPointer()) {
return *value;
}
return GetField<ArenaStringPtr>(message, field).Get();
return field->default_value_string();
}
}
}
@ -1242,20 +1225,14 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
case FieldOptions::STRING: {
if (IsInlined(field)) {
MutableField<InlinedStringField>(message, field)
->SetNoArena(nullptr, std::move(value));
break;
}
// Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it work.
// This allows us to not have the real default accessible from
// reflection.
const std::string* default_ptr =
schema_.InRealOneof(field)
? &GetEmptyString()
: &DefaultRaw<ArenaStringPtr>(field).Get();
? nullptr
: DefaultRaw<ArenaStringPtr>(field).GetPointer();
if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof());
MutableField<ArenaStringPtr>(message, field)
@ -1968,10 +1945,6 @@ const Type& Reflection::GetRaw(const Message& message,
return GetConstRefAtOffset<Type>(message, schema_.GetFieldOffset(field));
}
bool Reflection::IsInlined(const FieldDescriptor* field) const {
return schema_.IsFieldInlined(field);
}
template <typename Type>
Type* Reflection::MutableRaw(Message* message,
const FieldDescriptor* field) const {
@ -2058,11 +2031,6 @@ bool Reflection::HasBit(const Message& message,
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: {
if (IsInlined(field)) {
return !GetField<InlinedStringField>(message, field)
.GetNoArena()
.empty();
}
return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
}
}
@ -2175,9 +2143,8 @@ void Reflection::ClearOneof(Message* message,
// We just need to pass some arbitrary default string to make it
// work. This allows us to not have the real default accessible
// from reflection.
const std::string* default_ptr = &GetEmptyString();
MutableField<ArenaStringPtr>(message, field)
->Destroy(default_ptr, GetArena(message));
->Destroy(nullptr, GetArena(message));
break;
}
}

@ -42,8 +42,6 @@
#include <vector>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
// TODO(jasonh): Remove this once the compiler change to directly include this
// is released to components.
#include <google/protobuf/descriptor.h>
#include <google/protobuf/generated_enum_reflection.h>
#include <google/protobuf/stubs/once.h>
@ -59,7 +57,6 @@
namespace google {
namespace protobuf {
class DescriptorPool;
class MapKey;
class MapValueRef;
class MessageLayoutInspector;
@ -148,17 +145,6 @@ struct ReflectionSchema {
}
}
bool IsFieldInlined(const FieldDescriptor* field) const {
if (InRealOneof(field)) {
size_t offset =
static_cast<size_t>(field->containing_type()->field_count() +
field->containing_oneof()->index());
return Inlined(offsets_[offset], field->type());
} else {
return Inlined(offsets_[field->index()], field->type());
}
}
uint32 GetOneofCaseOffset(const OneofDescriptor* oneof_descriptor) const {
return static_cast<uint32>(oneof_case_offset_) +
static_cast<uint32>(static_cast<size_t>(oneof_descriptor->index()) *
@ -215,14 +201,17 @@ struct ReflectionSchema {
// Returns true if the field's accessor is called by any external code (aka,
// non proto library code).
bool IsFieldUsed(const FieldDescriptor* /* field */) const {
(void)field;
return true;
}
bool IsFieldStripped(const FieldDescriptor* /* field */) const {
(void)field;
return false;
}
bool IsMessageStripped(const Descriptor* /* descriptor */) const {
(void)descriptor;
return false;
}
@ -246,25 +235,9 @@ struct ReflectionSchema {
int weak_field_map_offset_;
// We tag offset values to provide additional data about fields (such as
// inlined).
// "unused").
static uint32 OffsetValue(uint32 v, FieldDescriptor::Type type) {
v &= 0x7FFFFFFFu;
if (type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
return v & ~1u;
} else {
return v;
}
}
static bool Inlined(uint32 v, FieldDescriptor::Type type) {
if (type == FieldDescriptor::TYPE_STRING ||
type == FieldDescriptor::TYPE_BYTES) {
return v & 1u;
} else {
// Non string/byte fields are not inlined.
return false;
}
return v & 0x7FFFFFFFu;
}
};

@ -73,9 +73,7 @@ enum ProcessingTypes {
TYPE_STRING_STRING_PIECE = 20,
TYPE_BYTES_CORD = 21,
TYPE_BYTES_STRING_PIECE = 22,
TYPE_STRING_INLINED = 23,
TYPE_BYTES_INLINED = 24,
TYPE_MAP = 25,
TYPE_MAP = 23,
};
static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
@ -106,8 +104,7 @@ struct PROTOBUF_EXPORT FieldMetadata {
enum {
kCordType = 19,
kStringPieceType = 20,
kInlinedType = 21,
kNumTypes = 21,
kNumTypes = 20,
kSpecial = kNumTypes * kNumTypeClasses,
};

@ -35,7 +35,6 @@
#include <google/protobuf/extension_set.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/implicit_weak_message.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/wire_format_lite.h>
#include <type_traits>
@ -50,7 +49,6 @@ namespace internal {
enum StringType {
StringType_STRING = 0,
StringType_INLINED = 3
};
// Logically a superset of StringType, consisting of all field types that
@ -59,8 +57,7 @@ enum ProcessingType {
ProcessingType_STRING = 0,
ProcessingType_CORD = 1,
ProcessingType_STRING_PIECE = 2,
ProcessingType_INLINED = 3,
ProcessingType_MESSAGE = 4,
ProcessingType_MESSAGE = 3,
};
enum Cardinality {
@ -90,8 +87,7 @@ inline ExtensionSet* GetExtensionSet(MessageLite* msg, int64 extension_offset) {
template <typename Type>
inline Type* AddField(MessageLite* msg, int64 offset) {
static_assert(std::is_pod<Type>::value ||
std::is_same<Type, InlinedStringField>::value,
static_assert(std::is_pod<Type>::value,
"Do not assign");
RepeatedField<Type>* repeated = Raw<RepeatedField<Type>>(msg, offset);
@ -157,12 +153,7 @@ inline void ClearOneofField(const ParseTableField& field, Arena* arena,
case WireFormatLite::TYPE_STRING:
case WireFormatLite::TYPE_BYTES:
Raw<ArenaStringPtr>(msg, field.offset)
->Destroy(&GetEmptyStringAlreadyInited(), arena);
break;
case TYPE_STRING_INLINED:
case TYPE_BYTES_INLINED:
Raw<InlinedStringField>(msg, field.offset)->DestroyNoArena(NULL);
->Destroy(ArenaStringPtr::EmptyDefault{}, arena);
break;
default:
@ -197,10 +188,6 @@ inline void ResetOneofField(const ParseTable& table, int field_number,
Raw<ArenaStringPtr>(msg, offset)
->UnsafeSetDefault(static_cast<const std::string*>(default_ptr));
break;
case ProcessingType_INLINED:
new (Raw<InlinedStringField>(msg, offset))
InlinedStringField(*static_cast<const std::string*>(default_ptr));
break;
case ProcessingType_MESSAGE:
MessageLite** submessage = Raw<MessageLite*>(msg, offset);
const MessageLite* prototype =
@ -225,35 +212,12 @@ static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
switch (ctype) {
case StringType_INLINED: {
InlinedStringField* s = nullptr;
switch (cardinality) {
case Cardinality_SINGULAR:
// TODO(ckennelly): Is this optimal?
s = MutableField<InlinedStringField>(msg, has_bits, has_bit_index,
offset);
break;
case Cardinality_REPEATED:
s = AddField<InlinedStringField>(msg, offset);
break;
case Cardinality_ONEOF:
s = Raw<InlinedStringField>(msg, offset);
break;
}
GOOGLE_DCHECK(s != nullptr);
std::string* value = s->MutableNoArena(NULL);
if (PROTOBUF_PREDICT_FALSE(!WireFormatLite::ReadString(input, value))) {
return false;
}
utf8_string_data = *value;
break;
}
case StringType_STRING: {
switch (cardinality) {
case Cardinality_SINGULAR: {
ArenaStringPtr* field = MutableField<ArenaStringPtr>(
msg, has_bits, has_bit_index, offset);
std::string* value = field->Mutable(
std::string* value = field->MutableNoCopy(
static_cast<const std::string*>(default_ptr), arena);
if (PROTOBUF_PREDICT_FALSE(
!WireFormatLite::ReadString(input, value))) {
@ -271,7 +235,7 @@ static inline bool HandleString(io::CodedInputStream* input, MessageLite* msg,
} break;
case Cardinality_ONEOF: {
ArenaStringPtr* field = Raw<ArenaStringPtr>(msg, offset);
std::string* value = field->Mutable(
std::string* value = field->MutableNoCopy(
static_cast<const std::string*>(default_ptr), arena);
if (PROTOBUF_PREDICT_FALSE(
!WireFormatLite::ReadString(input, value))) {
@ -481,23 +445,6 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
}
break;
}
case TYPE_BYTES_INLINED:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED:
#endif // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena = msg->GetArena();
const void* default_ptr = table.aux[field_number].strings.default_ptr;
if (PROTOBUF_PREDICT_FALSE(
(!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
false, StringType_INLINED>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, nullptr)))) {
return false;
}
break;
}
case WireFormatLite::TYPE_BYTES | kOneofMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case WireFormatLite::TYPE_STRING | kOneofMask:
@ -521,10 +468,8 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
break;
}
case (WireFormatLite::TYPE_BYTES) | kRepeatedMask:
case TYPE_BYTES_INLINED | kRepeatedMask:
#ifndef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case (WireFormatLite::TYPE_STRING) | kRepeatedMask:
case TYPE_STRING_INLINED | kRepeatedMask:
#endif // !GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
{
Arena* const arena = msg->GetArena();
@ -554,7 +499,6 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
}
break;
}
case TYPE_STRING_INLINED | kRepeatedMask:
case (WireFormatLite::TYPE_STRING) | kRepeatedMask: {
Arena* const arena = msg->GetArena();
const void* default_ptr = table.aux[field_number].strings.default_ptr;
@ -712,22 +656,6 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
break;
}
#ifdef GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_STRING_INLINED: {
Arena* const arena = msg->GetArena();
const void* default_ptr = table.aux[field_number].strings.default_ptr;
const char* field_name = table.aux[field_number].strings.field_name;
if (PROTOBUF_PREDICT_FALSE(
(!HandleString<UnknownFieldHandler, Cardinality_SINGULAR,
true, StringType_INLINED>(
input, msg, arena, has_bits, presence_index, offset,
default_ptr, field_name)))) {
return false;
}
break;
}
#endif // GOOGLE_PROTOBUF_UTF8_VALIDATION_ENABLED
case TYPE_MAP: {
if (PROTOBUF_PREDICT_FALSE(!(*table.aux[field_number].maps.parse_map)(
input, Raw<void>(msg, offset)))) {
@ -750,8 +678,6 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
GOOGLE_DCHECK_NE(processing_type, kRepeatedMask);
GOOGLE_DCHECK_EQ(0, processing_type & kOneofMask);
GOOGLE_DCHECK_NE(TYPE_BYTES_INLINED | kRepeatedMask, processing_type);
GOOGLE_DCHECK_NE(TYPE_STRING_INLINED | kRepeatedMask, processing_type);
// Mask out kRepeatedMask bit, allowing the jump table to be smaller.
switch (static_cast<WireFormatLite::FieldType>(processing_type ^
@ -847,7 +773,7 @@ bool MergePartialFromCodedStreamInlined(MessageLite* msg,
}
}
}
}
} // NOLINT(readability/fn_size)
template <typename UnknownFieldHandler>
bool MergePartialFromCodedStreamImpl(MessageLite* msg, const ParseTable& table,

@ -246,10 +246,6 @@ struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
: PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
// We want to serialize to both CodedOutputStream and directly into byte arrays
// without duplicating the code. In fact we might want extra output channels in
// the future.
@ -408,15 +404,6 @@ struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
}
};
template <>
struct SingularFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
WriteTagTo(md.tag, output);
SerializeTo<FieldMetadata::kInlinedType>(&Get<std::string>(field), output);
}
};
template <int type>
struct RepeatedFieldHelper {
template <typename O>
@ -489,10 +476,6 @@ struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
};
template <>
struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
: RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct PackedFieldHelper {
template <typename O>
@ -528,9 +511,6 @@ struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
template <>
struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <>
struct PackedFieldHelper<FieldMetadata::kInlinedType>
: PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
template <int type>
struct OneOfFieldHelper {
@ -541,15 +521,6 @@ struct OneOfFieldHelper {
};
template <>
struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
template <typename O>
static void Serialize(const void* field, const FieldMetadata& md, O* output) {
SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
Get<const std::string*>(field), md, output);
}
};
void SerializeNotImplemented(int field) {
GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
}
@ -590,11 +561,6 @@ bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
}
template <>
bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
return static_cast<const std::string*>(ptr)->empty();
}
#define SERIALIZERS_FOR_TYPE(type) \
case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \
if (!IsPresent(base, field_metadata.has_offset)) continue; \
@ -642,7 +608,6 @@ void SerializeInternal(const uint8* base,
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial:
@ -687,7 +652,6 @@ uint8* SerializeInternalToArray(const uint8* base,
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
// Special cases
case FieldMetadata::kSpecial: {
io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);

@ -1,260 +0,0 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
#define GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__
#include <string>
#include <utility>
#include <google/protobuf/port.h>
#include <google/protobuf/stubs/strutil.h>
// Must be included last.
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
class Arena;
namespace internal {
// InlinedStringField wraps a std::string instance and exposes an API similar to
// ArenaStringPtr's wrapping of a std::string* instance. As std::string is
// never allocated on the Arena, we expose only the *NoArena methods of
// ArenaStringPtr.
//
// default_value parameters are taken for consistency with ArenaStringPtr, but
// are not used for most methods. With inlining, these should be removed from
// the generated binary.
class PROTOBUF_EXPORT InlinedStringField {
public:
InlinedStringField() PROTOBUF_ALWAYS_INLINE;
explicit InlinedStringField(const std::string& default_value);
void AssignWithDefault(const std::string* default_value,
const InlinedStringField& from) PROTOBUF_ALWAYS_INLINE;
void ClearToEmpty(const std::string* default_value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
ClearToEmptyNoArena(default_value);
}
void ClearNonDefaultToEmpty() PROTOBUF_ALWAYS_INLINE {
ClearNonDefaultToEmptyNoArena();
}
void ClearToEmptyNoArena(const std::string* /*default_value*/)
PROTOBUF_ALWAYS_INLINE {
ClearNonDefaultToEmptyNoArena();
}
void ClearNonDefaultToEmptyNoArena() PROTOBUF_ALWAYS_INLINE;
void ClearToDefault(const std::string* default_value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
ClearToDefaultNoArena(default_value);
}
void ClearToDefaultNoArena(const std::string* default_value)
PROTOBUF_ALWAYS_INLINE;
void Destroy(const std::string* default_value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
DestroyNoArena(default_value);
}
void DestroyNoArena(const std::string* default_value) PROTOBUF_ALWAYS_INLINE;
const std::string& Get() const PROTOBUF_ALWAYS_INLINE { return GetNoArena(); }
const std::string& GetNoArena() const PROTOBUF_ALWAYS_INLINE;
std::string* Mutable(const std::string* default_value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
return MutableNoArena(default_value);
}
std::string* MutableNoArena(const std::string* default_value)
PROTOBUF_ALWAYS_INLINE;
std::string* Release(const std::string* default_value, Arena* /*arena*/) {
return ReleaseNoArena(default_value);
}
std::string* ReleaseNonDefault(const std::string* default_value,
Arena* /*arena*/) {
return ReleaseNonDefaultNoArena(default_value);
}
std::string* ReleaseNoArena(const std::string* default_value) {
return ReleaseNonDefaultNoArena(default_value);
}
std::string* ReleaseNonDefaultNoArena(const std::string* default_value);
void Set(const std::string* default_value, StringPiece value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetLite(const std::string* default_value, StringPiece value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetNoArena(const std::string* default_value,
StringPiece value) PROTOBUF_ALWAYS_INLINE;
void Set(const std::string* default_value, const std::string& value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetLite(const std::string* default_value, const std::string& value,
Arena* /*arena*/) PROTOBUF_ALWAYS_INLINE {
SetNoArena(default_value, value);
}
void SetNoArena(const std::string* default_value,
const std::string& value) PROTOBUF_ALWAYS_INLINE;
void SetNoArena(const std::string* default_value,
std::string&& value) PROTOBUF_ALWAYS_INLINE;
void SetAllocated(const std::string* default_value, std::string* value,
Arena* /*arena*/) {
SetAllocatedNoArena(default_value, value);
}
void SetAllocatedNoArena(const std::string* default_value,
std::string* value);
void Swap(InlinedStringField* from) PROTOBUF_ALWAYS_INLINE;
std::string* UnsafeMutablePointer();
void UnsafeSetDefault(const std::string* default_value);
std::string* UnsafeArenaRelease(const std::string* default_value,
Arena* arena);
void UnsafeArenaSetAllocated(const std::string* default_value,
std::string* value, Arena* arena);
bool IsDefault(const std::string* /*default_value*/) { return false; }
private:
std::string value_;
};
inline InlinedStringField::InlinedStringField() {}
inline InlinedStringField::InlinedStringField(const std::string& default_value)
: value_(default_value) {}
inline void InlinedStringField::AssignWithDefault(
const std::string* /*default_value*/, const InlinedStringField& from) {
value_ = from.value_;
}
inline const std::string& InlinedStringField::GetNoArena() const {
return value_;
}
inline std::string* InlinedStringField::MutableNoArena(const std::string*) {
return &value_;
}
inline void InlinedStringField::SetAllocatedNoArena(
const std::string* default_value, std::string* value) {
if (value == NULL) {
value_.assign(*default_value);
} else {
value_.assign(std::move(*value));
delete value;
}
}
inline void InlinedStringField::DestroyNoArena(const std::string*) {
// This is invoked from the generated message's ArenaDtor, which is used to
// clean up objects not allocated on the Arena.
this->~InlinedStringField();
}
inline void InlinedStringField::ClearNonDefaultToEmptyNoArena() {
value_.clear();
}
inline void InlinedStringField::ClearToDefaultNoArena(
const std::string* default_value) {
value_.assign(*default_value);
}
inline std::string* InlinedStringField::ReleaseNonDefaultNoArena(
const std::string* default_value) {
std::string* released = new std::string(*default_value);
value_.swap(*released);
return released;
}
inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
StringPiece value) {
value_.assign(value.data(), value.length());
}
inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
const std::string& value) {
value_.assign(value);
}
inline void InlinedStringField::SetNoArena(const std::string* /*default_value*/,
std::string&& value) {
value_.assign(std::move(value));
}
inline void InlinedStringField::Swap(InlinedStringField* from) {
value_.swap(from->value_);
}
inline std::string* InlinedStringField::UnsafeMutablePointer() {
return &value_;
}
inline void InlinedStringField::UnsafeSetDefault(
const std::string* default_value) {
value_.assign(*default_value);
}
inline std::string* InlinedStringField::UnsafeArenaRelease(
const std::string* default_value, Arena* /*arena*/) {
return ReleaseNoArena(default_value);
}
inline void InlinedStringField::UnsafeArenaSetAllocated(
const std::string* default_value, std::string* value, Arena* /*arena*/) {
if (value == NULL) {
value_.assign(*default_value);
} else {
value_.assign(*value);
}
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_INLINED_STRING_FIELD_H__

@ -165,25 +165,14 @@ int FileInputStream::CopyingFileInputStream::Skip(int count) {
// ===================================================================
FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
: copying_output_(file_descriptor), impl_(&copying_output_, block_size) {}
FileOutputStream::~FileOutputStream() { impl_.Flush(); }
: CopyingOutputStreamAdaptor(&copying_output_),
copying_output_(file_descriptor) {}
bool FileOutputStream::Close() {
bool flush_succeeded = impl_.Flush();
bool flush_succeeded = Flush();
return copying_output_.Close() && flush_succeeded;
}
bool FileOutputStream::Flush() { return impl_.Flush(); }
bool FileOutputStream::Next(void** data, int* size) {
return impl_.Next(data, size);
}
void FileOutputStream::BackUp(int count) { impl_.BackUp(count); }
int64_t FileOutputStream::ByteCount() const { return impl_.ByteCount(); }
FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
int file_descriptor)
: file_(file_descriptor),
@ -191,6 +180,8 @@ FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
is_closed_(false),
errno_(0) {}
FileOutputStream::~FileOutputStream() { Flush(); }
FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
if (close_on_delete_) {
if (!Close()) {

@ -139,13 +139,14 @@ class PROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
// harming performance. Also, it's conceivable that FileOutputStream could
// someday be enhanced to use zero-copy file descriptors on OSs which
// support them.
class PROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
class PROTOBUF_EXPORT FileOutputStream : public CopyingOutputStreamAdaptor {
public:
// Creates a stream that writes to the given Unix file descriptor.
// If a block_size is given, it specifies the size of the buffers
// that should be returned by Next(). Otherwise, a reasonable default
// is used.
explicit FileOutputStream(int file_descriptor, int block_size = -1);
~FileOutputStream() override;
// Flushes any buffers and closes the underlying file. Returns false if
@ -153,11 +154,6 @@ class PROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
// Even if an error occurs, the file descriptor is closed when this returns.
bool Close();
// Flushes FileOutputStream's buffers but does not close the
// underlying file. No special measures are taken to ensure that
// underlying operating system file object is synchronized to disk.
bool Flush();
// By default, the file descriptor is not closed when the stream is
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
// This leaves no way for the caller to detect if close() fails. If
@ -171,11 +167,6 @@ class PROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
// fail.
int GetErrno() const { return copying_output_.GetErrno(); }
// implements ZeroCopyOutputStream ---------------------------------
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
private:
class PROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
public:
@ -202,7 +193,6 @@ class PROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
};
CopyingFileOutputStream copying_output_;
CopyingOutputStreamAdaptor impl_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
};

@ -342,6 +342,37 @@ int64_t CopyingOutputStreamAdaptor::ByteCount() const {
return position_ + buffer_used_;
}
bool CopyingOutputStreamAdaptor::WriteAliasedRaw(const void* data, int size) {
if (size >= buffer_size_) {
if (!Flush() || !copying_stream_->Write(data, size)) {
return false;
}
GOOGLE_DCHECK_EQ(buffer_used_, 0);
position_ += size;
return true;
}
void* out;
int out_size;
while (true) {
if (!Next(&out, &out_size)) {
return false;
}
if (size <= out_size) {
std::memcpy(out, data, size);
BackUp(out_size - size);
return true;
}
std::memcpy(out, data, out_size);
data = static_cast<const char*>(data) + out_size;
size -= out_size;
}
return true;
}
bool CopyingOutputStreamAdaptor::WriteBuffer() {
if (failed_) {
// Already failed on a previous write.

@ -307,6 +307,8 @@ class PROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
bool Next(void** data, int* size) override;
void BackUp(int count) override;
int64_t ByteCount() const override;
bool WriteAliasedRaw(const void* data, int size) override;
bool AllowsAliasing() const override { return true; }
private:
// Write the current buffer, if it is present.

@ -41,6 +41,8 @@
#include <google/protobuf/test_util_lite.h>
#include <google/protobuf/unittest_lite.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/wire_format_lite.h>
#include <gtest/gtest.h>
@ -1187,5 +1189,84 @@ TEST(Lite, AliasedEnum) {
EXPECT_EQ(protobuf_unittest::DupEnum::FOO2, value);
}
TEST(Lite, CodedInputStreamRollback) {
{
protobuf_unittest::TestAllTypesLite m;
m.set_optional_bytes(std::string(30, 'a'));
std::string serialized = m.SerializeAsString();
serialized += '\014';
serialized += std::string(3, ' ');
io::ArrayInputStream is(serialized.data(), serialized.size(),
serialized.size() - 6);
{
io::CodedInputStream cis(&is);
m.Clear();
m.MergePartialFromCodedStream(&cis);
EXPECT_TRUE(cis.LastTagWas(12));
EXPECT_FALSE(cis.ConsumedEntireMessage());
// Should leave is with 3 spaces;
}
const void* data;
int size;
ASSERT_TRUE(is.Next(&data, &size));
ASSERT_EQ(size, 3);
EXPECT_EQ(memcmp(data, " ", 3), 0);
}
{
protobuf_unittest::TestPackedTypesLite m;
constexpr int kCount = 30;
for (int i = 0; i < kCount; i++) m.add_packed_fixed32(i);
std::string serialized = m.SerializeAsString();
serialized += '\014';
serialized += std::string(3, ' ');
// Buffer breaks in middle of a fixed32.
io::ArrayInputStream is(serialized.data(), serialized.size(),
serialized.size() - 7);
{
io::CodedInputStream cis(&is);
m.Clear();
m.MergePartialFromCodedStream(&cis);
EXPECT_TRUE(cis.LastTagWas(12));
EXPECT_FALSE(cis.ConsumedEntireMessage());
// Should leave is with 3 spaces;
}
ASSERT_EQ(m.packed_fixed32_size(), kCount);
for (int i = 0; i < kCount; i++) EXPECT_EQ(m.packed_fixed32(i), i);
const void* data;
int size;
ASSERT_TRUE(is.Next(&data, &size));
ASSERT_EQ(size, 3);
EXPECT_EQ(memcmp(data, " ", 3), 0);
}
{
protobuf_unittest::TestPackedTypesLite m;
constexpr int kCount = 30;
// Make sure we output 2 byte varints
for (int i = 0; i < kCount; i++) m.add_packed_fixed32(128 + i);
std::string serialized = m.SerializeAsString();
serialized += '\014';
serialized += std::string(3, ' ');
// Buffer breaks in middle of a 2 byte varint.
io::ArrayInputStream is(serialized.data(), serialized.size(),
serialized.size() - 5);
{
io::CodedInputStream cis(&is);
m.Clear();
m.MergePartialFromCodedStream(&cis);
EXPECT_TRUE(cis.LastTagWas(12));
EXPECT_FALSE(cis.ConsumedEntireMessage());
// Should leave is with 3 spaces;
}
ASSERT_EQ(m.packed_fixed32_size(), kCount);
for (int i = 0; i < kCount; i++) EXPECT_EQ(m.packed_fixed32(i), i + 128);
const void* data;
int size;
ASSERT_TRUE(is.Next(&data, &size));
ASSERT_EQ(size, 3);
EXPECT_EQ(memcmp(data, " ", 3), 0);
}
}
} // namespace protobuf
} // namespace google

@ -337,6 +337,8 @@ struct MapPair {
MapPair(const Key& other_first, const T& other_second)
: first(other_first), second(other_second) {}
explicit MapPair(const Key& other_first) : first(other_first), second() {}
explicit MapPair(Key&& other_first)
: first(std::move(other_first)), second() {}
MapPair(const MapPair& other) : first(other.first), second(other.second) {}
~MapPair() {}
@ -685,7 +687,8 @@ class Map {
// Insert the key into the map, if not present. In that case, the value will
// be value initialized.
std::pair<iterator, bool> insert(const Key& k) {
template <typename K>
std::pair<iterator, bool> insert(K&& k) {
std::pair<const_iterator, size_type> p = FindHelper(k);
// Case 1: key was already present.
if (p.first.node_ != nullptr)
@ -696,12 +699,18 @@ class Map {
}
const size_type b = p.second; // bucket number
Node* node;
// If K is not key_type, make the conversion to key_type explicit.
using TypeToInit = typename std::conditional<
std::is_same<typename std::decay<K>::type, key_type>::value, K&&,
key_type>::type;
if (alloc_.arena() == nullptr) {
node = new Node{value_type(k), nullptr};
node = new Node{value_type(static_cast<TypeToInit>(std::forward<K>(k))),
nullptr};
} else {
node = Alloc<Node>(1);
Arena::CreateInArenaStorage(const_cast<Key*>(&node->kv.first),
alloc_.arena(), k);
Arena::CreateInArenaStorage(
const_cast<Key*>(&node->kv.first), alloc_.arena(),
static_cast<TypeToInit>(std::forward<K>(k)));
Arena::CreateInArenaStorage(&node->kv.second, alloc_.arena());
}
@ -710,7 +719,10 @@ class Map {
return std::make_pair(result, true);
}
value_type& operator[](const Key& k) { return *insert(k).first; }
template <typename K>
value_type& operator[](K&& k) {
return *insert(std::forward<K>(k)).first;
}
void erase(iterator it) {
GOOGLE_DCHECK_EQ(it.m_, this);
@ -1183,7 +1195,17 @@ class Map {
bool empty() const { return size() == 0; }
// Element access
T& operator[](const key_type& key) { return elements_[key].second; }
template <typename K = key_type>
T& operator[](const key_arg<K>& key) {
return elements_[key].second;
}
template <
typename K = key_type,
// Disable for integral types to reduce code bloat.
typename = typename std::enable_if<!std::is_integral<K>::value>::type>
T& operator[](key_arg<K>&& key) {
return elements_[std::forward<K>(key)].second;
}
template <typename K = key_type>
const T& at(const key_arg<K>& key) const {

@ -194,6 +194,62 @@ TEST_F(MapImplTest, OperatorBracket) {
ExpectSingleElement(key, value2);
}
struct MoveTestKey {
MoveTestKey(int data, int* copies) : data(data), copies(copies) {}
MoveTestKey(const MoveTestKey& other)
: data(other.data), copies(other.copies) {
++*copies;
}
MoveTestKey(MoveTestKey&& other) noexcept
: data(other.data), copies(other.copies) {}
friend bool operator==(const MoveTestKey& lhs, const MoveTestKey& rhs) {
return lhs.data == rhs.data;
}
friend bool operator<(const MoveTestKey& lhs, const MoveTestKey& rhs) {
return lhs.data < rhs.data;
}
int data;
int* copies;
};
} // namespace
} // namespace internal
} // namespace protobuf
} // namespace google
namespace std {
template <> // NOLINT
struct hash<google::protobuf::internal::MoveTestKey> {
size_t operator()(const google::protobuf::internal::MoveTestKey& key) const {
return hash<int>{}(key.data);
}
};
} // namespace std
namespace google {
namespace protobuf {
namespace internal {
namespace {
TEST_F(MapImplTest, OperatorBracketRValue) {
Arena arena;
for (Arena* arena_to_use : {&arena, static_cast<Arena*>(nullptr)}) {
int copies = 0;
Map<MoveTestKey, int> map(arena_to_use);
MoveTestKey key1(1, &copies);
EXPECT_EQ(copies, 0);
map[key1] = 0;
EXPECT_EQ(copies, 1);
map[MoveTestKey(2, &copies)] = 2;
EXPECT_EQ(copies, 1);
}
}
TEST_F(MapImplTest, OperatorBracketNonExist) {
int32 key = 0;
int32 default_value = 0;
@ -1104,6 +1160,11 @@ void TestTransparent(const Key& key, const Key& miss_key) {
EXPECT_EQ(m.erase(key), 0);
EXPECT_EQ(m.erase(miss_key), 0);
EXPECT_THAT(m, UnorderedElementsAre(Pair("DEF", 2)));
m[key];
EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 0), Pair("DEF", 2)));
m[key] = 1;
EXPECT_THAT(m, UnorderedElementsAre(Pair("ABC", 1), Pair("DEF", 2)));
}
TEST_F(MapImplTest, TransparentLookupForString) {

@ -570,7 +570,7 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* arena) { \
value->ClearToEmpty(&internal::GetEmptyStringAlreadyInited(), arena); \
value->ClearToEmpty(); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
@ -593,7 +593,7 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
Type>::MapEntryAccessorType* \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \
TypeOnMemory* value, Arena* arena) { \
return value->Mutable(&internal::GetEmptyStringAlreadyInited(), arena); \
return value->Mutable(ArenaStringPtr::EmptyDefault{}, arena); \
} \
template <typename Type> \
inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \

@ -175,7 +175,7 @@ namespace {
#define HASH_MAP std::unordered_map
#define STR_HASH_FXN hash<const char*>
#define STR_HASH_FXN hash<::google::protobuf::StringPiece>
class GeneratedMessageFactory : public MessageFactory {
@ -190,8 +190,8 @@ class GeneratedMessageFactory : public MessageFactory {
private:
// Only written at static init time, so does not require locking.
HASH_MAP<const char*, const google::protobuf::internal::DescriptorTable*, STR_HASH_FXN,
streq>
HASH_MAP<StringPiece, const google::protobuf::internal::DescriptorTable*,
STR_HASH_FXN>
file_map_;
internal::WrappedMutex mutex_;

@ -1057,8 +1057,6 @@ class PROTOBUF_EXPORT Reflection final {
internal::InternalMetadata* MutableInternalMetadata(Message* message) const;
inline bool IsInlined(const FieldDescriptor* field) const;
inline bool HasBit(const Message& message,
const FieldDescriptor* field) const;
inline void SetBit(Message* message, const FieldDescriptor* field) const;

@ -313,11 +313,11 @@ bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
return ParseFrom<kParsePartial>(internal::BoundedZCIS{input, size});
}
bool MessageLite::ParseFromString(const std::string& data) {
bool MessageLite::ParseFromString(ConstStringParam data) {
return ParseFrom<kParse>(data);
}
bool MessageLite::ParsePartialFromString(const std::string& data) {
bool MessageLite::ParsePartialFromString(ConstStringParam data) {
return ParseFrom<kParsePartial>(data);
}
@ -329,7 +329,7 @@ bool MessageLite::ParsePartialFromArray(const void* data, int size) {
return ParseFrom<kParsePartial>(as_string_view(data, size));
}
bool MessageLite::MergeFromString(const std::string& data) {
bool MessageLite::MergeFromString(ConstStringParam data) {
return ParseFrom<kMerge>(data);
}

@ -315,12 +315,11 @@ class PROTOBUF_EXPORT MessageLite {
// format, matching the encoding output by MessageLite::SerializeToString().
// If you'd like to convert a human-readable string into a protocol buffer
// object, see google::protobuf::TextFormat::ParseFromString().
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromString(
const std::string& data);
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromString(ConstStringParam data);
// Like ParseFromString(), but accepts messages that are missing
// required fields.
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParsePartialFromString(
const std::string& data);
ConstStringParam data);
// Parse a protocol buffer contained in an array of bytes.
PROTOBUF_ATTRIBUTE_REINITIALIZES bool ParseFromArray(const void* data,
int size);
@ -351,7 +350,7 @@ class PROTOBUF_EXPORT MessageLite {
bool MergePartialFromCodedStream(io::CodedInputStream* input);
// Merge a protocol buffer contained in a string.
bool MergeFromString(const std::string& data);
bool MergeFromString(ConstStringParam data);
// Serialization ---------------------------------------------------

@ -48,7 +48,7 @@ namespace internal {
namespace {
// Only call if at start of tag.
bool ParseEndsInSlopRegion(const char* begin, int overrun, int d) {
bool ParseEndsInSlopRegion(const char* begin, int overrun, int depth) {
constexpr int kSlopBytes = EpsCopyInputStream::kSlopBytes;
GOOGLE_DCHECK(overrun >= 0);
GOOGLE_DCHECK(overrun <= kSlopBytes);
@ -79,11 +79,11 @@ bool ParseEndsInSlopRegion(const char* begin, int overrun, int d) {
break;
}
case 3: { // start group
d++;
depth++;
break;
}
case 4: { // end group
if (--d < 0) return true; // We exit early
if (--depth < 0) return true; // We exit early
break;
}
case 5: { // fixed32
@ -99,7 +99,7 @@ bool ParseEndsInSlopRegion(const char* begin, int overrun, int d) {
} // namespace
const char* EpsCopyInputStream::Next(int overrun, int d) {
const char* EpsCopyInputStream::NextBuffer(int overrun, int depth) {
if (next_chunk_ == nullptr) return nullptr; // We've reached end of stream.
if (next_chunk_ != buffer_) {
GOOGLE_DCHECK(size_ > kSlopBytes);
@ -115,7 +115,7 @@ const char* EpsCopyInputStream::Next(int overrun, int d) {
// buffer_.
std::memmove(buffer_, buffer_end_, kSlopBytes);
if (overall_limit_ > 0 &&
(d < 0 || !ParseEndsInSlopRegion(buffer_, overrun, d))) {
(depth < 0 || !ParseEndsInSlopRegion(buffer_, overrun, depth))) {
const void* data;
// ZeroCopyInputStream indicates Next may return 0 size buffers. Hence
// we loop.
@ -154,11 +154,22 @@ const char* EpsCopyInputStream::Next(int overrun, int d) {
return buffer_;
}
std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
int d) {
GOOGLE_DCHECK(ptr >= limit_end_);
int overrun = ptr - buffer_end_;
GOOGLE_DCHECK(overrun <= kSlopBytes); // Guaranteed by parse loop.
const char* EpsCopyInputStream::Next() {
GOOGLE_DCHECK(limit_ > kSlopBytes);
auto p = NextBuffer(0 /* immaterial */, -1);
if (p == nullptr) {
limit_end_ = buffer_end_;
// Distinguish ending on a pushed limit or ending on end-of-stream.
SetEndOfStream();
return nullptr;
}
limit_ -= buffer_end_ - p; // Adjust limit_ relative to new anchor
limit_end_ = buffer_end_ + std::min(0, limit_);
return p;
}
std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(int overrun,
int depth) {
// Did we exceeded the limit (parse error).
if (PROTOBUF_PREDICT_FALSE(overrun > limit_)) return {nullptr, true};
GOOGLE_DCHECK(overrun != limit_); // Guaranteed by caller.
@ -171,10 +182,11 @@ std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
// At this point we know the following assertion holds.
GOOGLE_DCHECK(limit_ > 0);
GOOGLE_DCHECK(limit_end_ == buffer_end_); // because limit_ > 0
const char* p;
do {
// We are past the end of buffer_end_, in the slop region.
GOOGLE_DCHECK(overrun >= 0);
auto p = Next(overrun, d);
p = NextBuffer(overrun, depth);
if (p == nullptr) {
// We are at the end of the stream
if (PROTOBUF_PREDICT_FALSE(overrun != 0)) return {nullptr, true};
@ -182,14 +194,14 @@ std::pair<const char*, bool> EpsCopyInputStream::DoneFallback(const char* ptr,
limit_end_ = buffer_end_;
// Distinguish ending on a pushed limit or ending on end-of-stream.
SetEndOfStream();
return {ptr, true};
return {buffer_end_, true};
}
limit_ -= buffer_end_ - p; // Adjust limit_ relative to new anchor
ptr = p + overrun;
overrun = ptr - buffer_end_;
p += overrun;
overrun = p - buffer_end_;
} while (overrun >= 0);
limit_end_ = buffer_end_ + std::min(0, limit_);
return {ptr, false};
return {p, false};
}
const char* EpsCopyInputStream::SkipFallback(const char* ptr, int size) {
@ -263,9 +275,11 @@ const char* EpsCopyInputStream::ReadPackedFixed(const char* ptr, int size,
for (int i = 0; i < num; i++)
dst[i] = UnalignedLoad<T>(ptr + i * sizeof(T));
#endif
ptr += block_size;
size -= block_size;
if (DoneWithCheck(&ptr, -1)) return nullptr;
if (limit_ <= kSlopBytes) return nullptr;
ptr = Next();
if (ptr == nullptr) return nullptr;
ptr += kSlopBytes - (nbytes - block_size);
nbytes = buffer_end_ + kSlopBytes - ptr;
}
int num = size / sizeof(T);

@ -208,9 +208,16 @@ class PROTOBUF_EXPORT EpsCopyInputStream {
bool DoneWithCheck(const char** ptr, int d) {
GOOGLE_DCHECK(*ptr);
if (PROTOBUF_PREDICT_TRUE(*ptr < limit_end_)) return false;
// No need to fetch buffer if we ended on a limit in the slop region
if ((*ptr - buffer_end_) == limit_) return true;
auto res = DoneFallback(*ptr, d);
int overrun = *ptr - buffer_end_;
GOOGLE_DCHECK_LE(overrun, kSlopBytes); // Guaranteed by parse loop.
if (overrun ==
limit_) { // No need to flip buffers if we ended on a limit.
// If we actually overrun the buffer and next_chunk_ is null. It means
// the stream ended and we passed the stream end.
if (overrun > 0 && next_chunk_ == nullptr) *ptr = nullptr;
return true;
}
auto res = DoneFallback(overrun, d);
*ptr = res.first;
return res.second;
}
@ -276,8 +283,26 @@ class PROTOBUF_EXPORT EpsCopyInputStream {
// systems. TODO(gerbens) do we need to set this as build flag?
enum { kSafeStringSize = 50000000 };
std::pair<const char*, bool> DoneFallback(const char* ptr, int d);
const char* Next(int overrun, int d);
// Advances to next buffer chunk returns a pointer to the same logical place
// in the stream as set by overrun. Overrun indicates the position in the slop
// region the parse was left (0 <= overrun <= kSlopBytes). Returns true if at
// limit, at which point the returned pointer maybe null if there was an
// error. The invariant of this function is that it's guaranteed that
// kSlopBytes bytes can be accessed from the returned ptr. This function might
// advance more buffers than one in the underlying ZeroCopyInputStream.
std::pair<const char*, bool> DoneFallback(int overrun, int depth);
// Advances to the next buffer, at most one call to Next() on the underlying
// ZeroCopyInputStream is made. This function DOES NOT match the returned
// pointer to where in the slop region the parse ends, hence no overrun
// parameter. This is useful for string operations where you always copy
// to the end of the buffer (including the slop region).
const char* Next();
// overrun is the location in the slop region the stream currently is
// (0 <= overrun <= kSlopBytes). To prevent flipping to the next buffer of
// the ZeroCopyInputStream in the case the parse will end in the last
// kSlopBytes of the current buffer. depth is the current depth of nested
// groups (or negative if the use case does not need careful tracking).
inline const char* NextBuffer(int overrun, int depth);
const char* SkipFallback(const char* ptr, int size);
const char* AppendStringFallback(const char* ptr, int size, std::string* str);
const char* ReadStringFallback(const char* ptr, int size, std::string* str);
@ -296,16 +321,17 @@ class PROTOBUF_EXPORT EpsCopyInputStream {
int chunk_size = buffer_end_ + kSlopBytes - ptr;
do {
GOOGLE_DCHECK(size > chunk_size);
if (next_chunk_ == nullptr) return nullptr;
append(ptr, chunk_size);
ptr += chunk_size;
size -= chunk_size;
// DoneFallBack asserts it isn't called when exactly on the limit. If this
// happens we fail the parse, as we are at the limit and still more bytes
// to read.
if (limit_ == kSlopBytes) return nullptr;
auto res = DoneFallback(ptr, -1);
if (res.second) return nullptr; // If done we passed the limit
ptr = res.first;
// TODO(gerbens) Next calls NextBuffer which generates buffers with
// overlap and thus incurs cost of copying the slop regions. This is not
// necessary for reading strings. We should just call Next buffers.
if (limit_ <= kSlopBytes) return nullptr;
ptr = Next();
if (ptr == nullptr) return nullptr; // passed the limit
ptr += kSlopBytes;
chunk_size = buffer_end_ + kSlopBytes - ptr;
} while (size > chunk_size);
append(ptr, size);
@ -319,11 +345,19 @@ class PROTOBUF_EXPORT EpsCopyInputStream {
// implicit weak messages. We keep these methods private and friend them.
template <typename A>
const char* AppendUntilEnd(const char* ptr, const A& append) {
while (!DoneWithCheck(&ptr, -1)) {
append(ptr, limit_end_ - ptr);
ptr = limit_end_;
if (ptr - buffer_end_ > limit_) return nullptr;
while (limit_ > kSlopBytes) {
int chunk_size = buffer_end_ + kSlopBytes - ptr;
GOOGLE_DCHECK_GE(chunk_size, 0);
append(ptr, chunk_size);
ptr = Next();
if (ptr == nullptr) return limit_end_;
ptr += kSlopBytes;
}
return ptr;
auto end = buffer_end_ + limit_;
GOOGLE_DCHECK(end >= ptr);
append(ptr, end - ptr);
return end;
}
PROTOBUF_MUST_USE_RESULT const char* AppendString(const char* ptr,
@ -354,7 +388,6 @@ class PROTOBUF_EXPORT ParseContext : public EpsCopyInputStream {
void TrackCorrectEnding() { group_depth_ = 0; }
bool Done(const char** ptr) { return DoneWithCheck(ptr, group_depth_); }
bool DoneNoSlopCheck(const char** ptr) { return DoneWithCheck(ptr, -1); }
int depth() const { return depth_; }
@ -619,21 +652,52 @@ PROTOBUF_MUST_USE_RESULT const char* ParseContext::ParseMessage(
}
template <typename Add>
const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add) {
int size = ReadSize(&ptr);
if (ptr == nullptr) return nullptr;
auto old = PushLimit(ptr, size);
if (old < 0) return nullptr;
while (!DoneWithCheck(&ptr, -1)) {
const char* ReadPackedVarintArray(const char* ptr, const char* end, Add add) {
while (ptr < end) {
uint64 varint;
ptr = VarintParse(ptr, &varint);
if (!ptr) return nullptr;
if (ptr == nullptr) return nullptr;
add(varint);
}
if (!PopLimit(old)) return nullptr;
return ptr;
}
template <typename Add>
const char* EpsCopyInputStream::ReadPackedVarint(const char* ptr, Add add) {
int size = ReadSize(&ptr);
if (ptr == nullptr) return nullptr;
int chunk_size = buffer_end_ - ptr;
while (size > chunk_size) {
ptr = ReadPackedVarintArray(ptr, buffer_end_, add);
if (ptr == nullptr) return nullptr;
int overrun = ptr - buffer_end_;
GOOGLE_DCHECK(overrun >= 0 && overrun <= kSlopBytes);
if (size - chunk_size <= kSlopBytes) {
// The current buffer contains all the information needed, we don't need
// to flip buffers. However we must parse from a buffer with enough space
// so we are not prone to a buffer overflow.
char buf[kSlopBytes + 10] = {};
std::memcpy(buf, buffer_end_, kSlopBytes);
GOOGLE_CHECK_LE(size - chunk_size, kSlopBytes);
auto end = buf + (size - chunk_size);
auto res = ReadPackedVarintArray(buf + overrun, end, add);
if (res == nullptr || res != end) return nullptr;
return buffer_end_ + (res - buf);
}
size -= overrun + chunk_size;
GOOGLE_DCHECK_GT(size, 0);
// We must flip buffers
if (limit_ <= kSlopBytes) return nullptr;
ptr = Next();
if (ptr == nullptr) return nullptr;
ptr += overrun;
chunk_size = buffer_end_ - ptr;
}
auto end = ptr + size;
ptr = ReadPackedVarintArray(ptr, end, add);
return end == ptr ? ptr : nullptr;
}
// Helper for verification of utf8
PROTOBUF_EXPORT
bool VerifyUTF8(StringPiece s, const char* field_name);

@ -238,12 +238,15 @@
#ifdef GOOGLE_PROTOBUF_ATTRIBUTE_RETURNS_NONNULL
#define PROTOBUF_RETURNS_NONNULL GOOGLE_PROTOBUF_ATTRIBUTE_RETURNS_NONNULL
#else
#ifdef __GNUC__
#if defined(__has_attribute)
#if __has_attribute(returns_nonnull)
#define PROTOBUF_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define PROTOBUF_RETURNS_NONNULL
#endif
#endif
#endif
#ifndef PROTOBUF_RETURNS_NONNULL
#define PROTOBUF_RETURNS_NONNULL
#endif
#if defined(__has_cpp_attribute)
#if __has_cpp_attribute(clang::reinitializes)
@ -433,6 +436,8 @@
#undef SEVERITY_ERROR
#pragma push_macro("STRICT")
#undef STRICT
#pragma push_macro("timezone")
#undef timezone
#endif // _MSC_VER
#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)

@ -93,6 +93,7 @@
#pragma pop_macro("SERVICE_DISABLED")
#pragma pop_macro("SEVERITY_ERROR")
#pragma pop_macro("STRICT")
#pragma pop_macro("timezone")
#endif
#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)

@ -43,7 +43,6 @@
#include <google/protobuf/map_field.h>
#include <google/protobuf/map_field_inl.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/port_def.inc>

@ -95,7 +95,7 @@ SourceContext::SourceContext(const SourceContext& from)
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
file_name_.UnsafeSetDefault(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited());
if (!from._internal_file_name().empty()) {
file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), from._internal_file_name(),
file_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, from._internal_file_name(),
GetArena());
}
// @@protoc_insertion_point(copy_constructor:google.protobuf.SourceContext)
@ -138,7 +138,7 @@ void SourceContext::Clear() {
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
file_name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
file_name_.ClearToEmpty();
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
}

@ -25,7 +25,6 @@
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_table_driven.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/inlined_string_field.h>
#include <google/protobuf/metadata_lite.h>
#include <google/protobuf/generated_message_reflection.h>
#include <google/protobuf/message.h>
@ -220,7 +219,7 @@ class PROTOBUF_EXPORT SourceContext PROTOBUF_FINAL :
// string file_name = 1;
inline void SourceContext::clear_file_name() {
file_name_.ClearToEmpty(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
file_name_.ClearToEmpty();
}
inline const std::string& SourceContext::file_name() const {
// @@protoc_insertion_point(field_get:google.protobuf.SourceContext.file_name)
@ -239,31 +238,30 @@ inline const std::string& SourceContext::_internal_file_name() const {
}
inline void SourceContext::_internal_set_file_name(const std::string& value) {
file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), value, GetArena());
file_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, value, GetArena());
}
inline void SourceContext::set_file_name(std::string&& value) {
file_name_.Set(
&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::move(value), GetArena());
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::move(value), GetArena());
// @@protoc_insertion_point(field_set_rvalue:google.protobuf.SourceContext.file_name)
}
inline void SourceContext::set_file_name(const char* value) {
GOOGLE_DCHECK(value != nullptr);
file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
GetArena());
file_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(value), GetArena());
// @@protoc_insertion_point(field_set_char:google.protobuf.SourceContext.file_name)
}
inline void SourceContext::set_file_name(const char* value,
size_t size) {
file_name_.Set(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), ::std::string(
file_name_.Set(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, ::std::string(
reinterpret_cast<const char*>(value), size), GetArena());
// @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceContext.file_name)
}
inline std::string* SourceContext::_internal_mutable_file_name() {
return file_name_.Mutable(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
return file_name_.Mutable(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
}
inline std::string* SourceContext::release_file_name() {
// @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name)

@ -546,7 +546,7 @@ void Value::clear_kind() {
break;
}
case kStringValue: {
kind_.string_value_.Destroy(&::PROTOBUF_NAMESPACE_ID::internal::GetEmptyStringAlreadyInited(), GetArena());
kind_.string_value_.Destroy(::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::EmptyDefault{}, GetArena());
break;
}
case kBoolValue: {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save