Page MenuHomePhabricator (Chris)

mc-dec128.h
No OneTemporary

Authored By
Unknown
Size
23 KB
Referenced Files
None
Subscribers
None

mc-dec128.h

#ifndef MC_DEC128_H_INCLUDED
#define MC_DEC128_H_INCLUDED
#include <bson/bson.h>
#include <mc-mlib/endian.h>
#include <mc-mlib/int128.h>
#include <mc-mlib/macros.h>
// Conditional preprocessor definition set by the usage of an intel_dfp from
// the ImportDFP.cmake script:
#ifndef MONGOCRYPT_INTELDFP
// Notify includers that Decimal128 is not available:
#define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT() false
#else // With IntelDFP:
// Tell includers that Decimal128 is okay:
#define MONGOCRYPT_HAVE_DECIMAL128_SUPPORT() true
// Include the header that declares the DFP functions, which may be macros that
// expand to renamed symbols:
#include <bid_conf.h>
#include <bid_functions.h>
#include <float.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
MLIB_C_LINKAGE_BEGIN
/// Rounding controls for Decimal128 operations
typedef enum mc_dec128_rounding_mode {
MC_DEC128_ROUND_NEAREST_EVEN = 0,
MC_DEC128_ROUND_DOWNWARD = 1,
MC_DEC128_ROUND_UPWARD = 2,
MC_DEC128_ROUND_TOWARD_ZERO = 3,
MC_DEC128_ROUND_NEAREST_AWAY = 4,
MC_DEC128_ROUND_DEFAULT = MC_DEC128_ROUND_NEAREST_EVEN,
} mc_dec128_rounding_mode;
typedef struct mc_dec128_flagset {
_IDEC_flags bits;
} mc_dec128_flagset;
// This alignment conditional is the same conditions used in Intel's DFP
// library, ensuring we match the ABI of the library without pulling the header
#if defined _MSC_VER
#if defined _M_IX86 && !defined __INTEL_COMPILER
#define _mcDec128Align(n)
#else
#define _mcDec128Align(n) __declspec(align(n))
#endif
#else
#if !defined HPUX_OS
#define _mcDec128Align(n) __attribute__((aligned(n)))
#else
#define _mcDec128Align(n)
#endif
#endif
typedef union _mcDec128Align(16) {
uint64_t _words[2];
#if !defined(__INTELLISENSE__) && defined(__GNUC__) && defined(__amd64) && !defined(__APPLE__) && !defined(__clang__)
// If supported by the compiler, emit a field that can be used to visualize
// the value in a debugger.
float value_ __attribute__((mode(TD)));
#endif
}
mc_dec128;
#undef _mcDec128Align
/// Expands to a dec128 constant value.
#ifdef __cplusplus
#define MC_DEC128_C(N) mc_dec128 _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
#else
#define MC_DEC128_C(N) _mcDec128Const(((N) < 0 ? -(N) : (N)), ((N) < 0 ? 1 : 0))
#endif
#define MC_DEC128(N) MLIB_INIT(mc_dec128) MC_DEC128_C(N)
#define _mcDec128Combination(Bits) ((uint64_t)(Bits) << (47))
#define _mcDec128ZeroExpCombo _mcDec128Combination(1 << 7 | 1 << 13 | 1 << 14)
#define _mcDec128Const(N, Negate) _mcDec128ConstFromParts(N, (_mcDec128ZeroExpCombo | ((uint64_t)(Negate) << 63)))
#define _mcDec128ConstFromParts(CoeffLow, HighWord) \
{ \
{ \
MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(CoeffLow) : (uint64_t)(HighWord), \
MLIB_IS_LITTLE_ENDIAN ? (uint64_t)(HighWord) : (uint64_t)(CoeffLow), \
}, \
}
static const mc_dec128 MC_DEC128_ZERO = MC_DEC128_C(0);
static const mc_dec128 MC_DEC128_ONE = MC_DEC128_C(1);
static const mc_dec128 MC_DEC128_MINUSONE = MC_DEC128_C(-1);
/// The greatest-magnitude finite negative value representable in a Decimal128
#define MC_DEC128_LARGEST_NEGATIVE mc_dec128_from_string("-9999999999999999999999999999999999E6111")
/// The least-magnitude non-zero negative value representable in a Decimal128
#define MC_DEC128_SMALLEST_NEGATIVE mc_dec128_from_string("-1E-6176")
/// The greatest-magnitude finite positive value representable in a Decimal128
#define MC_DEC128_LARGEST_POSITIVE mc_dec128_from_string("9999999999999999999999999999999999E6111")
/// The least-magnitude non-zero positive value representable in a Decimal128
#define MC_DEC128_SMALLEST_POSITIVE mc_dec128_from_string("1E-6176")
/// The normalized zero of Decimal128
#define MC_DEC128_NORMALIZED_ZERO MC_DEC128_C(0)
/// A zero of Decimal128 with the least exponent
#define MC_DEC128_NEGATIVE_EXPONENT_ZERO mc_dec128_from_string("0E-6176")
#define _mcDec128InfCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12)
#define _mcDec128QuietNaNCombo _mcDec128Combination(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | 1 << 11)
/// Positive infinity of Decimal128
#define MC_DEC128_POSITIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo)
/// Negative infinity of Decimal128
#define MC_DEC128_NEGATIVE_INFINITY _mcDec128ConstFromParts(0, _mcDec128InfCombo | 1ull << 63)
/// Positve quiet NaN of Decimal128
#define MC_DEC128_POSITIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo)
/// Negative quiet NaN of Decimal128
#define MC_DEC128_NEGATIVE_NAN _mcDec128ConstFromParts(0, _mcDec128QuietNaNCombo | 1ull << 63)
/// Convert an mc_dec128 value to a DFP 128-bit object
static inline BID_UINT128 _mc_to_bid128(mc_dec128 d) {
BID_UINT128 r;
memcpy(&r, &d, sizeof d);
return r;
}
/// Convert a DFP 128-bit object to a mc_dec128 value
static inline mc_dec128 _bid128_to_mc(BID_UINT128 d) {
mc_dec128 r;
memcpy(&r, &d, sizeof d);
return r;
}
/**
* @brief Convert a double-precision binary floating point value into the
* nearest Decimal128 value
*
* @param d The number to conver
* @param rnd The rounding mode in case the value is not exactly representable
* @param flags Out param for exception/error flags (Optional)
*/
static inline mc_dec128 mc_dec128_from_double_ex(double d, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
return _bid128_to_mc(binary64_to_bid128(d, rnd, flags ? &flags->bits : &zero_flags.bits));
}
/**
* @brief Convert a double-precision binary floating point value into the
* nearest Decimal128 value
*/
static inline mc_dec128 mc_dec128_from_double(double d) {
return mc_dec128_from_double_ex(d, MC_DEC128_ROUND_DEFAULT, NULL);
}
/**
* @brief Convert a string representation of a number into the nearest
* Decimal128 value
*
* @param s The string to parse. MUST be null-terminated
* @param rnd The rounding mode to use if the result is not representable
* @param flags Out param for exception/error flags (Optional)
*/
static inline mc_dec128 mc_dec128_from_string_ex(const char *s, mc_dec128_rounding_mode rnd, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
return _bid128_to_mc(bid128_from_string((char *)s, rnd, flags ? &flags->bits : &zero_flags.bits));
}
/**
* @brief Convert a string representation of a number into the nearest
* Decimal128 value
*/
static inline mc_dec128 mc_dec128_from_string(const char *s) {
return mc_dec128_from_string_ex(s, MC_DEC128_ROUND_DEFAULT, NULL);
}
/**
* @brief A type capable of holding a string rendering of a Decimal128 in
* engineering notation.
*/
typedef struct mc_dec128_string {
/// The character array of the rendered value. Null-terminated
char str[48];
} mc_dec128_string;
/**
* @brief Render a Decimal128 value as a string (in engineering notation)
*
* @param d The number to represent
* @param flags Output parameter for exception/error flags (optional)
*/
static inline mc_dec128_string mc_dec128_to_string_ex(mc_dec128 d, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
mc_dec128_string out = {{0}};
bid128_to_string(out.str, _mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits);
return out;
}
/**
* @brief Render a Decimal128 value as a string (in engineering notation)
*/
static inline mc_dec128_string mc_dec128_to_string(mc_dec128 d) {
return mc_dec128_to_string_ex(d, NULL);
}
/// Compare two dec128 numbers
#define DECL_IDF_COMPARE_1(Oper) \
static inline bool mc_dec128_##Oper##_ex(mc_dec128 left, mc_dec128 right, mc_dec128_flagset *flags) { \
mc_dec128_flagset zero_flags = {0}; \
return 0 \
!= bid128_quiet_##Oper(_mc_to_bid128(left), \
_mc_to_bid128(right), \
flags ? &flags->bits : &zero_flags.bits); \
} \
\
static inline bool mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \
return mc_dec128_##Oper##_ex(left, right, NULL); \
}
#define DECL_IDF_COMPARE(Op) DECL_IDF_COMPARE_1(Op)
DECL_IDF_COMPARE(equal)
DECL_IDF_COMPARE(not_equal)
DECL_IDF_COMPARE(greater)
DECL_IDF_COMPARE(greater_equal)
DECL_IDF_COMPARE(less)
DECL_IDF_COMPARE(less_equal)
#undef DECL_IDF_COMPARE
#undef DECL_IDF_COMPARE_1
/// Test properties of Decimal128 numbers
#define DECL_PREDICATE(Name, BIDName) \
static inline bool mc_dec128_##Name(mc_dec128 d) { return 0 != bid128_##BIDName(_mc_to_bid128(d)); }
DECL_PREDICATE(is_zero, isZero)
DECL_PREDICATE(is_negative, isSigned)
DECL_PREDICATE(is_inf, isInf)
DECL_PREDICATE(is_finite, isFinite)
DECL_PREDICATE(is_nan, isNaN)
#undef DECL_PREDICATE
/// Binary arithmetic operations on two Decimal128 numbers
#define DECL_IDF_BINOP_WRAPPER(Oper) \
static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 left, \
mc_dec128 right, \
mc_dec128_rounding_mode mode, \
mc_dec128_flagset *flags) { \
mc_dec128_flagset zero_flags = {0}; \
return _bid128_to_mc( \
bid128_##Oper(_mc_to_bid128(left), _mc_to_bid128(right), mode, flags ? &flags->bits : &zero_flags.bits)); \
} \
\
static inline mc_dec128 mc_dec128_##Oper(mc_dec128 left, mc_dec128 right) { \
return mc_dec128_##Oper##_ex(left, right, MC_DEC128_ROUND_DEFAULT, NULL); \
}
DECL_IDF_BINOP_WRAPPER(add)
DECL_IDF_BINOP_WRAPPER(mul)
DECL_IDF_BINOP_WRAPPER(div)
DECL_IDF_BINOP_WRAPPER(sub)
DECL_IDF_BINOP_WRAPPER(pow)
#undef DECL_IDF_BINOP_WRAPPER
/// Unary arithmetic operations on two Decimal128 numbers
#define DECL_IDF_UNOP_WRAPPER(Oper) \
static inline mc_dec128 mc_dec128_##Oper##_ex(mc_dec128 operand, mc_dec128_flagset *flags) { \
mc_dec128_flagset zero_flags = {0}; \
return _bid128_to_mc( \
bid128_##Oper(_mc_to_bid128(operand), MC_DEC128_ROUND_DEFAULT, flags ? &flags->bits : &zero_flags.bits)); \
} \
\
static inline mc_dec128 mc_dec128_##Oper(mc_dec128 operand) { return mc_dec128_##Oper##_ex(operand, NULL); }
DECL_IDF_UNOP_WRAPPER(log2)
DECL_IDF_UNOP_WRAPPER(log10)
#undef DECL_IDF_UNOP_WRAPPER
static inline mc_dec128
mc_dec128_round_integral_ex(mc_dec128 value, mc_dec128_rounding_mode direction, mc_dec128_flagset *flags) {
BID_UINT128 bid = _mc_to_bid128(value);
mc_dec128_flagset zero_flags = {0};
_IDEC_flags *fl = flags ? &flags->bits : &zero_flags.bits;
switch (direction) {
case MC_DEC128_ROUND_TOWARD_ZERO: return _bid128_to_mc(bid128_round_integral_zero(bid, fl));
case MC_DEC128_ROUND_NEAREST_AWAY: return _bid128_to_mc(bid128_round_integral_nearest_away(bid, fl));
case MC_DEC128_ROUND_NEAREST_EVEN: return _bid128_to_mc(bid128_round_integral_nearest_even(bid, fl));
case MC_DEC128_ROUND_DOWNWARD: return _bid128_to_mc(bid128_round_integral_negative(bid, fl));
case MC_DEC128_ROUND_UPWARD: return _bid128_to_mc(bid128_round_integral_positive(bid, fl));
default: abort();
}
}
static inline mc_dec128 mc_dec128_negate(mc_dec128 operand) {
return _bid128_to_mc(bid128_negate(_mc_to_bid128(operand)));
}
static inline mc_dec128 mc_dec128_abs(mc_dec128 operand) {
return _bid128_to_mc(bid128_abs(_mc_to_bid128(operand)));
}
/**
* @brief Scale the given Decimal128 by a power of ten
*
* @param fac The value being scaled
* @param exp The exponent: 10^exp is the scale factor
* @param rounding Rounding behavior
* @param flags Control/result flags
* @return mc_dec128 The product
*/
static inline mc_dec128
mc_dec128_scale_ex(mc_dec128 fac, long int exp, mc_dec128_rounding_mode rounding, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
return _bid128_to_mc(bid128_scalbln(_mc_to_bid128(fac), exp, rounding, flags ? &flags->bits : &zero_flags.bits));
}
/**
* @brief Scale the given Decimal128 by a power of ten
*
* @param fac The value being scaled
* @param exp The exponent: 10^exp is the scale factor
* @return mc_dec128 The product
*/
static inline mc_dec128 mc_dec128_scale(mc_dec128 fac, long int exp) {
return mc_dec128_scale_ex(fac, exp, MC_DEC128_ROUND_DEFAULT, NULL);
}
/// The result of a dec_128 modf operation
typedef struct mc_dec128_modf_result {
/// The whole part of the result
mc_dec128 whole;
/// The fractional part of the result
mc_dec128 frac;
} mc_dec128_modf_result;
/**
* @brief Split a Decimal128 into its whole and fractional parts.
*
* The "whole" value is the integral value of the Decimal128 rounded towards
* zero. The "frac" part is the remainder after removing the whole.
*
* @param d The value to inspect
* @param flags Results status flags
*/
static inline mc_dec128_modf_result mc_dec128_modf_ex(mc_dec128 d, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
mc_dec128_modf_result res;
BID_UINT128 whole;
res.frac = _bid128_to_mc(bid128_modf(_mc_to_bid128(d), &whole, flags ? &flags->bits : &zero_flags.bits));
res.whole = _bid128_to_mc(whole);
return res;
}
/**
* @brief Split a Decimal128 into its whole and fractional parts.
*
* The "whole" value is the integral value of the Decimal128 rounded towards
* zero. The "frac" part is the remainder after removing the whole.
*
* @param d The value to inspect
*/
static inline mc_dec128_modf_result mc_dec128_modf(mc_dec128 d) {
return mc_dec128_modf_ex(d, NULL);
}
/**
* @brief Compute the "fmod", the remainder after decimal division rounding
* towards zero.
*
* @param numer The dividend of the modulus
* @param denom The divisor of the modulus
* @param flags Control/status flags
*/
static inline mc_dec128 mc_dec128_fmod_ex(mc_dec128 numer, mc_dec128 denom, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
return _bid128_to_mc(
bid128_fmod(_mc_to_bid128(numer), _mc_to_bid128(denom), flags ? &flags->bits : &zero_flags.bits));
}
/**
* @brief Compute the "fmod", the remainder after decimal division rounding
* towards zero.
*
* @param numer The dividend of the modulus
* @param denom The divisor of the modulus
*/
static inline mc_dec128 mc_dec128_fmod(mc_dec128 numer, mc_dec128 denom) {
return mc_dec128_fmod_ex(numer, denom, NULL);
}
/**
* @brief Obtain the a 64-bit binary integer value for the given Decimal128
* value, nearest rounding toward zero.
*
* @param d The value to inspect
* @param flags Control/status flags
*/
static inline int64_t mc_dec128_to_int64_ex(mc_dec128 d, mc_dec128_flagset *flags) {
mc_dec128_flagset zero_flags = {0};
return bid128_to_int64_int(_mc_to_bid128(d), flags ? &flags->bits : &zero_flags.bits);
}
/**
* @brief Obtain the a 64-bit binary integer value for the given Decimal128
* value, nearest rounding toward zero.
*
* @param d The value to inspect
*/
static inline int64_t mc_dec128_to_int64(mc_dec128 d) {
return mc_dec128_to_int64_ex(d, NULL);
}
/// Constants for inspection/deconstruction of Decimal128
enum {
/// Least non-canonical combination bits value
MC_DEC128_COMBO_NONCANONICAL = 3 << 15,
/// Least combination value indicating infinity
MC_DEC128_COMBO_INFINITY = 0x1e << 12,
/// The greatest Decimal128 biased exponent
MC_DEC128_MAX_BIASED_EXPONENT = 6143 + 6144,
/// The exponent bias of Decimal128
MC_DEC128_EXPONENT_BIAS = 6143 + 33, // +33 to include the 34 decimal digits
/// Minimum exponent value (without bias)
MC_DEC_MIN_EXPONENT = -6143,
/// Maximum exponent value (without bias)
MC_DEC_MAX_EXPONENT = 6144,
};
/// Obtain the value of the combination bits of a decimal128
static inline uint32_t mc_dec128_combination(mc_dec128 d) {
// Grab the high 64 bits:
uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
// Sign is the 64th bit:
int signpos = 64 - 1;
// Combo is the next 16 bits:
int fieldpos = signpos - 17;
int fieldmask = (1 << 17) - 1;
return (uint32_t)((hi >> fieldpos) & (uint32_t)fieldmask);
}
/**
* @brief Obtain the value of the high 49 bits of the Decimal128 coefficient
*/
static inline uint64_t mc_dec128_coeff_high(mc_dec128 d) {
uint64_t hi_field_mask = (1ull << 49) - 1;
uint32_t combo = mc_dec128_combination(d);
if (combo < MC_DEC128_COMBO_NONCANONICAL) {
uint64_t hi = d._words[MLIB_IS_LITTLE_ENDIAN ? 1 : 0];
return hi & hi_field_mask;
} else {
return 0;
}
}
/**
* @brief Obtain the value of the low 64 bits of the Decimal128 coefficient
*/
static inline uint64_t mc_dec128_coeff_low(mc_dec128 d) {
uint32_t combo = mc_dec128_combination(d);
if (combo < MC_DEC128_COMBO_NONCANONICAL) {
uint64_t lo = d._words[MLIB_IS_LITTLE_ENDIAN ? 0 : 1];
return lo;
} else {
return 0;
}
}
/**
* @brief Obtain the full coefficient of the given Decimal128 number. Requires a
* 128-bit integer.
*/
static inline mlib_int128 mc_dec128_coeff(mc_dec128 d) {
// Hi bits
uint64_t hi = mc_dec128_coeff_high(d);
// Lo bits
uint64_t lo = mc_dec128_coeff_low(d);
// Shift and add
mlib_int128 hi_128 = mlib_int128_lshift(MLIB_INT128_CAST(hi), 64);
return mlib_int128_add(hi_128, MLIB_INT128_CAST(lo));
}
/**
* @brief Obtain the biased value of the Decimal128 exponent.
*
* The value is "biased" in that its binary value not actually zero for 10^0. It
* is offset by half the exponent range (the "bias") so it can encode the full
* positive and negative exponent range. The bias value is defined as
* MC_DEC128_EXPONENT_BIAS.
*/
static inline uint32_t mc_dec128_get_biased_exp(mc_dec128 d) {
uint32_t combo = mc_dec128_combination(d);
if (combo < MC_DEC128_COMBO_NONCANONICAL) {
return combo >> 3;
}
if (combo >= MC_DEC128_COMBO_INFINITY) {
return MC_DEC128_MAX_BIASED_EXPONENT + 1;
} else {
return (combo >> 1) & ((1 << 14) - 1);
}
}
/// Create a decimal string from a dec128 number. The result must be freed.
static inline char *mc_dec128_to_new_decimal_string(mc_dec128 d) {
if (mc_dec128_is_zero(d)) {
// Just return "0"
char *s = (char *)calloc(2, 1);
if (s) {
s[0] = '0';
}
return s;
}
if (mc_dec128_is_negative(d)) {
// Negate the result, return a string with a '-' prefix
d = mc_dec128_negate(d);
char *s = mc_dec128_to_new_decimal_string(d);
if (!s) {
return NULL;
}
char *s1 = (char *)calloc(strlen(s) + 2, 1);
if (s1) {
s1[0] = '-';
strcpy(s1 + 1, s);
}
free(s);
return s1;
}
if (mc_dec128_is_inf(d) || mc_dec128_is_nan(d)) {
const char *r = mc_dec128_is_inf(d) ? "Infinity" : "NaN";
char *c = (char *)calloc(strlen(r) + 1, 1);
if (c) {
strcpy(c, r);
}
return c;
}
const char DIGITS[] = "0123456789";
const mc_dec128 TEN = MC_DEC128_C(10);
// Format the whole and fractional part separately.
mc_dec128_modf_result modf = mc_dec128_modf(d);
if (mc_dec128_is_zero(modf.frac)) {
// This is a non-zero integer
// Allocate enough digits:
mc_dec128 log10 = mc_dec128_modf(mc_dec128_log10(d)).whole;
int64_t ndigits = mc_dec128_to_int64(log10) + 1;
// +1 for null
char *strbuf = (char *)calloc((size_t)(ndigits + 1), 1);
if (strbuf) {
// Write the string backwards:
char *optr = strbuf + ndigits - 1;
while (!mc_dec128_is_zero(modf.whole)) {
mc_dec128 rem = mc_dec128_fmod(modf.whole, TEN);
int64_t remi = mc_dec128_to_int64(rem);
*optr-- = DIGITS[remi];
// Divide ten
modf = mc_dec128_modf(mc_dec128_div(modf.whole, TEN));
}
}
return strbuf;
} else if (mc_dec128_is_zero(modf.whole)) {
// This is only a fraction (less than one, but more than zero)
while (!mc_dec128_is_zero(mc_dec128_modf(d).frac)) {
d = mc_dec128_mul(d, TEN);
}
// 'd' is now a whole number
char *part = mc_dec128_to_new_decimal_string(d);
if (!part) {
return NULL;
}
char *buf = (char *)calloc(strlen(part) + 3, 1);
if (buf) {
buf[0] = '0';
buf[1] = '.';
strcpy(buf + 2, part);
}
free(part);
return buf;
} else {
// We have both a whole part and a fractional part
char *whole = mc_dec128_to_new_decimal_string(modf.whole);
if (!whole) {
return NULL;
}
char *frac = mc_dec128_to_new_decimal_string(modf.frac);
if (!frac) {
free(whole);
return NULL;
}
char *ret = (char *)calloc(strlen(whole) + strlen(frac) + 1, 1);
if (ret) {
char *out = ret;
strcpy(out, whole);
out += strlen(whole);
// "frac" contains a leading zero, which we don't want
strcpy(out, frac + 1);
}
free(whole);
free(frac);
return ret;
}
}
static inline mc_dec128 mc_dec128_from_bson_iter(const bson_iter_t *it) {
bson_decimal128_t b;
if (!bson_iter_decimal128(it, &b)) {
mc_dec128 nan = MC_DEC128_POSITIVE_NAN;
return nan;
}
mc_dec128 ret;
memcpy(&ret, &b, sizeof b);
return ret;
}
static inline bson_decimal128_t mc_dec128_to_bson_decimal128(mc_dec128 v) {
bson_decimal128_t ret;
memcpy(&ret, &v, sizeof ret);
return ret;
}
MLIB_C_LINKAGE_END
#endif /// defined MONGOCRYPT_INTELDFP
#endif // MC_DEC128_H_INCLUDED

File Metadata

Mime Type
text/x-c
Expires
Sun, Nov 15, 12:10 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
139507
Default Alt Text
mc-dec128.h (23 KB)

Event Timeline