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

pull/10729/head
Mike Kruskal 2 years ago
commit 87084d39ef
  1. 6
      BUILD.bazel
  2. 3
      Protobuf-C++.podspec
  3. 4
      build_defs/cpp_opts.bzl
  4. 2
      cmake/install.cmake
  5. 637
      conformance/binary_json_conformance_suite.cc
  6. 23
      conformance/binary_json_conformance_suite.h
  7. 13
      conformance/conformance.proto
  8. 65
      conformance/conformance_test.cc
  9. 16
      conformance/conformance_test.h
  10. 57
      conformance/conformance_test_runner.cc
  11. 607
      conformance/text_format_conformance_suite.cc
  12. 16
      conformance/text_format_conformance_suite.h
  13. 12
      java/core/src/main/java/com/google/protobuf/FieldSet.java
  14. 14
      java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java
  15. 2
      java/internal/testing.bzl
  16. 5
      java/util/src/main/java/com/google/protobuf/util/Values.java
  17. 18
      pkg/BUILD.bazel
  18. 6
      protobuf_version.bzl
  19. 14
      python/google/protobuf/internal/descriptor_pool_test.py
  20. 36
      python/google/protobuf/internal/numpy_test.py
  21. 1
      src/BUILD.bazel
  22. 59
      src/file_lists.cmake
  23. 79
      src/google/protobuf/BUILD.bazel
  24. 141
      src/google/protobuf/arena.cc
  25. 13
      src/google/protobuf/arena_align.cc
  26. 155
      src/google/protobuf/arena_align.h
  27. 215
      src/google/protobuf/arena_align_test.cc
  28. 126
      src/google/protobuf/arena_allocation_policy.h
  29. 189
      src/google/protobuf/arena_cleanup.h
  30. 278
      src/google/protobuf/arena_impl.h
  31. 1
      src/google/protobuf/compiler/command_line_interface.cc
  32. 1
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  33. 768
      src/google/protobuf/compiler/cpp/enum.cc
  34. 48
      src/google/protobuf/compiler/cpp/enum.h
  35. 1
      src/google/protobuf/compiler/cpp/enum_field.cc
  36. 1
      src/google/protobuf/compiler/cpp/extension.cc
  37. 95
      src/google/protobuf/compiler/cpp/field.cc
  38. 6
      src/google/protobuf/compiler/cpp/field.h
  39. 43
      src/google/protobuf/compiler/cpp/file.cc
  40. 12
      src/google/protobuf/compiler/cpp/generator.cc
  41. 84
      src/google/protobuf/compiler/cpp/helpers.cc
  42. 25
      src/google/protobuf/compiler/cpp/helpers.h
  43. 2
      src/google/protobuf/compiler/cpp/map_field.cc
  44. 866
      src/google/protobuf/compiler/cpp/message.cc
  45. 133
      src/google/protobuf/compiler/cpp/message.h
  46. 17
      src/google/protobuf/compiler/cpp/message_field.cc
  47. 52
      src/google/protobuf/compiler/cpp/parse_function_generator.cc
  48. 1
      src/google/protobuf/compiler/cpp/primitive_field.cc
  49. 22
      src/google/protobuf/compiler/cpp/string_field.cc
  50. 1
      src/google/protobuf/compiler/cpp/unittest.inc
  51. 1
      src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc
  52. 2
      src/google/protobuf/compiler/csharp/csharp_map_field.cc
  53. 2
      src/google/protobuf/compiler/csharp/csharp_reflection_class.cc
  54. 6
      src/google/protobuf/compiler/importer.h
  55. 1
      src/google/protobuf/compiler/java/context.cc
  56. 1
      src/google/protobuf/compiler/java/doc_comment.cc
  57. 1
      src/google/protobuf/compiler/java/enum.cc
  58. 1
      src/google/protobuf/compiler/java/enum_field.cc
  59. 1
      src/google/protobuf/compiler/java/enum_field_lite.cc
  60. 1
      src/google/protobuf/compiler/java/enum_lite.cc
  61. 1
      src/google/protobuf/compiler/java/extension.cc
  62. 1
      src/google/protobuf/compiler/java/extension_lite.cc
  63. 1
      src/google/protobuf/compiler/java/field.cc
  64. 1
      src/google/protobuf/compiler/java/file.cc
  65. 1
      src/google/protobuf/compiler/java/map_field.cc
  66. 1
      src/google/protobuf/compiler/java/message.cc
  67. 1
      src/google/protobuf/compiler/java/message_builder.cc
  68. 1
      src/google/protobuf/compiler/java/message_builder_lite.cc
  69. 1
      src/google/protobuf/compiler/java/message_field.cc
  70. 1
      src/google/protobuf/compiler/java/message_field_lite.cc
  71. 1
      src/google/protobuf/compiler/java/message_lite.cc
  72. 1
      src/google/protobuf/compiler/java/names.cc
  73. 6
      src/google/protobuf/compiler/java/names.h
  74. 1
      src/google/protobuf/compiler/java/primitive_field.cc
  75. 1
      src/google/protobuf/compiler/java/primitive_field_lite.cc
  76. 1
      src/google/protobuf/compiler/java/service.cc
  77. 1
      src/google/protobuf/compiler/java/string_field.cc
  78. 1
      src/google/protobuf/compiler/java/string_field_lite.cc
  79. 4
      src/google/protobuf/compiler/main.cc
  80. 3
      src/google/protobuf/compiler/objectivec/helpers.cc
  81. 30
      src/google/protobuf/compiler/objectivec/nsobject_methods.h
  82. 3
      src/google/protobuf/compiler/objectivec/text_format_decode_data.cc
  83. 3
      src/google/protobuf/compiler/parser.cc
  84. 3
      src/google/protobuf/compiler/php/php_generator.cc
  85. 27
      src/google/protobuf/compiler/plugin.pb.cc
  86. 76
      src/google/protobuf/compiler/plugin.pb.h
  87. 7
      src/google/protobuf/descriptor.cc
  88. 214
      src/google/protobuf/descriptor.pb.cc
  89. 598
      src/google/protobuf/descriptor.pb.h
  90. 19
      src/google/protobuf/descriptor_unittest.cc
  91. 1
      src/google/protobuf/extension_set_unittest.cc
  92. 3
      src/google/protobuf/generated_message_reflection.cc
  93. 2
      src/google/protobuf/generated_message_reflection.h
  94. 1
      src/google/protobuf/generated_message_reflection_unittest.cc
  95. 3
      src/google/protobuf/generated_message_tctable_decl.h
  96. 87
      src/google/protobuf/generated_message_tctable_gen.cc
  97. 44
      src/google/protobuf/generated_message_tctable_gen.h
  98. 4
      src/google/protobuf/generated_message_tctable_impl.h
  99. 42
      src/google/protobuf/generated_message_tctable_lite.cc
  100. 1
      src/google/protobuf/io/coded_stream_unittest.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -217,6 +217,12 @@ alias(
visibility = ["//visibility:public"],
)
alias(
name = "json",
actual = "//src/google/protobuf/json",
visibility = ["//visibility:public"],
)
################################################################################
# Java support
################################################################################

@ -13,8 +13,7 @@ Pod::Spec.new do |s|
s.source_files = 'src/google/protobuf/*.{h,cc,inc}',
'src/google/protobuf/stubs/*.{h,cc}',
'src/google/protobuf/io/*.{h,cc}',
'src/google/protobuf/util/*.{h,cc}',
'src/google/protobuf/util/internal/*.{h,cc}'
'src/google/protobuf/util/*.{h,cc}'
# Excluding all the tests in the directories above
s.exclude_files = 'src/google/**/*_test.{h,cc,inc}',

@ -21,7 +21,9 @@ COPTS = select({
"-Wno-sign-compare",
"-Werror",
],
})
}) + [
"-std=c++14", # Protobuf requires C++14.
]
# Android and MSVC builds do not need to link in a separate pthread library.
LINK_OPTS = select({

@ -47,7 +47,7 @@ include(${protobuf_SOURCE_DIR}/src/file_lists.cmake)
set(protobuf_HEADERS
${libprotobuf_hdrs}
${libprotoc_hdrs}
${wkt_protos_proto_srcs}
${wkt_protos_files}
${descriptor_proto_proto_srcs}
${plugin_proto_proto_srcs}
)

@ -37,6 +37,7 @@
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "third_party/jsoncpp/json.h"
#include "conformance/conformance.pb.h"
#include "conformance_test.h"
#include "google/protobuf/test_messages_proto2.pb.h"
#include "google/protobuf/test_messages_proto3.pb.h"
@ -60,6 +61,10 @@ namespace {
static const char kTypeUrlPrefix[] = "type.googleapis.com";
// The number of repetitions to use for performance tests.
// Corresponds approx to 500KB wireformat bytes.
static const size_t kPerformanceRepeatCount = 50000;
static string GetTypeUrl(const Descriptor* message) {
return string(kTypeUrlPrefix) + "/" + message->full_name();
}
@ -477,6 +482,25 @@ void BinaryAndJsonConformanceSuite::RunValidJsonTest(
const string& test_name, ConformanceLevel level, const string& input_json,
const string& equivalent_text_format) {
TestAllTypesProto3 prototype;
RunValidJsonTestWithMessage(test_name, level, input_json,
equivalent_text_format, prototype);
}
void BinaryAndJsonConformanceSuite::RunValidJsonTest(
const string& test_name, ConformanceLevel level, const string& input_json,
const string& equivalent_text_format, bool is_proto3) {
if (is_proto3) {
RunValidJsonTest(test_name, level, input_json, equivalent_text_format);
} else {
TestAllTypesProto2 prototype;
RunValidJsonTestWithMessage(test_name, level, input_json,
equivalent_text_format, prototype);
}
}
void BinaryAndJsonConformanceSuite::RunValidJsonTestWithMessage(
const string& test_name, ConformanceLevel level, const string& input_json,
const string& equivalent_text_format, const Message& prototype) {
ConformanceRequestSetting setting1(
level, conformance::JSON, conformance::PROTOBUF,
conformance::JSON_TEST,
@ -550,6 +574,27 @@ void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest(
RunValidBinaryInputTest(setting, expected_protobuf, true);
}
void BinaryAndJsonConformanceSuite::RunBinaryPerformanceMergeMessageWithField(
const string& test_name, const string& field_proto, bool is_proto3) {
string message_tag = tag(27, WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
string message_proto = cat(message_tag, delim(field_proto));
string proto;
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
proto.append(message_proto);
}
string multiple_repeated_field_proto;
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
multiple_repeated_field_proto.append(field_proto);
}
string expected_proto =
cat(message_tag, delim(multiple_repeated_field_proto));
RunValidBinaryProtobufTest(test_name, RECOMMENDED, proto, expected_proto,
is_proto3);
}
void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage(
const string& test_name, ConformanceLevel level, const Message *input,
const string& equivalent_text_format, bool is_proto3) {
@ -1311,6 +1356,60 @@ void BinaryAndJsonConformanceSuite::TestUnknownMessage(
message.SerializeAsString(), is_proto3);
}
void BinaryAndJsonConformanceSuite::
TestBinaryPerformanceForAlternatingUnknownFields() {
string unknown_field_1 =
cat(tag(UNKNOWN_FIELD, WireFormatLite::WIRETYPE_VARINT), varint(1234));
string unknown_field_2 = cat(
tag(UNKNOWN_FIELD + 1, WireFormatLite::WIRETYPE_VARINT), varint(5678));
for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
string proto;
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
proto.append(unknown_field_1);
proto.append(unknown_field_2);
}
RunValidBinaryProtobufTest(
"TestBinaryPerformanceForAlternatingUnknownFields", RECOMMENDED, proto,
is_proto3);
}
}
void BinaryAndJsonConformanceSuite::
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::Type type) {
const string type_name =
UpperCase(string(".") + FieldDescriptor::TypeName(type));
for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
int field_number =
GetFieldForType(type, true, is_proto3, Packed::kFalse)->number();
string rep_field_proto = cat(
tag(field_number, WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(type))),
GetNonDefaultValue(type));
RunBinaryPerformanceMergeMessageWithField(
"TestBinaryPerformanceMergeMessageWithRepeatedFieldForType" + type_name,
rep_field_proto, is_proto3);
}
}
void BinaryAndJsonConformanceSuite::
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::Type type) {
const string type_name =
UpperCase(string(".") + FieldDescriptor::TypeName(type));
string unknown_field_proto =
cat(tag(UNKNOWN_FIELD, WireFormatLite::WireTypeForFieldType(
static_cast<WireFormatLite::FieldType>(type))),
GetNonDefaultValue(type));
for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
RunBinaryPerformanceMergeMessageWithField(
"TestBinaryPerformanceMergeMessageWithUnknownFieldForType" + type_name,
unknown_field_proto, is_proto3);
}
}
void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
// Hack to get the list of test failures based on whether
// GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER is enabled or not.
@ -1330,232 +1429,324 @@ void BinaryAndJsonConformanceSuite::RunSuiteImpl() {
kTypeUrlPrefix, DescriptorPool::generated_pool()));
type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor());
for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
if (i == FieldDescriptor::TYPE_GROUP) continue;
TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
}
if (!performance_) {
for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) {
if (i == FieldDescriptor::TYPE_GROUP) continue;
TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
}
TestIllegalTags();
int64 kInt64Min = -9223372036854775808ULL;
int64 kInt64Max = 9223372036854775807ULL;
uint64 kUint64Max = 18446744073709551615ULL;
int32 kInt32Max = 2147483647;
int32 kInt32Min = -2147483648;
uint32 kUint32Max = 4294967295UL;
TestValidDataForType(
FieldDescriptor::TYPE_DOUBLE,
{
{dbl(0), dbl(0)},
{dbl(0.1), dbl(0.1)},
{dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)},
{dbl(2.22507385850720138309e-308), dbl(2.22507385850720138309e-308)},
});
TestValidDataForType(
FieldDescriptor::TYPE_FLOAT,
{
{flt(0), flt(0)},
{flt(0.1), flt(0.1)},
{flt(1.00000075e-36), flt(1.00000075e-36)},
{flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38
{flt(1.17549435e-38f), flt(1.17549435e-38)},
});
TestValidDataForType(FieldDescriptor::TYPE_INT64,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{varint(kInt64Max), varint(kInt64Max)},
{varint(kInt64Min), varint(kInt64Min)},
});
TestValidDataForType(FieldDescriptor::TYPE_UINT64,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{varint(kUint64Max), varint(kUint64Max)},
});
TestValidDataForType(FieldDescriptor::TYPE_INT32,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{longvarint(12345, 2), varint(12345)},
{longvarint(12345, 7), varint(12345)},
{varint(kInt32Max), varint(kInt32Max)},
{varint(kInt32Min), varint(kInt32Min)},
{varint(1LL << 33), varint(0)},
{varint((1LL << 33) - 1), varint(-1)},
{varint(kInt64Max), varint(-1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForType(
FieldDescriptor::TYPE_UINT32,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{longvarint(12345, 2), varint(12345)},
{longvarint(12345, 7), varint(12345)},
{varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX
{varint(1LL << 33), varint(0)},
{varint((1LL << 33) + 1), varint(1)},
{varint((1LL << 33) - 1), varint((1LL << 32) - 1)},
{varint(kInt64Max), varint((1LL << 32) - 1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED64,
{
{u64(0), u64(0)},
{u64(12345), u64(12345)},
{u64(kUint64Max), u64(kUint64Max)},
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED32,
{
{u32(0), u32(0)},
{u32(12345), u32(12345)},
{u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED64,
{
{u64(0), u64(0)},
{u64(12345), u64(12345)},
{u64(kInt64Max), u64(kInt64Max)},
{u64(kInt64Min), u64(kInt64Min)},
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED32,
{
{u32(0), u32(0)},
{u32(12345), u32(12345)},
{u32(kInt32Max), u32(kInt32Max)},
{u32(kInt32Min), u32(kInt32Min)},
});
// Bools should be serialized as 0 for false and 1 for true. Parsers should
// also interpret any nonzero value as true.
TestValidDataForType(FieldDescriptor::TYPE_BOOL,
{
{varint(0), varint(0)},
{varint(1), varint(1)},
{varint(-1), varint(1)},
{varint(12345678), varint(1)},
{varint(1LL << 33), varint(1)},
{varint(kInt64Max), varint(1)},
{varint(kInt64Min), varint(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_SINT32,
{
{zz32(0), zz32(0)},
{zz32(12345), zz32(12345)},
{zz32(kInt32Max), zz32(kInt32Max)},
{zz32(kInt32Min), zz32(kInt32Min)},
{zz64(kInt32Max + 2LL), zz32(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_SINT64,
{
{zz64(0), zz64(0)},
{zz64(12345), zz64(12345)},
{zz64(kInt64Max), zz64(kInt64Max)},
{zz64(kInt64Min), zz64(kInt64Min)},
});
TestValidDataForType(
FieldDescriptor::TYPE_STRING,
{
{delim(""), delim("")},
{delim("Hello world!"), delim("Hello world!")},
{delim("\'\"\?\\\a\b\f\n\r\t\v"),
delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape
{delim("谷歌"), delim("谷歌")}, // Google in Chinese
{delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape
{delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode
{delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁
});
TestValidDataForType(FieldDescriptor::TYPE_BYTES,
{
{delim(""), delim("")},
{delim("Hello world!"), delim("Hello world!")},
{delim("\x01\x02"), delim("\x01\x02")},
{delim("\xfb"), delim("\xfb")},
});
TestValidDataForType(FieldDescriptor::TYPE_ENUM,
{
{varint(0), varint(0)},
{varint(1), varint(1)},
{varint(2), varint(2)},
{varint(-1), varint(-1)},
{varint(kInt64Max), varint(-1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForRepeatedScalarMessage();
TestValidDataForType(
FieldDescriptor::TYPE_MESSAGE,
{
{delim(""), delim("")},
{delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))),
delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))},
});
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_INT32);
TestValidDataForMapType(FieldDescriptor::TYPE_INT64,
FieldDescriptor::TYPE_INT64);
TestValidDataForMapType(FieldDescriptor::TYPE_UINT32,
FieldDescriptor::TYPE_UINT32);
TestValidDataForMapType(FieldDescriptor::TYPE_UINT64,
FieldDescriptor::TYPE_UINT64);
TestValidDataForMapType(FieldDescriptor::TYPE_SINT32,
FieldDescriptor::TYPE_SINT32);
TestValidDataForMapType(FieldDescriptor::TYPE_SINT64,
FieldDescriptor::TYPE_SINT64);
TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32,
FieldDescriptor::TYPE_FIXED32);
TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64,
FieldDescriptor::TYPE_FIXED64);
TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32,
FieldDescriptor::TYPE_SFIXED32);
TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64,
FieldDescriptor::TYPE_SFIXED64);
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_FLOAT);
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_DOUBLE);
TestValidDataForMapType(FieldDescriptor::TYPE_BOOL,
FieldDescriptor::TYPE_BOOL);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_STRING);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_BYTES);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_ENUM);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_MESSAGE);
// Additional test to check overwriting message value map.
TestOverwriteMessageValueMap();
TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32);
TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL);
TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64);
TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT);
TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE);
TestValidDataForOneofType(FieldDescriptor::TYPE_STRING);
TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES);
TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM);
TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE);
// Additional test to check merging oneof message.
TestMergeOneofMessage();
// TODO(haberman):
// TestValidDataForType(FieldDescriptor::TYPE_GROUP
// Unknown fields.
{
TestAllTypesProto3 messageProto3;
TestAllTypesProto2 messageProto2;
// TODO(yilunchong): update this behavior when unknown field's behavior
// changed in open source. Also delete
// Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
// from failure list of python_cpp python java
TestUnknownMessage(messageProto3, true);
TestUnknownMessage(messageProto2, false);
TestIllegalTags();
int64 kInt64Min = -9223372036854775808ULL;
int64 kInt64Max = 9223372036854775807ULL;
uint64 kUint64Max = 18446744073709551615ULL;
int32 kInt32Max = 2147483647;
int32 kInt32Min = -2147483648;
uint32 kUint32Max = 4294967295UL;
TestValidDataForType(
FieldDescriptor::TYPE_DOUBLE,
{
{dbl(0), dbl(0)},
{dbl(0.1), dbl(0.1)},
{dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)},
{dbl(2.22507385850720138309e-308),
dbl(2.22507385850720138309e-308)},
});
TestValidDataForType(
FieldDescriptor::TYPE_FLOAT,
{
{flt(0), flt(0)},
{flt(0.1), flt(0.1)},
{flt(1.00000075e-36), flt(1.00000075e-36)},
{flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38
{flt(1.17549435e-38f), flt(1.17549435e-38)},
});
TestValidDataForType(FieldDescriptor::TYPE_INT64,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{varint(kInt64Max), varint(kInt64Max)},
{varint(kInt64Min), varint(kInt64Min)},
});
TestValidDataForType(FieldDescriptor::TYPE_UINT64,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{varint(kUint64Max), varint(kUint64Max)},
});
TestValidDataForType(FieldDescriptor::TYPE_INT32,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{longvarint(12345, 2), varint(12345)},
{longvarint(12345, 7), varint(12345)},
{varint(kInt32Max), varint(kInt32Max)},
{varint(kInt32Min), varint(kInt32Min)},
{varint(1LL << 33), varint(0)},
{varint((1LL << 33) - 1), varint(-1)},
{varint(kInt64Max), varint(-1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForType(
FieldDescriptor::TYPE_UINT32,
{
{varint(0), varint(0)},
{varint(12345), varint(12345)},
{longvarint(12345, 2), varint(12345)},
{longvarint(12345, 7), varint(12345)},
{varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX
{varint(1LL << 33), varint(0)},
{varint((1LL << 33) + 1), varint(1)},
{varint((1LL << 33) - 1), varint((1LL << 32) - 1)},
{varint(kInt64Max), varint((1LL << 32) - 1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED64,
{
{u64(0), u64(0)},
{u64(12345), u64(12345)},
{u64(kUint64Max), u64(kUint64Max)},
});
TestValidDataForType(FieldDescriptor::TYPE_FIXED32,
{
{u32(0), u32(0)},
{u32(12345), u32(12345)},
{u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED64,
{
{u64(0), u64(0)},
{u64(12345), u64(12345)},
{u64(kInt64Max), u64(kInt64Max)},
{u64(kInt64Min), u64(kInt64Min)},
});
TestValidDataForType(FieldDescriptor::TYPE_SFIXED32,
{
{u32(0), u32(0)},
{u32(12345), u32(12345)},
{u32(kInt32Max), u32(kInt32Max)},
{u32(kInt32Min), u32(kInt32Min)},
});
// Bools should be serialized as 0 for false and 1 for true. Parsers should
// also interpret any nonzero value as true.
TestValidDataForType(FieldDescriptor::TYPE_BOOL,
{
{varint(0), varint(0)},
{varint(1), varint(1)},
{varint(-1), varint(1)},
{varint(12345678), varint(1)},
{varint(1LL << 33), varint(1)},
{varint(kInt64Max), varint(1)},
{varint(kInt64Min), varint(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_SINT32,
{
{zz32(0), zz32(0)},
{zz32(12345), zz32(12345)},
{zz32(kInt32Max), zz32(kInt32Max)},
{zz32(kInt32Min), zz32(kInt32Min)},
{zz64(kInt32Max + 2LL), zz32(1)},
});
TestValidDataForType(FieldDescriptor::TYPE_SINT64,
{
{zz64(0), zz64(0)},
{zz64(12345), zz64(12345)},
{zz64(kInt64Max), zz64(kInt64Max)},
{zz64(kInt64Min), zz64(kInt64Min)},
});
TestValidDataForType(
FieldDescriptor::TYPE_STRING,
{
{delim(""), delim("")},
{delim("Hello world!"), delim("Hello world!")},
{delim("\'\"\?\\\a\b\f\n\r\t\v"),
delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape
{delim("谷歌"), delim("谷歌")}, // Google in Chinese
{delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape
{delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode
{delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁
});
TestValidDataForType(FieldDescriptor::TYPE_BYTES,
{
{delim(""), delim("")},
{delim("Hello world!"), delim("Hello world!")},
{delim("\x01\x02"), delim("\x01\x02")},
{delim("\xfb"), delim("\xfb")},
});
TestValidDataForType(FieldDescriptor::TYPE_ENUM,
{
{varint(0), varint(0)},
{varint(1), varint(1)},
{varint(2), varint(2)},
{varint(-1), varint(-1)},
{varint(kInt64Max), varint(-1)},
{varint(kInt64Min + 1), varint(1)},
});
TestValidDataForRepeatedScalarMessage();
TestValidDataForType(
FieldDescriptor::TYPE_MESSAGE,
{
{delim(""), delim("")},
{delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))),
delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))},
});
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_INT32);
TestValidDataForMapType(FieldDescriptor::TYPE_INT64,
FieldDescriptor::TYPE_INT64);
TestValidDataForMapType(FieldDescriptor::TYPE_UINT32,
FieldDescriptor::TYPE_UINT32);
TestValidDataForMapType(FieldDescriptor::TYPE_UINT64,
FieldDescriptor::TYPE_UINT64);
TestValidDataForMapType(FieldDescriptor::TYPE_SINT32,
FieldDescriptor::TYPE_SINT32);
TestValidDataForMapType(FieldDescriptor::TYPE_SINT64,
FieldDescriptor::TYPE_SINT64);
TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32,
FieldDescriptor::TYPE_FIXED32);
TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64,
FieldDescriptor::TYPE_FIXED64);
TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32,
FieldDescriptor::TYPE_SFIXED32);
TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64,
FieldDescriptor::TYPE_SFIXED64);
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_FLOAT);
TestValidDataForMapType(FieldDescriptor::TYPE_INT32,
FieldDescriptor::TYPE_DOUBLE);
TestValidDataForMapType(FieldDescriptor::TYPE_BOOL,
FieldDescriptor::TYPE_BOOL);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_STRING);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_BYTES);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_ENUM);
TestValidDataForMapType(FieldDescriptor::TYPE_STRING,
FieldDescriptor::TYPE_MESSAGE);
// Additional test to check overwriting message value map.
TestOverwriteMessageValueMap();
TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32);
TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL);
TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64);
TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT);
TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE);
TestValidDataForOneofType(FieldDescriptor::TYPE_STRING);
TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES);
TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM);
TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE);
// Additional test to check merging oneof message.
TestMergeOneofMessage();
// TODO(haberman):
// TestValidDataForType(FieldDescriptor::TYPE_GROUP
// Unknown fields.
{
TestAllTypesProto3 messageProto3;
TestAllTypesProto2 messageProto2;
// TODO(yilunchong): update this behavior when unknown field's behavior
// changed in open source. Also delete
// Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput
// from failure list of python_cpp python java
TestUnknownMessage(messageProto3, true);
TestUnknownMessage(messageProto2, false);
}
RunJsonTests();
}
// Flag control performance tests to keep them internal and opt-in only
if (performance_) {
RunBinaryPerformanceTests();
RunJsonPerformanceTests();
}
}
void BinaryAndJsonConformanceSuite::RunBinaryPerformanceTests() {
TestBinaryPerformanceForAlternatingUnknownFields();
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_BOOL);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_DOUBLE);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_FLOAT);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_UINT32);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_UINT64);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_STRING);
TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_BYTES);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_BOOL);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_DOUBLE);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_FLOAT);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_UINT32);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_UINT64);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_STRING);
TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
FieldDescriptor::TYPE_BYTES);
}
void BinaryAndJsonConformanceSuite::RunJsonPerformanceTests() {
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_BOOL, "true");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_DOUBLE, "123");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_FLOAT, "123");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_UINT32, "123");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_UINT64, "123");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_STRING, "\"foo\"");
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::TYPE_BYTES, "\"foo\"");
}
// This is currently considered valid input by some languages but not others
void BinaryAndJsonConformanceSuite::
TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
FieldDescriptor::Type type, string field_value) {
const string type_name =
UpperCase(string(".") + FieldDescriptor::TypeName(type));
for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) {
const FieldDescriptor* field =
GetFieldForType(type, true, is_proto3, Packed::kFalse);
string field_name = field->name();
string message_field = "\"" + field_name + "\": [" + field_value + "]";
string recursive_message =
"\"recursive_message\": { " + message_field + "}";
string input = "{";
input.append(recursive_message);
for (size_t i = 1; i < kPerformanceRepeatCount; i++) {
input.append("," + recursive_message);
}
input.append("}");
RunJsonTests();
string textproto_message_field = field_name + ": " + field_value;
string expected_textproto = "recursive_message { ";
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
expected_textproto.append(textproto_message_field + " ");
}
expected_textproto.append("}");
RunValidJsonTest(
"TestJsonPerformanceMergeMessageWithRepeatedFieldForType" + type_name,
RECOMMENDED, input, expected_textproto, is_proto3);
}
}
void BinaryAndJsonConformanceSuite::RunJsonTests() {

@ -31,6 +31,7 @@
#ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
#define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
#include "google/protobuf/descriptor.h"
#include "third_party/jsoncpp/json.h"
#include "conformance_test.h"
@ -43,6 +44,8 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
private:
void RunSuiteImpl() override;
void RunBinaryPerformanceTests();
void RunJsonPerformanceTests();
void RunJsonTests();
void RunJsonTestsForFieldNameConvention();
void RunJsonTestsForNonRepeatedTypes();
@ -56,6 +59,15 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
void RunValidJsonTest(const std::string& test_name, ConformanceLevel level,
const std::string& input_json,
const std::string& equivalent_text_format);
void RunValidJsonTest(const std::string& test_name, ConformanceLevel level,
const std::string& input_json,
const std::string& equivalent_text_format,
bool is_proto3);
void RunValidJsonTestWithMessage(const std::string& test_name,
ConformanceLevel level,
const std::string& input_json,
const std::string& equivalent_text_forma,
const Message& prototype);
void RunValidJsonTestWithProtobufInput(
const std::string& test_name, ConformanceLevel level,
const protobuf_test_messages::proto3::TestAllTypesProto3& input,
@ -78,6 +90,10 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
const std::string& input_protobuf,
const std::string& expected_protobuf,
bool is_proto3);
void RunBinaryPerformanceMergeMessageWithField(const std::string& test_name,
const std::string& field_proto,
bool is_proto3);
void RunValidProtobufTestWithMessage(
const std::string& test_name, ConformanceLevel level,
const Message* input, const std::string& equivalent_text_format,
@ -130,6 +146,13 @@ class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
void TestValidDataForOneofType(google::protobuf::FieldDescriptor::Type);
void TestMergeOneofMessage();
void TestOverwriteMessageValueMap();
void TestBinaryPerformanceForAlternatingUnknownFields();
void TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
google::protobuf::FieldDescriptor::Type);
void TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
google::protobuf::FieldDescriptor::Type);
void TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
google::protobuf::FieldDescriptor::Type, std::string field_value);
std::unique_ptr<google::protobuf::util::TypeResolver> type_resolver_;
std::string type_url_;

@ -72,7 +72,8 @@ enum TestCategory {
// https://developers.google.com/protocol-buffers/docs/proto3#json_options
// for more detail.
JSON_IGNORE_UNKNOWN_PARSING_TEST = 3;
// Test jspb wire format. Google internal only. Opensource testees just skip it.
// Test jspb wire format. Google internal only. Opensource testees just skip
// it.
JSPB_TEST = 4;
// Test text format. For cpp, java and python, testees can already deal with
// this type. Testees of other languages can simply skip it.
@ -112,8 +113,8 @@ message ConformanceRequest {
string message_type = 4;
// Each test is given a specific test category. Some category may need
// specific support in testee programs. Refer to the definition of TestCategory
// for more information.
// specific support in testee programs. Refer to the definition of
// TestCategory for more information.
TestCategory test_category = 5;
// Specify details for how to encode jspb.
@ -139,6 +140,11 @@ message ConformanceResponse {
// this field.
string serialize_error = 6;
// This should be set if the test program timed out. The string should
// provide more information about what the child process was doing when it
// was killed.
string timeout_error = 9;
// This should be set if some other error occurred. This will always
// indicate that the test failed. The string can provide more information
// about the failure.
@ -172,4 +178,3 @@ message JspbEncodingConfig {
// Encode the value field of Any as jspb array if true, otherwise binary.
bool use_jspb_array_any_format = 1;
}

@ -44,6 +44,7 @@
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "conformance/conformance.pb.h"
#include "conformance/conformance.pb.h"
using conformance::ConformanceRequest;
using conformance::ConformanceResponse;
@ -176,6 +177,59 @@ string ConformanceTestSuite::ConformanceRequestSetting::
return "";
}
void ConformanceTestSuite::TruncateDebugPayload(string* payload) {
if (payload != nullptr && payload->size() > 200) {
payload->resize(200);
payload->append("...(truncated)");
}
}
const ConformanceRequest ConformanceTestSuite::TruncateRequest(
const ConformanceRequest& request) {
ConformanceRequest debug_request(request);
switch (debug_request.payload_case()) {
case ConformanceRequest::kProtobufPayload:
TruncateDebugPayload(debug_request.mutable_protobuf_payload());
break;
case ConformanceRequest::kJsonPayload:
TruncateDebugPayload(debug_request.mutable_json_payload());
break;
case ConformanceRequest::kTextPayload:
TruncateDebugPayload(debug_request.mutable_text_payload());
break;
case ConformanceRequest::kJspbPayload:
TruncateDebugPayload(debug_request.mutable_jspb_payload());
break;
default:
// Do nothing.
break;
}
return debug_request;
}
const ConformanceResponse ConformanceTestSuite::TruncateResponse(
const ConformanceResponse& response) {
ConformanceResponse debug_response(response);
switch (debug_response.result_case()) {
case ConformanceResponse::kProtobufPayload:
TruncateDebugPayload(debug_response.mutable_protobuf_payload());
break;
case ConformanceResponse::kJsonPayload:
TruncateDebugPayload(debug_response.mutable_json_payload());
break;
case ConformanceResponse::kTextPayload:
TruncateDebugPayload(debug_response.mutable_text_payload());
break;
case ConformanceResponse::kJspbPayload:
TruncateDebugPayload(debug_response.mutable_jspb_payload());
break;
default:
// Do nothing.
break;
}
return debug_response;
}
void ConformanceTestSuite::ReportSuccess(const string& test_name) {
if (expected_to_fail_.erase(test_name) != 0) {
absl::StrAppendFormat(
@ -203,9 +257,10 @@ void ConformanceTestSuite::ReportFailure(const string& test_name,
absl::StrAppendFormat(&output_, "ERROR, test=%s: ", test_name);
unexpected_failing_tests_.insert(test_name);
}
absl::StrAppendFormat(&output_, "%s request=%s, response=%s\n", message,
request.ShortDebugString(),
response.ShortDebugString());
absl::StrAppendFormat(&output_, "%s, request=%s, response=%s\n", message,
TruncateRequest(request).ShortDebugString(),
TruncateResponse(response).ShortDebugString());
}
void ConformanceTestSuite::ReportSkip(const string& test_name,
@ -261,6 +316,7 @@ void ConformanceTestSuite::VerifyResponse(
return;
case ConformanceResponse::kParseError:
case ConformanceResponse::kTimeoutError:
case ConformanceResponse::kRuntimeError:
case ConformanceResponse::kSerializeError:
ReportFailure(test_name, level, request, response,
@ -327,7 +383,8 @@ void ConformanceTestSuite::RunTest(const string& test_name,
if (verbose_) {
absl::StrAppendFormat(
&output_, "conformance test: name=%s, request=%s, response=%s\n",
test_name, request.ShortDebugString(), response->ShortDebugString());
test_name, TruncateRequest(request).ShortDebugString(),
TruncateResponse(*response).ShortDebugString());
}
}

@ -88,10 +88,12 @@ class ForkPipeRunner : public ConformanceTestRunner {
const std::vector<ConformanceTestSuite*>& suites);
ForkPipeRunner(const std::string& executable,
const std::vector<std::string>& executable_args)
const std::vector<std::string>& executable_args,
bool performance)
: child_pid_(-1),
executable_(executable),
executable_args_(executable_args) {}
executable_args_(executable_args),
performance_(performance) {}
explicit ForkPipeRunner(const std::string& executable)
: child_pid_(-1), executable_(executable) {}
@ -114,6 +116,7 @@ class ForkPipeRunner : public ConformanceTestRunner {
pid_t child_pid_;
std::string executable_;
const std::vector<std::string> executable_args_;
bool performance_;
std::string current_test_name_;
};
@ -148,10 +151,12 @@ class ConformanceTestSuite {
public:
ConformanceTestSuite()
: verbose_(false),
performance_(false),
enforce_recommended_(false),
failure_list_flag_name_("--failure_list") {}
virtual ~ConformanceTestSuite() {}
void SetPerformance(bool performance) { performance_ = performance; }
void SetVerbose(bool verbose) { verbose_ = verbose; }
// Whether to require the testee to pass RECOMMENDED tests. By default failing
@ -272,6 +277,12 @@ class ConformanceTestSuite {
const conformance::ConformanceResponse& response,
bool need_report_success, bool require_same_wire_format);
void TruncateDebugPayload(std::string* payload);
const conformance::ConformanceRequest TruncateRequest(
const conformance::ConformanceRequest& request);
const conformance::ConformanceResponse TruncateResponse(
const conformance::ConformanceResponse& response);
void ReportSuccess(const std::string& test_name);
void ReportFailure(const std::string& test_name, ConformanceLevel level,
const conformance::ConformanceRequest& request,
@ -299,6 +310,7 @@ class ConformanceTestSuite {
int successes_;
int expected_failures_;
bool verbose_;
bool performance_;
bool enforce_recommended_;
std::string output_;
std::string output_dir_;

@ -54,12 +54,15 @@
// 4. testee sends M bytes representing a ConformanceResponse proto
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <future>
#include <vector>
#include "absl/strings/str_format.h"
@ -149,7 +152,6 @@ void ForkPipeRunner::RunTest(const std::string &test_name,
if (child_pid_ < 0) {
SpawnTestProgram();
}
current_test_name_ = test_name;
uint32_t len = request.size();
@ -164,9 +166,18 @@ void ForkPipeRunner::RunTest(const std::string &test_name,
waitpid(child_pid_, &status, WEXITED);
string error_msg;
conformance::ConformanceResponse response_obj;
if (WIFEXITED(status)) {
absl::StrAppendFormat(&error_msg, "child exited, status=%d",
WEXITSTATUS(status));
if (WEXITSTATUS(status) == 0) {
absl::StrAppendFormat(&error_msg,
"child timed out, killed by signal %d",
WTERMSIG(status));
response_obj.set_timeout_error(error_msg);
} else {
absl::StrAppendFormat(&error_msg, "child exited, status=%d",
WEXITSTATUS(status));
response_obj.set_runtime_error(error_msg);
}
} else if (WIFSIGNALED(status)) {
absl::StrAppendFormat(&error_msg, "child killed by signal %d",
WTERMSIG(status));
@ -174,8 +185,6 @@ void ForkPipeRunner::RunTest(const std::string &test_name,
GOOGLE_LOG(INFO) << error_msg;
child_pid_ = -1;
conformance::ConformanceResponse response_obj;
response_obj.set_runtime_error(error_msg);
response_obj.SerializeToString(response);
return;
}
@ -197,11 +206,15 @@ int ForkPipeRunner::Run(int argc, char *argv[],
string failure_list_filename;
conformance::FailureSet failure_list;
bool performance = false;
for (int arg = 1; arg < argc; ++arg) {
if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) {
if (++arg == argc) UsageError();
failure_list_filename = argv[arg];
ParseFailureList(argv[arg], &failure_list);
} else if (strcmp(argv[arg], "--performance") == 0) {
performance = true;
suite->SetPerformance(true);
} else if (strcmp(argv[arg], "--verbose") == 0) {
suite->SetVerbose(true);
} else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
@ -230,7 +243,7 @@ int ForkPipeRunner::Run(int argc, char *argv[],
}
}
ForkPipeRunner runner(program, program_args);
ForkPipeRunner runner(program, program_args, performance);
std::string output;
all_ok = all_ok && suite->RunSuite(&runner, &output, failure_list_filename,
@ -319,8 +332,36 @@ void ForkPipeRunner::CheckedWrite(int fd, const void *buf, size_t len) {
bool ForkPipeRunner::TryRead(int fd, void *buf, size_t len) {
size_t ofs = 0;
while (len > 0) {
ssize_t bytes_read = read(fd, (char *)buf + ofs, len);
std::future<ssize_t> future = std::async(
std::launch::async,
[](int fd, void *buf, size_t ofs, size_t len) {
return read(fd, (char *)buf + ofs, len);
},
fd, buf, ofs, len);
std::future_status status;
if (performance_) {
status = future.wait_for(std::chrono::seconds(5));
if (status == std::future_status::timeout) {
GOOGLE_LOG(ERROR) << current_test_name_ << ": timeout from test program";
kill(child_pid_, SIGQUIT);
// TODO(sandyzhang): Only log in flag-guarded mode, since reading output
// from SIGQUIT is slow and verbose.
std::vector<char> err;
err.resize(5000);
ssize_t err_bytes_read;
size_t err_ofs = 0;
do {
err_bytes_read =
read(fd, (void *)&err[err_ofs], err.size() - err_ofs);
err_ofs += err_bytes_read;
} while (err_bytes_read > 0 && err_ofs < err.size());
GOOGLE_LOG(ERROR) << "child_pid_=" << child_pid_ << " SIGQUIT: \n" << &err[0];
return false;
}
} else {
future.wait();
}
ssize_t bytes_read = future.get();
if (bytes_read == 0) {
GOOGLE_LOG(ERROR) << current_test_name_ << ": unexpected EOF from test program";
return false;

@ -51,6 +51,10 @@ using std::string;
namespace google {
namespace protobuf {
// The number of repetitions to use for performance tests.
// Corresponds approx to 500KB wireformat bytes.
static const size_t kPerformanceRepeatCount = 50000;
TextFormatConformanceTestSuite::TextFormatConformanceTestSuite() {
SetFailureListFlagName("--text_format_failure_list");
}
@ -166,6 +170,22 @@ void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2(
RunValidTextFormatTestWithMessage(test_name, level, input_text, prototype);
}
void TextFormatConformanceTestSuite::RunValidTextFormatTestWithExpected(
const string& test_name, ConformanceLevel level, const string& input_text,
const string& expected_text) {
TestAllTypesProto3 prototype;
RunValidTextFormatTestWithMessage(test_name, level, input_text, expected_text,
prototype);
}
void TextFormatConformanceTestSuite::RunValidTextFormatTestProto2WithExpected(
const string& test_name, ConformanceLevel level, const string& input_text,
const string& expected_text) {
TestAllTypesProto2 prototype;
RunValidTextFormatTestWithMessage(test_name, level, input_text, expected_text,
prototype);
}
void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
const string& test_name, ConformanceLevel level, const string& input_text,
const Message& prototype) {
@ -179,6 +199,19 @@ void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
RunValidInputTest(setting2, input_text);
}
void TextFormatConformanceTestSuite::RunValidTextFormatTestWithMessage(
const string& test_name, ConformanceLevel level, const string& input_text,
const string& expected_text, const Message& prototype) {
ConformanceRequestSetting setting1(
level, conformance::TEXT_FORMAT, conformance::PROTOBUF,
conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
RunValidInputTest(setting1, expected_text);
ConformanceRequestSetting setting2(
level, conformance::TEXT_FORMAT, conformance::TEXT_FORMAT,
conformance::TEXT_FORMAT_TEST, prototype, test_name, input_text);
RunValidInputTest(setting2, expected_text);
}
void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
const string& test_name, const Message& message) {
string serialized_input;
@ -201,276 +234,324 @@ void TextFormatConformanceTestSuite::RunValidUnknownTextFormatTest(
}
void TextFormatConformanceTestSuite::RunSuiteImpl() {
RunValidTextFormatTest("HelloWorld", REQUIRED,
"optional_string: 'Hello, World!'");
// Integer fields.
RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED,
"optional_int32: 2147483647");
RunValidTextFormatTest("Int32FieldMinValue", REQUIRED,
"optional_int32: -2147483648");
RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED,
"optional_uint32: 4294967295");
RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED,
"optional_int64: 9223372036854775807");
RunValidTextFormatTest("Int64FieldMinValue", REQUIRED,
"optional_int64: -9223372036854775808");
RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
"optional_uint64: 18446744073709551615");
// Parsers reject out-of-bound integer values.
ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
"optional_int32: 2147483648");
ExpectParseFailure("Int32FieldTooSmall", REQUIRED,
"optional_int32: -2147483649");
ExpectParseFailure("Uint32FieldTooLarge", REQUIRED,
"optional_uint32: 4294967296");
ExpectParseFailure("Int64FieldTooLarge", REQUIRED,
"optional_int64: 9223372036854775808");
ExpectParseFailure("Int64FieldTooSmall", REQUIRED,
"optional_int64: -9223372036854775809");
ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
"optional_uint64: 18446744073709551616");
// Floating point fields
RunValidTextFormatTest("FloatField", REQUIRED,
"optional_float: 3.192837");
RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
"optional_float: 3.123456789123456789");
RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
"optional_float: 3.4028235e+38");
RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
"optional_float: 1.17549e-38");
RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED,
"optional_float: NaN");
RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
"optional_float: inf");
RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
"optional_float: -inf");
RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
"optional_float: 4294967296");
RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
"optional_float: 9223372036854775808");
RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED,
"optional_float: 3.4028235e+39");
RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED,
"optional_float: 1.17549e-39");
RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
"optional_float: 18446744073709551616");
// String literals x {Strings, Bytes}
for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) {
const std::string field_name =
field_type == "String" ? "optional_string" : "optional_bytes";
RunValidTextFormatTest(
absl::StrCat("StringLiteralConcat", field_type), REQUIRED,
absl::StrCat(field_name, ": 'first' \"second\"\n'third'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralBasicEscapes", field_type), REQUIRED,
absl::StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralOctalEscapes", field_type), REQUIRED,
absl::StrCat(field_name, ": '\\341\\210\\264'"));
RunValidTextFormatTest(absl::StrCat("StringLiteralHexEscapes", field_type),
REQUIRED,
absl::StrCat(field_name, ": '\\xe1\\x88\\xb4'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralShortUnicodeEscape", field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\u1234'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralLongUnicodeEscapes", field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U00001234\\U00010437'"));
// String literals don't include line feeds.
ExpectParseFailure(absl::StrCat("StringLiteralIncludesLF", field_type),
REQUIRED,
absl::StrCat(field_name, ": 'first line\nsecond line'"));
// Unicode escapes don't include code points that lie beyond the planes
// (> 0x10ffff).
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type),
REQUIRED, absl::StrCat(field_name, ": '\\U00110000'"));
// Unicode escapes don't include surrogates.
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogatePair",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\udc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\ud800'"));
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\udc00'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d800'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000dc00'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogatePair", field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\U00000dc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\udc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong",
field_type),
RECOMMENDED, absl::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)(absl::StrCat(field_type, "FieldBadUTF8Octal"),
REQUIRED, absl::StrCat(field_name, ": '\\300'"));
(this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Hex"), REQUIRED,
absl::StrCat(field_name, ": '\\xc0'"));
}
if (!performance_) {
RunValidTextFormatTest("HelloWorld", REQUIRED,
"optional_string: 'Hello, World!'");
// Integer fields.
RunValidTextFormatTest("Int32FieldMaxValue", REQUIRED,
"optional_int32: 2147483647");
RunValidTextFormatTest("Int32FieldMinValue", REQUIRED,
"optional_int32: -2147483648");
RunValidTextFormatTest("Uint32FieldMaxValue", REQUIRED,
"optional_uint32: 4294967295");
RunValidTextFormatTest("Int64FieldMaxValue", REQUIRED,
"optional_int64: 9223372036854775807");
RunValidTextFormatTest("Int64FieldMinValue", REQUIRED,
"optional_int64: -9223372036854775808");
RunValidTextFormatTest("Uint64FieldMaxValue", REQUIRED,
"optional_uint64: 18446744073709551615");
// Parsers reject out-of-bound integer values.
ExpectParseFailure("Int32FieldTooLarge", REQUIRED,
"optional_int32: 2147483648");
ExpectParseFailure("Int32FieldTooSmall", REQUIRED,
"optional_int32: -2147483649");
ExpectParseFailure("Uint32FieldTooLarge", REQUIRED,
"optional_uint32: 4294967296");
ExpectParseFailure("Int64FieldTooLarge", REQUIRED,
"optional_int64: 9223372036854775808");
ExpectParseFailure("Int64FieldTooSmall", REQUIRED,
"optional_int64: -9223372036854775809");
ExpectParseFailure("Uint64FieldTooLarge", REQUIRED,
"optional_uint64: 18446744073709551616");
// Floating point fields
RunValidTextFormatTest("FloatField", REQUIRED, "optional_float: 3.192837");
RunValidTextFormatTest("FloatFieldWithVeryPreciseNumber", REQUIRED,
"optional_float: 3.123456789123456789");
RunValidTextFormatTest("FloatFieldMaxValue", REQUIRED,
"optional_float: 3.4028235e+38");
RunValidTextFormatTest("FloatFieldMinValue", REQUIRED,
"optional_float: 1.17549e-38");
RunValidTextFormatTest("FloatFieldNaNValue", REQUIRED,
"optional_float: NaN");
RunValidTextFormatTest("FloatFieldPosInfValue", REQUIRED,
"optional_float: inf");
RunValidTextFormatTest("FloatFieldNegInfValue", REQUIRED,
"optional_float: -inf");
RunValidTextFormatTest("FloatFieldWithInt32Max", REQUIRED,
"optional_float: 4294967296");
RunValidTextFormatTest("FloatFieldLargerThanInt64", REQUIRED,
"optional_float: 9223372036854775808");
RunValidTextFormatTest("FloatFieldTooLarge", REQUIRED,
"optional_float: 3.4028235e+39");
RunValidTextFormatTest("FloatFieldTooSmall", REQUIRED,
"optional_float: 1.17549e-39");
RunValidTextFormatTest("FloatFieldLargerThanUint64", REQUIRED,
"optional_float: 18446744073709551616");
// String literals x {Strings, Bytes}
for (const auto& field_type : std::vector<std::string>{"String", "Bytes"}) {
const std::string field_name =
field_type == "String" ? "optional_string" : "optional_bytes";
RunValidTextFormatTest(
absl::StrCat("StringLiteralConcat", field_type), REQUIRED,
absl::StrCat(field_name, ": 'first' \"second\"\n'third'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralBasicEscapes", field_type), REQUIRED,
absl::StrCat(field_name, ": '\\a\\b\\f\\n\\r\\t\\v\\?\\\\\\'\\\"'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralOctalEscapes", field_type), REQUIRED,
absl::StrCat(field_name, ": '\\341\\210\\264'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralHexEscapes", field_type), REQUIRED,
absl::StrCat(field_name, ": '\\xe1\\x88\\xb4'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralShortUnicodeEscape", field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\u1234'"));
RunValidTextFormatTest(
absl::StrCat("StringLiteralLongUnicodeEscapes", field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U00001234\\U00010437'"));
// String literals don't include line feeds.
ExpectParseFailure(
absl::StrCat("StringLiteralIncludesLF", field_type), REQUIRED,
absl::StrCat(field_name, ": 'first line\nsecond line'"));
// Unicode escapes don't include code points that lie beyond the planes
// (> 0x10ffff).
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeTooLarge", field_type),
REQUIRED, absl::StrCat(field_name, ": '\\U00110000'"));
// Unicode escapes don't include surrogates.
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogatePair",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\ud801\\udc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\ud800'"));
ExpectParseFailure(
absl::StrCat("StringLiteralShortUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\udc00'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateFirstOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d800'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogateSecondOnly",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000dc00'"));
ExpectParseFailure(
absl::StrCat("StringLiteralLongUnicodeEscapeSurrogatePair",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\U00000dc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairLongShort",
field_type),
RECOMMENDED, absl::StrCat(field_name, ": '\\U0000d801\\udc37'"));
ExpectParseFailure(
absl::StrCat("StringLiteralUnicodeEscapeSurrogatePairShortLong",
field_type),
RECOMMENDED, absl::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)(absl::StrCat(field_type, "FieldBadUTF8Octal"),
REQUIRED, absl::StrCat(field_name, ": '\\300'"));
(this->*test_method)(absl::StrCat(field_type, "FieldBadUTF8Hex"),
REQUIRED, absl::StrCat(field_name, ": '\\xc0'"));
}
// Group fields
RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
"Data { group_int32: 1 }");
RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
"Data: { group_int32: 1 }");
RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED,
"Data {}");
// Unknown Fields
UnknownToTestAllTypes message;
// Unable to print unknown Fixed32/Fixed64 fields as if they are known.
// Fixed32/Fixed64 fields are not added in the tests.
message.set_optional_int32(123);
message.set_optional_string("hello");
message.set_optional_bool(true);
RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
message.Clear();
message.mutable_nested_message()->set_c(111);
RunValidUnknownTextFormatTest("MessageUnknownFields", message);
message.Clear();
message.mutable_optionalgroup()->set_a(321);
RunValidUnknownTextFormatTest("GroupUnknownFields", message);
message.add_repeated_int32(1);
message.add_repeated_int32(2);
message.add_repeated_int32(3);
RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
// Any fields
RunValidTextFormatTest("AnyField", REQUIRED,
R"(
optional_any: {
[type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
optional_int32: 12345
// Group fields
RunValidTextFormatTestProto2("GroupFieldNoColon", REQUIRED,
"Data { group_int32: 1 }");
RunValidTextFormatTestProto2("GroupFieldWithColon", REQUIRED,
"Data: { group_int32: 1 }");
RunValidTextFormatTestProto2("GroupFieldEmpty", REQUIRED, "Data {}");
// Unknown Fields
UnknownToTestAllTypes message;
// Unable to print unknown Fixed32/Fixed64 fields as if they are known.
// Fixed32/Fixed64 fields are not added in the tests.
message.set_optional_int32(123);
message.set_optional_string("hello");
message.set_optional_bool(true);
RunValidUnknownTextFormatTest("ScalarUnknownFields", message);
message.Clear();
message.mutable_nested_message()->set_c(111);
RunValidUnknownTextFormatTest("MessageUnknownFields", message);
message.Clear();
message.mutable_optionalgroup()->set_a(321);
RunValidUnknownTextFormatTest("GroupUnknownFields", message);
message.add_repeated_int32(1);
message.add_repeated_int32(2);
message.add_repeated_int32(3);
RunValidUnknownTextFormatTest("RepeatedUnknownFields", message);
// Any fields
RunValidTextFormatTest("AnyField", REQUIRED,
R"(
optional_any: {
[type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3] {
optional_int32: 12345
}
}
}
)");
RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED,
R"(
optional_any: {
type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
value: "\b\271`"
}
)");
ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED,
R"(
optional_any: {
[type.googleapis.com/unknown] {
optional_int32: 12345
)");
RunValidTextFormatTest("AnyFieldWithRawBytes", REQUIRED,
R"(
optional_any: {
type_url: "type.googleapis.com/protobuf_test_messages.proto3.TestAllTypesProto3"
value: "\b\271`"
}
}
)");
)");
ExpectParseFailure("AnyFieldWithInvalidType", REQUIRED,
R"(
optional_any: {
[type.googleapis.com/unknown] {
optional_int32: 12345
}
}
)");
// Map fields
TestAllTypesProto3 prototype;
(*prototype.mutable_map_string_string())["c"] = "value";
(*prototype.mutable_map_string_string())["b"] = "value";
(*prototype.mutable_map_string_string())["a"] = "value";
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys",
REQUIRED,
R"(
map_string_string {
key: "a"
value: "value"
}
map_string_string {
key: "b"
value: "value"
}
map_string_string {
key: "c"
value: "value"
}
)",
prototype);
prototype.Clear();
(*prototype.mutable_map_int32_int32())[3] = 0;
(*prototype.mutable_map_int32_int32())[2] = 0;
(*prototype.mutable_map_int32_int32())[1] = 0;
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys",
REQUIRED,
R"(
map_int32_int32 {
key: 1
value: 0
}
map_int32_int32 {
key: 2
value: 0
}
map_int32_int32 {
key: 3
value: 0
}
)",
prototype);
prototype.Clear();
(*prototype.mutable_map_bool_bool())[true] = false;
(*prototype.mutable_map_bool_bool())[false] = false;
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys",
REQUIRED,
R"(
map_bool_bool {
key: false
value: false
}
map_bool_bool {
key: true
value: false
}
)",
prototype);
prototype.Clear();
ConformanceRequestSetting setting_map(
REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF,
conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"(
map_string_nested_message {
key: "duplicate"
value: { a: 123 }
}
map_string_nested_message {
key: "duplicate"
value: { corecursive: {} }
}
)");
// The last-specified value will be retained in a parsed map
RunValidInputTest(setting_map, R"(
map_string_nested_message {
key: "duplicate"
value: { corecursive: {} }
}
)");
}
// Flag control performance tests to keep them internal and opt-in only
if (performance_) {
RunTextFormatPerformanceTests();
}
}
// Map fields
TestAllTypesProto3 prototype;
(*prototype.mutable_map_string_string())["c"] = "value";
(*prototype.mutable_map_string_string())["b"] = "value";
(*prototype.mutable_map_string_string())["a"] = "value";
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapStringKeys",
REQUIRED,
R"(
map_string_string {
key: "a"
value: "value"
}
map_string_string {
key: "b"
value: "value"
}
map_string_string {
key: "c"
value: "value"
}
)",
prototype);
void TextFormatConformanceTestSuite::RunTextFormatPerformanceTests() {
TestTextFormatPerformanceMergeMessageWithRepeatedField("Bool",
"repeated_bool: true");
TestTextFormatPerformanceMergeMessageWithRepeatedField(
"Double", "repeated_double: 123");
TestTextFormatPerformanceMergeMessageWithRepeatedField(
"Int32", "repeated_uint32: 123");
TestTextFormatPerformanceMergeMessageWithRepeatedField(
"Int64", "repeated_uint64: 123");
TestTextFormatPerformanceMergeMessageWithRepeatedField(
"String", R"(repeated_string: "foo")");
TestTextFormatPerformanceMergeMessageWithRepeatedField(
"Bytes", R"(repeated_bytes: "foo")");
}
prototype.Clear();
(*prototype.mutable_map_int32_int32())[3] = 0;
(*prototype.mutable_map_int32_int32())[2] = 0;
(*prototype.mutable_map_int32_int32())[1] = 0;
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapIntKeys", REQUIRED,
R"(
map_int32_int32 {
key: 1
value: 0
}
map_int32_int32 {
key: 2
value: 0
}
map_int32_int32 {
key: 3
value: 0
}
)",
prototype);
// This is currently considered valid input by some languages but not others
void TextFormatConformanceTestSuite::
TestTextFormatPerformanceMergeMessageWithRepeatedField(
const string& test_type_name, const string& message_field) {
string recursive_message = "recursive_message { " + message_field + " }";
prototype.Clear();
(*prototype.mutable_map_bool_bool())[true] = false;
(*prototype.mutable_map_bool_bool())[false] = false;
RunValidTextFormatTestWithMessage("AlphabeticallySortedMapBoolKeys", REQUIRED,
R"(
map_bool_bool {
key: false
value: false
}
map_bool_bool {
key: true
value: false
}
)",
prototype);
string input;
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
input.append(recursive_message);
}
prototype.Clear();
ConformanceRequestSetting setting_map(
REQUIRED, conformance::TEXT_FORMAT, conformance::PROTOBUF,
conformance::TEXT_FORMAT_TEST, prototype, "DuplicateMapKey", R"(
map_string_nested_message {
key: "duplicate"
value: { a: 123 }
}
map_string_nested_message {
key: "duplicate"
value: { corecursive: {} }
}
)");
// The last-specified value will be retained in a parsed map
RunValidInputTest(setting_map, R"(
map_string_nested_message {
key: "duplicate"
value: { corecursive: {} }
}
)");
string expected = "recursive_message { ";
for (size_t i = 0; i < kPerformanceRepeatCount; i++) {
expected.append(message_field + " ");
}
expected.append("}");
RunValidTextFormatTestProto2WithExpected(
"TestTextFormatPerformanceMergeMessageWithRepeatedField" +
test_type_name + "Proto2",
RECOMMENDED, input, expected);
RunValidTextFormatTestWithExpected(
"TestTextFormatPerformanceMergeMessageWithRepeatedField" +
test_type_name + "Proto3",
RECOMMENDED, input, expected);
}
} // namespace protobuf

@ -42,15 +42,29 @@ class TextFormatConformanceTestSuite : public ConformanceTestSuite {
private:
void RunSuiteImpl() override;
void RunTextFormatPerformanceTests();
void RunValidTextFormatTest(const std::string& test_name,
ConformanceLevel level, const std::string& input);
void RunValidTextFormatTestProto2(const std::string& test_name,
ConformanceLevel level,
const std::string& input);
void RunValidTextFormatTestWithExpected(const std::string& test_name,
ConformanceLevel level,
const std::string& input,
const std::string& expected);
void RunValidTextFormatTestProto2WithExpected(const std::string& test_name,
ConformanceLevel level,
const std::string& input,
const std::string& expected);
void RunValidTextFormatTestWithMessage(const std::string& test_name,
ConformanceLevel level,
const std::string& input_text,
const Message& prototype);
void RunValidTextFormatTestWithMessage(const std::string& test_name,
ConformanceLevel level,
const std::string& input_text,
const std::string& expected_text,
const Message& prototype);
void RunValidUnknownTextFormatTest(const std::string& test_name,
const Message& message);
void ExpectParseFailure(const std::string& test_name, ConformanceLevel level,
@ -61,6 +75,8 @@ class TextFormatConformanceTestSuite : public ConformanceTestSuite {
bool ParseResponse(const conformance::ConformanceResponse& response,
const ConformanceRequestSetting& setting,
Message* test_message) override;
void TestTextFormatPerformanceMergeMessageWithRepeatedField(
const std::string& test_type_name, const std::string& message_field);
};
} // namespace protobuf

@ -728,6 +728,10 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
if (descriptor.isRepeated()) {
final List<?> valueList = (List<?>) value;
if (descriptor.isPacked()) {
if (valueList.isEmpty()) {
// The tag should not be written for empty packed fields.
return;
}
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
// Compute the total data size so the length can be written.
int dataSize = 0;
@ -893,9 +897,13 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
List<?> valueList = (List<?>) value;
if (descriptor.isPacked()) {
if (valueList.isEmpty()) {
return 0;
}
int dataSize = 0;
for (final Object element : (List<?>) value) {
for (final Object element : valueList) {
dataSize += computeElementSizeNoTag(type, element);
}
return dataSize
@ -903,7 +911,7 @@ final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
+ CodedOutputStream.computeUInt32SizeNoTag(dataSize);
} else {
int size = 0;
for (final Object element : (List<?>) value) {
for (final Object element : valueList) {
size += computeElementSize(type, number, element);
}
return size;

@ -44,6 +44,7 @@ import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.junit.runner.RunWith;
@ -230,6 +231,19 @@ public class DynamicMessageTest {
assertThat(rawBytes).isEqualTo(TestUtil.getPackedSet().toByteString());
}
@Test
public void testDynamicMessagePackedEmptySerialization() throws Exception {
Message message =
DynamicMessage.newBuilder(TestPackedTypes.getDescriptor())
.setField(
TestPackedTypes.getDescriptor()
.findFieldByNumber(TestPackedTypes.PACKED_INT64_FIELD_NUMBER),
new ArrayList<Long>())
.build();
assertThat(message.toByteString()).isEqualTo(ByteString.EMPTY);
}
@Test
public void testDynamicMessagePackedParsing() throws Exception {
TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();

@ -50,7 +50,7 @@ def junit_tests(name, srcs, data = [], deps = [], package_name = "com.google.pro
if not test_name.endswith("Test") or test_name.startswith("Abstract"):
continue
if test_prefix:
test_name = "%s%s" % (test_prefix, test_name)
test_name = "%s%s" % (test_prefix, test_name)
test_names = test_names + [test_name]
suite_name = prefix + '_' + test_name
_gen_suite(

@ -75,10 +75,7 @@ public final class Values {
* element in the iterable.
*/
public static Value of(Iterable<Value> values) {
Value.Builder valueBuilder = Value.newBuilder();
ListValue.Builder listValue = valueBuilder.getListValueBuilder();
listValue.addAllValues(values);
return valueBuilder.build();
return Value.newBuilder().setListValue(ListValue.newBuilder().addAllValues(values)).build();
}
private Values() {}

@ -6,14 +6,9 @@ load(
"pkg_files",
"strip_prefix",
)
load("//:protobuf_release.bzl", "package_naming")
load(":build_systems.bzl", "gen_file_lists")
load(":cc_dist_library.bzl", "cc_dist_library")
package_naming(
name = "protobuf_pkg_naming",
)
pkg_files(
name = "wkt_protos_files",
srcs = [
@ -375,6 +370,7 @@ cc_dist_library(
"//src/google/protobuf/io:printer",
"//src/google/protobuf/io:tokenizer",
"//src/google/protobuf/io:zero_copy_sink",
"//src/google/protobuf/json",
"//src/google/protobuf/stubs",
"//src/google/protobuf/stubs:lite",
"//src/google/protobuf/util:delimited_message_util",
@ -383,15 +379,6 @@ cc_dist_library(
"//src/google/protobuf/util:json_util",
"//src/google/protobuf/util:time_util",
"//src/google/protobuf/util:type_resolver_util",
"//src/google/protobuf/util/internal:constants",
"//src/google/protobuf/util/internal:datapiece",
"//src/google/protobuf/util/internal:default_value",
"//src/google/protobuf/util/internal:field_mask_utility",
"//src/google/protobuf/util/internal:json",
"//src/google/protobuf/util/internal:object_writer",
"//src/google/protobuf/util/internal:protostream",
"//src/google/protobuf/util/internal:type_info",
"//src/google/protobuf/util/internal:utility",
],
)
@ -434,9 +421,6 @@ cc_dist_library(
deps = [
"//src/google/protobuf:test_util",
"//src/google/protobuf:test_util2",
"//src/google/protobuf/util/internal:expecting_objectwriter",
"//src/google/protobuf/util/internal:mock_error_listener",
"//src/google/protobuf/util/internal:type_info_test_helper",
"//src/google/protobuf/compiler:annotation_test_util",
"//src/google/protobuf/compiler/cpp:unittest_lib",
],

@ -1,3 +1,3 @@
PROTOC_VERSION = '21.7'
PROTOBUF_JAVA_VERSION = '3.21.7'
PROTOBUF_PYTHON_VERSION = '4.21.7'
PROTOC_VERSION = "21.7"
PROTOBUF_JAVA_VERSION = "3.21.7"
PROTOBUF_PYTHON_VERSION = "4.21.7"

@ -414,6 +414,20 @@ class DescriptorPoolTestBase(object):
field = file_json.message_types_by_name['class'].fields_by_name['int_field']
self.assertEqual(field.json_name, 'json_int')
def testAddSerializedFileTwice(self):
if isinstance(self, SecondaryDescriptorFromDescriptorDB):
if api_implementation.Type() != 'python':
# Cpp extension cannot call Add on a DescriptorPool
# that uses a DescriptorDatabase.
# TODO(jieluo): Fix python and cpp extension diff.
return
self.pool = descriptor_pool.DescriptorPool()
file1_first = self.pool.AddSerializedFile(
self.factory_test1_fd.SerializeToString())
file1_again = self.pool.AddSerializedFile(
self.factory_test1_fd.SerializeToString())
self.assertIs(file1_first, file1_again)
def testEnumDefaultValue(self):
"""Test the default value of enums which don't start at zero."""
def _CheckDefaultValue(file_descriptor):

@ -1,3 +1,33 @@
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
# https://developers.google.com/protocol-buffers/
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Test use of numpy types with repeated and non-repeated scalar fields."""
import unittest
@ -32,6 +62,7 @@ np_2_bool_array = np.zeros(shape=(2,), dtype=np.bool_)
np_11_bool_array = np.zeros(shape=(1, 1), dtype=np.bool_)
np_22_bool_array = np.zeros(shape=(2, 2), dtype=np.bool_)
@testing_refleaks.TestCase
class NumpyIntProtoTest(unittest.TestCase):
@ -94,6 +125,7 @@ class NumpyIntProtoTest(unittest.TestCase):
with self.assertRaises(TypeError):
message.optional_int64 = np_22_float_array
@testing_refleaks.TestCase
class NumpyFloatProtoTest(unittest.TestCase):
@ -122,6 +154,7 @@ class NumpyFloatProtoTest(unittest.TestCase):
with self.assertRaises(TypeError):
message.optional_float = np_22_float_array
@testing_refleaks.TestCase
class NumpyBoolProtoTest(unittest.TestCase):
@ -150,6 +183,7 @@ class NumpyBoolProtoTest(unittest.TestCase):
with self.assertRaises(TypeError):
message.optional_bool = np_22_bool_array
@testing_refleaks.TestCase
class NumpyProtoIndexingTest(unittest.TestCase):
@ -178,4 +212,4 @@ class NumpyProtoIndexingTest(unittest.TestCase):
dtype=int)]
if __name__ == '__main__':
unittest.main()
unittest.main()

@ -31,7 +31,6 @@ pkg_filegroup(
"//src/google/protobuf/stubs:dist_files",
"//src/google/protobuf/testing:dist_files",
"//src/google/protobuf/util:dist_files",
"//src/google/protobuf/util/internal:dist_files",
],
visibility = ["//pkg:__pkg__"],
)

@ -24,7 +24,6 @@ set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/any.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc
@ -54,6 +53,7 @@ set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/message.cc
@ -72,20 +72,6 @@ set(libprotobuf_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/utility.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util.cc
@ -143,6 +129,7 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.h
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.h
${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.h
${protobuf_SOURCE_DIR}/src/google/protobuf/map.h
${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry.h
${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry_lite.h
@ -179,24 +166,6 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/constants.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/datapiece.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/error_listener.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/field_mask_utility.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_escaping.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/location_tracker.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_location_tracker.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_source.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/object_writer.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/proto_writer.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/structured_objectwriter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/utility.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util.h
@ -210,7 +179,6 @@ set(libprotobuf_hdrs
set(libprotobuf_lite_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.cc
@ -570,7 +538,6 @@ set(test_util_srcs
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/annotation_test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_tester.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.cc
)
# //pkg:test_util
@ -587,15 +554,13 @@ set(test_util_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util2.h
${protobuf_SOURCE_DIR}/src/google/protobuf/test_util_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/expecting_objectwriter.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/mock_error_listener.h
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.h
${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_unittest.inc
)
# //src/google/protobuf:full_test_srcs
set(protobuf_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arena_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler_test.cc
@ -721,13 +686,6 @@ set(util_test_files
${protobuf_SOURCE_DIR}/src/google/protobuf/util/delimited_message_util_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_comparator_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/field_mask_util_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/default_value_objectwriter_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_objectwriter_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/json_stream_parser_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectsource_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/protostream_objectwriter_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/type_info_test_helper.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_util_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/time_util_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/util/type_resolver_util_test.cc
@ -735,17 +693,6 @@ set(util_test_files
# //src/google/protobuf/util:test_proto_srcs
set(util_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/anys.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/books.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/default_value.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/default_value_test.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/field_mask.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/maps.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/oneofs.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/proto3.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/struct.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/timestamp_duration.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/internal/testdata/wrappers.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/json_format_proto3.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/util/message_differencer_unittest.proto

@ -10,6 +10,7 @@ load("//build_defs:cpp_opts.bzl", "COPTS", "LINK_OPTS")
package(
default_visibility = [
"//:__pkg__", # "public" targets are alias rules in //.
"//json:__subpackages__",
],
)
@ -162,11 +163,66 @@ cc_library(
],
)
cc_library(
name = "arena_align",
srcs = ["arena_align.cc"],
hdrs = ["arena_align.h"],
include_prefix = "google/protobuf",
visibility = [
"//:__subpackages__",
"//src/google/protobuf:__subpackages__",
],
deps = [
"//src/google/protobuf/stubs:lite",
"@com_google_absl//absl/numeric:bits",
],
)
cc_library(
name = "arena_cleanup",
hdrs = ["arena_cleanup.h"],
include_prefix = "google/protobuf",
visibility = [
"//:__subpackages__",
"//src/google/protobuf:__subpackages__",
],
deps = [
"@com_google_absl//absl/base:core_headers",
],
)
cc_library(
name = "arena_config",
srcs = ["arena_config.cc"],
hdrs = ["arena_config.h"],
include_prefix = "google/protobuf",
visibility = [
"//:__subpackages__",
"//src/google/protobuf:__subpackages__",
],
deps = [
"//src/google/protobuf/stubs:lite",
],
)
cc_library(
name = "arena_allocation_policy",
hdrs = ["arena_allocation_policy.h"],
include_prefix = "google/protobuf",
visibility = [
"//:__subpackages__",
"//src/google/protobuf:__subpackages__",
],
deps = [
":arena_config",
"//src/google/protobuf/stubs:lite",
],
)
cc_library(
name = "arena",
srcs = [
"arena.cc",
"arena_config.cc",
],
hdrs = [
"arena.h",
@ -180,6 +236,9 @@ cc_library(
"//src/google/protobuf:__subpackages__",
],
deps = [
":arena_allocation_policy",
":arena_cleanup",
":arena_config",
"//src/google/protobuf/stubs:lite",
"@com_google_absl//absl/synchronization",
],
@ -207,7 +266,6 @@ cc_library(
hdrs = [
"any.h",
"arena.h",
"arena_config.h",
"arena_impl.h",
"arenastring.h",
"arenaz_sampler.h",
@ -250,6 +308,7 @@ cc_library(
# In Bazel 6.0+, these will be `interface_deps`:
deps = [
":arena",
":arena_config",
"//src/google/protobuf/io",
"//src/google/protobuf/stubs:lite",
"@com_google_absl//absl/container:flat_hash_set",
@ -673,6 +732,22 @@ cc_test(
],
)
cc_test(
name = "arena_align_test",
srcs = ["arena_align_test.cc"],
copts = COPTS + select({
"//build_defs:config_msvc": [],
"//conditions:default": [
"-Wno-error=sign-compare",
],
}),
deps = [
":arena_align",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "arena_unittest",
srcs = ["arena_unittest.cc"],

@ -38,6 +38,7 @@
#include <typeinfo>
#include "absl/synchronization/mutex.h"
#include "google/protobuf/arena_allocation_policy.h"
#include "google/protobuf/arena_impl.h"
#include "google/protobuf/arenaz_sampler.h"
#include "google/protobuf/port.h"
@ -55,8 +56,9 @@ namespace protobuf {
namespace internal {
namespace {
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT ArenaBlock
kSentryArenaBlock = {};
// kSentryArenaBlock is used for arenas which can be referenced pre-main. So,
// constexpr is required.
constexpr ArenaBlock kSentryArenaBlock = {};
ArenaBlock* SentryArenaBlock() {
// const_cast<> is okay as kSentryArenaBlock will never be mutated.
@ -122,7 +124,7 @@ SerialArena::SerialArena(ArenaBlock* b, ThreadSafeArena& parent)
: ptr_{b->Pointer(kBlockHeaderSize + ThreadSafeArena::kSerialArenaSize)},
limit_{b->Limit()},
head_{b},
space_allocated_{b->size()},
space_allocated_{b->size},
parent_{parent} {
GOOGLE_DCHECK(!b->IsSentry());
}
@ -135,7 +137,7 @@ SerialArena::SerialArena(ThreadSafeArena& parent)
// provided or newly allocated to store AllocationPolicy.
SerialArena::SerialArena(FirstSerialArena, ArenaBlock* b,
ThreadSafeArena& parent)
: head_{b}, space_allocated_{b->size()}, parent_{parent} {
: head_{b}, space_allocated_{b->size}, parent_{parent} {
if (b->IsSentry()) return;
set_ptr(b->Pointer(kBlockHeaderSize));
@ -145,9 +147,9 @@ SerialArena::SerialArena(FirstSerialArena, ArenaBlock* b,
void SerialArena::Init(ArenaBlock* b, size_t offset) {
set_ptr(b->Pointer(offset));
limit_ = b->Limit();
set_head(b);
space_used_.relaxed_set(0);
space_allocated_.relaxed_set(b->size());
head_.store(b, std::memory_order_relaxed);
space_used_.store(0, std::memory_order_relaxed);
space_allocated_.store(b->size, std::memory_order_relaxed);
cached_block_length_ = 0;
cached_blocks_ = nullptr;
}
@ -164,11 +166,11 @@ SerialArena* SerialArena::New(Memory mem, ThreadSafeArena& parent) {
template <typename Deallocator>
SerialArena::Memory SerialArena::Free(Deallocator deallocator) {
ArenaBlock* b = head();
Memory mem = {b, b->size()};
Memory mem = {b, b->size};
while (b->next) {
b = b->next; // We must first advance before deleting this block
deallocator(mem);
mem = {b, b->size()};
mem = {b, b->size};
}
return mem;
}
@ -204,8 +206,9 @@ void SerialArena::AllocateNewBlock(size_t n) {
// Record how much used in this block.
used = static_cast<size_t>(ptr() - old_head->Pointer(kBlockHeaderSize));
wasted = old_head->size() - used;
space_used_.relaxed_set(space_used_.relaxed_get() + used);
wasted = old_head->size - used;
space_used_.store(space_used_.load(std::memory_order_relaxed) + used,
std::memory_order_relaxed);
}
// TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
@ -213,18 +216,21 @@ void SerialArena::AllocateNewBlock(size_t n) {
// but with a CPU regression. The regression might have been an artifact of
// the microbenchmark.
auto mem = AllocateMemory(parent_.AllocPolicy(), old_head->size(), n);
auto mem = AllocateMemory(parent_.AllocPolicy(), old_head->size, n);
// We don't want to emit an expensive RMW instruction that requires
// exclusive access to a cacheline. Hence we write it in terms of a
// regular add.
space_allocated_.relaxed_set(space_allocated_.relaxed_get() + mem.size);
space_allocated_.store(
space_allocated_.load(std::memory_order_relaxed) + mem.size,
std::memory_order_relaxed);
ThreadSafeArenaStats::RecordAllocateStats(parent_.arena_stats_.MutableStats(),
/*used=*/used,
/*allocated=*/mem.size, wasted);
auto* new_head = new (mem.ptr) ArenaBlock{old_head, mem.size};
set_head(new_head);
set_ptr(new_head->Pointer(kBlockHeaderSize));
limit_ = new_head->Limit();
// Previous writes must take effect before writing new head.
head_.store(new_head, std::memory_order_release);
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(ptr(), limit_ - ptr());
@ -239,15 +245,15 @@ uint64_t SerialArena::SpaceUsed() const {
// usage of the *current* block.
// TODO(mkruskal) Consider eliminating this race in exchange for a possible
// performance hit on ARM (see cl/455186837).
const ArenaBlock* h = head();
const ArenaBlock* h = head_.load(std::memory_order_acquire);
if (h->IsSentry()) return 0;
const uint64_t current_block_size = h->size();
const uint64_t current_block_size = h->size;
uint64_t current_space_used = std::min(
static_cast<uint64_t>(
ptr() - const_cast<ArenaBlock*>(h)->Pointer(kBlockHeaderSize)),
current_block_size);
return current_space_used + space_used_.relaxed_get();
return current_space_used + space_used_.load(std::memory_order_relaxed);
}
void SerialArena::CleanupList() {
@ -308,21 +314,21 @@ void SerialArena::CleanupList() {
// struct SerialArenaChunkHeader {
// SerialArenaChunk* next_chunk;
// uint32_t capacity;
// Atomic<uint32_t> size;
// std::atomic<uint32_t> size;
// } header;
// Atomic<void*> ids[];
// Atomic<SerialArena*> arenas[];
// std::atomic<void*> ids[];
// std::atomic<SerialArena*> arenas[];
// };
//
// where the size of "ids" and "arenas" is determined at runtime; hence the use
// of Layout.
struct SerialArenaChunkHeader {
PROTOBUF_CONSTEXPR SerialArenaChunkHeader(uint32_t capacity, uint32_t size)
constexpr SerialArenaChunkHeader(uint32_t capacity, uint32_t size)
: next_chunk(nullptr), capacity(capacity), size(size) {}
ThreadSafeArena::SerialArenaChunk* next_chunk;
uint32_t capacity;
Atomic<uint32_t> size;
std::atomic<uint32_t> size;
};
class ThreadSafeArena::SerialArenaChunk {
@ -330,14 +336,14 @@ class ThreadSafeArena::SerialArenaChunk {
SerialArenaChunk(uint32_t capacity, void* me, SerialArena* serial) {
new (&header()) SerialArenaChunkHeader{capacity, 1};
new (&id(0)) Atomic<void*>{me};
new (&id(0)) std::atomic<void*>{me};
for (uint32_t i = 1; i < capacity; ++i) {
new (&id(i)) Atomic<void*>{nullptr};
new (&id(i)) std::atomic<void*>{nullptr};
}
new (&arena(0)) Atomic<SerialArena*>{serial};
new (&arena(0)) std::atomic<SerialArena*>{serial};
for (uint32_t i = 1; i < capacity; ++i) {
new (&arena(i)) Atomic<void*>{nullptr};
new (&arena(i)) std::atomic<void*>{nullptr};
}
}
@ -355,29 +361,29 @@ class ThreadSafeArena::SerialArenaChunk {
void set_capacity(uint32_t capacity) { header().capacity = capacity; }
// ids: returns up to size().
absl::Span<const Atomic<void*>> ids() const {
absl::Span<const std::atomic<void*>> ids() const {
return Layout(capacity()).Slice<kIds>(ptr()).first(safe_size());
}
absl::Span<Atomic<void*>> ids() {
absl::Span<std::atomic<void*>> ids() {
return Layout(capacity()).Slice<kIds>(ptr()).first(safe_size());
}
Atomic<void*>& id(uint32_t i) {
std::atomic<void*>& id(uint32_t i) {
GOOGLE_DCHECK_LT(i, capacity());
return Layout(capacity()).Pointer<kIds>(ptr())[i];
}
// arenas: returns up to size().
absl::Span<const Atomic<SerialArena*>> arenas() const {
absl::Span<const std::atomic<SerialArena*>> arenas() const {
return Layout(capacity()).Slice<kArenas>(ptr()).first(safe_size());
}
absl::Span<Atomic<SerialArena*>> arenas() {
absl::Span<std::atomic<SerialArena*>> arenas() {
return Layout(capacity()).Slice<kArenas>(ptr()).first(safe_size());
}
const Atomic<SerialArena*>& arena(uint32_t i) const {
const std::atomic<SerialArena*>& arena(uint32_t i) const {
GOOGLE_DCHECK_LT(i, capacity());
return Layout(capacity()).Pointer<kArenas>(ptr())[i];
}
Atomic<SerialArena*>& arena(uint32_t i) {
std::atomic<SerialArena*>& arena(uint32_t i) {
GOOGLE_DCHECK_LT(i, capacity());
return Layout(capacity()).Pointer<kArenas>(ptr())[i];
}
@ -391,16 +397,16 @@ class ThreadSafeArena::SerialArenaChunk {
// other paths, either race is not possible (GetSerialArenaFallback) or must
// be prevented by users (CleanupList, Free).
bool insert(void* me, SerialArena* serial) {
uint32_t idx = size().relaxed_fetch_add(1);
uint32_t idx = size().fetch_add(1, std::memory_order_relaxed);
// Bail out if this chunk is full.
if (idx >= capacity()) {
// Write old value back to avoid potential overflow.
size().relaxed_set(capacity());
size().store(capacity(), std::memory_order_relaxed);
return false;
}
id(idx).relaxed_set(me);
arena(idx).relaxed_set(serial);
id(idx).store(me, std::memory_order_relaxed);
arena(idx).store(serial, std::memory_order_release);
return true;
}
@ -411,9 +417,8 @@ class ThreadSafeArena::SerialArenaChunk {
constexpr static int kIds = 1;
constexpr static int kArenas = 2;
using layout_type =
absl::container_internal::Layout<SerialArenaChunkHeader, Atomic<void*>,
Atomic<SerialArena*>>;
using layout_type = absl::container_internal::Layout<
SerialArenaChunkHeader, std::atomic<void*>, std::atomic<SerialArena*>>;
const char* ptr() const { return reinterpret_cast<const char*>(this); }
char* ptr() { return reinterpret_cast<char*>(this); }
@ -425,13 +430,13 @@ class ThreadSafeArena::SerialArenaChunk {
return *layout_type::Partial().Pointer<kHeader>(ptr());
}
Atomic<uint32_t>& size() { return header().size; }
const Atomic<uint32_t>& size() const { return header().size; }
std::atomic<uint32_t>& size() { return header().size; }
const std::atomic<uint32_t>& size() const { return header().size; }
// Returns the size capped by the capacity as fetch_add may result in a size
// greater than capacity.
uint32_t safe_size() const {
return std::min(capacity(), size().relaxed_get());
return std::min(capacity(), size().load(std::memory_order_relaxed));
}
constexpr static layout_type Layout(size_t n) {
@ -442,7 +447,7 @@ class ThreadSafeArena::SerialArenaChunk {
}
};
PROTOBUF_CONSTEXPR SerialArenaChunkHeader kSentryArenaChunk = {0, 0};
constexpr SerialArenaChunkHeader kSentryArenaChunk = {0, 0};
ThreadSafeArena::SerialArenaChunk* ThreadSafeArena::SentrySerialArenaChunk() {
// const_cast is okay because the sentry chunk is never mutated. Also,
@ -562,7 +567,8 @@ uint64_t ThreadSafeArena::GetNextLifeCycleId() {
// On platforms that don't support uint64_t atomics we can certainly not
// afford to increment by large intervals and expect uniqueness due to
// wrapping, hence we only add by 1.
id = lifecycle_id_generator_.id.relaxed_fetch_add(1) * kInc;
id = lifecycle_id_generator_.id.fetch_add(1, std::memory_order_relaxed) *
kInc;
}
tc.next_lifecycle_id = id + kDelta;
return id;
@ -597,7 +603,7 @@ ThreadSafeArena::SerialArenaChunk* ThreadSafeArena::NewSerialArenaChunk(
// Tries to reserve an entry by atomic fetch_add. If the head chunk is already
// full (size >= capacity), acquires the mutex and adds a new head.
void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) {
SerialArenaChunk* head = head_.atomic_get();
SerialArenaChunk* head = head_.load(std::memory_order_acquire);
// Fast path without acquiring mutex.
if (!head->IsSentry() && head->insert(id, serial)) {
return;
@ -607,7 +613,7 @@ void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) {
absl::MutexLock lock(&mutex_);
// Refetch and if someone else installed a new head, try allocating on that!
SerialArenaChunk* new_head = head_.atomic_get();
SerialArenaChunk* new_head = head_.load(std::memory_order_acquire);
if (new_head != head) {
if (new_head->insert(id, serial)) return;
// Update head to link to the latest one.
@ -619,7 +625,7 @@ void ThreadSafeArena::AddSerialArena(void* id, SerialArena* serial) {
// Use "std::memory_order_release" to make sure prior stores are visible after
// this one.
head_.atomic_set(new_head);
head_.store(new_head, std::memory_order_release);
}
void ThreadSafeArena::Init() {
@ -631,7 +637,7 @@ void ThreadSafeArena::Init() {
GOOGLE_DCHECK_EQ(tag_and_id_, kMessageOwnedArena);
}
arena_stats_ = Sample();
head_.relaxed_set(SentrySerialArenaChunk());
head_.store(SentrySerialArenaChunk(), std::memory_order_relaxed);
GOOGLE_DCHECK_EQ(message_owned, IsMessageOwned());
first_owner_ = &thread_cache();
@ -668,12 +674,12 @@ SerialArena::Memory ThreadSafeArena::Free(size_t* space_allocated) {
auto deallocator = GetDeallocator(alloc_policy_.get(), space_allocated);
WalkSerialArenaChunk([deallocator](SerialArenaChunk* chunk) {
absl::Span<Atomic<SerialArena*>> span = chunk->arenas();
absl::Span<std::atomic<SerialArena*>> span = chunk->arenas();
// Walks arenas backward to handle the first serial arena the last. Freeing
// in reverse-order to the order in which objects were created may not be
// necessary to Free and we should revisit this. (b/247560530)
for (auto it = span.rbegin(); it != span.rend(); ++it) {
SerialArena* serial = it->relaxed_get();
SerialArena* serial = it->load(std::memory_order_relaxed);
GOOGLE_DCHECK_NE(serial, nullptr);
// Always frees the first block of "serial" as it cannot be user-provided.
SerialArena::Memory mem = serial->Free(deallocator);
@ -734,21 +740,21 @@ void* ThreadSafeArena::AllocateAlignedWithCleanup(size_t n, size_t align,
void ThreadSafeArena::AddCleanup(void* elem, void (*cleanup)(void*)) {
SerialArena* arena;
if (PROTOBUF_PREDICT_FALSE(!GetSerialArenaFast(&arena))) {
arena = GetSerialArenaFallback();
arena = GetSerialArenaFallback(kMaxCleanupNodeSize);
}
arena->AddCleanup(elem, cleanup, AllocPolicy(), arena_stats_.MutableStats());
arena->AddCleanup(elem, cleanup);
}
PROTOBUF_NOINLINE
void* ThreadSafeArena::AllocateAlignedWithCleanupFallback(
size_t n, size_t align, void (*destructor)(void*)) {
return GetSerialArenaFallback()->AllocateAlignedWithCleanup(n, align,
destructor);
return GetSerialArenaFallback(n + kMaxCleanupNodeSize)
->AllocateAlignedWithCleanup(n, align, destructor);
}
template <typename Functor>
void ThreadSafeArena::WalkConstSerialArenaChunk(Functor fn) const {
const SerialArenaChunk* chunk = head_.atomic_get();
const SerialArenaChunk* chunk = head_.load(std::memory_order_acquire);
for (; !chunk->IsSentry(); chunk = chunk->next_chunk()) {
fn(chunk);
@ -760,7 +766,7 @@ void ThreadSafeArena::WalkSerialArenaChunk(Functor fn) {
// By omitting an Acquire barrier we help the sanitizer that any user code
// that doesn't properly synchronize Reset() or the destructor will throw a
// TSAN warning.
SerialArenaChunk* chunk = head_.relaxed_get();
SerialArenaChunk* chunk = head_.load(std::memory_order_relaxed);
while (!chunk->IsSentry()) {
// Cache next chunk in case this chunk is destroyed.
@ -774,7 +780,7 @@ template <typename Functor>
void ThreadSafeArena::PerConstSerialArenaInChunk(Functor fn) const {
WalkConstSerialArenaChunk([&fn](const SerialArenaChunk* chunk) {
for (const auto& each : chunk->arenas()) {
const SerialArena* serial = each.relaxed_get();
const SerialArena* serial = each.load(std::memory_order_acquire);
// It is possible that newly added SerialArena is not updated although
// size was. This is acceptable for SpaceAllocated and SpaceUsed.
if (serial == nullptr) continue;
@ -805,7 +811,7 @@ uint64_t ThreadSafeArena::SpaceUsed() const {
template <AllocationClient alloc_client>
PROTOBUF_NOINLINE void* ThreadSafeArena::AllocateAlignedFallback(size_t n) {
return GetSerialArenaFallback()->AllocateAligned<alloc_client>(n);
return GetSerialArenaFallback(n)->AllocateAligned<alloc_client>(n);
}
template void* ThreadSafeArena::AllocateAlignedFallback<
@ -815,12 +821,12 @@ template void*
void ThreadSafeArena::CleanupList() {
WalkSerialArenaChunk([](SerialArenaChunk* chunk) {
absl::Span<Atomic<SerialArena*>> span = chunk->arenas();
absl::Span<std::atomic<SerialArena*>> span = chunk->arenas();
// Walks arenas backward to handle the first serial arena the last.
// Destroying in reverse-order to the construction is often assumed by users
// and required not to break inter-object dependencies. (b/247560530)
for (auto it = span.rbegin(); it != span.rend(); ++it) {
SerialArena* serial = it->relaxed_get();
SerialArena* serial = it->load(std::memory_order_relaxed);
GOOGLE_DCHECK_NE(serial, nullptr);
serial->CleanupList();
}
@ -830,7 +836,7 @@ void ThreadSafeArena::CleanupList() {
}
PROTOBUF_NOINLINE
SerialArena* ThreadSafeArena::GetSerialArenaFallback() {
SerialArena* ThreadSafeArena::GetSerialArenaFallback(size_t n) {
void* const id = &thread_cache();
if (id == first_owner_) {
CacheSerialArena(&first_arena_);
@ -840,10 +846,10 @@ SerialArena* ThreadSafeArena::GetSerialArenaFallback() {
// Search matching SerialArena.
SerialArena* serial = nullptr;
WalkConstSerialArenaChunk([&serial, id](const SerialArenaChunk* chunk) {
absl::Span<const Atomic<void*>> ids = chunk->ids();
absl::Span<const std::atomic<void*>> ids = chunk->ids();
for (uint32_t i = 0; i < ids.size(); ++i) {
if (ids[i].relaxed_get() == id) {
serial = chunk->arena(i).relaxed_get();
if (ids[i].load(std::memory_order_relaxed) == id) {
serial = chunk->arena(i).load(std::memory_order_relaxed);
GOOGLE_DCHECK_NE(serial, nullptr);
break;
}
@ -852,9 +858,10 @@ SerialArena* ThreadSafeArena::GetSerialArenaFallback() {
if (!serial) {
// This thread doesn't have any SerialArena, which also means it doesn't
// have any blocks yet. So we'll allocate its first block now.
// have any blocks yet. So we'll allocate its first block now. It must be
// big enough to host SerialArena and the pending request.
serial = SerialArena::New(
AllocateMemory(alloc_policy_.get(), 0, kSerialArenaSize), *this);
AllocateMemory(alloc_policy_.get(), 0, n + kSerialArenaSize), *this);
AddSerialArena(id, serial);
}

@ -28,15 +28,18 @@
// (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/util/internal/error_listener.h"
#include "google/protobuf/arena_align.h"
#include <cstddef>
#include <cstdint>
namespace google {
namespace protobuf {
namespace util {
namespace converter {
namespace internal {
// There are still compilers (open source) requiring a definition for constexpr.
constexpr size_t ArenaAlignDefault::align; // NOLINT
} // namespace converter
} // namespace util
} // namespace internal
} // namespace protobuf
} // namespace google

@ -0,0 +1,155 @@
// 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.
// This file provides alignment utilities for use in arenas.
//
// `ArenaAlign` constains a single `align` data member and provides
// the below functions which operate on the given alignment.
//
// Ceil(size_t n) - rounds `n` up to the nearest `align` boundary.
// Floor(size_t n) - rounds `n` down to the nearest `align` boundary.
// Ceil(T* P) - rounds `p` up to the nearest `align` boundary.
// IsAligned(size_t n) - returns true if `n` is aligned to `align`
// IsAligned(T* p) - returns true if `p` is aligned to `align`
// CheckAligned(T* p) - returns `p`. Checks alignment of `p` in debug.
//
// Additionally there is an optimized `CeilDefaultAligned(T*)` method which is
// equivalent to `Ceil(ArenaAlignDefault().CheckAlign(p))` but more efficiently
// implemented as a 'check only' for ArenaAlignDefault.
//
// These classes allow for generic arena logic using 'alignment policies'.
//
// For example:
//
// template <Align>
// void* NaiveAlloc(size_t n, Align align) {
// align.CheckAligned(n);
// uint8_t* ptr = align.CeilDefaultAligned(ptr_);
// ptr_ += n;
// return ptr;
// }
//
// void CallSites() {
// void *p1 = NaiveAlloc(n, ArenaAlignDefault());
// void *p2 = NaiveAlloc(n, ArenaAlignAs(32));
// }
//
#ifndef GOOGLE_PROTOBUF_ARENA_ALIGN_H__
#define GOOGLE_PROTOBUF_ARENA_ALIGN_H__
#include <cstddef>
#include <cstdint>
#include "google/protobuf/stubs/logging.h"
#include "google/protobuf/stubs/common.h"
#include "absl/numeric/bits.h"
namespace google {
namespace protobuf {
namespace internal {
struct ArenaAlignDefault {
static constexpr size_t align = 8; // NOLINT
static constexpr bool IsAligned(size_t n) { return (n & (align - 1)) == 0; }
template <typename T>
static bool IsAligned(T* ptr) {
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0;
}
static constexpr size_t Ceil(size_t n) { return (n + align - 1) & -align; }
static constexpr size_t Floor(size_t n) { return (n & ~(align - 1)); }
template <typename T>
T* Ceil(T* ptr) const {
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
return reinterpret_cast<T*>((intptr + align - 1) & -align);
}
template <typename T>
T* CeilDefaultAligned(T* ptr) const {
return ArenaAlignDefault().CheckAligned(ptr);
}
// Address sanitizer enabled alignment check
template <typename T>
static T* CheckAligned(T* ptr) {
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr);
return ptr;
}
};
struct ArenaAlign {
static constexpr bool IsDefault() { return false; };
size_t align = 8;
constexpr bool IsAligned(size_t n) const { return (n & (align - 1)) == 0; }
template <typename T>
bool IsAligned(T* ptr) const {
return (reinterpret_cast<uintptr_t>(ptr) & (align - 1)) == 0;
}
constexpr size_t Ceil(size_t n) const { return (n + align - 1) & -align; }
constexpr size_t Floor(size_t n) const { return (n & ~(align - 1)); }
template <typename T>
T* Ceil(T* ptr) const {
uintptr_t intptr = reinterpret_cast<uintptr_t>(ptr);
return reinterpret_cast<T*>((intptr + align - 1) & -align);
}
template <typename T>
T* CeilDefaultAligned(T* ptr) const {
return Ceil(ArenaAlignDefault().CheckAligned(ptr));
}
// Address sanitizer enabled alignment check
template <typename T>
T* CheckAligned(T* ptr) const {
GOOGLE_DCHECK(IsAligned(ptr)) << static_cast<void*>(ptr);
return ptr;
}
};
inline ArenaAlign ArenaAlignAs(size_t align) {
// align must be a non zero power of 2 >= 8
GOOGLE_DCHECK_NE(align, 0);
GOOGLE_DCHECK(absl::has_single_bit(align)) << "Invalid alignment " << align;
return ArenaAlign{align};
}
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_ALIGN_H__

@ -0,0 +1,215 @@
// 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/arena_align.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace google {
namespace protobuf {
namespace internal {
namespace {
using ::testing::Eq;
TEST(ArenaAlignDefault, Align) {
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.align, Eq(8));
}
TEST(ArenaAlignDefault, Floor) {
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.Floor(0), Eq(0));
EXPECT_THAT(align_default.Floor(1), Eq(0));
EXPECT_THAT(align_default.Floor(7), Eq(0));
EXPECT_THAT(align_default.Floor(8), Eq(8));
EXPECT_THAT(align_default.Floor(9), Eq(8));
EXPECT_THAT(align_default.Floor(15), Eq(8));
EXPECT_THAT(align_default.Floor(16), Eq(16));
}
TEST(ArenaAlignDefault, Ceil) {
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.Ceil(0), Eq(0));
EXPECT_THAT(align_default.Ceil(1), Eq(8));
EXPECT_THAT(align_default.Ceil(7), Eq(8));
EXPECT_THAT(align_default.Ceil(8), Eq(8));
EXPECT_THAT(align_default.Ceil(9), Eq(16));
EXPECT_THAT(align_default.Ceil(15), Eq(16));
EXPECT_THAT(align_default.Ceil(16), Eq(16));
}
TEST(ArenaAlignDefault, CeilPtr) {
char p[17] = {0};
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.Ceil(p + 0), Eq(p + 0));
EXPECT_THAT(align_default.Ceil(p + 1), Eq(p + 8));
EXPECT_THAT(align_default.Ceil(p + 7), Eq(p + 8));
EXPECT_THAT(align_default.Ceil(p + 8), Eq(p + 8));
EXPECT_THAT(align_default.Ceil(p + 9), Eq(p + 16));
EXPECT_THAT(align_default.Ceil(p + 15), Eq(p + 16));
EXPECT_THAT(align_default.Ceil(p + 16), Eq(p + 16));
}
TEST(ArenaAlignDefault, CheckAligned) {
char p[17] = {0};
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.CheckAligned(p + 0), Eq(p + 0));
EXPECT_THAT(align_default.CheckAligned(p + 8), Eq(p + 8));
EXPECT_THAT(align_default.CheckAligned(p + 16), Eq(p + 16));
#ifdef PROTOBUF_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 1), ".*");
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 7), ".*");
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 9), ".*");
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 15), ".*");
EXPECT_DEBUG_DEATH(align_default.CheckAligned(p + 17), ".*");
#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST(ArenaAlignDefault, CeilDefaultAligned) {
char p[17] = {0};
auto align_default = ArenaAlignDefault();
EXPECT_THAT(align_default.CeilDefaultAligned(p + 0), Eq(p + 0));
EXPECT_THAT(align_default.CeilDefaultAligned(p + 8), Eq(p + 8));
EXPECT_THAT(align_default.CeilDefaultAligned(p + 16), Eq(p + 16));
#ifdef PROTOBUF_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 1), ".*");
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 7), ".*");
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 9), ".*");
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 15), ".*");
EXPECT_DEBUG_DEATH(align_default.CeilDefaultAligned(p + 17), ".*");
#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST(ArenaAlignDefault, IsAligned) {
auto align_default = ArenaAlignDefault();
EXPECT_TRUE(align_default.IsAligned(0));
EXPECT_FALSE(align_default.IsAligned(1));
EXPECT_FALSE(align_default.IsAligned(7));
EXPECT_TRUE(align_default.IsAligned(8));
EXPECT_FALSE(align_default.IsAligned(9));
EXPECT_FALSE(align_default.IsAligned(15));
EXPECT_TRUE(align_default.IsAligned(16));
}
TEST(ArenaAlign, Align) {
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.align, Eq(64));
}
TEST(ArenaAlign, Floor) {
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.Floor(0), Eq(0));
EXPECT_THAT(align_64.Floor(1), Eq(0));
EXPECT_THAT(align_64.Floor(63), Eq(0));
EXPECT_THAT(align_64.Floor(64), Eq(64));
EXPECT_THAT(align_64.Floor(65), Eq(64));
EXPECT_THAT(align_64.Floor(127), Eq(64));
EXPECT_THAT(align_64.Floor(128), Eq(128));
}
TEST(ArenaAlign, Ceil) {
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.Ceil(0), Eq(0));
EXPECT_THAT(align_64.Ceil(1), Eq(64));
EXPECT_THAT(align_64.Ceil(63), Eq(64));
EXPECT_THAT(align_64.Ceil(64), Eq(64));
EXPECT_THAT(align_64.Ceil(65), Eq(128));
EXPECT_THAT(align_64.Ceil(127), Eq(128));
EXPECT_THAT(align_64.Ceil(128), Eq(128));
}
TEST(ArenaAlign, CeilPtr) {
alignas(64) char p[129] = {0};
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.Ceil(p + 0), Eq(p));
EXPECT_THAT(align_64.Ceil(p + 1), Eq(p + 64));
EXPECT_THAT(align_64.Ceil(p + 63), Eq(p + 64));
EXPECT_THAT(align_64.Ceil(p + 64), Eq(p + 64));
EXPECT_THAT(align_64.Ceil(p + 65), Eq(p + 128));
EXPECT_THAT(align_64.Ceil(p + 127), Eq(p + 128));
EXPECT_THAT(align_64.Ceil(p + 128), Eq(p + 128));
}
TEST(ArenaAlign, CheckAligned) {
alignas(128) char p[129] = {0};
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.CheckAligned(p + 0), Eq(p));
EXPECT_THAT(align_64.CheckAligned(p + 64), Eq(p + 64));
EXPECT_THAT(align_64.CheckAligned(p + 128), Eq(p + 128));
#ifdef PROTOBUF_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 1), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 7), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 8), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 56), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 63), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 65), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 72), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 120), ".*");
EXPECT_DEBUG_DEATH(align_64.CheckAligned(p + 129), ".*");
#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST(ArenaAlign, CeilDefaultAligned) {
alignas(128) char p[129] = {0};
auto align_64 = ArenaAlignAs(64);
EXPECT_THAT(align_64.CeilDefaultAligned(p + 0), Eq(p));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 8), Eq(p + 64));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 56), Eq(p + 64));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 64), Eq(p + 64));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 72), Eq(p + 128));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 120), Eq(p + 128));
EXPECT_THAT(align_64.CeilDefaultAligned(p + 128), Eq(p + 128));
#ifdef PROTOBUF_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 1), ".*");
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 7), ".*");
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 63), ".*");
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 65), ".*");
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 127), ".*");
EXPECT_DEBUG_DEATH(align_64.CeilDefaultAligned(p + 129), ".*");
#endif // PROTOBUF_HAS_DEATH_TEST
}
TEST(ArenaAlign, IsAligned) {
auto align_64 = ArenaAlignAs(64);
EXPECT_TRUE(align_64.IsAligned(0));
EXPECT_FALSE(align_64.IsAligned(1));
EXPECT_FALSE(align_64.IsAligned(63));
EXPECT_TRUE(align_64.IsAligned(64));
EXPECT_FALSE(align_64.IsAligned(65));
EXPECT_FALSE(align_64.IsAligned(127));
EXPECT_TRUE(align_64.IsAligned(128));
}
} // namespace
} // namespace internal
} // namespace protobuf
} // namespace google

@ -0,0 +1,126 @@
// 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_ARENA_ALLOCATION_POLICY_H__
#define GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__
#include <cstddef>
#include <cstdint>
#include "google/protobuf/arena_config.h"
namespace google {
namespace protobuf {
namespace internal {
// `AllocationPolicy` defines `Arena` allocation policies. Applications can
// customize the inital and maximum sizes for arena allocation, as well as set
// custom allocation and deallocation functions. `AllocationPolicy` is for
// protocol buffer internal use only, and typically created from a user facing
// public configuration class such as `ArenaOptions`.
struct AllocationPolicy {
static constexpr size_t kDefaultStartBlockSize = 256;
size_t start_block_size = kDefaultStartBlockSize;
size_t max_block_size = GetDefaultArenaMaxBlockSize();
void* (*block_alloc)(size_t) = nullptr;
void (*block_dealloc)(void*, size_t) = nullptr;
bool IsDefault() const {
return start_block_size == kDefaultStartBlockSize &&
max_block_size == GetDefaultArenaMaxBlockSize() &&
block_alloc == nullptr && block_dealloc == nullptr;
}
};
// Tagged pointer to an AllocationPolicy.
class TaggedAllocationPolicyPtr {
public:
constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
: policy_(reinterpret_cast<uintptr_t>(policy)) {}
void set_policy(AllocationPolicy* policy) {
auto bits = policy_ & kTagsMask;
policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
}
AllocationPolicy* get() {
return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
}
const AllocationPolicy* get() const {
return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
}
AllocationPolicy& operator*() { return *get(); }
const AllocationPolicy& operator*() const { return *get(); }
AllocationPolicy* operator->() { return get(); }
const AllocationPolicy* operator->() const { return get(); }
bool is_user_owned_initial_block() const {
return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
}
void set_is_user_owned_initial_block(bool v) {
set_mask<kUserOwnedInitialBlock>(v);
}
uintptr_t get_raw() const { return policy_; }
private:
enum : uintptr_t {
kUserOwnedInitialBlock = 1,
};
static constexpr uintptr_t kTagsMask = 7;
static constexpr uintptr_t kPtrMask = ~kTagsMask;
template <uintptr_t kMask>
uintptr_t get_mask() const {
return policy_ & kMask;
}
template <uintptr_t kMask>
void set_mask(bool v) {
if (v) {
policy_ |= kMask;
} else {
policy_ &= ~kMask;
}
}
uintptr_t policy_;
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_ALLOCATION_POLICY_H__

@ -0,0 +1,189 @@
// 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_ARENA_CLEANUP_H__
#define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
#include <cstddef>
#include <cstdint>
#include <string>
#include "google/protobuf/stubs/logging.h"
#include "google/protobuf/stubs/common.h"
#include "absl/base/attributes.h"
namespace google {
namespace protobuf {
namespace internal {
namespace cleanup {
// Helper function invoking the destructor of `object`
template <typename T>
void arena_destruct_object(void* object) {
reinterpret_cast<T*>(object)->~T();
}
// Tag defines the type of cleanup / cleanup object. This tag is stored in the
// lowest 2 bits of the `elem` value identifying the type of node. All node
// types must start with a `uintptr_t` that stores `Tag` in its low two bits.
enum class Tag : uintptr_t {
kDynamic = 0, // DynamicNode
kString = 1, // StringNode (std::string)
};
// DynamicNode contains the object (`elem`) that needs to be
// destroyed, and the function to destroy it (`destructor`)
// elem must be aligned at minimum on a 4 byte boundary.
struct DynamicNode {
uintptr_t elem;
void (*destructor)(void*);
};
// StringNode contains a `std::string` object (`elem`) that needs to be
// destroyed. The lowest 2 bits of `elem` contain the non-zero kString tag.
struct StringNode {
uintptr_t elem;
};
// EnableSpecializedTags() return true if the alignment of tagged objects
// such as std::string allow us to poke tags in the 2 LSB bits.
inline constexpr bool EnableSpecializedTags() {
// For now we require 2 bits
return alignof(std::string) >= 8;
}
// Adds a cleanup entry identified by `tag` at memory location `pos`.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode(Tag tag, void* pos,
const void* elem_raw,
void (*destructor)(void*)) {
auto elem = reinterpret_cast<uintptr_t>(elem_raw);
if (EnableSpecializedTags()) {
GOOGLE_DCHECK_EQ(elem & 3, 0ULL); // Must be aligned
switch (tag) {
case Tag::kString: {
StringNode n = {elem | static_cast<uintptr_t>(Tag::kString)};
memcpy(pos, &n, sizeof(n));
return;
}
default:
break;
}
}
DynamicNode n = {elem, destructor};
memcpy(pos, &n, sizeof(n));
}
// Optimization: performs a prefetch on `elem_address`.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNode(
const void* elem_address) {
(void)elem_address;
}
// Destroys the node idenitfied by `tag` stored at memory location `pos`.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) {
if (EnableSpecializedTags()) {
switch (tag) {
case Tag::kString: {
StringNode n;
memcpy(&n, pos, sizeof(n));
auto* s = reinterpret_cast<std::string*>(n.elem & ~0x7ULL);
// Some compilers don't like fully qualified explicit dtor calls,
// so use an alias to avoid having to type `::`.
using string_type = std::string;
s->~string_type();
return;
}
default:
break;
}
}
DynamicNode n;
memcpy(&n, pos, sizeof(n));
n.destructor(reinterpret_cast<void*>(n.elem));
}
// Returns the `tag` identifying the type of object for `destructor` or
// kDynamic if `destructor` does not identify a well know object type.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) {
if (EnableSpecializedTags()) {
if (destructor == &arena_destruct_object<std::string>) {
return Tag::kString;
}
}
return Tag::kDynamic;
}
// Returns the `tag` identifying the type of object stored at memory location
// `elem`, which represents the first uintptr_t value in the node.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void* raw) {
if (!EnableSpecializedTags()) return Tag::kDynamic;
uintptr_t elem;
memcpy(&elem, raw, sizeof(elem));
switch (static_cast<Tag>(elem & 0x7ULL)) {
case Tag::kDynamic:
return Tag::kDynamic;
case Tag::kString:
return Tag::kString;
default:
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL);
return Tag::kDynamic;
}
}
// Returns the required size in bytes off the node type identified by `tag`.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(Tag tag) {
if (!EnableSpecializedTags()) return sizeof(DynamicNode);
switch (tag) {
case Tag::kDynamic:
return sizeof(DynamicNode);
case Tag::kString:
return sizeof(StringNode);
default:
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast<int>(tag);
return sizeof(DynamicNode);
}
}
// Returns the required size in bytes off the node type for `destructor`.
inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) {
return destructor == nullptr ? 0 : Size(Type(destructor));
}
} // namespace cleanup
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__

@ -43,11 +43,12 @@
#include "google/protobuf/stubs/logging.h"
#include "absl/numeric/bits.h"
#include "absl/synchronization/mutex.h"
#include "google/protobuf/port.h"
#include "google/protobuf/arena_allocation_policy.h"
#include "google/protobuf/arena_cleanup.h"
#include "google/protobuf/arena_config.h"
#include "google/protobuf/arenaz_sampler.h"
#include "google/protobuf/port.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
@ -87,177 +88,33 @@ inline PROTOBUF_ALWAYS_INLINE void* AlignTo(void* p, size_t a) {
}
}
// Wraps std::atomic<T> to avoid accidentally accessing the atomic variable via
// a default memory order (std::memory_order_seq_cst).
template <typename T>
struct Atomic {
PROTOBUF_CONSTEXPR explicit Atomic(T v) : val(v) {}
T relaxed_get() const { return val.load(std::memory_order_relaxed); }
T relaxed_get() { return val.load(std::memory_order_relaxed); }
void relaxed_set(T v) { val.store(v, std::memory_order_relaxed); }
T atomic_get() const { return val.load(std::memory_order_acquire); }
T atomic_get() { return val.load(std::memory_order_acquire); }
void atomic_set(T v) { val.store(v, std::memory_order_release); }
T relaxed_fetch_add(T v) {
return val.fetch_add(v, std::memory_order_relaxed);
}
private:
std::atomic<T> val;
};
// Arena blocks are variable length malloc-ed objects. The following structure
// describes the common header for all blocks.
struct ArenaBlock {
// For the sentry block with zero-size where ptr_, limit_, cleanup_nodes all
// point to "this".
PROTOBUF_CONSTEXPR ArenaBlock()
: next(nullptr), cleanup_nodes(this), relaxed_size(0) {}
constexpr ArenaBlock()
: next(nullptr), cleanup_nodes(this), size(0) {}
ArenaBlock(ArenaBlock* next, size_t size)
: next(next), cleanup_nodes(nullptr), relaxed_size(size) {
: next(next), cleanup_nodes(nullptr), size(size) {
GOOGLE_DCHECK_GT(size, sizeof(ArenaBlock));
}
char* Pointer(size_t n) {
GOOGLE_DCHECK_LE(n, size());
GOOGLE_DCHECK_LE(n, size);
return reinterpret_cast<char*>(this) + n;
}
char* Limit() { return Pointer(size() & static_cast<size_t>(-8)); }
char* Limit() { return Pointer(size & static_cast<size_t>(-8)); }
size_t size() const { return relaxed_size.relaxed_get(); }
bool IsSentry() const { return size() == 0; }
bool IsSentry() const { return size == 0; }
ArenaBlock* const next;
void* cleanup_nodes;
private:
const Atomic<size_t> relaxed_size;
const size_t size;
// data follows
};
namespace cleanup {
template <typename T>
void arena_destruct_object(void* object) {
reinterpret_cast<T*>(object)->~T();
}
enum class Tag : uintptr_t {
kDynamic = 0, // {void* elem, void (*destructor)(void*)}
kString = 1, // std::string* | kString
};
constexpr bool EnableSpecializedTags() {
return alignof(std::string) >= 8
;
}
// All node types must start with a `uintptr_t` that stores `Tag` in its low
// two bits.
struct DynamicNode {
uintptr_t elem;
void (*destructor)(void*);
};
struct StringNode {
uintptr_t elem;
};
inline PROTOBUF_ALWAYS_INLINE void CreateNode(Tag tag, void* pos,
const void* elem,
void (*destructor)(void*)) {
if (EnableSpecializedTags()) {
switch (tag) {
case Tag::kString: {
StringNode n = {reinterpret_cast<uintptr_t>(elem) |
static_cast<uintptr_t>(Tag::kString)};
memcpy(pos, &n, sizeof(n));
return;
}
default:
break;
}
}
DynamicNode n = {reinterpret_cast<uintptr_t>(elem), destructor};
memcpy(pos, &n, sizeof(n));
}
inline PROTOBUF_ALWAYS_INLINE void PrefetchNode(const void* elem_address) {
(void)elem_address;
}
inline PROTOBUF_ALWAYS_INLINE void DestroyNode(Tag tag, const void* pos) {
if (EnableSpecializedTags()) {
switch (tag) {
case Tag::kString: {
StringNode n;
memcpy(&n, pos, sizeof(n));
auto* s = reinterpret_cast<std::string*>(n.elem & ~0x7ULL);
// Some compilers don't like fully qualified explicit dtor calls,
// so use an alias to avoid having to type `::`.
using string_type = std::string;
s->~string_type();
return;
}
default:
break;
}
}
DynamicNode n;
memcpy(&n, pos, sizeof(n));
n.destructor(reinterpret_cast<void*>(n.elem));
}
inline PROTOBUF_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) {
if (EnableSpecializedTags()) {
if (destructor == &arena_destruct_object<std::string>) {
return Tag::kString;
}
}
return Tag::kDynamic;
}
inline PROTOBUF_ALWAYS_INLINE Tag Type(void* raw) {
if (!EnableSpecializedTags()) return Tag::kDynamic;
uintptr_t elem;
memcpy(&elem, raw, sizeof(elem));
switch (static_cast<Tag>(elem & 0x7ULL)) {
case Tag::kDynamic:
return Tag::kDynamic;
case Tag::kString:
return Tag::kString;
default:
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL);
return Tag::kDynamic;
}
}
inline PROTOBUF_ALWAYS_INLINE size_t Size(Tag tag) {
if (!EnableSpecializedTags()) return sizeof(DynamicNode);
switch (tag) {
case Tag::kDynamic:
return sizeof(DynamicNode);
case Tag::kString:
return sizeof(StringNode);
default:
GOOGLE_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast<int>(tag);
return sizeof(DynamicNode);
}
}
inline PROTOBUF_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) {
return destructor == nullptr ? 0 : Size(Type(destructor));
}
} // namespace cleanup
using LifecycleIdAtomic = uint64_t;
// MetricsCollector collects stats for a particular arena.
@ -293,79 +150,6 @@ class PROTOBUF_EXPORT ArenaMetricsCollector {
const bool record_allocs_;
};
struct AllocationPolicy {
static constexpr size_t kDefaultStartBlockSize = 256;
size_t start_block_size = kDefaultStartBlockSize;
size_t max_block_size = GetDefaultArenaMaxBlockSize();
void* (*block_alloc)(size_t) = nullptr;
void (*block_dealloc)(void*, size_t) = nullptr;
bool IsDefault() const {
return start_block_size == kDefaultStartBlockSize &&
max_block_size == GetDefaultArenaMaxBlockSize() &&
block_alloc == nullptr && block_dealloc == nullptr;
}
};
// Tagged pointer to an AllocationPolicy.
class TaggedAllocationPolicyPtr {
public:
constexpr TaggedAllocationPolicyPtr() : policy_(0) {}
explicit TaggedAllocationPolicyPtr(AllocationPolicy* policy)
: policy_(reinterpret_cast<uintptr_t>(policy)) {}
void set_policy(AllocationPolicy* policy) {
auto bits = policy_ & kTagsMask;
policy_ = reinterpret_cast<uintptr_t>(policy) | bits;
}
AllocationPolicy* get() {
return reinterpret_cast<AllocationPolicy*>(policy_ & kPtrMask);
}
const AllocationPolicy* get() const {
return reinterpret_cast<const AllocationPolicy*>(policy_ & kPtrMask);
}
AllocationPolicy& operator*() { return *get(); }
const AllocationPolicy& operator*() const { return *get(); }
AllocationPolicy* operator->() { return get(); }
const AllocationPolicy* operator->() const { return get(); }
bool is_user_owned_initial_block() const {
return static_cast<bool>(get_mask<kUserOwnedInitialBlock>());
}
void set_is_user_owned_initial_block(bool v) {
set_mask<kUserOwnedInitialBlock>(v);
}
uintptr_t get_raw() const { return policy_; }
private:
enum : uintptr_t {
kUserOwnedInitialBlock = 1,
};
static constexpr uintptr_t kTagsMask = 7;
static constexpr uintptr_t kPtrMask = ~kTagsMask;
template <uintptr_t kMask>
uintptr_t get_mask() const {
return policy_ & kMask;
}
template <uintptr_t kMask>
void set_mask(bool v) {
if (v) {
policy_ |= kMask;
} else {
policy_ &= ~kMask;
}
}
uintptr_t policy_;
};
enum class AllocationClient { kDefault, kArray };
class ThreadSafeArena;
@ -394,7 +178,9 @@ class PROTOBUF_EXPORT SerialArena {
};
void CleanupList();
uint64_t SpaceAllocated() const { return space_allocated_.relaxed_get(); }
uint64_t SpaceAllocated() const {
return space_allocated_.load(std::memory_order_relaxed);
}
uint64_t SpaceUsed() const;
bool HasSpace(size_t n) const {
@ -542,8 +328,7 @@ class PROTOBUF_EXPORT SerialArena {
}
PROTOBUF_ALWAYS_INLINE
void AddCleanup(void* elem, void (*destructor)(void*),
const AllocationPolicy* policy, ThreadSafeArenaStats* stats) {
void AddCleanup(void* elem, void (*destructor)(void*)) {
size_t required = cleanup::Size(destructor);
if (PROTOBUF_PREDICT_FALSE(!HasSpace(required))) {
return AddCleanupFallback(elem, destructor);
@ -592,13 +377,13 @@ class PROTOBUF_EXPORT SerialArena {
// Next pointer to allocate from. Always 8-byte aligned. Points inside
// head_ (and head_->pos will always be non-canonical). We keep these
// here to reduce indirection.
Atomic<char*> ptr_{nullptr};
std::atomic<char*> ptr_{nullptr};
// Limiting address up to which memory can be allocated from the head block.
char* limit_ = nullptr;
Atomic<ArenaBlock*> head_{nullptr}; // Head of linked list of blocks.
Atomic<size_t> space_used_{0}; // Necessary for metrics.
Atomic<size_t> space_allocated_{0};
std::atomic<ArenaBlock*> head_{nullptr}; // Head of linked list of blocks.
std::atomic<size_t> space_used_{0}; // Necessary for metrics.
std::atomic<size_t> space_allocated_{0};
ThreadSafeArena& parent_;
// Repeated*Field and Arena play together to reduce memory consumption by
@ -616,13 +401,14 @@ class PROTOBUF_EXPORT SerialArena {
CachedBlock** cached_blocks_ = nullptr;
// Helper getters/setters to handle relaxed operations on atomic variables.
ArenaBlock* head() { return head_.relaxed_get(); }
const ArenaBlock* head() const { return head_.relaxed_get(); }
void set_head(ArenaBlock* head) { return head_.relaxed_set(head); }
ArenaBlock* head() { return head_.load(std::memory_order_relaxed); }
const ArenaBlock* head() const {
return head_.load(std::memory_order_relaxed);
}
char* ptr() { return ptr_.relaxed_get(); }
const char* ptr() const { return ptr_.relaxed_get(); }
void set_ptr(char* ptr) { return ptr_.relaxed_set(ptr); }
char* ptr() { return ptr_.load(std::memory_order_relaxed); }
const char* ptr() const { return ptr_.load(std::memory_order_relaxed); }
void set_ptr(char* ptr) { return ptr_.store(ptr, std::memory_order_relaxed); }
// Constructor is private as only New() should be used.
inline SerialArena(ArenaBlock* b, ThreadSafeArena& parent);
@ -763,7 +549,7 @@ class PROTOBUF_EXPORT ThreadSafeArena {
// Adding a new chunk to head_ must be protected by mutex_.
absl::Mutex mutex_;
// Pointer to a linked list of SerialArenaChunk.
Atomic<SerialArenaChunk*> head_{nullptr};
std::atomic<SerialArenaChunk*> head_{nullptr};
void* first_owner_;
// Must be declared after alloc_policy_; otherwise, it may lose info on
@ -805,8 +591,9 @@ class PROTOBUF_EXPORT ThreadSafeArena {
return false;
}
// Finds SerialArena or creates one if not found.
SerialArena* GetSerialArenaFallback();
// Finds SerialArena or creates one if not found. When creating a new one,
// create a big enough block to accommodate n bytes.
SerialArena* GetSerialArenaFallback(size_t n);
template <AllocationClient alloc_client = AllocationClient::kDefault>
void* AllocateAlignedFallback(size_t n);
@ -865,9 +652,9 @@ class PROTOBUF_EXPORT ThreadSafeArena {
#pragma warning(disable : 4324)
#endif
struct alignas(kCacheAlignment) CacheAlignedLifecycleIdGenerator {
PROTOBUF_CONSTEXPR CacheAlignedLifecycleIdGenerator() : id{0} {}
constexpr CacheAlignedLifecycleIdGenerator() : id{0} {}
Atomic<LifecycleIdAtomic> id;
std::atomic<LifecycleIdAtomic> id;
};
static CacheAlignedLifecycleIdGenerator lifecycle_id_generator_;
#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
@ -891,6 +678,7 @@ class PROTOBUF_EXPORT ThreadSafeArena {
(sizeof(SerialArena) + 7) & static_cast<size_t>(-8);
static constexpr size_t kAllocPolicySize =
AlignUpTo8(sizeof(AllocationPolicy));
static constexpr size_t kMaxCleanupNodeSize = 16;
static_assert(kBlockHeaderSize % 8 == 0,
"kBlockHeaderSize must be a multiple of 8.");
static_assert(kSerialArenaSize % 8 == 0,

@ -74,7 +74,6 @@
#include "google/protobuf/stubs/logging.h"
#include "google/protobuf/compiler/subprocess.h"
#include "google/protobuf/compiler/plugin.pb.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/match.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_replace.h"

@ -67,7 +67,6 @@
#include "google/protobuf/compiler/mock_code_generator.h"
#include "google/protobuf/compiler/subprocess.h"
#include "google/protobuf/compiler/cpp/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/io_win32.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"

@ -34,14 +34,18 @@
#include "google/protobuf/compiler/cpp/enum.h"
#include <algorithm>
#include <cstdint>
#include <limits>
#include <map>
#include <unordered_set>
#include <string>
#include <utility>
#include <vector>
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "google/protobuf/descriptor.h"
#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/cpp/names.h"
@ -49,8 +53,23 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
absl::flat_hash_map<std::string, std::string> EnumVars(
const EnumDescriptor* enum_, const Options& options,
const EnumValueDescriptor* min, const EnumValueDescriptor* max) {
auto classname = ClassName(enum_, false);
return {
{"Enum", enum_->name()},
{"Enum_", ResolveKeyword(enum_->name())},
{"Msg_Enum", classname},
{"::Msg_Enum", QualifiedClassName(enum_, options)},
{"Msg_Enum_",
enum_->containing_type() == nullptr ? "" : absl::StrCat(classname, "_")},
{"kMin", absl::StrCat(min->number())},
{"kMax", absl::StrCat(max->number())},
};
}
// The ARRAYSIZE constant is the max enum value plus 1. If the max enum value
// is kint32max, ARRAYSIZE will overflow. In such cases we should omit the
// generation of the ARRAYSIZE constant.
@ -63,22 +82,9 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
}
return max_value != std::numeric_limits<int32_t>::max();
}
// Returns the number of unique numeric enum values. This is less than
// descriptor->value_count() when there are aliased values.
int CountUniqueValues(const EnumDescriptor* descriptor) {
std::unordered_set<int> values;
for (int i = 0; i < descriptor->value_count(); ++i) {
values.insert(descriptor->value(i)->number());
}
return values.size();
}
struct MinMaxEnumDescriptors {
const EnumValueDescriptor* min;
const EnumValueDescriptor* max;
};
MinMaxEnumDescriptors EnumLimits(const EnumDescriptor* descriptor) {
} // namespace
EnumGenerator::ValueLimits EnumGenerator::ValueLimits::FromEnum(
const EnumDescriptor* descriptor) {
const EnumValueDescriptor* min_desc = descriptor->value(0);
const EnumValueDescriptor* max_desc = descriptor->value(0);
@ -90,266 +96,303 @@ MinMaxEnumDescriptors EnumLimits(const EnumDescriptor* descriptor) {
max_desc = descriptor->value(i);
}
}
return {min_desc, max_desc};
}
// Assumes that HasDescriptorMethods is true.
bool ShouldCacheDenseEnum(const EnumDescriptor* descriptor,
MinMaxEnumDescriptors limits) {
// The conditions here for what is "sparse" are not rigorously
// chosen. We use unsigned values in case the subtraction of min from max
// exceeds the bounds of int.
const unsigned values_range = static_cast<unsigned>(limits.max->number()) -
static_cast<unsigned>(limits.min->number());
return (values_range < 16u ||
values_range < static_cast<unsigned>(descriptor->value_count()) * 2u);
return {min_desc, max_desc};
}
} // namespace
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
const std::map<std::string, std::string>& vars,
const Options& options)
: descriptor_(descriptor),
classname_(ClassName(descriptor, false)),
: enum_(descriptor),
options_(options),
generate_array_size_(ShouldGenerateArraySize(descriptor)),
variables_(vars) {
variables_["classname"] = classname_;
variables_["classtype"] = QualifiedClassName(descriptor_, options);
variables_["short_name"] = descriptor_->name();
variables_["nested_name"] = descriptor_->name();
variables_["resolved_name"] = ResolveKeyword(descriptor_->name());
variables_["prefix"] =
(descriptor_->containing_type() == nullptr) ? "" : classname_ + "_";
has_reflection_(HasDescriptorMethods(enum_->file(), options_)),
limits_(ValueLimits::FromEnum(enum_)) {
// The conditions here for what is "sparse" are not rigorously
// chosen.
size_t values_range = static_cast<size_t>(limits_.max->number()) -
static_cast<size_t>(limits_.min->number());
size_t total_values = static_cast<size_t>(enum_->value_count());
should_cache_ = has_reflection_ &&
(values_range < 16u || values_range < total_values * 2u);
}
EnumGenerator::~EnumGenerator() {}
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
Formatter format(printer, variables_);
format("enum ${1$$classname$$}$ : int {\n", descriptor_);
format.Indent();
for (int i = 0; i < descriptor_->value_count(); i++) {
auto format_value = format;
format_value.Set("name", EnumValueName(descriptor_->value(i)));
// In C++, an value of -2147483648 gets interpreted as the negative of
// 2147483648, and since 2147483648 can't fit in an integer, this produces a
// compiler warning. This works around that issue.
format_value.Set("number", Int32ToString(descriptor_->value(i)->number()));
format_value.Set("deprecation",
DeprecatedAttribute(options_, descriptor_->value(i)));
if (i > 0) format_value(",\n");
format_value("${1$$prefix$$name$$}$ $deprecation$= $number$",
descriptor_->value(i));
}
if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
// For new enum semantics: generate min and max sentinel values equal to
// INT32_MIN and INT32_MAX
if (descriptor_->value_count() > 0) format(",\n");
format(
"$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = "
"std::numeric_limits<$int32$>::min(),\n"
"$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = "
"std::numeric_limits<$int32$>::max()");
}
format.Outdent();
format("\n};\n");
MinMaxEnumDescriptors enum_limits = EnumLimits(descriptor_);
format(
"$dllexport_decl $bool $classname$_IsValid(int value);\n"
"constexpr $classname$ ${1$$prefix$$short_name$_MIN$}$ = "
"$prefix$$2$;\n"
"constexpr $classname$ ${1$$prefix$$short_name$_MAX$}$ = "
"$prefix$$3$;\n",
descriptor_, EnumValueName(enum_limits.min),
EnumValueName(enum_limits.max));
void EnumGenerator::GenerateDefinition(io::Printer* p) {
auto v1 = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
auto v2 = p->WithVars({
{"Msg_Enum_Enum_MIN",
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MIN"), enum_},
{"Msg_Enum_Enum_MAX",
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_MAX"), enum_},
});
p->Emit(
{
{"values",
[&] {
for (int i = 0; i < enum_->value_count(); ++i) {
const auto* value = enum_->value(i);
p->Emit(
{
{
"Msg_Enum_VALUE",
absl::StrCat(p->LookupVar("Msg_Enum_"),
EnumValueName(value)),
value,
},
{"kNumber", Int32ToString(value->number())},
{"DEPRECATED", value->options().deprecated()
? "PROTOBUF_DEPRECATED_ENUM"
: ""},
},
R"cc(
$Msg_Enum_VALUE$$ DEPRECATED$ = $kNumber$,
)cc");
}
}},
// Only emit annotations for the $Msg_Enum$ used in the `enum`
// definition.
{"Msg_Enum_annotated", p->LookupVar("Msg_Enum"), enum_},
{"open_enum_sentinels",
[&] {
if (enum_->is_closed()) {
return;
}
// For open enum semantics: generate min and max sentinel values
// equal to INT32_MIN and INT32_MAX
p->Emit({{"Msg_Enum_Msg_Enum_",
absl::StrCat(p->LookupVar("Msg_Enum"), "_",
p->LookupVar("Msg_Enum_"))}},
R"cc(
$Msg_Enum_Msg_Enum_$INT_MIN_SENTINEL_DO_NOT_USE_ =
std::numeric_limits<int32_t>::min(),
$Msg_Enum_Msg_Enum_$INT_MAX_SENTINEL_DO_NOT_USE_ =
std::numeric_limits<int32_t>::max(),
)cc");
}},
},
R"cc(
enum $Msg_Enum_annotated$ : int {
$values$,
$open_enum_sentinels$,
};
$dllexport_decl $bool $Msg_Enum$_IsValid(int value);
constexpr $Msg_Enum$ $Msg_Enum_Enum_MIN$ = static_cast<$Msg_Enum$>($kMin$);
constexpr $Msg_Enum$ $Msg_Enum_Enum_MAX$ = static_cast<$Msg_Enum$>($kMax$);
)cc");
if (generate_array_size_) {
format(
"constexpr int ${1$$prefix$$short_name$_ARRAYSIZE$}$ = "
"$prefix$$short_name$_MAX + 1;\n\n",
descriptor_);
p->Emit(
{{"Msg_Enum_Enum_ARRAYSIZE",
absl::StrCat(p->LookupVar("Msg_Enum_"), enum_->name(), "_ARRAYSIZE"),
enum_}},
R"cc(
constexpr int $Msg_Enum_Enum_ARRAYSIZE$ = $kMax$ + 1;
)cc");
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"$dllexport_decl $const ::$proto_ns$::EnumDescriptor* "
"$classname$_descriptor();\n");
if (has_reflection_) {
p->Emit(R"cc(
$dllexport_decl $const ::$proto_ns$::EnumDescriptor*
$Msg_Enum$_descriptor();
)cc");
} else {
p->Emit(R"cc(
const std::string& $Msg_Enum$_Name($Msg_Enum$ value);
)cc");
}
// The _Name and _Parse functions. The lite implementation is table-based, so
// we make sure to keep the tables hidden in the .cc file.
if (!HasDescriptorMethods(descriptor_->file(), options_)) {
format("const std::string& $classname$_Name($classname$ value);\n");
}
// The _Name() function accepts the enum type itself but also any integral
// type.
format(
"template<typename T>\n"
"inline const std::string& $classname$_Name(T enum_t_value) {\n"
" static_assert(::std::is_same<T, $classname$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $classname$_Name.\");\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
if (ShouldCacheDenseEnum(descriptor_, enum_limits)) {
// There are three possible implementations of $Enum$_Name() and
// $Msg_Enum$_Parse(), depending on whether we are using a dense enum name
// cache or not, and whether or not we have reflection. Very little code is
// shared between the three, so it is split into three Emit() calls.
// Can't use WithVars here, since callbacks can only be passed to Emit()
// directly. Because this includes $Enum$, it must be a callback.
auto write_assert = [&] {
p->Emit(R"cc(
static_assert(std::is_same<T, $Msg_Enum$>::value ||
std::is_integral<T>::value,
"Incorrect type passed to $Enum$_Name().");
)cc");
};
if (should_cache_ || !has_reflection_) {
p->Emit({{"static_assert", write_assert}}, R"cc(
template <typename T>
const std::string& $Msg_Enum$_Name(T value) {
$static_assert$;
return $Msg_Enum$_Name(static_cast<$Msg_Enum$>(value));
}
)cc");
if (should_cache_) {
// Using the NameOfEnum routine can be slow, so we create a small
// cache of pointers to the std::string objects that reflection
// stores internally. This cache is a simple contiguous array of
// pointers, so if the enum values are sparse, it's not worth it.
format(
" return "
"$classname$_Name(static_cast<$classname$>(enum_t_value));\n");
p->Emit(R"cc(
template <>
inline const std::string& $Msg_Enum$_Name($Msg_Enum$ value) {
return ::$proto_ns$::internal::NameOfDenseEnum<$Msg_Enum$_descriptor,
$kMin$, $kMax$>(
static_cast<int>(value));
}
)cc");
} else {
format(
" return ::$proto_ns$::internal::NameOfEnum(\n"
" $classname$_descriptor(), enum_t_value);\n");
p->Emit(R"cc(
const std::string& $Msg_Enum$_Name($Msg_Enum$ value);
)cc");
}
} else {
format(
" return $classname$_Name(static_cast<$classname$>(enum_t_value));\n");
p->Emit({{"static_assert", write_assert}}, R"cc(
template <typename T>
const std::string& $Msg_Enum$_Name(T value) {
$static_assert$;
return ::$proto_ns$::internal::NameOfEnum($Msg_Enum$_descriptor(), value);
}
)cc");
}
format("}\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
if (ShouldCacheDenseEnum(descriptor_, enum_limits)) {
format(
"template<>\n"
"inline const std::string& $classname$_Name($classname$ value) {\n"
" return ::$proto_ns$::internal::NameOfDenseEnum\n"
" <$classname$_descriptor, $1$, $2$>(static_cast<int>(value));\n"
"}\n",
enum_limits.min->number(), enum_limits.max->number());
}
format(
"inline bool $classname$_Parse(\n"
" ::absl::string_view name, $classname$* "
"value) "
"{\n"
" return ::$proto_ns$::internal::ParseNamedEnum<$classname$>(\n"
" $classname$_descriptor(), name, value);\n"
"}\n");
if (has_reflection_) {
p->Emit(R"cc(
inline bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) {
return ::$proto_ns$::internal::ParseNamedEnum<$Msg_Enum$>(
$Msg_Enum$_descriptor(), name, value);
}
)cc");
} else {
format(
"bool $classname$_Parse(\n"
" ::absl::string_view name, $classname$* "
"value);\n");
p->Emit(R"cc(
bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value);
)cc");
}
}
void EnumGenerator::GenerateGetEnumDescriptorSpecializations(
io::Printer* printer) {
Formatter format(printer, variables_);
format(
"template <> struct is_proto_enum< $classtype$> : ::std::true_type "
"{};\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"template <>\n"
"inline const EnumDescriptor* GetEnumDescriptor< $classtype$>() {\n"
" return $classtype$_descriptor();\n"
"}\n");
void EnumGenerator::GenerateGetEnumDescriptorSpecializations(io::Printer* p) {
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
p->Emit(R"cc(
template <>
struct is_proto_enum<$::Msg_Enum$> : std::true_type {};
)cc");
if (!has_reflection_) {
return;
}
p->Emit(R"cc(
template <>
inline const EnumDescriptor* GetEnumDescriptor<$::Msg_Enum$>() {
return $::Msg_Enum$_descriptor();
}
)cc");
}
void EnumGenerator::GenerateSymbolImports(io::Printer* printer) const {
Formatter format(printer, variables_);
format("typedef $classname$ $resolved_name$;\n");
for (int j = 0; j < descriptor_->value_count(); j++) {
std::string deprecated_attr =
DeprecatedAttribute(options_, descriptor_->value(j));
format(
"$1$static constexpr $resolved_name$ ${2$$3$$}$ =\n"
" $classname$_$3$;\n",
deprecated_attr, descriptor_->value(j),
EnumValueName(descriptor_->value(j)));
void EnumGenerator::GenerateSymbolImports(io::Printer* p) const {
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
p->Emit(R"cc(
using $Enum_$ = $Msg_Enum$;
)cc");
for (int j = 0; j < enum_->value_count(); ++j) {
const auto* value = enum_->value(j);
p->Emit(
{
{"VALUE", EnumValueName(enum_->value(j)), value},
{"DEPRECATED",
value->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM" : ""},
},
R"cc(
$DEPRECATED $static constexpr $Enum_$ $VALUE$ = $Msg_Enum$_$VALUE$;
)cc");
}
format(
"static inline bool $nested_name$_IsValid(int value) {\n"
" return $classname$_IsValid(value);\n"
"}\n"
"static constexpr $resolved_name$ ${1$$nested_name$_MIN$}$ =\n"
" $classname$_$nested_name$_MIN;\n"
"static constexpr $resolved_name$ ${1$$nested_name$_MAX$}$ =\n"
" $classname$_$nested_name$_MAX;\n",
descriptor_);
p->Emit(
{
{"Enum_MIN", absl::StrCat(enum_->name(), "_MIN"), enum_},
{"Enum_MAX", absl::StrCat(enum_->name(), "_MAX"), enum_},
},
R"cc(
static inline bool $Enum$_IsValid(int value) {
return $Msg_Enum$_IsValid(value);
}
static constexpr $Enum_$ $Enum_MIN$ = $Msg_Enum$_$Enum$_MIN;
static constexpr $Enum_$ $Enum_MAX$ = $Msg_Enum$_$Enum$_MAX;
)cc");
if (generate_array_size_) {
format(
"static constexpr int ${1$$nested_name$_ARRAYSIZE$}$ =\n"
" $classname$_$nested_name$_ARRAYSIZE;\n",
descriptor_);
p->Emit(
{{"Enum_ARRAYSIZE", absl::StrCat(enum_->name(), "_ARRAYSIZE"), enum_}},
R"cc(
static constexpr int $Enum_ARRAYSIZE$ = $Msg_Enum$_$Enum$_ARRAYSIZE;
)cc");
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"static inline const ::$proto_ns$::EnumDescriptor*\n"
"$nested_name$_descriptor() {\n"
" return $classname$_descriptor();\n"
"}\n");
if (has_reflection_) {
p->Emit(R"cc(
static inline const ::$proto_ns$::EnumDescriptor* $Enum$_descriptor() {
return $Msg_Enum$_descriptor();
}
)cc");
}
format(
"template<typename T>\n"
"static inline const std::string& $nested_name$_Name(T enum_t_value) {\n"
" static_assert(::std::is_same<T, $resolved_name$>::value ||\n"
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $nested_name$_Name.\");\n"
" return $classname$_Name(enum_t_value);\n"
"}\n");
format(
"static inline bool "
"$nested_name$_Parse(::absl::string_view name,\n"
" $resolved_name$* value) {\n"
" return $classname$_Parse(name, value);\n"
"}\n");
p->Emit(R"cc(
template <typename T>
static inline const std::string& $Enum$_Name(T value) {
return $Msg_Enum$_Name(value);
}
static inline bool $Enum$_Parse(absl::string_view name, $Enum_$* value) {
return $Msg_Enum$_Parse(name, value);
}
)cc");
}
void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
Formatter format(printer, variables_);
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
"const ::$proto_ns$::EnumDescriptor* $classname$_descriptor() {\n"
" ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);\n"
" return $file_level_enum_descriptors$[$1$];\n"
"}\n",
idx);
}
format(
"bool $classname$_IsValid(int value) {\n"
" switch (value) {\n");
// Multiple values may have the same number. Make sure we only cover
// each number once by first constructing a set containing all valid
// numbers, then printing a case statement for each element.
void EnumGenerator::GenerateMethods(int idx, io::Printer* p) {
auto v = p->WithVars(EnumVars(enum_, options_, limits_.min, limits_.max));
std::set<int> numbers;
for (int j = 0; j < descriptor_->value_count(); j++) {
const EnumValueDescriptor* value = descriptor_->value(j);
numbers.insert(value->number());
}
for (std::set<int>::iterator iter = numbers.begin(); iter != numbers.end();
++iter) {
format(" case $1$:\n", Int32ToString(*iter));
if (has_reflection_) {
p->Emit({{"idx", idx}}, R"cc(
const ::$proto_ns$::EnumDescriptor* $Msg_Enum$_descriptor() {
::$proto_ns$::internal::AssignDescriptors(&$desc_table$);
return $file_level_enum_descriptors$[$idx$];
}
)cc");
}
format(
" return true;\n"
" default:\n"
" return false;\n"
" }\n"
"}\n"
"\n");
if (!HasDescriptorMethods(descriptor_->file(), options_)) {
p->Emit({{"cases",
[&] {
// Multiple values may have the same number. Make sure we only
// cover each number once by first constructing a set containing
// all valid numbers, then printing a case statement for each
// element.
std::vector<int> numbers;
numbers.reserve(enum_->value_count());
for (int i = 0; i < enum_->value_count(); ++i) {
numbers.push_back(enum_->value(i)->number());
}
// Sort and deduplicate `numbers`.
absl::c_sort(numbers);
numbers.erase(std::unique(numbers.begin(), numbers.end()),
numbers.end());
for (int n : numbers) {
p->Emit({{"n", n}}, R"cc(
case $n$:
)cc");
}
}}},
R"(
bool $Msg_Enum$_IsValid(int value) {
switch (value) {
$cases$;
return true;
default:
return false;
}
}
)");
if (!has_reflection_) {
// In lite mode (where descriptors are unavailable), we generate separate
// tables for mapping between enum names and numbers. The _entries table
// contains the bulk of the data and is sorted by name, while
@ -363,119 +406,168 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) {
// numerical value. In cases where there are multiple names for the same
// number, we treat the first name appearing in the .proto file as the
// canonical one.
std::map<std::string, int> name_to_number;
std::map<int, std::string> number_to_canonical_name;
for (int i = 0; i < descriptor_->value_count(); i++) {
const EnumValueDescriptor* value = descriptor_->value(i);
absl::btree_map<std::string, int> name_to_number;
absl::flat_hash_map<int, std::string> number_to_canonical_name;
for (int i = 0; i < enum_->value_count(); ++i) {
const auto* value = enum_->value(i);
name_to_number.emplace(value->name(), value->number());
// The same number may appear with multiple names, so we use emplace() to
// let the first name win.
number_to_canonical_name.emplace(value->number(), value->name());
}
format(
"static ::$proto_ns$::internal::ExplicitlyConstructed<std::string> "
"$classname$_strings[$1$] = {};\n\n",
CountUniqueValues(descriptor_));
// We concatenate all the names for a given enum into one big string
// literal. If instead we store an array of string literals, the linker
// seems to put all enum strings for a given .proto file in the same
// section, which hinders its ability to strip out unused strings.
format("static const char $classname$_names[] =");
for (const auto& p : name_to_number) {
format("\n \"$1$\"", p.first);
}
format(";\n\n");
format(
"static const ::$proto_ns$::internal::EnumEntry $classname$_entries[] "
"= {\n");
int i = 0;
std::map<int, int> number_to_index;
int data_index = 0;
for (const auto& p : name_to_number) {
format(" { {$classname$_names + $1$, $2$}, $3$ },\n", data_index,
p.first.size(), p.second);
if (number_to_canonical_name[p.second] == p.first) {
number_to_index.emplace(p.second, i);
}
++i;
data_index += p.first.size();
}
format(
"};\n"
"\n"
"static const int $classname$_entries_by_number[] = {\n");
for (const auto& p : number_to_index) {
format(" $1$, // $2$ -> $3$\n", p.second, p.first,
number_to_canonical_name[p.first]);
// Build the offset table for the strings table.
struct Offset {
int number;
size_t index, byte_offset, len;
};
std::vector<Offset> offsets;
size_t index = 0;
size_t offset = 0;
for (const auto& e : name_to_number) {
offsets.push_back(Offset{e.second, index, offset, e.first.size()});
++index;
offset += e.first.size();
}
format(
"};\n"
"\n");
format(
"const std::string& $classname$_Name(\n"
" $classname$ value) {\n"
" static const bool dummy =\n"
" ::$proto_ns$::internal::InitializeEnumStrings(\n"
" $classname$_entries,\n"
" $classname$_entries_by_number,\n"
" $1$, $classname$_strings);\n"
" (void) dummy;\n"
" int idx = ::$proto_ns$::internal::LookUpEnumName(\n"
" $classname$_entries,\n"
" $classname$_entries_by_number,\n"
" $1$, value);\n"
" return idx == -1 ? ::$proto_ns$::internal::GetEmptyString() :\n"
" $classname$_strings[idx].get();\n"
"}\n",
CountUniqueValues(descriptor_));
format(
"bool $classname$_Parse(\n"
" ::absl::string_view name, $classname$* "
"value) "
"{\n"
" int int_value;\n"
" bool success = ::$proto_ns$::internal::LookUpEnumValue(\n"
" $classname$_entries, $1$, name, &int_value);\n"
" if (success) {\n"
" *value = static_cast<$classname$>(int_value);\n"
" }\n"
" return success;\n"
"}\n",
descriptor_->value_count());
absl::c_sort(offsets, [](const auto& a, const auto& b) {
return a.byte_offset < b.byte_offset;
});
std::vector<Offset> offsets_by_number = offsets;
absl::c_sort(offsets_by_number, [](const auto& a, const auto& b) {
return a.number < b.number;
});
offsets_by_number.erase(
std::unique(
offsets_by_number.begin(), offsets_by_number.end(),
[](const auto& a, const auto& b) { return a.number == b.number; }),
offsets_by_number.end());
p->Emit(
{
{"num_unique", number_to_canonical_name.size()},
{"num_declared", enum_->value_count()},
{"names",
// We concatenate all the names for a given enum into one big
// string literal. If instead we store an array of string
// literals, the linker seems to put all enum strings for a given
// .proto file in the same section, which hinders its ability to
// strip out unused strings.
[&] {
for (const auto& e : name_to_number) {
p->Emit({{"name", e.first}}, R"cc(
"$name$"
)cc");
}
}},
{"entries",
[&] {
for (const auto& offset : offsets) {
p->Emit({{"number", offset.number},
{"offset", offset.byte_offset},
{"len", offset.len}},
R"cc(
{{&$Msg_Enum$_names[$offset$], $len$}, $number$},
)cc");
}
}},
{"entries_by_number",
[&] {
for (const auto& offset : offsets_by_number) {
p->Emit({{"number", offset.number},
{"index", offset.index},
{"name", number_to_canonical_name[offset.number]}},
R"cc(
$index$, // $number$ -> $name$
)cc");
}
}},
},
R"cc(
static ::$proto_ns$::internal::ExplicitlyConstructed<std::string>
$Msg_Enum$_strings[$num_unique$] = {};
static const char $Msg_Enum$_names[] = {
$names$,
};
static const ::$proto_ns$::internal::EnumEntry $Msg_Enum$_entries[] =
{
$entries$,
};
static const int $Msg_Enum$_entries_by_number[] = {
$entries_by_number$,
};
const std::string& $Msg_Enum$_Name($Msg_Enum$ value) {
static const bool kDummy =
::$proto_ns$::internal::InitializeEnumStrings(
$Msg_Enum$_entries, $Msg_Enum$_entries_by_number,
$num_unique$, $Msg_Enum$_strings);
(void)kDummy;
int idx = ::$proto_ns$::internal::LookUpEnumName(
$Msg_Enum$_entries, $Msg_Enum$_entries_by_number, $num_unique$,
value);
return idx == -1 ? ::$proto_ns$::internal::GetEmptyString()
: $Msg_Enum$_strings[idx].get();
}
bool $Msg_Enum$_Parse(absl::string_view name, $Msg_Enum$* value) {
int int_value;
bool success = ::$proto_ns$::internal::LookUpEnumValue(
$Msg_Enum$_entries, $num_declared$, name, &int_value);
if (success) {
*value = static_cast<$Msg_Enum$>(int_value);
}
return success;
}
)cc");
}
if (descriptor_->containing_type() != nullptr) {
std::string parent = ClassName(descriptor_->containing_type(), false);
if (enum_->containing_type() != nullptr) {
// Before C++17, we must define the static constants which were
// declared in the header, to give the linker a place to put them.
// But MSVC++ pre-2015 and post-2017 (version 15.5+) insists that we not.
format(
"#if (__cplusplus < 201703) && "
"(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
for (int i = 0; i < descriptor_->value_count(); i++) {
format("constexpr $classname$ $1$::$2$;\n", parent,
EnumValueName(descriptor_->value(i)));
}
format(
"constexpr $classname$ $1$::$nested_name$_MIN;\n"
"constexpr $classname$ $1$::$nested_name$_MAX;\n",
parent);
if (generate_array_size_) {
format("constexpr int $1$::$nested_name$_ARRAYSIZE;\n", parent);
}
format(
"#endif // (__cplusplus < 201703) && "
"(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))\n");
p->Emit(
{
{"Msg_", ClassName(enum_->containing_type(), false)},
{"constexpr_storage",
[&] {
for (int i = 0; i < enum_->value_count(); i++) {
p->Emit({{"VALUE", EnumValueName(enum_->value(i))}},
R"cc(
constexpr $Msg_Enum$ $Msg_$::$VALUE$;
)cc");
}
}},
{"array_size",
[&] {
if (generate_array_size_) {
p->Emit(R"cc(
constexpr int $Msg_$::$Enum$_ARRAYSIZE;
)cc");
}
}},
},
R"(
#if (__cplusplus < 201703) && \
(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
$constexpr_storage$;
constexpr $Msg_Enum$ $Msg_$::$Enum$_MIN;
constexpr $Msg_Enum$ $Msg_$::$Enum$_MAX;
$array_size$;
#endif // (__cplusplus < 201703) &&
// (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
)");
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf

@ -41,62 +41,60 @@
#include "google/protobuf/descriptor.h"
#include "google/protobuf/compiler/cpp/options.h"
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
} // namespace protobuf
} // namespace google
#include "google/protobuf/io/printer.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
EnumGenerator(const EnumDescriptor* descriptor,
const std::map<std::string, std::string>& vars,
const Options& options);
EnumGenerator(const EnumDescriptor* descriptor, const Options& options);
EnumGenerator(const EnumGenerator&) = delete;
EnumGenerator& operator=(const EnumGenerator&) = delete;
~EnumGenerator();
~EnumGenerator() = default;
// Generate header code defining the enum. This code should be placed
// within the enum's package namespace, but NOT within any class, even for
// nested enums.
void GenerateDefinition(io::Printer* printer);
void GenerateDefinition(io::Printer* p);
// Generate specialization of GetEnumDescriptor<MyEnum>().
// Precondition: in ::google::protobuf namespace.
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
void GenerateGetEnumDescriptorSpecializations(io::Printer* p);
// For enums nested within a message, generate code to import all the enum's
// symbols (e.g. the enum type name, all its values, etc.) into the class's
// namespace. This should be placed inside the class definition in the
// header.
void GenerateSymbolImports(io::Printer* printer) const;
void GenerateSymbolImports(io::Printer* p) const;
// Source file stuff.
// Generate non-inline methods related to the enum, such as IsValidValue().
// Goes in the .cc file. EnumDescriptors are stored in an array, idx is
// the index in this array that corresponds with this enum.
void GenerateMethods(int idx, io::Printer* printer);
void GenerateMethods(int idx, io::Printer* p);
private:
const EnumDescriptor* descriptor_;
const std::string classname_;
const Options& options_;
// whether to generate the *_ARRAYSIZE constant.
const bool generate_array_size_;
friend class FileGenerator;
std::map<std::string, std::string> variables_;
struct ValueLimits {
const EnumValueDescriptor* min = nullptr;
const EnumValueDescriptor* max = nullptr;
friend class FileGenerator;
static ValueLimits FromEnum(const EnumDescriptor* descriptor);
};
const EnumDescriptor* enum_;
Options options_;
bool generate_array_size_;
bool should_cache_;
bool has_reflection_;
ValueLimits limits_;
};
} // namespace cpp

@ -36,7 +36,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "google/protobuf/compiler/cpp/field.h"
#include "google/protobuf/compiler/cpp/helpers.h"

@ -37,7 +37,6 @@
#include <map>
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
#include "google/protobuf/compiler/cpp/helpers.h"

@ -48,7 +48,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "google/protobuf/compiler/cpp/enum_field.h"
#include "google/protobuf/compiler/cpp/map_field.h"
#include "google/protobuf/compiler/cpp/message_field.h"
@ -233,37 +232,72 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor,
"OnAddMutable", variables);
}
absl::flat_hash_map<std::string, std::string> FieldVars(
const FieldDescriptor* desc, const Options& opts) {
bool split = ShouldSplit(desc, opts);
absl::flat_hash_map<std::string, std::string> vars = {
{"ns", Namespace(desc, opts)},
{"name", FieldName(desc)},
{"index", absl::StrCat(desc->index())},
{"number", absl::StrCat(desc->number())},
{"classname", ClassName(FieldScope(desc), false)},
{"declared_type", DeclaredTypeMethodName(desc->type())},
{"field", FieldMemberName(desc, split)},
{"tag_size",
absl::StrCat(WireFormat::TagSize(desc->number(), desc->type()))},
{"deprecated_attr", DeprecatedAttribute(opts, desc)},
{"set_hasbit", ""},
{"clear_hasbit", ""},
{"maybe_prepare_split_message",
split ? "PrepareSplitMessageForWrite();" : ""},
// These variables are placeholders to pick out the beginning and ends of
// identifiers for annotations (when doing so with existing variables
// would be ambiguous or impossible). They should never be set to anything
// but the empty string.
{"{", ""},
{"}", ""},
};
// TODO(b/245791219): Refactor AddAccessorAnnotations to avoid this
// workaround.
std::map<std::string, std::string> workaround = {
{"field", vars["field"]},
{"tracker", "Impl_::_tracker_"},
};
AddAccessorAnnotations(desc, opts, &workaround);
for (auto& pair : workaround) {
vars.emplace(pair);
}
return vars;
}
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables,
const Options& options) {
SetCommonMessageDataVariables(descriptor->containing_type(), variables);
(*variables)["ns"] = Namespace(descriptor, options);
(*variables)["name"] = FieldName(descriptor);
(*variables)["index"] = absl::StrCat(descriptor->index());
(*variables)["number"] = absl::StrCat(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
bool split = ShouldSplit(descriptor, options);
(*variables)["field"] = FieldMemberName(descriptor, split);
(*variables)["tag_size"] = absl::StrCat(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor);
(*variables)["set_hasbit"] = "";
(*variables)["clear_hasbit"] = "";
(*variables)["maybe_prepare_split_message"] =
split ? " PrepareSplitMessageForWrite();\n" : "";
AddAccessorAnnotations(descriptor, options, variables);
// These variables are placeholders to pick out the beginning and ends of
// identifiers for annotations (when doing so with existing variables would
// be ambiguous or impossible). They should never be set to anything but the
// empty string.
(*variables)["{"] = "";
(*variables)["}"] = "";
for (auto& pair : FieldVars(descriptor, options)) {
variables->emplace(pair);
}
}
absl::flat_hash_map<std::string, std::string> OneofFieldVars(
const FieldDescriptor* descriptor) {
if (descriptor->containing_oneof() == nullptr) {
return {};
}
return {{"oneof_name", descriptor->containing_oneof()->name()}};
}
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
for (auto& pair : OneofFieldVars(descriptor)) {
variables->emplace(pair);
}
}
void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) {
@ -330,13 +364,6 @@ void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
}
}
void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
const std::string prefix = descriptor->containing_oneof()->name() + "_.";
(*variables)["oneof_name"] = descriptor->containing_oneof()->name();
}
FieldGenerator::~FieldGenerator() {}
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,

@ -57,6 +57,12 @@ namespace protobuf {
namespace compiler {
namespace cpp {
absl::flat_hash_map<std::string, std::string> FieldVars(
const FieldDescriptor* desc, const Options& opts);
absl::flat_hash_map<std::string, std::string> OneofFieldVars(
const FieldDescriptor* descriptor);
// Helper function: set variables in the map that are the same for all
// field code generators.
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',

@ -66,6 +66,8 @@
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h" // for StringReplace.
// Must be last.
#include "google/protobuf/port_def.inc"
@ -122,8 +124,8 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
}
for (int i = 0; i < file->enum_type_count(); ++i) {
enum_generators_.push_back(absl::make_unique<EnumGenerator>(
file->enum_type(i), variables_, options));
enum_generators_.push_back(
absl::make_unique<EnumGenerator>(file->enum_type(i), options));
}
for (int i = 0; i < file->service_count(); ++i) {
@ -522,7 +524,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
// Generate the split instance first because it's needed in the constexpr
// constructor.
if (ShouldSplit(generator->descriptor_, options_)) {
if (ShouldSplit(generator->descriptor(), options_)) {
// Use a union to disable the destructor of the _instance member.
// We can constant initialize, but the object will still have a non-trivial
// destructor that we need to elide.
@ -533,13 +535,14 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
// there just to improve performance and binary size in these builds.
p->Emit(
{
{"type", DefaultInstanceType(generator->descriptor_, options_,
{"type", DefaultInstanceType(generator->descriptor(), options_,
/*split=*/true)},
{"name", DefaultInstanceName(generator->descriptor_, options_,
{"name", DefaultInstanceName(generator->descriptor(), options_,
/*split=*/true)},
{"default",
[&] { generator->GenerateInitDefaultSplitInstance(p); }},
{"class", absl::StrCat(generator->classname_, "::Impl_::Split")},
{"class", absl::StrCat(ClassName(generator->descriptor()),
"::Impl_::Split")},
},
R"cc(
struct $type$ {
@ -558,10 +561,10 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
p->Emit(
{
{"type", DefaultInstanceType(generator->descriptor_, options_)},
{"name", DefaultInstanceName(generator->descriptor_, options_)},
{"type", DefaultInstanceType(generator->descriptor(), options_)},
{"name", DefaultInstanceName(generator->descriptor(), options_)},
{"default", [&] { generator->GenerateInitDefaultSplitInstance(p); }},
{"class", generator->classname_},
{"class", ClassName(generator->descriptor())},
},
R"cc(
struct $type$ {
@ -576,8 +579,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $type$ $name$;
)cc");
for (int i = 0; i < generator->descriptor_->field_count(); ++i) {
const FieldDescriptor* field = generator->descriptor_->field(i);
for (int i = 0; i < generator->descriptor()->field_count(); ++i) {
const FieldDescriptor* field = generator->descriptor()->field(i);
if (!IsStringInlined(field, options_)) {
continue;
}
@ -585,9 +588,9 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
// Force the initialization of the inlined string in the default instance.
p->Emit(
{
{"class", ClassName(generator->descriptor_)},
{"class", ClassName(generator->descriptor())},
{"field", FieldName(field)},
{"default", DefaultInstanceName(generator->descriptor_, options_)},
{"default", DefaultInstanceName(generator->descriptor(), options_)},
{"member", FieldMemberName(field, ShouldSplit(field, options_))},
},
R"cc(
@ -600,8 +603,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, io::Printer* p) {
if (options_.lite_implicit_weak_fields) {
p->Emit(
{
{"ptr", DefaultInstancePtr(generator->descriptor_, options_)},
{"name", DefaultInstanceName(generator->descriptor_, options_)},
{"ptr", DefaultInstancePtr(generator->descriptor(), options_)},
{"name", DefaultInstanceName(generator->descriptor(), options_)},
},
R"cc(
PROTOBUF_CONSTINIT const void* $ptr$ = &$name$;
@ -709,7 +712,7 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* p) {
}
CrossFileReferences refs;
ForEachField(message_generators_[idx]->descriptor_,
ForEachField(message_generators_[idx]->descriptor(),
[this, &refs](const FieldDescriptor* field) {
GetCrossFileReferencesForField(field, &refs);
});
@ -915,8 +918,8 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) {
for (auto& gen : message_generators_) {
p->Emit(
{
{"ns", Namespace(gen->descriptor_, options_)},
{"class", ClassName(gen->descriptor_)},
{"ns", Namespace(gen->descriptor(), options_)},
{"class", ClassName(gen->descriptor())},
},
R"cc(
&$ns$::_$class$_default_instance_._instance,
@ -1213,9 +1216,9 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* p) {
decls[Namespace(e, options_)].AddEnum(e);
}
for (const auto& mg : message_generators_) {
const Descriptor* d = mg->descriptor_;
const Descriptor* d = mg->descriptor();
if (d != nullptr && public_set.count(d->file()) == 0u &&
ShouldSplit(mg->descriptor_, options_))
ShouldSplit(mg->descriptor(), options_))
decls[Namespace(d, options_)].AddSplit(d);
}

@ -156,6 +156,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
}
} else if (key == "proto_h") {
file_options.proto_h = true;
} else if (key == "proto_static_reflection_h") {
} else if (key == "annotate_accessor") {
file_options.annotate_accessor = true;
} else if (key == "inject_field_listener_events") {
@ -209,6 +210,17 @@ bool CppGenerator::Generate(const FileDescriptor* file,
std::string basename = StripProto(file->name());
auto generate_reserved_static_reflection_header = [&basename,
&generator_context]() {
auto output = absl::WrapUnique(generator_context->Open(
absl::StrCat(basename, ".proto.static_reflection.h")));
io::Printer(output.get()).Emit(R"cc(
// Reserved for future use.
)cc");
};
// Suppress maybe unused warning.
(void)generate_reserved_static_reflection_header;
if (MaybeBootstrap(file_options, generator_context, file_options.bootstrap,
&basename)) {
return true;

@ -235,46 +235,66 @@ bool IsLazilyVerifiedLazy(const FieldDescriptor* field,
return false;
}
absl::flat_hash_map<std::string, std::string> MessageVars(
const Descriptor* desc) {
absl::string_view prefix = IsMapEntryMessage(desc) ? "" : "_impl_.";
return {
{"any_metadata", absl::StrCat(prefix, "_any_metadata_")},
{"cached_size", absl::StrCat(prefix, "_cached_size_")},
{"extensions", absl::StrCat(prefix, "_extensions_")},
{"has_bits", absl::StrCat(prefix, "_has_bits_")},
{"inlined_string_donated_array",
absl::StrCat(prefix, "_inlined_string_donated_")},
{"oneof_case", absl::StrCat(prefix, "_oneof_case_")},
{"tracker", "Impl_::_tracker_"},
{"weak_field_map", absl::StrCat(prefix, "_weak_field_map_")},
{"split", absl::StrCat(prefix, "_split_")},
{"cached_split_ptr", "cached_split_ptr"},
};
}
void SetCommonMessageDataVariables(
const Descriptor* descriptor,
std::map<std::string, std::string>* variables) {
std::string prefix = IsMapEntryMessage(descriptor) ? "" : "_impl_.";
(*variables)["any_metadata"] = prefix + "_any_metadata_";
(*variables)["cached_size"] = prefix + "_cached_size_";
(*variables)["extensions"] = prefix + "_extensions_";
(*variables)["has_bits"] = prefix + "_has_bits_";
(*variables)["inlined_string_donated_array"] =
prefix + "_inlined_string_donated_";
(*variables)["oneof_case"] = prefix + "_oneof_case_";
(*variables)["tracker"] = "Impl_::_tracker_";
(*variables)["weak_field_map"] = prefix + "_weak_field_map_";
(*variables)["split"] = prefix + "_split_";
(*variables)["cached_split_ptr"] = "cached_split_ptr";
for (auto& pair : MessageVars(descriptor)) {
variables->emplace(pair);
}
}
void SetUnknownFieldsVariable(const Descriptor* descriptor,
const Options& options,
std::map<std::string, std::string>* variables) {
std::string proto_ns = ProtobufNamespace(options);
absl::flat_hash_map<std::string, std::string> UnknownFieldsVars(
const Descriptor* desc, const Options& opts) {
std::string proto_ns = ProtobufNamespace(opts);
std::string unknown_fields_type;
if (UseUnknownFieldSet(descriptor->file(), options)) {
unknown_fields_type = "::" + proto_ns + "::UnknownFieldSet";
(*variables)["unknown_fields"] =
"_internal_metadata_.unknown_fields<" + unknown_fields_type + ">(" +
unknown_fields_type + "::default_instance)";
std::string default_instance;
if (UseUnknownFieldSet(desc->file(), opts)) {
unknown_fields_type = absl::StrCat("::", proto_ns, "::UnknownFieldSet");
default_instance = absl::StrCat(unknown_fields_type, "::default_instance");
} else {
unknown_fields_type =
PrimitiveTypeName(options, FieldDescriptor::CPPTYPE_STRING);
(*variables)["unknown_fields"] = "_internal_metadata_.unknown_fields<" +
unknown_fields_type + ">(::" + proto_ns +
"::internal::GetEmptyString)";
}
(*variables)["unknown_fields_type"] = unknown_fields_type;
(*variables)["have_unknown_fields"] =
"_internal_metadata_.have_unknown_fields()";
(*variables)["mutable_unknown_fields"] =
"_internal_metadata_.mutable_unknown_fields<" + unknown_fields_type +
">()";
PrimitiveTypeName(opts, FieldDescriptor::CPPTYPE_STRING);
default_instance =
absl::StrCat("::", proto_ns, "::internal::GetEmptyString");
}
return {
{"unknown_fields",
absl::Substitute("_internal_metadata_.unknown_fields<$0>($1)",
unknown_fields_type, default_instance)},
{"unknown_fields_type", unknown_fields_type},
{"have_unknown_fields", "_internal_metadata_.have_unknown_fields()"},
{"mutable_unknown_fields",
absl::Substitute("_internal_metadata_.mutable_unknown_fields<$0>()",
unknown_fields_type)},
};
}
void SetUnknownFieldsVariable(const Descriptor* descriptor,
const Options& options,
std::map<std::string, std::string>* variables) {
for (auto& pair : UnknownFieldsVars(descriptor, options)) {
variables->emplace(pair);
}
}
std::string UnderscoresToCamelCase(const std::string& input,

@ -46,6 +46,7 @@
#include "absl/container/flat_hash_map.h"
#include "absl/strings/match.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/names.h"
#include "google/protobuf/compiler/cpp/options.h"
#include "google/protobuf/descriptor.pb.h"
@ -88,11 +89,17 @@ inline std::string DeprecatedAttribute(const Options& /* options */,
extern const char kThickSeparator[];
extern const char kThinSeparator[];
absl::flat_hash_map<std::string, std::string> MessageVars(
const Descriptor* desc);
// Variables to access message data from the message scope.
void SetCommonMessageDataVariables(
const Descriptor* descriptor,
std::map<std::string, std::string>* variables);
absl::flat_hash_map<std::string, std::string> UnknownFieldsVars(
const Descriptor* desc, const Options& opts);
void SetUnknownFieldsVariable(const Descriptor* descriptor,
const Options& options,
std::map<std::string, std::string>* variables);
@ -874,16 +881,26 @@ class PROTOC_EXPORT Formatter {
}
};
template <class T>
void PrintFieldComment(const Formatter& format, const T* field) {
template <typename T>
std::string FieldComment(const T* field) {
// Print the field's (or oneof's) proto-syntax definition as a comment.
// We don't want to print group bodies so we cut off after the first
// line.
DebugStringOptions options;
options.elide_group_body = true;
options.elide_oneof_body = true;
std::string def = field->DebugStringWithOptions(options);
format("// $1$\n", def.substr(0, def.find_first_of('\n')));
for (absl::string_view chunk :
absl::StrSplit(field->DebugStringWithOptions(options), '\n')) {
return std::string(chunk);
}
return "<unknown>";
}
template <class T>
void PrintFieldComment(const Formatter& format, const T* field) {
format("// $1$\n", FieldComment(field));
}
class PROTOC_EXPORT NamespaceOpener {

@ -32,10 +32,10 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/stubs/strutil.h"
namespace google {
namespace protobuf {

File diff suppressed because it is too large Load Diff

@ -37,42 +37,38 @@
#include <cstdint>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "google/protobuf/compiler/cpp/enum.h"
#include "google/protobuf/compiler/cpp/extension.h"
#include "google/protobuf/compiler/cpp/field.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/cpp/message_layout_helper.h"
#include "google/protobuf/compiler/cpp/options.h"
#include "google/protobuf/compiler/cpp/parse_function_generator.h"
namespace google {
namespace protobuf {
namespace io {
class Printer; // printer.h
}
} // namespace protobuf
} // namespace google
#include "google/protobuf/io/printer.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
class EnumGenerator; // enum.h
class ExtensionGenerator; // extension.h
class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
MessageGenerator(const Descriptor* descriptor,
const std::map<std::string, std::string>& vars,
const std::map<std::string, std::string>& ignored,
int index_in_file_messages, const Options& options,
MessageSCCAnalyzer* scc_analyzer);
MessageGenerator(const MessageGenerator&) = delete;
MessageGenerator& operator=(const MessageGenerator&) = delete;
~MessageGenerator();
~MessageGenerator() = default;
// Append the two types of nested generators to the corresponding vector.
void AddGenerators(
@ -80,94 +76,94 @@ class MessageGenerator {
std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators);
// Generate definitions for this class and all its nested types.
void GenerateClassDefinition(io::Printer* printer);
void GenerateClassDefinition(io::Printer* p);
// Generate definitions of inline methods (placed at the end of the header
// file).
void GenerateInlineMethods(io::Printer* printer);
// Source file stuff.
void GenerateInlineMethods(io::Printer* p);
// Generate all non-inline methods for this class.
void GenerateClassMethods(io::Printer* printer);
void GenerateClassMethods(io::Printer* p);
// Generate source file code that should go outside any namespace.
void GenerateSourceInProto2Namespace(io::Printer* printer);
void GenerateSourceInProto2Namespace(io::Printer* p);
private:
// Generate declarations and definitions of accessors for fields.
void GenerateFieldAccessorDeclarations(io::Printer* printer);
void GenerateFieldAccessorDefinitions(io::Printer* printer);
void GenerateInitDefaultSplitInstance(io::Printer* p);
// Generate the constexpr constructor for constant initialization of the
// default instance.
void GenerateConstexprConstructor(io::Printer* p);
void GenerateSchema(io::Printer* p, int offset, int has_offset);
// Generate the field offsets array. Returns the a pair of the total number
// of entries generated and the index of the first has_bit entry.
std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer);
void GenerateSchema(io::Printer* printer, int offset, int has_offset);
std::pair<size_t, size_t> GenerateOffsets(io::Printer* p);
const Descriptor* descriptor() const { return descriptor_; }
private:
// Generate declarations and definitions of accessors for fields.
void GenerateFieldAccessorDeclarations(io::Printer* p);
void GenerateFieldAccessorDefinitions(io::Printer* p);
// Generate constructors and destructor.
void GenerateStructors(io::Printer* printer);
void GenerateStructors(io::Printer* p);
// The compiler typically generates multiple copies of each constructor and
// destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
// Placing common code in a separate method reduces the generated code size.
//
// Generate the shared constructor code.
void GenerateSharedConstructorCode(io::Printer* printer);
void GenerateSharedConstructorCode(io::Printer* p);
// Generate the shared destructor code.
void GenerateSharedDestructorCode(io::Printer* printer);
void GenerateSharedDestructorCode(io::Printer* p);
// Generate the arena-specific destructor code.
void GenerateArenaDestructorCode(io::Printer* printer);
// Generate the constexpr constructor for constant initialization of the
// default instance.
void GenerateConstexprConstructor(io::Printer* printer);
void GenerateInitDefaultSplitInstance(io::Printer* printer);
void GenerateArenaDestructorCode(io::Printer* p);
// Generate standard Message methods.
void GenerateClear(io::Printer* printer);
void GenerateOneofClear(io::Printer* printer);
void GenerateVerify(io::Printer* printer);
void GenerateSerializeWithCachedSizes(io::Printer* printer);
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
void GenerateSerializeWithCachedSizesBody(io::Printer* printer);
void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer);
void GenerateByteSize(io::Printer* printer);
void GenerateMergeFrom(io::Printer* printer);
void GenerateClassSpecificMergeImpl(io::Printer* printer);
void GenerateCopyFrom(io::Printer* printer);
void GenerateSwap(io::Printer* printer);
void GenerateIsInitialized(io::Printer* printer);
void GenerateClear(io::Printer* p);
void GenerateOneofClear(io::Printer* p);
void GenerateVerify(io::Printer* p);
void GenerateSerializeWithCachedSizes(io::Printer* p);
void GenerateSerializeWithCachedSizesToArray(io::Printer* p);
void GenerateSerializeWithCachedSizesBody(io::Printer* p);
void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* p);
void GenerateByteSize(io::Printer* p);
void GenerateMergeFrom(io::Printer* p);
void GenerateClassSpecificMergeImpl(io::Printer* p);
void GenerateCopyFrom(io::Printer* p);
void GenerateSwap(io::Printer* p);
void GenerateIsInitialized(io::Printer* p);
// Helpers for GenerateSerializeWithCachedSizes().
//
// cached_has_bit_index maintains that:
// cached_has_bits = _has_bits_[cached_has_bit_index]
// for cached_has_bit_index >= 0
void GenerateSerializeOneField(io::Printer* printer,
const FieldDescriptor* field,
void GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field,
int cached_has_bits_index);
// Generate a switch statement to serialize 2+ fields from the same oneof.
// Or, if fields.size() == 1, just call GenerateSerializeOneField().
void GenerateSerializeOneofFields(
io::Printer* printer, const std::vector<const FieldDescriptor*>& fields);
io::Printer* p, const std::vector<const FieldDescriptor*>& fields);
void GenerateSerializeOneExtensionRange(
io::Printer* printer, const Descriptor::ExtensionRange* range);
io::Printer* p, const Descriptor::ExtensionRange* range);
// Generates has_foo() functions and variables for singular field has-bits.
void GenerateSingularFieldHasBits(const FieldDescriptor* field,
Formatter format);
io::Printer* p);
// Generates has_foo() functions and variables for oneof field has-bits.
void GenerateOneofHasBits(io::Printer* printer);
void GenerateOneofHasBits(io::Printer* p);
// Generates has_foo_bar() functions for oneof members.
void GenerateOneofMemberHasBits(const FieldDescriptor* field,
const Formatter& format);
void GenerateOneofMemberHasBits(const FieldDescriptor* field, io::Printer* p);
// Generates the clear_foo() method for a field.
void GenerateFieldClear(const FieldDescriptor* field, bool is_inline,
Formatter format);
io::Printer* p);
// Generates the body of the message's copy constructor.
void GenerateCopyConstructorBody(io::Printer* printer) const;
void GenerateCopyConstructorBody(io::Printer* p) const;
// Returns the level that this message needs ArenaDtor. If the message has
// a field that is not arena-exclusive, it needs an ArenaDtor
@ -183,15 +179,13 @@ class MessageGenerator {
size_t HasBitsSize() const;
size_t InlinedStringDonatedSize() const;
int HasBitIndex(const FieldDescriptor* a) const;
int HasByteIndex(const FieldDescriptor* a) const;
int HasWordIndex(const FieldDescriptor* a) const;
bool SameHasByte(const FieldDescriptor* a, const FieldDescriptor* b) const;
int HasBitIndex(const FieldDescriptor* field) const;
int HasByteIndex(const FieldDescriptor* field) const;
int HasWordIndex(const FieldDescriptor* field) const;
std::vector<uint32_t> RequiredFieldsBitMask() const;
const Descriptor* descriptor_;
int index_in_file_messages_;
std::string classname_;
Options options_;
FieldGeneratorMap field_generators_;
// optimized_order_ is the order we layout the message's fields in the
@ -201,19 +195,19 @@ class MessageGenerator {
// optimized_order_ excludes oneof fields and weak fields.
std::vector<const FieldDescriptor*> optimized_order_;
std::vector<int> has_bit_indices_;
int max_has_bit_index_;
int max_has_bit_index_ = 0;
// A map from field index to inlined_string index. For non-inlined-string
// fields, the element is -1. If there is no inlined string in the message,
// this is empty.
std::vector<int> inlined_string_indices_;
// The count of inlined_string fields in the message.
int max_inlined_string_index_;
int max_inlined_string_index_ = 0;
std::vector<const EnumGenerator*> enum_generators_;
std::vector<const ExtensionGenerator*> extension_generators_;
int num_required_fields_;
int num_weak_fields_;
int num_required_fields_ = 0;
int num_weak_fields_ = 0;
std::unique_ptr<MessageLayoutHelper> message_layout_helper_;
std::unique_ptr<ParseFunctionGenerator> parse_function_generator_;
@ -222,7 +216,6 @@ class MessageGenerator {
std::map<std::string, std::string> variables_;
friend class FileGenerator;
};
} // namespace cpp

@ -191,12 +191,19 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
} else {
format(" $field$ = $name$;\n");
}
auto nonempty = [this](const char* fn) {
auto var_it = variables_.find(fn);
return var_it != variables_.end() && !var_it->second.empty();
};
if (nonempty("set_hasbit") || nonempty("clear_hasbit")) {
format(
" if ($name$) {\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n");
}
format(
" if ($name$) {\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n"
"$annotate_set$"
" // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
":$full_name$)\n"

@ -585,6 +585,11 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) {
QualifiedClassName(aux_entry.field->message_type(),
options_));
break;
case TailCallTableInfo::kSubMessageWeak:
format("{::_pbi::FieldAuxDefaultMessage{}, &$1$},\n",
QualifiedDefaultInstancePtr(
aux_entry.field->message_type(), options_));
break;
case TailCallTableInfo::kEnumRange:
format("{$1$, $2$},\n", aux_entry.enum_range.start,
aux_entry.enum_range.size);
@ -628,24 +633,26 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) {
GOOGLE_CHECK(!ShouldSplit(info.field, options_));
std::string func_name = info.func_name;
// For 1-byte tags we have a more optimized version of the varint parser
// that can hardcode the offset and has bit.
if (absl::EndsWith(func_name, "V8S1") ||
absl::EndsWith(func_name, "V32S1") ||
absl::EndsWith(func_name, "V64S1")) {
std::string field_type = absl::EndsWith(func_name, "V8S1") ? "bool"
: absl::EndsWith(func_name, "V32S1")
? "uint32_t"
: "uint64_t";
func_name =
absl::StrCat("::_pbi::TcParser::SingularVarintNoZag1<", field_type,
", offsetof(", //
ClassName(info.field->containing_type()), //
", ", //
FieldMemberName(info.field, /*split=*/false), //
"), ", //
info.hasbit_idx, //
">()");
if (GetOptimizeFor(info.field->file(), options_) == FileOptions::SPEED) {
// For 1-byte tags we have a more optimized version of the varint parser
// that can hardcode the offset and has bit.
if (absl::EndsWith(func_name, "V8S1") ||
absl::EndsWith(func_name, "V32S1") ||
absl::EndsWith(func_name, "V64S1")) {
std::string field_type = absl::EndsWith(func_name, "V8S1") ? "bool"
: absl::EndsWith(func_name, "V32S1")
? "uint32_t"
: "uint64_t";
func_name = absl::StrCat(
"::_pbi::TcParser::SingularVarintNoZag1<", field_type,
", offsetof(", //
ClassName(info.field->containing_type()), //
", ", //
FieldMemberName(info.field, /*split=*/false), //
"), ", //
info.hasbit_idx, //
">()");
}
}
format(
@ -708,20 +715,19 @@ static void FormatFieldKind(Formatter& format,
case fl::kFkMessage: {
format(" | ::_fl::kMessage");
static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy",
"IWeak"};
static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy"};
static_assert((fl::kRepGroup >> fl::kRepShift) == 1, "");
static_assert((fl::kRepLazy >> fl::kRepShift) == 2, "");
static_assert((fl::kRepIWeak >> fl::kRepShift) == 3, "");
if (auto* rep = kRepNames[rep_index]) {
format(" | ::_fl::kRep$1$", rep);
}
static constexpr const char* kXFormNames[] = {nullptr, "Default",
"Table"};
static constexpr const char* kXFormNames[] = {nullptr, "Default", "Table",
"WeakPtr"};
static_assert((fl::kTvDefault >> fl::kTvShift) == 1, "");
static_assert((fl::kTvTable >> fl::kTvShift) == 2, "");
static_assert((fl::kTvWeakPtr >> fl::kTvShift) == 3, "");
if (auto* xform = kXFormNames[tv_index]) {
format(" | ::_fl::kTv$1$", xform);

@ -36,7 +36,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/cpp/helpers.h"

@ -35,11 +35,11 @@
#include "google/protobuf/compiler/cpp/string_field.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/stubs/strutil.h"
namespace google {
namespace protobuf {
@ -313,12 +313,20 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
format(
"}\n"
"inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
"$maybe_prepare_split_message$"
" if ($name$ != nullptr) {\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n");
"$maybe_prepare_split_message$");
auto nonempty = [this](const char* fn) {
auto var_it = variables_.find(fn);
return var_it != variables_.end() && !var_it->second.empty();
};
if (nonempty("set_hasbit") || nonempty("clear_hasbit")) {
format(
" if ($name$ != nullptr) {\n"
" $set_hasbit$\n"
" } else {\n"
" $clear_hasbit$\n"
" }\n");
}
if (!inlined_) {
format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n");
if (descriptor_->default_value_string().empty()) {

@ -50,6 +50,7 @@
#include <vector>
#include "google/protobuf/compiler/cpp/unittest.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#ifndef _MSC_VER
// We exclude this large proto because it's too large for

@ -41,7 +41,6 @@
#include "google/protobuf/testing/file.h"
#include "google/protobuf/testing/googletest.h"
#include "google/protobuf/stubs/strutil.h"
#include <gtest/gtest.h>
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"

@ -88,7 +88,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.MergeFrom(other.$name$_);\n");
"$name$_.Add(other.$name$_);\n");
}
void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {

@ -38,8 +38,8 @@
#include "google/protobuf/compiler/csharp/csharp_field_base.h"
#include "google/protobuf/compiler/csharp/csharp_helpers.h"
#include "google/protobuf/compiler/csharp/csharp_message.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/compiler/csharp/csharp_options.h"
#include "google/protobuf/compiler/csharp/names.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"

@ -221,12 +221,6 @@ class PROTOBUF_EXPORT SourceTree {
SourceTree& operator=(const SourceTree&) = delete;
virtual ~SourceTree();
// This is a temporary typedef alias to allow migrating the argument type of
// Open in an atomic change without touching certain directories which are
// restricted for various reasons. This must match the argument type used
// below.
using SourceTreeOpenArgumentType = absl::string_view;
// Open the given file and return a stream that reads it, or NULL if not
// found. The caller takes ownership of the returned object. The filename
// must be a path relative to the root of the source tree and must not

@ -31,7 +31,6 @@
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/field.h"
#include "google/protobuf/compiler/java/helpers.h"

@ -38,7 +38,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_split.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"

@ -38,7 +38,6 @@
#include <string>
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -987,7 +987,6 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCodeFromPacked(
"}\n"
"input.popLimit(oldLimit);\n");
}
void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
if (descriptor_->is_packed()) {

@ -42,7 +42,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -38,7 +38,6 @@
#include <string>
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -35,7 +35,6 @@
#include "google/protobuf/compiler/java/extension.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -31,7 +31,6 @@
#include "google/protobuf/compiler/java/extension_lite.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"
#include "google/protobuf/compiler/java/helpers.h"

@ -39,7 +39,6 @@
#include "google/protobuf/stubs/logging.h"
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/java/context.h"

@ -41,7 +41,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/enum.h"

@ -848,7 +848,6 @@ void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
" $name$__.getKey(), $name$__.getValue());\n");
}
}
void ImmutableMapFieldGenerator::GenerateSerializationCode(
io::Printer* printer) const {
printer->Print(variables_,

@ -44,7 +44,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"

@ -42,7 +42,6 @@
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"

@ -43,7 +43,6 @@
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/java/context.h"

@ -39,7 +39,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"
#include "google/protobuf/compiler/java/helpers.h"

@ -40,7 +40,6 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -44,7 +44,6 @@
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"

@ -140,7 +140,6 @@ std::string ClassName(const FileDescriptor* descriptor) {
return name_resolver.GetClassName(descriptor, true);
}
std::string FileJavaPackage(const FileDescriptor* file, bool immutable,
Options options) {
std::string result;

@ -43,6 +43,9 @@
#include "google/protobuf/descriptor.h"
#include "google/protobuf/compiler/java/options.h"
// Must be last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
@ -122,8 +125,11 @@ std::string UnderscoresToCamelCase(const MethodDescriptor* method);
// Same as UnderscoresToCamelCase, but checks for reserved keywords
std::string UnderscoresToCamelCaseCheckReserved(const FieldDescriptor* field);
} // namespace java
} // namespace compiler
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__

@ -42,7 +42,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -42,7 +42,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"

@ -35,7 +35,6 @@
#include "google/protobuf/compiler/java/service.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -43,7 +43,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -43,7 +43,6 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/str_cat.h"
#include "google/protobuf/compiler/java/context.h"
#include "google/protobuf/compiler/java/doc_comment.h"

@ -28,11 +28,11 @@
// (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/compiler/command_line_interface.h"
#include "google/protobuf/compiler/cpp/generator.h"
#include "google/protobuf/compiler/csharp/csharp_generator.h"
#include "google/protobuf/compiler/java/generator.h"
#include "google/protobuf/compiler/java/kotlin_generator.h"
#include "google/protobuf/compiler/command_line_interface.h"
#include "google/protobuf/compiler/csharp/csharp_generator.h"
#include "google/protobuf/compiler/objectivec/generator.h"
#include "google/protobuf/compiler/php/php_generator.h"
#include "google/protobuf/compiler/python/generator.h"

@ -32,12 +32,13 @@
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/str_replace.h"
#include "google/protobuf/compiler/objectivec/helpers.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/stubs/common.h"
// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for errors.

@ -1,3 +1,33 @@
// 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.
// NSObject methods
// Autogenerated by method_dump.sh. Do not edit by hand.
// Date: Thu Nov 1 14:12:16 PDT 2018

@ -29,11 +29,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/str_replace.h"
#include "google/protobuf/compiler/objectivec/text_format_decode_data.h"
#include "google/protobuf/compiler/objectivec/names.h"
#include "google/protobuf/io/coded_stream.h"

@ -1585,11 +1585,12 @@ bool Parser::ParseOption(Message* options,
break;
}
// value too large for an integer; fall through below to treat as floating point
ABSL_FALLTHROUGH_INTENDED;
}
case io::Tokenizer::TYPE_FLOAT: {
value_location.AddPath(UninterpretedOption::kDoubleValueFieldNumber);
double value;
double value = 0.0;
DO(ConsumeNumber(&value, "Expected number."));
uninterpreted_option->set_double_value(is_negative ? -value : value);
break;

@ -33,7 +33,6 @@
#include <sstream>
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/stubs/strutil.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_replace.h"
@ -43,6 +42,8 @@
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/stubs/strutil.h" // for StringReplace.
const std::string kDescriptorFile = "google/protobuf/descriptor.proto";
const std::string kEmptyFile = "google/protobuf/empty.proto";
const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php";

@ -254,14 +254,17 @@ bool CodeGeneratorResponse_Feature_IsValid(int value) {
return false;
}
}
#if (__cplusplus < 201703) && \
(!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_NONE;
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::FEATURE_PROTO3_OPTIONAL;
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MIN;
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse::Feature_MAX;
constexpr int CodeGeneratorResponse::Feature_ARRAYSIZE;
#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
#endif // (__cplusplus < 201703) &&
// (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
// ===================================================================
class Version::_Internal {
@ -371,6 +374,7 @@ void Version::Clear() {
}
const char* Version::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
_Internal::HasBits has_bits{};
while (!ctx->Done(&ptr)) {
@ -442,6 +446,7 @@ failure:
uint8_t* Version::_InternalSerialize(
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.Version)
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
@ -484,6 +489,7 @@ uint8_t* Version::_InternalSerialize(
}
size_t Version::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.Version)
size_t total_size = 0;
@ -529,6 +535,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*Version::GetClassData() const
void Version::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
auto* const _this = static_cast<Version*>(&to_msg);
auto& from = static_cast<const Version&>(from_msg);
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.Version)
GOOGLE_DCHECK_NE(&from, _this);
uint32_t cached_has_bits = 0;
@ -583,6 +590,7 @@ void Version::InternalSwap(Version* other) {
}
::PROTOBUF_NAMESPACE_ID::Metadata Version::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]);
@ -704,6 +712,7 @@ void CodeGeneratorRequest::Clear() {
}
const char* CodeGeneratorRequest::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
_Internal::HasBits has_bits{};
while (!ctx->Done(&ptr)) {
@ -786,6 +795,7 @@ failure:
uint8_t* CodeGeneratorRequest::_InternalSerialize(
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
@ -835,6 +845,7 @@ uint8_t* CodeGeneratorRequest::_InternalSerialize(
}
size_t CodeGeneratorRequest::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest)
size_t total_size = 0;
@ -887,6 +898,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorRequest::GetClass
void CodeGeneratorRequest::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
auto* const _this = static_cast<CodeGeneratorRequest*>(&to_msg);
auto& from = static_cast<const CodeGeneratorRequest&>(from_msg);
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest)
GOOGLE_DCHECK_NE(&from, _this);
uint32_t cached_has_bits = 0;
@ -936,6 +948,7 @@ void CodeGeneratorRequest::InternalSwap(CodeGeneratorRequest* other) {
}
::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorRequest::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]);
@ -1092,6 +1105,7 @@ void CodeGeneratorResponse_File::Clear() {
}
const char* CodeGeneratorResponse_File::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
_Internal::HasBits has_bits{};
while (!ctx->Done(&ptr)) {
@ -1168,6 +1182,7 @@ failure:
uint8_t* CodeGeneratorResponse_File::_InternalSerialize(
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
@ -1219,6 +1234,7 @@ uint8_t* CodeGeneratorResponse_File::_InternalSerialize(
}
size_t CodeGeneratorResponse_File::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File)
size_t total_size = 0;
@ -1270,6 +1286,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse_File::Ge
void CodeGeneratorResponse_File::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
auto* const _this = static_cast<CodeGeneratorResponse_File*>(&to_msg);
auto& from = static_cast<const CodeGeneratorResponse_File&>(from_msg);
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File)
GOOGLE_DCHECK_NE(&from, _this);
uint32_t cached_has_bits = 0;
@ -1327,6 +1344,7 @@ void CodeGeneratorResponse_File::InternalSwap(CodeGeneratorResponse_File* other)
}
::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse_File::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]);
@ -1428,6 +1446,7 @@ void CodeGeneratorResponse::Clear() {
}
const char* CodeGeneratorResponse::_InternalParse(const char* ptr, ::_pbi::ParseContext* ctx) {
#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure
_Internal::HasBits has_bits{};
while (!ctx->Done(&ptr)) {
@ -1494,6 +1513,7 @@ failure:
uint8_t* CodeGeneratorResponse::_InternalSerialize(
uint8_t* target, ::PROTOBUF_NAMESPACE_ID::io::EpsCopyOutputStream* stream) const {
// @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
@ -1532,6 +1552,7 @@ uint8_t* CodeGeneratorResponse::_InternalSerialize(
}
size_t CodeGeneratorResponse::ByteSizeLong() const {
// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse)
size_t total_size = 0;
@ -1574,6 +1595,7 @@ const ::PROTOBUF_NAMESPACE_ID::Message::ClassData*CodeGeneratorResponse::GetClas
void CodeGeneratorResponse::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PROTOBUF_NAMESPACE_ID::Message& from_msg) {
auto* const _this = static_cast<CodeGeneratorResponse*>(&to_msg);
auto& from = static_cast<const CodeGeneratorResponse&>(from_msg);
// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse)
GOOGLE_DCHECK_NE(&from, _this);
uint32_t cached_has_bits = 0;
@ -1619,6 +1641,7 @@ void CodeGeneratorResponse::InternalSwap(CodeGeneratorResponse* other) {
}
::PROTOBUF_NAMESPACE_ID::Metadata CodeGeneratorResponse::GetMetadata() const {
return ::_pbi::AssignDescriptors(
&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]);

@ -87,30 +87,31 @@ PROTOBUF_NAMESPACE_OPEN
namespace compiler {
enum CodeGeneratorResponse_Feature : int {
CodeGeneratorResponse_Feature_FEATURE_NONE = 0,
CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1
CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL = 1,
};
PROTOC_EXPORT bool CodeGeneratorResponse_Feature_IsValid(int value);
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = CodeGeneratorResponse_Feature_FEATURE_NONE;
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL;
constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_MAX + 1;
PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CodeGeneratorResponse_Feature_descriptor();
template<typename T>
inline const std::string& CodeGeneratorResponse_Feature_Name(T enum_t_value) {
static_assert(::std::is_same<T, CodeGeneratorResponse_Feature>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function CodeGeneratorResponse_Feature_Name.");
return CodeGeneratorResponse_Feature_Name(static_cast<CodeGeneratorResponse_Feature>(enum_t_value));
}
template<>
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MIN = static_cast<CodeGeneratorResponse_Feature>(0);
constexpr CodeGeneratorResponse_Feature CodeGeneratorResponse_Feature_Feature_MAX = static_cast<CodeGeneratorResponse_Feature>(1);
constexpr int CodeGeneratorResponse_Feature_Feature_ARRAYSIZE = 1 + 1;
PROTOC_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
CodeGeneratorResponse_Feature_descriptor();
template <typename T>
const std::string& CodeGeneratorResponse_Feature_Name(T value) {
static_assert(std::is_same<T, CodeGeneratorResponse_Feature>::value ||
std::is_integral<T>::value,
"Incorrect type passed to Feature_Name().");
return CodeGeneratorResponse_Feature_Name(static_cast<CodeGeneratorResponse_Feature>(value));
}
template <>
inline const std::string& CodeGeneratorResponse_Feature_Name(CodeGeneratorResponse_Feature value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<CodeGeneratorResponse_Feature_descriptor, 0, 1>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<CodeGeneratorResponse_Feature_descriptor,
0, 1>(
static_cast<int>(value));
}
inline bool CodeGeneratorResponse_Feature_Parse(
::absl::string_view name, CodeGeneratorResponse_Feature* value) {
inline bool CodeGeneratorResponse_Feature_Parse(absl::string_view name, CodeGeneratorResponse_Feature* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<CodeGeneratorResponse_Feature>(
CodeGeneratorResponse_Feature_descriptor(), name, value);
CodeGeneratorResponse_Feature_descriptor(), name, value);
}
// ===================================================================
@ -908,33 +909,23 @@ class PROTOC_EXPORT CodeGeneratorResponse final :
typedef CodeGeneratorResponse_File File;
typedef CodeGeneratorResponse_Feature Feature;
static constexpr Feature FEATURE_NONE =
CodeGeneratorResponse_Feature_FEATURE_NONE;
static constexpr Feature FEATURE_PROTO3_OPTIONAL =
CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL;
using Feature = CodeGeneratorResponse_Feature;
static constexpr Feature FEATURE_NONE = CodeGeneratorResponse_Feature_FEATURE_NONE;
static constexpr Feature FEATURE_PROTO3_OPTIONAL = CodeGeneratorResponse_Feature_FEATURE_PROTO3_OPTIONAL;
static inline bool Feature_IsValid(int value) {
return CodeGeneratorResponse_Feature_IsValid(value);
}
static constexpr Feature Feature_MIN =
CodeGeneratorResponse_Feature_Feature_MIN;
static constexpr Feature Feature_MAX =
CodeGeneratorResponse_Feature_Feature_MAX;
static constexpr int Feature_ARRAYSIZE =
CodeGeneratorResponse_Feature_Feature_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
Feature_descriptor() {
static constexpr Feature Feature_MIN = CodeGeneratorResponse_Feature_Feature_MIN;
static constexpr Feature Feature_MAX = CodeGeneratorResponse_Feature_Feature_MAX;
static constexpr int Feature_ARRAYSIZE = CodeGeneratorResponse_Feature_Feature_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Feature_descriptor() {
return CodeGeneratorResponse_Feature_descriptor();
}
template<typename T>
static inline const std::string& Feature_Name(T enum_t_value) {
static_assert(::std::is_same<T, Feature>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Feature_Name.");
return CodeGeneratorResponse_Feature_Name(enum_t_value);
template <typename T>
static inline const std::string& Feature_Name(T value) {
return CodeGeneratorResponse_Feature_Name(value);
}
static inline bool Feature_Parse(::absl::string_view name,
Feature* value) {
static inline bool Feature_Parse(absl::string_view name, Feature* value) {
return CodeGeneratorResponse_Feature_Parse(name, value);
}
@ -1885,9 +1876,10 @@ PROTOBUF_NAMESPACE_CLOSE
PROTOBUF_NAMESPACE_OPEN
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature>() {
return ::PROTOBUF_NAMESPACE_ID::compiler::CodeGeneratorResponse_Feature_descriptor();
}

@ -2531,10 +2531,6 @@ void FileDescriptor::CopyTo(FileDescriptorProto* proto) const {
for (int i = 0; i < extension_count(); i++) {
extension(i)->CopyTo(proto->add_extension());
}
if (&options() != &FileOptions::default_instance()) {
proto->mutable_options()->CopyFrom(options());
}
}
void FileDescriptor::CopyHeadingTo(FileDescriptorProto* proto) const {
@ -2548,6 +2544,9 @@ void FileDescriptor::CopyHeadingTo(FileDescriptorProto* proto) const {
) {
proto->set_syntax(SyntaxName(syntax()));
}
if (&options() != &FileOptions::default_instance()) {
*proto->mutable_options() = options();
}
}
void FileDescriptor::CopyJsonNameTo(FileDescriptorProto* proto) const {

File diff suppressed because it is too large Load Diff

@ -208,198 +208,205 @@ enum FieldDescriptorProto_Type : int {
FieldDescriptorProto_Type_TYPE_SFIXED32 = 15,
FieldDescriptorProto_Type_TYPE_SFIXED64 = 16,
FieldDescriptorProto_Type_TYPE_SINT32 = 17,
FieldDescriptorProto_Type_TYPE_SINT64 = 18
FieldDescriptorProto_Type_TYPE_SINT64 = 18,
};
PROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value);
constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE;
constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64;
constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Type_descriptor();
template<typename T>
inline const std::string& FieldDescriptorProto_Type_Name(T enum_t_value) {
static_assert(::std::is_same<T, FieldDescriptorProto_Type>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function FieldDescriptorProto_Type_Name.");
return FieldDescriptorProto_Type_Name(static_cast<FieldDescriptorProto_Type>(enum_t_value));
}
template<>
constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = static_cast<FieldDescriptorProto_Type>(1);
constexpr FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = static_cast<FieldDescriptorProto_Type>(18);
constexpr int FieldDescriptorProto_Type_Type_ARRAYSIZE = 18 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
FieldDescriptorProto_Type_descriptor();
template <typename T>
const std::string& FieldDescriptorProto_Type_Name(T value) {
static_assert(std::is_same<T, FieldDescriptorProto_Type>::value ||
std::is_integral<T>::value,
"Incorrect type passed to Type_Name().");
return FieldDescriptorProto_Type_Name(static_cast<FieldDescriptorProto_Type>(value));
}
template <>
inline const std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<FieldDescriptorProto_Type_descriptor, 1, 18>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<FieldDescriptorProto_Type_descriptor,
1, 18>(
static_cast<int>(value));
}
inline bool FieldDescriptorProto_Type_Parse(
::absl::string_view name, FieldDescriptorProto_Type* value) {
inline bool FieldDescriptorProto_Type_Parse(absl::string_view name, FieldDescriptorProto_Type* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Type>(
FieldDescriptorProto_Type_descriptor(), name, value);
FieldDescriptorProto_Type_descriptor(), name, value);
}
enum FieldDescriptorProto_Label : int {
FieldDescriptorProto_Label_LABEL_OPTIONAL = 1,
FieldDescriptorProto_Label_LABEL_REQUIRED = 2,
FieldDescriptorProto_Label_LABEL_REPEATED = 3
FieldDescriptorProto_Label_LABEL_REPEATED = 3,
};
PROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value);
constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL;
constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED;
constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldDescriptorProto_Label_descriptor();
template<typename T>
inline const std::string& FieldDescriptorProto_Label_Name(T enum_t_value) {
static_assert(::std::is_same<T, FieldDescriptorProto_Label>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function FieldDescriptorProto_Label_Name.");
return FieldDescriptorProto_Label_Name(static_cast<FieldDescriptorProto_Label>(enum_t_value));
}
template<>
constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = static_cast<FieldDescriptorProto_Label>(1);
constexpr FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = static_cast<FieldDescriptorProto_Label>(3);
constexpr int FieldDescriptorProto_Label_Label_ARRAYSIZE = 3 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
FieldDescriptorProto_Label_descriptor();
template <typename T>
const std::string& FieldDescriptorProto_Label_Name(T value) {
static_assert(std::is_same<T, FieldDescriptorProto_Label>::value ||
std::is_integral<T>::value,
"Incorrect type passed to Label_Name().");
return FieldDescriptorProto_Label_Name(static_cast<FieldDescriptorProto_Label>(value));
}
template <>
inline const std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<FieldDescriptorProto_Label_descriptor, 1, 3>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<FieldDescriptorProto_Label_descriptor,
1, 3>(
static_cast<int>(value));
}
inline bool FieldDescriptorProto_Label_Parse(
::absl::string_view name, FieldDescriptorProto_Label* value) {
inline bool FieldDescriptorProto_Label_Parse(absl::string_view name, FieldDescriptorProto_Label* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldDescriptorProto_Label>(
FieldDescriptorProto_Label_descriptor(), name, value);
FieldDescriptorProto_Label_descriptor(), name, value);
}
enum FileOptions_OptimizeMode : int {
FileOptions_OptimizeMode_SPEED = 1,
FileOptions_OptimizeMode_CODE_SIZE = 2,
FileOptions_OptimizeMode_LITE_RUNTIME = 3
FileOptions_OptimizeMode_LITE_RUNTIME = 3,
};
PROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value);
constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED;
constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME;
constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FileOptions_OptimizeMode_descriptor();
template<typename T>
inline const std::string& FileOptions_OptimizeMode_Name(T enum_t_value) {
static_assert(::std::is_same<T, FileOptions_OptimizeMode>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function FileOptions_OptimizeMode_Name.");
return FileOptions_OptimizeMode_Name(static_cast<FileOptions_OptimizeMode>(enum_t_value));
}
template<>
constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = static_cast<FileOptions_OptimizeMode>(1);
constexpr FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = static_cast<FileOptions_OptimizeMode>(3);
constexpr int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = 3 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
FileOptions_OptimizeMode_descriptor();
template <typename T>
const std::string& FileOptions_OptimizeMode_Name(T value) {
static_assert(std::is_same<T, FileOptions_OptimizeMode>::value ||
std::is_integral<T>::value,
"Incorrect type passed to OptimizeMode_Name().");
return FileOptions_OptimizeMode_Name(static_cast<FileOptions_OptimizeMode>(value));
}
template <>
inline const std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<FileOptions_OptimizeMode_descriptor, 1, 3>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<FileOptions_OptimizeMode_descriptor,
1, 3>(
static_cast<int>(value));
}
inline bool FileOptions_OptimizeMode_Parse(
::absl::string_view name, FileOptions_OptimizeMode* value) {
inline bool FileOptions_OptimizeMode_Parse(absl::string_view name, FileOptions_OptimizeMode* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FileOptions_OptimizeMode>(
FileOptions_OptimizeMode_descriptor(), name, value);
FileOptions_OptimizeMode_descriptor(), name, value);
}
enum FieldOptions_CType : int {
FieldOptions_CType_STRING = 0,
FieldOptions_CType_CORD = 1,
FieldOptions_CType_STRING_PIECE = 2
FieldOptions_CType_STRING_PIECE = 2,
};
PROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value);
constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING;
constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE;
constexpr int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_CType_descriptor();
template<typename T>
inline const std::string& FieldOptions_CType_Name(T enum_t_value) {
static_assert(::std::is_same<T, FieldOptions_CType>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function FieldOptions_CType_Name.");
return FieldOptions_CType_Name(static_cast<FieldOptions_CType>(enum_t_value));
}
template<>
constexpr FieldOptions_CType FieldOptions_CType_CType_MIN = static_cast<FieldOptions_CType>(0);
constexpr FieldOptions_CType FieldOptions_CType_CType_MAX = static_cast<FieldOptions_CType>(2);
constexpr int FieldOptions_CType_CType_ARRAYSIZE = 2 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
FieldOptions_CType_descriptor();
template <typename T>
const std::string& FieldOptions_CType_Name(T value) {
static_assert(std::is_same<T, FieldOptions_CType>::value ||
std::is_integral<T>::value,
"Incorrect type passed to CType_Name().");
return FieldOptions_CType_Name(static_cast<FieldOptions_CType>(value));
}
template <>
inline const std::string& FieldOptions_CType_Name(FieldOptions_CType value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<FieldOptions_CType_descriptor, 0, 2>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<FieldOptions_CType_descriptor,
0, 2>(
static_cast<int>(value));
}
inline bool FieldOptions_CType_Parse(
::absl::string_view name, FieldOptions_CType* value) {
inline bool FieldOptions_CType_Parse(absl::string_view name, FieldOptions_CType* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_CType>(
FieldOptions_CType_descriptor(), name, value);
FieldOptions_CType_descriptor(), name, value);
}
enum FieldOptions_JSType : int {
FieldOptions_JSType_JS_NORMAL = 0,
FieldOptions_JSType_JS_STRING = 1,
FieldOptions_JSType_JS_NUMBER = 2
FieldOptions_JSType_JS_NUMBER = 2,
};
PROTOBUF_EXPORT bool FieldOptions_JSType_IsValid(int value);
constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = FieldOptions_JSType_JS_NORMAL;
constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = FieldOptions_JSType_JS_NUMBER;
constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = FieldOptions_JSType_JSType_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* FieldOptions_JSType_descriptor();
template<typename T>
inline const std::string& FieldOptions_JSType_Name(T enum_t_value) {
static_assert(::std::is_same<T, FieldOptions_JSType>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function FieldOptions_JSType_Name.");
return FieldOptions_JSType_Name(static_cast<FieldOptions_JSType>(enum_t_value));
}
template<>
constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MIN = static_cast<FieldOptions_JSType>(0);
constexpr FieldOptions_JSType FieldOptions_JSType_JSType_MAX = static_cast<FieldOptions_JSType>(2);
constexpr int FieldOptions_JSType_JSType_ARRAYSIZE = 2 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
FieldOptions_JSType_descriptor();
template <typename T>
const std::string& FieldOptions_JSType_Name(T value) {
static_assert(std::is_same<T, FieldOptions_JSType>::value ||
std::is_integral<T>::value,
"Incorrect type passed to JSType_Name().");
return FieldOptions_JSType_Name(static_cast<FieldOptions_JSType>(value));
}
template <>
inline const std::string& FieldOptions_JSType_Name(FieldOptions_JSType value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<FieldOptions_JSType_descriptor, 0, 2>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<FieldOptions_JSType_descriptor,
0, 2>(
static_cast<int>(value));
}
inline bool FieldOptions_JSType_Parse(
::absl::string_view name, FieldOptions_JSType* value) {
inline bool FieldOptions_JSType_Parse(absl::string_view name, FieldOptions_JSType* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<FieldOptions_JSType>(
FieldOptions_JSType_descriptor(), name, value);
FieldOptions_JSType_descriptor(), name, value);
}
enum MethodOptions_IdempotencyLevel : int {
MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN = 0,
MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS = 1,
MethodOptions_IdempotencyLevel_IDEMPOTENT = 2
MethodOptions_IdempotencyLevel_IDEMPOTENT = 2,
};
PROTOBUF_EXPORT bool MethodOptions_IdempotencyLevel_IsValid(int value);
constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IDEMPOTENT;
constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* MethodOptions_IdempotencyLevel_descriptor();
template<typename T>
inline const std::string& MethodOptions_IdempotencyLevel_Name(T enum_t_value) {
static_assert(::std::is_same<T, MethodOptions_IdempotencyLevel>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function MethodOptions_IdempotencyLevel_Name.");
return MethodOptions_IdempotencyLevel_Name(static_cast<MethodOptions_IdempotencyLevel>(enum_t_value));
}
template<>
constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN = static_cast<MethodOptions_IdempotencyLevel>(0);
constexpr MethodOptions_IdempotencyLevel MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX = static_cast<MethodOptions_IdempotencyLevel>(2);
constexpr int MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE = 2 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
MethodOptions_IdempotencyLevel_descriptor();
template <typename T>
const std::string& MethodOptions_IdempotencyLevel_Name(T value) {
static_assert(std::is_same<T, MethodOptions_IdempotencyLevel>::value ||
std::is_integral<T>::value,
"Incorrect type passed to IdempotencyLevel_Name().");
return MethodOptions_IdempotencyLevel_Name(static_cast<MethodOptions_IdempotencyLevel>(value));
}
template <>
inline const std::string& MethodOptions_IdempotencyLevel_Name(MethodOptions_IdempotencyLevel value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<MethodOptions_IdempotencyLevel_descriptor, 0, 2>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<MethodOptions_IdempotencyLevel_descriptor,
0, 2>(
static_cast<int>(value));
}
inline bool MethodOptions_IdempotencyLevel_Parse(
::absl::string_view name, MethodOptions_IdempotencyLevel* value) {
inline bool MethodOptions_IdempotencyLevel_Parse(absl::string_view name, MethodOptions_IdempotencyLevel* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<MethodOptions_IdempotencyLevel>(
MethodOptions_IdempotencyLevel_descriptor(), name, value);
MethodOptions_IdempotencyLevel_descriptor(), name, value);
}
enum GeneratedCodeInfo_Annotation_Semantic : int {
GeneratedCodeInfo_Annotation_Semantic_NONE = 0,
GeneratedCodeInfo_Annotation_Semantic_SET = 1,
GeneratedCodeInfo_Annotation_Semantic_ALIAS = 2
GeneratedCodeInfo_Annotation_Semantic_ALIAS = 2,
};
PROTOBUF_EXPORT bool GeneratedCodeInfo_Annotation_Semantic_IsValid(int value);
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN = GeneratedCodeInfo_Annotation_Semantic_NONE;
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX = GeneratedCodeInfo_Annotation_Semantic_ALIAS;
constexpr int GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE = GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GeneratedCodeInfo_Annotation_Semantic_descriptor();
template<typename T>
inline const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(T enum_t_value) {
static_assert(::std::is_same<T, GeneratedCodeInfo_Annotation_Semantic>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function GeneratedCodeInfo_Annotation_Semantic_Name.");
return GeneratedCodeInfo_Annotation_Semantic_Name(static_cast<GeneratedCodeInfo_Annotation_Semantic>(enum_t_value));
}
template<>
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN = static_cast<GeneratedCodeInfo_Annotation_Semantic>(0);
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX = static_cast<GeneratedCodeInfo_Annotation_Semantic>(2);
constexpr int GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE = 2 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
GeneratedCodeInfo_Annotation_Semantic_descriptor();
template <typename T>
const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(T value) {
static_assert(std::is_same<T, GeneratedCodeInfo_Annotation_Semantic>::value ||
std::is_integral<T>::value,
"Incorrect type passed to Semantic_Name().");
return GeneratedCodeInfo_Annotation_Semantic_Name(static_cast<GeneratedCodeInfo_Annotation_Semantic>(value));
}
template <>
inline const std::string& GeneratedCodeInfo_Annotation_Semantic_Name(GeneratedCodeInfo_Annotation_Semantic value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<GeneratedCodeInfo_Annotation_Semantic_descriptor, 0, 2>(static_cast<int>(value));
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<GeneratedCodeInfo_Annotation_Semantic_descriptor,
0, 2>(
static_cast<int>(value));
}
inline bool GeneratedCodeInfo_Annotation_Semantic_Parse(
::absl::string_view name, GeneratedCodeInfo_Annotation_Semantic* value) {
inline bool GeneratedCodeInfo_Annotation_Semantic_Parse(absl::string_view name, GeneratedCodeInfo_Annotation_Semantic* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<GeneratedCodeInfo_Annotation_Semantic>(
GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value);
GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value);
}
// ===================================================================
@ -2189,97 +2196,60 @@ class PROTOBUF_EXPORT FieldDescriptorProto final :
// nested types ----------------------------------------------------
typedef FieldDescriptorProto_Type Type;
static constexpr Type TYPE_DOUBLE =
FieldDescriptorProto_Type_TYPE_DOUBLE;
static constexpr Type TYPE_FLOAT =
FieldDescriptorProto_Type_TYPE_FLOAT;
static constexpr Type TYPE_INT64 =
FieldDescriptorProto_Type_TYPE_INT64;
static constexpr Type TYPE_UINT64 =
FieldDescriptorProto_Type_TYPE_UINT64;
static constexpr Type TYPE_INT32 =
FieldDescriptorProto_Type_TYPE_INT32;
static constexpr Type TYPE_FIXED64 =
FieldDescriptorProto_Type_TYPE_FIXED64;
static constexpr Type TYPE_FIXED32 =
FieldDescriptorProto_Type_TYPE_FIXED32;
static constexpr Type TYPE_BOOL =
FieldDescriptorProto_Type_TYPE_BOOL;
static constexpr Type TYPE_STRING =
FieldDescriptorProto_Type_TYPE_STRING;
static constexpr Type TYPE_GROUP =
FieldDescriptorProto_Type_TYPE_GROUP;
static constexpr Type TYPE_MESSAGE =
FieldDescriptorProto_Type_TYPE_MESSAGE;
static constexpr Type TYPE_BYTES =
FieldDescriptorProto_Type_TYPE_BYTES;
static constexpr Type TYPE_UINT32 =
FieldDescriptorProto_Type_TYPE_UINT32;
static constexpr Type TYPE_ENUM =
FieldDescriptorProto_Type_TYPE_ENUM;
static constexpr Type TYPE_SFIXED32 =
FieldDescriptorProto_Type_TYPE_SFIXED32;
static constexpr Type TYPE_SFIXED64 =
FieldDescriptorProto_Type_TYPE_SFIXED64;
static constexpr Type TYPE_SINT32 =
FieldDescriptorProto_Type_TYPE_SINT32;
static constexpr Type TYPE_SINT64 =
FieldDescriptorProto_Type_TYPE_SINT64;
using Type = FieldDescriptorProto_Type;
static constexpr Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE;
static constexpr Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT;
static constexpr Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64;
static constexpr Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64;
static constexpr Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32;
static constexpr Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64;
static constexpr Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32;
static constexpr Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL;
static constexpr Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING;
static constexpr Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP;
static constexpr Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE;
static constexpr Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES;
static constexpr Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32;
static constexpr Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM;
static constexpr Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32;
static constexpr Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64;
static constexpr Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32;
static constexpr Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64;
static inline bool Type_IsValid(int value) {
return FieldDescriptorProto_Type_IsValid(value);
}
static constexpr Type Type_MIN =
FieldDescriptorProto_Type_Type_MIN;
static constexpr Type Type_MAX =
FieldDescriptorProto_Type_Type_MAX;
static constexpr int Type_ARRAYSIZE =
FieldDescriptorProto_Type_Type_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
Type_descriptor() {
static constexpr Type Type_MIN = FieldDescriptorProto_Type_Type_MIN;
static constexpr Type Type_MAX = FieldDescriptorProto_Type_Type_MAX;
static constexpr int Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Type_descriptor() {
return FieldDescriptorProto_Type_descriptor();
}
template<typename T>
static inline const std::string& Type_Name(T enum_t_value) {
static_assert(::std::is_same<T, Type>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Type_Name.");
return FieldDescriptorProto_Type_Name(enum_t_value);
template <typename T>
static inline const std::string& Type_Name(T value) {
return FieldDescriptorProto_Type_Name(value);
}
static inline bool Type_Parse(::absl::string_view name,
Type* value) {
static inline bool Type_Parse(absl::string_view name, Type* value) {
return FieldDescriptorProto_Type_Parse(name, value);
}
typedef FieldDescriptorProto_Label Label;
static constexpr Label LABEL_OPTIONAL =
FieldDescriptorProto_Label_LABEL_OPTIONAL;
static constexpr Label LABEL_REQUIRED =
FieldDescriptorProto_Label_LABEL_REQUIRED;
static constexpr Label LABEL_REPEATED =
FieldDescriptorProto_Label_LABEL_REPEATED;
using Label = FieldDescriptorProto_Label;
static constexpr Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL;
static constexpr Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED;
static constexpr Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED;
static inline bool Label_IsValid(int value) {
return FieldDescriptorProto_Label_IsValid(value);
}
static constexpr Label Label_MIN =
FieldDescriptorProto_Label_Label_MIN;
static constexpr Label Label_MAX =
FieldDescriptorProto_Label_Label_MAX;
static constexpr int Label_ARRAYSIZE =
FieldDescriptorProto_Label_Label_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
Label_descriptor() {
static constexpr Label Label_MIN = FieldDescriptorProto_Label_Label_MIN;
static constexpr Label Label_MAX = FieldDescriptorProto_Label_Label_MAX;
static constexpr int Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Label_descriptor() {
return FieldDescriptorProto_Label_descriptor();
}
template<typename T>
static inline const std::string& Label_Name(T enum_t_value) {
static_assert(::std::is_same<T, Label>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Label_Name.");
return FieldDescriptorProto_Label_Name(enum_t_value);
template <typename T>
static inline const std::string& Label_Name(T value) {
return FieldDescriptorProto_Label_Name(value);
}
static inline bool Label_Parse(::absl::string_view name,
Label* value) {
static inline bool Label_Parse(absl::string_view name, Label* value) {
return FieldDescriptorProto_Label_Parse(name, value);
}
@ -3889,35 +3859,24 @@ class PROTOBUF_EXPORT FileOptions final :
// nested types ----------------------------------------------------
typedef FileOptions_OptimizeMode OptimizeMode;
static constexpr OptimizeMode SPEED =
FileOptions_OptimizeMode_SPEED;
static constexpr OptimizeMode CODE_SIZE =
FileOptions_OptimizeMode_CODE_SIZE;
static constexpr OptimizeMode LITE_RUNTIME =
FileOptions_OptimizeMode_LITE_RUNTIME;
using OptimizeMode = FileOptions_OptimizeMode;
static constexpr OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED;
static constexpr OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE;
static constexpr OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME;
static inline bool OptimizeMode_IsValid(int value) {
return FileOptions_OptimizeMode_IsValid(value);
}
static constexpr OptimizeMode OptimizeMode_MIN =
FileOptions_OptimizeMode_OptimizeMode_MIN;
static constexpr OptimizeMode OptimizeMode_MAX =
FileOptions_OptimizeMode_OptimizeMode_MAX;
static constexpr int OptimizeMode_ARRAYSIZE =
FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
OptimizeMode_descriptor() {
static constexpr OptimizeMode OptimizeMode_MIN = FileOptions_OptimizeMode_OptimizeMode_MIN;
static constexpr OptimizeMode OptimizeMode_MAX = FileOptions_OptimizeMode_OptimizeMode_MAX;
static constexpr int OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* OptimizeMode_descriptor() {
return FileOptions_OptimizeMode_descriptor();
}
template<typename T>
static inline const std::string& OptimizeMode_Name(T enum_t_value) {
static_assert(::std::is_same<T, OptimizeMode>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function OptimizeMode_Name.");
return FileOptions_OptimizeMode_Name(enum_t_value);
template <typename T>
static inline const std::string& OptimizeMode_Name(T value) {
return FileOptions_OptimizeMode_Name(value);
}
static inline bool OptimizeMode_Parse(::absl::string_view name,
OptimizeMode* value) {
static inline bool OptimizeMode_Parse(absl::string_view name, OptimizeMode* value) {
return FileOptions_OptimizeMode_Parse(name, value);
}
@ -5043,67 +5002,45 @@ class PROTOBUF_EXPORT FieldOptions final :
// nested types ----------------------------------------------------
typedef FieldOptions_CType CType;
static constexpr CType STRING =
FieldOptions_CType_STRING;
static constexpr CType CORD =
FieldOptions_CType_CORD;
static constexpr CType STRING_PIECE =
FieldOptions_CType_STRING_PIECE;
using CType = FieldOptions_CType;
static constexpr CType STRING = FieldOptions_CType_STRING;
static constexpr CType CORD = FieldOptions_CType_CORD;
static constexpr CType STRING_PIECE = FieldOptions_CType_STRING_PIECE;
static inline bool CType_IsValid(int value) {
return FieldOptions_CType_IsValid(value);
}
static constexpr CType CType_MIN =
FieldOptions_CType_CType_MIN;
static constexpr CType CType_MAX =
FieldOptions_CType_CType_MAX;
static constexpr int CType_ARRAYSIZE =
FieldOptions_CType_CType_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
CType_descriptor() {
static constexpr CType CType_MIN = FieldOptions_CType_CType_MIN;
static constexpr CType CType_MAX = FieldOptions_CType_CType_MAX;
static constexpr int CType_ARRAYSIZE = FieldOptions_CType_CType_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* CType_descriptor() {
return FieldOptions_CType_descriptor();
}
template<typename T>
static inline const std::string& CType_Name(T enum_t_value) {
static_assert(::std::is_same<T, CType>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function CType_Name.");
return FieldOptions_CType_Name(enum_t_value);
template <typename T>
static inline const std::string& CType_Name(T value) {
return FieldOptions_CType_Name(value);
}
static inline bool CType_Parse(::absl::string_view name,
CType* value) {
static inline bool CType_Parse(absl::string_view name, CType* value) {
return FieldOptions_CType_Parse(name, value);
}
typedef FieldOptions_JSType JSType;
static constexpr JSType JS_NORMAL =
FieldOptions_JSType_JS_NORMAL;
static constexpr JSType JS_STRING =
FieldOptions_JSType_JS_STRING;
static constexpr JSType JS_NUMBER =
FieldOptions_JSType_JS_NUMBER;
using JSType = FieldOptions_JSType;
static constexpr JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL;
static constexpr JSType JS_STRING = FieldOptions_JSType_JS_STRING;
static constexpr JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER;
static inline bool JSType_IsValid(int value) {
return FieldOptions_JSType_IsValid(value);
}
static constexpr JSType JSType_MIN =
FieldOptions_JSType_JSType_MIN;
static constexpr JSType JSType_MAX =
FieldOptions_JSType_JSType_MAX;
static constexpr int JSType_ARRAYSIZE =
FieldOptions_JSType_JSType_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
JSType_descriptor() {
static constexpr JSType JSType_MIN = FieldOptions_JSType_JSType_MIN;
static constexpr JSType JSType_MAX = FieldOptions_JSType_JSType_MAX;
static constexpr int JSType_ARRAYSIZE = FieldOptions_JSType_JSType_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* JSType_descriptor() {
return FieldOptions_JSType_descriptor();
}
template<typename T>
static inline const std::string& JSType_Name(T enum_t_value) {
static_assert(::std::is_same<T, JSType>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function JSType_Name.");
return FieldOptions_JSType_Name(enum_t_value);
template <typename T>
static inline const std::string& JSType_Name(T value) {
return FieldOptions_JSType_Name(value);
}
static inline bool JSType_Parse(::absl::string_view name,
JSType* value) {
static inline bool JSType_Parse(absl::string_view name, JSType* value) {
return FieldOptions_JSType_Parse(name, value);
}
@ -7051,35 +6988,24 @@ class PROTOBUF_EXPORT MethodOptions final :
// nested types ----------------------------------------------------
typedef MethodOptions_IdempotencyLevel IdempotencyLevel;
static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN =
MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
static constexpr IdempotencyLevel NO_SIDE_EFFECTS =
MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
static constexpr IdempotencyLevel IDEMPOTENT =
MethodOptions_IdempotencyLevel_IDEMPOTENT;
using IdempotencyLevel = MethodOptions_IdempotencyLevel;
static constexpr IdempotencyLevel IDEMPOTENCY_UNKNOWN = MethodOptions_IdempotencyLevel_IDEMPOTENCY_UNKNOWN;
static constexpr IdempotencyLevel NO_SIDE_EFFECTS = MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS;
static constexpr IdempotencyLevel IDEMPOTENT = MethodOptions_IdempotencyLevel_IDEMPOTENT;
static inline bool IdempotencyLevel_IsValid(int value) {
return MethodOptions_IdempotencyLevel_IsValid(value);
}
static constexpr IdempotencyLevel IdempotencyLevel_MIN =
MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN;
static constexpr IdempotencyLevel IdempotencyLevel_MAX =
MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX;
static constexpr int IdempotencyLevel_ARRAYSIZE =
MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
IdempotencyLevel_descriptor() {
static constexpr IdempotencyLevel IdempotencyLevel_MIN = MethodOptions_IdempotencyLevel_IdempotencyLevel_MIN;
static constexpr IdempotencyLevel IdempotencyLevel_MAX = MethodOptions_IdempotencyLevel_IdempotencyLevel_MAX;
static constexpr int IdempotencyLevel_ARRAYSIZE = MethodOptions_IdempotencyLevel_IdempotencyLevel_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* IdempotencyLevel_descriptor() {
return MethodOptions_IdempotencyLevel_descriptor();
}
template<typename T>
static inline const std::string& IdempotencyLevel_Name(T enum_t_value) {
static_assert(::std::is_same<T, IdempotencyLevel>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function IdempotencyLevel_Name.");
return MethodOptions_IdempotencyLevel_Name(enum_t_value);
template <typename T>
static inline const std::string& IdempotencyLevel_Name(T value) {
return MethodOptions_IdempotencyLevel_Name(value);
}
static inline bool IdempotencyLevel_Parse(::absl::string_view name,
IdempotencyLevel* value) {
static inline bool IdempotencyLevel_Parse(absl::string_view name, IdempotencyLevel* value) {
return MethodOptions_IdempotencyLevel_Parse(name, value);
}
@ -8347,35 +8273,24 @@ class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
// nested types ----------------------------------------------------
typedef GeneratedCodeInfo_Annotation_Semantic Semantic;
static constexpr Semantic NONE =
GeneratedCodeInfo_Annotation_Semantic_NONE;
static constexpr Semantic SET =
GeneratedCodeInfo_Annotation_Semantic_SET;
static constexpr Semantic ALIAS =
GeneratedCodeInfo_Annotation_Semantic_ALIAS;
using Semantic = GeneratedCodeInfo_Annotation_Semantic;
static constexpr Semantic NONE = GeneratedCodeInfo_Annotation_Semantic_NONE;
static constexpr Semantic SET = GeneratedCodeInfo_Annotation_Semantic_SET;
static constexpr Semantic ALIAS = GeneratedCodeInfo_Annotation_Semantic_ALIAS;
static inline bool Semantic_IsValid(int value) {
return GeneratedCodeInfo_Annotation_Semantic_IsValid(value);
}
static constexpr Semantic Semantic_MIN =
GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN;
static constexpr Semantic Semantic_MAX =
GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX;
static constexpr int Semantic_ARRAYSIZE =
GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
Semantic_descriptor() {
static constexpr Semantic Semantic_MIN = GeneratedCodeInfo_Annotation_Semantic_Semantic_MIN;
static constexpr Semantic Semantic_MAX = GeneratedCodeInfo_Annotation_Semantic_Semantic_MAX;
static constexpr int Semantic_ARRAYSIZE = GeneratedCodeInfo_Annotation_Semantic_Semantic_ARRAYSIZE;
static inline const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* Semantic_descriptor() {
return GeneratedCodeInfo_Annotation_Semantic_descriptor();
}
template<typename T>
static inline const std::string& Semantic_Name(T enum_t_value) {
static_assert(::std::is_same<T, Semantic>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Semantic_Name.");
return GeneratedCodeInfo_Annotation_Semantic_Name(enum_t_value);
template <typename T>
static inline const std::string& Semantic_Name(T value) {
return GeneratedCodeInfo_Annotation_Semantic_Name(value);
}
static inline bool Semantic_Parse(::absl::string_view name,
Semantic* value) {
static inline bool Semantic_Parse(absl::string_view name, Semantic* value) {
return GeneratedCodeInfo_Annotation_Semantic_Parse(name, value);
}
@ -14884,39 +14799,46 @@ PROTOBUF_NAMESPACE_CLOSE
PROTOBUF_NAMESPACE_OPEN
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>() {
return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>() {
return ::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>() {
return ::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>() {
return ::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>() {
return ::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>() {
return ::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_descriptor();
}
template <> struct is_proto_enum< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic> : ::std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>() {
struct is_proto_enum<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic> : std::true_type {};
template <>
inline const EnumDescriptor* GetEnumDescriptor<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>() {
return ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_descriptor();
}

@ -559,6 +559,7 @@ TEST_F(FileDescriptorTest, CopyHeadingTo) {
proto.set_name("foo.proto");
proto.set_package("foo.bar.baz");
proto.set_syntax("proto3");
proto.mutable_options()->set_java_package("foo.bar.baz");
// Won't be copied.
proto.add_message_type()->set_name("Foo");
@ -572,6 +573,7 @@ TEST_F(FileDescriptorTest, CopyHeadingTo) {
EXPECT_EQ(other.name(), "foo.proto");
EXPECT_EQ(other.package(), "foo.bar.baz");
EXPECT_EQ(other.syntax(), "proto3");
EXPECT_EQ(other.options().java_package(), "foo.bar.baz");
EXPECT_TRUE(other.message_type().empty());
}
@ -5361,8 +5363,7 @@ TEST_F(ValidationErrorTest, InputTypeNotDefined) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
"foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n"
);
"foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not defined.\n");
}
TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
@ -5375,8 +5376,7 @@ TEST_F(ValidationErrorTest, InputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Bar\" output_type: \"Foo\" }"
"}",
"foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n"
);
"foo.proto: TestService.A: INPUT_TYPE: \"Bar\" is not a message type.\n");
}
TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
@ -5388,8 +5388,7 @@ TEST_F(ValidationErrorTest, OutputTypeNotDefined) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
"foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n"
);
"foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not defined.\n");
}
TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
@ -5402,8 +5401,8 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
" method { name: \"A\" input_type: \"Foo\" output_type: \"Bar\" }"
"}",
"foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n"
);
"foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message "
"type.\n");
}
@ -6035,8 +6034,8 @@ TEST_F(ValidationErrorTest, RollbackAfterError) {
" }"
"}",
"foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not defined.\n"
);
"foo.proto: TestService.Baz: INPUT_TYPE: \"NoSuchType\" is not "
"defined.\n");
// Make sure that if we build the same file again with the error fixed,
// it works. If the above rollback was incomplete, then some symbols will

@ -49,6 +49,7 @@
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/base/casts.h"
#include "absl/strings/cord.h"
#include "absl/strings/match.h"
#include "google/protobuf/test_util.h"
#include "google/protobuf/test_util2.h"

@ -2491,7 +2491,7 @@ int Reflection::MapSize(const Message& message,
// -----------------------------------------------------------------------------
const FieldDescriptor* Reflection::FindKnownExtensionByName(
const std::string& name) const {
absl::string_view name) const {
if (!schema_.HasExtensionSet()) return nullptr;
return descriptor_pool_->FindExtensionByPrintableName(descriptor_, name);
}
@ -3203,6 +3203,7 @@ void Reflection::PopulateTcParseFieldAux(
field_aux++->offset = schema_.SizeofSplit();
break;
case internal::TailCallTableInfo::kSubTable:
case internal::TailCallTableInfo::kSubMessageWeak:
GOOGLE_LOG(FATAL) << "Not supported";
break;
case internal::TailCallTableInfo::kSubMessage:

@ -386,7 +386,7 @@ PROTOBUF_EXPORT const std::string& NameOfDenseEnumSlow(int v,
// very fast. This assumes all the enums fall in the range [min_val .. max_val].
template <const EnumDescriptor* (*descriptor_fn)(), int min_val, int max_val>
const std::string& NameOfDenseEnum(int v) {
static_assert(max_val - min_val >= 0, "Too mamny enums between min and max.");
static_assert(max_val - min_val >= 0, "Too many enums between min and max.");
static DenseEnumCacheInfo deci = {/* atomic ptr */ {}, min_val, max_val,
descriptor_fn};
const std::string** cache = deci.cache.load(std::memory_order_acquire );

@ -56,6 +56,7 @@
#include "google/protobuf/descriptor.h"
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/strings/cord.h"
#include "google/protobuf/map_test_util.h"
#include "google/protobuf/test_util.h"

@ -287,6 +287,9 @@ struct alignas(uint64_t) TcParseTableBase {
const MessageLite* message_default() const {
return static_cast<const MessageLite*>(message_default_p);
}
const MessageLite* message_default_weak() const {
return *static_cast<const MessageLite* const*>(message_default_p);
}
};
const FieldAux* field_aux(uint32_t idx) const {
return reinterpret_cast<const FieldAux*>(reinterpret_cast<uintptr_t>(this) +

@ -179,21 +179,30 @@ bool IsFieldEligibleForFastParsing(
const TailCallTableInfo::FieldEntryInfo& entry,
const TailCallTableInfo::OptionProvider& option_provider) {
const auto* field = entry.field;
// Conditions which exclude a field from being handled by fast parsing
// regardless of options should be considered in IsExcludedFromFastParsing.
if (!IsDescriptorEligibleForFastParsing(field)) return false;
const auto options = option_provider.GetForField(field);
// Weak, lazy, and split fields are not handled on the fast path.
if (options.is_implicitly_weak) return false;
if (options.is_lazy) return false;
if (options.should_split) return false;
// Map, oneof, weak, and lazy fields are not handled on the fast path.
if (field->is_map() || field->real_containing_oneof() ||
field->options().weak() || options.is_implicitly_weak ||
options.is_lazy || options.should_split) {
return false;
}
// We will check for a valid auxiliary index range later. However, we might
// want to change the value we check for inlined string fields.
int aux_idx = entry.aux_idx;
switch (field->type()) {
case FieldDescriptor::TYPE_ENUM:
// If enum values are not validated at parse time, then this field can be
// handled on the fast path like an int32.
if (cpp::HasPreservingUnknownEnumSemantics(field)) {
break;
}
if (field->is_repeated() && field->is_packed()) {
return false;
}
break;
// Some bytes fields can be handled on fast path.
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
@ -226,6 +235,13 @@ bool IsFieldEligibleForFastParsing(
return false;
}
// The largest tag that can be read by the tailcall parser is two bytes
// when varint-coded. This allows 14 bits for the numeric tag value:
// byte 0 byte 1
// 1nnnnttt 0nnnnnnn
// ^^^^^^^ ^^^^^^^
if (field->number() >= 1 << 11) return false;
return true;
}
@ -375,8 +391,7 @@ std::vector<const FieldDescriptor*> FilterMiniParsedFields(
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
// TODO(b/210762816): support remaining field types.
if (field->is_map() || field->options().weak() ||
options.is_implicitly_weak || options.is_lazy) {
if (field->is_map() || field->options().weak() || options.is_lazy) {
handled = false;
} else {
handled = true;
@ -393,9 +408,27 @@ std::vector<const FieldDescriptor*> FilterMiniParsedFields(
return generated_fallback_fields;
}
// We only need field names for reporting UTF-8 parsing errors, so we only
// emit them for string fields with Utf8 transform specified.
absl::string_view FieldNameForTable(
const TailCallTableInfo::FieldEntryInfo& entry) {
const auto* field = entry.field;
if (field->type() == FieldDescriptor::TYPE_STRING) {
const uint16_t xform_val = entry.type_card & field_layout::kTvMask;
switch (xform_val) {
case field_layout::kTvUtf8:
case field_layout::kTvUtf8Debug:
return field->name();
break;
}
}
return "?";
}
std::vector<uint8_t> GenerateFieldNames(
const Descriptor* descriptor,
const std::vector<const FieldDescriptor*>& fields) {
const std::vector<TailCallTableInfo::FieldEntryInfo>& entries) {
static constexpr int kMaxNameLength = 255;
std::vector<uint8_t> out;
// First, we output the size of each string, as an unsigned byte. The first
@ -403,8 +436,8 @@ std::vector<uint8_t> GenerateFieldNames(
int count = 1;
out.push_back(std::min(static_cast<int>(descriptor->full_name().size()),
kMaxNameLength));
for (const auto* field : fields) {
out.push_back(field->name().size());
for (const auto& entry : entries) {
out.push_back(FieldNameForTable(entry).size());
++count;
}
while (count & 7) { // align to an 8-byte boundary
@ -421,8 +454,9 @@ std::vector<uint8_t> GenerateFieldNames(
}
out.insert(out.end(), message_name.begin(), message_name.end());
// Then we output the actual field names
for (const auto* field : fields) {
out.insert(out.end(), field->name().begin(), field->name().end());
for (const auto& entry : entries) {
const auto& field_name = FieldNameForTable(entry);
out.insert(out.end(), field_name.begin(), field_name.end());
}
return out;
@ -611,7 +645,9 @@ uint16_t MakeTypeCardForField(
case FieldDescriptor::TYPE_GROUP:
type_card |= 0 | fl::kMessage | fl::kRepGroup;
if (options.use_direct_tcparser_table) {
if (options.is_implicitly_weak) {
type_card |= fl::kTvWeakPtr;
} else if (options.use_direct_tcparser_table) {
type_card |= fl::kTvTable;
} else {
type_card |= fl::kTvDefault;
@ -624,11 +660,11 @@ uint16_t MakeTypeCardForField(
type_card |= fl::kMessage;
if (options.is_lazy) {
type_card |= fl::kRepLazy;
} else if (options.is_implicitly_weak) {
type_card |= fl::kRepIWeak;
}
if (options.use_direct_tcparser_table) {
if (options.is_implicitly_weak) {
type_card |= fl::kTvWeakPtr;
} else if (options.use_direct_tcparser_table) {
type_card |= fl::kTvTable;
} else {
type_card |= fl::kTvDefault;
@ -698,15 +734,15 @@ TailCallTableInfo::TailCallTableInfo(
} else if (field->options().weak()) {
// Don't generate anything for weak fields. They are handled by the
// generated fallback.
} else if (options.is_implicitly_weak) {
// Implicit weak fields don't need to store a default instance pointer.
} else if (options.is_lazy) {
// Lazy fields are handled by the generated fallback function.
} else {
field_entries.back().aux_idx = aux_entries.size();
aux_entries.push_back(
{options.use_direct_tcparser_table ? kSubTable : kSubMessage,
{field}});
aux_entries.push_back({options.is_implicitly_weak ? kSubMessageWeak
: options.use_direct_tcparser_table
? kSubTable
: kSubMessage,
{field}});
}
} else if (field->type() == FieldDescriptor::TYPE_ENUM &&
!cpp::HasPreservingUnknownEnumSemantics(field)) {
@ -794,7 +830,8 @@ TailCallTableInfo::TailCallTableInfo(
);
num_to_entry_table = MakeNumToEntryTable(ordered_fields);
field_name_data = GenerateFieldNames(descriptor, ordered_fields);
GOOGLE_CHECK_EQ(field_entries.size(), ordered_fields.size());
field_name_data = GenerateFieldNames(descriptor, field_entries);
// If there are no fallback fields, and at most one extension range, the
// parser can use a generic fallback function. Otherwise, a message-specific

@ -102,6 +102,7 @@ struct PROTOBUF_EXPORT TailCallTableInfo {
kSplitSizeof,
kSubMessage,
kSubTable,
kSubMessageWeak,
kEnumRange,
kEnumValidator,
kNumericOffset,
@ -154,49 +155,6 @@ struct PROTOBUF_EXPORT TailCallTableInfo {
bool use_generated_fallback;
};
// A quick check to see if a field can be placed into the fast-table.
// This is meant to be fast but not exhaustive; options that apply to some
// fields may also exclude them.
inline bool IsDescriptorEligibleForFastParsing(const FieldDescriptor* field) {
// Map, oneof, weak, and lazy fields are not handled on the fast path.
if (field->is_map()) return false;
if (field->real_containing_oneof()) return false;
if (field->options().weak()) return false;
switch (field->type()) {
case FieldDescriptor::TYPE_ENUM:
// If enum values are not validated at parse time, then this field can be
// handled on the fast path like an int32.
if (cpp::HasPreservingUnknownEnumSemantics(field)) {
break;
}
if (field->is_repeated() && field->is_packed()) {
return false;
}
break;
// Some bytes fields can be handled on fast path.
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
if (field->options().ctype() != FieldOptions::STRING) {
return false;
}
break;
default:
break;
}
// The largest tag that can be read by the tailcall parser is two bytes
// when varint-coded. This allows 14 bits for the numeric tag value:
// byte 0 byte 1
// 1nnnnttt 0nnnnnnn
// ^^^^^^^ ^^^^^^^
if (field->number() >= 1 << 11) return false;
return true;
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -149,7 +149,6 @@ enum FieldRep : uint16_t {
kRepMessage = 0, // MessageLite*
kRepGroup = 1 << kRepShift, // MessageLite* (WT=3,4)
kRepLazy = 2 << kRepShift, // LazyField*
kRepIWeak = 3 << kRepShift, // ImplicitWeak
};
// Transform/validation (2 bits):
@ -168,8 +167,9 @@ enum TransformValidation : uint16_t {
kTvUtf8 = 2 << kTvShift, // proto3
// Message fields:
kTvDefault = 1 << kTvShift, // Aux has default_instance
kTvDefault = 1 << kTvShift, // Aux has default_instance*
kTvTable = 2 << kTvShift, // Aux has TcParseTableBase*
kTvWeakPtr = 3 << kTvShift, // Aux has default_instance** (for weak)
};
static_assert((kTvEnum & kTvRange) != 0,

@ -256,7 +256,9 @@ absl::string_view TcParser::FieldName(const TcParseTableBase* table,
const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
uint32_t tag;
ptr = ReadTagInlined(ptr, &tag);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
return Error(PROTOBUF_TC_PARAM_PASS);
}
auto* entry = FindFieldEntry(table, tag >> 3);
if (entry == nullptr) {
@ -850,7 +852,7 @@ PROTOBUF_NOINLINE const char* TcParser::SingularVarBigint(
}
const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
return SpecializedFastV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS);
PROTOBUF_MUSTTAIL return SpecializedFastV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS);
}
const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
@ -1284,7 +1286,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
#endif
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
default:
if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) {
if (PROTOBUF_PREDICT_TRUE(::google::protobuf::internal::IsStructurallyValidUTF8(field.Get()))) {
return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
}
ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
@ -1357,7 +1359,7 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
return true;
default:
if (PROTOBUF_PREDICT_TRUE(
IsStructurallyValidUTF8(field[field.size() - 1]))) {
::google::protobuf::internal::IsStructurallyValidUTF8(field[field.size() - 1]))) {
return true;
}
ReportFastUtf8Error(FastDecodeTag(expected_tag), table);
@ -1477,8 +1479,7 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table,
} else if (current_kind == field_layout::kFkMessage) {
switch (current_rep) {
case field_layout::kRepMessage:
case field_layout::kRepGroup:
case field_layout::kRepIWeak: {
case field_layout::kRepGroup: {
auto& field = RefAt<MessageLite*>(msg, current_entry->offset);
if (!msg->GetArenaForAllocation()) {
delete field;
@ -1825,7 +1826,7 @@ bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes,
const TcParseTableBase* table,
const FieldEntry& entry, uint16_t xform_val) {
if (xform_val == field_layout::kTvUtf8) {
if (!IsStructurallyValidUTF8(wire_bytes)) {
if (!::google::protobuf::internal::IsStructurallyValidUTF8(wire_bytes)) {
PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
false);
return false;
@ -1834,7 +1835,7 @@ bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes,
}
#ifndef NDEBUG
if (xform_val == field_layout::kTvUtf8Debug) {
if (!IsStructurallyValidUTF8(wire_bytes)) {
if (!::google::protobuf::internal::IsStructurallyValidUTF8(wire_bytes)) {
PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry), "parsing",
false);
}
@ -2035,8 +2036,14 @@ const char* TcParser::MpMessage(PROTOBUF_TC_PARAM_DECL) {
return ctx->ParseMessage<TcParser>(field, ptr, inner_table);
} else {
if (need_init || field == nullptr) {
field = table->field_aux(&entry)->message_default()->New(
msg->GetArenaForAllocation());
const MessageLite* def;
if ((type_card & field_layout::kTvMask) == field_layout::kTvDefault) {
def = table->field_aux(&entry)->message_default();
} else {
GOOGLE_DCHECK_EQ(type_card & field_layout::kTvMask, +field_layout::kTvWeakPtr);
def = table->field_aux(&entry)->message_default_weak();
}
field = def->New(msg->GetArenaForAllocation());
}
if (is_group) {
return ctx->ParseGroup(field, ptr, decoded_tag);
@ -2076,8 +2083,10 @@ const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) {
}
SyncHasbits(msg, hasbits, table);
auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
const auto aux = *table->field_aux(&entry);
if ((type_card & field_layout::kTvMask) == field_layout::kTvTable) {
auto* inner_table = table->field_aux(&entry)->table;
auto* inner_table = aux.table;
auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
MessageLite* value = field.Add<GenericTypeHandler<MessageLite>>(
inner_table->default_instance);
@ -2086,9 +2095,14 @@ const char* TcParser::MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL) {
}
return ctx->ParseMessage<TcParser>(value, ptr, inner_table);
} else {
auto& field = RefAt<RepeatedPtrFieldBase>(msg, entry.offset);
MessageLite* value = field.Add<GenericTypeHandler<MessageLite>>(
table->field_aux(&entry)->message_default());
const MessageLite* def;
if ((type_card & field_layout::kTvMask) == field_layout::kTvDefault) {
def = aux.message_default();
} else {
GOOGLE_DCHECK_EQ(type_card & field_layout::kTvMask, +field_layout::kTvWeakPtr);
def = aux.message_default_weak();
}
MessageLite* value = field.Add<GenericTypeHandler<MessageLite>>(def);
if (is_group) {
return ctx->ParseGroup(value, ptr, decoded_tag);
}

@ -48,6 +48,7 @@
#include <gtest/gtest.h>
#include "absl/base/casts.h"
#include "google/protobuf/stubs/logging.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"

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

Loading…
Cancel
Save