15 #include "google/cloud/spanner/numeric.h"
16 #include "google/cloud/status.h"
17 #include "absl/strings/string_view.h"
32 namespace spanner_internal {
37 inline bool IsDigit(
char ch) {
38 return std::isdigit(
static_cast<
unsigned char>(ch)) != 0;
41 inline bool IsSpace(
char ch) {
42 return std::isspace(
static_cast<
unsigned char>(ch)) != 0;
45 Status InvalidArgument(std::string message) {
49 Status OutOfRange(std::string message) {
54 bool IsCanonical(absl::string_view sign_part, absl::string_view int_part,
55 absl::string_view frac_part) {
56 if (int_part.empty())
return false;
59 if (int_part.size() == 1 && int_part.front() ==
'0') {
60 if (frac_part.empty()) {
61 if (!sign_part.empty())
return false;
63 if (!sign_part.empty() && sign_part.front() ==
'+')
return false;
64 if (frac_part.size() == 1 || frac_part.back() ==
'0')
return false;
67 if (!sign_part.empty() && sign_part.front() ==
'+')
return false;
68 if (int_part.front() ==
'0')
return false;
69 if (frac_part.size() == 1)
return false;
70 if (!frac_part.empty() && frac_part.back() ==
'0')
return false;
77 void Round(std::deque<
char>& int_rep, std::deque<
char>& frac_rep,
79 static constexpr auto kDigits =
"0123456789";
81 auto it = frac_rep.begin() + (std::min)(prec, frac_rep.size());
82 if (frac_rep.size() <= prec || std::strchr(kDigits, *it) - kDigits < 5) {
84 while (it != frac_rep.begin() && *(it - 1) ==
'0') --it;
85 frac_rep.erase(it, frac_rep.end());
90 while (it != frac_rep.begin()) {
92 *it = *(std::strchr(kDigits, *it) + 1);
93 frac_rep.erase(++it, frac_rep.end());
100 int_rep.push_front(
'0');
102 while (*--it ==
'9') *it =
'0';
103 *it = *(std::strchr(kDigits, *it) + 1);
108 std::string ToString(absl::int128 value) {
109 std::ostringstream ss;
111 return std::move(ss).str();
114 std::string ToString(absl::uint128 value) {
115 std::ostringstream ss;
117 return std::move(ss).str();
120 Status DataLoss(std::string message) {
138 char const* p = s.c_str();
139 char const* e = p + s.size();
142 auto sign_part = absl::string_view(p, 0);
143 if (p != e && (*p ==
'+' || *p ==
'-')) {
144 sign_part = absl::string_view(p++, 1);
149 for (; p != e && IsDigit(*p); ++p)
continue;
150 auto int_part = absl::string_view(ip, p - ip);
153 auto frac_part = absl::string_view(p, 0);
154 if (p != e && *p ==
'.') {
155 char const* fp = p++;
156 for (; p != e && IsDigit(*p); ++p)
continue;
157 frac_part = absl::string_view(fp, p - fp);
161 if (p == e && IsCanonical(sign_part, int_part, frac_part)) {
167 if (p != e && (*p ==
'e' || *p ==
'E')) {
168 if (p + 1 != e && !IsSpace(*(p + 1))) {
171 exponent = std::strtol(p + 1, &ep, 10);
173 if (errno != 0)
return OutOfRange(std::move(s));
180 if (p != e)
return InvalidArgument(std::move(s));
183 if (int_part.empty() && frac_part.size() <= 1) {
184 return InvalidArgument(std::move(s));
187 auto int_rep = std::deque<
char>(int_part.begin(), int_part.end());
188 auto frac_rep = std::deque<
char>(frac_part.begin(), frac_part.end());
189 if (!frac_rep.empty()) frac_rep.pop_front();
193 auto shift = std::min<std::size_t>(exponent, frac_rep.size());
194 int_rep.insert(int_rep.end(), frac_rep.begin(), frac_rep.begin() + shift);
195 int_rep.insert(int_rep.end(), exponent - shift,
'0');
196 frac_rep.erase(frac_rep.begin(), frac_rep.begin() + shift);
198 auto shift = std::min<std::size_t>(-exponent, int_rep.size());
199 frac_rep.insert(frac_rep.begin(), int_rep.end() - shift, int_rep.end());
200 frac_rep.insert(frac_rep.begin(), -exponent - shift,
'0');
201 int_rep.erase(int_rep.end() - shift, int_rep.end());
208 while (!int_rep.empty() && int_rep.front() ==
'0') int_rep.pop_front();
210 return OutOfRange(std::move(s));
214 bool empty = int_rep.empty() && frac_rep.empty();
215 bool negate = !empty && !sign_part.empty() && sign_part.front() ==
'-';
216 if (int_rep.empty()) int_rep.push_front(
'0');
217 if (negate) int_rep.push_front(
'-');
218 if (!frac_rep.empty()) frac_rep.push_front(
'.');
222 rep.reserve(int_rep.size() + frac_rep.size());
223 rep.append(int_rep.begin(), int_rep.end());
224 rep.append(frac_rep.begin(), frac_rep.end());
229 StatusOr<
spanner::
Numeric> MakeNumeric(std::string s,
int exponent) {
230 if (exponent != 0) s +=
'e' + std::to_string(exponent);
231 return MakeNumeric(std::move(s));
246 return spanner_internal::MakeNumeric(std::move(s));
250 std::ostringstream ss;
251 ss.imbue(std::locale::classic());
252 ss << std::setprecision(std::numeric_limits<
double>::digits10 + 1) << d;
253 std::string s = std::move(ss).str();
254 if (!std::isfinite(d))
return spanner_internal::OutOfRange(std::move(s));
255 return spanner_internal::MakeNumeric(std::move(s));