Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
10855 lines (10370 sloc) 353 KB
// This file is part of PLINK 1.90, copyright (C) 2005-2019 Shaun Purcell,
// Christopher Chang.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "plink_common.h"
// #include "pigz.h"
// no leading \n since this is used in LOGPRINTFWW expressions
const char g_errstr_fopen[] = "Error: Failed to open %s.\n";
const char g_cmdline_format_str[] = "\n " PROG_NAME_STR " <input flag(s)...> [command flag(s)...] [other flag(s)...]\n " PROG_NAME_STR " --help [flag name(s)...]\n\n";
char g_textbuf[TEXTBUF_SIZE];
// note that \xxx character constants are interpreted in octal.
// technically no need to represent 0-31, but 64 extra bytes of data is
// probably cheaper than the code to subtract 32 everywhere.
const char g_one_char_strs[] = "\0\0\1\0\2\0\3\0\4\0\5\0\6\0\7\0\10\0\11\0\12\0\13\0\14\0\15\0\16\0\17\0\20\0\21\0\22\0\23\0\24\0\25\0\26\0\27\0\30\0\31\0\32\0\33\0\34\0\35\0\36\0\37\0\40\0\41\0\42\0\43\0\44\0\45\0\46\0\47\0\50\0\51\0\52\0\53\0\54\0\55\0\56\0\57\0\60\0\61\0\62\0\63\0\64\0\65\0\66\0\67\0\70\0\71\0\72\0\73\0\74\0\75\0\76\0\77\0\100\0\101\0\102\0\103\0\104\0\105\0\106\0\107\0\110\0\111\0\112\0\113\0\114\0\115\0\116\0\117\0\120\0\121\0\122\0\123\0\124\0\125\0\126\0\127\0\130\0\131\0\132\0\133\0\134\0\135\0\136\0\137\0\140\0\141\0\142\0\143\0\144\0\145\0\146\0\147\0\150\0\151\0\152\0\153\0\154\0\155\0\156\0\157\0\160\0\161\0\162\0\163\0\164\0\165\0\166\0\167\0\170\0\171\0\172\0\173\0\174\0\175\0\176\0\177\0\200\0\201\0\202\0\203\0\204\0\205\0\206\0\207\0\210\0\211\0\212\0\213\0\214\0\215\0\216\0\217\0\220\0\221\0\222\0\223\0\224\0\225\0\226\0\227\0\230\0\231\0\232\0\233\0\234\0\235\0\236\0\237\0\240\0\241\0\242\0\243\0\244\0\245\0\246\0\247\0\250\0\251\0\252\0\253\0\254\0\255\0\256\0\257\0\260\0\261\0\262\0\263\0\264\0\265\0\266\0\267\0\270\0\271\0\272\0\273\0\274\0\275\0\276\0\277\0\300\0\301\0\302\0\303\0\304\0\305\0\306\0\307\0\310\0\311\0\312\0\313\0\314\0\315\0\316\0\317\0\320\0\321\0\322\0\323\0\324\0\325\0\326\0\327\0\330\0\331\0\332\0\333\0\334\0\335\0\336\0\337\0\340\0\341\0\342\0\343\0\344\0\345\0\346\0\347\0\350\0\351\0\352\0\353\0\354\0\355\0\356\0\357\0\360\0\361\0\362\0\363\0\364\0\365\0\366\0\367\0\370\0\371\0\372\0\373\0\374\0\375\0\376\0\377";
const char* g_missing_geno_ptr = &(g_one_char_strs[96]);
const char* g_output_missing_geno_ptr = &(g_one_char_strs[96]);
uintptr_t g_failed_alloc_attempt_size = 0;
sfmt_t g_sfmt;
FILE* g_logfile = nullptr;
char g_logbuf[MAXLINELEN * 2];
uint32_t g_debug_on = 0;
uint32_t g_log_failed = 0;
uint32_t g_thread_ct;
uint32_t aligned_malloc(uintptr_t size, uintptr_t** aligned_pp) {
#if defined __LP64__ && !defined __APPLE__
// Avoid random segfaults on 64-bit machines which have 8-byte- instead of
// 16-byte-aligned malloc(). (Slightly different code is needed if malloc()
// does not even guarantee 8-byte alignment.)
uintptr_t* malloc_ptr = (uintptr_t*)malloc(size + VEC_BYTES);
if (!malloc_ptr) {
g_failed_alloc_attempt_size = size + VEC_BYTES;
return 1;
}
*aligned_pp = (uintptr_t*)((((uintptr_t)malloc_ptr) + VEC_BYTES) & (~(VEC_BYTES_M1 * ONELU)));
(*aligned_pp)[-1] = (uintptr_t)malloc_ptr;
#else
// no SSE2 concerns here
*aligned_pp = (uintptr_t*)malloc(size);
if (!(*aligned_pp)) {
g_failed_alloc_attempt_size = size;
return 1;
}
#endif
return 0;
}
void aligned_free(uintptr_t* aligned_pp) {
#if defined __LP64__ && !defined __APPLE__
free((uintptr_t*)(aligned_pp[-1]));
#else
free(aligned_pp);
#endif
}
uint32_t push_ll_str(const char* ss, Ll_str** ll_stack_ptr) {
uintptr_t str_bytes = strlen(ss) + 1;
Ll_str* new_ll_str = (Ll_str*)malloc(sizeof(Ll_str) + str_bytes);
if (!new_ll_str) {
g_failed_alloc_attempt_size = sizeof(Ll_str) + str_bytes;
return 1;
}
new_ll_str->next = *ll_stack_ptr;
memcpy(new_ll_str->ss, ss, str_bytes);
*ll_stack_ptr = new_ll_str;
return 0;
}
void logstr(const char* ss) {
if (!g_debug_on) {
fputs(ss, g_logfile);
if (ferror(g_logfile)) {
putc_unlocked('\n', stdout);
fflush(stdout);
fprintf(stderr, "Warning: Logging failure on:\n%s\nFurther logging will not be attempted in this run.\n", ss);
g_log_failed = 1;
}
} else {
if (g_log_failed) {
fflush(stdout);
fputs(ss, stderr);
} else {
fputs(ss, g_logfile);
if (ferror(g_logfile)) {
putc_unlocked('\n', stdout);
fflush(stdout);
fprintf(stderr, "Error: Debug logging failure. Dumping to stderr:\n%s", ss);
g_log_failed = 1;
} else {
fflush(g_logfile);
}
}
}
}
void logprint(const char* ss) {
logstr(ss);
fputs(ss, stdout);
}
void logerrprint(const char* ss) {
logstr(ss);
fflush(stdout);
fputs(ss, stderr);
}
void logprintb() {
logstr(g_logbuf);
fputs(g_logbuf, stdout);
}
void logerrprintb() {
logstr(g_logbuf);
fflush(stdout);
fputs(g_logbuf, stderr);
}
void wordwrap(uint32_t suffix_len, char* ss) {
// Input: A null-terminated string with no intermediate newlines. If
// suffix_len is zero, there should be a terminating \n; otherwise,
// the last character should be a space.
// Effect: Spaces are replaced with newlines in a manner that plays well with
// 80 column terminal windows. (Multi-space blocks are never
// collapsed.)
char* token_start = ss;
char* line_end = &(ss[79]);
char* token_end;
while (1) {
while (*token_start == ' ') {
token_start++;
}
if (token_start > line_end) {
do {
*line_end = '\n';
line_end = &(line_end[80]);
} while (token_start > line_end);
}
token_end = strchr(token_start, ' ');
if (!token_end) {
if (&(token_start[79]) == line_end) {
return;
}
token_end = strchr(token_start, '\0');
if (!suffix_len) {
if (token_end <= &(line_end[1])) {
// okay if end-of-string is one past the end, because function
// assumes last character is \n in suffix_len == 0 case
assert(token_end[-1] == '\n');
return;
}
} else {
if (&(token_end[suffix_len]) <= line_end) {
return;
}
// because of terminal space assumption, token_start actually points
// to the end of the string
assert(token_start[-1] == ' ');
}
token_start[-1] = '\n';
return;
}
if (token_end > line_end) {
if (&(token_start[79]) != line_end) {
token_start[-1] = '\n';
line_end = &(token_start[79]);
if (token_end > line_end) {
// single really long token, can't do anything beyond putting it on
// its own line
*token_end = '\n';
line_end = &(token_end[80]);
}
} else {
// single really long token, *and* previous token was either
// nonexistent or long
*token_end = '\n';
line_end = &(token_end[80]);
}
}
token_start = &(token_end[1]);
}
}
void wordwrapb(uint32_t suffix_len) {
wordwrap(suffix_len, g_logbuf);
}
int32_t fopen_checked(const char* fname, const char* mode, FILE** target_ptr) {
*target_ptr = fopen(fname, mode);
if (!(*target_ptr)) {
LOGERRPRINTFWW(g_errstr_fopen, fname);
return -1;
}
return 0;
}
int32_t fwrite_checked(const void* buf, size_t len, FILE* outfile) {
while (len > 0x7ffff000) {
// OS X can't perform 2GB+ writes
// typical disk block size is 4kb, so 0x7ffff000 is the largest sensible
// write size
fwrite(buf, 1, 0x7ffff000, outfile);
buf = &(((unsigned char*)buf)[0x7ffff000]);
len -= 0x7ffff000;
}
fwrite(buf, 1, len, outfile);
return ferror(outfile);
}
int32_t gzopen_read_checked(const char* fname, gzFile* gzf_ptr) {
*gzf_ptr = gzopen(fname, FOPEN_RB);
if (!(*gzf_ptr)) {
LOGERRPRINTFWW(g_errstr_fopen, fname);
return RET_OPEN_FAIL;
}
if (gzbuffer(*gzf_ptr, 131072)) {
return RET_NOMEM;
}
return 0;
}
// manually managed, very large stack
unsigned char* g_bigstack_base;
unsigned char* g_bigstack_end;
unsigned char* bigstack_alloc(uintptr_t size) {
unsigned char* alloc_ptr;
size = round_up_pow2(size, CACHELINE);
if (bigstack_left() < size) {
g_failed_alloc_attempt_size = size;
return nullptr;
}
alloc_ptr = g_bigstack_base;
g_bigstack_base += size;
return alloc_ptr;
}
void bigstack_shrink_top(const void* rebase, uintptr_t new_size) {
uintptr_t freed_bytes = ((uintptr_t)(g_bigstack_base - ((unsigned char*)rebase))) - round_up_pow2(new_size, CACHELINE);
g_bigstack_base -= freed_bytes;
}
unsigned char* bigstack_end_alloc_presized(uintptr_t size) {
assert(!(size & END_ALLOC_CHUNK_M1));
uintptr_t cur_bigstack_left = bigstack_left();
if (size > cur_bigstack_left) {
g_failed_alloc_attempt_size = size;
return nullptr;
} else {
g_bigstack_end -= size;
return g_bigstack_end;
}
}
uint32_t match_upper(const char* ss, const char* fixed_str) {
char cc = *fixed_str++;
do {
if ((((unsigned char)(*ss++)) & 0xdf) != ((unsigned char)cc)) {
return 0;
}
cc = *fixed_str++;
} while (cc);
return !(*ss);
}
uint32_t match_upper_counted(const char* ss, const char* fixed_str, uint32_t ct) {
do {
if ((((unsigned char)(*ss++)) & 0xdf) != ((unsigned char)(*fixed_str++))) {
return 0;
}
} while (--ct);
return 1;
}
#ifdef __LP64__
static inline uint32_t scan_uint_capped_finish(const char* ss, uint64_t cap, uint32_t* valp) {
uint64_t val = *valp;
while (1) {
// a little bit of unrolling seems to help
const uint64_t cur_digit = (uint64_t)((unsigned char)(*ss++)) - 48;
if (cur_digit >= 10) {
break;
}
// val = val * 10 + cur_digit;
const uint64_t cur_digit2 = (uint64_t)((unsigned char)(*ss++)) - 48;
if (cur_digit2 >= 10) {
val = val * 10 + cur_digit;
if (val > cap) {
return 1;
}
break;
}
val = val * 100 + cur_digit * 10 + cur_digit2;
if (val > cap) {
return 1;
}
}
*valp = val;
return 0;
}
uint32_t scan_posint_capped(const char* ss, uint64_t cap, uint32_t* valp) {
// '0' has ascii code 48
*valp = (uint32_t)((unsigned char)(*ss++)) - 48;
if (*valp >= 10) {
// permit leading '+' (ascii 43), but not '++' or '+-'
if (*valp != 0xfffffffbU) {
return 1;
}
*valp = (uint32_t)((unsigned char)(*ss++)) - 48;
if (*valp >= 10) {
return 1;
}
}
while (!(*valp)) {
*valp = (uint32_t)((unsigned char)(*ss++)) - 48;
if ((*valp) >= 10) {
return 1;
}
}
return scan_uint_capped_finish(ss, cap, valp);
}
uint32_t scan_uint_capped(const char* ss, uint64_t cap, uint32_t* valp) {
// Reads an integer in [0, cap]. Assumes first character is nonspace.
uint32_t val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
if (val != 0xfffffffbU) {
// '-' has ascii code 45, so unsigned 45 - 48 = 0xfffffffdU
if ((val != 0xfffffffdU) || (*ss != '0')) {
return 1;
}
// accept "-0", "-00", etc.
while (*(++ss) == '0');
*valp = 0;
return ((uint32_t)((unsigned char)(*ss)) - 48) < 10;
}
// accept leading '+'
val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
*valp = val;
return scan_uint_capped_finish(ss, cap, valp);
}
uint32_t scan_int_abs_bounded(const char* ss, uint64_t bound, int32_t* valp) {
// Reads an integer in [-bound, bound]. Assumes first character is nonspace.
*valp = (uint32_t)((unsigned char)(*ss++)) - 48;
int32_t sign = 1;
if (((uint32_t)*valp) >= 10) {
if (*valp == -3) {
sign = -1;
} else if (*valp != -5) {
return 1;
}
*valp = (uint32_t)((unsigned char)(*ss++)) - 48;
if (((uint32_t)*valp) >= 10) {
return 1;
}
}
if (scan_uint_capped_finish(ss, bound, (uint32_t*)valp)) {
return 1;
}
*valp *= sign;
return 0;
}
#else // not __LP64__
uint32_t scan_posint_capped32(const char* ss, uint32_t cap_div_10, uint32_t cap_mod_10, uint32_t* valp) {
// '0' has ascii code 48
uint32_t val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
if (val != 0xfffffffbU) {
return 1;
}
val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
while (!val) {
val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
while (1) {
const uint32_t cur_digit = (uint32_t)((unsigned char)(*ss++)) - 48;
if (cur_digit >= 10) {
*valp = val;
return 0;
}
// avoid integer overflow in middle of computation
if ((val >= cap_div_10) && ((val > cap_div_10) || (cur_digit > cap_mod_10))) {
return 1;
}
val = val * 10 + cur_digit;
}
}
uint32_t scan_uint_capped32(const char* ss, uint32_t cap_div_10, uint32_t cap_mod_10, uint32_t* valp) {
// Reads an integer in [0, cap]. Assumes first character is nonspace.
uint32_t val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
if (val != 0xfffffffbU) {
if ((val != 0xfffffffdU) || (*ss != '0')) {
return 1;
}
while (*(++ss) == '0');
*valp = 0;
return ((uint32_t)((unsigned char)(*ss)) - 48) < 10;
}
val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
while (1) {
const uint32_t cur_digit = (uint32_t)((unsigned char)(*ss++)) - 48;
if (cur_digit >= 10) {
*valp = val;
return 0;
}
if ((val >= cap_div_10) && ((val > cap_div_10) || (cur_digit > cap_mod_10))) {
return 1;
}
val = val * 10 + cur_digit;
}
}
uint32_t scan_int_abs_bounded32(const char* ss, uint32_t bound_div_10, uint32_t bound_mod_10, int32_t* valp) {
// Reads an integer in [-bound, bound]. Assumes first character is nonspace.
uint32_t val = (uint32_t)((unsigned char)(*ss++)) - 48;
int32_t sign = 1;
if (val >= 10) {
if (val == 0xfffffffdU) {
sign = -1;
} else if (val != 0xfffffffbU) {
return 1;
}
val = (uint32_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
while (1) {
const uint32_t cur_digit = (uint32_t)((unsigned char)(*ss++)) - 48;
if (cur_digit >= 10) {
*valp = sign * ((int32_t)val);
return 0;
}
if ((val >= bound_div_10) && ((val > bound_div_10) || (cur_digit > bound_mod_10))) {
return 1;
}
val = val * 10 + cur_digit;
}
}
#endif
uint32_t scan_posintptr(const char* ss, uintptr_t* valp) {
// Reads an integer in [1, 2^BITCT - 1]. Assumes first character is
// nonspace.
uintptr_t val = (uintptr_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
#ifdef __LP64__
if (val != 0xfffffffffffffffbLLU) {
return 1;
}
#else
if (val != 0xfffffffbU) {
return 1;
}
#endif
val = (uintptr_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
while (!val) {
val = (uintptr_t)((unsigned char)(*ss++)) - 48;
if (val >= 10) {
return 1;
}
}
// limit is 20 digits, we've already read one
#ifdef __LP64__
const char* ss_limit = &(ss[20]);
#else
const char* ss_limit = &(ss[10]);
#endif
while (1) {
const uintptr_t cur_digit = (uintptr_t)((unsigned char)(*ss++)) - 48;
if (cur_digit >= 10) {
*valp = val;
return 0;
}
const uintptr_t cur_digit2 = (uintptr_t)((unsigned char)(*ss++)) - 48;
if (ss == ss_limit) {
if ((cur_digit2 < 10) || ((val >= (~ZEROLU) / 10) && ((val > (~ZEROLU) / 10) || (cur_digit > (~ZEROLU) % 10)))) {
return 1;
}
*valp = val * 10 + cur_digit;
return 0;
}
if (cur_digit2 >= 10) {
*valp = val * 10 + cur_digit;
return 0;
}
val = val * 100 + cur_digit * 10 + cur_digit2;
}
}
/*
uint32_t scan_uintptr(char* ss, uintptr_t* valp) {
// [0, 2^BITCT - 1].
uintptr_t val = (uint32_t)((unsigned char)*ss) - 48;
uintptr_t cur_digit;
if (val < 10) {
while (1) {
scan_uintptr_main_loop:
cur_digit = (uint32_t)((unsigned char)(*(++ss))) - 48;
if (cur_digit >= 10) {
*valp = val;
return 0;
}
if ((val >= (~ZEROLU) / 10) && ((val > (~ZEROLU) / 10) || (cur_digit > (~ZEROLU) % 10))) {
return 1;
}
val = val * 10 + cur_digit;
}
}
ss++;
if (val != 0xfffffffdU) {
if (val == 0xfffffffbU) {
val = (uint32_t)((unsigned char)(*ss)) - 48;
if (val < 10) {
goto scan_uintptr_main_loop;
}
}
return 1;
}
if (*ss != '0') {
return 1;
}
while (*(++ss) == '0');
*valp = 0;
return ((uint32_t)((unsigned char)(*ss)) - 48) < 10;
}
*/
uint32_t scan_posint_cappedx(const char* ss, uint64_t cap, uint32_t* valp) {
double val;
if (scan_doublex(ss, &val) || (val < 1.0) || (val > ((double)cap))) {
return 1;
}
*valp = (uint32_t)val;
return (val != ((double)(*valp)));
}
uint32_t scan_uint_cappedx(const char* ss, uint64_t cap, uint32_t* valp) {
double val;
if (scan_doublex(ss, &val) || (val < 0.0) || (val > ((double)cap))) {
return 1;
}
*valp = (uint32_t)val;
return (val != ((double)(*valp)));
}
uint32_t scan_int_abs_boundedx(const char* ss, uint64_t bound, int32_t* valp) {
const double bound_d = (double)bound;
double val;
if (scan_doublex(ss, &val) || (val < -bound_d) || (val > bound_d)) {
return 1;
}
*valp = (int32_t)val;
return (val != ((double)(*valp)));
}
uint32_t scan_posintptrx(const char* ss, uintptr_t* valp) {
double val;
if (scan_doublex(ss, &val) || (val < 1.0) || (val > ((double)(~ZEROLU)))) {
return 1;
}
*valp = (uintptr_t)val;
return (val != ((double)(*valp)));
}
uint32_t scan_two_doubles(char* ss, double* __restrict val1p, double* __restrict val2p) {
char* ss2;
*val1p = strtod(ss, &ss2);
if (ss == ss2) {
return 1;
}
ss = skip_initial_spaces(ss2);
*val2p = strtod(ss, &ss2);
return (ss == ss2)? 1 : 0;
}
int32_t scan_token_ct_len(uintptr_t half_bufsize, FILE* infile, char* buf, uintptr_t* __restrict token_ct_ptr, uintptr_t* __restrict max_token_len_ptr) {
// buf must be of size >= (2 * half_bufsize + 2)
// max_token_len includes trailing null
uintptr_t full_bufsize = half_bufsize * 2;
uintptr_t curtoklen = 0;
uintptr_t token_ct = *token_ct_ptr;
uintptr_t max_token_len = *max_token_len_ptr;
char* midbuf = &(buf[half_bufsize]);
char* bufptr;
char* bufptr2;
char* buf_end;
uintptr_t bufsize;
while (1) {
if (fread_checked(midbuf, half_bufsize, infile, &bufsize)) {
return RET_READ_FAIL;
}
if (!bufsize) {
if (curtoklen) {
// corner case
if (curtoklen >= max_token_len) {
max_token_len = curtoklen + 1;
}
token_ct++;
}
break;
}
buf_end = &(midbuf[bufsize]);
*buf_end = ' ';
buf_end[1] = '0';
bufptr = &(buf[half_bufsize - curtoklen]);
bufptr2 = midbuf;
if (curtoklen) {
goto scan_token_ct_len_tok_start;
}
while (1) {
while (*bufptr <= ' ') {
bufptr++;
}
if (bufptr >= buf_end) {
curtoklen = 0;
break;
}
bufptr2 = &(bufptr[1]);
scan_token_ct_len_tok_start:
while (*bufptr2 > ' ') {
bufptr2++;
}
curtoklen = (uintptr_t)(bufptr2 - bufptr);
if ((bufptr2 == buf_end) && (buf_end == &(buf[full_bufsize]))) {
if (curtoklen >= half_bufsize) {
return RET_INVALID_FORMAT;
}
break;
}
if (curtoklen >= max_token_len) {
if (curtoklen >= half_bufsize) {
return RET_INVALID_FORMAT;
}
max_token_len = curtoklen + 1;
}
token_ct++;
bufptr = &(bufptr2[1]);
}
}
if (!feof(infile)) {
return RET_READ_FAIL;
}
*max_token_len_ptr = max_token_len;
*token_ct_ptr = token_ct;
return 0;
}
int32_t read_tokens(uintptr_t half_bufsize, uintptr_t token_ct, uintptr_t max_token_len, FILE* infile, char* __restrict buf, char* __restrict token_name_buf) {
// buf must be of size >= (2 * half_bufsize + 2).
// max_token_len includes trailing null
uintptr_t full_bufsize = half_bufsize * 2;
uintptr_t curtoklen = 0;
uintptr_t token_idx = 0;
char* midbuf = &(buf[half_bufsize]);
char* bufptr = midbuf;
char* bufptr2;
char* bufptr3;
char* buf_end;
uintptr_t bufsize;
while (1) {
if (fread_checked(midbuf, half_bufsize, infile, &bufsize)) {
return RET_READ_FAIL;
}
if (!bufsize) {
if (curtoklen) {
if (token_idx + 1 == token_ct) {
memcpyx(&(token_name_buf[token_idx * max_token_len]), bufptr, curtoklen, '\0');
return 0;
}
}
// something very strange has to happen to get here
return RET_READ_FAIL;
}
buf_end = &(midbuf[bufsize]);
*buf_end = ' ';
buf_end[1] = '0';
bufptr2 = midbuf;
if (curtoklen) {
goto read_tokens_tok_start;
}
while (1) {
while (*bufptr <= ' ') {
bufptr++;
}
if (bufptr >= buf_end) {
curtoklen = 0;
bufptr = midbuf;
break;
}
bufptr2 = &(bufptr[1]);
read_tokens_tok_start:
while (*bufptr2 > ' ') {
bufptr2++;
}
curtoklen = (uintptr_t)(bufptr2 - bufptr);
if ((bufptr2 == buf_end) && (buf_end == &(buf[full_bufsize]))) {
bufptr3 = &(buf[half_bufsize - curtoklen]);
memcpy(bufptr3, bufptr, curtoklen);
bufptr = bufptr3;
break;
}
memcpyx(&(token_name_buf[token_idx * max_token_len]), bufptr, curtoklen, '\0');
if (++token_idx == token_ct) {
return 0;
}
bufptr = &(bufptr2[1]);
}
}
}
int32_t gzputs_w4(gzFile gz_outfile, const char* ss) {
if (!ss[1]) {
if (gzputs(gz_outfile, " ") == -1) {
return -1;
}
return gzputc(gz_outfile, ss[0]);
}
if (!ss[2]) {
if (gzputs(gz_outfile, " ") == -1) {
return -1;
}
} else if (!ss[3]) {
if (gzputc(gz_outfile, ' ') == -1) {
return -1;
}
}
return gzputs(gz_outfile, ss);
}
int32_t get_next_noncomment(FILE* fptr, char** lptr_ptr, uintptr_t* line_idx_ptr) {
char* lptr;
do {
if (!fgets(g_textbuf, MAXLINELEN, fptr)) {
return -1;
}
*line_idx_ptr += 1;
lptr = skip_initial_spaces(g_textbuf);
} while (is_eoln_or_comment_kns(*lptr));
*lptr_ptr = lptr;
return 0;
}
int32_t get_next_noncomment_excl(const uintptr_t* __restrict marker_exclude, FILE* fptr, char** lptr_ptr, uintptr_t* __restrict line_idx_ptr, uintptr_t* __restrict marker_uidx_ptr) {
while (!get_next_noncomment(fptr, lptr_ptr, line_idx_ptr)) {
if (!is_set_ul(marker_exclude, *marker_uidx_ptr)) {
return 0;
}
*marker_uidx_ptr += 1;
}
return -1;
}
void get_top_two_ui(const uint32_t* __restrict uint_arr, uintptr_t uia_size, uintptr_t* __restrict top_idx_ptr, uintptr_t* __restrict second_idx_ptr) {
assert(uia_size > 1);
uintptr_t top_idx = (uint_arr[1] > uint_arr[0])? 1 : 0;
uintptr_t second_idx = 1 ^ top_idx;
uint32_t top_val = uint_arr[top_idx];
uint32_t second_val = uint_arr[second_idx];
uintptr_t cur_idx;
uintptr_t cur_val;
for (cur_idx = 2; cur_idx < uia_size; ++cur_idx) {
cur_val = uint_arr[cur_idx];
if (cur_val > second_val) {
if (cur_val > top_val) {
second_val = top_val;
second_idx = top_idx;
top_val = cur_val;
top_idx = cur_idx;
} else {
second_val = cur_val;
second_idx = cur_idx;
}
}
}
*top_idx_ptr = top_idx;
*second_idx_ptr = second_idx;
}
uint32_t intlen(int32_t num) {
int32_t retval = 1;
uint32_t absnum;
if (num < 0) {
absnum = -num;
retval++;
} else {
absnum = num;
}
while (absnum > 99) {
// division by a constant is faster for unsigned ints
absnum /= 100;
retval += 2;
}
if (absnum > 9) {
retval++;
}
return retval;
}
int32_t strcmp_se(const char* s_read, const char* s_const, uint32_t s_const_len) {
return memcmp(s_read, s_const, s_const_len) || (!is_space_or_eoln(s_read[s_const_len]));
}
char* next_token(char* sptr) {
if (!sptr) {
return nullptr;
}
unsigned char ucc = *sptr;
while (ucc > 32) {
ucc = *(++sptr);
}
while ((ucc == ' ') || (ucc == '\t')) {
ucc = *(++sptr);
}
return (ucc > 32)? sptr : nullptr;
}
char* next_token_mult(char* sptr, uint32_t ct) {
assert(ct);
if (!sptr) {
return nullptr;
}
unsigned char ucc = *sptr;
do {
while (ucc > 32) {
ucc = *(++sptr);
}
while ((ucc == ' ') || (ucc == '\t')) {
ucc = *(++sptr);
}
if (ucc <= 32) {
return nullptr;
}
} while (--ct);
return sptr;
}
uint32_t count_tokens(const char* bufptr) {
uint32_t token_ct = 0;
while ((*bufptr == ' ') || (*bufptr == '\t')) {
bufptr++;
}
while (!is_eoln_kns(*bufptr)) {
token_ct++;
while (!is_space_or_eoln(*(++bufptr)));
while ((*bufptr == ' ') || (*bufptr == '\t')) {
bufptr++;
}
}
return token_ct;
}
uint32_t count_and_measure_multistr(const char* multistr, uintptr_t* max_slen_ptr) {
// max_slen includes null terminator
// assumes multistr is nonempty
uint32_t ct = 0;
uintptr_t max_slen = *max_slen_ptr;
uintptr_t slen;
do {
slen = strlen(multistr) + 1;
if (slen > max_slen) {
max_slen = slen;
}
multistr = &(multistr[slen]);
ct++;
} while (*multistr);
*max_slen_ptr = max_slen;
return ct;
}
// number-to-string encoders
static const char digit2_table[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
'0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
'1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
'2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
'2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
'4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
'4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
'5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
'5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
'6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
'7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
'8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
'9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
char* uint32toa(uint32_t uii, char* start) {
// Memory-efficient fast integer writer. (You can do a bit better sometimes
// by using a larger lookup table, but on average I doubt that pays off.)
// Returns a pointer to the end of the integer (not null-terminated).
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
*start++ = '0' + uii;
return start;
}
if (uii < 100) {
goto uint32toa_2;
}
quotient = uii / 100;
*start++ = '0' + quotient;
} else {
if (uii < 10000000) {
if (uii >= 100000) {
if (uii < 1000000) {
goto uint32toa_6;
}
quotient = uii / 1000000;
*start++ = '0' + quotient;
goto uint32toa_6b;
}
if (uii < 10000) {
goto uint32toa_4;
}
quotient = uii / 10000;
*start++ = '0' + quotient;
} else {
if (uii >= 100000000) {
quotient = uii / 100000000;
if (uii >= 1000000000) {
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
} else {
*start++ = '0' + quotient;
}
uii -= 100000000 * quotient;
}
quotient = uii / 1000000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uint32toa_6b:
uii -= 1000000 * quotient;
uint32toa_6:
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 10000 * quotient;
uint32toa_4:
// could make a uitoa_z4() call here, but that's slightly slower
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 100 * quotient;
uint32toa_2:
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
char* int32toa(int32_t ii, char* start) {
uint32_t uii = ii;
if (ii < 0) {
// -INT_MIN is undefined, but negating the unsigned int equivalent works
*start++ = '-';
uii = -uii;
}
return uint32toa(uii, start);
}
char* uitoa_z4(uint32_t uii, char* start) {
uint32_t quotient = uii / 100;
assert(quotient < 100);
uii -= 100 * quotient;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
char* uitoa_z6(uint32_t uii, char* start) {
uint32_t quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
return uitoa_z4(uii - 10000 * quotient, start);
}
char* uitoa_z8(uint32_t uii, char* start) {
uint32_t quotient = uii / 1000000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
return uitoa_z6(uii - 1000000 * quotient, start);
}
char* int64toa(int64_t llii, char* start) {
uint64_t ullii = llii;
uint64_t top_digits;
uint32_t bottom_eight;
uint32_t middle_eight;
if (llii < 0) {
*start++ = '-';
ullii = -ullii;
}
if (ullii <= 0xffffffffLLU) {
return uint32toa((uint32_t)ullii, start);
}
top_digits = ullii / 100000000;
bottom_eight = (uint32_t)(ullii - (top_digits * 100000000));
if (top_digits <= 0xffffffffLLU) {
start = uint32toa((uint32_t)top_digits, start);
return uitoa_z8(bottom_eight, start);
}
ullii = top_digits / 100000000;
middle_eight = (uint32_t)(top_digits - (ullii * 100000000));
start = uint32toa((uint32_t)ullii, start);
start = uitoa_z8(middle_eight, start);
return uitoa_z8(bottom_eight, start);
}
char* uint32toa_w4(uint32_t uii, char* start) {
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
// assumes little-endian
*((uint32_t*)start) = 0x30202020 + (uii << 24);
return &(start[4]);
}
if (uii < 100) {
memset(start, 32, 2);
} else {
quotient = uii / 100;
*start++ = ' ';
*start++ = '0' + quotient;
uii -= quotient * 100;
}
return memcpya(start, &(digit2_table[uii * 2]), 2);
} else {
// presumably the field width is 4 for a reason; don't bother optimizing
// this
return uint32toa(uii, start);
}
}
char* uint32toa_w6(uint32_t uii, char* start) {
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
start = memseta(start, 32, 5);
*start++ = '0' + uii;
return start;
}
if (uii < 100) {
start = memseta(start, 32, 4);
goto uint32toa_w6_2;
}
quotient = uii / 100;
// the little-endian trick doesn't seem to help here. possibly relevant
// differences from uint32toa_w4() and _w8(): sequential dependence on
// quotient, need to interpret pointer as a char* again
start = memseta(start, 32, 3);
*start++ = '0' + quotient;
} else {
if (uii < 10000000) {
if (uii >= 100000) {
if (uii < 1000000) {
goto uint32toa_w6_6;
}
quotient = uii / 1000000;
*start++ = '0' + quotient;
goto uint32toa_w6_6b;
} else if (uii >= 10000) {
*start++ = ' ';
quotient = uii / 10000;
*start++ = '0' + quotient;
} else {
start = memseta(start, 32, 2);
goto uint32toa_w6_4;
}
} else {
if (uii >= 100000000) {
quotient = uii / 100000000;
if (uii >= 1000000000) {
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
} else {
*start++ = '0' + quotient;
}
uii -= 100000000 * quotient;
}
quotient = uii / 1000000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uint32toa_w6_6b:
uii -= 1000000 * quotient;
uint32toa_w6_6:
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 10000 * quotient;
uint32toa_w6_4:
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 100 * quotient;
uint32toa_w6_2:
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
char* uint32toa_w7(uint32_t uii, char* start) {
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
start = memseta(start, 32, 6);
*start++ = '0' + uii;
return start;
}
if (uii < 100) {
start = memseta(start, 32, 5);
goto uint32toa_w7_2;
}
quotient = uii / 100;
start = memseta(start, 32, 4);
*start++ = '0' + quotient;
} else {
if (uii < 10000000) {
if (uii >= 100000) {
if (uii >= 1000000) {
quotient = uii / 1000000;
*start++ = '0' + quotient;
goto uint32toa_w7_6b;
}
*start++ = ' ';
goto uint32toa_w7_6;
} else if (uii >= 10000) {
start = memseta(start, 32, 2);
quotient = uii / 10000;
*start++ = '0' + quotient;
} else {
start = memseta(start, 32, 3);
goto uint32toa_w7_4;
}
} else {
if (uii >= 100000000) {
quotient = uii / 100000000;
if (uii >= 1000000000) {
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
} else {
*start++ = '0' + quotient;
}
uii -= 100000000 * quotient;
}
quotient = uii / 1000000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uint32toa_w7_6b:
uii -= 1000000 * quotient;
uint32toa_w7_6:
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 10000 * quotient;
uint32toa_w7_4:
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 100 * quotient;
uint32toa_w7_2:
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
char* uint32toa_w8(uint32_t uii, char* start) {
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
#ifdef __LP64__
*((uintptr_t*)start) = 0x3020202020202020LLU + (((uintptr_t)uii) << 56);
return &(start[8]);
#else
start = memseta(start, 32, 7);
*start++ = '0' + uii;
return start;
#endif
}
if (uii < 100) {
start = memseta(start, 32, 6);
goto uint32toa_w8_2;
}
quotient = uii / 100;
start = memseta(start, 32, 5);
*start++ = '0' + quotient;
} else {
if (uii < 10000000) {
if (uii >= 100000) {
if (uii < 1000000) {
start = memseta(start, 32, 2);
goto uint32toa_w8_6;
}
quotient = uii / 1000000;
*start = ' ';
start[1] = '0' + quotient;
start += 2;
goto uint32toa_w8_6b;
} else if (uii < 10000) {
start = memseta(start, 32, 4);
goto uint32toa_w8_4;
}
memset(start, 32, 3);
quotient = uii / 10000;
start[3] = '0' + quotient;
start += 4;
} else {
if (uii >= 100000000) {
quotient = uii / 100000000;
if (uii >= 1000000000) {
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
} else {
*start++ = '0' + quotient;
}
uii -= 100000000 * quotient;
}
quotient = uii / 1000000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uint32toa_w8_6b:
uii -= 1000000 * quotient;
uint32toa_w8_6:
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 10000 * quotient;
uint32toa_w8_4:
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 100 * quotient;
uint32toa_w8_2:
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
char* uint32toa_w10(uint32_t uii, char* start) {
// if we decide to reduce code size and optimize only one field width, this
// should be it
uint32_t quotient;
if (uii < 1000) {
if (uii < 10) {
start = memseta(start, 32, 9);
*start++ = '0' + uii;
return start;
}
if (uii < 100) {
start = memseta(start, 32, 8);
goto uint32toa_w10_2;
}
quotient = uii / 100;
start = memseta(start, 32, 7);
*start++ = '0' + quotient;
} else {
if (uii < 10000000) {
if (uii >= 100000) {
if (uii < 1000000) {
start = memseta(start, 32, 4);
goto uint32toa_w10_6;
}
quotient = uii / 1000000;
memset(start, 32, 3);
start[3] = '0' + quotient;
start += 4;
goto uint32toa_w10_6b;
} else if (uii < 10000) {
start = memseta(start, 32, 6);
goto uint32toa_w10_4;
}
memset(start, 32, 5);
quotient = uii / 10000;
start[5] = '0' + quotient;
start += 6;
} else {
if (uii >= 100000000) {
quotient = uii / 100000000;
if (uii >= 1000000000) {
memcpy(start, &(digit2_table[quotient * 2]), 2);
} else {
*start = ' ';
start[1] = '0' + quotient;
}
uii -= 100000000 * quotient;
} else {
memset(start, 32, 2);
}
quotient = uii / 1000000;
memcpy(&(start[2]), &(digit2_table[quotient * 2]), 2);
start += 4;
uint32toa_w10_6b:
uii -= 1000000 * quotient;
uint32toa_w10_6:
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 10000 * quotient;
uint32toa_w10_4:
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
}
uii -= 100 * quotient;
uint32toa_w10_2:
return memcpya(start, &(digit2_table[uii * 2]), 2);
}
static inline char* uitoa_trunc2(uint32_t uii, char* start) {
// Given 0 < uii < 100, writes uii without *trailing* zeroes. (I.e. this is
// for floating-point encoder use.)
memcpy(start, &(digit2_table[uii * 2]), 2);
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* uitoa_trunc3(uint32_t uii, char* start) {
*start++ = '0' + (uii / 100);
uii %= 100;
if (!uii) {
return start;
}
memcpy(start, &(digit2_table[uii * 2]), 2);
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* uitoa_trunc4(uint32_t uii, char* start) {
uint32_t quotient = uii / 100;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
if (uii) {
start += 2;
memcpy(start, &(digit2_table[uii * 2]), 2);
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* uitoa_trunc6(uint32_t uii, char* start) {
uint32_t quotient = uii / 10000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 10000 * quotient;
if (uii) {
quotient = uii / 100;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
if (uii) {
start += 2;
memcpy(start, &(digit2_table[uii * 2]), 2);
}
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* uitoa_trunc8(uint32_t uii, char* start) {
uint32_t quotient = uii / 1000000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 1000000 * quotient;
if (uii) {
quotient = uii / 10000;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 10000 * quotient;
if (uii) {
quotient = uii / 100;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
if (uii) {
start += 2;
memcpy(start, &(digit2_table[uii * 2]), 2);
}
}
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* qrtoa_1p1(uint32_t quotient, uint32_t remainder, char* start) {
start[0] = '0' + quotient;
if (!remainder) {
return &(start[1]);
}
start[1] = '.';
start[2] = '0' + remainder;
return &(start[3]);
}
static inline char* qrtoa_1p2(uint32_t quotient, uint32_t remainder, char* start) {
*start++ = '0' + quotient;
if (!remainder) {
return start;
}
*start++ = '.';
memcpy(start, &(digit2_table[remainder * 2]), 2);
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* qrtoa_1p3(uint32_t quotient, uint32_t remainder, char* start) {
// quotient = (int32_t)dxx;
// remainder = ((int32_t)(dxx * 1000)) - (quotient * 1000);
*start++ = '0' + quotient;
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 10;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 10 * quotient;
if (remainder) {
start[2] = '0' + remainder;
return &(start[3]);
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* qrtoa_1p5(uint32_t quotient, uint32_t remainder, char* start) {
*start++ = '0' + quotient;
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 1000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 1000 * quotient;
if (remainder) {
quotient = remainder / 10;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 10 * quotient;
if (remainder) {
start[2] = '0' + remainder;
return &(start[3]);
}
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
static inline char* qrtoa_1p7(uint32_t quotient, uint32_t remainder, char* start) {
*start++ = '0' + quotient;
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 100000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 100000 * quotient;
if (remainder) {
quotient = remainder / 1000;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 1000 * quotient;
if (remainder) {
quotient = remainder / 10;
start += 2;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 10 * quotient;
if (remainder) {
start[2] = '0' + remainder;
return &(start[3]);
}
}
}
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
}
// Okay, time to do banker's rounding when printing doubles. 14 digits of
// precision are used in judging equality to 0.5 (actual precision of doubles
// is 15-17 digits); the intention is to capture all directly loaded or exactly
// computed edge cases (so enough tolerance is needed to survive the internal
// multiplications by powers of 10, etc.), while rounding a negligible number
// of honest-to-god 0.4999999s up and 0.5000001s down.
// To avoid inadvertent printing of an extra digit, there's a deliberate gap
// between the 99.9994999...-type bounds and the largest numbers that would
// actually round down.
static const double banker_round5[] = {0.499995, 0.500005};
static const double banker_round6[] = {0.4999995, 0.5000005};
static const double banker_round7[] = {0.49999995, 0.50000005};
static const double banker_round8[] = {0.499999995, 0.500000005};
static const double banker_round9[] = {0.4999999995, 0.5000000005};
static const double banker_round10[] = {0.49999999995, 0.50000000005};
static const double banker_round11[] = {0.499999999995, 0.500000000005};
static const double banker_round12[] = {0.4999999999995, 0.5000000000005};
static inline uint32_t double_bround(double dxx, const double* banker_round) {
uint32_t result = (int32_t)dxx;
return result + (int32_t)((dxx - ((int32_t)result)) + banker_round[result & 1]);
}
// These are separate functions so the compiler can optimize the integer
// divisions.
static inline void double_bround1(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 10;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 10;
*remainderp = remainder - (*quotientp) * 10;
}
static inline void double_bround2(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 100;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 100;
*remainderp = remainder - (*quotientp) * 100;
}
static inline void double_bround3(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 1000;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 1000;
*remainderp = remainder - (*quotientp) * 1000;
}
static inline void double_bround4(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 10000;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 10000;
*remainderp = remainder - (*quotientp) * 10000;
}
static inline void double_bround5(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 100000;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 100000;
*remainderp = remainder - (*quotientp) * 100000;
}
static inline void double_bround6(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 1000000;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 1000000;
*remainderp = remainder - (*quotientp) * 1000000;
}
static inline void double_bround7(double dxx, const double* banker_round, uint32_t* quotientp, uint32_t* remainderp) {
dxx *= 10000000;
uint32_t remainder = (int32_t)dxx;
remainder += (int32_t)((dxx - ((int32_t)remainder)) + banker_round[remainder & 1]);
*quotientp = remainder / 10000000;
*remainderp = remainder - (*quotientp) * 10000000;
}
char* dtoa_so6(double dxx, char* start) {
// 6 sig fig number, 0.999995 <= dxx < 999999.5
// 'so' = "significand only"
// Just hardcoding all six cases, in the absence of a better approach...
uint32_t uii;
uint32_t quotient;
uint32_t remainder;
if (dxx < 99.999949999999) {
if (dxx < 9.9999949999999) {
double_bround5(dxx, banker_round8, &quotient, &remainder);
return qrtoa_1p5(quotient, remainder, start);
}
double_bround4(dxx, banker_round8, &quotient, &remainder);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 100;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 100 * quotient;
if (remainder) {
start += 2;
dtoa_so6_pretail:
memcpy(start, &(digit2_table[remainder * 2]), 2);
}
dtoa_so6_tail:
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
} else if (dxx < 9999.9949999999) {
if (dxx < 999.99949999999) {
double_bround3(dxx, banker_round8, &uii, &remainder);
quotient = uii / 100;
*start++ = '0' + quotient;
quotient = uii - 100 * quotient;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 10;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= quotient * 10;
if (!remainder) {
goto dtoa_so6_tail;
}
start[2] = '0' + remainder;
return &(start[3]);
}
double_bround2(dxx, banker_round8, &uii, &remainder);
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
quotient = uii - (100 * quotient);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
goto dtoa_so6_pretail;
} else if (dxx < 99999.949999999) {
double_bround1(dxx, banker_round8, &uii, &remainder);
quotient = uii / 10000;
*start = '0' + quotient;
uii -= 10000 * quotient;
quotient = uii / 100;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
uii = uii - 100 * quotient;
start = memcpya(start, &(digit2_table[uii * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
*start = '0' + remainder;
return &(start[1]);
} else {
return uitoa_z6(double_bround(dxx, banker_round8), start);
}
}
// Briefly had banker's rounding for floats, but then I realized that the only
// float-printing function calls are --make-grm related, they all request 6-7
// digits of precision, and at that point it's impossible to distinguish exact
// 0.5-matches in the remainder. So we just have generic rounding functions
// here, with similar interfaces to the double-rounding functions to minimize
// the need for separate reasoning about this code.
static inline uint32_t float_round(float fxx) {
return (uint32_t)((int32_t)(fxx + 0.5));
}
static inline void float_round1(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 10);
*quotientp = remainder / 10;
*remainderp = remainder - (*quotientp) * 10;
}
static inline void float_round2(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 100);
*quotientp = remainder / 100;
*remainderp = remainder - (*quotientp) * 100;
}
static inline void float_round3(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 1000);
*quotientp = remainder / 1000;
*remainderp = remainder - (*quotientp) * 1000;
}
static inline void float_round4(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 10000);
*quotientp = remainder / 10000;
*remainderp = remainder - (*quotientp) * 10000;
}
static inline void float_round5(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 100000);
*quotientp = remainder / 100000;
*remainderp = remainder - (*quotientp) * 100000;
}
static inline void float_round6(float fxx, uint32_t* quotientp, uint32_t* remainderp) {
uint32_t remainder = float_round(fxx * 1000000);
*quotientp = remainder / 1000000;
*remainderp = remainder - (*quotientp) * 1000000;
}
char* ftoa_so6(float fxx, char* start) {
uint32_t uii;
uint32_t quotient;
uint32_t remainder;
// difference between consecutive floats near 10 can be as large as
// 10 * 2^{-23}, which is just under 1.2e-6. So, to avoid printing an extra
// digit, we have to set this bound to be robust to an addition error of size
// 6e-7.
// (possible todo: just brute-force test this on all <2^32 possible floats
// and look for a better threshold)
if (fxx < 99.999944) {
if (fxx < 9.9999944) {
float_round5(fxx, &quotient, &remainder);
return qrtoa_1p5(quotient, remainder, start);
}
float_round4(fxx, &quotient, &remainder);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 100;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 100 * quotient;
if (remainder) {
start += 2;
ftoa_so6_pretail:
memcpy(start, &(digit2_table[remainder * 2]), 2);
}
ftoa_so6_tail:
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
} else if (fxx < 9999.9944) {
if (fxx < 999.99944) {
float_round3(fxx, &uii, &remainder);
quotient = uii / 100;
*start = '0' + quotient;
quotient = uii - 100 * quotient;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 10;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= quotient * 10;
if (!remainder) {
goto ftoa_so6_tail;
}
start[2] = '0' + remainder;
return &(start[3]);
}
float_round2(fxx, &uii, &remainder);
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
quotient = uii - (100 * quotient);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
goto ftoa_so6_pretail;
} else if (fxx < 99999.944) {
float_round1(fxx, &uii, &remainder);
quotient = uii / 10000;
*start = '0' + quotient;
uii -= 10000 * quotient;
quotient = uii / 100;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
uii = uii - 100 * quotient;
start = memcpya(start, &(digit2_table[uii * 2]), 2);
if (!remainder) {
return start;
}
*start = '.';
start[1] = '0' + remainder;
return &(start[2]);
} else {
return uitoa_z6(float_round(fxx), start);
}
}
char* dtoa_so2(double dxx, char* start) {
// 2 sig fig number, 0.95 <= dxx < 99.5
uint32_t quotient;
uint32_t remainder;
if (dxx < 9.9499999999999) {
double_bround1(dxx, banker_round12, &quotient, &remainder);
return qrtoa_1p1(quotient, remainder, start);
}
return memcpya(start, &(digit2_table[(double_bround(dxx, banker_round12)) * 2]), 2);
}
char* dtoa_so3(double dxx, char* start) {
// 3 sig fig number, 0.995 <= dxx < 999.5
uint32_t quotient;
uint32_t remainder;
if (dxx < 99.949999999999) {
if (dxx < 9.9949999999999) {
double_bround2(dxx, banker_round11, &quotient, &remainder);
return qrtoa_1p2(quotient, remainder, start);
}
double_bround1(dxx, banker_round11, &quotient, &remainder);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
} else {
quotient = double_bround(dxx, banker_round11);
start = memcpya(start, &(digit2_table[(quotient / 10) * 2]), 2);
remainder = quotient % 10;
}
*start = '0' + remainder;
return &(start[1]);
}
char* dtoa_so4(double dxx, char* start) {
// 4 sig fig number, 0.9995 <= dxx < 9999.5
uint32_t uii;
uint32_t quotient;
uint32_t remainder;
if (dxx < 99.994999999999) {
if (dxx < 9.9994999999999) {
double_bround3(dxx, banker_round10, &quotient, &remainder);
return qrtoa_1p3(quotient, remainder, start);
}
double_bround2(dxx, banker_round10, &quotient, &remainder);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
memcpy(start, &(digit2_table[remainder * 2]), 2);
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
} else if (dxx < 999.94999999999) {
double_bround1(dxx, banker_round10, &uii, &remainder);
quotient = uii / 100;
*start = '0' + quotient;
quotient = uii - 100 * quotient;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start = '.';
start[1] = '0' + remainder;
return &(start[2]);
} else {
uitoa_z4(double_bround(dxx, banker_round10), start);
return &(start[4]);
}
}
char* dtoa_so8(double dxx, char* start) {
// 8 sig fig number, 0.99999995 <= dxx < 99999999.5
uint32_t uii;
uint32_t quotient;
uint32_t remainder;
if (dxx < 99.999999499999) {
if (dxx < 9.9999999499999) {
double_bround7(dxx, banker_round6, &quotient, &remainder);
return qrtoa_1p7(quotient, remainder, start);
}
double_bround6(dxx, banker_round6, &quotient, &remainder);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 10000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 10000 * quotient;
if (remainder) {
start += 2;
dtoa_so8_pretail4:
quotient = remainder / 100;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= 100 * quotient;
if (remainder) {
start += 2;
dtoa_so8_pretail2:
memcpy(start, &(digit2_table[remainder * 2]), 2);
}
}
dtoa_so8_tail:
if (start[1] != '0') {
return &(start[2]);
}
return &(start[1]);
} else if (dxx < 9999.9999499999) {
if (dxx < 999.99999499999) {
double_bround5(dxx, banker_round6, &uii, &remainder);
quotient = uii / 100;
*start++ = '0' + quotient;
quotient = uii - 100 * quotient;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
quotient = remainder / 1000;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= quotient * 1000;
if (!remainder) {
goto dtoa_so8_tail;
}
start += 2;
dtoa_so8_pretail3:
quotient = remainder / 10;
memcpy(start, &(digit2_table[quotient * 2]), 2);
remainder -= quotient * 10;
if (!remainder) {
goto dtoa_so8_tail;
}
start[2] = '0' + remainder;
return &(start[3]);
}
double_bround4(dxx, banker_round6, &uii, &remainder);
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
quotient = uii - (100 * quotient);
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
goto dtoa_so8_pretail4;
} else if (dxx < 999999.99499999) {
if (dxx < 99999.999499999) {
double_bround3(dxx, banker_round6, &uii, &remainder);
quotient = uii / 10000;
*start = '0' + quotient;
uii -= 10000 * quotient;
quotient = uii / 100;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
start = memcpya(start, &(digit2_table[uii * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
goto dtoa_so8_pretail3;
}
double_bround2(dxx, banker_round6, &uii, &remainder);
quotient = uii / 10000;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uii -= 10000 * quotient;
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
start = memcpya(start, &(digit2_table[uii * 2]), 2);
if (!remainder) {
return start;
}
*start++ = '.';
goto dtoa_so8_pretail2;
} else if (dxx < 9999999.9499999) {
double_bround1(dxx, banker_round6, &uii, &remainder);
quotient = uii / 1000000;
*start = '0' + quotient;
uii -= 1000000 * quotient;
quotient = uii / 10000;
start = memcpya(&(start[1]), &(digit2_table[quotient * 2]), 2);
uii -= 10000 * quotient;
quotient = uii / 100;
start = memcpya(start, &(digit2_table[quotient * 2]), 2);
uii -= 100 * quotient;
start = memcpya(start, &(digit2_table[uii * 2]), 2);
if (!remainder) {
return start;
}
*start = '.';
start[1] = '0' + remainder;
return &(start[2]);
} else {
return uitoa_z8(double_bround(dxx, banker_round6), start);
}
}
char* dtoa_e(double dxx, char* start) {
uint32_t xp10 = 0;
uint32_t quotient;
uint32_t remainder;
char sign;
if (dxx != dxx) {
// do this first to avoid generating exception
return memcpyl3a(start, "nan");
} else if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
}
if (dxx >= 9.9999994999999e-1) {
if (dxx >= 9.9999994999999e7) {
if (dxx >= 9.9999994999999e127) {
if (dxx == INFINITY) {
return memcpyl3a(start, "inf");
} else if (dxx >= 9.9999994999999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9999994999999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9999994999999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9999994999999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
if (dxx >= 9.9999994999999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
}
if (dxx >= 9.9999994999999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9999994999999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9999994999999) {
dxx *= 1.0e-1;
xp10++;
}
sign = '+';
} else {
if (dxx < 9.9999994999999e-8) {
// general case
if (dxx < 9.9999994999999e-128) {
if (dxx == 0.0) {
return memcpya(start, "0.000000e+00", 12);
}
if (dxx < 9.9999994999999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9999994999999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9999994999999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9999994999999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
if (dxx < 9.9999994999999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
}
if (dxx < 9.999994999999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9999994999999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9999994999999e-1) {
dxx *= 10;
xp10++;
}
sign = '-';
}
double_bround6(dxx, banker_round7, &quotient, &remainder);
*start++ = '0' + quotient;
*start++ = '.';
start = uitoa_z6(remainder, start);
*start++ = 'e';
*start++ = sign;
if (xp10 >= 100) {
quotient = xp10 / 100;
*start++ = '0' + quotient;
xp10 -= quotient * 100;
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
}
char* ftoa_e(float fxx, char* start) {
uint32_t xp10 = 0;
uint32_t quotient;
uint32_t remainder;
char sign;
if (fxx != fxx) {
// do this first to avoid generating exception
return memcpyl3a(start, "nan");
} else if (fxx < 0) {
*start++ = '-';
fxx = -fxx;
}
if (fxx >= 9.9999995e-1) {
if (fxx >= 9.9999995e15) {
if (fxx == INFINITY) {
return memcpyl3a(start, "inf");
} else if (fxx >= 9.9999995e31) {
fxx *= 1.0e-32;
xp10 |= 32;
} else {
fxx *= 1.0e-16;
xp10 |= 16;
}
}
if (fxx >= 9.9999995e7) {
fxx *= 1.0e-8;
xp10 |= 8;
}
if (fxx >= 9.9999995e3) {
fxx *= 1.0e-4;
xp10 |= 4;
}
if (fxx >= 9.9999995e1) {
fxx *= 1.0e-2;
xp10 |= 2;
}
if (fxx >= 9.9999995) {
fxx *= 1.0e-1;
xp10++;
}
sign = '+';
} else {
if (fxx < 9.9999995e-16) {
if (fxx == 0.0) {
return memcpya(start, "0.000000e+00", 12);
} else if (fxx < 9.9999995e-32) {
fxx *= 1.0e32;
xp10 |= 32;
} else {
fxx *= 1.0e16;
xp10 |= 16;
}
}
if (fxx < 9.9999995e-8) {
fxx *= 100000000;
xp10 |= 8;
}
if (fxx < 9.9999995e-4) {
fxx *= 10000;
xp10 |= 4;
}
if (fxx < 9.9999995e-2) {
fxx *= 100;
xp10 |= 2;
}
if (fxx < 9.9999995e-1) {
fxx *= 10;
xp10++;
}
sign = '-';
}
float_round6(fxx, &quotient, &remainder);
*start++ = '0' + quotient;
*start++ = '.';
start = uitoa_z6(remainder, start);
*start++ = 'e';
*start++ = sign;
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
}
char* dtoa_f_p2(double dxx, char* start) {
const double* br_ptr;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
return memcpyl3a(start, "nan");
} else if (dxx < 9.9949999999999) {
if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
if (dxx >= 9.9949999999999) {
goto dtoa_f_p2_10;
}
}
double_bround2(dxx, banker_round11, &quotient, &remainder);
*start++ = '0' + quotient;
dtoa_f_p2_dec:
*start++ = '.';
return memcpya(start, &(digit2_table[remainder * 2]), 2);
}
dtoa_f_p2_10:
if (dxx < 9999999.9949999) {
if (dxx < 999.99499999999) {
if (dxx < 99.994999999999) {
br_ptr = banker_round10;
} else {
br_ptr = banker_round9;
}
} else if (dxx < 99999.994999999) {
if (dxx < 9999.9949999999) {
br_ptr = banker_round8;
} else {
br_ptr = banker_round7;
}
} else if (dxx < 999999.99499999) {
br_ptr = banker_round6;
} else {
br_ptr = banker_round5;
}
double_bround2(dxx, br_ptr, &quotient, &remainder);
start = uint32toa(quotient, start);
goto dtoa_f_p2_dec;
}
if (dxx == INFINITY) {
return memcpyl3a(start, "inf");
}
// just punt larger numbers to glibc for now, this isn't a bottleneck
start += sprintf(start, "%.2f", dxx);
return start;
}
char* dtoa_f_p3(double dxx, char* start) {
const double* br_ptr;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
return memcpyl3a(start, "nan");
} else if (dxx < 9.9994999999999) {
if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
if (dxx >= 9.9994999999999) {
goto dtoa_f_p3_10;
}
}
double_bround3(dxx, banker_round10, &quotient, &remainder);
*start++ = '0' + quotient;
dtoa_f_p3_dec:
*start++ = '.';
quotient = remainder / 100;
remainder -= 100 * quotient;
*start++ = '0' + quotient;
return memcpya(start, &(digit2_table[remainder * 2]), 2);
}
dtoa_f_p3_10:
if (dxx < 999999.99949999) {
if (dxx < 999.99949999999) {
if (dxx < 99.999499999999) {
br_ptr = banker_round9;
} else {
br_ptr = banker_round8;
}
} else if (dxx < 99999.999499999) {
if (dxx < 9999.9994999999) {
br_ptr = banker_round7;
} else {
br_ptr = banker_round6;
}
} else {
br_ptr = banker_round5;
}
double_bround3(dxx, br_ptr, &quotient, &remainder);
start = uint32toa(quotient, start);
goto dtoa_f_p3_dec;
}
if (dxx == INFINITY) {
return memcpyl3a(start, "inf");
}
start += sprintf(start, "%.3f", dxx);
return start;
}
char* dtoa_f_w9p6(double dxx, char* start) {
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
return memcpya(start, " nan", 9);
} else if (dxx < 9.9999994999999) {
if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
if (dxx >= 9.9999994999999) {
goto dtoa_f_w9p6_10;
}
} else {
*start++ = ' ';
}
double_bround6(dxx, banker_round7, &quotient, &remainder);
*start++ = '0' + quotient;
dtoa_f_w9p6_dec:
*start++ = '.';
return uitoa_z6(remainder, start);
}
dtoa_f_w9p6_10:
if (dxx < 999.99999949999) {
double_bround6(dxx, (dxx < 99.999999499999)? banker_round6 : banker_round5, &quotient, &remainder);
start = uint32toa(quotient, start);
goto dtoa_f_w9p6_dec;
}
if (dxx == INFINITY) {
return memcpya(start, " inf", 9);
}
start += sprintf(start, "%.6f", dxx);
return start;
}
char* dtoa_f_w7p4(double dxx, char* start) {
const double* br_ptr;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
return memcpya(start, " nan", 7);
} else if (dxx < 9.9999499999999) {
if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
if (dxx >= 9.9999499999999) {
goto dtoa_f_w7p4_10;
}
} else {
*start++ = ' ';
}
double_bround4(dxx, banker_round9, &quotient, &remainder);
*start++ = '0' + quotient;
dtoa_f_w7p4_dec:
*start++ = '.';
quotient = remainder / 100;
remainder -= 100 * quotient;
return memcpya(memcpya(start, &(digit2_table[quotient * 2]), 2), &(digit2_table[remainder * 2]), 2);
}
dtoa_f_w7p4_10:
if (dxx < 99999.999949999) {
if (dxx < 999.99994999999) {
if (dxx < 99.999949999999) {
br_ptr = banker_round8;
} else {
br_ptr = banker_round7;
}
} else if (dxx < 9999.9999499999) {
br_ptr = banker_round6;
} else {
br_ptr = banker_round5;
}
double_bround4(dxx, br_ptr, &quotient, &remainder);
start = uint32toa(quotient, start);
goto dtoa_f_w7p4_dec;
}
if (dxx == INFINITY) {
return memcpya(start, " inf", 7);
}
start += sprintf(start, "%.4f", dxx);
return start;
}
char* dtoa_f_w9p6_spaced(double dxx, char* start) {
// Prettier fixed-width decimal: removes trailing zero(es) if and only if the
// match appears to be exact.
// Does not detect exact matches when abs(dxx) > 2^31 / 10^5.
double dyy = dxx * 100000 + 0.00000005;
start = dtoa_f_w9p6(dxx, start);
if (dyy - ((double)((int32_t)dyy)) >= 0.0000001) {
return start;
}
trailing_zeroes_to_spaces(start);
return start;
}
char* dtoa_f_w9p6_clipped(double dxx, char* start) {
// same conditions as _spaced()
double dyy = dxx * 100000 + 0.00000005;
start = dtoa_f_w9p6(dxx, start);
if (dyy - ((double)((int32_t)dyy)) >= 0.0000001) {
return start;
}
return clip_trailing_zeroes(start);
}
char* dtoa_g(double dxx, char* start) {
uint32_t xp10 = 0;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
return memcpyl3a(start, "nan");
} else if (dxx < 0) {
*start++ = '-';
dxx = -dxx;
}
if (dxx < 9.9999949999999e-5) {
// 6 sig fig exponential notation, small
if (dxx < 9.9999949999999e-16) {
if (dxx < 9.9999949999999e-128) {
if (dxx == 0.0) {
*start = '0';
return &(start[1]);
} else if (dxx < 9.9999949999999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9999949999999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9999949999999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9999949999999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
}
if (dxx < 9.9999949999999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
if (dxx < 9.9999949999999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9999949999999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9999949999999e-1) {
dxx *= 10;
xp10++;
}
double_bround5(dxx, banker_round8, &quotient, &remainder);
start = memcpya(qrtoa_1p5(quotient, remainder, start), "e-", 2);
if (xp10 >= 100) {
quotient = xp10 / 100;
*start++ = '0' + quotient;
xp10 -= 100 * quotient;
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 999999.49999999) {
// 6 sig fig exponential notation, large
if (dxx >= 9.9999949999999e15) {
if (dxx >= 9.9999949999999e127) {
if (dxx == INFINITY) {
return memcpyl3a(start, "inf");
} else if (dxx >= 9.9999949999999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9999949999999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9999949999999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9999949999999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
}
if (dxx >= 9.9999949999999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
if (dxx >= 9.9999949999999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9999949999999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9999949999999e0) {
dxx *= 1.0e-1;
xp10++;
}
double_bround5(dxx, banker_round8, &quotient, &remainder);
start = memcpya(qrtoa_1p5(quotient, remainder, start), "e+", 2);
if (xp10 >= 100) {
quotient = xp10 / 100;
*start++ = '0' + quotient;
xp10 -= 100 * quotient;
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 0.99999949999999) {
return dtoa_so6(dxx, start);
} else {
// 6 sig fig decimal, no less than ~0.0001
start = memcpya(start, "0.", 2);
if (dxx < 9.9999949999999e-3) {
dxx *= 100;
start = memcpya(start, "00", 2);
}
if (dxx < 9.9999949999999e-2) {
dxx *= 10;
*start++ = '0';
}
return uitoa_trunc6(double_bround(dxx * 1000000, banker_round8), start);
}
}
char* ftoa_g(float fxx, char* start) {
uint32_t xp10 = 0;
uint32_t quotient;
uint32_t remainder;
if (fxx != fxx) {
return memcpyl3a(start, "nan");
} else if (fxx < 0) {
*start++ = '-';
fxx = -fxx;
}
if (fxx < 9.9999944e-5) {
if (fxx < 9.9999944e-16) {
if (fxx == 0.0) {
*start = '0';
return &(start[1]);
} else if (fxx < 9.9999944e-32) {
fxx *= 1.0e32;
xp10 |= 32;
} else {
fxx *= 1.0e16;
xp10 |= 16;
}
}
if (fxx < 9.9999944e-8) {
fxx *= 100000000;
xp10 |= 8;
}
if (fxx < 9.9999944e-4) {
fxx *= 10000;
xp10 |= 4;
}
if (fxx < 9.9999944e-2) {
fxx *= 100;
xp10 |= 2;
}
if (fxx < 9.9999944e-1) {
fxx *= 10;
xp10++;
}
float_round5(fxx, &quotient, &remainder);
return memcpya(memcpya(qrtoa_1p5(quotient, remainder, start), "e-", 2), &(digit2_table[xp10 * 2]), 2);
} else if (fxx >= 999999.44) {
if (fxx >= 9.9999944e15) {
if (fxx == INFINITY) {
return memcpyl3a(start, "inf");
} else if (fxx >= 9.9999944e31) {
fxx *= 1.0e-32;
xp10 |= 32;
} else {
fxx *= 1.0e-16;
xp10 |= 16;
}
}
if (fxx >= 9.9999944e7) {
fxx *= 1.0e-8;
xp10 |= 8;
}
if (fxx >= 9.9999944e3) {
fxx *= 1.0e-4;
xp10 |= 4;
}
if (fxx >= 9.9999944e1) {
fxx *= 1.0e-2;
xp10 |= 2;
}
if (fxx >= 9.9999944e0) {
fxx *= 1.0e-1;
xp10++;
}
float_round5(fxx, &quotient, &remainder);
return memcpya(memcpya(qrtoa_1p5(quotient, remainder, start), "e+", 2), &(digit2_table[xp10 * 2]), 2);
} else if (fxx >= 0.99999944) {
return ftoa_so6(fxx, start);
} else {
// 6 sig fig decimal, no less than ~0.0001
start = memcpya(start, "0.", 2);
if (fxx < 9.9999944e-3) {
fxx *= 100;
start = memcpya(start, "00", 2);
}
if (fxx < 9.9999944e-2) {
fxx *= 10;
*start++ = '0';
}
return uitoa_trunc6(float_round(fxx * 1000000), start);
}
}
char* dtoa_g_wxp2(double dxx, uint32_t min_width, char* start) {
assert(min_width >= 5);
uint32_t xp10 = 0;
char wbuf[16];
char* wpos = wbuf;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
memcpy(memseta(start, 32, min_width - 4), " nan", 4);
return &(start[min_width]);
} else if (dxx < 0) {
*wpos++ = '-';
dxx = -dxx;
}
if (dxx < 9.9499999999999e-5) {
// 2 sig fig exponential notation, small
if (dxx < 9.9499999999999e-16) {
if (dxx < 9.9499999999999e-128) {
if (dxx == 0.0) {
memset(start, 32, min_width - 1);
start[min_width - 1] = '0';
return &(start[min_width]);
} else if (dxx < 9.9499999999999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9499999999999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9499999999999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9499999999999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
}
if (dxx < 9.9499999999999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
if (dxx < 9.9499999999999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9499999999999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9499999999999e-1) {
dxx *= 10;
xp10++;
}
double_bround1(dxx, banker_round12, &quotient, &remainder);
wpos = qrtoa_1p1(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder < min_width - 5) {
memcpy(memseta(start, 32, min_width - 5 - remainder), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e-", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder < min_width - 4) {
memcpy(memseta(start, 32, min_width - 4 - remainder), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e-", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 99.499999999999) {
// 2 sig fig exponential notation, large
if (dxx >= 9.9499999999999e15) {
if (dxx >= 9.9499999999999e127) {
if (dxx == INFINITY) {
start = memseta(start, 32, min_width - 4);
if (wpos == wbuf) {
return memcpya(start, " inf", 4);
} else {
return memcpya(start, "-inf", 4);
}
} else if (dxx >= 9.9499999999999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9499999999999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9499999999999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9499999999999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
}
if (dxx >= 9.9499999999999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
if (dxx >= 9.9499999999999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9499999999999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9499999999999e0) {
dxx *= 1.0e-1;
xp10++;
}
double_bround1(dxx, banker_round12, &quotient, &remainder);
wpos = qrtoa_1p1(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder < min_width - 5) {
memcpy(memseta(start, 32, min_width - 5 - remainder), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e+", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder < min_width - 4) {
memcpy(memseta(start, 32, min_width - 4 - remainder), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e+", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else {
if (dxx >= 0.99499999999999) {
wpos = dtoa_so2(dxx, wpos);
} else {
// 2 sig fig decimal, no less than ~0.0001
wpos = memcpya(wpos, "0.", 2);
if (dxx < 9.9499999999999e-3) {
dxx *= 100;
wpos = memcpya(wpos, "00", 2);
}
if (dxx < 9.9499999999999e-2) {
dxx *= 10;
*wpos++ = '0';
}
wpos = uitoa_trunc2(double_bround(dxx * 100, banker_round12), wpos);
}
remainder = wpos - wbuf;
if (remainder < min_width) {
memcpy(memseta(start, 32, min_width - remainder), wbuf, remainder);
return &(start[min_width]);
} else {
return memcpya(start, wbuf, remainder);
}
}
}
char* dtoa_g_wxp3(double dxx, uint32_t min_width, char* start) {
assert(min_width >= 5);
uint32_t xp10 = 0;
char wbuf[16];
char* wpos = wbuf;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
memcpy(memseta(start, 32, min_width - 4), " nan", 4);
return &(start[min_width]);
} else if (dxx < 0) {
*wpos++ = '-';
dxx = -dxx;
}
if (dxx < 9.9949999999999e-5) {
// 3 sig fig exponential notation, small
if (dxx < 9.9949999999999e-16) {
if (dxx < 9.9949999999999e-128) {
if (dxx == 0.0) {
memset(start, 32, min_width - 1);
start[min_width - 1] = '0';
return &(start[min_width]);
} else if (dxx < 9.9949999999999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9949999999999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9949999999999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9949999999999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
}
if (dxx < 9.9949999999999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
if (dxx < 9.9949999999999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9949999999999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9949999999999e-1) {
dxx *= 10;
xp10++;
}
double_bround2(dxx, banker_round11, &quotient, &remainder);
wpos = qrtoa_1p2(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder < min_width - 5) {
memcpy(memseta(start, 32, min_width - 5 - remainder), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e-", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder < min_width - 4) {
memcpy(memseta(start, 32, min_width - 4 - remainder), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e-", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 999.49999999999) {
// 3 sig fig exponential notation, large
if (dxx >= 9.9949999999999e15) {
if (dxx >= 9.9949999999999e127) {
if (dxx == INFINITY) {
start = memseta(start, 32, min_width - 4);
if (wpos == wbuf) {
return memcpya(start, " inf", 4);
} else {
return memcpya(start, "-inf", 4);
}
} else if (dxx >= 9.9949999999999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9949999999999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9949999999999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9949999999999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
}
if (dxx >= 9.9949999999999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
if (dxx >= 9.9949999999999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9949999999999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9949999999999e0) {
dxx *= 1.0e-1;
xp10++;
}
double_bround2(dxx, banker_round11, &quotient, &remainder);
wpos = qrtoa_1p2(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder < min_width - 5) {
memcpy(memseta(start, 32, min_width - 5 - remainder), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e+", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder < min_width - 4) {
memcpy(memseta(start, 32, min_width - 4 - remainder), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e+", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else {
if (dxx >= 0.99949999999999) {
wpos = dtoa_so3(dxx, wpos);
} else {
// 3 sig fig decimal, no less than ~0.001
wpos = memcpya(wpos, "0.", 2);
if (dxx < 9.9949999999999e-3) {
dxx *= 100;
wpos = memcpya(wpos, "00", 2);
}
if (dxx < 9.9949999999999e-2) {
dxx *= 10;
*wpos++ = '0';
}
wpos = uitoa_trunc3(double_bround(dxx * 1000, banker_round11), wpos);
}
remainder = wpos - wbuf;
if (remainder < min_width) {
memcpy(memseta(start, 32, min_width - remainder), wbuf, remainder);
return &(start[min_width]);
} else {
return memcpya(start, wbuf, remainder);
}
}
}
char* dtoa_g_wxp4(double dxx, uint32_t min_width, char* start) {
uint32_t xp10 = 0;
char wbuf[16];
char* wpos = wbuf;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
if (min_width > 3) {
start = memseta(start, 32, min_width - 3);
}
return memcpyl3a(start, "nan");
} else if (dxx < 0) {
*wpos++ = '-';
dxx = -dxx;
}
if (dxx < 9.9994999999999e-5) {
// 4 sig fig exponential notation, small
if (dxx < 9.9994999999999e-16) {
if (dxx < 9.9994999999999e-128) {
if (dxx == 0.0) {
memset(start, 32, min_width - 1);
start[min_width - 1] = '0';
return &(start[min_width]);
} else if (dxx < 9.9994999999999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9994999999999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9994999999999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9994999999999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
}
if (dxx < 9.9994999999999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
if (dxx < 9.9994999999999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9994999999999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9994999999999e-1) {
dxx *= 10;
xp10++;
}
double_bround3(dxx, banker_round10, &quotient, &remainder);
wpos = qrtoa_1p3(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder + 5 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 5)), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e-", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder + 4 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 4)), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e-", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 9999.4999999999) {
// 4 sig fig exponential notation, large
if (dxx >= 9.9994999999999e15) {
if (dxx >= 9.9994999999999e127) {
if (dxx == INFINITY) {
if (min_width > 4) {
start = memseta(start, 32, min_width - 4);
}
if (wpos == wbuf) {
return memcpya(start, " inf", 4);
} else {
return memcpya(start, "-inf", 4);
}
} else if (dxx >= 9.9994999999999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9994999999999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9994999999999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9994999999999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
}
if (dxx >= 9.9994999999999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
if (dxx >= 9.9994999999999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9994999999999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9994999999999e0) {
dxx *= 1.0e-1;
xp10++;
}
double_bround3(dxx, banker_round10, &quotient, &remainder);
wpos = qrtoa_1p3(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder + 5 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 5)), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e+", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder + 4 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 4)), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e+", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else {
if (dxx >= 0.99994999999999) {
wpos = dtoa_so4(dxx, wpos);
} else {
// 4 sig fig decimal, no less than ~0.0001
wpos = memcpya(wpos, "0.", 2);
if (dxx < 9.9994999999999e-3) {
dxx *= 100;
wpos = memcpya(wpos, "00", 2);
}
if (dxx < 9.9994999999999e-2) {
dxx *= 10;
*wpos++ = '0';
}
wpos = uitoa_trunc4(double_bround(dxx * 10000, banker_round10), wpos);
}
remainder = wpos - wbuf;
if (remainder < min_width) {
memcpy(memseta(start, 32, min_width - remainder), wbuf, remainder);
return &(start[min_width]);
} else {
return memcpya(start, wbuf, remainder);
}
}
}
char* dtoa_g_wxp8(double dxx, uint32_t min_width, char* start) {
uint32_t xp10 = 0;
char wbuf[16];
char* wpos = wbuf;
uint32_t quotient;
uint32_t remainder;
if (dxx != dxx) {
if (min_width > 3) {
start = memseta(start, 32, min_width - 3);
}
return memcpyl3a(start, "nan");
} else if (dxx < 0) {
*wpos++ = '-';
dxx = -dxx;
}
if (dxx < 9.9999999499999e-5) {
// 8 sig fig exponential notation, small
if (dxx < 9.9999999499999e-16) {
if (dxx < 9.9999999499999e-128) {
if (dxx == 0.0) {
memset(start, 32, min_width - 1);
start[min_width - 1] = '0';
return &(start[min_width]);
} else if (dxx < 9.9999999499999e-256) {
dxx *= 1.0e256;
xp10 |= 256;
} else {
dxx *= 1.0e128;
xp10 |= 128;
}
}
if (dxx < 9.9999999499999e-64) {
dxx *= 1.0e64;
xp10 |= 64;
}
if (dxx < 9.9999999499999e-32) {
dxx *= 1.0e32;
xp10 |= 32;
}
if (dxx < 9.9999999499999e-16) {
dxx *= 1.0e16;
xp10 |= 16;
}
}
if (dxx < 9.9999999499999e-8) {
dxx *= 100000000;
xp10 |= 8;
}
if (dxx < 9.9999999499999e-4) {
dxx *= 10000;
xp10 |= 4;
}
if (dxx < 9.9999999499999e-2) {
dxx *= 100;
xp10 |= 2;
}
if (dxx < 9.9999999499999e-1) {
dxx *= 10;
xp10++;
}
double_bround7(dxx, banker_round6, &quotient, &remainder);
wpos = qrtoa_1p7(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder + 5 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 5)), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e-", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder + 4 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 4)), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e-", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else if (dxx >= 99999999.499999) {
// 8 sig fig exponential notation, large
if (dxx >= 9.9999999499999e15) {
if (dxx >= 9.9999999499999e127) {
if (dxx == INFINITY) {
if (min_width > 4) {
start = memseta(start, 32, min_width - 4);
}
if (wpos == wbuf) {
return memcpya(start, " inf", 4);
} else {
return memcpya(start, "-inf", 4);
}
} else if (dxx >= 9.9999999499999e255) {
dxx *= 1.0e-256;
xp10 |= 256;
} else {
dxx *= 1.0e-128;
xp10 |= 128;
}
}
if (dxx >= 9.9999999499999e63) {
dxx *= 1.0e-64;
xp10 |= 64;
}
if (dxx >= 9.9999999499999e31) {
dxx *= 1.0e-32;
xp10 |= 32;
}
if (dxx >= 9.9999999499999e15) {
dxx *= 1.0e-16;
xp10 |= 16;
}
}
if (dxx >= 9.9999999499999e7) {
dxx *= 1.0e-8;
xp10 |= 8;
}
if (dxx >= 9.9999999499999e3) {
dxx *= 1.0e-4;
xp10 |= 4;
}
if (dxx >= 9.9999999499999e1) {
dxx *= 1.0e-2;
xp10 |= 2;
}
if (dxx >= 9.9999999499999e0) {
dxx *= 1.0e-1;
xp10++;
}
double_bround7(dxx, banker_round6, &quotient, &remainder);
wpos = qrtoa_1p7(quotient, remainder, wpos);
remainder = wpos - wbuf;
if (xp10 >= 100) {
if (remainder + 5 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 5)), wbuf, remainder);
start = &(start[min_width - 5]);
} else {
start = memcpya(start, wbuf, remainder);
}
quotient = xp10 / 100;
start = memcpyax(start, "e+", 2, '0' + quotient);
xp10 -= 100 * quotient;
} else {
if (remainder + 4 < min_width) {
memcpy(memseta(start, 32, min_width - (remainder + 4)), wbuf, remainder);
start = &(start[min_width - 4]);
} else {
start = memcpya(start, wbuf, remainder);
}
start = memcpya(start, "e+", 2);
}
return memcpya(start, &(digit2_table[xp10 * 2]), 2);
} else {
if (dxx >= 0.99999999499999) {
wpos = dtoa_so8(dxx, wpos);
} else {
// 8 sig fig decimal, no less than ~0.0001
wpos = memcpya(wpos, "0.", 2);
if (dxx < 9.9999999499999e-3) {
dxx *= 100;
wpos = memcpya(wpos, "00", 2);
}
if (dxx < 9.9999999499999e-2) {
dxx *= 10;
*wpos++ = '0';
}
wpos = uitoa_trunc8(double_bround(dxx * 100000000, banker_round6), wpos);
}
remainder = wpos - wbuf;
if (remainder < min_width) {
memcpy(memseta(start, 32, min_width - remainder), wbuf, remainder);
return &(start[min_width]);
} else {
return memcpya(start, wbuf, remainder);
}
}
}
char* chrom_print_human(uint32_t num, char* buf) {
uint32_t n10;
if (num < 10) {
*buf = '0' + num;
return &(buf[1]);
} else if (num < 23) {
n10 = num / 10;
*buf = '0' + n10;
buf[1] = '0' + (num - 10 * n10);
return &(buf[2]);
} else if (num < 25) {
// X is 24th letter of alphabet, and 23rd chromosome
*buf = 'A' + num;
return &(buf[1]);
} else if (num > 26) {
// --allow-extra-chr 0
*buf = '0';
return &(buf[1]);
} else if (num == 25) {
memcpy(buf, "XY", 2);
return &(buf[2]);
} else {
memcpy(buf, "MT", 2);
return &(buf[2]);
}
}
void magic_num(uint32_t divisor, uint64_t* multp, uint32_t* __restrict pre_shiftp, uint32_t* __restrict post_shiftp, uint32_t* __restrict incrp) {
// Enables fast integer division by a constant not known until runtime. See
// http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html .
// Assumes divisor is not zero, of course.
// May want to populate a struct instead.
uint32_t down_multiplier = 0;
uint32_t down_exponent = 0;
uint32_t has_magic_down = 0;
uint32_t quotient;
uint32_t remainder;
uint32_t ceil_log_2_d;
uint32_t exponent;
uint32_t uii;
if (divisor & (divisor - 1)) {
quotient = 0x80000000U / divisor;
remainder = 0x80000000U - (quotient * divisor);
ceil_log_2_d = 32 - __builtin_clz(divisor);
for (exponent = 0; ; exponent++) {
if (remainder >= divisor - remainder) {
quotient = quotient * 2 + 1;
remainder = remainder * 2 - divisor;
} else {
quotient = quotient * 2;
remainder = remainder * 2;
}
if ((exponent >= ceil_log_2_d) || (divisor - remainder) <= (1U << exponent)) {
break;
}
if ((!has_magic_down) && (remainder <= (1U << exponent))) {
has_magic_down = 1;
down_multiplier = quotient;
down_exponent = exponent;
}
}
if (exponent < ceil_log_2_d) {
*multp = quotient + 1;
*pre_shiftp = 0;
*post_shiftp = 32 + exponent;
*incrp = 0;
return;
} else if (divisor & 1) {
*multp = down_multiplier;
*pre_shiftp = 0;
*post_shiftp = 32 + down_exponent;
*incrp = 1;
return;
} else {
*pre_shiftp = __builtin_ctz(divisor);
magic_num(divisor >> (*pre_shiftp), multp, &uii, post_shiftp, incrp);
return;
}
} else {
// power of 2
*multp = 1;
*pre_shiftp = 0;
*post_shiftp = __builtin_ctz(divisor);
*incrp = 0;
}
}
void fill_bits(uintptr_t loc_start, uintptr_t len, uintptr_t* bitarr) {
assert(len);
uintptr_t maj_start = loc_start / BITCT;
uintptr_t maj_end = (loc_start + len) / BITCT;
uintptr_t minor;
if (maj_start == maj_end) {
bitarr[maj_start] |= (ONELU << ((loc_start + len) % BITCT)) - (ONELU << (loc_start % BITCT));
} else {
bitarr[maj_start] |= ~((ONELU << (loc_start % BITCT)) - ONELU);
fill_ulong_one(maj_end - maj_start - 1, &(bitarr[maj_start + 1]));
minor = (loc_start + len) % BITCT;
if (minor) {
bitarr[maj_end] |= (ONELU << minor) - ONELU;
}
}
}
void clear_bits(uintptr_t loc_start, uintptr_t len, uintptr_t* bitarr) {
assert(len);
uintptr_t maj_start = loc_start / BITCT;
uintptr_t maj_end = (loc_start + len) / BITCT;
uintptr_t minor;
if (maj_start == maj_end) {
bitarr[maj_start] &= ~((ONELU << ((loc_start + len) % BITCT)) - (ONELU << (loc_start % BITCT)));
} else {
bitarr[maj_start] &= ((ONELU << (loc_start % BITCT)) - ONELU);
fill_ulong_zero(maj_end - maj_start - 1, &(bitarr[maj_start + 1]));
minor = (loc_start + len) % BITCT;
if (minor) {
bitarr[maj_end] &= ~((ONELU << minor) - ONELU);
}
}
}
uint32_t next_unset_unsafe(const uintptr_t* bitarr, uint32_t loc) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (~(*bitarr_ptr)) >> (loc % BITCT);
if (ulii) {
return loc + CTZLU(ulii);
}
do {
ulii = *(++bitarr_ptr);
} while (ulii == ~ZEROLU);
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(~ulii);
}
#ifdef __LP64__
uintptr_t next_unset_ul_unsafe(const uintptr_t* bitarr, uintptr_t loc) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (~(*bitarr_ptr)) >> (loc % BITCT);
if (ulii) {
return loc + CTZLU(ulii);
}
do {
ulii = *(++bitarr_ptr);
} while (ulii == ~ZEROLU);
return (((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(~ulii));
}
#endif
uint32_t next_unset(const uintptr_t* bitarr, uint32_t loc, uint32_t ceil) {
// safe version.
assert(ceil >= 1);
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (~(*bitarr_ptr)) >> (loc % BITCT);
const uintptr_t* bitarr_last;
if (ulii) {
loc += CTZLU(ulii);
return MINV(loc, ceil);
}
bitarr_last = &(bitarr[(ceil - 1) / BITCT]);
do {
if (bitarr_ptr >= bitarr_last) {
return ceil;
}
ulii = *(++bitarr_ptr);
} while (ulii == ~ZEROLU);
loc = ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(~ulii);
return MINV(loc, ceil);
}
#ifdef __LP64__
uintptr_t next_unset_ul(const uintptr_t* bitarr, uintptr_t loc, uintptr_t ceil) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (~(*bitarr_ptr)) >> (loc % BITCT);
const uintptr_t* bitarr_last;
if (ulii) {
ulii = loc + CTZLU(ulii);
return MINV(ulii, ceil);
}
bitarr_last = &(bitarr[(ceil - 1) / BITCT]);
do {
if (bitarr_ptr >= bitarr_last) {
return ceil;
}
ulii = *(++bitarr_ptr);
} while (ulii == ~ZEROLU);
ulii = ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(~ulii);
return MINV(ulii, ceil);
}
#endif
uint32_t next_set_unsafe(const uintptr_t* bitarr, uint32_t loc) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (*bitarr_ptr) >> (loc % BITCT);
if (ulii) {
return loc + CTZLU(ulii);
}
do {
ulii = *(++bitarr_ptr);
} while (!ulii);
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(ulii);
}
#ifdef __LP64__
uintptr_t next_set_ul_unsafe(const uintptr_t* bitarr, uintptr_t loc) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (*bitarr_ptr) >> (loc % BITCT);
if (ulii) {
return loc + CTZLU(ulii);
}
do {
ulii = *(++bitarr_ptr);
} while (!ulii);
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(ulii);
}
#endif
uint32_t next_set(const uintptr_t* bitarr, uint32_t loc, uint32_t ceil) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (*bitarr_ptr) >> (loc % BITCT);
const uintptr_t* bitarr_last;
uint32_t rval;
if (ulii) {
rval = loc + CTZLU(ulii);
return MINV(rval, ceil);
}
bitarr_last = &(bitarr[(ceil - 1) / BITCT]);
do {
if (bitarr_ptr >= bitarr_last) {
return ceil;
}
ulii = *(++bitarr_ptr);
} while (!ulii);
rval = ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(ulii);
return MINV(rval, ceil);
}
#ifdef __LP64__
uintptr_t next_set_ul(const uintptr_t* bitarr, uintptr_t loc, uintptr_t ceil) {
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uintptr_t ulii = (*bitarr_ptr) >> (loc % BITCT);
const uintptr_t* bitarr_last;
if (ulii) {
ulii = loc + CTZLU(ulii);
return MINV(ulii, ceil);
}
bitarr_last = &(bitarr[(ceil - 1) / BITCT]);
do {
if (bitarr_ptr >= bitarr_last) {
return ceil;
}
ulii = *(++bitarr_ptr);
} while (!ulii);
ulii = ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + CTZLU(ulii);
return MINV(ulii, ceil);
}
#endif
int32_t last_set_bit(const uintptr_t* bitarr, uint32_t word_ct) {
const uintptr_t* bitarr_ptr = &(bitarr[word_ct]);
uintptr_t ulii;
do {
ulii = *(--bitarr_ptr);
if (ulii) {
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + BITCT - 1 - CLZLU(ulii);
}
} while (bitarr_ptr > bitarr);
return -1;
}
int32_t last_clear_bit(const uintptr_t* bitarr, uint32_t ceil) {
// can return ceil or any lower number
const uintptr_t* bitarr_ptr = &(bitarr[ceil / BITCT]);
uint32_t remainder = ceil % BITCT;
uintptr_t ulii;
if (remainder) {
ulii = (~(*bitarr_ptr)) & ((ONELU << remainder) - ONELU);
if (ulii) {
return (ceil | (BITCT - 1)) - CLZLU(ulii);
}
}
while (bitarr_ptr > bitarr) {
ulii = ~(*(--bitarr_ptr));
if (ulii) {
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + BITCT - 1 - CLZLU(ulii);
}
}
return -1;
}
uint32_t prev_unset_unsafe(const uintptr_t* bitarr, uint32_t loc) {
// unlike the next_{un}set family, this always returns a STRICTLY earlier
// position
const uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uint32_t remainder = loc % BITCT;
uintptr_t ulii;
if (remainder) {
ulii = (~(*bitarr_ptr)) & ((ONELU << remainder) - ONELU);
if (ulii) {
return (loc | (BITCT - 1)) - CLZLU(ulii);
}
}
do {
ulii = ~(*(--bitarr_ptr));
} while (!ulii);
return ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + BITCT - 1 - CLZLU(ulii);
}
/*
uint32_t prev_unset(uintptr_t* bitarr, uint32_t loc, uint32_t floor) {
uintptr_t* bitarr_ptr = &(bitarr[loc / BITCT]);
uint32_t remainder = loc % BITCT;
uintptr_t* bitarr_first;
uintptr_t ulii;
if (remainder) {
ulii = (~(*bitarr_ptr)) & ((ONELU << remainder) - ONELU);
if (ulii) {
loc = (loc | (BITCT - 1)) - CLZLU(ulii);
return MAXV(loc, floor);
}
}
bitarr_first = &(bitarr[floor / BITCT]);
do {
if (bitarr_ptr == bitarr_first) {
return floor;
}
ulii = ~(*(--bitarr_ptr));
} while (!ulii);
loc = ((uintptr_t)(bitarr_ptr - bitarr)) * BITCT + BITCT - 1 - CLZLU(ulii);
return MAXV(loc, floor);
}
*/
int32_t bigstack_calloc_uc(uintptr_t ct, unsigned char** ucp_ptr) {
*ucp_ptr = (unsigned char*)bigstack_alloc(ct);
if (!(*ucp_ptr)) {
return 1;
}
memset(*ucp_ptr, 0, ct);
return 0;
}
int32_t bigstack_calloc_d(uintptr_t ct, double** dp_ptr) {
*dp_ptr = (double*)bigstack_alloc(ct * sizeof(double));
if (!(*dp_ptr)) {
return 1;
}
fill_double_zero(ct, *dp_ptr);
return 0;
}
int32_t bigstack_calloc_f(uintptr_t ct, float** fp_ptr) {
*fp_ptr = (float*)bigstack_alloc(ct * sizeof(float));
if (!(*fp_ptr)) {
return 1;
}
fill_float_zero(ct, *fp_ptr);
return 0;
}
int32_t bigstack_calloc_ui(uintptr_t ct, uint32_t** uip_ptr) {
*uip_ptr = (uint32_t*)bigstack_alloc(ct * sizeof(int32_t));
if (!(*uip_ptr)) {
return 1;
}
fill_uint_zero(ct, *uip_ptr);
return 0;
}
int32_t bigstack_calloc_ul(uintptr_t ct, uintptr_t** ulp_ptr) {
*ulp_ptr = (uintptr_t*)bigstack_alloc(ct * sizeof(intptr_t));
if (!(*ulp_ptr)) {
return 1;
}
fill_ulong_zero(ct, *ulp_ptr);
return 0;
}
int32_t bigstack_calloc_ull(uintptr_t ct, uint64_t** ullp_ptr) {
*ullp_ptr = (uint64_t*)bigstack_alloc(ct * sizeof(int64_t));
if (!(*ullp_ptr)) {
return 1;
}
fill_ull_zero(ct, *ullp_ptr);
return 0;
}
int32_t bigstack_end_calloc_uc(uintptr_t ct, unsigned char** ucp_ptr) {
*ucp_ptr = (unsigned char*)bigstack_end_alloc(ct);
if (!(*ucp_ptr)) {
return 1;
}
memset(*ucp_ptr, 0, ct);
return 0;
}
int32_t bigstack_end_calloc_d(uintptr_t ct, double** dp_ptr) {
*dp_ptr = (double*)bigstack_end_alloc(ct * sizeof(double));
if (!(*dp_ptr)) {
return 1;
}
fill_double_zero(ct, *dp_ptr);
return 0;
}
int32_t bigstack_end_calloc_f(uintptr_t ct, float** fp_ptr) {
*fp_ptr = (float*)bigstack_end_alloc(ct * sizeof(float));
if (!(*fp_ptr)) {
return 1;
}
fill_float_zero(ct, *fp_ptr);
return 0;
}
int32_t bigstack_end_calloc_ui(uintptr_t ct, uint32_t** uip_ptr) {
*uip_ptr = (uint32_t*)bigstack_end_alloc(ct * sizeof(int32_t));
if (!(*uip_ptr)) {
return 1;
}
fill_uint_zero(ct, *uip_ptr);
return 0;
}
int32_t bigstack_end_calloc_ul(uintptr_t ct, uintptr_t** ulp_ptr) {
*ulp_ptr = (uintptr_t*)bigstack_end_alloc(ct * sizeof(intptr_t));
if (!(*ulp_ptr)) {
return 1;
}
fill_ulong_zero(ct, *ulp_ptr);
return 0;
}
int32_t bigstack_end_calloc_ull(uintptr_t ct, uint64_t** ullp_ptr) {
*ullp_ptr = (uint64_t*)bigstack_end_alloc(ct * sizeof(int64_t));
if (!(*ullp_ptr)) {
return 1;
}
fill_ull_zero(ct, *ullp_ptr);
return 0;
}
// MurmurHash3, from
// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
static inline uint32_t rotl32(uint32_t x, int8_t r) {
return (x << r) | (x >> (32 - r));
}
static inline uint32_t getblock32(const uint32_t* p, int i) {
return p[i];
}
//-----------------------------------------------------------------------------
// Finalization mix - force all bits of a hash block to avalanche
static inline uint32_t fmix32(uint32_t h) {
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
uint32_t murmurhash3_32(const void* key, uint32_t len) {
const uint8_t* data = (const uint8_t*)key;
cons