Added Reflection::GetCord() method in C++
PiperOrigin-RevId: 519246549
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 71a540a..a83a62c 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -2653,6 +2653,9 @@
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
diff --git a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc
index 21d01cc..bdefe09 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc
@@ -206,7 +206,7 @@
// 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 @@
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(
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index 3970389..830846e 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -978,7 +978,8 @@
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 @@
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 @@
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;
}
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h
index fd2ea7b..56b599a 100644
--- a/src/google/protobuf/compiler/cpp/helpers.h
+++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -346,25 +346,21 @@
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?
diff --git a/src/google/protobuf/compiler/cpp/unittest.inc b/src/google/protobuf/compiler/cpp/unittest.inc
index dd5829c..bf434f5 100644
--- a/src/google/protobuf/compiler/cpp/unittest.inc
+++ b/src/google/protobuf/compiler/cpp/unittest.inc
@@ -1452,6 +1452,9 @@
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;
}
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 87ae9ed..68434ee 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -2645,6 +2645,21 @@
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.
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index e7cb11f..626672b 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -403,8 +403,20 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+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 @@
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 @@
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 @@
// (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 @@
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
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index 3de242c..4c8e0ab 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -165,6 +165,22 @@
"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 @@
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 @@
"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 @@
#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;
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index ac7fbe5..549f24a 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -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 @@
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 -----------------------------------------
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index 57a752e..cd45dd6 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -213,10 +213,6 @@
// 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
diff --git a/src/google/protobuf/test_util.inc b/src/google/protobuf/test_util.inc
index 37363a7..4c53b20 100644
--- a/src/google/protobuf/test_util.inc
+++ b/src/google/protobuf/test_util.inc
@@ -2396,6 +2396,7 @@
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 @@
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++;
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index b98fc2c..d302587 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -827,7 +827,6 @@
optional int32 a = 5;
optional string b = 6;
}
- bytes foo_bytes_cord = 7 [ctype=CORD];
}
}
@@ -855,6 +854,7 @@
optional string b = 10;
}
NestedMessage foo_lazy_message = 11 [lazy=true];
+ bytes foo_bytes_cord = 30 [ctype=CORD];
}
oneof bar {