Skip to content

Commit

Permalink
Added Reflection::GetCord() method in C++
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 519246549
  • Loading branch information
anandolee authored and copybara-github committed Mar 24, 2023
1 parent 477e35f commit 6ecb5d0
Show file tree
Hide file tree
Showing 12 changed files with 392 additions and 52 deletions.
3 changes: 3 additions & 0 deletions java/core/src/test/java/com/google/protobuf/TestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,9 @@ public static void assertAtMostOneFieldSetOneof(TestOneof2 message) {
case FOO_LAZY_MESSAGE:
Assert.assertTrue(message.hasFooLazyMessage());
break;
case FOO_BYTES_CORD:
Assert.assertTrue(message.hasFooBytesCord());
break;
case FOO_NOT_SET:
break;
// TODO(b/18683919): go/enum-switch-lsc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ void SingularString::GenerateAccessorDeclarations(io::Printer* p) const {
// reflection interface since the reflection interface is independent of
// the string's underlying representation.
bool unknown_ctype =
field_->options().ctype() != EffectiveStringCType(field_, options_);
field_->options().ctype() != internal::cpp::EffectiveStringCType(field_);

if (unknown_ctype) {
p->Emit(R"cc(
Expand Down Expand Up @@ -759,7 +759,7 @@ class RepeatedString : public FieldGeneratorBase {

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

if (unknown_ctype) {
p->Emit(R"cc(
Expand Down
22 changes: 3 additions & 19 deletions src/google/protobuf/compiler/cpp/helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,8 @@ bool HasRepeatedFields(const FileDescriptor* file) {
static bool IsStringPieceField(const FieldDescriptor* field,
const Options& options) {
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
internal::cpp::EffectiveStringCType(field) ==
FieldOptions::STRING_PIECE;
}

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

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

static bool HasCordFields(const Descriptor* descriptor,
Expand Down Expand Up @@ -1118,23 +1119,6 @@ bool IsStringOrMessage(const FieldDescriptor* field) {
return false;
}

FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
const Options& options) {
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
if (options.opensource_runtime) {
// Open-source protobuf release only supports STRING ctype and CORD for
// sinuglar bytes.
if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated() &&
field->options().ctype() == FieldOptions::CORD) {
return FieldOptions::CORD;
}
return FieldOptions::STRING;
} else {
// Google-internal supports all ctypes.
return field->options().ctype();
}
}

bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
return descriptor->name() == kAnyProtoFile;
}
Expand Down
12 changes: 4 additions & 8 deletions src/google/protobuf/compiler/cpp/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,25 +346,21 @@ 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
// not supported, returns the default of STRING.
FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
const Options& options);

inline bool IsCord(const FieldDescriptor* field, const Options& options) {
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
EffectiveStringCType(field, options) == FieldOptions::CORD;
internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD;
}

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

inline bool IsStringPiece(const FieldDescriptor* field,
const Options& options) {
return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE;
internal::cpp::EffectiveStringCType(field) ==
FieldOptions::STRING_PIECE;
}

// Does the given FileDescriptor use lazy fields?
Expand Down
3 changes: 3 additions & 0 deletions src/google/protobuf/compiler/cpp/unittest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,9 @@ class OneofTest : public testing::Test {
case UNITTEST::TestOneof2::kFooLazyMessage:
EXPECT_TRUE(message.has_foo_lazy_message());
break;
case UNITTEST::TestOneof2::kFooBytesCord:
EXPECT_TRUE(message.has_foo_bytes_cord());
break;
case UNITTEST::TestOneof2::FOO_NOT_SET:
break;
}
Expand Down
15 changes: 15 additions & 0 deletions src/google/protobuf/descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,21 @@ PROTOBUF_EXPORT bool HasPreservingUnknownEnumSemantics(

PROTOBUF_EXPORT bool HasHasbit(const FieldDescriptor* field);

// For a string field, returns the effective ctype. If the actual ctype is
// not supported, returns the default of STRING.
template <typename FD = FieldDescriptor, typename FO = FieldOptions>
typename FO::CType EffectiveStringCType(const FD* field) {
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
ABSL_DCHECK(!field->is_extension());
// Open-source protobuf release only supports STRING ctype and CORD for
// sinuglar bytes.
if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated() &&
field->options().ctype() == FO::CORD) {
return FO::CORD;
}
return FO::STRING;
}

#ifndef SWIG
enum class Utf8CheckMode {
kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields.
Expand Down
130 changes: 113 additions & 17 deletions src/google/protobuf/generated_message_reflection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,20 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
break;
case FieldDescriptor::CPPTYPE_STRING: {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
total_size += GetField<absl::Cord*>(message, field)
->EstimatedMemoryUsage();
} else {
// sizeof(absl::Cord) is included to self.
total_size += GetField<absl::Cord>(message, field)
.EstimatedMemoryUsage() -
sizeof(absl::Cord);
}
break;
default:
case FieldOptions::STRING:
if (IsInlined(field)) {
const std::string* ptr =
Expand Down Expand Up @@ -501,7 +513,10 @@ struct OneofFieldMover {
to->SetString(from->GetString());
break;
}
switch (field->options().ctype()) {
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
to->SetCord(from->GetCord());
break;
default:
case FieldOptions::STRING: {
to->SetArenaStringPtr(from->GetArenaStringPtr());
Expand Down Expand Up @@ -635,7 +650,12 @@ template <bool unsafe_shallow_swap>
void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
Message* rhs,
const FieldDescriptor* field) {
switch (field->options().ctype()) {
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
// Always shallow swap for Cord.
std::swap(*r->MutableRaw<absl::Cord>(lhs, field),
*r->MutableRaw<absl::Cord>(rhs, field));
break;
default:
case FieldOptions::STRING: {
if (r->IsInlined(field)) {
Expand Down Expand Up @@ -891,6 +911,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
LOCAL_VAR_ACCESSOR(int, enum, Enum);
LOCAL_VAR_ACCESSOR(Message*, message, Message);
LOCAL_VAR_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
LOCAL_VAR_ACCESSOR(absl::Cord*, cord, Cord);
const std::string& GetString() const { return string_val; }
void SetString(const std::string& v) { string_val = v; }
Message* UnsafeGetMessage() const { return GetMessage(); }
Expand All @@ -908,6 +929,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
int type_enum;
Message* type_message;
internal::ArenaStringPtr type_arena_string_ptr;
absl::Cord* type_cord;
} oneof_val;
// std::string cannot be in union.
Expand All @@ -931,6 +953,7 @@ void Reflection::SwapOneofField(Message* lhs, Message* rhs,
MESSAGE_FIELD_ACCESSOR(bool, bool, Bool);
MESSAGE_FIELD_ACCESSOR(int, enum, Enum);
MESSAGE_FIELD_ACCESSOR(ArenaStringPtr, arena_string_ptr, ArenaStringPtr);
MESSAGE_FIELD_ACCESSOR(absl::Cord*, cord, Cord);
std::string GetString() const {
return reflection->GetString(*message, field);
}
Expand Down Expand Up @@ -1321,8 +1344,16 @@ void Reflection::ClearField(Message* message,
break;
case FieldDescriptor::CPPTYPE_STRING: {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (field->has_default_value()) {
*MutableRaw<absl::Cord>(message, field) =
field->default_value_string();
} else {
MutableRaw<absl::Cord>(message, field)->Clear();
}
break;
default:
case FieldOptions::STRING:
if (IsInlined(field)) {
// Currently, string with default value can't be inlined. So we
Expand Down Expand Up @@ -1718,8 +1749,14 @@ std::string Reflection::GetString(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return field->default_value_string();
}
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
return std::string(*GetField<absl::Cord*>(message, field));
} else {
return std::string(GetField<absl::Cord>(message, field));
}
default:
case FieldOptions::STRING:
if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena();
Expand All @@ -1743,8 +1780,16 @@ const std::string& Reflection::GetStringReference(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return field->default_value_string();
}
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
absl::CopyCordToString(*GetField<absl::Cord*>(message, field),
scratch);
} else {
absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch);
}
return *scratch;
default:
case FieldOptions::STRING:
if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena();
Expand All @@ -1756,6 +1801,39 @@ const std::string& Reflection::GetStringReference(const Message& message,
}
}

absl::Cord Reflection::GetCord(const Message& message,
const FieldDescriptor* field) const {
USAGE_CHECK_ALL(GetCord, SINGULAR, STRING);
if (field->is_extension()) {
return absl::Cord(GetExtensionSet(message).GetString(
field->number(), field->default_value_string()));
} else {
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return absl::Cord(field->default_value_string());
}
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
return *GetField<absl::Cord*>(message, field);
} else {
return GetField<absl::Cord>(message, field);
}
default:
case FieldOptions::STRING:
if (IsInlined(field)) {
return absl::Cord(
GetField<InlinedStringField>(message, field).GetNoArena());
} else {
const auto& str = GetField<ArenaStringPtr>(message, field);
return absl::Cord(str.IsDefault() ? field->default_value_string()
: str.Get());
}
}

ABSL_LOG(FATAL) << "Can't get here.";
return absl::Cord(); // Make compiler happy.
}
}


void Reflection::SetString(Message* message, const FieldDescriptor* field,
Expand All @@ -1765,8 +1843,20 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
return MutableExtensionSet(message)->SetString(
field->number(), field->type(), std::move(value), field);
} else {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof());
*MutableField<absl::Cord*>(message, field) =
Arena::Create<absl::Cord>(message->GetArenaForAllocation());
}
*(*MutableField<absl::Cord*>(message, field)) = value;
break;
}
*MutableField<absl::Cord>(message, field) = value;
break;
default:
case FieldOptions::STRING: {
if (IsInlined(field)) {
const uint32_t index = schema_.InlinedStringIndex(field);
Expand Down Expand Up @@ -1805,7 +1895,7 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
MutableExtensionSet(message)->MutableString(
field->number(), field->type(), field));
} else {
switch (field->options().ctype()) {
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) {
Expand Down Expand Up @@ -2721,8 +2811,11 @@ bool Reflection::HasBit(const Message& message,
// (which uses HasField()) needs to be consistent with this.
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: {
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
return !GetField<const absl::Cord>(message, field).empty();
default:
case FieldOptions::STRING: {
if (IsInlined(field)) {
return !GetField<InlinedStringField>(message, field)
.GetNoArena()
Expand Down Expand Up @@ -2833,8 +2926,11 @@ void Reflection::ClearOneof(Message* message,
if (message->GetArenaForAllocation() == nullptr) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING: {
switch (field->options().ctype()) {
default: // TODO(kenton): Support other string reps.
switch (internal::cpp::EffectiveStringCType(field)) {
case FieldOptions::CORD:
delete *MutableRaw<absl::Cord*>(message, field);
break;
default:
case FieldOptions::STRING: {
// Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it
Expand Down
Loading

0 comments on commit 6ecb5d0

Please sign in to comment.