Skip to content

Commit

Permalink
Rebase Deron Meranda's original bignum patch
Browse files Browse the repository at this point in the history
  • Loading branch information
akheron committed Jan 28, 2014
1 parent 30fdf60 commit f8716ac
Show file tree
Hide file tree
Showing 12 changed files with 1,563 additions and 122 deletions.
717 changes: 681 additions & 36 deletions doc/apiref.rst

Large diffs are not rendered by default.

23 changes: 17 additions & 6 deletions doc/conformance.rst
Expand Up @@ -43,7 +43,9 @@ JSON makes no distinction between real and integer numbers; Jansson
does. Real numbers are mapped to the ``double`` type and integers to
the ``json_int_t`` type, which is a typedef of ``long long`` or
``long``, depending on whether ``long long`` is supported by your
compiler or not.
compiler or not. Jansson also has an extension mechanism that allows
an externally provided big number package to be used to represent
arbitrary-sized integers and real numbers.

A JSON number is considered to be a real number if its lexical
representation includes one of ``e``, ``E``, or ``.``; regardless if
Expand All @@ -61,6 +63,13 @@ represented in JSON as ``3.0``, not ``3``.
Overflow, Underflow & Precision
-------------------------------

If a big number extension is used for either integer or real values,
then the behavior of all overflows, underflows, or loss of precision
is left to the extension. It is possible that no errors or loss of
information need ever occur.

However lacking a big number extension there are limitations.

Real numbers whose absolute values are too small to be represented in
a C ``double`` will be silently estimated with 0.0. Thus, depending on
platform, JSON numbers very close to zero such as 1E-999 may result in
Expand Down Expand Up @@ -101,10 +110,12 @@ IEEE support the concept of signed integer zeros.
Types
-----

No support is provided in Jansson for any C numeric types other than
``json_int_t`` and ``double``. This excludes things such as unsigned
types, ``long double``, etc. Obviously, shorter types like ``short``,
The only numeric types with direct built-in support in Jansson are the
``json_int_t`` and ``double`` types. Shorter types like ``short``,
``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float``
are implicitly handled via the ordinary C type coercion rules (subject
to overflow semantics). Also, no support or hooks are provided for any
supplemental "bignum" type add-on packages.
to overflow semantics).

Larger or more precise numeric types may be supported by using the big
number extension API; though such support depends upon an external big
number package.
89 changes: 81 additions & 8 deletions src/dump.c
Expand Up @@ -192,29 +192,102 @@ static int do_dump(const json_t *json, size_t flags, int depth,
{
char buffer[MAX_INTEGER_STR_LENGTH];
int size;
int rc;

size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;

return dump(buffer, size, data);
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) {
rc = -1;
}
else {
rc = dump(buffer, size, data);
}
jsonp_overwrite(buffer, sizeof(buffer));
return rc;
}

case JSON_BIGINTEGER:
{
json_context_t *ctx;
json_bigz_const_t z;
int size;
int rc;
char buffer[MAX_INTEGER_STR_LENGTH * 5];

ctx = jsonp_context();
if(!ctx->have_bigint)
return -1;
z = json_biginteger_value(json);
size = ctx->bigint.to_string_fn(z, buffer, sizeof(buffer), &ctx->memfuncs);

if(size >= (int)sizeof(buffer)) {
/* Buffer was too small, allocate a bigger one */
char* bigbuffer;
bigbuffer = ctx->memfuncs.malloc_fn(size + 4 /*extra for safety*/);
if(!bigbuffer)
return -1;
size = ctx->bigint.to_string_fn(z, bigbuffer, size, &ctx->memfuncs);
rc = dump(bigbuffer, size, data);
ctx->memfuncs.free_fn(bigbuffer);
}
else {
rc = dump(buffer, size, data);
}
ctx->memfuncs.overwrite_fn(buffer, sizeof(buffer));
return rc;
}

case JSON_REAL:
{
char buffer[MAX_REAL_STR_LENGTH];
int rc;
int size;
double value = json_real_value(json);

size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
if(size < 0)
return -1;

return dump(buffer, size, data);
if(size < 0) {
rc = -1;
}
else {
rc = dump(buffer, size, data);
}
jsonp_overwrite(buffer, sizeof(buffer));
value = 0.0;
return rc;
}

case JSON_BIGREAL:
{
json_context_t *ctx;
json_bigr_const_t r;
int size;
int rc;
char buffer[MAX_REAL_STR_LENGTH * 5];

ctx = jsonp_context();
if(!ctx->have_bigreal)
return -1;
r = json_bigreal_value(json);
size = ctx->bigreal.to_string_fn(r, buffer, sizeof(buffer), &ctx->memfuncs);

if(size >= (int)sizeof(buffer)) {
/* Buffer was too small, allocate a bigger one */
char* bigbuffer;
bigbuffer = ctx->memfuncs.malloc_fn(size + 4 /*extra for safety*/);
if(!bigbuffer)
return -1;
size = ctx->bigreal.to_string_fn(r, bigbuffer, size, &ctx->memfuncs);
rc = dump(bigbuffer, size, data);
ctx->memfuncs.free_fn(bigbuffer);
}
else {
rc = dump(buffer, size, data);
}
ctx->memfuncs.overwrite_fn(buffer, sizeof(buffer));
return rc;
}

case JSON_STRING:
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);

Expand Down
134 changes: 123 additions & 11 deletions src/jansson.h
Expand Up @@ -14,6 +14,10 @@

#include <jansson_config.h>

#if USE_GNU_MP
#include <gmp.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand All @@ -36,6 +40,9 @@ extern "C" {

/* types */


struct json_context; /* forward reference */

typedef enum {
JSON_OBJECT,
JSON_ARRAY,
Expand All @@ -44,7 +51,9 @@ typedef enum {
JSON_REAL,
JSON_TRUE,
JSON_FALSE,
JSON_NULL
JSON_NULL,
JSON_BIGINTEGER,
JSON_BIGREAL
} json_type;

typedef struct json_t {
Expand All @@ -66,13 +75,32 @@ typedef long json_int_t;
#endif /* JSON_INTEGER_IS_LONG_LONG */
#endif

#ifndef JSON_BIGZ_TYPE
#define JSON_BIGZ_TYPE void
#endif
#ifndef JSON_BIGR_TYPE
#define JSON_BIGR_TYPE void
#endif

typedef JSON_BIGZ_TYPE * json_bigz_t;
typedef JSON_BIGR_TYPE * json_bigr_t;
typedef JSON_BIGZ_TYPE const * json_bigz_const_t;
typedef JSON_BIGR_TYPE const * json_bigr_const_t;


#define json_typeof(json) ((json)->type)
#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
#define json_is_biginteger(json) (json && json_typeof(json) == JSON_BIGINTEGER)
#define json_is_anyinteger(json) (json_is_integer(json) || json_is_biginteger(json))
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_bigreal(json) (json && json_typeof(json) == JSON_BIGREAL)
#define json_is_anyreal(json) (json_is_real(json) || json_is_bigreal(json))
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
#define json_is_bignumber(json) (json_is_biginteger(json) || json_is_bigreal(json))
#define json_is_anynumber(json) (json_is_number(json) || json_is_bignumber(json))
#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
#define json_boolean_value json_is_true
Expand All @@ -93,6 +121,8 @@ json_t *json_true(void);
json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
json_t *json_biginteger(json_bigz_const_t value);
json_t *json_bigreal(json_bigr_const_t value);

static JSON_INLINE
json_t *json_incref(json_t *json)
Expand Down Expand Up @@ -214,6 +244,12 @@ int json_string_setn_nocheck(json_t *string, const char *value, size_t len);
int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);

json_bigz_const_t json_biginteger_value(const json_t *biginteger);
int json_biginteger_set(json_t *biginteger, json_bigz_const_t mpz);

json_bigr_const_t json_bigreal_value(const json_t *bigreal);
int json_bigreal_set(json_t *bigreal, json_bigr_const_t mpf);

/* pack, unpack */

json_t *json_pack(const char *fmt, ...);
Expand Down Expand Up @@ -258,13 +294,17 @@ 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_USE_BIGINT 0x800
#define JSON_USE_BIGINT_ALWAYS 0x1000
#define JSON_USE_BIGREAL 0x2000
#define JSON_USE_BIGREAL_ALWAYS 0x4000

typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);

Expand All @@ -273,12 +313,84 @@ int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);

/* custom memory allocation */
/* custom memory functions */

typedef void *(*json_malloc_t)(size_t); /* allocate memory */
typedef void (*json_free_t)(void *); /* free memory */
typedef void *(*json_realloc_t)(void *, size_t); /* change allocation size */
typedef void (*json_overwrite_t)(void *, size_t); /* overwrite memory */
typedef char *(*json_strdup_t)(const char *); /* duplicate string */

typedef void *(*json_malloc_t)(size_t);
typedef void (*json_free_t)(void *);
typedef struct {
json_malloc_t malloc_fn;
json_free_t free_fn;
json_realloc_t realloc_fn;
json_overwrite_t overwrite_fn;
json_strdup_t strdup_fn;
} json_memory_funcs_t;

void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_set_realloc_func(json_realloc_t realloc_fn);
void json_set_overwrite_func( json_overwrite_t overwrite_fn );


/* big integers */

typedef json_bigz_t (*json_bigint_copy_t)(json_bigz_const_t bignum,
const json_memory_funcs_t *memfuncs);
typedef void (*json_bigint_del_t)(json_bigz_t bignum,
const json_memory_funcs_t *memfuncs);
typedef int (*json_bigint_cmp_t)(json_bigz_const_t bignum1,
json_bigz_const_t bignum2,
const json_memory_funcs_t *memfuncs);
typedef int (*json_bigint_to_str_t)(json_bigz_const_t bignum,
char *buffer, size_t size,
const json_memory_funcs_t *memfuncs);
typedef json_bigz_t (*json_bigint_from_str_t)(const char *value,
const json_memory_funcs_t *memfuncs);
typedef json_bigz_t (*json_bigint_from_int_t)(json_int_t value,
const json_memory_funcs_t *memfuncs);

typedef struct {
json_bigint_copy_t copy_fn;
json_bigint_del_t delete_fn;
json_bigint_cmp_t compare_fn;
json_bigint_to_str_t to_string_fn;
json_bigint_from_str_t from_string_fn;
json_bigint_from_int_t from_int_fn;
} json_bigint_funcs_t;

void json_set_biginteger_funcs(const json_bigint_funcs_t* functions);


/* Big reals */

typedef json_bigr_t (*json_bigreal_copy_t)(json_bigr_const_t bigreal,
const json_memory_funcs_t *memfuncs);
typedef void (*json_bigreal_del_t)(json_bigr_t bigreal,
const json_memory_funcs_t *memfuncs);
typedef int (*json_bigreal_cmp_t)(json_bigr_const_t bigreal1,
json_bigr_const_t bigreal2,
const json_memory_funcs_t *memfuncs);
typedef int (*json_bigreal_to_str_t)(json_bigr_const_t bigreal,
char *buffer, size_t size,
const json_memory_funcs_t *memfuncs);
typedef json_bigr_t (*json_bigreal_from_str_t)(const char *value,
const json_memory_funcs_t *memfuncs);
typedef json_bigr_t (*json_bigreal_from_real_t)(double value,
const json_memory_funcs_t *memfuncs);

typedef struct {
json_bigreal_copy_t copy_fn;
json_bigreal_del_t delete_fn;
json_bigreal_cmp_t compare_fn;
json_bigreal_to_str_t to_string_fn;
json_bigreal_from_str_t from_string_fn;
json_bigreal_from_real_t from_real_fn;
} json_bigreal_funcs_t;

void json_set_bigreal_funcs(const json_bigreal_funcs_t* functions);


#ifdef __cplusplus
}
Expand Down

0 comments on commit f8716ac

Please sign in to comment.