mirror of
https://github.com/neovim/neovim.git
synced 2025-10-02 16:08:36 +00:00
build: vendor libmpack source from libmpack/libmpack 22b1fd90285117c995728511f9525d29520a8c82
This commit is contained in:
375
src/mpack/conv.c
Normal file
375
src/mpack/conv.c
Normal file
@@ -0,0 +1,375 @@
|
||||
#include "conv.h"
|
||||
|
||||
static int mpack_fits_single(double v);
|
||||
static mpack_value_t mpack_pack_ieee754(double v, unsigned m, unsigned e);
|
||||
static int mpack_is_be(void) FPURE;
|
||||
static double mpack_fmod_pow2_32(double a);
|
||||
|
||||
|
||||
#define POW2(n) \
|
||||
((double)(1 << (n / 2)) * (double)(1 << (n / 2)) * (double)(1 << (n % 2)))
|
||||
|
||||
#define MPACK_SWAP_VALUE(val) \
|
||||
do { \
|
||||
mpack_uint32_t lo = val.lo; \
|
||||
val.lo = val.hi; \
|
||||
val.hi = lo; \
|
||||
} while (0)
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_nil(void)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_NIL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_boolean(unsigned v)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_BOOLEAN;
|
||||
rv.data.value.lo = v ? 1 : 0;
|
||||
rv.data.value.hi = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_uint(mpack_uintmax_t v)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.data.value.lo = v & 0xffffffff;
|
||||
rv.data.value.hi = (mpack_uint32_t)((v >> 31) >> 1);
|
||||
rv.type = MPACK_TOKEN_UINT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_sint(mpack_sintmax_t v)
|
||||
{
|
||||
if (v < 0) {
|
||||
mpack_token_t rv;
|
||||
mpack_uintmax_t tc = -((mpack_uintmax_t)(v + 1)) + 1;
|
||||
tc = ~tc + 1;
|
||||
rv = mpack_pack_uint(tc);
|
||||
rv.type = MPACK_TOKEN_SINT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return mpack_pack_uint((mpack_uintmax_t)v);
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_float_compat(double v)
|
||||
{
|
||||
/* ieee754 single-precision limits to determine if "v" can be fully
|
||||
* represented in 4 bytes */
|
||||
mpack_token_t rv;
|
||||
|
||||
if (mpack_fits_single(v)) {
|
||||
rv.length = 4;
|
||||
rv.data.value = mpack_pack_ieee754(v, 23, 8);
|
||||
} else {
|
||||
rv.length = 8;
|
||||
rv.data.value = mpack_pack_ieee754(v, 52, 11);
|
||||
}
|
||||
|
||||
rv.type = MPACK_TOKEN_FLOAT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_float_fast(double v)
|
||||
{
|
||||
/* ieee754 single-precision limits to determine if "v" can be fully
|
||||
* represented in 4 bytes */
|
||||
mpack_token_t rv;
|
||||
|
||||
if (mpack_fits_single(v)) {
|
||||
union {
|
||||
float f;
|
||||
mpack_uint32_t m;
|
||||
} conv;
|
||||
conv.f = (float)v;
|
||||
rv.length = 4;
|
||||
rv.data.value.lo = conv.m;
|
||||
rv.data.value.hi = 0;
|
||||
} else {
|
||||
union {
|
||||
double d;
|
||||
mpack_value_t m;
|
||||
} conv;
|
||||
conv.d = v;
|
||||
rv.length = 8;
|
||||
rv.data.value = conv.m;
|
||||
if (mpack_is_be()) {
|
||||
MPACK_SWAP_VALUE(rv.data.value);
|
||||
}
|
||||
}
|
||||
|
||||
rv.type = MPACK_TOKEN_FLOAT;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_number(double v)
|
||||
{
|
||||
mpack_token_t tok;
|
||||
double vabs;
|
||||
vabs = v < 0 ? -v : v;
|
||||
assert(v <= 9007199254740991. && v >= -9007199254740991.);
|
||||
tok.data.value.hi = (mpack_uint32_t)(vabs / POW2(32));
|
||||
tok.data.value.lo = (mpack_uint32_t)mpack_fmod_pow2_32(vabs);
|
||||
|
||||
if (v < 0) {
|
||||
/* Compute the two's complement */
|
||||
tok.type = MPACK_TOKEN_SINT;
|
||||
tok.data.value.hi = ~tok.data.value.hi;
|
||||
tok.data.value.lo = ~tok.data.value.lo + 1;
|
||||
if (!tok.data.value.lo) tok.data.value.hi++;
|
||||
if (tok.data.value.lo == 0 && tok.data.value.hi == 0) tok.length = 1;
|
||||
else if (tok.data.value.lo < 0x80000000) tok.length = 8;
|
||||
else if (tok.data.value.lo < 0xffff7fff) tok.length = 4;
|
||||
else if (tok.data.value.lo < 0xffffff7f) tok.length = 2;
|
||||
else tok.length = 1;
|
||||
} else {
|
||||
tok.type = MPACK_TOKEN_UINT;
|
||||
if (tok.data.value.hi) tok.length = 8;
|
||||
else if (tok.data.value.lo > 0xffff) tok.length = 4;
|
||||
else if (tok.data.value.lo > 0xff) tok.length = 2;
|
||||
else tok.length = 1;
|
||||
}
|
||||
|
||||
if (mpack_unpack_number(tok) != v) {
|
||||
return mpack_pack_float(v);
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_chunk(const char *p, mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_CHUNK;
|
||||
rv.data.chunk_ptr = p;
|
||||
rv.length = l;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_str(mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_STR;
|
||||
rv.length = l;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_bin(mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_BIN;
|
||||
rv.length = l;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_ext(int t, mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_EXT;
|
||||
rv.length = l;
|
||||
rv.data.ext_type = t;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_array(mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_ARRAY;
|
||||
rv.length = l;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API mpack_token_t mpack_pack_map(mpack_uint32_t l)
|
||||
{
|
||||
mpack_token_t rv;
|
||||
rv.type = MPACK_TOKEN_MAP;
|
||||
rv.length = l;
|
||||
return rv;
|
||||
}
|
||||
|
||||
MPACK_API bool mpack_unpack_boolean(mpack_token_t t)
|
||||
{
|
||||
return t.data.value.lo || t.data.value.hi;
|
||||
}
|
||||
|
||||
MPACK_API mpack_uintmax_t mpack_unpack_uint(mpack_token_t t)
|
||||
{
|
||||
return (((mpack_uintmax_t)t.data.value.hi << 31) << 1) | t.data.value.lo;
|
||||
}
|
||||
|
||||
/* unpack signed integer without relying on two's complement as internal
|
||||
* representation */
|
||||
MPACK_API mpack_sintmax_t mpack_unpack_sint(mpack_token_t t)
|
||||
{
|
||||
mpack_uint32_t hi = t.data.value.hi;
|
||||
mpack_uint32_t lo = t.data.value.lo;
|
||||
mpack_uintmax_t rv = lo;
|
||||
assert(t.length <= sizeof(mpack_sintmax_t));
|
||||
|
||||
if (t.length == 8) {
|
||||
rv |= (((mpack_uintmax_t)hi) << 31) << 1;
|
||||
}
|
||||
/* reverse the two's complement so that lo/hi contain the absolute value.
|
||||
* note that we have to mask ~rv so that it reflects the two's complement
|
||||
* of the appropriate byte length */
|
||||
rv = (~rv & (((mpack_uintmax_t)1 << ((t.length * 8) - 1)) - 1)) + 1;
|
||||
/* negate and return the absolute value, making sure mpack_sintmax_t can
|
||||
* represent the positive cast. */
|
||||
return -((mpack_sintmax_t)(rv - 1)) - 1;
|
||||
}
|
||||
|
||||
MPACK_API double mpack_unpack_float_compat(mpack_token_t t)
|
||||
{
|
||||
mpack_uint32_t sign;
|
||||
mpack_sint32_t exponent, bias;
|
||||
unsigned mantbits;
|
||||
unsigned expbits;
|
||||
double mant;
|
||||
|
||||
if (t.data.value.lo == 0 && t.data.value.hi == 0)
|
||||
/* nothing to do */
|
||||
return 0;
|
||||
|
||||
if (t.length == 4) mantbits = 23, expbits = 8;
|
||||
else mantbits = 52, expbits = 11;
|
||||
bias = (1 << (expbits - 1)) - 1;
|
||||
|
||||
/* restore sign/exponent/mantissa */
|
||||
if (mantbits == 52) {
|
||||
sign = t.data.value.hi >> 31;
|
||||
exponent = (t.data.value.hi >> 20) & ((1 << 11) - 1);
|
||||
mant = (t.data.value.hi & ((1 << 20) - 1)) * POW2(32);
|
||||
mant += t.data.value.lo;
|
||||
} else {
|
||||
sign = t.data.value.lo >> 31;
|
||||
exponent = (t.data.value.lo >> 23) & ((1 << 8) - 1);
|
||||
mant = t.data.value.lo & ((1 << 23) - 1);
|
||||
}
|
||||
|
||||
mant /= POW2(mantbits);
|
||||
if (exponent) mant += 1.0; /* restore leading 1 */
|
||||
else exponent = 1; /* subnormal */
|
||||
exponent -= bias;
|
||||
|
||||
/* restore original value */
|
||||
while (exponent > 0) mant *= 2.0, exponent--;
|
||||
while (exponent < 0) mant /= 2.0, exponent++;
|
||||
return mant * (sign ? -1 : 1);
|
||||
}
|
||||
|
||||
MPACK_API double mpack_unpack_float_fast(mpack_token_t t)
|
||||
{
|
||||
if (t.length == 4) {
|
||||
union {
|
||||
float f;
|
||||
mpack_uint32_t m;
|
||||
} conv;
|
||||
conv.m = t.data.value.lo;
|
||||
return conv.f;
|
||||
} else {
|
||||
union {
|
||||
double d;
|
||||
mpack_value_t m;
|
||||
} conv;
|
||||
conv.m = t.data.value;
|
||||
|
||||
if (mpack_is_be()) {
|
||||
MPACK_SWAP_VALUE(conv.m);
|
||||
}
|
||||
|
||||
return conv.d;
|
||||
}
|
||||
}
|
||||
|
||||
MPACK_API double mpack_unpack_number(mpack_token_t t)
|
||||
{
|
||||
double rv;
|
||||
mpack_uint32_t hi, lo;
|
||||
if (t.type == MPACK_TOKEN_FLOAT) return mpack_unpack_float(t);
|
||||
assert(t.type == MPACK_TOKEN_UINT || t.type == MPACK_TOKEN_SINT);
|
||||
hi = t.data.value.hi;
|
||||
lo = t.data.value.lo;
|
||||
if (t.type == MPACK_TOKEN_SINT) {
|
||||
/* same idea as mpack_unpack_sint, except here we shouldn't rely on
|
||||
* mpack_uintmax_t having 64-bits, operating on the 32-bit words separately.
|
||||
*/
|
||||
if (!hi) {
|
||||
assert(t.length <= 4);
|
||||
hi = 0;
|
||||
lo = (~lo & (((mpack_uint32_t)1 << ((t.length * 8) - 1)) - 1));
|
||||
} else {
|
||||
hi = ~hi;
|
||||
lo = ~lo;
|
||||
}
|
||||
lo++;
|
||||
if (!lo) hi++;
|
||||
}
|
||||
rv = (double)lo + POW2(32) * hi;
|
||||
return t.type == MPACK_TOKEN_SINT ? -rv : rv;
|
||||
}
|
||||
|
||||
static int mpack_fits_single(double v)
|
||||
{
|
||||
return (float)v == v;
|
||||
}
|
||||
|
||||
static mpack_value_t mpack_pack_ieee754(double v, unsigned mantbits,
|
||||
unsigned expbits)
|
||||
{
|
||||
mpack_value_t rv = {0, 0};
|
||||
mpack_sint32_t exponent, bias = (1 << (expbits - 1)) - 1;
|
||||
mpack_uint32_t sign;
|
||||
double mant;
|
||||
|
||||
if (v == 0) {
|
||||
rv.lo = 0;
|
||||
rv.hi = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (v < 0) sign = 1, mant = -v;
|
||||
else sign = 0, mant = v;
|
||||
|
||||
exponent = 0;
|
||||
while (mant >= 2.0) mant /= 2.0, exponent++;
|
||||
while (mant < 1.0 && exponent > -(bias - 1)) mant *= 2.0, exponent--;
|
||||
|
||||
if (mant < 1.0) exponent = -bias; /* subnormal value */
|
||||
else mant = mant - 1.0; /* remove leading 1 */
|
||||
exponent += bias;
|
||||
mant *= POW2(mantbits);
|
||||
|
||||
if (mantbits == 52) {
|
||||
rv.hi = (mpack_uint32_t)(mant / POW2(32));
|
||||
rv.lo = (mpack_uint32_t)(mant - rv.hi * POW2(32));
|
||||
rv.hi |= ((mpack_uint32_t)exponent << 20) | (sign << 31);
|
||||
} else if (mantbits == 23) {
|
||||
rv.hi = 0;
|
||||
rv.lo = (mpack_uint32_t)mant;
|
||||
rv.lo |= ((mpack_uint32_t)exponent << 23) | (sign << 31);
|
||||
}
|
||||
|
||||
end:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int mpack_is_be(void)
|
||||
{
|
||||
union {
|
||||
mpack_uint32_t i;
|
||||
char c[sizeof(mpack_uint32_t)];
|
||||
} test;
|
||||
|
||||
test.i = 1;
|
||||
return test.c[0] == 0;
|
||||
}
|
||||
|
||||
/* this simplified version of `fmod` that returns the remainder of double
|
||||
* division by 0xffffffff, which is enough for our purposes */
|
||||
static double mpack_fmod_pow2_32(double a)
|
||||
{
|
||||
return a - ((double)(mpack_uint32_t)(a / POW2(32)) * POW2(32));
|
||||
}
|
Reference in New Issue
Block a user