Add JSON_REAL_PRECISION

Fixes #178.
This commit is contained in:
Petri Lehtinen 2014-04-30 12:46:33 +03:00
parent 5b88cc5ded
commit 17b5fdd94b
6 changed files with 55 additions and 18 deletions

View File

@ -905,6 +905,16 @@ can be ORed together to obtain *flags*.
.. versionadded:: 2.4
``JSON_REAL_PRECISION(n)``
Output all real numbers with at most *n* digits of precision. The
valid range for *n* is between 0 and 31 (inclusive), and other
values result in an undefined behavior.
By default, the precision is 17, to correctly and losslessly encode
all IEEE 754 double precision floating point numbers.
.. versionadded:: 2.7
The following functions perform the actual JSON encoding. The result
is in UTF-8.

View File

@ -22,6 +22,9 @@
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct object_key {
size_t serial;
const char *key;
@ -45,9 +48,9 @@ static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(JSON_INDENT(flags) > 0)
if(FLAGS_TO_INDENT(flags) > 0)
{
int i, ws_count = JSON_INDENT(flags);
int i, ws_count = FLAGS_TO_INDENT(flags);
if(dump("\n", 1, data))
return -1;
@ -208,7 +211,8 @@ static int do_dump(const json_t *json, size_t flags, int depth,
int size;
double value = json_real_value(json);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
FLAGS_TO_PRECISION(flags));
if(size < 0)
return -1;

View File

@ -259,13 +259,14 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
/* encoding */
#define JSON_INDENT(n) (n & 0x1F)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_INDENT(n) ((n) & 0x1F)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);

View File

@ -81,7 +81,7 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);

View File

@ -78,13 +78,16 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out)
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value)
int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
{
int ret;
char *start, *end;
size_t length;
ret = snprintf(buffer, size, "%.17g", value);
if (precision == 0)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, value);
if(ret < 0)
return -1;

View File

@ -39,6 +39,7 @@ struct config {
int use_env;
int have_hashseed;
int hashseed;
int precision;
} conf;
#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t')
@ -108,6 +109,8 @@ static void read_conf(FILE *conffile)
conf.preserve_order = atoi(val);
if (!strcmp(line, "JSON_SORT_KEYS"))
conf.sort_keys = atoi(val);
if (!strcmp(line, "JSON_REAL_PRECISION"))
conf.precision = atoi(val);
if (!strcmp(line, "STRIP"))
conf.strip = atoi(val);
if (!strcmp(line, "HASHSEED")) {
@ -176,11 +179,10 @@ int use_conf(char *test_path)
fclose(conffile);
}
if (conf.indent < 0 || conf.indent > 255) {
if (conf.indent < 0 || conf.indent > 31) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent);
return 2;
}
if (conf.indent)
flags |= JSON_INDENT(conf.indent);
@ -196,6 +198,14 @@ int use_conf(char *test_path)
if (conf.sort_keys)
flags |= JSON_SORT_KEYS;
if (conf.precision < 0 || conf.precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
conf.precision);
return 2;
}
if (conf.precision)
flags |= JSON_REAL_PRECISION(conf.precision);
if (conf.have_hashseed)
json_object_seed(conf.hashseed);
@ -245,7 +255,7 @@ static int getenv_int(const char *name)
int use_env()
{
int indent;
int indent, precision;
size_t flags = 0;
json_t *json;
json_error_t error;
@ -258,11 +268,10 @@ int use_env()
#endif
indent = getenv_int("JSON_INDENT");
if(indent < 0 || indent > 255) {
if(indent < 0 || indent > 31) {
fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent);
return 2;
}
if(indent > 0)
flags |= JSON_INDENT(indent);
@ -278,9 +287,19 @@ int use_env()
if(getenv_int("JSON_SORT_KEYS"))
flags |= JSON_SORT_KEYS;
precision = getenv_int("JSON_REAL_PRECISION");
if(precision < 0 || precision > 31) {
fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n",
precision);
return 2;
}
if(getenv("HASHSEED"))
json_object_seed(getenv_int("HASHSEED"));
if(precision > 0)
flags |= JSON_REAL_PRECISION(precision);
if(getenv_int("STRIP")) {
/* Load to memory, strip leading and trailing whitespace */
size_t size = 0, used = 0;