* interface with this. */
typedef union JsonValue {
- /* Encodes a simple value. On x86-64 this structure is 16 bytes wide (as long double is 128bit). */
+ /* Encodes a simple value. This structure is generally 8 bytes wide (as double is 64bit). */
bool boolean;
- long double real;
+ double real;
intmax_t integer;
uintmax_t unsig;
} JsonValue;
/* Let's protect us against accidental structure size changes on our most relevant arch */
#ifdef __x86_64__
-assert_cc(sizeof(JsonValue) == 16U);
+assert_cc(sizeof(JsonValue) == 8U);
#endif
#define JSON_VALUE_NULL ((JsonValue) {})
};
};
-/* Inside string arrays we have a series of JasonVariant structures one after the other. In this case, strings longer
+/* Inside string arrays we have a series of JsonVariant structures one after the other. In this case, strings longer
* than INLINE_STRING_MAX are stored as references, and all shorter ones inline. (This means — on x86-64 — strings up
- * to 15 chars are stored within the array elements, and all others in separate allocations) */
+ * to 7 chars are stored within the array elements, and all others in separate allocations) */
#define INLINE_STRING_MAX (sizeof(JsonVariant) - offsetof(JsonVariant, string) - 1U)
/* Let's make sure this structure isn't increased in size accidentally. This check is only for our most relevant arch
* (x86-64). */
#ifdef __x86_64__
-assert_cc(sizeof(JsonVariant) == 48U);
-assert_cc(INLINE_STRING_MAX == 15U);
+assert_cc(sizeof(JsonVariant) == 40U);
+assert_cc(INLINE_STRING_MAX == 7U);
#endif
static JsonSource* json_source_new(const char *name) {
return 0;
}
-int json_variant_new_real(JsonVariant **ret, long double d) {
+int json_variant_new_real(JsonVariant **ret, double d) {
JsonVariant *v;
int r;
return offsetof(JsonVariant, string) + strlen(v->string) + 1;
case JSON_VARIANT_REAL:
- return offsetof(JsonVariant, value) + sizeof(long double);
+ return offsetof(JsonVariant, value) + sizeof(double);
case JSON_VARIANT_UNSIGNED:
return offsetof(JsonVariant, value) + sizeof(uintmax_t);
converted = (intmax_t) v->value.real;
DISABLE_WARNING_FLOAT_EQUAL;
- if ((long double) converted == v->value.real)
+ if ((double) converted == v->value.real)
return converted;
REENABLE_WARNING;
- log_debug("Real %Lg requested as integer, and cannot be converted losslessly, returning 0.", v->value.real);
+ log_debug("Real %g requested as integer, and cannot be converted losslessly, returning 0.", v->value.real);
return 0;
}
converted = (uintmax_t) v->value.real;
DISABLE_WARNING_FLOAT_EQUAL;
- if ((long double) converted == v->value.real)
+ if ((double) converted == v->value.real)
return converted;
REENABLE_WARNING;
- log_debug("Real %Lg requested as unsigned integer, and cannot be converted losslessly, returning 0.", v->value.real);
+ log_debug("Real %g requested as unsigned integer, and cannot be converted losslessly, returning 0.", v->value.real);
return 0;
}
return 0;
}
-long double json_variant_real(JsonVariant *v) {
+double json_variant_real(JsonVariant *v) {
if (!v)
return 0.0;
if (v == JSON_VARIANT_MAGIC_ZERO_INTEGER ||
return v->value.real;
case JSON_VARIANT_INTEGER: {
- long double converted;
-
- converted = (long double) v->value.integer;
+ double converted = (double) v->value.integer;
if ((intmax_t) converted == v->value.integer)
return converted;
}
case JSON_VARIANT_UNSIGNED: {
- long double converted;
-
- converted = (long double) v->value.unsig;
+ double converted = (double) v->value.unsig;
if ((uintmax_t) converted == v->value.unsig)
return converted;
return v->type;
}
-_function_no_sanitize_float_cast_overflow_ bool json_variant_has_type(JsonVariant *v, JsonVariantType type) {
+_function_no_sanitize_float_cast_overflow_
+bool json_variant_has_type(JsonVariant *v, JsonVariantType type) {
JsonVariantType rt;
- /* Note: we turn off ubsan float cast overflo detection for this function, since it would complain
+ /* Note: we turn off ubsan float cast overflow detection for this function, since it would complain
* about our float casts but we do them explicitly to detect conversion errors. */
v = json_variant_dereference(v);
/* Any integer that can be converted lossley to a real and back may also be considered a real */
if (rt == JSON_VARIANT_INTEGER && type == JSON_VARIANT_REAL)
- return (intmax_t) (long double) v->value.integer == v->value.integer;
+ return (intmax_t) (double) v->value.integer == v->value.integer;
if (rt == JSON_VARIANT_UNSIGNED && type == JSON_VARIANT_REAL)
- return (uintmax_t) (long double) v->value.unsig == v->value.unsig;
+ return (uintmax_t) (double) v->value.unsig == v->value.unsig;
DISABLE_WARNING_FLOAT_EQUAL;
/* Any real that can be converted losslessly to an integer and back may also be considered an integer */
if (rt == JSON_VARIANT_REAL && type == JSON_VARIANT_INTEGER)
- return (long double) (intmax_t) v->value.real == v->value.real;
+ return (double) (intmax_t) v->value.real == v->value.real;
if (rt == JSON_VARIANT_REAL && type == JSON_VARIANT_UNSIGNED)
- return (long double) (uintmax_t) v->value.real == v->value.real;
+ return (double) (uintmax_t) v->value.real == v->value.real;
REENABLE_WARNING;
if (flags & JSON_FORMAT_COLOR)
fputs(ansi_highlight_blue(), f);
- fprintf(f, "%.*Le", DECIMAL_DIG, json_variant_real(v));
+ fprintf(f, "%.*e", DECIMAL_DIG, json_variant_real(v));
if (flags & JSON_FORMAT_COLOR)
fputs(ANSI_NORMAL, f);
break;
case JSON_VARIANT_REAL:
- k = sizeof(long double);
+ k = sizeof(double);
value.real = json_variant_real(v);
source = &value;
break;
static int json_parse_number(const char **p, JsonValue *ret) {
bool negative = false, exponent_negative = false, is_real = false;
- long double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
+ double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
intmax_t i = 0;
uintmax_t u = 0;
const char *c;
*p = c;
if (is_real) {
- ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10l((exponent_negative ? -1.0 : 1.0) * exponent);
+ ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent);
return JSON_TOKEN_REAL;
} else if (negative) {
ret->integer = i;
}
case _JSON_BUILD_REAL: {
- long double d;
+ double d;
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
r = -EINVAL;
goto finish;
}
- d = va_arg(ap, long double);
+ d = va_arg(ap, double);
if (current->n_suppress == 0) {
r = json_variant_new_real(&add, d);
Limitations:
- Doesn't allow embedded NUL in strings
- - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'long double' for
+ - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'double' for
values outside this range, which is lossy)
- Can't store negative zero (will be treated identical to positive zero, and not retained across serialization)
- - Can't store non-integer numbers that can't be stored in "long double" losslessly
+ - Can't store non-integer numbers that can't be stored in "double" losslessly
- Allows creation and parsing of objects with duplicate keys. The "dispatcher" will refuse them however. This means
we can parse and pass around such objects, but will carefully refuse them when we convert them into our own data.
int json_variant_new_hex(JsonVariant **ret, const void *p, size_t n);
int json_variant_new_integer(JsonVariant **ret, intmax_t i);
int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
-int json_variant_new_real(JsonVariant **ret, long double d);
+int json_variant_new_real(JsonVariant **ret, double d);
int json_variant_new_boolean(JsonVariant **ret, bool b);
int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n);
int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n);
const char *json_variant_string(JsonVariant *v);
intmax_t json_variant_integer(JsonVariant *v);
uintmax_t json_variant_unsigned(JsonVariant *v);
-long double json_variant_real(JsonVariant *v);
+double json_variant_real(JsonVariant *v);
bool json_variant_boolean(JsonVariant *v);
JsonVariantType json_variant_type(JsonVariant *v);
#define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, (const char*) { s }
#define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, (intmax_t) { i }
#define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, (uintmax_t) { u }
-#define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, (long double) { d }
+#define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, (double) { d }
#define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, (bool) { b }
#define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
#define JSON_BUILD_EMPTY_ARRAY _JSON_BUILD_ARRAY_BEGIN, _JSON_BUILD_ARRAY_END
assert_se(streq_ptr(nn, str));
} else if (t == JSON_TOKEN_REAL) {
- long double d;
+ double d;
- d = va_arg(ap, long double);
-
- /* Valgrind doesn't support long double calculations and automatically downgrades to 80bit:
- * http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits.
- * Some architectures might not support long double either.
- */
+ d = va_arg(ap, double);
assert_se(fabsl(d - v.real) < 1e-10 ||
fabsl((d - v.real) / v.real) < 1e-10);
}
static void test_float_match(JsonVariant *v) {
- const long double delta = 0.0001;
+ const double delta = 0.0001;
assert_se(json_variant_is_array(v));
assert_se(json_variant_elements(v) == 9);
- assert_se(fabsl((long double) 1.0 - ((long double) DBL_MIN / json_variant_real(json_variant_by_index(v, 0)))) <= delta);
- assert_se(fabsl((long double) 1.0 - ((long double) DBL_MAX / json_variant_real(json_variant_by_index(v, 1)))) <= delta);
+ assert_se(fabsl((double) 1.0 - ((double) DBL_MIN / json_variant_real(json_variant_by_index(v, 0)))) <= delta);
+ assert_se(fabsl((double) 1.0 - ((double) DBL_MAX / json_variant_real(json_variant_by_index(v, 1)))) <= delta);
assert_se(json_variant_is_null(json_variant_by_index(v, 2))); /* nan is not supported by json → null */
assert_se(json_variant_is_null(json_variant_by_index(v, 3))); /* +inf is not supported by json → null */
assert_se(json_variant_is_null(json_variant_by_index(v, 4))); /* -inf is not supported by json → null */
assert_se(json_variant_is_null(json_variant_by_index(v, 5)) ||
- fabsl((long double) 1.0 - ((long double) HUGE_VAL / json_variant_real(json_variant_by_index(v, 5)))) <= delta); /* HUGE_VAL might be +inf, but might also be something else */
+ fabsl((double) 1.0 - ((double) HUGE_VAL / json_variant_real(json_variant_by_index(v, 5)))) <= delta); /* HUGE_VAL might be +inf, but might also be something else */
assert_se(json_variant_is_real(json_variant_by_index(v, 6)) &&
json_variant_is_integer(json_variant_by_index(v, 6)) &&
json_variant_integer(json_variant_by_index(v, 6)) == 0);
test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
test_tokenizer("18446744073709551615", JSON_TOKEN_UNSIGNED, (uintmax_t) UINT64_MAX, JSON_TOKEN_END);
test_tokenizer("-9223372036854775808", JSON_TOKEN_INTEGER, (intmax_t) INT64_MIN, JSON_TOKEN_END);
- test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (long double) 18446744073709551616.0L, JSON_TOKEN_END);
- test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (long double) -9223372036854775809.0L, JSON_TOKEN_END);
+ test_tokenizer("18446744073709551616", JSON_TOKEN_REAL, (double) 18446744073709551616.0L, JSON_TOKEN_END);
+ test_tokenizer("-9223372036854775809", JSON_TOKEN_REAL, (double) -9223372036854775809.0L, JSON_TOKEN_END);
test_tokenizer("-1234", JSON_TOKEN_INTEGER, (intmax_t) -1234, JSON_TOKEN_END);
- test_tokenizer("3.141", JSON_TOKEN_REAL, (long double) 3.141, JSON_TOKEN_END);
- test_tokenizer("0.0", JSON_TOKEN_REAL, (long double) 0.0, JSON_TOKEN_END);
- test_tokenizer("7e3", JSON_TOKEN_REAL, (long double) 7e3, JSON_TOKEN_END);
- test_tokenizer("-7e-3", JSON_TOKEN_REAL, (long double) -7e-3, JSON_TOKEN_END);
+ test_tokenizer("3.141", JSON_TOKEN_REAL, (double) 3.141, JSON_TOKEN_END);
+ test_tokenizer("0.0", JSON_TOKEN_REAL, (double) 0.0, JSON_TOKEN_END);
+ test_tokenizer("7e3", JSON_TOKEN_REAL, (double) 7e3, JSON_TOKEN_END);
+ test_tokenizer("-7e-3", JSON_TOKEN_REAL, (double) -7e-3, JSON_TOKEN_END);
test_tokenizer("true", JSON_TOKEN_BOOLEAN, true, JSON_TOKEN_END);
test_tokenizer("false", JSON_TOKEN_BOOLEAN, false, JSON_TOKEN_END);
test_tokenizer("null", JSON_TOKEN_NULL, JSON_TOKEN_END);