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

pull/10233/head
theodorerose 2 years ago
commit eac04f8a6e
  1. 2
      conformance/failure_list_cpp.txt
  2. 5
      java/core/src/main/java/com/google/protobuf/Internal.java
  3. 4
      java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java
  4. 4
      java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
  5. 3
      java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java
  6. 3
      java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
  7. 2
      java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
  8. 2
      java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java
  9. 1
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  10. 25
      python/google/protobuf/internal/descriptor_test.py
  11. 4
      src/google/protobuf/arena.cc
  12. 12
      src/google/protobuf/arena_impl.h
  13. 74
      src/google/protobuf/compiler/cpp/enum.cc
  14. 5
      src/google/protobuf/compiler/cpp/helpers.cc
  15. 2
      src/google/protobuf/compiler/cpp/helpers.h
  16. 67
      src/google/protobuf/compiler/cpp/message.cc
  17. 3
      src/google/protobuf/compiler/cpp/options.h
  18. 95
      src/google/protobuf/compiler/cpp/padding_optimizer.cc
  19. 28
      src/google/protobuf/compiler/cpp/parse_function_generator.cc
  20. 8
      src/google/protobuf/compiler/plugin.pb.h
  21. 26
      src/google/protobuf/compiler/subprocess.cc
  22. 107
      src/google/protobuf/descriptor.pb.cc
  23. 157
      src/google/protobuf/descriptor.pb.h
  24. 14
      src/google/protobuf/descriptor.proto
  25. 49
      src/google/protobuf/generated_message_reflection.cc
  26. 30
      src/google/protobuf/generated_message_reflection.h
  27. 6
      src/google/protobuf/generated_message_tctable_impl.h
  28. 8
      src/google/protobuf/generated_message_tctable_lite.cc
  29. 5
      src/google/protobuf/port_def.inc
  30. 1
      src/google/protobuf/port_undef.inc
  31. 8
      src/google/protobuf/struct.pb.h
  32. 24
      src/google/protobuf/type.pb.h
  33. 6
      src/google/protobuf/util/json_format_proto3.proto
  34. 1
      src/google/protobuf/util/json_util.cc
  35. 323
      src/google/protobuf/util/json_util_test.cc

@ -12,8 +12,6 @@ Recommended.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Proto3.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.Proto3.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Proto3.JsonInput.FieldNameDuplicate
Recommended.Proto3.JsonInput.FieldNameDuplicateDifferentCasing1

@ -600,6 +600,7 @@ public final class Internal {
void addInt(int element);
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
@CanIgnoreReturnValue
int setInt(int index, int element);
/** Returns a mutable clone of this list with the specified capacity. */
@ -620,6 +621,7 @@ public final class Internal {
void addBoolean(boolean element);
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
@CanIgnoreReturnValue
boolean setBoolean(int index, boolean element);
/** Returns a mutable clone of this list with the specified capacity. */
@ -640,6 +642,7 @@ public final class Internal {
void addLong(long element);
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
@CanIgnoreReturnValue
long setLong(int index, long element);
/** Returns a mutable clone of this list with the specified capacity. */
@ -660,6 +663,7 @@ public final class Internal {
void addDouble(double element);
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
@CanIgnoreReturnValue
double setDouble(int index, double element);
/** Returns a mutable clone of this list with the specified capacity. */
@ -680,6 +684,7 @@ public final class Internal {
void addFloat(float element);
/** Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. */
@CanIgnoreReturnValue
float setFloat(int index, float element);
/** Returns a mutable clone of this list with the specified capacity. */

@ -277,6 +277,7 @@ public class RepeatedFieldBuilder<
* @param message the message to set
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> setMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -298,6 +299,7 @@ public class RepeatedFieldBuilder<
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addMessage(MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -319,6 +321,7 @@ public class RepeatedFieldBuilder<
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -338,6 +341,7 @@ public class RepeatedFieldBuilder<
* @param values the messages to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {

@ -277,6 +277,7 @@ public class RepeatedFieldBuilderV3<
* @param message the message to set
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -298,6 +299,7 @@ public class RepeatedFieldBuilderV3<
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -319,6 +321,7 @@ public class RepeatedFieldBuilderV3<
* @param message the message to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(int index, MType message) {
checkNotNull(message);
ensureMutableMessageList();
@ -338,6 +341,7 @@ public class RepeatedFieldBuilderV3<
* @param values the messages to add
* @return the builder
*/
@CanIgnoreReturnValue
public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {

@ -156,6 +156,7 @@ public class SingleFieldBuilder<
* @param message the message to set
* @return the builder
*/
@CanIgnoreReturnValue
public SingleFieldBuilder<MType, BType, IType> setMessage(MType message) {
this.message = checkNotNull(message);
if (builder != null) {
@ -172,6 +173,7 @@ public class SingleFieldBuilder<
* @param value the value to merge from
* @return the builder
*/
@CanIgnoreReturnValue
public SingleFieldBuilder<MType, BType, IType> mergeFrom(MType value) {
if (builder == null && message == message.getDefaultInstanceForType()) {
message = value;
@ -188,6 +190,7 @@ public class SingleFieldBuilder<
* @return the builder
*/
@SuppressWarnings("unchecked")
@CanIgnoreReturnValue
public SingleFieldBuilder<MType, BType, IType> clear() {
message =
(MType)

@ -156,6 +156,7 @@ public class SingleFieldBuilderV3<
* @param message the message to set
* @return the builder
*/
@CanIgnoreReturnValue
public SingleFieldBuilderV3<MType, BType, IType> setMessage(MType message) {
this.message = checkNotNull(message);
if (builder != null) {
@ -172,6 +173,7 @@ public class SingleFieldBuilderV3<
* @param value the value to merge from
* @return the builder
*/
@CanIgnoreReturnValue
public SingleFieldBuilderV3<MType, BType, IType> mergeFrom(MType value) {
if (builder == null && message == message.getDefaultInstanceForType()) {
message = value;
@ -188,6 +190,7 @@ public class SingleFieldBuilderV3<
* @return the builder
*/
@SuppressWarnings("unchecked")
@CanIgnoreReturnValue
public SingleFieldBuilderV3<MType, BType, IType> clear() {
message =
(MType)

@ -82,7 +82,7 @@ public class SingleFieldBuilderV3Test {
assertThat(mockParent.getInvalidationCount()).isEqualTo(0);
assertThat(builder.getBuilder().getOptionalInt32()).isEqualTo(1);
assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(1);
builder.build();
TestAllTypes unused = builder.build();
builder.getBuilder().setOptionalInt32(2);
assertThat(builder.getBuilder().getOptionalInt32()).isEqualTo(2);
assertThat(builder.getMessage().getOptionalInt32()).isEqualTo(2);

@ -49,7 +49,7 @@ public class TestBadIdentifiers extends TestCase {
TestBadIdentifiersProto.Override.getDefaultInstance();
}
@SuppressWarnings("IgnoredPureGetter") // TODO(b/221602772): Fix this
@SuppressWarnings({"IgnoredPureGetter", "CheckReturnValue"}) // TODO(b/221602772): Fix this
public void testGetDescriptor() {
TestBadIdentifiersProto.getDescriptor();
TestBadIdentifiersProto.Descriptor.getDefaultInstance().getDescriptor();

@ -823,6 +823,7 @@ public class TextFormatTest {
}
}
@CanIgnoreReturnValue
private TestAllTypes assertParseSuccessWithOverwriteForbidden(String text)
throws TextFormat.ParseException {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();

@ -603,6 +603,12 @@ class GeneratedDescriptorTest(unittest.TestCase):
def CheckDescriptorMapping(self, mapping):
# Verifies that a property like 'messageDescriptor.fields' has all the
# properties of an immutable abc.Mapping.
iterated_keys = []
for key in mapping:
iterated_keys.append(key)
self.assertEqual(len(iterated_keys), len(mapping))
self.assertEqual(set(iterated_keys), set(mapping.keys()))
self.assertNotEqual(
mapping, unittest_pb2.TestAllExtensions.DESCRIPTOR.fields_by_name)
self.assertNotEqual(mapping, {})
@ -619,10 +625,15 @@ class GeneratedDescriptorTest(unittest.TestCase):
with self.assertRaises(TypeError):
mapping.get()
# TODO(jieluo): Fix python and cpp extension diff.
if api_implementation.Type() == 'python':
self.assertRaises(TypeError, mapping.get, [])
else:
if api_implementation.Type() == 'cpp':
self.assertEqual(None, mapping.get([]))
else:
self.assertRaises(TypeError, mapping.get, [])
with self.assertRaises(TypeError):
if [] in mapping:
pass
with self.assertRaises(TypeError):
_ = mapping[[]]
# keys(), iterkeys() &co
item = (next(iter(mapping.keys())), next(iter(mapping.values())))
self.assertEqual(item, next(iter(mapping.items())))
@ -634,10 +645,12 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.assertRaises(KeyError, mapping.__getitem__, 'key_error')
self.assertRaises(KeyError, mapping.__getitem__, len(mapping) + 1)
# TODO(jieluo): Add __repr__ support for DescriptorMapping.
if api_implementation.Type() == 'python':
self.assertEqual(len(str(dict(mapping.items()))), len(str(mapping)))
else:
if api_implementation.Type() == 'cpp':
self.assertEqual(str(mapping)[0], '<')
else:
print(str(dict(mapping.items()))[:100])
print(str(mapping)[:100])
self.assertEqual(len(str(dict(mapping.items()))), len(str(mapping)))
def testDescriptor(self):
message_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR

@ -183,11 +183,11 @@ void SerialArena::AllocateNewBlock(size_t n, const AllocationPolicy* policy) {
ThreadSafeArenaStats::RecordAllocateStats(arena_stats_, /*used=*/used,
/*allocated=*/mem.size, wasted);
set_head(new (mem.ptr) Block{head(), mem.size});
ptr_.store(head()->Pointer(kBlockHeaderSize), std::memory_order_relaxed);
set_ptr(head()->Pointer(kBlockHeaderSize));
limit_ = head()->Pointer(head()->size());
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_);
ASAN_POISON_MEMORY_REGION(ptr(), limit_ - ptr());
#endif // ADDRESS_SANITIZER
}

@ -252,7 +252,7 @@ struct AllocationPolicy {
ArenaMetricsCollector* metrics_collector = nullptr;
bool IsDefault() const {
return start_block_size == kDefaultMaxBlockSize &&
return start_block_size == kDefaultStartBlockSize &&
max_block_size == kDefaultMaxBlockSize && block_alloc == nullptr &&
block_dealloc == nullptr && metrics_collector == nullptr;
}
@ -499,11 +499,11 @@ class PROTOBUF_EXPORT SerialArena {
void (*destructor)(void*)) {
n = AlignUpTo(n, align);
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(ptr_, n);
ASAN_UNPOISON_MEMORY_REGION(ptr(), n);
#endif // ADDRESS_SANITIZER
void* ret = internal::AlignTo(ptr_, align);
ptr_ += n;
GOOGLE_DCHECK_GE(limit_, ptr_);
void* ret = internal::AlignTo(ptr(), align);
set_ptr(ptr() + n);
GOOGLE_DCHECK_GE(limit_, ptr());
AddCleanupFromExisting(ret, destructor);
return ret;
}
@ -517,7 +517,7 @@ class PROTOBUF_EXPORT SerialArena {
ASAN_UNPOISON_MEMORY_REGION(limit_ - n, n);
#endif // ADDRESS_SANITIZER
limit_ -= n;
GOOGLE_DCHECK_GE(limit_, ptr_);
GOOGLE_DCHECK_GE(limit_, ptr());
cleanup::CreateNode(tag, limit_, elem, destructor);
}

@ -37,6 +37,8 @@
#include <cstdint>
#include <limits>
#include <map>
#include <unordered_set>
#include <utility>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
@ -65,13 +67,44 @@ bool ShouldGenerateArraySize(const EnumDescriptor* descriptor) {
// 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::set<int> values;
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) {
const EnumValueDescriptor* min_desc = descriptor->value(0);
const EnumValueDescriptor* max_desc = descriptor->value(0);
for (int i = 1; i < descriptor->value_count(); ++i) {
if (descriptor->value(i)->number() < min_desc->number()) {
min_desc = descriptor->value(i);
}
if (descriptor->value(i)->number() > max_desc->number()) {
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);
}
} // namespace
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
@ -98,9 +131,6 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
format("enum ${1$$classname$$}$ : int {\n", descriptor_);
format.Indent();
const EnumValueDescriptor* min_value = descriptor_->value(0);
const EnumValueDescriptor* max_value = descriptor_->value(0);
for (int i = 0; i < descriptor_->value_count(); i++) {
auto format_value = format;
format_value.Set("name", EnumValueName(descriptor_->value(i)));
@ -114,13 +144,6 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
if (i > 0) format_value(",\n");
format_value("${1$$prefix$$name$$}$ $deprecation$= $number$",
descriptor_->value(i));
if (descriptor_->value(i)->number() < min_value->number()) {
min_value = descriptor_->value(i);
}
if (descriptor_->value(i)->number() > max_value->number()) {
max_value = descriptor_->value(i);
}
}
if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
@ -137,13 +160,15 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
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(min_value), EnumValueName(max_value));
descriptor_, EnumValueName(enum_limits.min),
EnumValueName(enum_limits.max));
if (generate_array_size_) {
format(
@ -172,9 +197,19 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
" ::std::is_integral<T>::value,\n"
" \"Incorrect type passed to function $classname$_Name.\");\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
" return ::$proto_ns$::internal::NameOfEnum(\n"
" $classname$_descriptor(), enum_t_value);\n");
if (ShouldCacheDenseEnum(descriptor_, enum_limits)) {
// 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");
} else {
format(
" return ::$proto_ns$::internal::NameOfEnum(\n"
" $classname$_descriptor(), enum_t_value);\n");
}
} else {
format(
" return $classname$_Name(static_cast<$classname$>(enum_t_value));\n");
@ -182,6 +217,15 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
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"
" ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, $classname$* "

@ -34,6 +34,7 @@
#include <google/protobuf/compiler/cpp/helpers.h>
#include <algorithm>
#include <cstdint>
#include <functional>
#include <limits>
@ -872,6 +873,10 @@ std::string SafeFunctionName(const Descriptor* descriptor,
return function_name;
}
bool IsProfileDriven(const Options& options) {
return options.access_info_map != nullptr;
}
bool IsStringInlined(const FieldDescriptor* descriptor,
const Options& options) {

@ -327,6 +327,8 @@ inline bool IsWeak(const FieldDescriptor* field, const Options& options) {
return false;
}
bool IsProfileDriven(const Options& options);
bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
// For a string field, returns the effective ctype. If the actual ctype is

@ -2722,19 +2722,6 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const {
" static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n"
" reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n";
if (ShouldSplit(descriptor_, options_)) {
format("if (!from.IsSplitMessageDefault()) {\n");
format.Indent();
format("_this->PrepareSplitMessageForWrite();\n");
for (auto field : optimized_order_) {
if (ShouldSplit(field, options_)) {
field_generators_.get(field).GenerateCopyConstructorCode(printer);
}
}
format.Outdent();
format("}\n");
}
for (size_t i = 0; i < optimized_order_.size(); ++i) {
const FieldDescriptor* field = optimized_order_[i];
if (ShouldSplit(field, options_)) {
@ -2763,6 +2750,20 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const {
field_generators_.get(field).GenerateCopyConstructorCode(printer);
}
}
if (ShouldSplit(descriptor_, options_)) {
format("if (!from.IsSplitMessageDefault()) {\n");
format.Indent();
format("_this->PrepareSplitMessageForWrite();\n");
// TODO(b/122856539): cache the split pointers.
for (auto field : optimized_order_) {
if (ShouldSplit(field, options_)) {
field_generators_.get(field).GenerateCopyConstructorCode(printer);
}
}
format.Outdent();
format("}\n");
}
}
void MessageGenerator::GenerateStructors(io::Printer* printer) {
@ -3037,15 +3038,26 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
kColdRatio);
int cached_has_word_index = -1;
for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
bool first_split_chunk_processed = false;
for (size_t chunk_index = 0; chunk_index < chunks.size(); chunk_index++) {
std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index];
cold_skipper.OnStartChunk(chunk_index, cached_has_word_index, "", printer);
const FieldDescriptor* memset_start = nullptr;
const FieldDescriptor* memset_end = nullptr;
bool saw_non_zero_init = false;
bool chunk_is_cold = !chunk.empty() && ShouldSplit(chunk.front(), options_);
bool chunk_is_split =
!chunk.empty() && ShouldSplit(chunk.front(), options_);
// All chunks after the first split chunk should also be split.
GOOGLE_CHECK(!first_split_chunk_processed || chunk_is_split);
if (chunk_is_split && !first_split_chunk_processed) {
// Some fields are cleared without checking has_bit. So we add the
// condition here to avoid writing to the default split instance.
format("if (!IsSplitMessageDefault()) {\n");
format.Indent();
first_split_chunk_processed = true;
}
for (const auto& field : chunk) {
if (CanInitializeByZeroing(field)) {
GOOGLE_CHECK(!saw_non_zero_init);
@ -3085,25 +3097,20 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
format.Indent();
}
if (chunk_is_cold) {
format("if (!IsSplitMessageDefault()) {\n");
format.Indent();
}
if (memset_start) {
if (memset_start == memset_end) {
// For clarity, do not memset a single field.
field_generators_.get(memset_start)
.GenerateMessageClearingCode(printer);
} else {
GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_start, options_));
GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_end, options_));
GOOGLE_CHECK_EQ(chunk_is_split, ShouldSplit(memset_start, options_));
GOOGLE_CHECK_EQ(chunk_is_split, ShouldSplit(memset_end, options_));
format(
"::memset(&$1$, 0, static_cast<size_t>(\n"
" reinterpret_cast<char*>(&$2$) -\n"
" reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n",
FieldMemberName(memset_start, chunk_is_cold),
FieldMemberName(memset_end, chunk_is_cold));
FieldMemberName(memset_start, chunk_is_split),
FieldMemberName(memset_end, chunk_is_split));
}
}
@ -3132,14 +3139,16 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
}
}
if (chunk_is_cold) {
if (have_outer_if) {
format.Outdent();
format("}\n");
}
if (have_outer_if) {
format.Outdent();
format("}\n");
if (chunk_index == chunks.size() - 1) {
if (first_split_chunk_processed) {
format.Outdent();
format("}\n");
}
}
if (cold_skipper.OnEndChunk(chunk_index, printer)) {

@ -40,6 +40,7 @@ namespace google {
namespace protobuf {
namespace compiler {
class AccessInfoMap;
class SplitMap;
namespace cpp {
@ -58,6 +59,7 @@ struct FieldListenerOptions {
// Generator options (see generator.cc for a description of each):
struct Options {
const AccessInfoMap* access_info_map = nullptr;
const SplitMap* split_map = nullptr;
std::string dllexport_decl;
std::string runtime_include_base;
std::string annotation_pragma_name;
@ -83,6 +85,7 @@ struct Options {
bool profile_driven_inline_string = true;
bool message_owned_arena_trial = false;
bool force_split = false;
bool profile_driven_split = false;
#ifdef PROTOBUF_STABLE_EXPERIMENTS
bool force_eagerly_verified_lazy = true;
bool force_inline_string = true;

@ -85,41 +85,11 @@ class FieldGroup {
} // namespace
// Reorder 'fields' so that if the fields are output into a c++ class in the new
// order, fields of similar family (see below) are together and within each
// family, alignment padding is minimized.
//
// We try to do this while keeping each field as close as possible to its field
// number order so that we don't reduce cache locality much for function that
// access each field in order. Originally, OptimizePadding used declaration
// order for its decisions, but generated code minus the serializer/parsers uses
// the output of OptimizePadding as well (stored in
// MessageGenerator::optimized_order_). Since the serializers use field number
// order, we use that as a tie-breaker.
//
// We classify each field into a particular "family" of fields, that we perform
// the same operation on in our generated functions.
//
// REPEATED is placed first, as the C++ compiler automatically initializes
// these fields in layout order.
//
// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
// calls ArenaStringPtr::Destroy on each.
//
// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset
// non-repeated fields otherwise.
//
// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
// delete on each. We initialize these fields with a NULL pointer (see
// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
// memset.
//
// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
//
// OTHER these fields are initialized one-by-one.
void PaddingOptimizer::OptimizeLayout(
std::vector<const FieldDescriptor*>* fields, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
static void OptimizeLayoutHelper(std::vector<const FieldDescriptor*>* fields,
const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
if (fields->empty()) return;
// The sorted numeric order of Family determines the declaration order in the
// memory layout.
enum Family {
@ -222,6 +192,61 @@ void PaddingOptimizer::OptimizeLayout(
}
}
// Reorder 'fields' so that if the fields are output into a c++ class in the new
// order, fields of similar family (see below) are together and within each
// family, alignment padding is minimized.
//
// We try to do this while keeping each field as close as possible to its field
// number order so that we don't reduce cache locality much for function that
// access each field in order. Originally, OptimizePadding used declaration
// order for its decisions, but generated code minus the serializer/parsers uses
// the output of OptimizePadding as well (stored in
// MessageGenerator::optimized_order_). Since the serializers use field number
// order, we use that as a tie-breaker.
//
// We classify each field into a particular "family" of fields, that we perform
// the same operation on in our generated functions.
//
// REPEATED is placed first, as the C++ compiler automatically initializes
// these fields in layout order.
//
// STRING is grouped next, as our Clear/SharedCtor/SharedDtor walks it and
// calls ArenaStringPtr::Destroy on each.
//
// LAZY_MESSAGE is grouped next, as it interferes with the ability to memset
// non-repeated fields otherwise.
//
// MESSAGE is grouped next, as our Clear/SharedDtor code walks it and calls
// delete on each. We initialize these fields with a NULL pointer (see
// MessageFieldGenerator::GenerateConstructorCode), which allows them to be
// memset.
//
// ZERO_INITIALIZABLE is memset in Clear/SharedCtor
//
// OTHER these fields are initialized one-by-one.
//
// If there are split fields in `fields`, they will be placed at the end. The
// order within split fields follows the same rule, aka classify and order by
// "family".
void PaddingOptimizer::OptimizeLayout(
std::vector<const FieldDescriptor*>* fields, const Options& options,
MessageSCCAnalyzer* scc_analyzer) {
std::vector<const FieldDescriptor*> normal;
std::vector<const FieldDescriptor*> split;
for (const auto* field : *fields) {
if (ShouldSplit(field, options)) {
split.push_back(field);
} else {
normal.push_back(field);
}
}
OptimizeLayoutHelper(&normal, options, scc_analyzer);
OptimizeLayoutHelper(&split, options, scc_analyzer);
fields->clear();
fields->insert(fields->end(), normal.begin(), normal.end());
fields->insert(fields->end(), split.begin(), split.end());
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf

@ -37,6 +37,7 @@
#include <google/protobuf/wire_format.h>
#include <google/protobuf/compiler/cpp/helpers.h>
#include <google/protobuf/generated_message_tctable_impl.h>
namespace google {
namespace protobuf {
@ -289,21 +290,32 @@ TailCallTableInfo::TailCallTableInfo(
MessageSCCAnalyzer* scc_analyzer) {
// If this message has any inlined string fields, store the donation state
// offset in the second auxiliary entry.
const auto set_fixed_aux_entry = [&](int index, const std::string& value) {
if (index >= aux_entries.size()) {
aux_entries.resize(index + 1); // pad if necessary
}
aux_entries[index] = value;
};
if (!inlined_string_indices.empty()) {
aux_entries.resize(1); // pad if necessary
aux_entries[0] =
set_fixed_aux_entry(
internal::kInlinedStringAuxIdx,
StrCat("_fl::Offset{offsetof(", ClassName(descriptor),
", _impl_._inlined_string_donated_)}");
", _impl_._inlined_string_donated_)}"));
}
// If this message is split, store the split pointer offset in the third
// auxiliary entry.
if (ShouldSplit(descriptor, options)) {
aux_entries.resize(4); // pad if necessary
aux_entries[2] = StrCat("_fl::Offset{offsetof(",
ClassName(descriptor), ", _impl_._split_)}");
aux_entries[3] = StrCat("_fl::Offset{sizeof(", ClassName(descriptor),
"::Impl_::Split)}");
set_fixed_aux_entry(
internal::kSplitOffsetAuxIdx,
StrCat("_fl::Offset{offsetof(", ClassName(descriptor),
", _impl_._split_)}"));
set_fixed_aux_entry(
internal::kSplitSizeAuxIdx,
StrCat("_fl::Offset{sizeof(", ClassName(descriptor),
"::Impl_::Split)}"));
}
// Fill in mini table entries.

@ -92,8 +92,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
CodeGeneratorResponse_Feature_descriptor(), enum_t_value);
return CodeGeneratorResponse_Feature_Name(static_cast<CodeGeneratorResponse_Feature>(enum_t_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));
}
inline bool CodeGeneratorResponse_Feature_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, CodeGeneratorResponse_Feature* value) {

@ -47,7 +47,6 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/substitute.h>
#include <google/protobuf/message.h>
#include <google/protobuf/io/io_win32.h>
namespace google {
namespace protobuf {
@ -114,7 +113,7 @@ void Subprocess::Start(const std::string& program, SearchMode search_mode) {
}
// Setup STARTUPINFO to redirect handles.
STARTUPINFOW startup_info;
STARTUPINFOA startup_info;
ZeroMemory(&startup_info, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
startup_info.dwFlags = STARTF_USESTDHANDLES;
@ -126,30 +125,17 @@ void Subprocess::Start(const std::string& program, SearchMode search_mode) {
GOOGLE_LOG(FATAL) << "GetStdHandle: " << Win32ErrorMessage(GetLastError());
}
// get wide string version of program as the path may contain non-ascii characters
std::wstring wprogram;
if (!io::win32::strings::utf8_to_wcs(program.c_str(), &wprogram)) {
GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError());
}
// Invoking cmd.exe allows for '.bat' files from the path as well as '.exe'.
std::string command_line = "cmd.exe /c \"" + program + "\"";
// get wide string version of command line as the path may contain non-ascii characters
std::wstring wcommand_line;
if (!io::win32::strings::utf8_to_wcs(command_line.c_str(), &wcommand_line)) {
GOOGLE_LOG(FATAL) << "utf8_to_wcs: " << Win32ErrorMessage(GetLastError());
}
// Using a malloc'ed string because CreateProcess() can mutate its second
// parameter.
wchar_t *wcommand_line_copy = _wcsdup(wcommand_line.c_str());
char* command_line =
portable_strdup(("cmd.exe /c \"" + program + "\"").c_str());
// Create the process.
PROCESS_INFORMATION process_info;
if (CreateProcessW((search_mode == SEARCH_PATH) ? nullptr : wprogram.c_str(),
(search_mode == SEARCH_PATH) ? wcommand_line_copy : NULL,
if (CreateProcessA((search_mode == SEARCH_PATH) ? nullptr : program.c_str(),
(search_mode == SEARCH_PATH) ? command_line : nullptr,
nullptr, // process security attributes
nullptr, // thread security attributes
TRUE, // inherit handles?
@ -169,7 +155,7 @@ void Subprocess::Start(const std::string& program, SearchMode search_mode) {
CloseHandleOrDie(stdin_pipe_read);
CloseHandleOrDie(stdout_pipe_write);
free(wcommand_line_copy);
free(command_line);
}
bool Subprocess::Communicate(const Message& input, Message* output,

@ -483,7 +483,8 @@ PROTOBUF_CONSTEXPR GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(
, /*decltype(_impl_._path_cached_byte_size_)*/{0}
, /*decltype(_impl_.source_file_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
, /*decltype(_impl_.begin_)*/0
, /*decltype(_impl_.end_)*/0} {}
, /*decltype(_impl_.end_)*/0
, /*decltype(_impl_.semantic_)*/0} {}
struct GeneratedCodeInfo_AnnotationDefaultTypeInternal {
PROTOBUF_CONSTEXPR GeneratedCodeInfo_AnnotationDefaultTypeInternal()
: _instance(::_pbi::ConstantInitialized{}) {}
@ -508,7 +509,7 @@ struct GeneratedCodeInfoDefaultTypeInternal {
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GeneratedCodeInfoDefaultTypeInternal _GeneratedCodeInfo_default_instance_;
PROTOBUF_NAMESPACE_CLOSE
static ::_pb::Metadata file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27];
static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
static const ::_pb::EnumDescriptor* file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[7];
static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_google_2fprotobuf_2fdescriptor_2eproto = nullptr;
const uint32_t TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
@ -964,10 +965,12 @@ const uint32_t TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets[] PRO
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.source_file_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.begin_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.end_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation, _impl_.semantic_),
~0u,
0,
1,
2,
3,
~0u, // no _has_bits_
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo, _internal_metadata_),
~0u, // no _extensions_
@ -1004,8 +1007,8 @@ static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protode
{ 391, 406, -1, sizeof(::PROTOBUF_NAMESPACE_ID::UninterpretedOption)},
{ 413, 426, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo_Location)},
{ 431, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::SourceCodeInfo)},
{ 440, 452, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
{ 456, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
{ 440, 453, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation)},
{ 458, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo)},
};
static const ::_pb::Message* const file_default_instances[] = {
@ -1183,19 +1186,22 @@ const char descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto[] PR
"rceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004pat"
"h\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020leading"
"_comments\030\003 \001(\t\022\031\n\021trailing_comments\030\004 \001"
"(\t\022!\n\031leading_detached_comments\030\006 \003(\t\"\247\001"
"(\t\022!\n\031leading_detached_comments\030\006 \003(\t\"\234\002"
"\n\021GeneratedCodeInfo\022A\n\nannotation\030\001 \003(\0132"
"-.google.protobuf.GeneratedCodeInfo.Anno"
"tation\032O\n\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023"
"\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003en"
"d\030\004 \001(\005B~\n\023com.google.protobufB\020Descript"
"orProtosH\001Z-google.golang.org/protobuf/t"
"ypes/descriptorpb\370\001\001\242\002\003GPB\252\002\032Google.Prot"
"obuf.Reflection"
"tation\032\303\001\n\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022"
"\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003e"
"nd\030\004 \001(\005\022H\n\010semantic\030\005 \001(\01626.google.prot"
"obuf.GeneratedCodeInfo.Annotation.Semant"
"ic\"(\n\010Semantic\022\010\n\004NONE\020\000\022\007\n\003SET\020\001\022\t\n\005ALI"
"AS\020\002B~\n\023com.google.protobufB\020DescriptorP"
"rotosH\001Z-google.golang.org/protobuf/type"
"s/descriptorpb\370\001\001\242\002\003GPB\252\002\032Google.Protobu"
"f.Reflection"
;
static ::_pbi::once_flag descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once;
const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2fdescriptor_2eproto = {
false, false, 6095, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
false, false, 6212, descriptor_table_protodef_google_2fprotobuf_2fdescriptor_2eproto,
"google/protobuf/descriptor.proto",
&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once, nullptr, 0, 27,
schemas, file_default_instances, TableStruct_google_2fprotobuf_2fdescriptor_2eproto::offsets,
@ -1377,6 +1383,29 @@ constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MIN;
constexpr MethodOptions_IdempotencyLevel MethodOptions::IdempotencyLevel_MAX;
constexpr int MethodOptions::IdempotencyLevel_ARRAYSIZE;
#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GeneratedCodeInfo_Annotation_Semantic_descriptor() {
::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto);
return file_level_enum_descriptors_google_2fprotobuf_2fdescriptor_2eproto[6];
}
bool GeneratedCodeInfo_Annotation_Semantic_IsValid(int value) {
switch (value) {
case 0:
case 1:
case 2:
return true;
default:
return false;
}
}
#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::NONE;
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::SET;
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::ALIAS;
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MIN;
constexpr GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::Semantic_MAX;
constexpr int GeneratedCodeInfo_Annotation::Semantic_ARRAYSIZE;
#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912))
// ===================================================================
@ -10882,6 +10911,9 @@ class GeneratedCodeInfo_Annotation::_Internal {
static void set_has_end(HasBits* has_bits) {
(*has_bits)[0] |= 4u;
}
static void set_has_semantic(HasBits* has_bits) {
(*has_bits)[0] |= 8u;
}
};
GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(::PROTOBUF_NAMESPACE_ID::Arena* arena,
@ -10900,7 +10932,8 @@ GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeIn
, /*decltype(_impl_._path_cached_byte_size_)*/{0}
, decltype(_impl_.source_file_){}
, decltype(_impl_.begin_){}
, decltype(_impl_.end_){}};
, decltype(_impl_.end_){}
, decltype(_impl_.semantic_){}};
_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
_impl_.source_file_.InitDefault();
@ -10912,8 +10945,8 @@ GeneratedCodeInfo_Annotation::GeneratedCodeInfo_Annotation(const GeneratedCodeIn
_this->GetArenaForAllocation());
}
::memcpy(&_impl_.begin_, &from._impl_.begin_,
static_cast<size_t>(reinterpret_cast<char*>(&_impl_.end_) -
reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
static_cast<size_t>(reinterpret_cast<char*>(&_impl_.semantic_) -
reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.semantic_));
// @@protoc_insertion_point(copy_constructor:google.protobuf.GeneratedCodeInfo.Annotation)
}
@ -10929,6 +10962,7 @@ inline void GeneratedCodeInfo_Annotation::SharedCtor(
, decltype(_impl_.source_file_){}
, decltype(_impl_.begin_){0}
, decltype(_impl_.end_){0}
, decltype(_impl_.semantic_){0}
};
_impl_.source_file_.InitDefault();
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
@ -10966,10 +11000,10 @@ void GeneratedCodeInfo_Annotation::Clear() {
if (cached_has_bits & 0x00000001u) {
_impl_.source_file_.ClearNonDefaultToEmpty();
}
if (cached_has_bits & 0x00000006u) {
if (cached_has_bits & 0x0000000eu) {
::memset(&_impl_.begin_, 0, static_cast<size_t>(
reinterpret_cast<char*>(&_impl_.end_) -
reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.end_));
reinterpret_cast<char*>(&_impl_.semantic_) -
reinterpret_cast<char*>(&_impl_.begin_)) + sizeof(_impl_.semantic_));
}
_impl_._has_bits_.Clear();
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
@ -11023,6 +11057,19 @@ const char* GeneratedCodeInfo_Annotation::_InternalParse(const char* ptr, ::_pbi
} else
goto handle_unusual;
continue;
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
case 5:
if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) {
uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_IsValid(val))) {
_internal_set_semantic(static_cast<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>(val));
} else {
::PROTOBUF_NAMESPACE_ID::internal::WriteVarint(5, val, mutable_unknown_fields());
}
} else
goto handle_unusual;
continue;
default:
goto handle_unusual;
} // switch
@ -11085,6 +11132,13 @@ uint8_t* GeneratedCodeInfo_Annotation::_InternalSerialize(
target = ::_pbi::WireFormatLite::WriteInt32ToArray(4, this->_internal_end(), target);
}
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
if (cached_has_bits & 0x00000008u) {
target = stream->EnsureSpace(target);
target = ::_pbi::WireFormatLite::WriteEnumToArray(
5, this->_internal_semantic(), target);
}
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
_internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
@ -11115,7 +11169,7 @@ size_t GeneratedCodeInfo_Annotation::ByteSizeLong() const {
}
cached_has_bits = _impl_._has_bits_[0];
if (cached_has_bits & 0x00000007u) {
if (cached_has_bits & 0x0000000fu) {
// optional string source_file = 2;
if (cached_has_bits & 0x00000001u) {
total_size += 1 +
@ -11133,6 +11187,12 @@ size_t GeneratedCodeInfo_Annotation::ByteSizeLong() const {
total_size += ::_pbi::WireFormatLite::Int32SizePlusOne(this->_internal_end());
}
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
if (cached_has_bits & 0x00000008u) {
total_size += 1 +
::_pbi::WireFormatLite::EnumSize(this->_internal_semantic());
}
}
return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_);
}
@ -11154,7 +11214,7 @@ void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& t
_this->_impl_.path_.MergeFrom(from._impl_.path_);
cached_has_bits = from._impl_._has_bits_[0];
if (cached_has_bits & 0x00000007u) {
if (cached_has_bits & 0x0000000fu) {
if (cached_has_bits & 0x00000001u) {
_this->_internal_set_source_file(from._internal_source_file());
}
@ -11164,6 +11224,9 @@ void GeneratedCodeInfo_Annotation::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& t
if (cached_has_bits & 0x00000004u) {
_this->_impl_.end_ = from._impl_.end_;
}
if (cached_has_bits & 0x00000008u) {
_this->_impl_.semantic_ = from._impl_.semantic_;
}
_this->_impl_._has_bits_[0] |= cached_has_bits;
}
_this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);
@ -11192,8 +11255,8 @@ void GeneratedCodeInfo_Annotation::InternalSwap(GeneratedCodeInfo_Annotation* ot
&other->_impl_.source_file_, rhs_arena
);
::PROTOBUF_NAMESPACE_ID::internal::memswap<
PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.end_)
+ sizeof(GeneratedCodeInfo_Annotation::_impl_.end_)
PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.semantic_)
+ sizeof(GeneratedCodeInfo_Annotation::_impl_.semantic_)
- PROTOBUF_FIELD_OFFSET(GeneratedCodeInfo_Annotation, _impl_.begin_)>(
reinterpret_cast<char*>(&_impl_.begin_),
reinterpret_cast<char*>(&other->_impl_.begin_));

@ -190,8 +190,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
FieldDescriptorProto_Type_descriptor(), enum_t_value);
return FieldDescriptorProto_Type_Name(static_cast<FieldDescriptorProto_Type>(enum_t_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));
}
inline bool FieldDescriptorProto_Type_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Type* value) {
@ -214,8 +218,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
FieldDescriptorProto_Label_descriptor(), enum_t_value);
return FieldDescriptorProto_Label_Name(static_cast<FieldDescriptorProto_Label>(enum_t_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));
}
inline bool FieldDescriptorProto_Label_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldDescriptorProto_Label* value) {
@ -238,8 +246,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
FileOptions_OptimizeMode_descriptor(), enum_t_value);
return FileOptions_OptimizeMode_Name(static_cast<FileOptions_OptimizeMode>(enum_t_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));
}
inline bool FileOptions_OptimizeMode_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FileOptions_OptimizeMode* value) {
@ -262,8 +274,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
FieldOptions_CType_descriptor(), enum_t_value);
return FieldOptions_CType_Name(static_cast<FieldOptions_CType>(enum_t_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));
}
inline bool FieldOptions_CType_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_CType* value) {
@ -286,8 +302,12 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
FieldOptions_JSType_descriptor(), enum_t_value);
return FieldOptions_JSType_Name(static_cast<FieldOptions_JSType>(enum_t_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));
}
inline bool FieldOptions_JSType_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, FieldOptions_JSType* value) {
@ -310,14 +330,46 @@ 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 ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
MethodOptions_IdempotencyLevel_descriptor(), enum_t_value);
return MethodOptions_IdempotencyLevel_Name(static_cast<MethodOptions_IdempotencyLevel>(enum_t_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));
}
inline bool MethodOptions_IdempotencyLevel_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, MethodOptions_IdempotencyLevel* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<MethodOptions_IdempotencyLevel>(
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
};
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<>
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));
}
inline bool GeneratedCodeInfo_Annotation_Semantic_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, GeneratedCodeInfo_Annotation_Semantic* value) {
return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<GeneratedCodeInfo_Annotation_Semantic>(
GeneratedCodeInfo_Annotation_Semantic_descriptor(), name, value);
}
// ===================================================================
class PROTOBUF_EXPORT FileDescriptorSet final :
@ -8285,6 +8337,38 @@ 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;
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() {
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);
}
static inline bool Semantic_Parse(::PROTOBUF_NAMESPACE_ID::ConstStringParam name,
Semantic* value) {
return GeneratedCodeInfo_Annotation_Semantic_Parse(name, value);
}
// accessors -------------------------------------------------------
enum : int {
@ -8292,6 +8376,7 @@ class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
kSourceFileFieldNumber = 2,
kBeginFieldNumber = 3,
kEndFieldNumber = 4,
kSemanticFieldNumber = 5,
};
// repeated int32 path = 1 [packed = true];
int path_size() const;
@ -8359,6 +8444,19 @@ class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
void _internal_set_end(int32_t value);
public:
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
bool has_semantic() const;
private:
bool _internal_has_semantic() const;
public:
void clear_semantic();
::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic semantic() const;
void set_semantic(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic value);
private:
::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic _internal_semantic() const;
void _internal_set_semantic(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic value);
public:
// @@protoc_insertion_point(class_scope:google.protobuf.GeneratedCodeInfo.Annotation)
private:
class _Internal;
@ -8374,6 +8472,7 @@ class PROTOBUF_EXPORT GeneratedCodeInfo_Annotation final :
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr source_file_;
int32_t begin_;
int32_t end_;
int semantic_;
};
union { Impl_ _impl_; };
friend struct ::TableStruct_google_2fprotobuf_2fdescriptor_2eproto;
@ -14696,6 +14795,35 @@ inline void GeneratedCodeInfo_Annotation::set_end(int32_t value) {
// @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.end)
}
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
inline bool GeneratedCodeInfo_Annotation::_internal_has_semantic() const {
bool value = (_impl_._has_bits_[0] & 0x00000008u) != 0;
return value;
}
inline bool GeneratedCodeInfo_Annotation::has_semantic() const {
return _internal_has_semantic();
}
inline void GeneratedCodeInfo_Annotation::clear_semantic() {
_impl_.semantic_ = 0;
_impl_._has_bits_[0] &= ~0x00000008u;
}
inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::_internal_semantic() const {
return static_cast< ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic >(_impl_.semantic_);
}
inline ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic GeneratedCodeInfo_Annotation::semantic() const {
// @@protoc_insertion_point(field_get:google.protobuf.GeneratedCodeInfo.Annotation.semantic)
return _internal_semantic();
}
inline void GeneratedCodeInfo_Annotation::_internal_set_semantic(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic value) {
assert(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_IsValid(value));
_impl_._has_bits_[0] |= 0x00000008u;
_impl_.semantic_ = value;
}
inline void GeneratedCodeInfo_Annotation::set_semantic(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic value) {
_internal_set_semantic(value);
// @@protoc_insertion_point(field_set:google.protobuf.GeneratedCodeInfo.Annotation.semantic)
}
// -------------------------------------------------------------------
// GeneratedCodeInfo
@ -14832,6 +14960,11 @@ 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>() {
return ::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_descriptor();
}
PROTOBUF_NAMESPACE_CLOSE

@ -916,8 +916,20 @@ message GeneratedCodeInfo {
optional int32 begin = 3;
// Identifies the ending offset in bytes in the generated code that
// relates to the identified offset. The end offset should be one past
// relates to the identified object. The end offset should be one past
// the last relevant byte (so the length of the text = end - begin).
optional int32 end = 4;
// Represents the identified object's effect on the element in the original
// .proto file.
enum Semantic {
// There is no effect or the effect is indescribable.
NONE = 0;
// The element is set or otherwise mutated.
SET = 1;
// An alias to the element is returned.
ALIAS = 2;
}
optional Semantic semantic = 5;
}
}

@ -35,6 +35,8 @@
#include <google/protobuf/generated_message_reflection.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <cstring>
#include <set>
@ -109,6 +111,53 @@ const std::string& NameOfEnum(const EnumDescriptor* descriptor, int value) {
return (d == nullptr ? GetEmptyString() : d->name());
}
// Internal helper routine for NameOfDenseEnum in the header file.
// Allocates and fills a simple array of string pointers, based on
// reflection information about the names of the enums. This routine
// allocates max_val + 1 entries, under the assumption that all the enums
// fall in the range [min_val .. max_val].
const std::string** MakeDenseEnumCache(const EnumDescriptor* desc, int min_val,
int max_val) {
auto* str_ptrs =
new const std::string*[static_cast<size_t>(max_val - min_val + 1)]();
const int count = desc->value_count();
for (int i = 0; i < count; ++i) {
const int num = desc->value(i)->number();
if (str_ptrs[num - min_val] == nullptr) {
// Don't over-write an existing entry, because in case of duplication, the
// first one wins.
str_ptrs[num - min_val] = &desc->value(i)->name();
}
}
// Change any unfilled entries to point to the empty string.
for (int i = 0; i < max_val - min_val + 1; ++i) {
if (str_ptrs[i] == nullptr) str_ptrs[i] = &GetEmptyStringAlreadyInited();
}
return str_ptrs;
}
const std::string& NameOfDenseEnumSlow(int v, DenseEnumCacheInfo* deci) {
if (v < deci->min_val || v > deci->max_val)
return GetEmptyStringAlreadyInited();
const std::string** new_cache =
MakeDenseEnumCache(deci->descriptor_fn(), deci->min_val, deci->max_val);
const std::string** old_cache = nullptr;
if (deci->cache.compare_exchange_strong(old_cache, new_cache,
std::memory_order_release,
std::memory_order_acquire)) {
// We successfully stored our new cache, and the old value was nullptr.
return *new_cache[v - deci->min_val];
} else {
// In the time it took to create our enum cache, another thread also
// created one, and put it into deci->cache. So delete ours, and
// use theirs instead.
delete[] new_cache;
return *old_cache[v - deci->min_val];
}
}
} // namespace internal
// ===================================================================

@ -38,6 +38,8 @@
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
#include <string>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
@ -368,6 +370,34 @@ struct PROTOBUF_EXPORT AddDescriptorsRunner {
explicit AddDescriptorsRunner(const DescriptorTable* table);
};
struct DenseEnumCacheInfo {
std::atomic<const std::string**> cache;
int min_val;
int max_val;
const EnumDescriptor* (*descriptor_fn)();
};
PROTOBUF_EXPORT const std::string& NameOfDenseEnumSlow(int v,
DenseEnumCacheInfo*);
// Similar to the routine NameOfEnum, this routine returns the name of an enum.
// Unlike that routine, it allocates, on-demand, a block of pointers to the
// std::string objects allocated by reflection to store the enum names. This
// way, as long as the enum values are fairly dense, looking them up can be
// 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 DenseEnumCacheInfo deci = {/* atomic ptr */ {}, min_val, max_val,
descriptor_fn};
const std::string** cache = deci.cache.load(std::memory_order_acquire );
if (PROTOBUF_PREDICT_TRUE(cache != nullptr)) {
if (PROTOBUF_PREDICT_TRUE(v >= min_val && v <= max_val)) {
return *cache[v - min_val];
}
}
return NameOfDenseEnumSlow(v, &deci);
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -54,6 +54,12 @@ class UnknownFieldSet;
namespace internal {
enum {
kInlinedStringAuxIdx = 0,
kSplitOffsetAuxIdx = 1,
kSplitSizeAuxIdx = 2,
};
// Field layout enums.
//
// Structural information about fields is packed into a 16-bit value. The enum

@ -1500,16 +1500,12 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table,
}
namespace {
enum {
kSplitOffsetIdx = 2,
kSplitSizeIdx = 3,
};
uint32_t GetSplitOffset(const TcParseTableBase* table) {
return table->field_aux(kSplitOffsetIdx)->offset;
return table->field_aux(kSplitOffsetAuxIdx)->offset;
}
uint32_t GetSizeofSplit(const TcParseTableBase* table) {
return table->field_aux(kSplitSizeIdx)->offset;
return table->field_aux(kSplitSizeAuxIdx)->offset;
}
} // namespace

@ -189,13 +189,10 @@
// Used to remove the manipulation of cleared elements in RepeatedPtrField.
// Owner: mkruskal@
#define PROTOBUF_FUTURE_REMOVE_CLEARED_API 1
<<<<<<< HEAD
=======
// Used to escape C++20 keywords.
// Owner: mkruskal@
#define PROTOBUF_FUTURE_CPP20_KEYWORDS 1
>>>>>>> 87d285c785cd1a4334e3e21e5d468a9bc3e85f62
#else
#define PROTOBUF_FUTURE_FINAL
#endif
@ -837,6 +834,8 @@
#undef CREATE_NEW
#pragma push_macro("DELETE")
#undef DELETE
#pragma push_macro("DOMAIN")
#undef DOMAIN
#pragma push_macro("DOUBLE_CLICK")
#undef DOUBLE_CLICK
#pragma push_macro("ERROR")

@ -119,6 +119,7 @@
#ifdef _WIN32
#pragma pop_macro("CREATE_NEW")
#pragma pop_macro("DELETE")
#pragma pop_macro("DOMAIN")
#pragma pop_macro("DOUBLE_CLICK")
#pragma pop_macro("ERROR")
#pragma pop_macro("ERROR_BUSY")

@ -86,8 +86,12 @@ inline const std::string& NullValue_Name(T enum_t_value) {
static_assert(::std::is_same<T, NullValue>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function NullValue_Name.");
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
NullValue_descriptor(), enum_t_value);
return NullValue_Name(static_cast<NullValue>(enum_t_value));
}
template<>
inline const std::string& NullValue_Name(NullValue value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<NullValue_descriptor, 0, 0>(static_cast<int>(value));
}
inline bool NullValue_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, NullValue* value) {

@ -107,8 +107,12 @@ inline const std::string& Field_Kind_Name(T enum_t_value) {
static_assert(::std::is_same<T, Field_Kind>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Field_Kind_Name.");
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
Field_Kind_descriptor(), enum_t_value);
return Field_Kind_Name(static_cast<Field_Kind>(enum_t_value));
}
template<>
inline const std::string& Field_Kind_Name(Field_Kind value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<Field_Kind_descriptor, 0, 18>(static_cast<int>(value));
}
inline bool Field_Kind_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Kind* value) {
@ -134,8 +138,12 @@ inline const std::string& Field_Cardinality_Name(T enum_t_value) {
static_assert(::std::is_same<T, Field_Cardinality>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Field_Cardinality_Name.");
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
Field_Cardinality_descriptor(), enum_t_value);
return Field_Cardinality_Name(static_cast<Field_Cardinality>(enum_t_value));
}
template<>
inline const std::string& Field_Cardinality_Name(Field_Cardinality value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<Field_Cardinality_descriptor, 0, 3>(static_cast<int>(value));
}
inline bool Field_Cardinality_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Field_Cardinality* value) {
@ -159,8 +167,12 @@ inline const std::string& Syntax_Name(T enum_t_value) {
static_assert(::std::is_same<T, Syntax>::value ||
::std::is_integral<T>::value,
"Incorrect type passed to function Syntax_Name.");
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum(
Syntax_descriptor(), enum_t_value);
return Syntax_Name(static_cast<Syntax>(enum_t_value));
}
template<>
inline const std::string& Syntax_Name(Syntax value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum
<Syntax_descriptor, 0, 1>(static_cast<int>(value));
}
inline bool Syntax_Parse(
::PROTOBUF_NAMESPACE_ID::ConstStringParam name, Syntax* value) {

@ -46,6 +46,7 @@ option java_outer_classname = "JsonFormatProto3";
enum EnumType {
FOO = 0;
BAR = 1;
TLSv1_2 = 2;
}
message MessageType {
@ -179,6 +180,11 @@ message TestBoolValue {
map<bool, int32> bool_map = 2;
}
message TestNullValue {
google.protobuf.NullValue null_value = 20;
repeated google.protobuf.NullValue repeated_null_value = 21;
}
message TestCustomJsonName {
int32 value = 1 [json_name = "@value"];
}

@ -164,6 +164,7 @@ util::Status JsonToBinaryStream(TypeResolver* resolver,
options.case_insensitive_enum_parsing;
converter::ProtoStreamObjectWriter proto_writer(
resolver, type, &sink, &listener, proto_writer_options);
proto_writer.set_use_strict_base64_decoding(false);
converter::JsonStreamParser parser(&proto_writer);
const void* buffer;

@ -37,6 +37,10 @@
#include <string>
#include <vector>
#include <google/protobuf/duration.pb.h>
#include <google/protobuf/field_mask.pb.h>
#include <google/protobuf/struct.pb.h>
#include <google/protobuf/timestamp.pb.h>
#include <google/protobuf/wrappers.pb.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@ -163,14 +167,27 @@ INSTANTIATE_TEST_SUITE_P(JsonTestSuite, JsonTest,
TEST_P(JsonTest, TestWhitespaces) {
TestMessage m;
m.mutable_message_value();
m.set_string_value("foo");
m.add_repeated_bool_value(true);
m.add_repeated_bool_value(false);
EXPECT_THAT(ToJson(m), IsOkAndHolds("{\"messageValue\":{}}"));
EXPECT_THAT(
ToJson(m),
IsOkAndHolds(
R"({"stringValue":"foo","messageValue":{},"repeatedBoolValue":[true,false]})"));
JsonPrintOptions options;
options.add_whitespace = true;
EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\n"
" \"messageValue\": {}\n"
"}\n"));
// Note: whitespace here is significant.
EXPECT_THAT(ToJson(m, options), IsOkAndHolds(R"({
"stringValue": "foo",
"messageValue": {},
"repeatedBoolValue": [
true,
false
]
}
)"));
}
TEST_P(JsonTest, TestDefaultValues) {
@ -202,7 +219,6 @@ TEST_P(JsonTest, TestDefaultValues) {
"\"repeatedMessageValue\":[]"
"}"));
options.always_print_primitive_fields = true;
m.set_string_value("i am a test string value");
m.set_bytes_value("i am a test bytes value");
EXPECT_THAT(
@ -230,33 +246,28 @@ TEST_P(JsonTest, TestDefaultValues) {
"\"repeatedMessageValue\":[]"
"}"));
options.preserve_proto_field_names = true;
m.set_string_value("i am a test string value");
m.set_bytes_value("i am a test bytes value");
EXPECT_THAT(
ToJson(m, options),
IsOkAndHolds("{\"bool_value\":false,"
"\"int32_value\":0,"
"\"int64_value\":\"0\","
"\"uint32_value\":0,"
"\"uint64_value\":\"0\","
"\"float_value\":0,"
"\"double_value\":0,"
"\"string_value\":\"i am a test string value\","
"\"bytes_value\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
"\"enum_value\":\"FOO\","
"\"repeated_bool_value\":[],"
"\"repeated_int32_value\":[],"
"\"repeated_int64_value\":[],"
"\"repeated_uint32_value\":[],"
"\"repeated_uint64_value\":[],"
"\"repeated_float_value\":[],"
"\"repeated_double_value\":[],"
"\"repeated_string_value\":[],"
"\"repeated_bytes_value\":[],"
"\"repeated_enum_value\":[],"
"\"repeated_message_value\":[]"
"}"));
ToJson(protobuf_unittest::TestAllTypes(), options),
IsOkAndHolds(
R"({"optionalInt32":0,"optionalInt64":"0","optionalUint32":0,)"
R"("optionalUint64":"0","optionalSint32":0,"optionalSint64":"0","optionalFixed32":0,)"
R"("optionalFixed64":"0","optionalSfixed32":0,"optionalSfixed64":"0",)"
R"("optionalFloat":0,"optionalDouble":0,"optionalBool":false,"optionalString":"",)"
R"("optionalBytes":"","optionalgroup":null,"optionalNestedEnum":"FOO","optionalForeignEnum":"FOREIGN_FOO",)"
R"("optionalImportEnum":"IMPORT_FOO","optionalStringPiece":"","optionalCord":"",)"
R"("repeatedInt32":[],"repeatedInt64":[],"repeatedUint32":[],"repeatedUint64":[],)"
R"("repeatedSint32":[],"repeatedSint64":[],"repeatedFixed32":[],"repeatedFixed64":[],)"
R"("repeatedSfixed32":[],"repeatedSfixed64":[],"repeatedFloat":[],"repeatedDouble":[],)"
R"("repeatedBool":[],"repeatedString":[],"repeatedBytes":[],"repeatedgroup":[],)"
R"("repeatedNestedMessage":[],"repeatedForeignMessage":[],"repeatedImportMessage":[],)"
R"("repeatedNestedEnum":[],"repeatedForeignEnum":[],"repeatedImportEnum":[],)"
R"("repeatedStringPiece":[],"repeatedCord":[],"repeatedLazyMessage":[],"defaultInt32":41,)"
R"("defaultInt64":"42","defaultUint32":43,"defaultUint64":"44","defaultSint32":-45,)"
R"("defaultSint64":"46","defaultFixed32":47,"defaultFixed64":"48","defaultSfixed32":49,)"
R"("defaultSfixed64":"-50","defaultFloat":51.5,"defaultDouble":52000,"defaultBool":true,)"
R"("defaultString":"hello","defaultBytes":"d29ybGQ=","defaultNestedEnum":"BAR",)"
R"("defaultForeignEnum":"FOREIGN_BAR","defaultImportEnum":"IMPORT_BAR",)"
R"("defaultStringPiece":"abc","defaultCord":"123"})"));
}
TEST_P(JsonTest, TestPreserveProtoFieldNames) {
@ -270,6 +281,7 @@ TEST_P(JsonTest, TestPreserveProtoFieldNames) {
JsonPrintOptions options;
options.preserve_proto_field_names = true;
EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\"message_value\":{}}"));
}
TEST_P(JsonTest, TestAlwaysPrintEnumsAsInts) {
@ -316,7 +328,7 @@ TEST_P(JsonTest, TestPrintEnumsAsIntsWithDefaultValue) {
EXPECT_EQ(parsed->enum_value3(), proto3::BAR);
}
TEST_P(JsonTest, DISABLED_TestPrintProto2EnumAsIntWithDefaultValue) {
TEST_P(JsonTest, TestPrintProto2EnumAsIntWithDefaultValue) {
protobuf_unittest::TestDefaultEnumValue orig;
JsonPrintOptions print_options;
@ -332,6 +344,15 @@ TEST_P(JsonTest, DISABLED_TestPrintProto2EnumAsIntWithDefaultValue) {
EXPECT_EQ(parsed->enum_value(), protobuf_unittest::DEFAULT);
}
TEST_P(JsonTest, WebSafeBytes) {
auto m = ToProto<TestMessage>(R"json({
"bytesValue": "-_"
})json");
ASSERT_OK(m);
EXPECT_EQ(m->bytes_value(), "\xfb");
}
TEST_P(JsonTest, ParseMessage) {
auto m = ToProto<TestMessage>(R"json(
{
@ -341,7 +362,7 @@ TEST_P(JsonTest, ParseMessage) {
"uint32Value": 42,
"uint64Value": 530242871653669,
"floatValue": 3.4e+38,
"doubleValue": -55.5,
"doubleValue": -55.3,
"stringValue": "foo bar baz",
"enumValue": "BAR",
"messageValue": {
@ -368,7 +389,11 @@ TEST_P(JsonTest, ParseMessage) {
EXPECT_EQ(m->uint32_value(), 42);
EXPECT_EQ(m->uint64_value(), 530242871653669);
EXPECT_EQ(m->float_value(), 3.4e+38f);
EXPECT_EQ(m->double_value(), -55.5);
EXPECT_EQ(m->double_value(),
-55.3); // This value is intentionally not a nice
// round number in base 2, so its floating point
// representation has many digits at the end, which
// printing back to JSON must handle well.
EXPECT_EQ(m->string_value(), "foo bar baz");
EXPECT_EQ(m->enum_value(), proto3::EnumType::BAR);
EXPECT_EQ(m->message_value().value(), 2048);
@ -406,13 +431,63 @@ TEST_P(JsonTest, ParseMessage) {
IsOkAndHolds(
R"({"boolValue":true,"int32Value":1234567891,"int64Value":"-5302428716536692736",)"
R"("uint32Value":42,"uint64Value":"530242871653669","floatValue":3.4e+38,)"
R"("doubleValue":-55.5,"stringValue":"foo bar baz","enumValue":"BAR",)"
R"("doubleValue":-55.3,"stringValue":"foo bar baz","enumValue":"BAR",)"
R"("messageValue":{"value":2048},"repeatedBoolValue":[true],"repeatedInt32Value":[0,-42])"
R"(,"repeatedUint64Value":["1","2"],"repeatedDoubleValue":[1.5,-2],)"
R"("repeatedStringValue":["foo","bar ",""],"repeatedEnumValue":["BAR","FOO"],)"
R"("repeatedMessageValue":[{"value":40},{"value":96}]})"));
}
TEST_P(JsonTest, CurseOfAtob) {
auto m = ToProto<TestMessage>(R"json(
{
repeatedBoolValue: ["0", "1", "false", "true", "f", "t", "no", "yes", "n", "y"]
}
)json");
ASSERT_OK(m);
EXPECT_EQ(m->repeated_bool_value_size(), 10);
EXPECT_FALSE(m->repeated_bool_value(0));
EXPECT_FALSE(m->repeated_bool_value(2));
EXPECT_FALSE(m->repeated_bool_value(4));
EXPECT_FALSE(m->repeated_bool_value(6));
EXPECT_FALSE(m->repeated_bool_value(8));
EXPECT_TRUE(m->repeated_bool_value(1));
EXPECT_TRUE(m->repeated_bool_value(3));
EXPECT_TRUE(m->repeated_bool_value(5));
EXPECT_TRUE(m->repeated_bool_value(7));
EXPECT_TRUE(m->repeated_bool_value(9));
}
TEST_P(JsonTest, ParseLegacySingleRepeatedField) {
auto m = ToProto<TestMessage>(R"json({
"repeatedInt32Value": 1997,
"repeatedStringValue": "oh no",
"repeatedEnumValue": "BAR",
"repeatedMessageValue": {"value": -1}
})json");
ASSERT_OK(m);
ASSERT_EQ(m->repeated_int32_value_size(), 1);
EXPECT_EQ(m->repeated_int32_value(0), 1997);
ASSERT_EQ(m->repeated_string_value_size(), 1);
EXPECT_EQ(m->repeated_string_value(0), "oh no");
ASSERT_EQ(m->repeated_enum_value_size(), 1);
EXPECT_EQ(m->repeated_enum_value(0), proto3::EnumType::BAR);
ASSERT_EQ(m->repeated_message_value_size(), 1);
EXPECT_EQ(m->repeated_message_value(0).value(), -1);
EXPECT_THAT(ToJson(*m),
IsOkAndHolds(R"({"repeatedInt32Value":[1997],)"
R"("repeatedStringValue":["oh no"],)"
R"("repeatedEnumValue":["BAR"],)"
R"("repeatedMessageValue":[{"value":-1}]})"));
}
TEST_P(JsonTest, ParseMap) {
TestMap message;
(*message.mutable_string_map())["hello"] = 1234;
@ -451,6 +526,15 @@ TEST_P(JsonTest, PrintPrimitiveOneof) {
IsOkAndHolds(R"({"oneofInt32Value":1})"));
}
TEST_P(JsonTest, ParseOverOneof) {
TestOneof m;
m.set_oneof_string_value("foo");
ASSERT_OK(ToProto(m, R"json({
"oneofInt32Value": 5,
})json"));
EXPECT_EQ(m.oneof_int32_value(), 5);
}
TEST_P(JsonTest, TestParseIgnoreUnknownFields) {
JsonParseOptions options;
options.ignore_unknown_fields = true;
@ -626,6 +710,19 @@ TEST_P(JsonTest, ParseWrappers) {
ToJson(*m),
IsOkAndHolds(
R"({"boolValue":true,"int32Value":42,"stringValue":"ieieo"})"));
auto m2 = ToProto<TestWrapper>(R"json(
{
"boolValue": { "value": true },
"int32Value": { "value": 42 },
"stringValue": { "value": "ieieo" },
}
)json");
ASSERT_OK(m2);
EXPECT_TRUE(m2->bool_value().value());
EXPECT_EQ(m2->int32_value().value(), 42);
EXPECT_EQ(m2->string_value().value(), "ieieo");
}
TEST_P(JsonTest, TestParsingUnknownAnyFields) {
@ -728,6 +825,15 @@ TEST_P(JsonTest, TestParsingEnumCaseSensitive) {
EXPECT_EQ(m.enum_value(), proto3::FOO);
}
TEST_P(JsonTest, TestParsingEnumLowercase) {
JsonParseOptions options;
options.case_insensitive_enum_parsing = true;
auto m = ToProto<TestMessage>(R"json({"enum_value": "TLSv1_2"})json", options);
ASSERT_OK(m);
EXPECT_THAT(m->enum_value(), proto3::TLSv1_2);
}
TEST_P(JsonTest, TestParsingEnumIgnoreCase) {
TestMessage m;
m.set_enum_value(proto3::FOO);
@ -738,6 +844,153 @@ TEST_P(JsonTest, TestParsingEnumIgnoreCase) {
EXPECT_EQ(m.enum_value(), proto3::BAR);
}
// Parsing does NOT work like MergeFrom: existing repeated field values are
// clobbered, not appended to.
TEST_P(JsonTest, TestOverwriteRepeated) {
TestMessage m;
m.add_repeated_int32_value(5);
ASSERT_OK(ToProto(m, R"json({"repeated_int32_value": [1, 2, 3]})json"));
EXPECT_EQ(m.repeated_int32_value_size(), 3);
EXPECT_EQ(m.repeated_int32_value(0), 1);
EXPECT_EQ(m.repeated_int32_value(1), 2);
EXPECT_EQ(m.repeated_int32_value(2), 3);
}
TEST_P(JsonTest, TestDuration) {
auto m = ToProto<proto3::TestDuration>(R"json(
{
"value": "123456.789s",
"repeated_value": ["0.1s", "999s"]
}
)json");
ASSERT_OK(m);
EXPECT_EQ(m->value().seconds(), 123456);
EXPECT_EQ(m->value().nanos(), 789000000);
EXPECT_EQ(m->repeated_value().size(), 2);
EXPECT_EQ(m->repeated_value(0).seconds(), 0);
EXPECT_EQ(m->repeated_value(0).nanos(), 100000000);
EXPECT_EQ(m->repeated_value(1).seconds(), 999);
EXPECT_EQ(m->repeated_value(1).nanos(), 0);
EXPECT_THAT(
ToJson(*m),
IsOkAndHolds(
R"({"value":"123456.789s","repeatedValue":["0.100s","999s"]})"));
auto m2 = ToProto<proto3::TestDuration>(R"json(
{
"value": {"seconds": 4, "nanos": 5},
}
)json");
ASSERT_OK(m2);
EXPECT_EQ(m2->value().seconds(), 4);
EXPECT_EQ(m2->value().nanos(), 5);
}
// These tests are not exhaustive; tests in //third_party/protobuf/conformance
// are more comprehensive.
TEST_P(JsonTest, TestTimestamp) {
auto m = ToProto<proto3::TestTimestamp>(R"json(
{
"value": "1996-02-27T12:00:00Z",
"repeated_value": ["9999-12-31T23:59:59Z"]
}
)json");
ASSERT_OK(m);
EXPECT_EQ(m->value().seconds(), 825422400);
EXPECT_EQ(m->value().nanos(), 0);
EXPECT_EQ(m->repeated_value().size(), 1);
EXPECT_EQ(m->repeated_value(0).seconds(), 253402300799);
EXPECT_EQ(m->repeated_value(0).nanos(), 0);
EXPECT_THAT(
ToJson(*m),
IsOkAndHolds(
R"({"value":"1996-02-27T12:00:00Z","repeatedValue":["9999-12-31T23:59:59Z"]})"));
auto m2 = ToProto<proto3::TestTimestamp>(R"json(
{
"value": {"seconds": 4, "nanos": 5},
}
)json");
ASSERT_OK(m2);
EXPECT_EQ(m2->value().seconds(), 4);
EXPECT_EQ(m2->value().nanos(), 5);
}
// This test case comes from Envoy's tests. They like to parse a Value out of
// YAML, turn it into JSON, and then parse it as a different proto. This means
// we must be extremely careful with integer fields, because they need to
// round-trip through doubles. This happens all over Envoy. :(
TEST_P(JsonTest, TestEnvoyRoundTrip) {
auto m = ToProto<google::protobuf::Value>(R"json(
{
"value": {"seconds": 1234567891, "nanos": 234000000},
}
)json");
ASSERT_OK(m);
auto j = ToJson(*m);
ASSERT_OK(j);
auto m2 = ToProto<proto3::TestTimestamp>(*j);
ASSERT_OK(m2);
EXPECT_EQ(m2->value().seconds(), 1234567891);
EXPECT_EQ(m2->value().nanos(), 234000000);
}
TEST_P(JsonTest, TestFieldMask) {
auto m = ToProto<proto3::TestFieldMask>(R"json(
{
"value": "foo,bar.bazBaz"
}
)json");
ASSERT_OK(m);
EXPECT_EQ(m->value().paths_size(), 2);
EXPECT_EQ(m->value().paths(0), "foo");
EXPECT_EQ(m->value().paths(1), "bar.baz_baz");
EXPECT_THAT(ToJson(*m), IsOkAndHolds(R"({"value":"foo,bar.bazBaz"})"));
auto m2 = ToProto<proto3::TestFieldMask>(R"json(
{
"value": {
"paths": ["yep.really"]
},
}
)json");
ASSERT_OK(m2);
EXPECT_EQ(m2->value().paths_size(), 1);
EXPECT_EQ(m2->value().paths(0), "yep.really");
}
TEST_P(JsonTest, TestLegalNullsInArray) {
auto m = ToProto<proto3::TestNullValue>(R"json({
"repeatedNullValue": [null]
})json");
ASSERT_OK(m);
EXPECT_EQ(m->repeated_null_value_size(), 1);
EXPECT_EQ(m->repeated_null_value(0), google::protobuf::NULL_VALUE);
auto m2 = ToProto<proto3::TestValue>(R"json({
"repeatedValue": [null]
})json");
ASSERT_OK(m2);
EXPECT_EQ(m2->repeated_value_size(), 1);
EXPECT_TRUE(m2->repeated_value(0).has_null_value());
}
TEST_P(JsonTest, DISABLED_HtmlEscape) {
TestMessage m;
m.set_string_value("</script>");

Loading…
Cancel
Save