#include "core/numparse.h"
#include <rayforce.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LANE8_BIT 0x8080808080808080ULL
#define LANE4_BIT 0x80808080U
bool ray_is_8_digits(const void *p) {
uint64_t chunk;
memcpy(&chunk, p, 8);
uint64_t under = chunk - 0x3030303030303030ULL;
uint64_t over = chunk + 0x4646464646464646ULL;
return ((under | over) & LANE8_BIT) == 0;
}
bool ray_is_4_digits(const void *p) {
uint32_t chunk;
memcpy(&chunk, p, 4);
uint32_t under = chunk - 0x30303030U;
uint32_t over = chunk + 0x46464646U;
return ((under | over) & LANE4_BIT) == 0;
}
uint64_t ray_parse_8_digits(const void *p) {
uint64_t chunk;
memcpy(&chunk, p, 8);
chunk -= 0x3030303030303030ULL;
uint64_t tens = chunk & 0x000F000F000F000FULL;
uint64_t ones = (chunk >> 8) & 0x000F000F000F000FULL;
uint64_t pairs = tens * 10 + ones;
uint64_t p_hi = pairs & 0x000000FF000000FFULL;
uint64_t p_lo = (pairs >> 16) & 0x000000FF000000FFULL;
uint64_t quads = p_hi * 100 + p_lo;
return (quads & 0xFFFFFFFFULL) * 10000 + (quads >> 32);
}
uint32_t ray_parse_4_digits(const void *p) {
uint32_t chunk;
memcpy(&chunk, p, 4);
chunk -= 0x30303030U;
uint32_t tens = chunk & 0x000F000FU;
uint32_t ones = (chunk >> 8) & 0x000F000FU;
uint32_t pairs = tens * 10 + ones;
return (pairs & 0xFFFFU) * 100 + (pairs >> 16);
}
#define IS_DIGIT(c) ((unsigned)((unsigned char)(c) - '0') < 10u)
size_t ray_parse_i64(const char *src, size_t len, int64_t *dst) {
if (len == 0) return 0;
size_t i = 0;
int neg = 0;
if (src[0] == '-') { neg = 1; i = 1; }
else if (src[0] == '+') { i = 1; }
if (i == len) return 0;
size_t digit_start = i;
while (i < len && src[i] == '0') i++;
size_t sig_start = i;
uint64_t result = 0;
if (i + 8 <= len && ray_is_8_digits(src + i)) {
result = ray_parse_8_digits(src + i);
i += 8;
if (i + 8 <= len && result <= 922337203ULL && ray_is_8_digits(src + i)) {
result = result * 100000000ULL + ray_parse_8_digits(src + i);
i += 8;
}
}
while (i < len && IS_DIGIT(src[i])) {
if ((size_t)(i - sig_start) >= 19) return 0;
uint64_t prev = result;
result = result * 10 + (uint64_t)(src[i] - '0');
if (result < prev) return 0;
i++;
}
if (i == digit_start) return 0;
if (neg) {
if (result > (uint64_t)INT64_MAX + 1ULL) return 0;
*dst = (int64_t)(0u - result);
} else {
if (result > (uint64_t)INT64_MAX) return 0;
*dst = (int64_t)result;
}
return i;
}
size_t ray_parse_i32(const char *src, size_t len, int32_t *dst) {
int64_t v;
size_t n = ray_parse_i64(src, len, &v);
if (n == 0) return 0;
if (v < INT32_MIN || v > INT32_MAX) return 0;
*dst = (int32_t)v;
return n;
}
static const double g_pow10[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22
};
static inline int icmp3(const char *p, char a, char b, char c) {
unsigned char x = (unsigned char)p[0], y = (unsigned char)p[1], z = (unsigned char)p[2];
return (x == (unsigned char)a || x == (unsigned char)(a ^ 0x20)) &&
(y == (unsigned char)b || y == (unsigned char)(b ^ 0x20)) &&
(z == (unsigned char)c || z == (unsigned char)(c ^ 0x20));
}
static inline double scale_pow10(double val, int e) {
if (e == 0) return val;
if (e > 0) {
if (e <= 22) return val * g_pow10[e];
return val * pow(10.0, (double)e);
} else {
int ne = -e;
if (ne <= 22) return val / g_pow10[ne];
while (ne > 22) {
val /= 1e22;
if (val == 0.0) return val;
ne -= 22;
}
return val / g_pow10[ne];
}
}
size_t ray_parse_f64(const char *src, size_t len, double *dst) {
if (len == 0) return 0;
size_t i = 0;
int neg = 0;
if (src[0] == '-') { neg = 1; i = 1; }
else if (src[0] == '+') { i = 1; }
if (i + 3 <= len && icmp3(src + i, 'n', 'a', 'n')) {
*dst = __builtin_nan("");
return i + 3;
}
if (i + 3 <= len && icmp3(src + i, 'i', 'n', 'f')) {
*dst = neg ? -__builtin_inf() : __builtin_inf();
return i + 3;
}
if (i == len) return 0;
uint64_t mantissa = 0;
int mant_digits = 0;
int dec_offset = 0;
bool have_digit = false;
while (i < len && src[i] == '0') { i++; have_digit = true; }
if (i + 8 <= len && ray_is_8_digits(src + i)) {
mantissa = ray_parse_8_digits(src + i);
mant_digits = 8;
i += 8;
have_digit = true;
if (i + 8 <= len && ray_is_8_digits(src + i)) {
mantissa = mantissa * 100000000ULL + ray_parse_8_digits(src + i);
mant_digits = 16;
i += 8;
}
}
while (i < len && IS_DIGIT(src[i])) {
if (mant_digits < 18) {
mantissa = mantissa * 10 + (uint64_t)(src[i] - '0');
mant_digits++;
} else {
dec_offset++;
}
i++;
have_digit = true;
}
if (i < len && src[i] == '.') {
i++;
if (mantissa == 0) {
while (i < len && src[i] == '0') {
dec_offset--;
i++;
have_digit = true;
}
}
if (i + 8 <= len && mant_digits + 8 <= 18 && ray_is_8_digits(src + i)) {
mantissa = mantissa * 100000000ULL + ray_parse_8_digits(src + i);
mant_digits += 8;
dec_offset -= 8;
i += 8;
have_digit = true;
}
while (i < len && IS_DIGIT(src[i])) {
if (mant_digits < 18) {
mantissa = mantissa * 10 + (uint64_t)(src[i] - '0');
mant_digits++;
dec_offset--;
}
i++;
have_digit = true;
}
}
if (!have_digit) return 0;
if (i < len && (src[i] == 'e' || src[i] == 'E')) {
size_t e_at = i;
i++;
int e_neg = 0;
if (i < len) {
if (src[i] == '-') { e_neg = 1; i++; }
else if (src[i] == '+') { i++; }
}
size_t e_start = i;
int exp_v = 0;
bool exp_capped = false;
while (i < len && IS_DIGIT(src[i])) {
if (exp_v <= 999) exp_v = exp_v * 10 + (src[i] - '0');
else exp_capped = true;
i++;
}
if (i == e_start) {
i = e_at;
} else {
int e = exp_capped ? 10000 : exp_v;
dec_offset += e_neg ? -e : e;
}
}
double val = 0.0;
bool need_strtod = false;
if (mantissa == 0) {
val = 0.0;
} else if (dec_offset > 308) {
val = __builtin_inf();
} else if (dec_offset < -342) {
val = 0.0;
} else if (mant_digits <= 15 && dec_offset >= -22 && dec_offset <= 22) {
val = (double)mantissa;
if (dec_offset > 0) val *= g_pow10[dec_offset];
else if (dec_offset < 0) val /= g_pow10[-dec_offset];
} else {
need_strtod = true;
}
if (need_strtod) {
char stackbuf[128];
char *buf;
ray_t *buf_block = NULL;
if (i + 1 <= sizeof(stackbuf)) {
buf = stackbuf;
} else {
buf_block = ray_alloc(i + 1);
buf = buf_block ? (char*)ray_data(buf_block) : NULL;
}
if (buf) {
memcpy(buf, src, i);
buf[i] = '\0';
char *endp = NULL;
double v = strtod(buf, &endp);
bool ok = (endp == buf + i);
if (buf_block) ray_free(buf_block);
if (ok) {
*dst = v;
return i;
}
}
val = scale_pow10((double)mantissa, dec_offset);
}
*dst = neg ? -val : val;
return i;
}
size_t ray_parse_u64_hex(const char *src, size_t len, uint64_t *dst) {
uint64_t v = 0;
size_t i = 0;
while (i < len && i < 16) {
unsigned char c = (unsigned char)src[i];
unsigned d;
if (c >= '0' && c <= '9') d = (unsigned)(c - '0');
else if (c >= 'a' && c <= 'f') d = (unsigned)(c - 'a' + 10);
else if (c >= 'A' && c <= 'F') d = (unsigned)(c - 'A' + 10);
else break;
v = (v << 4) | d;
i++;
}
if (i == 0) return 0;
*dst = v;
return i;
}