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 }