summary refs log tree commit diff stats
path: root/qobject
diff options
context:
space:
mode:
Diffstat (limited to 'qobject')
-rw-r--r--qobject/Makefile.objs2
-rw-r--r--qobject/json-parser.c30
-rw-r--r--qobject/qdict.c37
-rw-r--r--qobject/qfloat.c62
-rw-r--r--qobject/qint.c61
-rw-r--r--qobject/qjson.c37
-rw-r--r--qobject/qnum.c159
-rw-r--r--qobject/qobject.c3
8 files changed, 194 insertions, 197 deletions
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
index bed55084bb..fc8885c9a4 100644
--- a/qobject/Makefile.objs
+++ b/qobject/Makefile.objs
@@ -1,2 +1,2 @@
-util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
+util-obj-y = qnull.o qnum.o qstring.o qdict.o qlist.o qbool.o
 util-obj-y += qjson.o qobject.o json-lexer.o json-streamer.o json-parser.o
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index c18e48ab94..5e808289f5 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -466,16 +466,16 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
     } else if (!strcmp(token->str, "%i")) {
         return QOBJECT(qbool_from_bool(va_arg(*ap, int)));
     } else if (!strcmp(token->str, "%d")) {
-        return QOBJECT(qint_from_int(va_arg(*ap, int)));
+        return QOBJECT(qnum_from_int(va_arg(*ap, int)));
     } else if (!strcmp(token->str, "%ld")) {
-        return QOBJECT(qint_from_int(va_arg(*ap, long)));
+        return QOBJECT(qnum_from_int(va_arg(*ap, long)));
     } else if (!strcmp(token->str, "%lld") ||
                !strcmp(token->str, "%I64d")) {
-        return QOBJECT(qint_from_int(va_arg(*ap, long long)));
+        return QOBJECT(qnum_from_int(va_arg(*ap, long long)));
     } else if (!strcmp(token->str, "%s")) {
         return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
     } else if (!strcmp(token->str, "%f")) {
-        return QOBJECT(qfloat_from_double(va_arg(*ap, double)));
+        return QOBJECT(qnum_from_double(va_arg(*ap, double)));
     }
     return NULL;
 }
@@ -491,24 +491,22 @@ static QObject *parse_literal(JSONParserContext *ctxt)
     case JSON_STRING:
         return QOBJECT(qstring_from_escaped_str(ctxt, token));
     case JSON_INTEGER: {
-        /* A possibility exists that this is a whole-valued float where the
-         * fractional part was left out due to being 0 (.0). It's not a big
-         * deal to treat these as ints in the parser, so long as users of the
-         * resulting QObject know to expect a QInt in place of a QFloat in
-         * cases like these.
+        /*
+         * Represent JSON_INTEGER as QNUM_I64 if possible, else as
+         * QNUM_DOUBLE.  Note that strtoll() fails with ERANGE when
+         * it's not possible.
          *
-         * However, in some cases these values will overflow/underflow a
-         * QInt/int64 container, thus we should assume these are to be handled
-         * as QFloats/doubles rather than silently changing their values.
-         *
-         * strtoll() indicates these instances by setting errno to ERANGE
+         * qnum_get_int() will then work for any signed 64-bit
+         * JSON_INTEGER, and qnum_get_double() both for any
+         * JSON_INTEGER and any JSON_FLOAT (with precision loss for
+         * integers beyond 53 bits)
          */
         int64_t value;
 
         errno = 0; /* strtoll doesn't set errno on success */
         value = strtoll(token->str, NULL, 10);
         if (errno != ERANGE) {
-            return QOBJECT(qint_from_int(value));
+            return QOBJECT(qnum_from_int(value));
         }
         /* fall through to JSON_FLOAT */
     }
@@ -516,7 +514,7 @@ static QObject *parse_literal(JSONParserContext *ctxt)
         /* FIXME dependent on locale; a pervasive issue in QEMU */
         /* FIXME our lexer matches RFC 7159 in forbidding Inf or NaN,
          * but those might be useful extensions beyond JSON */
-        return QOBJECT(qfloat_from_double(strtod(token->str, NULL)));
+        return QOBJECT(qnum_from_double(strtod(token->str, NULL)));
     default:
         abort();
     }
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 88e2ecd658..576018e531 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -11,8 +11,7 @@
  */
 
 #include "qemu/osdep.h"
-#include "qapi/qmp/qint.h"
-#include "qapi/qmp/qfloat.h"
+#include "qapi/qmp/qnum.h"
 #include "qapi/qmp/qdict.h"
 #include "qapi/qmp/qbool.h"
 #include "qapi/qmp/qstring.h"
@@ -180,37 +179,26 @@ size_t qdict_size(const QDict *qdict)
 /**
  * qdict_get_double(): Get an number mapped by 'key'
  *
- * This function assumes that 'key' exists and it stores a
- * QFloat or QInt object.
+ * This function assumes that 'key' exists and it stores a QNum.
  *
  * Return number mapped by 'key'.
  */
 double qdict_get_double(const QDict *qdict, const char *key)
 {
-    QObject *obj = qdict_get(qdict, key);
-
-    assert(obj);
-    switch (qobject_type(obj)) {
-    case QTYPE_QFLOAT:
-        return qfloat_get_double(qobject_to_qfloat(obj));
-    case QTYPE_QINT:
-        return qint_get_int(qobject_to_qint(obj));
-    default:
-        abort();
-    }
+    return qnum_get_double(qobject_to_qnum(qdict_get(qdict, key)));
 }
 
 /**
  * qdict_get_int(): Get an integer mapped by 'key'
  *
  * This function assumes that 'key' exists and it stores a
- * QInt object.
+ * QNum representable as int.
  *
  * Return integer mapped by 'key'.
  */
 int64_t qdict_get_int(const QDict *qdict, const char *key)
 {
-    return qint_get_int(qobject_to_qint(qdict_get(qdict, key)));
+    return qnum_get_int(qobject_to_qnum(qdict_get(qdict, key)));
 }
 
 /**
@@ -259,16 +247,21 @@ const char *qdict_get_str(const QDict *qdict, const char *key)
 /**
  * qdict_get_try_int(): Try to get integer mapped by 'key'
  *
- * Return integer mapped by 'key', if it is not present in
- * the dictionary or if the stored object is not of QInt type
- * 'def_value' will be returned.
+ * Return integer mapped by 'key', if it is not present in the
+ * dictionary or if the stored object is not a QNum representing an
+ * integer, 'def_value' will be returned.
  */
 int64_t qdict_get_try_int(const QDict *qdict, const char *key,
                           int64_t def_value)
 {
-    QInt *qint = qobject_to_qint(qdict_get(qdict, key));
+    QNum *qnum = qobject_to_qnum(qdict_get(qdict, key));
+    int64_t val;
+
+    if (!qnum || !qnum_get_try_int(qnum, &val)) {
+        return def_value;
+    }
 
-    return qint ? qint_get_int(qint) : def_value;
+    return val;
 }
 
 /**
diff --git a/qobject/qfloat.c b/qobject/qfloat.c
deleted file mode 100644
index d5da847701..0000000000
--- a/qobject/qfloat.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * QFloat Module
- *
- * Copyright IBM, Corp. 2009
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/qmp/qfloat.h"
-#include "qapi/qmp/qobject.h"
-#include "qemu-common.h"
-
-/**
- * qfloat_from_int(): Create a new QFloat from a float
- *
- * Return strong reference.
- */
-QFloat *qfloat_from_double(double value)
-{
-    QFloat *qf;
-
-    qf = g_malloc(sizeof(*qf));
-    qobject_init(QOBJECT(qf), QTYPE_QFLOAT);
-    qf->value = value;
-
-    return qf;
-}
-
-/**
- * qfloat_get_double(): Get the stored float
- */
-double qfloat_get_double(const QFloat *qf)
-{
-    return qf->value;
-}
-
-/**
- * qobject_to_qfloat(): Convert a QObject into a QFloat
- */
-QFloat *qobject_to_qfloat(const QObject *obj)
-{
-    if (!obj || qobject_type(obj) != QTYPE_QFLOAT) {
-        return NULL;
-    }
-    return container_of(obj, QFloat, base);
-}
-
-/**
- * qfloat_destroy_obj(): Free all memory allocated by a
- * QFloat object
- */
-void qfloat_destroy_obj(QObject *obj)
-{
-    assert(obj != NULL);
-    g_free(qobject_to_qfloat(obj));
-}
diff --git a/qobject/qint.c b/qobject/qint.c
deleted file mode 100644
index d7d1b3021f..0000000000
--- a/qobject/qint.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * QInt Module
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * Authors:
- *  Luiz Capitulino <lcapitulino@redhat.com>
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING.LIB file in the top-level directory.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/qmp/qint.h"
-#include "qapi/qmp/qobject.h"
-#include "qemu-common.h"
-
-/**
- * qint_from_int(): Create a new QInt from an int64_t
- *
- * Return strong reference.
- */
-QInt *qint_from_int(int64_t value)
-{
-    QInt *qi;
-
-    qi = g_malloc(sizeof(*qi));
-    qobject_init(QOBJECT(qi), QTYPE_QINT);
-    qi->value = value;
-
-    return qi;
-}
-
-/**
- * qint_get_int(): Get the stored integer
- */
-int64_t qint_get_int(const QInt *qi)
-{
-    return qi->value;
-}
-
-/**
- * qobject_to_qint(): Convert a QObject into a QInt
- */
-QInt *qobject_to_qint(const QObject *obj)
-{
-    if (!obj || qobject_type(obj) != QTYPE_QINT) {
-        return NULL;
-    }
-    return container_of(obj, QInt, base);
-}
-
-/**
- * qint_destroy_obj(): Free all memory allocated by a
- * QInt object
- */
-void qint_destroy_obj(QObject *obj)
-{
-    assert(obj != NULL);
-    g_free(qobject_to_qint(obj));
-}
diff --git a/qobject/qjson.c b/qobject/qjson.c
index b2f3bfec53..2e0930884e 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -132,12 +132,11 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
     case QTYPE_QNULL:
         qstring_append(str, "null");
         break;
-    case QTYPE_QINT: {
-        QInt *val = qobject_to_qint(obj);
-        char buffer[1024];
-
-        snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val));
+    case QTYPE_QNUM: {
+        QNum *val = qobject_to_qnum(obj);
+        char *buffer = qnum_to_string(val);
         qstring_append(str, buffer);
+        g_free(buffer);
         break;
     }
     case QTYPE_QSTRING: {
@@ -234,34 +233,6 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
         qstring_append(str, "]");
         break;
     }
-    case QTYPE_QFLOAT: {
-        QFloat *val = qobject_to_qfloat(obj);
-        char buffer[1024];
-        int len;
-
-        /* FIXME: snprintf() is locale dependent; but JSON requires
-         * numbers to be formatted as if in the C locale. Dependence
-         * on C locale is a pervasive issue in QEMU. */
-        /* FIXME: This risks printing Inf or NaN, which are not valid
-         * JSON values. */
-        /* FIXME: the default precision of 6 for %f often causes
-         * rounding errors; we should be using DBL_DECIMAL_DIG (17),
-         * and only rounding to a shorter number if the result would
-         * still produce the same floating point value.  */
-        len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
-        while (len > 0 && buffer[len - 1] == '0') {
-            len--;
-        }
-
-        if (len && buffer[len - 1] == '.') {
-            buffer[len - 1] = 0;
-        } else {
-            buffer[len] = 0;
-        }
-
-        qstring_append(str, buffer);
-        break;
-    }
     case QTYPE_QBOOL: {
         QBool *val = qobject_to_qbool(obj);
 
diff --git a/qobject/qnum.c b/qobject/qnum.c
new file mode 100644
index 0000000000..7bb9006763
--- /dev/null
+++ b/qobject/qnum.c
@@ -0,0 +1,159 @@
+/*
+ * QNum Module
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ *  Luiz Capitulino <lcapitulino@redhat.com>
+ *  Anthony Liguori <aliguori@us.ibm.com>
+ *  Marc-André Lureau <marcandre.lureau@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qobject.h"
+#include "qemu-common.h"
+
+/**
+ * qnum_from_int(): Create a new QNum from an int64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_int(int64_t value)
+{
+    QNum *qn = g_new(QNum, 1);
+
+    qobject_init(QOBJECT(qn), QTYPE_QNUM);
+    qn->kind = QNUM_I64;
+    qn->u.i64 = value;
+
+    return qn;
+}
+
+/**
+ * qnum_from_double(): Create a new QNum from a double
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_double(double value)
+{
+    QNum *qn = g_new(QNum, 1);
+
+    qobject_init(QOBJECT(qn), QTYPE_QNUM);
+    qn->kind = QNUM_DOUBLE;
+    qn->u.dbl = value;
+
+    return qn;
+}
+
+/**
+ * qnum_get_try_int(): Get an integer representation of the number
+ *
+ * Return true on success.
+ */
+bool qnum_get_try_int(const QNum *qn, int64_t *val)
+{
+    switch (qn->kind) {
+    case QNUM_I64:
+        *val = qn->u.i64;
+        return true;
+    case QNUM_DOUBLE:
+        return false;
+    }
+
+    assert(0);
+    return false;
+}
+
+/**
+ * qnum_get_int(): Get an integer representation of the number
+ *
+ * assert() on failure.
+ */
+int64_t qnum_get_int(const QNum *qn)
+{
+    int64_t val;
+    bool success = qnum_get_try_int(qn, &val);
+    assert(success);
+    return val;
+}
+
+/**
+ * qnum_get_double(): Get a float representation of the number
+ *
+ * qnum_get_double() loses precision for integers beyond 53 bits.
+ */
+double qnum_get_double(QNum *qn)
+{
+    switch (qn->kind) {
+    case QNUM_I64:
+        return qn->u.i64;
+    case QNUM_DOUBLE:
+        return qn->u.dbl;
+    }
+
+    assert(0);
+    return 0.0;
+}
+
+char *qnum_to_string(QNum *qn)
+{
+    char *buffer;
+    int len;
+
+    switch (qn->kind) {
+    case QNUM_I64:
+        return g_strdup_printf("%" PRId64, qn->u.i64);
+    case QNUM_DOUBLE:
+        /* FIXME: snprintf() is locale dependent; but JSON requires
+         * numbers to be formatted as if in the C locale. Dependence
+         * on C locale is a pervasive issue in QEMU. */
+        /* FIXME: This risks printing Inf or NaN, which are not valid
+         * JSON values. */
+        /* FIXME: the default precision of 6 for %f often causes
+         * rounding errors; we should be using DBL_DECIMAL_DIG (17),
+         * and only rounding to a shorter number if the result would
+         * still produce the same floating point value.  */
+        buffer = g_strdup_printf("%f" , qn->u.dbl);
+        len = strlen(buffer);
+        while (len > 0 && buffer[len - 1] == '0') {
+            len--;
+        }
+
+        if (len && buffer[len - 1] == '.') {
+            buffer[len - 1] = 0;
+        } else {
+            buffer[len] = 0;
+        }
+
+        return buffer;
+    }
+
+    assert(0);
+    return NULL;
+}
+
+/**
+ * qobject_to_qnum(): Convert a QObject into a QNum
+ */
+QNum *qobject_to_qnum(const QObject *obj)
+{
+    if (!obj || qobject_type(obj) != QTYPE_QNUM) {
+        return NULL;
+    }
+    return container_of(obj, QNum, base);
+}
+
+/**
+ * qnum_destroy_obj(): Free all memory allocated by a
+ * QNum object
+ */
+void qnum_destroy_obj(QObject *obj)
+{
+    assert(obj != NULL);
+    g_free(qobject_to_qnum(obj));
+}
diff --git a/qobject/qobject.c b/qobject/qobject.c
index fe4fa10989..b0cafb66f1 100644
--- a/qobject/qobject.c
+++ b/qobject/qobject.c
@@ -14,11 +14,10 @@
 static void (*qdestroy[QTYPE__MAX])(QObject *) = {
     [QTYPE_NONE] = NULL,               /* No such object exists */
     [QTYPE_QNULL] = NULL,              /* qnull_ is indestructible */
-    [QTYPE_QINT] = qint_destroy_obj,
+    [QTYPE_QNUM] = qnum_destroy_obj,
     [QTYPE_QSTRING] = qstring_destroy_obj,
     [QTYPE_QDICT] = qdict_destroy_obj,
     [QTYPE_QLIST] = qlist_destroy_obj,
-    [QTYPE_QFLOAT] = qfloat_destroy_obj,
     [QTYPE_QBOOL] = qbool_destroy_obj,
 };