Added Reflection::GetCord() method in C++

PiperOrigin-RevId: 519246549
pull/12334/head
Jie Luo 2 years ago committed by Copybara-Service
parent 477e35f4c2
commit 6ecb5d097e
  1. 3
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  2. 4
      src/google/protobuf/compiler/cpp/field_generators/string_field.cc
  3. 22
      src/google/protobuf/compiler/cpp/helpers.cc
  4. 12
      src/google/protobuf/compiler/cpp/helpers.h
  5. 3
      src/google/protobuf/compiler/cpp/unittest.inc
  6. 15
      src/google/protobuf/descriptor.h
  7. 130
      src/google/protobuf/generated_message_reflection.cc
  8. 239
      src/google/protobuf/generated_message_reflection_unittest.cc
  9. 8
      src/google/protobuf/message.h
  10. 4
      src/google/protobuf/port_def.inc
  11. 2
      src/google/protobuf/test_util.inc
  12. 2
      src/google/protobuf/unittest.proto

@ -2653,6 +2653,9 @@ public final class TestUtil {
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

@ -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(
@ -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(

@ -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,
@ -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,
@ -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;
}

@ -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?

@ -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;
}

@ -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.

@ -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 =
@ -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());
@ -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)) {
@ -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(); }
@ -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.
@ -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);
}
@ -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
@ -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();
@ -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();
@ -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,
@ -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);
@ -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)) {
@ -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()
@ -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

@ -165,6 +165,22 @@ TEST(GeneratedMessageReflectionTest, GetStringReference) {
"a reference to the underlying string.";
}
TEST(GeneratedMessageReflectionTest, GetStringReferenceCopy) {
// Test that GetStringReference() returns the scratch string when the
// underlying representation is not a normal string.
unittest::TestCord cord_message;
cord_message.set_optional_bytes_cord("bytes_cord");
const Reflection* cord_reflection = cord_message.GetReflection();
const Descriptor* descriptor = unittest::TestCord::descriptor();
std::string cord_scratch;
EXPECT_EQ(
&cord_scratch,
&cord_reflection->GetStringReference(
cord_message, descriptor->FindFieldByName("optional_bytes_cord"),
&cord_scratch));
}
class GeneratedMessageReflectionSwapTest : public testing::TestWithParam<bool> {
protected:
@ -981,6 +997,8 @@ TEST(GeneratedMessageReflectionTest, Oneof) {
EXPECT_NE(&unittest::TestOneof2::FooGroup::default_instance(),
&reflection->GetMessage(
message, descriptor->FindFieldByName("foo_lazy_message")));
EXPECT_EQ("", reflection->GetString(
message, descriptor->FindFieldByName("foo_bytes_cord")));
EXPECT_EQ(
5, reflection->GetInt32(message, descriptor->FindFieldByName("bar_int")));
EXPECT_EQ("STRING", reflection->GetString(
@ -1009,6 +1027,11 @@ TEST(GeneratedMessageReflectionTest, Oneof) {
"bytes");
EXPECT_EQ("bytes", reflection->GetString(
message, descriptor->FindFieldByName("foo_bytes")));
reflection->SetString(&message, descriptor->FindFieldByName("foo_bytes_cord"),
"bytes_cord");
EXPECT_EQ("bytes_cord",
reflection->GetString(
message, descriptor->FindFieldByName("foo_bytes_cord")));
reflection->SetString(&message, descriptor->FindFieldByName("bar_cord"),
"change_cord");
EXPECT_EQ(
@ -1321,6 +1344,222 @@ TEST(GeneratedMessageReflectionTest, UsageErrors) {
#endif // GTEST_HAS_DEATH_TEST
class GeneratedMessageReflectionCordAccessorsTest : public testing::Test {
protected:
const FieldDescriptor* optional_string_;
const FieldDescriptor* optional_string_piece_;
const FieldDescriptor* optional_cord_;
const FieldDescriptor* repeated_string_;
const FieldDescriptor* repeated_string_piece_;
const FieldDescriptor* repeated_cord_;
const FieldDescriptor* default_string_;
const FieldDescriptor* default_string_piece_;
const FieldDescriptor* default_cord_;
const FieldDescriptor* optional_string_extension_;
const FieldDescriptor* repeated_string_extension_;
unittest::TestAllTypes message_;
const Reflection* reflection_;
unittest::TestAllExtensions extensions_message_;
const Reflection* extensions_reflection_;
void SetUp() override {
const Descriptor* descriptor = unittest::TestAllTypes::descriptor();
optional_string_ = descriptor->FindFieldByName("optional_string");
optional_string_piece_ =
descriptor->FindFieldByName("optional_string_piece");
optional_cord_ = descriptor->FindFieldByName("optional_cord");
repeated_string_ = descriptor->FindFieldByName("repeated_string");
repeated_string_piece_ =
descriptor->FindFieldByName("repeated_string_piece");
repeated_cord_ = descriptor->FindFieldByName("repeated_cord");
default_string_ = descriptor->FindFieldByName("default_string");
default_string_piece_ = descriptor->FindFieldByName("default_string_piece");
default_cord_ = descriptor->FindFieldByName("default_cord");
optional_string_extension_ =
descriptor->file()->FindExtensionByName("optional_string_extension");
repeated_string_extension_ =
descriptor->file()->FindExtensionByName("repeated_string_extension");
ASSERT_TRUE(optional_string_ != nullptr);
ASSERT_TRUE(optional_string_piece_ != nullptr);
ASSERT_TRUE(optional_cord_ != nullptr);
ASSERT_TRUE(repeated_string_ != nullptr);
ASSERT_TRUE(repeated_string_piece_ != nullptr);
ASSERT_TRUE(repeated_cord_ != nullptr);
ASSERT_TRUE(optional_string_extension_ != nullptr);
ASSERT_TRUE(repeated_string_extension_ != nullptr);
reflection_ = message_.GetReflection();
extensions_reflection_ = extensions_message_.GetReflection();
}
};
TEST_F(GeneratedMessageReflectionCordAccessorsTest, GetCord) {
message_.set_optional_string("foo");
extensions_message_.SetExtension(unittest::optional_string_extension, "moo");
EXPECT_EQ("foo", reflection_->GetCord(message_, optional_string_));
EXPECT_EQ("moo", extensions_reflection_->GetCord(extensions_message_,
optional_string_extension_));
EXPECT_EQ("hello", reflection_->GetCord(message_, default_string_));
EXPECT_EQ("abc", reflection_->GetCord(message_, default_string_piece_));
EXPECT_EQ("123", reflection_->GetCord(message_, default_cord_));
unittest::TestCord message;
const Descriptor* descriptor = unittest::TestCord::descriptor();
const Reflection* reflection = message.GetReflection();
message.set_optional_bytes_cord("bytes_cord");
EXPECT_EQ("bytes_cord",
reflection->GetCord(
message, descriptor->FindFieldByName("optional_bytes_cord")));
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, GetOneofCord) {
unittest::TestOneof2 message;
const Descriptor* descriptor = unittest::TestOneof2::descriptor();
const Reflection* reflection = message.GetReflection();
message.set_foo_bytes_cord("bytes_cord");
EXPECT_EQ("bytes_cord",
reflection->GetCord(message,
descriptor->FindFieldByName("foo_bytes_cord")));
message.set_foo_string("foo");
EXPECT_EQ("foo", reflection->GetCord(
message, descriptor->FindFieldByName("foo_string")));
message.set_foo_bytes("bytes");
EXPECT_EQ("bytes", reflection->GetCord(
message, descriptor->FindFieldByName("foo_bytes")));
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, SetStringFromCord) {
reflection_->SetString(&message_, optional_string_, absl::Cord("foo"));
reflection_->SetString(&message_, optional_string_piece_, absl::Cord("bar"));
reflection_->SetString(&message_, optional_cord_, absl::Cord("baz"));
extensions_reflection_->SetString(
&extensions_message_, optional_string_extension_, absl::Cord("moo"));
EXPECT_TRUE(message_.has_optional_string());
EXPECT_TRUE(message_.has_optional_string_piece());
EXPECT_TRUE(message_.has_optional_cord());
EXPECT_TRUE(
extensions_message_.HasExtension(unittest::optional_string_extension));
EXPECT_EQ("foo", message_.optional_string());
EXPECT_EQ("bar", std::string(
reflection_->GetCord(message_, optional_string_piece_)));
EXPECT_EQ("baz", std::string(reflection_->GetCord(message_, optional_cord_)));
EXPECT_EQ("moo", extensions_message_.GetExtension(
unittest::optional_string_extension));
unittest::TestCord message;
const Descriptor* descriptor = unittest::TestCord::descriptor();
const Reflection* reflection = message.GetReflection();
reflection->SetString(&message,
descriptor->FindFieldByName("optional_bytes_cord"),
absl::Cord("cord"));
EXPECT_TRUE(message.has_optional_bytes_cord());
EXPECT_EQ("cord", message.optional_bytes_cord());
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, SetOneofStringFromCord) {
unittest::TestOneof2 message;
const Descriptor* descriptor = unittest::TestOneof2::descriptor();
const Reflection* reflection = message.GetReflection();
reflection->SetString(&message, descriptor->FindFieldByName("foo_string"),
absl::Cord("foo"));
EXPECT_TRUE(message.has_foo_string());
EXPECT_EQ("foo", message.foo_string());
reflection->SetString(&message, descriptor->FindFieldByName("foo_bytes"),
absl::Cord("bytes"));
EXPECT_TRUE(message.has_foo_bytes());
EXPECT_EQ("bytes", message.foo_bytes());
reflection->SetString(&message, descriptor->FindFieldByName("foo_cord"),
absl::Cord("cord"));
EXPECT_EQ("cord", std::string(reflection->GetCord(
message, descriptor->FindFieldByName("foo_cord"))));
reflection->SetString(&message,
descriptor->FindFieldByName("foo_string_piece"),
absl::Cord("string_piece"));
EXPECT_EQ("string_piece",
reflection->GetCord(
message, descriptor->FindFieldByName("foo_string_piece")));
reflection->SetString(&message, descriptor->FindFieldByName("foo_bytes_cord"),
absl::Cord("bytes_cord"));
EXPECT_TRUE(message.has_foo_bytes_cord());
EXPECT_EQ("bytes_cord", message.foo_bytes_cord());
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, CordSingularBytes) {
unittest::TestCord message;
absl::Cord cord_value("test");
message.set_optional_bytes_cord(cord_value);
EXPECT_EQ("test", message.optional_bytes_cord());
EXPECT_TRUE(message.has_optional_bytes_cord());
message.clear_optional_bytes_cord();
EXPECT_FALSE(message.has_optional_bytes_cord());
std::string string_value = "test";
message.set_optional_bytes_cord(string_value);
EXPECT_EQ("test", message.optional_bytes_cord());
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, CordSingularBytesDefault) {
unittest::TestCord message;
EXPECT_EQ("hello", message.optional_bytes_cord_default());
absl::Cord cord_value("world");
message.set_optional_bytes_cord_default(cord_value);
EXPECT_EQ("world", message.optional_bytes_cord_default());
message.clear_optional_bytes_cord_default();
EXPECT_EQ("hello", message.optional_bytes_cord_default());
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, CordSingularOneofBytes) {
unittest::TestOneof2 message;
absl::Cord cord_value("test");
message.set_foo_bytes_cord(cord_value);
EXPECT_EQ("test", message.foo_bytes_cord());
EXPECT_TRUE(message.has_foo_bytes_cord());
message.clear_foo();
EXPECT_FALSE(message.has_foo_bytes_cord());
std::string string_value = "test";
message.set_foo_bytes_cord(string_value);
EXPECT_EQ("test", message.foo_bytes_cord());
EXPECT_TRUE(message.has_foo_bytes_cord());
}
TEST_F(GeneratedMessageReflectionCordAccessorsTest, ClearOneofCord) {
unittest::TestOneof2 message;
absl::Cord cord_value("test");
message.set_foo_bytes_cord(cord_value);
const Descriptor* descriptor = unittest::TestOneof2::descriptor();
const Reflection* reflection = message.GetReflection();
EXPECT_TRUE(message.has_foo_bytes_cord());
reflection->ClearOneof(&message, descriptor->FindOneofByName("foo"));
EXPECT_FALSE(message.has_foo_bytes_cord());
}
using internal::IsDescendant;

@ -122,6 +122,7 @@
#include "absl/base/call_once.h"
#include "absl/base/casts.h"
#include "absl/functional/function_ref.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/generated_message_reflection.h"
@ -131,7 +132,6 @@
#include "google/protobuf/message_lite.h"
#include "google/protobuf/port.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
@ -630,6 +630,12 @@ class PROTOBUF_EXPORT Reflection final {
const FieldDescriptor* field,
std::string* scratch) const;
// Returns a Cord containing the value of the string field. If the
// underlying field is stored as a cord (e.g. it has the [ctype=CORD]
// option), this involves no copies (just reference counting). If the
// underlying representation is not a Cord, a copy will have to be made.
absl::Cord GetCord(const Message& message,
const FieldDescriptor* field) const;
// Singular field mutators -----------------------------------------

@ -213,10 +213,6 @@ static_assert(PROTOBUF_CPLUSPLUS_MIN(201402L), "Protobuf only supports C++14 and
// Owner: shaod@, gberg@
#define PROTOBUF_FUTURE_DESCRIPTOR_EXTENSION_DECL 1
// Enable cord handling.
// Owner: mvels@, mkruskal@
#define PROTOBUF_FUTURE_OPENSOURCE_CORD 1
// Used to remove `RepeatedPtrField::GetArena() const`.
// Owner: ezb@
#define PROTOBUF_FUTURE_REMOVE_CONST_REPEATEDFIELD_GETARENA_API 1

@ -2396,6 +2396,7 @@ inline void TestUtil::ExpectOneofClear(const UNITTEST::TestOneof2& message) {
EXPECT_FALSE(message.has_foo_message());
EXPECT_FALSE(message.has_foogroup());
EXPECT_FALSE(message.has_foo_lazy_message());
EXPECT_FALSE(message.has_foo_bytes_cord());
EXPECT_FALSE(message.has_bar_int());
EXPECT_FALSE(message.has_bar_string());
@ -2419,6 +2420,7 @@ inline void TestUtil::ExpectAtMostOneFieldSetInOneof(
if (message.has_foo_message()) count++;
if (message.has_foogroup()) count++;
if (message.has_foo_lazy_message()) count++;
if (message.has_foo_bytes_cord()) count++;
EXPECT_LE(count, 1);
count = 0;
if (message.has_bar_int()) count++;

@ -827,7 +827,6 @@ message TestOneof {
optional int32 a = 5;
optional string b = 6;
}
bytes foo_bytes_cord = 7 [ctype=CORD];
}
}
@ -855,6 +854,7 @@ message TestOneof2 {
optional string b = 10;
}
NestedMessage foo_lazy_message = 11 [lazy=true];
bytes foo_bytes_cord = 30 [ctype=CORD];
}
oneof bar {

Loading…
Cancel
Save