Skip to content

Commit 714f975

Browse files
anandoleecopybara-github
authored andcommitted
Support C++ protobuf ctype=CORD for bytes field (generated code).
Reflection::SetString() can take CORD as input. PiperOrigin-RevId: 518313997
1 parent 4b5652b commit 714f975

File tree

14 files changed

+156
-18
lines changed

14 files changed

+156
-18
lines changed

src/google/protobuf/compiler/cpp/field.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,16 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
180180
case FieldDescriptor::CPPTYPE_MESSAGE:
181181
return MakeSinguarMessageGenerator(field, options, scc);
182182
case FieldDescriptor::CPPTYPE_STRING:
183-
return MakeSinguarStringGenerator(field, options, scc);
183+
if (field->type() == FieldDescriptor::TYPE_BYTES &&
184+
field->options().ctype() == FieldOptions::CORD) {
185+
if (field->real_containing_oneof()) {
186+
return MakeOneofCordGenerator(field, options, scc);
187+
} else {
188+
return MakeSingularCordGenerator(field, options, scc);
189+
}
190+
} else {
191+
return MakeSinguarStringGenerator(field, options, scc);
192+
}
184193
case FieldDescriptor::CPPTYPE_ENUM:
185194
return MakeSinguarEnumGenerator(field, options, scc);
186195
default:

src/google/protobuf/compiler/cpp/field_generators/cord_field.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ void CordFieldGenerator::GenerateAccessorDeclarations(
146146
"$deprecated_attr$void ${1$set_$name$$}$(const ::absl::Cord& value);\n"
147147
"$deprecated_attr$void ${1$set_$name$$}$(::absl::string_view value);\n",
148148
std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
149-
format("private:\n");
150149
format(
150+
"private:\n"
151+
"const ::absl::Cord& ${1$_internal_$name$$}$() const;\n"
151152
"void ${1$_internal_set_$name$$}$(const ::absl::Cord& value);\n"
152153
"::absl::Cord* ${1$_internal_mutable_$name$$}$();\n"
153154
"public:\n",
@@ -183,13 +184,17 @@ void CordFieldGenerator::GenerateInlineAccessorDefinitions(
183184
" $field$ = value;\n"
184185
"$annotate_set$"
185186
" // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
187+
"}\n"
188+
"inline ::absl::Cord* $classname$::_internal_mutable_$name$() {\n"
189+
" $set_hasbit$\n"
190+
" return &$field$;\n"
186191
"}\n");
187192
}
188193

189194
void CordFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
190195
Formatter format(printer, variables_);
191196
if (descriptor_->default_value_string().empty()) {
192-
format("$field$.clear();\n");
197+
format("$field$.Clear();\n");
193198
} else {
194199
format("$field$ = ::absl::string_view($default$, $default_length$);\n");
195200
}
@@ -358,12 +363,6 @@ void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
358363
" }\n"
359364
" }\n"
360365
" return $field$;\n"
361-
"}\n"
362-
"inline ::absl::Cord* $classname$::mutable_$name$() {\n"
363-
" ::absl::Cord* _cord = _internal_mutable_$name$();\n"
364-
"$annotate_mutable$"
365-
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
366-
" return _cord;\n"
367366
"}\n");
368367
}
369368

src/google/protobuf/compiler/cpp/field_generators/generators.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ std::unique_ptr<FieldGeneratorBase> MakeOneofMessageGenerator(
9090
std::unique_ptr<FieldGeneratorBase> MakeMapGenerator(
9191
const FieldDescriptor* desc, const Options& options,
9292
MessageSCCAnalyzer* scc);
93+
94+
std::unique_ptr<FieldGeneratorBase> MakeSingularCordGenerator(
95+
const FieldDescriptor* desc, const Options& options,
96+
MessageSCCAnalyzer* scc);
97+
98+
std::unique_ptr<FieldGeneratorBase> MakeOneofCordGenerator(
99+
const FieldDescriptor* desc, const Options& options,
100+
MessageSCCAnalyzer* scc);
101+
93102
} // namespace cpp
94103
} // namespace compiler
95104
} // namespace protobuf

src/google/protobuf/compiler/cpp/file.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* p) {
492492

493493
if (HasCordFields(file_, options_)) {
494494
p->Emit(R"(
495-
#include "third_party/absl/strings/internal/string_constant.h"
495+
#include "absl/strings/internal/string_constant.h"
496496
)");
497497
}
498498

@@ -1322,11 +1322,11 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* p) {
13221322
if (HasStringPieceFields(file_, options_)) {
13231323
IncludeFile("third_party/protobuf/string_piece_field_support.h", p);
13241324
}
1325-
if (HasCordFields(file_, options_)) {
1326-
p->Emit(R"(
1327-
#include "third_party/absl/strings/cord.h"
1325+
}
1326+
if (HasCordFields(file_, options_)) {
1327+
p->Emit(R"(
1328+
#include "absl/strings/cord.h"
13281329
)");
1329-
}
13301330
}
13311331
if (HasMapFields(file_)) {
13321332
IncludeFileAndExport("third_party/protobuf/map.h", p);

src/google/protobuf/compiler/cpp/helpers.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,12 @@ FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
11221122
const Options& options) {
11231123
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
11241124
if (options.opensource_runtime) {
1125-
// Open-source protobuf release only supports STRING ctype.
1125+
// Open-source protobuf release only supports STRING ctype and CORD for
1126+
// sinuglar bytes.
1127+
if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated() &&
1128+
field->options().ctype() == FieldOptions::CORD) {
1129+
return FieldOptions::CORD;
1130+
}
11261131
return FieldOptions::STRING;
11271132
} else {
11281133
// Google-internal supports all ctypes.

src/google/protobuf/compiler/cpp/parse_function_generator.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -951,10 +951,17 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format,
951951
const FieldDescriptor* field,
952952
bool check_utf8) {
953953
FieldOptions::CType ctype = FieldOptions::STRING;
954-
if (!options_.opensource_runtime) {
955-
// Open source doesn't support other ctypes;
956-
ctype = field->options().ctype();
954+
955+
if (!field->is_repeated() && field->type() == FieldDescriptor::TYPE_BYTES &&
956+
field->options().ctype() == FieldOptions::CORD) {
957+
ctype = FieldOptions::CORD;
958+
} else {
959+
if (!options_.opensource_runtime) {
960+
// Open source doesn't support other ctypes;
961+
ctype = field->options().ctype();
962+
}
957963
}
964+
958965
if (!field->is_repeated() && !options_.opensource_runtime &&
959966
GetOptimizeFor(field->file(), options_) != FileOptions::LITE_RUNTIME &&
960967
// For now only use arena string for strings with empty defaults.

src/google/protobuf/generated_message_reflection.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,56 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
17971797
}
17981798
}
17991799

1800+
void Reflection::SetString(Message* message, const FieldDescriptor* field,
1801+
const absl::Cord& value) const {
1802+
USAGE_CHECK_ALL(SetString, SINGULAR, STRING);
1803+
if (field->is_extension()) {
1804+
return absl::CopyCordToString(value,
1805+
MutableExtensionSet(message)->MutableString(
1806+
field->number(), field->type(), field));
1807+
} else {
1808+
switch (field->options().ctype()) {
1809+
case FieldOptions::CORD:
1810+
if (schema_.InRealOneof(field)) {
1811+
if (!HasOneofField(*message, field)) {
1812+
ClearOneof(message, field->containing_oneof());
1813+
*MutableField<absl::Cord*>(message, field) =
1814+
Arena::Create<absl::Cord>(message->GetArenaForAllocation());
1815+
}
1816+
*(*MutableField<absl::Cord*>(message, field)) = value;
1817+
} else {
1818+
*MutableField<absl::Cord>(message, field) = value;
1819+
}
1820+
break;
1821+
default:
1822+
case FieldOptions::STRING: {
1823+
// Oneof string fields are never set as a default instance.
1824+
// We just need to pass some arbitrary default string to make it work.
1825+
// This allows us to not have the real default accessible from
1826+
// reflection.
1827+
if (schema_.InRealOneof(field) && !HasOneofField(*message, field)) {
1828+
ClearOneof(message, field->containing_oneof());
1829+
MutableField<ArenaStringPtr>(message, field)->InitDefault();
1830+
}
1831+
if (IsInlined(field)) {
1832+
auto* str = MutableField<InlinedStringField>(message, field);
1833+
const uint32_t index = schema_.InlinedStringIndex(field);
1834+
ABSL_DCHECK_GT(index, 0);
1835+
uint32_t* states =
1836+
&MutableInlinedStringDonatedArray(message)[index / 32];
1837+
uint32_t mask = ~(static_cast<uint32_t>(1) << (index % 32));
1838+
str->Set(std::string(value), message->GetArenaForAllocation(),
1839+
IsInlinedStringDonated(*message, field), states, mask,
1840+
message);
1841+
} else {
1842+
auto* str = MutableField<ArenaStringPtr>(message, field);
1843+
str->Set(std::string(value), message->GetArenaForAllocation());
1844+
}
1845+
break;
1846+
}
1847+
}
1848+
}
1849+
}
18001850

18011851
std::string Reflection::GetRepeatedString(const Message& message,
18021852
const FieldDescriptor* field,

src/google/protobuf/generated_message_util.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT
6969
fixed_address_empty_string{}; // NOLINT
7070

7171

72+
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT const EmptyCord empty_cord_;
73+
7274
PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
7375
static bool InitProtobufDefaultsImpl() {
7476
fixed_address_empty_string.DefaultConstruct();

src/google/protobuf/generated_message_util.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ PROTOBUF_EXPORT inline const std::string& GetEmptyString() {
9797
return GetEmptyStringAlreadyInited();
9898
}
9999

100+
// Default empty Cord object. Don't use directly. Instead, call
101+
// GetEmptyCordAlreadyInited() to get the reference.
102+
union EmptyCord {
103+
constexpr EmptyCord() : value() {}
104+
~EmptyCord() {}
105+
::absl::Cord value;
106+
};
107+
PROTOBUF_EXPORT extern const EmptyCord empty_cord_;
108+
109+
constexpr const ::absl::Cord& GetEmptyCordAlreadyInited() {
110+
return empty_cord_.value;
111+
}
100112

101113
// True if IsInitialized() is true for all elements of t. Type is expected
102114
// to be a RepeatedPtrField<some message type>. It's useful to have this

src/google/protobuf/message.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,11 @@ class PROTOBUF_EXPORT Reflection final {
651651
bool value) const;
652652
void SetString(Message* message, const FieldDescriptor* field,
653653
std::string value) const;
654+
// Set a string field to a Cord value. If the underlying field is
655+
// represented using a Cord already, this involves no copies (just
656+
// reference counting). Otherwise, a copy must be made.
657+
void SetString(Message* message, const FieldDescriptor* field,
658+
const absl::Cord& value) const;
654659
void SetEnum(Message* message, const FieldDescriptor* field,
655660
const EnumValueDescriptor* value) const;
656661
// Set an enum field's value with an integer rather than EnumValueDescriptor.

0 commit comments

Comments
 (0)