15#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_NUMERIC_H
16#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_NUMERIC_H
18#include "google/cloud/spanner/version.h"
19#include "google/cloud/status.h"
20#include "google/cloud/status_or.h"
21#include "absl/numeric/int128.h"
22#include "absl/strings/string_view.h"
36GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
55GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
58namespace spanner_internal {
59GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
61StatusOr<
spanner::Decimal<Mode>> MakeDecimal(std::string);
62GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
66GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
105 static constexpr std::size_t
kIntPrec = 29;
106 static constexpr std::size_t
kFracPrec = 9;
114 Decimal(Decimal&&)
noexcept =
default;
115 Decimal&
operator=(Decimal&&)
noexcept =
default;
116 Decimal(Decimal
const&) =
default;
117 Decimal&
operator=(Decimal
const&) =
default;
121
122
123
124
125
126
127
128
129
130
132 std::string
const&
ToString()
const& {
return rep_; }
133 std::string&&
ToString() && {
return std::move(rep_); }
138 friend bool operator==(Decimal
const& a, Decimal
const& b) {
144 return a.rep_ == b.rep_;
146 friend bool operator!=(Decimal
const& a, Decimal
const& b) {
152 friend std::ostream& operator<<(std::ostream& os, Decimal
const& d) {
153 return os << d.ToString();
158 friend StatusOr<Decimal<Mode>> spanner_internal::
159#if defined(__GNUC__
) && !defined(__clang__
)
160 GOOGLE_CLOUD_CPP_NS::
162 MakeDecimal(std::string);
164 explicit Decimal(std::string rep) : rep_(std::move(rep)) {}
170constexpr std::size_t Decimal<Mode>::
kIntPrec;
172constexpr std::size_t Decimal<Mode>::
kFracPrec;
174GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
178namespace spanner_internal {
179GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
181Status DataLoss(std::string message);
185std::string ToString(T&& value) {
186 return std::to_string(std::forward<T>(value));
188std::string ToString(absl::int128 value);
189std::string ToString(absl::uint128 value);
191StatusOr<std::string> MakeDecimalRep(std::string s,
bool has_nan,
192 std::size_t int_prec,
193 std::size_t frac_prec);
194StatusOr<std::string> MakeDecimalRep(
double d);
197StatusOr<
spanner::Decimal<Mode>> MakeDecimal(std::string s) {
198 auto rep = MakeDecimalRep(std::move(s),
spanner::Decimal<Mode>::kHasNaN,
199 spanner::Decimal<Mode>::kIntPrecision,
200 spanner::Decimal<Mode>::kFracPrecision);
201 if (!rep)
return std::move(rep).status();
202 return spanner::Decimal<Mode>(*std::move(rep));
207StatusOr<
spanner::Decimal<Mode>> MakeDecimal(std::string s,
int exponent) {
208 if (exponent != 0) s +=
'e' + std::to_string(exponent);
209 return MakeDecimal<Mode>(std::move(s));
212GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
216GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
219
220
221
222
223
224
225
226
227
228
229
230
231
232
234StatusOr<Decimal<Mode>>
MakeDecimal(std::string s) {
235 return spanner_internal::MakeDecimal<Mode>(std::move(s));
239
240
241
242
243
244
245
248 auto rep = spanner_internal::MakeDecimalRep(d);
249 if (!rep)
return std::move(rep)
.status();
250 return spanner_internal::MakeDecimal<Mode>(
*std::move(rep));
254
255
256
257
261 typename std::enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0
264StatusOr<Decimal<Mode>>
MakeDecimal(T i,
int exponent = 0) {
265 return spanner_internal::MakeDecimal<Mode>(spanner_internal::ToString(i),
270
271
272
273
274
276double ToDouble(Decimal<Mode>
const& d) {
277 return std::atof(d.ToString().c_str());
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
300 typename std::enable_if<std::numeric_limits<T>::is_integer &&
301 !std::numeric_limits<T>::is_signed,
306 Decimal<Mode>
const& d,
int exponent = 0) {
307 std::string
const& rep = d.ToString();
309 auto const en = spanner_internal::MakeDecimal<Mode>(rep, exponent);
310 return en ? ToInteger<T>(*en, 0) : en.status();
313 constexpr auto kDigits =
"0123456789";
314 constexpr auto kMax = (std::numeric_limits<T>::max)();
315 enum { kIntPart, kFracPart } state = kIntPart;
316 for (
auto const ch : rep) {
317 auto const* dp = std::strchr(kDigits, ch);
318 if (state == kFracPart) {
319 if (dp - kDigits >= 5) {
320 if (v == kMax)
return spanner_internal::DataLoss(rep);
321 v =
static_cast<T>(v + 1);
326 if (ch ==
'-')
return spanner_internal::DataLoss(rep);
329 if (v > kMax / 10)
return spanner_internal::DataLoss(rep);
330 v =
static_cast<T>(v * 10);
331 auto dv =
static_cast<T>(dp - kDigits);
332 if (v > kMax - dv)
return spanner_internal::DataLoss(rep);
333 v =
static_cast<T>(v + dv);
340 typename std::enable_if<std::numeric_limits<T>::is_integer &&
341 std::numeric_limits<T>::is_signed,
345StatusOr<T> ToInteger(
346 Decimal<Mode>
const& d,
int exponent = 0) {
347 std::string
const& rep = d.ToString();
349 auto const en = spanner_internal::MakeDecimal<Mode>(rep, exponent);
350 return en ? ToInteger<T>(*en, 0) : en.status();
353 constexpr auto kDigits =
"0123456789";
354 constexpr auto kMin = (std::numeric_limits<T>::min)();
356 enum { kIntPart, kFracPart } state = kIntPart;
357 for (
auto const ch : rep) {
358 auto const* dp = std::strchr(kDigits, ch);
359 if (state == kFracPart) {
360 if (dp - kDigits >= 5) {
361 if (v == kMin)
return spanner_internal::DataLoss(rep);
362 v =
static_cast<T>(v - 1);
373 if (v < kMin / 10)
return spanner_internal::DataLoss(rep);
374 v =
static_cast<T>(v * 10);
375 auto dv =
static_cast<T>(dp - kDigits);
376 if (v < kMin + dv)
return spanner_internal::DataLoss(rep);
377 v =
static_cast<T>(v - dv);
380 if (!negate)
return v;
381 constexpr auto kMax = (std::numeric_limits<T>::max)();
382 if (kMin != -kMax && v == kMin)
return spanner_internal::DataLoss(rep);
383 return static_cast<T>(-v);
388
389
390
391
392
393
394
395
396
403
404
406inline StatusOr<Numeric>
MakeNumeric(std::string s) {
415 typename std::enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0
418StatusOr<Numeric>
MakeNumeric(T i,
int exponent = 0) {
424
425
436 typename std::enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0
444GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
friend bool operator==(Decimal const &a, Decimal const &b)
Definition: numeric.h:138
Decimal & operator=(Decimal &&) noexcept=default
static constexpr std::size_t kFracPrec
Definition: numeric.h:106
static constexpr std::size_t kIntPrec
Definition: numeric.h:105
Decimal(Decimal const &)=default
static std::size_t const kIntPrecision
Definition: numeric.h:94
Decimal & operator=(Decimal const &)=default
friend bool operator!=(Decimal const &a, Decimal const &b)
Definition: numeric.h:146
Decimal()
A zero value.
Definition: numeric.h:110
std::string const & ToString() const &
Conversion to a decimal-string representation of the Decimal in one of the following forms:
Definition: numeric.h:132
Decimal(Decimal &&) noexcept=default
static bool const kHasNaN
Whether DecimalMode supports NaN values.
Definition: numeric.h:99
std::string && ToString() &&
Conversion to a decimal-string representation of the Decimal in one of the following forms:
Definition: numeric.h:133
static std::size_t const kFracPrecision
Definition: numeric.h:95
Contains all the Cloud Spanner C++ client types and functions.
Definition: backoff_policy.h:23
StatusOr< Decimal< Mode > > MakeDecimal(double d)
Construction from a double.
Definition: numeric.h:247
StatusOr< Numeric > MakeNumeric(double d)
MakeNumeric() factory functions for Numeric.
Definition: numeric.h:409
DecimalMode
Definition: numeric.h:39
StatusOr< Decimal< Mode > > MakeDecimal(T i, int exponent=0)
Construction from an integer i, scaled by 10^exponent.
Definition: numeric.h:264
StatusOr< PgNumeric > MakePgNumeric(T i, int exponent=0)
MakePgNumeric() factory functions for PgNumeric.
Definition: numeric.h:439
StatusOr< Numeric > MakeNumeric(T i, int exponent=0)
MakeNumeric() factory functions for Numeric.
Definition: numeric.h:418
StatusOr< PgNumeric > MakePgNumeric(std::string s)
MakePgNumeric() factory functions for PgNumeric.
Definition: numeric.h:427
StatusOr< Decimal< Mode > > MakeDecimal(std::string s)
Construction from a string, in decimal fixed- or floating-point formats.
Definition: numeric.h:234
StatusOr< PgNumeric > MakePgNumeric(double d)
MakePgNumeric() factory functions for PgNumeric.
Definition: numeric.h:430
double ToDouble(Decimal< Mode > const &d)
Conversion to the closest double value, with possible loss of precision.
Definition: numeric.h:276
StatusOr< T > ToInteger(Decimal< Mode > const &d, int exponent=0)
Conversion to the nearest integer value, scaled by 10^exponent.
Definition: numeric.h:305
StatusOr< Numeric > MakeNumeric(std::string s)
MakeNumeric() factory functions for Numeric.
Definition: numeric.h:406