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"
27 #include <type_traits>
39 namespace spanner_internal {
45 std::string ToString(T&& value) {
46 return std::to_string(std::forward<T>(value));
48 std::string ToString(absl::int128 value);
49 std::string ToString(absl::uint128 value);
52 Status DataLoss(std::string message);
53 StatusOr<
spanner::
Numeric> MakeNumeric(std::string s,
int exponent);
115 std::string
const&
ToString()
const& {
return rep_; }
116 std::string&&
ToString() && {
return std::move(rep_); }
122 return a.rep_ == b.rep_;
130 friend std::ostream& operator<<(std::ostream& os,
Numeric const& n) {
137 explicit Numeric(std::string rep) : rep_(std::move(rep)) {}
172 template <
typename T,
typename std::enable_if<
173 std::numeric_limits<T>::is_integer,
int>::type = 0>
175 return spanner_internal::MakeNumeric(spanner_internal::ToString(i), exponent);
204 template <
typename T,
205 typename std::enable_if<std::numeric_limits<T>::is_integer &&
206 !std::numeric_limits<T>::is_signed,
209 Numeric const& n,
int exponent = 0) {
212 auto const en = spanner_internal::MakeNumeric(rep, exponent);
213 return en ? ToInteger<T>(
*en, 0) : en
.status();
216 constexpr auto kDigits =
"0123456789";
217 constexpr auto kMax = (std::numeric_limits<T>::max)();
218 enum { kIntPart, kFracPart } state = kIntPart;
219 for (
auto const ch : rep) {
220 auto const* dp = std::strchr(kDigits, ch);
221 if (state == kFracPart) {
222 if (dp - kDigits >= 5) {
223 if (v == kMax)
return spanner_internal::DataLoss(rep);
224 v =
static_cast<T>(v + 1);
229 if (ch ==
'-')
return spanner_internal::DataLoss(rep);
232 if (v > kMax / 10)
return spanner_internal::DataLoss(rep);
233 v =
static_cast<T>(v * 10);
234 auto d =
static_cast<T>(dp - kDigits);
235 if (v > kMax - d)
return spanner_internal::DataLoss(rep);
236 v =
static_cast<T>(v + d);
242 template <
typename T,
243 typename std::enable_if<std::numeric_limits<T>::is_integer &&
244 std::numeric_limits<T>::is_signed,
246 StatusOr<T> ToInteger(
247 Numeric const& n,
int exponent = 0) {
250 auto const en = spanner_internal::MakeNumeric(rep, exponent);
251 return en ? ToInteger<T>(
*en, 0) : en
.status();
254 constexpr auto kDigits =
"0123456789";
255 constexpr auto kMin = (std::numeric_limits<T>::min)();
257 enum { kIntPart, kFracPart } state = kIntPart;
258 for (
auto const ch : rep) {
259 auto const* dp = std::strchr(kDigits, ch);
260 if (state == kFracPart) {
261 if (dp - kDigits >= 5) {
262 if (v == kMin)
return spanner_internal::DataLoss(rep);
263 v =
static_cast<T>(v - 1);
274 if (v < kMin / 10)
return spanner_internal::DataLoss(rep);
275 v =
static_cast<T>(v * 10);
276 auto d =
static_cast<T>(dp - kDigits);
277 if (v < kMin + d)
return spanner_internal::DataLoss(rep);
278 v =
static_cast<T>(v - d);
281 if (!negate)
return v;
282 constexpr auto kMax = (std::numeric_limits<T>::max)();
283 if (kMin != -kMax && v == kMin)
return spanner_internal::DataLoss(rep);
284 return static_cast<T>(-v);