Skip to content

Commit 8689a95

Browse files
authored
ci(bigtable): handle string vs Cord proto fields (#15562)
1 parent c169c9b commit 8689a95

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

google/cloud/bigtable/value.cc

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "google/cloud/bigtable/value.h"
1616
#include "google/cloud/bigtable/timestamp.h"
1717
#include "google/cloud/internal/throw_delegate.h"
18+
#include "absl/strings/cord.h"
1819
#include <google/bigtable/v2/types.pb.h>
1920
#include <google/protobuf/descriptor.h>
2021
#include <google/protobuf/message.h>
@@ -25,6 +26,30 @@ namespace cloud {
2526
namespace bigtable {
2627
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2728
namespace {
29+
30+
// Some Bigtable proto fields use Cord internally and string externally.
31+
template <typename T, typename std::enable_if<
32+
std::is_same<T, std::string>::value>::type* = nullptr>
33+
std::string AsString(T const& s) {
34+
return s;
35+
}
36+
template <typename T, typename std::enable_if<
37+
std::is_same<T, std::string>::value>::type* = nullptr>
38+
std::string AsString(T&& s) {
39+
return std::move(s); // NOLINT(bugprone-move-forwarding-reference)
40+
}
41+
template <typename T, typename std::enable_if<
42+
std::is_same<T, absl::Cord>::value>::type* = nullptr>
43+
std::string AsString(T const& s) {
44+
return std::string(s);
45+
}
46+
template <typename T, typename std::enable_if<
47+
std::is_same<T, absl::Cord>::value>::type* = nullptr>
48+
std::string AsString(T&& s) {
49+
return std::string(
50+
std::move(s)); // NOLINT(bugprone-move-forwarding-reference)
51+
}
52+
2853
// Compares two sets of Type and Value protos for equality. This method calls
2954
// itself recursively to compare subtypes and subvalues.
3055
bool Equal(google::bigtable::v2::Type const& pt1, // NOLINT(misc-no-recursion)
@@ -91,7 +116,7 @@ std::ostream& StreamHelper(std::ostream& os, // NOLINT(misc-no-recursion)
91116
return os << v.string_value();
92117
}
93118
if (v.kind_case() == google::bigtable::v2::Value::kBytesValue) {
94-
return os << Bytes(v.bytes_value());
119+
return os << Bytes(AsString(v.bytes_value()));
95120
}
96121
if (v.kind_case() == google::bigtable::v2::Value::kTimestampValue) {
97122
auto ts = MakeTimestamp(v.timestamp_value());
@@ -326,23 +351,23 @@ StatusOr<std::string> Value::GetValue(std::string const&,
326351
if (pv.kind_case() != google::bigtable::v2::Value::kStringValue) {
327352
return internal::UnknownError("missing STRING", GCP_ERROR_INFO());
328353
}
329-
return pv.string_value();
354+
return AsString(pv.string_value());
330355
}
331356
StatusOr<std::string> Value::GetValue(std::string const&,
332357
google::bigtable::v2::Value&& pv,
333358
google::bigtable::v2::Type const&) {
334359
if (pv.kind_case() != google::bigtable::v2::Value::kStringValue) {
335360
return internal::UnknownError("missing STRING", GCP_ERROR_INFO());
336361
}
337-
return std::move(*pv.mutable_string_value());
362+
return AsString(std::move(*pv.mutable_string_value()));
338363
}
339364
StatusOr<Bytes> Value::GetValue(Bytes const&,
340365
google::bigtable::v2::Value const& pv,
341366
google::bigtable::v2::Type const&) {
342367
if (pv.kind_case() != google::bigtable::v2::Value::kBytesValue) {
343368
return internal::UnknownError("missing BYTES", GCP_ERROR_INFO());
344369
}
345-
return Bytes(pv.bytes_value());
370+
return Bytes(AsString(pv.bytes_value()));
346371
}
347372
StatusOr<Timestamp> Value::GetValue(Timestamp const&,
348373
google::bigtable::v2::Value const& pv,

google/cloud/bigtable/value_test.cc

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "google/cloud/internal/base64_transforms.h"
1717
#include "google/cloud/testing_util/is_proto_equal.h"
1818
#include "google/cloud/testing_util/status_matchers.h"
19+
#include "absl/strings/cord.h"
1920
#include <google/type/date.pb.h>
2021
#include <gmock/gmock.h>
2122
#include <cmath>
@@ -226,6 +227,30 @@ TEST(Value, Equality) {
226227
}
227228
}
228229

230+
// The next tests assume std::string is the underlying type of protobuf
231+
// accessors for string values. In situations where the underlying type is
232+
// absl::Cord, the assumptions are no longer valid and checking the moved
233+
// from state of the std::string is even less of a good idea than normal.
234+
template <typename T,
235+
typename U = decltype(std::declval<google::bigtable::v2::Value>()
236+
.string_value()),
237+
typename std::enable_if<
238+
std::is_same<std::remove_cv_t<std::remove_reference_t<U>>,
239+
std::string>::value>::type* = nullptr>
240+
StatusOr<T> MovedFromString(Value const& v) {
241+
return v.get<T>();
242+
}
243+
244+
template <typename T,
245+
typename U = decltype(std::declval<google::bigtable::v2::Value>()
246+
.string_value()),
247+
typename std::enable_if<
248+
std::is_same<std::remove_cv_t<std::remove_reference_t<U>>,
249+
absl::Cord>::value>::type* = nullptr>
250+
StatusOr<T> MovedFromString(Value const&) {
251+
return T{""};
252+
}
253+
229254
// NOTE: This test relies on unspecified behavior about the moved-from state
230255
// of std::string. Specifically, this test relies on the fact that "large"
231256
// strings, when moved-from, end up empty. And we use this fact to verify that
@@ -246,7 +271,7 @@ TEST(Value, RvalueGetString) {
246271
EXPECT_EQ(data, *s);
247272

248273
// NOLINTNEXTLINE(bugprone-use-after-move)
249-
s = v.get<Type>();
274+
s = MovedFromString<Type>(v);
250275
ASSERT_STATUS_OK(s);
251276
EXPECT_EQ("", *s);
252277
}
@@ -271,7 +296,7 @@ TEST(Value, RvalueGetOptionalString) {
271296
EXPECT_EQ(*data, **s);
272297

273298
// NOLINTNEXTLINE(bugprone-use-after-move)
274-
s = v.get<Type>();
299+
s = MovedFromString<Type>(v);
275300
ASSERT_STATUS_OK(s);
276301
EXPECT_EQ("", **s);
277302
}

0 commit comments

Comments
 (0)