Skip to content

Commit

Permalink
jv int64 and uint64 support
Browse files Browse the repository at this point in the history
  • Loading branch information
nicowilliams committed Jan 29, 2017
1 parent d2c3cf4 commit b28c886
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 5 deletions.
2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ if test "x$valgrind_cmd" = "x" ; then
fi
AC_CHECK_FUNCS(memmem)
AC_CHECK_FUNCS(mkstemp)
AC_CHECK_FUNCS(strtoimax)
AC_CHECK_FUNCS(strtoumax)

AC_CHECK_HEADER("shlwapi.h",[have_win32=1;])
AM_CONDITIONAL([WIN32], [test "x$have_win32" = x1])
Expand Down
123 changes: 121 additions & 2 deletions src/jv.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ jv_kind jv_get_kind(jv x) {
return x.kind_flags & KIND_MASK;
}

jv_subkind jv_get_subkind(jv x) {
return x.subkind_flags & KIND_MASK;
}

const char* jv_kind_name(jv_kind k) {
switch (k) {
case JV_KIND_INVALID: return "<invalid>";
Expand Down Expand Up @@ -138,19 +142,86 @@ static void jvp_invalid_free(jv x) {
*/

jv jv_number(double x) {
jv j = {JV_KIND_NUMBER, 0, 0, 0, {.number = x}};
jv j = {JV_KIND_NUMBER, JV_SUBKIND_NONE, 0, 0, {.number = x}};
return j;
}

jv jv_int64(int64_t x) {
#ifndef JQ_OMIT_INTS
jv j = {JV_KIND_NUMBER, JV_SUBKIND_INT64, 0, 0, {.int64 = x}};
#else
jv j = {JV_KIND_NUMBER, JV_SUBKIND_INT64, 0, 0, {.number = x}};
#endif
return j;
}

jv jv_uint64(uint64_t x) {
#ifndef JQ_OMIT_INTS
jv j = {JV_KIND_NUMBER, JV_SUBKIND_UINT64, 0, 0, {.uint64 = x}};
#else
jv j = {JV_KIND_NUMBER, JV_SUBKIND_UINT64, 0, 0, {.number = x}};
#endif
return j;
}

double jv_number_value(jv j) {
assert(jv_get_kind(j) == JV_KIND_NUMBER);
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk == JV_SUBKIND_NONE)
return j.u.number;
if (sk == JV_SUBKIND_INT64)
return j.u.int64;
assert(sk == JV_SUBKIND_UINT64);
return j.u.uint64;
#else
return j.u.number;
#endif
}

int64_t jv_int64_value(jv j)
{
assert(jv_get_kind(j) == JV_KIND_NUMBER);
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk == JV_SUBKIND_INT64)
return j.u.int64;
if (sk == JV_SUBKIND_UINT64) {
if (j.u.uint64 <= INT64_MAX)
return (int64_t)j.u.uint64;
return INT64_MAX;
}
#endif
return j.u.number;
}

uint64_t jv_uint64_value(jv j)
{
assert(jv_get_kind(j) == JV_KIND_NUMBER);
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk == JV_SUBKIND_UINT64)
return j.u.uint64;
if (sk == JV_SUBKIND_INT64) {
if (j.u.int64 >= 0)
return j.u.int64;
return 0;
}
#endif
return j.u.number;
}

int jv_is_integer(jv j){
if(jv_get_kind(j) != JV_KIND_NUMBER){
return 0;
}
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk != JV_SUBKIND_NONE) {
assert(sk == JV_SUBKIND_UINT64 || sk == JV_SUBKIND_INT64);
return 1;
}
#endif
double x = jv_number_value(j);
if(x != x || x > INT_MAX || x < INT_MIN){
return 0;
Expand All @@ -159,6 +230,42 @@ int jv_is_integer(jv j){
return x == (int)x;
}

int jv_is_int64(jv j)
{
if(jv_get_kind(j) != JV_KIND_NUMBER){
return 0;
}
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk == JV_SUBKIND_INT64)
return 1;
if (sk == JV_SUBKIND_UINT64) {
if (j.u.uint64 <= INT64_MAX)
return 1;
return 0;
}
#endif
return jv_is_integer(j);
}

int jv_is_uint64(jv j)
{
if(jv_get_kind(j) != JV_KIND_NUMBER){
return 0;
}
#ifndef JQ_OMIT_INTS
char sk = jv_get_subkind(j);
if (sk == JV_SUBKIND_UINT64)
return 1;
if (sk == JV_SUBKIND_INT64) {
if (j.u.int64 >= 0)
return 1;
return 0;
}
#endif
return jv_is_integer(j);
}

/*
* Arrays (internal helpers)
*/
Expand Down Expand Up @@ -1302,9 +1409,21 @@ int jv_identical(jv a, jv b) {
case JV_KIND_OBJECT:
r = a.u.ptr == b.u.ptr;
break;
case JV_KIND_NUMBER:
case JV_KIND_NUMBER: {
#ifndef JQ_OMIT_INTS
char ask = jv_get_subkind(a);
char bsk = jv_get_subkind(b);
if (ask != bsk)
r = jv_number_value(a) == jv_number_value(b);
else if (ask == JV_SUBKIND_NONE)
r = memcmp(&a.u.number, &b.u.number, sizeof(a.u.number)) == 0;
else
r = a.u.int64 == b.u.int64; /* this handles int64 and uint64 */
#else
r = memcmp(&a.u.number, &b.u.number, sizeof(a.u.number)) == 0;
#endif
break;
}
default:
r = 1;
break;
Expand Down
17 changes: 16 additions & 1 deletion src/jv.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@ typedef enum {
JV_KIND_OBJECT
} jv_kind;

typedef enum {
JV_SUBKIND_NONE,
JV_SUBKIND_INT64,
JV_SUBKIND_UINT64,
} jv_subkind;

struct jv_refcnt;

/* All of the fields of this struct are private.
Really. Do not play with them. */
typedef struct {
unsigned char kind_flags;
unsigned char pad_;
unsigned char subkind_flags;
unsigned short offset; /* array offsets */
int size;
union {
struct jv_refcnt* ptr;
double number;
int64_t int64;
uint64_t uint64;
} u;
} jv;

Expand All @@ -37,6 +45,7 @@ typedef struct {
*/

jv_kind jv_get_kind(jv);
jv_subkind jv_get_subkind(jv);
const char* jv_kind_name(jv_kind);
static int jv_is_valid(jv x) { return jv_get_kind(x) != JV_KIND_INVALID; }

Expand All @@ -61,8 +70,14 @@ jv jv_false(void);
jv jv_bool(int);

jv jv_number(double);
jv jv_int64(int64_t);
jv jv_uint64(uint64_t);
double jv_number_value(jv);
int64_t jv_int64_value(jv);
uint64_t jv_uint64_value(jv);
int jv_is_integer(jv);
int jv_is_int64(jv);
int jv_is_uint64(jv);

jv jv_array(void);
jv jv_array_sized(int);
Expand Down
49 changes: 48 additions & 1 deletion src/jv_parse.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "jv.h"
#include "jv_dtoa.h"
#include "jv_unicode.h"
Expand Down Expand Up @@ -496,8 +499,52 @@ static pfunc check_literal(struct jv_parser* p) {
double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end);
if (end == 0 || *end != 0)
return "Invalid numeric literal";

#ifndef JQ_OMIT_INTS
if (d == (int64_t)d || d == (uint64_t)d) {
if (d >= INT64_MIN && d <= INT64_MAX) {
TRY(value(p, jv_int64(d)));
goto out;
} else if (d >= 0 && d <= UINT64_MAX) {
TRY(value(p, jv_uint64(d)));
goto out;
}

char *q = p->tokenbuf;
int is_signed = 0;
while (isspace(*q))
q++;
if (*q == '-') {
is_signed = 1;
q++;
}
errno = 0;
if (is_signed) {
#ifdef HAVE_STRTOIMAX
int64_t i64 = strtoimax(p->tokenbuf, &q, 10);
#else
int64_t i64 = strtoll(p->tokenbuf, &q, 10);
#endif
if (q == end && i64 < 0 && errno == 0) {
TRY(value(p, jv_int64(i64)));
goto out;
}
} else {
#ifdef HAVE_STRTOUMAX
uint64_t u64 = strtoumax(p->tokenbuf, &q, 10);
#else
uint64_t u64 = strtoull(p->tokenbuf, &q, 10);
#endif
if (q == end && errno == 0) {
TRY(value(p, jv_int64(u64)));
goto out;
}
}
}
#endif
TRY(value(p, jv_number(d)));
}
out:
p->tokenpos = 0;
return 0;
}
Expand Down
18 changes: 17 additions & 1 deletion src/jv_print.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <assert.h>
#include <stdio.h>
#include <inttypes.h>
#include <float.h>
#include <stdio.h>
#include <string.h>

#ifdef WIN32
Expand Down Expand Up @@ -182,6 +183,21 @@ static void jv_dump_term(struct dtoa_context* C, jv x, int flags, int indent, FI
put_str("true", F, S, flags & JV_PRINT_ISATTY);
break;
case JV_KIND_NUMBER: {
#ifndef JQ_OMIT_INTS
if (jv_is_int64(x)) {
int64_t i64 = jv_int64_value(x);
char buf[21];
(void) snprintf(buf, sizeof(buf), "%" PRId64, i64);
put_str(buf, F, S, flags & JV_PRINT_ISATTY);
break;
} else if (jv_is_uint64(x)) {
uint64_t u64 = jv_uint64_value(x);
char buf[21];
(void) snprintf(buf, sizeof(buf), "%" PRIu64, u64);
put_str(buf, F, S, flags & JV_PRINT_ISATTY);
break;
}
#endif
double d = jv_number_value(x);
if (d != d) {
// JSON doesn't have NaN, so we'll render it as "null"
Expand Down

0 comments on commit b28c886

Please sign in to comment.