mdbx: add key-to-value functions.

Change-Id: Ie0acd8c58833047931444fd9d94d5b82e6d541bb
This commit is contained in:
Leonid Yuriev 2020-06-23 23:50:37 +03:00
parent 63bf01a60a
commit 428f753c03
2 changed files with 102 additions and 20 deletions

9
mdbx.h
View File

@ -2681,7 +2681,7 @@ LIBMDBX_API int mdbx_dbi_open_ex(MDBX_txn *txn, const char *name,
LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name, unsigned flags, LIBMDBX_API int mdbx_dbi_open(MDBX_txn *txn, const char *name, unsigned flags,
MDBX_dbi *dbi); MDBX_dbi *dbi);
/* Key-making functions to avoid custom comparators. /* Key-making (value-to-key) functions to avoid custom comparators.
* *
* The mdbx_key_from_jsonInteger() build key which are comparable with * The mdbx_key_from_jsonInteger() build key which are comparable with
* keys created by mdbx_key_from_double(). So this allow mix int64 and IEEE754 * keys created by mdbx_key_from_double(). So this allow mix int64 and IEEE754
@ -2700,6 +2700,13 @@ __inline uint32_t mdbx_key_from_int32(const int32_t i32) {
return UINT32_C(0x80000000) + i32; return UINT32_C(0x80000000) + i32;
} }
/* Key-reverse (key-to-value) functions to avoid custom comparators. */
LIBMDBX_API int64_t mdbx_jsonInteger_from_key(const MDBX_val);
LIBMDBX_API double mdbx_double_from_key(const MDBX_val);
LIBMDBX_API float mdbx_float_from_key(const MDBX_val);
LIBMDBX_API int32_t mdbx_int32_from_key(const MDBX_val);
LIBMDBX_API int64_t mdbx_int64_from_key(const MDBX_val);
/* Retrieve statistics for a database. /* Retrieve statistics for a database.
* *
* [in] txn A transaction handle returned by mdbx_txn_begin(). * [in] txn A transaction handle returned by mdbx_txn_begin().

View File

@ -18402,18 +18402,50 @@ __cold intptr_t mdbx_limits_txnsize_max(intptr_t pagesize) {
/*** Key-making functions to avoid custom comparators *************************/ /*** Key-making functions to avoid custom comparators *************************/
static __always_inline double key2double(const int64_t key) {
union {
uint64_t u;
double f;
} casting;
casting.u = (key < 0) ? key + UINT64_C(0x8000000000000000)
: UINT64_C(0xffffFFFFffffFFFF) - key;
return casting.f;
}
static __always_inline uint64_t double2key(const double *const ptr) { static __always_inline uint64_t double2key(const double *const ptr) {
STATIC_ASSERT(sizeof(double) == sizeof(int64_t)); STATIC_ASSERT(sizeof(double) == sizeof(int64_t));
const int64_t i64 = *(const int64_t *)ptr; const int64_t i = *(const int64_t *)ptr;
return (i64 >= 0) ? /* positive */ UINT64_C(0x8000000000000000) + i64 const uint64_t u = (i < 0) ? UINT64_C(0xffffFFFFffffFFFF) - i
: /* negative */ (uint64_t)-i64; : i + UINT64_C(0x8000000000000000);
if (mdbx_assert_enabled()) {
const double f = key2double(u);
assert(memcmp(&f, ptr, 8) == 0);
}
return u;
}
static __always_inline float key2float(const int32_t key) {
union {
uint32_t u;
float f;
} casting;
casting.u =
(key < 0) ? key + UINT32_C(0x80000000) : UINT32_C(0xffffFFFF) - key;
return casting.f;
} }
static __always_inline uint32_t float2key(const float *const ptr) { static __always_inline uint32_t float2key(const float *const ptr) {
STATIC_ASSERT(sizeof(float) == sizeof(int32_t)); STATIC_ASSERT(sizeof(float) == sizeof(int32_t));
const int32_t i32 = *(const int32_t *)ptr; const int32_t i = *(const int32_t *)ptr;
return (i32 >= 0) ? /* positive */ UINT32_C(0x80000000) + i32 const uint32_t u =
: /* negative */ (uint32_t)-i32; (i < 0) ? UINT32_C(0xffffFFFF) - i : i + UINT32_C(0x80000000);
if (mdbx_assert_enabled()) {
const float f = key2float(u);
assert(memcmp(&f, ptr, 4) == 0);
}
return u;
} }
uint64_t mdbx_key_from_double(const double ieee754_64bit) { uint64_t mdbx_key_from_double(const double ieee754_64bit) {
@ -18433,8 +18465,8 @@ uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit) {
} }
#define IEEE754_DOUBLE_MANTISSA_SIZE 52 #define IEEE754_DOUBLE_MANTISSA_SIZE 52
#define IEEE754_DOUBLE_BIAS 0x3FF #define IEEE754_DOUBLE_EXPONENTA_BIAS 0x3FF
#define IEEE754_DOUBLE_MAX 0x7FF #define IEEE754_DOUBLE_EXPONENTA_MAX 0x7FF
#define IEEE754_DOUBLE_IMPLICIT_LEAD UINT64_C(0x0010000000000000) #define IEEE754_DOUBLE_IMPLICIT_LEAD UINT64_C(0x0010000000000000)
#define IEEE754_DOUBLE_MANTISSA_MASK UINT64_C(0x000FFFFFFFFFFFFF) #define IEEE754_DOUBLE_MANTISSA_MASK UINT64_C(0x000FFFFFFFFFFFFF)
#define IEEE754_DOUBLE_MANTISSA_AMAX UINT64_C(0x001FFFFFFFFFFFFF) #define IEEE754_DOUBLE_MANTISSA_AMAX UINT64_C(0x001FFFFFFFFFFFFF)
@ -18480,7 +18512,7 @@ static __inline int clz64(uint64_t value) {
return debruijn_clz64[value * UINT64_C(0x03F79D71B4CB0A89) >> 58]; return debruijn_clz64[value * UINT64_C(0x03F79D71B4CB0A89) >> 58];
} }
static uint64_t round_mantissa(const uint64_t u64, int shift) { static __inline uint64_t round_mantissa(const uint64_t u64, int shift) {
assert(shift < 0 && u64 > 0); assert(shift < 0 && u64 > 0);
shift = -shift; shift = -shift;
const unsigned half = 1 << (shift - 1); const unsigned half = 1 << (shift - 1);
@ -18490,7 +18522,7 @@ static uint64_t round_mantissa(const uint64_t u64, int shift) {
} }
uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) { uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
const uint64_t biased_zero = UINT64_C(0x8000000000000000); const uint64_t bias = UINT64_C(0x8000000000000000);
if (json_integer > 0) { if (json_integer > 0) {
const uint64_t u64 = json_integer; const uint64_t u64 = json_integer;
int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1); int shift = clz64(u64) - (64 - IEEE754_DOUBLE_MANTISSA_SIZE - 1);
@ -18504,10 +18536,9 @@ uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD && assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX); mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
const uint64_t exponent = const uint64_t exponent =
IEEE754_DOUBLE_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift; IEEE754_DOUBLE_EXPONENTA_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
assert(exponent > 0 && exponent <= IEEE754_DOUBLE_MAX); assert(exponent > 0 && exponent <= IEEE754_DOUBLE_EXPONENTA_MAX);
const uint64_t key = biased_zero + const uint64_t key = bias + (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) +
(exponent << IEEE754_DOUBLE_MANTISSA_SIZE) +
(mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD); (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
#if !defined(_MSC_VER) || \ #if !defined(_MSC_VER) || \
defined( \ defined( \
@ -18531,10 +18562,9 @@ uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD && assert(mantissa >= IEEE754_DOUBLE_IMPLICIT_LEAD &&
mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX); mantissa <= IEEE754_DOUBLE_MANTISSA_AMAX);
const uint64_t exponent = const uint64_t exponent =
IEEE754_DOUBLE_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift; IEEE754_DOUBLE_EXPONENTA_BIAS + IEEE754_DOUBLE_MANTISSA_SIZE - shift;
assert(exponent > 0 && exponent <= IEEE754_DOUBLE_MAX); assert(exponent > 0 && exponent <= IEEE754_DOUBLE_EXPONENTA_MAX);
const uint64_t key = biased_zero - const uint64_t key = bias - 1 - (exponent << IEEE754_DOUBLE_MANTISSA_SIZE) -
(exponent << IEEE754_DOUBLE_MANTISSA_SIZE) -
(mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD); (mantissa - IEEE754_DOUBLE_IMPLICIT_LEAD);
#if !defined(_MSC_VER) || \ #if !defined(_MSC_VER) || \
defined( \ defined( \
@ -18545,7 +18575,52 @@ uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer) {
return key; return key;
} }
return biased_zero; return bias;
}
int64_t mdbx_jsonInteger_from_key(const MDBX_val v) {
assert(v.iov_len == 8);
const uint64_t key = unaligned_peek_u64(2, v.iov_base);
const uint64_t bias = UINT64_C(0x8000000000000000);
const uint64_t covalent = (key > bias) ? key - bias : bias - key - 1;
const int shift = IEEE754_DOUBLE_EXPONENTA_BIAS + 63 -
(IEEE754_DOUBLE_EXPONENTA_MAX &
(int)(covalent >> IEEE754_DOUBLE_MANTISSA_SIZE));
if (unlikely(shift < 1))
return (key < bias) ? INT64_MIN : INT64_MAX;
if (unlikely(shift > 63))
return 0;
const uint64_t unscaled = ((covalent & IEEE754_DOUBLE_MANTISSA_MASK)
<< (63 - IEEE754_DOUBLE_MANTISSA_SIZE)) +
bias;
const int64_t absolute = unscaled >> shift;
const int64_t value = (key < bias) ? -absolute : absolute;
assert(key == mdbx_key_from_jsonInteger(value) ||
(mdbx_key_from_jsonInteger(value - 1) < key &&
key < mdbx_key_from_jsonInteger(value + 1)));
return value;
}
double mdbx_double_from_key(const MDBX_val v) {
assert(v.iov_len == 8);
return key2double(unaligned_peek_u64(2, v.iov_base));
}
float mdbx_float_from_key(const MDBX_val v) {
assert(v.iov_len == 4);
return key2float(unaligned_peek_u32(2, v.iov_base));
}
int32_t mdbx_int32_from_key(const MDBX_val v) {
assert(v.iov_len == 4);
return (int32_t)(unaligned_peek_u32(2, v.iov_base) - UINT32_C(0x80000000));
}
int64_t mdbx_int64_from_key(const MDBX_val v) {
assert(v.iov_len == 8);
return (int64_t)(unaligned_peek_u64(2, v.iov_base) -
UINT64_C(0x8000000000000000));
} }
/*** Attribute support functions for Nexenta **********************************/ /*** Attribute support functions for Nexenta **********************************/