|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
#include <cstdint> |
|
#include <iosfwd> |
|
#include <limits> |
|
#include <string> |
|
#include <string_view> |
|
#include <utility> |
|
|
|
#include "arrow/result.h" |
|
#include "arrow/status.h" |
|
#include "arrow/type_fwd.h" |
|
#include "arrow/util/basic_decimal.h" |
|
|
|
namespace arrow { |
|
|
|
class Decimal64; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ARROW_EXPORT Decimal32 : public BasicDecimal32 { |
|
public: |
|
|
|
|
|
using BasicDecimal32::BasicDecimal32; |
|
|
|
|
|
|
|
constexpr Decimal32(const BasicDecimal32& value) noexcept |
|
: BasicDecimal32(value) {} |
|
|
|
|
|
explicit Decimal32(const std::string& value); |
|
|
|
|
|
|
|
constexpr Decimal32() noexcept : BasicDecimal32() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result<std::pair<Decimal32, Decimal32>> Divide(const Decimal32& divisor) const { |
|
std::pair<Decimal32, Decimal32> result; |
|
auto dstatus = BasicDecimal32::Divide(divisor, &result.first, &result.second); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return result; |
|
} |
|
|
|
|
|
std::string ToString(int32_t scale) const; |
|
|
|
|
|
std::string ToIntegerString() const; |
|
|
|
|
|
explicit operator int64_t() const; |
|
|
|
explicit operator Decimal64() const; |
|
|
|
|
|
|
|
static Status FromString(std::string_view s, Decimal32* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const std::string& s, Decimal32* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const char* s, Decimal32* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Result<Decimal32> FromString(std::string_view s); |
|
static Result<Decimal32> FromString(const std::string& s); |
|
static Result<Decimal32> FromString(const char* s); |
|
|
|
static Result<Decimal32> FromReal(double real, int32_t precision, int32_t scale); |
|
static Result<Decimal32> FromReal(float real, int32_t precision, int32_t scale); |
|
|
|
|
|
|
|
|
|
static Result<Decimal32> FromBigEndian(const uint8_t* data, int32_t length); |
|
|
|
|
|
Result<Decimal32> Rescale(int32_t original_scale, int32_t new_scale) const { |
|
Decimal32 out; |
|
auto dstatus = BasicDecimal32::Rescale(original_scale, new_scale, &out); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return out; |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Result<T> ToInteger() const { |
|
return static_cast<T>(value_); |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Status ToInteger(T* out) const { |
|
return ToInteger<T>().Value(out); |
|
} |
|
|
|
|
|
float ToFloat(int32_t scale) const; |
|
|
|
double ToDouble(int32_t scale) const; |
|
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> |
|
T ToReal(int32_t scale) const { |
|
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>, |
|
"Unexpected floating-point type"); |
|
if constexpr (std::is_same_v<T, float>) { |
|
return ToFloat(scale); |
|
} else { |
|
return ToDouble(scale); |
|
} |
|
} |
|
|
|
ARROW_FRIEND_EXPORT friend std::ostream& operator<<(std::ostream& os, |
|
const Decimal32& decimal); |
|
|
|
private: |
|
|
|
Status ToArrowStatus(DecimalStatus dstatus) const; |
|
}; |
|
|
|
class ARROW_EXPORT Decimal64 : public BasicDecimal64 { |
|
public: |
|
|
|
|
|
using BasicDecimal64::BasicDecimal64; |
|
|
|
|
|
|
|
constexpr Decimal64(const BasicDecimal64& value) noexcept |
|
: BasicDecimal64(value) {} |
|
|
|
explicit Decimal64(const BasicDecimal32& value) noexcept |
|
: BasicDecimal64(static_cast<int64_t>(value.value())) {} |
|
|
|
|
|
explicit Decimal64(const std::string& value); |
|
|
|
|
|
|
|
constexpr Decimal64() noexcept : BasicDecimal64() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result<std::pair<Decimal64, Decimal64>> Divide(const Decimal64& divisor) const { |
|
std::pair<Decimal64, Decimal64> result; |
|
auto dstatus = BasicDecimal64::Divide(divisor, &result.first, &result.second); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return result; |
|
} |
|
|
|
|
|
std::string ToString(int32_t scale) const; |
|
|
|
|
|
std::string ToIntegerString() const; |
|
|
|
|
|
explicit operator int64_t() const; |
|
|
|
|
|
|
|
static Status FromString(std::string_view s, Decimal64* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const std::string& s, Decimal64* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const char* s, Decimal64* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Result<Decimal64> FromString(std::string_view s); |
|
static Result<Decimal64> FromString(const std::string& s); |
|
static Result<Decimal64> FromString(const char* s); |
|
|
|
static Result<Decimal64> FromReal(double real, int32_t precision, int32_t scale); |
|
static Result<Decimal64> FromReal(float real, int32_t precision, int32_t scale); |
|
|
|
|
|
|
|
|
|
static Result<Decimal64> FromBigEndian(const uint8_t* data, int32_t length); |
|
|
|
|
|
Result<Decimal64> Rescale(int32_t original_scale, int32_t new_scale) const { |
|
Decimal64 out; |
|
auto dstatus = BasicDecimal64::Rescale(original_scale, new_scale, &out); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return out; |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Result<T> ToInteger() const { |
|
return static_cast<T>(value_); |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Status ToInteger(T* out) const { |
|
return ToInteger<T>().Value(out); |
|
} |
|
|
|
|
|
float ToFloat(int32_t scale) const; |
|
|
|
double ToDouble(int32_t scale) const; |
|
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> |
|
T ToReal(int32_t scale) const { |
|
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>, |
|
"Unexpected floating-point type"); |
|
if constexpr (std::is_same_v<T, float>) { |
|
return ToFloat(scale); |
|
} else { |
|
return ToDouble(scale); |
|
} |
|
} |
|
|
|
ARROW_FRIEND_EXPORT friend std::ostream& operator<<(std::ostream& os, |
|
const Decimal64& decimal); |
|
|
|
private: |
|
|
|
Status ToArrowStatus(DecimalStatus dstatus) const; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ARROW_EXPORT Decimal128 : public BasicDecimal128 { |
|
public: |
|
|
|
|
|
using BasicDecimal128::BasicDecimal128; |
|
|
|
|
|
|
|
constexpr Decimal128(const BasicDecimal128& value) noexcept |
|
: BasicDecimal128(value) {} |
|
|
|
|
|
explicit Decimal128(const std::string& value); |
|
|
|
|
|
|
|
constexpr Decimal128() noexcept : BasicDecimal128() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result<std::pair<Decimal128, Decimal128>> Divide(const Decimal128& divisor) const { |
|
std::pair<Decimal128, Decimal128> result; |
|
auto dstatus = BasicDecimal128::Divide(divisor, &result.first, &result.second); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return result; |
|
} |
|
|
|
|
|
|
|
std::string ToString(int32_t scale) const; |
|
|
|
|
|
std::string ToIntegerString() const; |
|
|
|
|
|
explicit operator int64_t() const; |
|
|
|
|
|
|
|
static Status FromString(std::string_view s, Decimal128* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const std::string& s, Decimal128* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const char* s, Decimal128* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Result<Decimal128> FromString(std::string_view s); |
|
static Result<Decimal128> FromString(const std::string& s); |
|
static Result<Decimal128> FromString(const char* s); |
|
|
|
static Result<Decimal128> FromReal(double real, int32_t precision, int32_t scale); |
|
static Result<Decimal128> FromReal(float real, int32_t precision, int32_t scale); |
|
|
|
|
|
|
|
|
|
static Result<Decimal128> FromBigEndian(const uint8_t* data, int32_t length); |
|
|
|
|
|
Result<Decimal128> Rescale(int32_t original_scale, int32_t new_scale) const { |
|
Decimal128 out; |
|
auto dstatus = BasicDecimal128::Rescale(original_scale, new_scale, &out); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return out; |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Result<T> ToInteger() const { |
|
constexpr auto min_value = std::numeric_limits<T>::min(); |
|
constexpr auto max_value = std::numeric_limits<T>::max(); |
|
const auto& self = *this; |
|
if (self < min_value || self > max_value) { |
|
return Status::Invalid("Invalid cast from Decimal128 to ", sizeof(T), |
|
" byte integer"); |
|
} |
|
return static_cast<T>(low_bits()); |
|
} |
|
|
|
|
|
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>> |
|
Status ToInteger(T* out) const { |
|
return ToInteger<T>().Value(out); |
|
} |
|
|
|
|
|
float ToFloat(int32_t scale) const; |
|
|
|
double ToDouble(int32_t scale) const; |
|
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> |
|
T ToReal(int32_t scale) const { |
|
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>, |
|
"Unexpected floating-point type"); |
|
if constexpr (std::is_same_v<T, float>) { |
|
return ToFloat(scale); |
|
} else { |
|
return ToDouble(scale); |
|
} |
|
} |
|
|
|
ARROW_FRIEND_EXPORT friend std::ostream& operator<<(std::ostream& os, |
|
const Decimal128& decimal); |
|
|
|
private: |
|
|
|
Status ToArrowStatus(DecimalStatus dstatus) const; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ARROW_EXPORT Decimal256 : public BasicDecimal256 { |
|
public: |
|
|
|
|
|
using BasicDecimal256::BasicDecimal256; |
|
|
|
|
|
|
|
constexpr Decimal256(const BasicDecimal256& value) noexcept |
|
: BasicDecimal256(value) {} |
|
|
|
|
|
explicit Decimal256(const std::string& value); |
|
|
|
|
|
|
|
constexpr Decimal256() noexcept : BasicDecimal256() {} |
|
|
|
|
|
|
|
std::string ToString(int32_t scale) const; |
|
|
|
|
|
std::string ToIntegerString() const; |
|
|
|
|
|
|
|
static Status FromString(std::string_view s, Decimal256* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const std::string& s, Decimal256* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Status FromString(const char* s, Decimal256* out, int32_t* precision, |
|
int32_t* scale = NULLPTR); |
|
static Result<Decimal256> FromString(std::string_view s); |
|
static Result<Decimal256> FromString(const std::string& s); |
|
static Result<Decimal256> FromString(const char* s); |
|
|
|
|
|
Result<Decimal256> Rescale(int32_t original_scale, int32_t new_scale) const { |
|
Decimal256 out; |
|
auto dstatus = BasicDecimal256::Rescale(original_scale, new_scale, &out); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return out; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Result<std::pair<Decimal256, Decimal256>> Divide(const Decimal256& divisor) const { |
|
std::pair<Decimal256, Decimal256> result; |
|
auto dstatus = BasicDecimal256::Divide(divisor, &result.first, &result.second); |
|
ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus)); |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
static Result<Decimal256> FromBigEndian(const uint8_t* data, int32_t length); |
|
|
|
static Result<Decimal256> FromReal(double real, int32_t precision, int32_t scale); |
|
static Result<Decimal256> FromReal(float real, int32_t precision, int32_t scale); |
|
|
|
|
|
|
|
float ToFloat(int32_t scale) const; |
|
|
|
double ToDouble(int32_t scale) const; |
|
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> |
|
T ToReal(int32_t scale) const { |
|
static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>, |
|
"Unexpected floating-point type"); |
|
if constexpr (std::is_same_v<T, float>) { |
|
return ToFloat(scale); |
|
} else { |
|
return ToDouble(scale); |
|
} |
|
} |
|
|
|
ARROW_FRIEND_EXPORT friend std::ostream& operator<<(std::ostream& os, |
|
const Decimal256& decimal); |
|
|
|
private: |
|
|
|
Status ToArrowStatus(DecimalStatus dstatus) const; |
|
}; |
|
|
|
|
|
|
|
inline Result<int32_t> MaxDecimalDigitsForInteger(Type::type type_id) { |
|
switch (type_id) { |
|
case Type::INT8: |
|
case Type::UINT8: |
|
return 3; |
|
case Type::INT16: |
|
case Type::UINT16: |
|
return 5; |
|
case Type::INT32: |
|
case Type::UINT32: |
|
return 10; |
|
case Type::INT64: |
|
return 19; |
|
case Type::UINT64: |
|
return 20; |
|
default: |
|
break; |
|
} |
|
return Status::Invalid("Not an integer type: ", type_id); |
|
} |
|
|
|
} |
|
|