neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

conv.c (9312B)


      1 #include "conv.h"
      2 
      3 static int mpack_fits_single(double v);
      4 static mpack_value_t mpack_pack_ieee754(double v, unsigned m, unsigned e);
      5 static int mpack_is_be(void) FPURE;
      6 static double mpack_fmod_pow2_32(double a);
      7 
      8 
      9 #define POW2(n) \
     10  ((double)(1 << (n / 2)) * (double)(1 << (n / 2)) * (double)(1 << (n % 2)))
     11 
     12 #define MPACK_SWAP_VALUE(val)                                  \
     13  do {                                                         \
     14    mpack_uint32_t lo = val.lo;                                \
     15    val.lo = val.hi;                                           \
     16    val.hi = lo;                                               \
     17  } while (0)
     18 
     19 MPACK_API mpack_token_t mpack_pack_nil(void)
     20 {
     21  mpack_token_t rv;
     22  rv.type = MPACK_TOKEN_NIL;
     23  return rv;
     24 }
     25 
     26 MPACK_API mpack_token_t mpack_pack_boolean(unsigned v)
     27 {
     28  mpack_token_t rv;
     29  rv.type = MPACK_TOKEN_BOOLEAN;
     30  rv.data.value.lo = v ? 1 : 0;
     31  rv.data.value.hi = 0;
     32  return rv;
     33 }
     34 
     35 MPACK_API mpack_token_t mpack_pack_uint(mpack_uintmax_t v)
     36 {
     37  mpack_token_t rv;
     38  rv.data.value.lo = v & 0xffffffff;
     39  rv.data.value.hi = (mpack_uint32_t)((v >> 31) >> 1);
     40  rv.type = MPACK_TOKEN_UINT;
     41  return rv;
     42 }
     43 
     44 MPACK_API mpack_token_t mpack_pack_sint(mpack_sintmax_t v)
     45 {
     46  if (v < 0) {
     47    mpack_token_t rv;
     48    mpack_uintmax_t tc = -((mpack_uintmax_t)(v + 1)) + 1;
     49    tc = ~tc + 1;
     50    rv = mpack_pack_uint(tc);
     51    rv.type = MPACK_TOKEN_SINT;
     52    return rv;
     53  }
     54 
     55  return mpack_pack_uint((mpack_uintmax_t)v);
     56 }
     57 
     58 MPACK_API mpack_token_t mpack_pack_float_compat(double v)
     59 {
     60  /* ieee754 single-precision limits to determine if "v" can be fully
     61   * represented in 4 bytes */
     62  mpack_token_t rv;
     63 
     64  if (mpack_fits_single(v)) {
     65    rv.length = 4;
     66    rv.data.value = mpack_pack_ieee754(v, 23, 8);
     67  } else {
     68    rv.length = 8;
     69    rv.data.value = mpack_pack_ieee754(v, 52, 11);
     70  }
     71 
     72  rv.type = MPACK_TOKEN_FLOAT;
     73  return rv;
     74 }
     75 
     76 MPACK_API mpack_token_t mpack_pack_float_fast(double v)
     77 {
     78  /* ieee754 single-precision limits to determine if "v" can be fully
     79   * represented in 4 bytes */
     80  mpack_token_t rv;
     81 
     82  if (mpack_fits_single(v)) {
     83    union {
     84      float f;
     85      mpack_uint32_t m;
     86    } conv;
     87    conv.f = (float)v;
     88    rv.length = 4;
     89    rv.data.value.lo = conv.m;
     90    rv.data.value.hi = 0;
     91  } else {
     92    union {
     93      double d;
     94      mpack_value_t m;
     95    } conv;
     96    conv.d = v;
     97    rv.length = 8;
     98    rv.data.value = conv.m;
     99    if (mpack_is_be()) {
    100      MPACK_SWAP_VALUE(rv.data.value);
    101    }
    102  }
    103 
    104  rv.type = MPACK_TOKEN_FLOAT;
    105  return rv;
    106 }
    107 
    108 MPACK_API mpack_token_t mpack_pack_number(double v)
    109 {
    110  mpack_token_t tok;
    111  double vabs;
    112  vabs = v < 0 ? -v : v;
    113  assert(v <= 9007199254740991. && v >= -9007199254740991.);
    114  tok.data.value.hi = (mpack_uint32_t)(vabs / POW2(32));
    115  tok.data.value.lo = (mpack_uint32_t)mpack_fmod_pow2_32(vabs);
    116 
    117  if (v < 0) {
    118    /* Compute the two's complement */
    119    tok.type = MPACK_TOKEN_SINT;
    120    tok.data.value.hi = ~tok.data.value.hi;
    121    tok.data.value.lo = ~tok.data.value.lo + 1;
    122    if (!tok.data.value.lo) tok.data.value.hi++;
    123    if (tok.data.value.lo == 0 && tok.data.value.hi == 0) tok.length = 1;
    124    else if (tok.data.value.lo < 0x80000000) tok.length = 8;
    125    else if (tok.data.value.lo < 0xffff7fff) tok.length = 4;
    126    else if (tok.data.value.lo < 0xffffff7f) tok.length = 2;
    127    else tok.length = 1;
    128  } else {
    129    tok.type = MPACK_TOKEN_UINT;
    130    if (tok.data.value.hi) tok.length = 8;
    131    else if (tok.data.value.lo > 0xffff) tok.length = 4;
    132    else if (tok.data.value.lo > 0xff) tok.length = 2;
    133    else tok.length = 1;
    134  }
    135 
    136  if (mpack_unpack_number(tok) != v) {
    137    return mpack_pack_float(v);
    138  }
    139 
    140  return tok;
    141 }
    142 
    143 MPACK_API mpack_token_t mpack_pack_chunk(const char *p, mpack_uint32_t l)
    144 {
    145  mpack_token_t rv;
    146  rv.type = MPACK_TOKEN_CHUNK;
    147  rv.data.chunk_ptr = p;
    148  rv.length = l;
    149  return rv;
    150 }
    151 
    152 MPACK_API mpack_token_t mpack_pack_str(mpack_uint32_t l)
    153 {
    154  mpack_token_t rv;
    155  rv.type = MPACK_TOKEN_STR;
    156  rv.length = l;
    157  return rv;
    158 }
    159 
    160 MPACK_API mpack_token_t mpack_pack_bin(mpack_uint32_t l)
    161 {
    162  mpack_token_t rv;
    163  rv.type = MPACK_TOKEN_BIN;
    164  rv.length = l;
    165  return rv;
    166 }
    167 
    168 MPACK_API mpack_token_t mpack_pack_ext(int t, mpack_uint32_t l)
    169 {
    170  mpack_token_t rv;
    171  rv.type = MPACK_TOKEN_EXT;
    172  rv.length = l;
    173  rv.data.ext_type = t;
    174  return rv;
    175 }
    176 
    177 MPACK_API mpack_token_t mpack_pack_array(mpack_uint32_t l)
    178 {
    179  mpack_token_t rv;
    180  rv.type = MPACK_TOKEN_ARRAY;
    181  rv.length = l;
    182  return rv;
    183 }
    184 
    185 MPACK_API mpack_token_t mpack_pack_map(mpack_uint32_t l)
    186 {
    187  mpack_token_t rv;
    188  rv.type = MPACK_TOKEN_MAP;
    189  rv.length = l;
    190  return rv;
    191 }
    192 
    193 MPACK_API bool mpack_unpack_boolean(mpack_token_t t)
    194 {
    195  return t.data.value.lo || t.data.value.hi;
    196 }
    197 
    198 MPACK_API mpack_uintmax_t mpack_unpack_uint(mpack_token_t t)
    199 {
    200  return (((mpack_uintmax_t)t.data.value.hi << 31) << 1) | t.data.value.lo;
    201 }
    202 
    203 /* unpack signed integer without relying on two's complement as internal
    204 * representation */
    205 MPACK_API mpack_sintmax_t mpack_unpack_sint(mpack_token_t t)
    206 {
    207  mpack_uint32_t hi = t.data.value.hi;
    208  mpack_uint32_t lo = t.data.value.lo;
    209  mpack_uintmax_t rv = lo;
    210  assert(t.length <= sizeof(mpack_sintmax_t));
    211 
    212  if (t.length == 8) {
    213    rv |= (((mpack_uintmax_t)hi) << 31) << 1;
    214  }
    215  /* reverse the two's complement so that lo/hi contain the absolute value.
    216   * note that we have to mask ~rv so that it reflects the two's complement
    217   * of the appropriate byte length */
    218  rv = (~rv & (((mpack_uintmax_t)1 << ((t.length * 8) - 1)) - 1)) + 1;
    219  /* negate and return the absolute value, making sure mpack_sintmax_t can
    220   * represent the positive cast. */
    221  return -((mpack_sintmax_t)(rv - 1)) - 1;
    222 }
    223 
    224 MPACK_API double mpack_unpack_float_compat(mpack_token_t t)
    225 {
    226  mpack_uint32_t sign;
    227  mpack_sint32_t exponent, bias;
    228  unsigned mantbits;
    229  unsigned expbits;
    230  double mant;
    231 
    232  if (t.data.value.lo == 0 && t.data.value.hi == 0)
    233    /* nothing to do */
    234    return 0;
    235 
    236  if (t.length == 4) mantbits = 23, expbits = 8;
    237  else mantbits = 52, expbits = 11;
    238  bias = (1 << (expbits - 1)) - 1;
    239 
    240  /* restore sign/exponent/mantissa */
    241  if (mantbits == 52) {
    242    sign = t.data.value.hi >> 31;
    243    exponent = (t.data.value.hi >> 20) & ((1 << 11) - 1);
    244    mant = (t.data.value.hi & ((1 << 20) - 1)) * POW2(32);
    245    mant += t.data.value.lo;
    246  } else {
    247    sign = t.data.value.lo >> 31;
    248    exponent = (t.data.value.lo >> 23) & ((1 << 8) - 1);
    249    mant = t.data.value.lo & ((1 << 23) - 1);
    250  }
    251 
    252  mant /= POW2(mantbits);
    253  if (exponent) mant += 1.0; /* restore leading 1 */
    254  else exponent = 1; /* subnormal */
    255  exponent -= bias;
    256 
    257  /* restore original value */
    258  while (exponent > 0) mant *= 2.0, exponent--;
    259  while (exponent < 0) mant /= 2.0, exponent++;
    260  return mant * (sign ? -1 : 1);
    261 }
    262 
    263 MPACK_API double mpack_unpack_float_fast(mpack_token_t t)
    264 {
    265  if (t.length == 4) {
    266    union {
    267      float f;
    268      mpack_uint32_t m;
    269    } conv;
    270    conv.m = t.data.value.lo;
    271    return conv.f;
    272  } else {
    273    union {
    274      double d;
    275      mpack_value_t m;
    276    } conv;
    277    conv.m = t.data.value;
    278    
    279    if (mpack_is_be()) {
    280      MPACK_SWAP_VALUE(conv.m);
    281    }
    282 
    283    return conv.d;
    284  }
    285 }
    286 
    287 MPACK_API double mpack_unpack_number(mpack_token_t t)
    288 {
    289  double rv;
    290  mpack_uint32_t hi, lo;
    291  if (t.type == MPACK_TOKEN_FLOAT) return mpack_unpack_float(t);
    292  assert(t.type == MPACK_TOKEN_UINT || t.type == MPACK_TOKEN_SINT);
    293  hi = t.data.value.hi;
    294  lo = t.data.value.lo;
    295  if (t.type == MPACK_TOKEN_SINT) {
    296    /* same idea as mpack_unpack_sint, except here we shouldn't rely on
    297     * mpack_uintmax_t having 64-bits, operating on the 32-bit words separately.
    298     */
    299    if (!hi) {
    300      assert(t.length <= 4);
    301      lo = (~lo & (((mpack_uint32_t)1 << ((t.length * 8) - 1)) - 1));
    302    } else {
    303      hi = ~hi;
    304      lo = ~lo;
    305    }
    306    lo++;
    307    if (!lo) hi++;
    308  }
    309  rv = (double)lo + POW2(32) * hi;
    310  return t.type == MPACK_TOKEN_SINT ? -rv : rv;
    311 }
    312 
    313 static int mpack_fits_single(double v)
    314 {
    315  return (float)v == v;
    316 }
    317 
    318 static mpack_value_t mpack_pack_ieee754(double v, unsigned mantbits,
    319    unsigned expbits)
    320 {
    321  mpack_value_t rv = {0, 0};
    322  mpack_sint32_t exponent, bias = (1 << (expbits - 1)) - 1;
    323  mpack_uint32_t sign;
    324  double mant;
    325 
    326  if (v == 0) {
    327    rv.lo = 0;
    328    rv.hi = 0;
    329    goto end;
    330  }
    331 
    332  if (v < 0) sign = 1, mant = -v;
    333  else sign = 0, mant = v;
    334 
    335  exponent = 0;
    336  while (mant >= 2.0) mant /= 2.0, exponent++;
    337  while (mant < 1.0 && exponent > -(bias - 1)) mant *= 2.0, exponent--;
    338 
    339  if (mant < 1.0) exponent = -bias; /* subnormal value */
    340  else mant = mant - 1.0; /* remove leading 1 */
    341  exponent += bias;
    342  mant *= POW2(mantbits);
    343 
    344  if (mantbits == 52) {
    345    rv.hi = (mpack_uint32_t)(mant / POW2(32));
    346    rv.lo = (mpack_uint32_t)(mant - rv.hi * POW2(32));
    347    rv.hi |= ((mpack_uint32_t)exponent << 20) | (sign << 31);
    348  } else if (mantbits == 23) {
    349    rv.hi = 0;
    350    rv.lo = (mpack_uint32_t)mant;
    351    rv.lo |= ((mpack_uint32_t)exponent << 23) | (sign << 31);
    352  }
    353 
    354 end:
    355  return rv;
    356 }
    357 
    358 static int mpack_is_be(void)
    359 {
    360  union {
    361    mpack_uint32_t i;
    362    char c[sizeof(mpack_uint32_t)];
    363  } test;
    364 
    365  test.i = 1;
    366  return test.c[0] == 0;
    367 }
    368 
    369 /* this simplified version of `fmod` that returns the remainder of double
    370 * division by 0xffffffff, which is enough for our purposes */
    371 static double mpack_fmod_pow2_32(double a)
    372 {
    373  return a - ((double)(mpack_uint32_t)(a / POW2(32)) * POW2(32));
    374 }