MCPcopy Create free account
hub / github.com/apache/arrow / DecimalFromString

Function DecimalFromString

cpp/src/arrow/util/decimal.cc:863–928  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

861
862template <typename Decimal>
863Status DecimalFromString(const char* type_name, std::string_view s, Decimal* out,
864 int32_t* precision, int32_t* scale) {
865 if (s.empty()) {
866 return Status::Invalid("Empty string cannot be converted to ", type_name);
867 }
868
869 DecimalComponents dec;
870 if (!ParseDecimalComponents(s.data(), s.size(), &dec)) {
871 return Status::Invalid("The string '", s, "' is not a valid ", type_name, " number");
872 }
873
874 // Count number of significant digits (without leading zeros)
875 size_t first_non_zero = dec.whole_digits.find_first_not_of('0');
876 size_t significant_digits = dec.fractional_digits.size();
877 if (first_non_zero != std::string::npos) {
878 significant_digits += dec.whole_digits.size() - first_non_zero;
879 }
880 int32_t parsed_precision = static_cast<int32_t>(significant_digits);
881
882 int32_t parsed_scale = 0;
883 if (dec.has_exponent) {
884 // parsed_scale = -exponent + fractional_digits, computed with overflow
885 // detection: an exponent of INT32_MIN ("0E-2147483648") makes the negation,
886 // and a near-INT32_MIN exponent the addition, signed-overflow UB otherwise.
887 if (internal::SubtractWithOverflow(static_cast<int32_t>(dec.fractional_digits.size()),
888 dec.exponent, &parsed_scale)) {
889 return Status::Invalid("The string '", s, "' cannot be represented as ", type_name);
890 }
891 } else {
892 parsed_scale = static_cast<int32_t>(dec.fractional_digits.size());
893 }
894
895 if (out != nullptr) {
896 static_assert(Decimal::kBitWidth % 64 == 0, "decimal bit-width not a multiple of 64");
897 std::array<uint64_t, Decimal::kBitWidth / 64> little_endian_array{};
898 ShiftAndAdd(dec.whole_digits, little_endian_array.data(), little_endian_array.size());
899 ShiftAndAdd(dec.fractional_digits, little_endian_array.data(),
900 little_endian_array.size());
901 *out = Decimal(bit_util::little_endian::ToNative(little_endian_array));
902 if (dec.sign == '-') {
903 out->Negate();
904 }
905 }
906
907 if (parsed_scale < 0) {
908 // Force the scale to zero, to avoid negative scales (due to compatibility issues
909 // with external systems such as databases)
910 if (-parsed_scale > Decimal::kMaxScale) {
911 return Status::Invalid("The string '", s, "' cannot be represented as ", type_name);
912 }
913 if (out != nullptr) {
914 *out *= Decimal::GetScaleMultiplier(-parsed_scale);
915 }
916 parsed_precision -= parsed_scale;
917 parsed_scale = 0;
918 }
919
920 if (precision != nullptr) {

Callers 1

FromStringMethod · 0.70

Calls 11

ParseDecimalComponentsFunction · 0.85
ShiftAndAddFunction · 0.85
ToNativeFunction · 0.85
GetScaleMultiplierFunction · 0.85
NegateMethod · 0.80
InvalidFunction · 0.50
DecimalClass · 0.50
OKFunction · 0.50
emptyMethod · 0.45
dataMethod · 0.45
sizeMethod · 0.45

Tested by

no test coverage detected