Skip to content

Commit 6ecb5d0

Browse files
anandoleecopybara-github
authored andcommitted
Added Reflection::GetCord() method in C++
PiperOrigin-RevId: 519246549
1 parent 477e35f commit 6ecb5d0

File tree

12 files changed

+392
-52
lines changed

12 files changed

+392
-52
lines changed

java/core/src/test/java/com/google/protobuf/TestUtil.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2653,6 +2653,9 @@ public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
26532653
case FOO_LAZY_MESSAGE:
26542654
Assert.assertTrue(message.hasFooLazyMessage());
26552655
break;
2656+
case FOO_BYTES_CORD:
2657+
Assert.assertTrue(message.hasFooBytesCord());
2658+
break;
26562659
case FOO_NOT_SET:
26572660
break;
26582661
// TODO(b/18683919): go/enum-switch-lsc

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ void SingularString::GenerateAccessorDeclarations(io::Printer* p) const {
206206
// reflection interface since the reflection interface is independent of
207207
// the string's underlying representation.
208208
bool unknown_ctype =
209-
field_->options().ctype() != EffectiveStringCType(field_, options_);
209+
field_->options().ctype() != internal::cpp::EffectiveStringCType(field_);
210210

211211
if (unknown_ctype) {
212212
p->Emit(R"cc(
@@ -759,7 +759,7 @@ class RepeatedString : public FieldGeneratorBase {
759759

760760
void RepeatedString::GenerateAccessorDeclarations(io::Printer* p) const {
761761
bool unknown_ctype =
762-
field_->options().ctype() != EffectiveStringCType(field_, options_);
762+
field_->options().ctype() != internal::cpp::EffectiveStringCType(field_);
763763

764764
if (unknown_ctype) {
765765
p->Emit(R"cc(

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

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,8 @@ bool HasRepeatedFields(const FileDescriptor* file) {
978978
static bool IsStringPieceField(const FieldDescriptor* field,
979979
const Options& options) {
980980
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
981-
EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
981+
internal::cpp::EffectiveStringCType(field) ==
982+
FieldOptions::STRING_PIECE;
982983
}
983984

984985
static bool HasStringPieceFields(const Descriptor* descriptor,
@@ -1001,7 +1002,7 @@ bool HasStringPieceFields(const FileDescriptor* file, const Options& options) {
10011002

10021003
static bool IsCordField(const FieldDescriptor* field, const Options& options) {
10031004
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
1004-
EffectiveStringCType(field, options) == FieldOptions::CORD;
1005+
internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD;
10051006
}
10061007

10071008
static bool HasCordFields(const Descriptor* descriptor,
@@ -1118,23 +1119,6 @@ bool IsStringOrMessage(const FieldDescriptor* field) {
11181119
return false;
11191120
}
11201121

1121-
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
1122-
const Options& options) {
1123-
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
1124-
if (options.opensource_runtime) {
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-
}
1131-
return FieldOptions::STRING;
1132-
} else {
1133-
// Google-internal supports all ctypes.
1134-
return field->options().ctype();
1135-
}
1136-
}
1137-
11381122
bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
11391123
return descriptor->name() == kAnyProtoFile;
11401124
}

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,25 +346,21 @@ bool IsProfileDriven(const Options& options);
346346

347347
bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options);
348348

349-
// For a string field, returns the effective ctype. If the actual ctype is
350-
// not supported, returns the default of STRING.
351-
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
352-
const Options& options);
353-
354349
inline bool IsCord(const FieldDescriptor* field, const Options& options) {
355350
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
356-
EffectiveStringCType(field, options) == FieldOptions::CORD;
351+
internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD;
357352
}
358353

359354
inline bool IsString(const FieldDescriptor* field, const Options& options) {
360355
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
361-
EffectiveStringCType(field, options) == FieldOptions::STRING;
356+
internal::cpp::EffectiveStringCType(field) == FieldOptions::STRING;
362357
}
363358

364359
inline bool IsStringPiece(const FieldDescriptor* field,
365360
const Options& options) {
366361
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
367-
EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
362+
internal::cpp::EffectiveStringCType(field) ==
363+
FieldOptions::STRING_PIECE;
368364
}
369365

370366
// Does the given FileDescriptor use lazy fields?

src/google/protobuf/compiler/cpp/unittest.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,9 @@ class OneofTest : public testing::Test {
14521452
case UNITTEST::TestOneof2::kFooLazyMessage:
14531453
EXPECT_TRUE(message.has_foo_lazy_message());
14541454
break;
1455+
case UNITTEST::TestOneof2::kFooBytesCord:
1456+
EXPECT_TRUE(message.has_foo_bytes_cord());
1457+
break;
14551458
case UNITTEST::TestOneof2::FOO_NOT_SET:
14561459
break;
14571460
}

src/google/protobuf/descriptor.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,6 +2645,21 @@ PROTOBUF_EXPORT bool HasPreservingUnknownEnumSemantics(
26452645

26462646
PROTOBUF_EXPORT bool HasHasbit(const FieldDescriptor* field);
26472647

2648+
// For a string field, returns the effective ctype. If the actual ctype is
2649+
// not supported, returns the default of STRING.
2650+
template <typename FD = FieldDescriptor, typename FO = FieldOptions>
2651+
typename FO::CType EffectiveStringCType(const FD* field) {
2652+
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
2653+
ABSL_DCHECK(!field->is_extension());
2654+
// Open-source protobuf release only supports STRING ctype and CORD for
2655+
// sinuglar bytes.
2656+
if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated() &&
2657+
field->options().ctype() == FO::CORD) {
2658+
return FO::CORD;
2659+
}
2660+
return FO::STRING;
2661+
}
2662+
26482663
#ifndef SWIG
26492664
enum class Utf8CheckMode {
26502665
kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields.

src/google/protobuf/generated_message_reflection.cc

Lines changed: 113 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,20 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
403403
break;
404404
405405
case FieldDescriptor::CPPTYPE_STRING: {
406-
switch (field->options().ctype()) {
407-
default: // TODO(kenton): Support other string reps.
406+
switch (internal::cpp::EffectiveStringCType(field)) {
407+
case FieldOptions::CORD:
408+
if (schema_.InRealOneof(field)) {
409+
total_size += GetField<absl::Cord*>(message, field)
410+
->EstimatedMemoryUsage();
411+
412+
} else {
413+
// sizeof(absl::Cord) is included to self.
414+
total_size += GetField<absl::Cord>(message, field)
415+
.EstimatedMemoryUsage() -
416+
sizeof(absl::Cord);
417+
}
418+
break;
419+
default:
408420
case FieldOptions::STRING:
409421
if (IsInlined(field)) {
410422
const std::string* ptr =
@@ -501,7 +513,10 @@ struct OneofFieldMover {
501513
to->SetString(from->GetString());
502514
break;
503515
}
504-
switch (field->options().ctype()) {
516+
switch (internal::cpp::EffectiveStringCType(field)) {
517+
case FieldOptions::CORD:
518+
to->SetCord(from->GetCord());
519+
break;
505520
default:
506521
case FieldOptions::STRING: {
507522
to->SetArenaStringPtr(from->GetArenaStringPtr());
@@ -635,7 +650,12 @@ template <bool unsafe_shallow_swap>
635650
void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
636651
Message* rhs,
637652
const FieldDescriptor* field) {
638-
switch (field->options().ctype()) {
653+
switch (internal::cpp::EffectiveStringCType(field)) {
654+
case FieldOptions::CORD:
655+
// Always shallow swap for Cord.
656+
std::swap(*r->MutableRaw<absl::Cord>(lhs, field),
657+
*r->MutableRaw<absl::Cord>(rhs, field));
658+
break;
639659
default:
640660
case FieldOptions::STRING: {
641661
if (r->IsInlined(field)) {
@@ -891,6 +911,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
891911
LOCAL_VAR_ACCESSOR(int, enum, Enum);
892912
LOCAL_VAR_ACCESSOR(Message*, message, Message);
893913
LOCAL_VAR_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
914+
LOCAL_VAR_ACCESSOR(absl::Cord*, cord, Cord);
894915
const std::string& GetString() const { return string_val; }
895916
void SetString(const std::string& v) { string_val = v; }
896917
Message* UnsafeGetMessage() const { return GetMessage(); }
@@ -908,6 +929,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
908929
int type_enum;
909930
Message* type_message;
910931
internal::ArenaStringPtr type_arena_string_ptr;
932+
absl::Cord* type_cord;
911933
} oneof_val;
912934
913935
// std::string cannot be in union.
@@ -931,6 +953,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
931953
MESSAGE_FIELD_ACCESSOR(bool, bool, Bool);
932954
MESSAGE_FIELD_ACCESSOR(int, enum, Enum);
933955
MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
956+
MESSAGE_FIELD_ACCESSOR(absl::Cord*, cord, Cord);
934957
std::string GetString() const {
935958
return reflection->GetString(*message, field);
936959
}
@@ -1321,8 +1344,16 @@ void Reflection::ClearField(Message* message,
13211344
break;
13221345
13231346
case FieldDescriptor::CPPTYPE_STRING: {
1324-
switch (field->options().ctype()) {
1325-
default: // TODO(kenton): Support other string reps.
1347+
switch (internal::cpp::EffectiveStringCType(field)) {
1348+
case FieldOptions::CORD:
1349+
if (field->has_default_value()) {
1350+
*MutableRaw<absl::Cord>(message, field) =
1351+
field->default_value_string();
1352+
} else {
1353+
MutableRaw<absl::Cord>(message, field)->Clear();
1354+
}
1355+
break;
1356+
default:
13261357
case FieldOptions::STRING:
13271358
if (IsInlined(field)) {
13281359
// Currently, string with default value can't be inlined. So we
@@ -1718,8 +1749,14 @@ std::string Reflection::GetString(const Message& message,
17181749
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
17191750
return field->default_value_string();
17201751
}
1721-
switch (field->options().ctype()) {
1722-
default: // TODO(kenton): Support other string reps.
1752+
switch (internal::cpp::EffectiveStringCType(field)) {
1753+
case FieldOptions::CORD:
1754+
if (schema_.InRealOneof(field)) {
1755+
return std::string(*GetField<absl::Cord*>(message, field));
1756+
} else {
1757+
return std::string(GetField<absl::Cord>(message, field));
1758+
}
1759+
default:
17231760
case FieldOptions::STRING:
17241761
if (IsInlined(field)) {
17251762
return GetField<InlinedStringField>(message, field).GetNoArena();
@@ -1743,8 +1780,16 @@ const std::string& Reflection::GetStringReference(const Message& message,
17431780
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
17441781
return field->default_value_string();
17451782
}
1746-
switch (field->options().ctype()) {
1747-
default: // TODO(kenton): Support other string reps.
1783+
switch (internal::cpp::EffectiveStringCType(field)) {
1784+
case FieldOptions::CORD:
1785+
if (schema_.InRealOneof(field)) {
1786+
absl::CopyCordToString(*GetField<absl::Cord*>(message, field),
1787+
scratch);
1788+
} else {
1789+
absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch);
1790+
}
1791+
return *scratch;
1792+
default:
17481793
case FieldOptions::STRING:
17491794
if (IsInlined(field)) {
17501795
return GetField<InlinedStringField>(message, field).GetNoArena();
@@ -1756,6 +1801,39 @@ const std::string& Reflection::GetStringReference(const Message& message,
17561801
}
17571802
}
17581803

1804+
absl::Cord Reflection::GetCord(const Message& message,
1805+
const FieldDescriptor* field) const {
1806+
USAGE_CHECK_ALL(GetCord, SINGULAR, STRING);
1807+
if (field->is_extension()) {
1808+
return absl::Cord(GetExtensionSet(message).GetString(
1809+
field->number(), field->default_value_string()));
1810+
} else {
1811+
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
1812+
return absl::Cord(field->default_value_string());
1813+
}
1814+
switch (internal::cpp::EffectiveStringCType(field)) {
1815+
case FieldOptions::CORD:
1816+
if (schema_.InRealOneof(field)) {
1817+
return *GetField<absl::Cord*>(message, field);
1818+
} else {
1819+
return GetField<absl::Cord>(message, field);
1820+
}
1821+
default:
1822+
case FieldOptions::STRING:
1823+
if (IsInlined(field)) {
1824+
return absl::Cord(
1825+
GetField<InlinedStringField>(message, field).GetNoArena());
1826+
} else {
1827+
const auto& str = GetField<ArenaStringPtr>(message, field);
1828+
return absl::Cord(str.IsDefault() ? field->default_value_string()
1829+
: str.Get());
1830+
}
1831+
}
1832+
1833+
ABSL_LOG(FATAL) << "Can't get here.";
1834+
return absl::Cord(); // Make compiler happy.
1835+
}
1836+
}
17591837

17601838

17611839
void Reflection::SetString(Message* message, const FieldDescriptor* field,
@@ -1765,8 +1843,20 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
17651843
return MutableExtensionSet(message)->SetString(
17661844
field->number(), field->type(), std::move(value), field);
17671845
} else {
1768-
switch (field->options().ctype()) {
1769-
default: // TODO(kenton): Support other string reps.
1846+
switch (internal::cpp::EffectiveStringCType(field)) {
1847+
case FieldOptions::CORD:
1848+
if (schema_.InRealOneof(field)) {
1849+
if (!HasOneofField(*message, field)) {
1850+
ClearOneof(message, field->containing_oneof());
1851+
*MutableField<absl::Cord*>(message, field) =
1852+
Arena::Create<absl::Cord>(message->GetArenaForAllocation());
1853+
}
1854+
*(*MutableField<absl::Cord*>(message, field)) = value;
1855+
break;
1856+
}
1857+
*MutableField<absl::Cord>(message, field) = value;
1858+
break;
1859+
default:
17701860
case FieldOptions::STRING: {
17711861
if (IsInlined(field)) {
17721862
const uint32_t index = schema_.InlinedStringIndex(field);
@@ -1805,7 +1895,7 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
18051895
MutableExtensionSet(message)->MutableString(
18061896
field->number(), field->type(), field));
18071897
} else {
1808-
switch (field->options().ctype()) {
1898+
switch (internal::cpp::EffectiveStringCType(field)) {
18091899
case FieldOptions::CORD:
18101900
if (schema_.InRealOneof(field)) {
18111901
if (!HasOneofField(*message, field)) {
@@ -2721,8 +2811,11 @@ bool Reflection::HasBit(const Message& message,
27212811
// (which uses HasField()) needs to be consistent with this.
27222812
switch (field->cpp_type()) {
27232813
case FieldDescriptor::CPPTYPE_STRING:
2724-
switch (field->options().ctype()) {
2725-
default: {
2814+
switch (internal::cpp::EffectiveStringCType(field)) {
2815+
case FieldOptions::CORD:
2816+
return !GetField<const absl::Cord>(message, field).empty();
2817+
default:
2818+
case FieldOptions::STRING: {
27262819
if (IsInlined(field)) {
27272820
return !GetField<InlinedStringField>(message, field)
27282821
.GetNoArena()
@@ -2833,8 +2926,11 @@ void Reflection::ClearOneof(Message* message,
28332926
if (message->GetArenaForAllocation() == nullptr) {
28342927
switch (field->cpp_type()) {
28352928
case FieldDescriptor::CPPTYPE_STRING: {
2836-
switch (field->options().ctype()) {
2837-
default: // TODO(kenton): Support other string reps.
2929+
switch (internal::cpp::EffectiveStringCType(field)) {
2930+
case FieldOptions::CORD:
2931+
delete *MutableRaw<absl::Cord*>(message, field);
2932+
break;
2933+
default:
28382934
case FieldOptions::STRING: {
28392935
// Oneof string fields are never set as a default instance.
28402936
// We just need to pass some arbitrary default string to make it

0 commit comments

Comments
 (0)