Skip to content

Commit 3962f01

Browse files
feat(bigtable): add support for other primitive Value types (googleapis#15550)
* feat(bigtable): [partial implementation] add primitive value types * feat(bigtable): add support for other primitive Value types * chore: reduce redundant messages * chore: fix comment * chore: fix naming * chore: fix clang-tidy * chore: include <cmath> * chore: use exceptions directive
1 parent bffeaef commit 3962f01

3 files changed

Lines changed: 525 additions & 0 deletions

File tree

google/cloud/bigtable/value.cc

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
#include "google/cloud/bigtable/value.h"
16+
#include "google/cloud/internal/throw_delegate.h"
1617
#include <google/bigtable/v2/types.pb.h>
1718
#include <google/protobuf/descriptor.h>
1819
#include <google/protobuf/message.h>
@@ -33,6 +34,15 @@ bool Equal(google::bigtable::v2::Type const& pt1, // NOLINT(misc-no-recursion)
3334
if (pt1.has_bool_type()) {
3435
return pv1.bool_value() == pv2.bool_value();
3536
}
37+
if (pt1.has_int64_type()) {
38+
return pv1.int_value() == pv2.int_value();
39+
}
40+
if (pt1.has_float32_type() || pt1.has_float64_type()) {
41+
return pv1.float_value() == pv2.float_value();
42+
}
43+
if (pt1.has_string_type()) {
44+
return pv1.string_value() == pv2.string_value();
45+
}
3646
return false;
3747
}
3848

@@ -57,6 +67,15 @@ std::ostream& StreamHelper(std::ostream& os, // NOLINT(misc-no-recursion)
5767
if (v.kind_case() == google::bigtable::v2::Value::kBoolValue) {
5868
return os << v.bool_value();
5969
}
70+
if (v.kind_case() == google::bigtable::v2::Value::kIntValue) {
71+
return os << v.int_value();
72+
}
73+
if (v.kind_case() == google::bigtable::v2::Value::kFloatValue) {
74+
return os << v.float_value();
75+
}
76+
if (v.kind_case() == google::bigtable::v2::Value::kStringValue) {
77+
return os << v.string_value();
78+
}
6079
// this should include type name
6180
return os << "Error: unknown value type code ";
6281
}
@@ -77,6 +96,19 @@ std::ostream& operator<<(std::ostream& os, Value const& v) {
7796
bool Value::TypeProtoIs(bool, google::bigtable::v2::Type const& type) {
7897
return type.has_bool_type();
7998
}
99+
bool Value::TypeProtoIs(std::int64_t, google::bigtable::v2::Type const& type) {
100+
return type.has_int64_type();
101+
}
102+
bool Value::TypeProtoIs(float, google::bigtable::v2::Type const& type) {
103+
return type.has_float32_type();
104+
}
105+
bool Value::TypeProtoIs(double, google::bigtable::v2::Type const& type) {
106+
return type.has_float64_type();
107+
}
108+
bool Value::TypeProtoIs(std::string const&,
109+
google::bigtable::v2::Type const& type) {
110+
return type.has_string_type();
111+
}
80112

81113
//
82114
// Value::MakeTypeProto
@@ -87,6 +119,35 @@ google::bigtable::v2::Type Value::MakeTypeProto(bool) {
87119
t.set_allocated_bool_type(std::move(new google::bigtable::v2::Type_Bool()));
88120
return t;
89121
}
122+
google::bigtable::v2::Type Value::MakeTypeProto(int const i) {
123+
return Value::MakeTypeProto(static_cast<std::int64_t>(i));
124+
}
125+
google::bigtable::v2::Type Value::MakeTypeProto(std::int64_t) {
126+
google::bigtable::v2::Type t;
127+
t.set_allocated_int64_type(std::move(new google::bigtable::v2::Type_Int64()));
128+
return t;
129+
}
130+
google::bigtable::v2::Type Value::MakeTypeProto(float) {
131+
google::bigtable::v2::Type t;
132+
t.set_allocated_float32_type(
133+
std::move(new google::bigtable::v2::Type_Float32()));
134+
return t;
135+
}
136+
google::bigtable::v2::Type Value::MakeTypeProto(double) {
137+
google::bigtable::v2::Type t;
138+
t.set_allocated_float64_type(
139+
std::move(new google::bigtable::v2::Type_Float64()));
140+
return t;
141+
}
142+
google::bigtable::v2::Type Value::MakeTypeProto(std::string const&) {
143+
google::bigtable::v2::Type t;
144+
t.set_allocated_string_type(
145+
std::move(new google::bigtable::v2::Type_String()));
146+
return t;
147+
}
148+
google::bigtable::v2::Type Value::MakeTypeProto(char const* s) {
149+
return Value::MakeTypeProto(std::string(std::move(s)));
150+
}
90151

91152
//
92153
// Value::MakeValueProto
@@ -97,6 +158,44 @@ google::bigtable::v2::Value Value::MakeValueProto(bool b) {
97158
v.set_bool_value(b);
98159
return v;
99160
}
161+
google::bigtable::v2::Value Value::MakeValueProto(std::int64_t i) {
162+
google::bigtable::v2::Value v;
163+
v.set_int_value(i);
164+
return v;
165+
}
166+
google::bigtable::v2::Value Value::MakeValueProto(int i) {
167+
return Value::MakeValueProto(static_cast<std::int64_t>(i));
168+
}
169+
google::bigtable::v2::Value Value::MakeValueProto(float f) {
170+
// NaN and Infinity are not supported. See
171+
// https://github.com/googleapis/googleapis/blob/5caeec4d72173ea3f2772b1b67a5c3f9192a6d06/google/bigtable/v2/data.proto#L140-L142
172+
if (std::isnan(f) || std::isinf(f)) {
173+
internal::ThrowInvalidArgument(
174+
bigtable_internal::kInvalidFloatValueMessage);
175+
}
176+
google::bigtable::v2::Value v;
177+
v.set_float_value(f);
178+
return v;
179+
}
180+
google::bigtable::v2::Value Value::MakeValueProto(double d) {
181+
// NaN and Infinity are not supported. See
182+
// https://github.com/googleapis/googleapis/blob/5caeec4d72173ea3f2772b1b67a5c3f9192a6d06/google/bigtable/v2/data.proto#L140-L142
183+
if (std::isnan(d) || std::isinf(d)) {
184+
internal::ThrowInvalidArgument(
185+
bigtable_internal::kInvalidFloatValueMessage);
186+
}
187+
google::bigtable::v2::Value v;
188+
v.set_float_value(d);
189+
return v;
190+
}
191+
google::bigtable::v2::Value Value::MakeValueProto(std::string s) {
192+
google::bigtable::v2::Value v;
193+
v.set_string_value(std::move(s));
194+
return v;
195+
}
196+
google::bigtable::v2::Value Value::MakeValueProto(char const* s) {
197+
return Value::MakeValueProto(std::string(s));
198+
}
100199

101200
//
102201
// Value::GetValue
@@ -109,6 +208,52 @@ StatusOr<bool> Value::GetValue(bool, google::bigtable::v2::Value const& pv,
109208
}
110209
return pv.bool_value();
111210
}
211+
StatusOr<std::int64_t> Value::GetValue(std::int64_t,
212+
google::bigtable::v2::Value const& pv,
213+
google::bigtable::v2::Type const&) {
214+
if (pv.kind_case() != google::bigtable::v2::Value::kIntValue) {
215+
return internal::UnknownError("missing INT64", GCP_ERROR_INFO());
216+
}
217+
return pv.int_value();
218+
}
219+
StatusOr<float> Value::GetValue(float, google::bigtable::v2::Value const& pv,
220+
google::bigtable::v2::Type const&) {
221+
if (pv.kind_case() != google::bigtable::v2::Value::kFloatValue) {
222+
return internal::UnknownError("missing FLOAT32", GCP_ERROR_INFO());
223+
}
224+
if (std::isnan(pv.float_value()) || std::isinf(pv.float_value())) {
225+
return internal::UnimplementedError(
226+
bigtable_internal::kInvalidFloatValueMessage);
227+
}
228+
return static_cast<float>(pv.float_value());
229+
}
230+
StatusOr<double> Value::GetValue(double, google::bigtable::v2::Value const& pv,
231+
google::bigtable::v2::Type const&) {
232+
if (pv.kind_case() != google::bigtable::v2::Value::kFloatValue) {
233+
return internal::UnknownError("missing FLOAT64", GCP_ERROR_INFO());
234+
}
235+
if (std::isnan(pv.float_value()) || std::isinf(pv.float_value())) {
236+
return internal::UnimplementedError(
237+
bigtable_internal::kInvalidFloatValueMessage);
238+
}
239+
return pv.float_value();
240+
}
241+
StatusOr<std::string> Value::GetValue(std::string const&,
242+
google::bigtable::v2::Value const& pv,
243+
google::bigtable::v2::Type const&) {
244+
if (pv.kind_case() != google::bigtable::v2::Value::kStringValue) {
245+
return internal::UnknownError("missing STRING", GCP_ERROR_INFO());
246+
}
247+
return pv.string_value();
248+
}
249+
StatusOr<std::string> Value::GetValue(std::string const&,
250+
google::bigtable::v2::Value&& pv,
251+
google::bigtable::v2::Type const&) {
252+
if (pv.kind_case() != google::bigtable::v2::Value::kStringValue) {
253+
return internal::UnknownError("missing STRING", GCP_ERROR_INFO());
254+
}
255+
return std::move(*pv.mutable_string_value());
256+
}
112257

113258
bool Value::is_null() const { return IsNullValue(value_); }
114259

google/cloud/bigtable/value.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,32 @@
1919
#include "google/cloud/status_or.h"
2020
#include <google/bigtable/v2/data.pb.h>
2121
#include <google/bigtable/v2/types.pb.h>
22+
#include <cmath>
2223

2324
namespace google {
2425
namespace cloud {
2526

2627
namespace bigtable_internal {
2728
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2829
struct ValueInternals;
30+
31+
static std::string const kInvalidFloatValueMessage =
32+
"NaN and Infinity are not supported for FLOAT** values";
33+
34+
static bool validate_float_value(double v) {
35+
if (std::isnan(v) || std::isinf(v)) {
36+
#if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
37+
throw internal::FailedPreconditionError(kInvalidFloatValueMessage);
38+
#else // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
39+
return false;
40+
#endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS
41+
}
42+
return true;
43+
}
44+
45+
static bool ValidateFloatValue(double v) { return validate_float_value(v); }
46+
47+
static bool ValidateFloatValue(float v) { return validate_float_value(v); }
2948
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
3049
} // namespace bigtable_internal
3150

@@ -45,6 +64,10 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
4564
* Bigtable Type | C++ Type `T`
4665
* ------------ | ------------
4766
* BOOL | `bool`
67+
* INT64 | `std::int64_t`
68+
* FLOAT32 | `float`
69+
* FLOAT64 | `double`
70+
* STRING | `std::string`
4871
*
4972
* Callers may create instances by passing any of the supported values
5073
* (shown in the table above) to the constructor. "Null" values are created
@@ -60,6 +83,38 @@ class Value {
6083
Value() = default;
6184
/// Constructs an instance with the specified type and value.
6285
explicit Value(bool v) : Value(PrivateConstructor{}, v) {}
86+
/// @copydoc Value(bool)
87+
explicit Value(std::int64_t v) : Value(PrivateConstructor{}, v) {}
88+
/// @copydoc Value(bool)
89+
explicit Value(float v) : Value(PrivateConstructor{}, v) {
90+
bigtable_internal::ValidateFloatValue(v);
91+
}
92+
/// @copydoc Value(bool)
93+
explicit Value(double v) : Value(PrivateConstructor{}, v) {
94+
bigtable_internal::ValidateFloatValue(v);
95+
}
96+
/// @copydoc Value(bool)
97+
explicit Value(std::string v) : Value(PrivateConstructor{}, std::move(v)) {}
98+
/**
99+
* Constructs an instance from common C++ literal types that closely, though
100+
* not exactly, match supported Bigtable types.
101+
*
102+
* An integer literal in C++ is of type `int`, which is not exactly an
103+
* allowed Bigtable type. This will be allowed but it will be implicitly up
104+
* converted to a `std::int64_t`. Similarly, a C++ string literal will be
105+
* implicitly converted to a `std::string`. For example:
106+
*
107+
* @code
108+
* bigtable::Value v1(42);
109+
* assert(42 == *v1.get<std::int64_t>());
110+
*
111+
* bigtable::Value v2("hello");
112+
* assert("hello" == *v2.get<std::string>());
113+
* @endcode
114+
*/
115+
explicit Value(int v) : Value(PrivateConstructor{}, v) {}
116+
/// @copydoc Value(int)
117+
explicit Value(char const* v) : Value(PrivateConstructor{}, v) {}
63118

64119
/**
65120
* Constructs a non-null instance if `opt` has a value, otherwise constructs
@@ -132,6 +187,11 @@ class Value {
132187
// Tag-dispatch overloads to check if a C++ type matches the type specified
133188
// by the given `Type` proto.
134189
static bool TypeProtoIs(bool, google::bigtable::v2::Type const&);
190+
static bool TypeProtoIs(std::int64_t, google::bigtable::v2::Type const&);
191+
static bool TypeProtoIs(float, google::bigtable::v2::Type const&);
192+
static bool TypeProtoIs(double, google::bigtable::v2::Type const&);
193+
static bool TypeProtoIs(std::string const&,
194+
google::bigtable::v2::Type const&);
135195
template <typename T>
136196
static bool TypeProtoIs(absl::optional<T>,
137197
google::bigtable::v2::Type const& type) {
@@ -141,6 +201,12 @@ class Value {
141201
// Tag-dispatch overloads to convert a C++ type to a `Type` protobuf. The
142202
// argument type is the tag, the argument value is ignored.
143203
static google::bigtable::v2::Type MakeTypeProto(bool);
204+
static google::bigtable::v2::Type MakeTypeProto(std::int64_t);
205+
static google::bigtable::v2::Type MakeTypeProto(float);
206+
static google::bigtable::v2::Type MakeTypeProto(double);
207+
static google::bigtable::v2::Type MakeTypeProto(std::string const&);
208+
static google::bigtable::v2::Type MakeTypeProto(int);
209+
static google::bigtable::v2::Type MakeTypeProto(char const*);
144210
template <typename T>
145211
static google::bigtable::v2::Type MakeTypeProto(absl::optional<T> const&) {
146212
return MakeTypeProto(T{});
@@ -149,6 +215,12 @@ class Value {
149215
// Encodes the argument as a protobuf according to the rules described in
150216
// https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/type.proto
151217
static google::bigtable::v2::Value MakeValueProto(bool b);
218+
static google::bigtable::v2::Value MakeValueProto(std::int64_t i);
219+
static google::bigtable::v2::Value MakeValueProto(float f);
220+
static google::bigtable::v2::Value MakeValueProto(double d);
221+
static google::bigtable::v2::Value MakeValueProto(std::string s);
222+
static google::bigtable::v2::Value MakeValueProto(int i);
223+
static google::bigtable::v2::Value MakeValueProto(char const* s);
152224
template <typename T>
153225
static google::bigtable::v2::Value MakeValueProto(absl::optional<T> opt) {
154226
if (opt.has_value()) return MakeValueProto(*std::move(opt));
@@ -162,6 +234,19 @@ class Value {
162234
// first argument type is the tag, its value is ignored.
163235
static StatusOr<bool> GetValue(bool, google::bigtable::v2::Value const&,
164236
google::bigtable::v2::Type const&);
237+
static StatusOr<std::int64_t> GetValue(std::int64_t,
238+
google::bigtable::v2::Value const&,
239+
google::bigtable::v2::Type const&);
240+
static StatusOr<float> GetValue(float, google::bigtable::v2::Value const&,
241+
google::bigtable::v2::Type const&);
242+
static StatusOr<double> GetValue(double, google::bigtable::v2::Value const&,
243+
google::bigtable::v2::Type const&);
244+
static StatusOr<std::string> GetValue(std::string const&,
245+
google::bigtable::v2::Value const&,
246+
google::bigtable::v2::Type const&);
247+
static StatusOr<std::string> GetValue(std::string const&,
248+
google::bigtable::v2::Value&&,
249+
google::bigtable::v2::Type const&);
165250

166251
template <typename T, typename V>
167252
static StatusOr<absl::optional<T>> GetValue(

0 commit comments

Comments
 (0)