Skip to content

Commit a3f5af0

Browse files
Add GetStringView() and GetRepeatedStringView() with scratch.
PiperOrigin-RevId: 608636288
1 parent 6c58b9a commit a3f5af0

4 files changed

Lines changed: 187 additions & 0 deletions

File tree

src/google/protobuf/generated_message_reflection.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,6 +1868,32 @@ absl::Cord Reflection::GetCord(const Message& message,
18681868
}
18691869
}
18701870

1871+
absl::string_view Reflection::GetStringView(const Message& message,
1872+
const FieldDescriptor* field,
1873+
ScratchSpace& scratch) const {
1874+
USAGE_CHECK_ALL(GetStringView, SINGULAR, STRING);
1875+
1876+
if (field->is_extension()) {
1877+
return GetExtensionSet(message).GetString(field->number(),
1878+
field->default_value_string());
1879+
}
1880+
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
1881+
return field->default_value_string();
1882+
}
1883+
1884+
switch (internal::cpp::EffectiveStringCType(field)) {
1885+
case FieldOptions::CORD: {
1886+
const auto& cord = schema_.InRealOneof(field)
1887+
? *GetField<absl::Cord*>(message, field)
1888+
: GetField<absl::Cord>(message, field);
1889+
return scratch.CopyFromCord(cord);
1890+
}
1891+
default:
1892+
auto str = GetField<ArenaStringPtr>(message, field);
1893+
return str.IsDefault() ? field->default_value_string() : str.Get();
1894+
}
1895+
}
1896+
18711897

18721898
void Reflection::SetString(Message* message, const FieldDescriptor* field,
18731899
std::string value) const {
@@ -2002,6 +2028,24 @@ const std::string& Reflection::GetRepeatedStringReference(
20022028
}
20032029
}
20042030

2031+
// See GetStringView(), above.
2032+
absl::string_view Reflection::GetRepeatedStringView(
2033+
const Message& message, const FieldDescriptor* field, int index,
2034+
ScratchSpace& scratch) const {
2035+
(void)scratch;
2036+
USAGE_CHECK_ALL(GetRepeatedStringView, REPEATED, STRING);
2037+
2038+
if (field->is_extension()) {
2039+
return GetExtensionSet(message).GetRepeatedString(field->number(), index);
2040+
}
2041+
2042+
switch (internal::cpp::EffectiveStringCType(field)) {
2043+
case FieldOptions::STRING:
2044+
default:
2045+
return GetRepeatedPtrField<std::string>(message, field, index);
2046+
}
2047+
}
2048+
20052049

20062050
void Reflection::SetRepeatedString(Message* message,
20072051
const FieldDescriptor* field, int index,

src/google/protobuf/generated_message_reflection_unittest.cc

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,99 @@ TEST(GeneratedMessageReflectionTest, GetStringReferenceCopy) {
162162
&cord_scratch));
163163
}
164164

165+
TEST(GeneratedMessageReflectionTest, GetStringView) {
166+
unittest::TestAllTypes message;
167+
TestUtil::SetAllFields(&message);
168+
169+
const Reflection* reflection = message.GetReflection();
170+
Reflection::ScratchSpace scratch;
171+
172+
EXPECT_EQ("115",
173+
reflection->GetStringView(message, F("optional_string"), scratch));
174+
EXPECT_EQ("124", reflection->GetStringView(
175+
message, F("optional_string_piece"), scratch));
176+
EXPECT_EQ("125",
177+
reflection->GetStringView(message, F("optional_cord"), scratch));
178+
}
179+
180+
TEST(GeneratedMessageReflectionTest, GetStringViewWithExtensions) {
181+
unittest::TestAllExtensions message;
182+
google::protobuf::FileDescriptor const* descriptor_file =
183+
message.GetDescriptor()->file();
184+
google::protobuf::FieldDescriptor const* string_ext =
185+
descriptor_file->FindExtensionByName("optional_string_extension");
186+
google::protobuf::FieldDescriptor const* string_piece_ext =
187+
descriptor_file->FindExtensionByName("optional_string_piece_extension");
188+
google::protobuf::FieldDescriptor const* cord_ext =
189+
descriptor_file->FindExtensionByName("optional_cord_extension");
190+
message.SetExtension(protobuf_unittest::optional_string_extension, "foo");
191+
message.SetExtension(protobuf_unittest::optional_string_piece_extension, "bar");
192+
message.SetExtension(protobuf_unittest::optional_cord_extension, "baz");
193+
const Reflection* reflection = message.GetReflection();
194+
Reflection::ScratchSpace scratch;
195+
196+
EXPECT_EQ("foo", reflection->GetStringView(message, string_ext, scratch));
197+
EXPECT_EQ("bar",
198+
reflection->GetStringView(message, string_piece_ext, scratch));
199+
EXPECT_EQ("baz", reflection->GetStringView(message, cord_ext, scratch));
200+
}
201+
202+
TEST(GeneratedMessageReflectionTest, GetStringViewWithOneof) {
203+
unittest::TestOneof2 message;
204+
const Reflection* reflection = message.GetReflection();
205+
const FieldDescriptor* string_field =
206+
message.GetDescriptor()->FindFieldByName("foo_string");
207+
const FieldDescriptor* string_piece_field =
208+
message.GetDescriptor()->FindFieldByName("foo_string_piece");
209+
Reflection::ScratchSpace scratch;
210+
211+
message.set_foo_string("foo");
212+
EXPECT_EQ("foo", reflection->GetStringView(message, string_field, scratch));
213+
EXPECT_EQ("",
214+
reflection->GetStringView(message, string_piece_field, scratch));
215+
216+
}
217+
218+
TEST(GeneratedMessageReflectionTest, GetRepeatedStringView) {
219+
unittest::TestAllTypes message;
220+
TestUtil::AddRepeatedFields1(&message);
221+
TestUtil::AddRepeatedFields2(&message);
222+
223+
const Reflection* reflection = message.GetReflection();
224+
Reflection::ScratchSpace scratch;
225+
226+
EXPECT_EQ("215", reflection->GetRepeatedStringView(
227+
message, F("repeated_string"), 0, scratch));
228+
EXPECT_EQ("224", reflection->GetRepeatedStringView(
229+
message, F("repeated_string_piece"), 0, scratch));
230+
EXPECT_EQ("225", reflection->GetRepeatedStringView(
231+
message, F("repeated_cord"), 0, scratch));
232+
}
233+
234+
TEST(GeneratedMessageReflectionTest, GetRepeatedStringViewWithExtensions) {
235+
unittest::TestAllExtensions message;
236+
google::protobuf::FileDescriptor const* descriptor_file =
237+
message.GetDescriptor()->file();
238+
google::protobuf::FieldDescriptor const* string_ext =
239+
descriptor_file->FindExtensionByName("repeated_string_extension");
240+
google::protobuf::FieldDescriptor const* string_piece_ext =
241+
descriptor_file->FindExtensionByName("repeated_string_piece_extension");
242+
google::protobuf::FieldDescriptor const* cord_ext =
243+
descriptor_file->FindExtensionByName("repeated_cord_extension");
244+
message.AddExtension(protobuf_unittest::repeated_string_extension, "foo");
245+
message.AddExtension(protobuf_unittest::repeated_string_piece_extension, "bar");
246+
message.AddExtension(protobuf_unittest::repeated_cord_extension, "baz");
247+
const Reflection* reflection = message.GetReflection();
248+
Reflection::ScratchSpace scratch;
249+
250+
EXPECT_EQ("foo",
251+
reflection->GetRepeatedStringView(message, string_ext, 0, scratch));
252+
EXPECT_EQ("bar", reflection->GetRepeatedStringView(message, string_piece_ext,
253+
0, scratch));
254+
EXPECT_EQ("baz",
255+
reflection->GetRepeatedStringView(message, cord_ext, 0, scratch));
256+
}
257+
165258

166259
class GeneratedMessageReflectionSwapTest : public testing::TestWithParam<bool> {
167260
protected:

src/google/protobuf/message.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989

9090
#include <cstddef>
9191
#include <cstdint>
92+
#include <memory>
9293
#include <string>
9394
#include <type_traits>
9495
#include <vector>
@@ -97,6 +98,7 @@
9798
#include "absl/base/call_once.h"
9899
#include "google/protobuf/stubs/common.h"
99100
#include "absl/log/absl_check.h"
101+
#include "absl/memory/memory.h"
100102
#include "absl/strings/cord.h"
101103
#include "absl/strings/string_view.h"
102104
#include "google/protobuf/arena.h"
@@ -585,6 +587,37 @@ class PROTOBUF_EXPORT Reflection final {
585587
absl::Cord GetCord(const Message& message,
586588
const FieldDescriptor* field) const;
587589

590+
// Enables GetStringView() and GetRepeatedStringView() APIs to return
591+
// absl::string_view even though the underlying implementation doesn't have
592+
// contiguous bytes; e.g. absl::Cord.
593+
class ScratchSpace {
594+
public:
595+
ScratchSpace() = default;
596+
597+
ScratchSpace(const ScratchSpace&) = delete;
598+
ScratchSpace& operator=(const ScratchSpace&) = delete;
599+
600+
private:
601+
friend class Reflection;
602+
603+
absl::string_view CopyFromCord(const absl::Cord& cord) {
604+
if (!buffer_) {
605+
buffer_ = absl::make_unique<std::string>();
606+
}
607+
absl::CopyCordToString(cord, buffer_.get());
608+
return *buffer_;
609+
}
610+
611+
std::unique_ptr<std::string> buffer_;
612+
};
613+
614+
// Returns a view into the contents of a string field. "scratch" is used to
615+
// flatten bytes if it is non-contiguous. The lifetime of absl::string_view is
616+
// either tied to "message" (contiguous) or "scratch" (otherwise).
617+
absl::string_view GetStringView(
618+
const Message& message, const FieldDescriptor* field,
619+
ScratchSpace& scratch ABSL_ATTRIBUTE_LIFETIME_BOUND) const;
620+
588621

589622
// Singular field mutators -----------------------------------------
590623
// These mutate the value of a non-repeated field.
@@ -706,6 +739,11 @@ class PROTOBUF_EXPORT Reflection final {
706739
int index,
707740
std::string* scratch) const;
708741

742+
// See GetStringView(), above.
743+
absl::string_view GetRepeatedStringView(
744+
const Message& message, const FieldDescriptor* field, int index,
745+
ScratchSpace& scratch ABSL_ATTRIBUTE_LIFETIME_BOUND) const;
746+
709747

710748
// Repeated field mutators -----------------------------------------
711749
// These mutate the value of one element of a repeated field.

src/google/protobuf/string_view_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ TEST(StringViewFieldTest, SingularSetAndGetByReflection) {
109109
reflection->SetString(&message, field, std::string{STRING_PAYLOAD});
110110

111111
EXPECT_THAT(reflection->GetString(message, field), StrEq(STRING_PAYLOAD));
112+
Reflection::ScratchSpace scratch;
113+
EXPECT_THAT(reflection->GetStringView(message, field, scratch),
114+
StrEq(STRING_PAYLOAD));
112115
EXPECT_THAT(message.singular_string(), StrEq(STRING_PAYLOAD));
113116
}
114117

@@ -292,6 +295,15 @@ TEST(StringViewFieldTest, RepeatedSetAndGetByReflection) {
292295
EXPECT_THAT(rep_str,
293296
ElementsAre("000000000000", "111111111111", "222222222222"));
294297
}
298+
299+
// GetRepeatedStringView.
300+
Reflection::ScratchSpace scratch;
301+
EXPECT_THAT(reflection->GetRepeatedStringView(message, field, 0, scratch),
302+
StrEq("000000000000"));
303+
EXPECT_THAT(reflection->GetRepeatedStringView(message, field, 1, scratch),
304+
StrEq("111111111111"));
305+
EXPECT_THAT(reflection->GetRepeatedStringView(message, field, 2, scratch),
306+
StrEq("222222222222"));
295307
}
296308

297309
} // namespace

0 commit comments

Comments
 (0)