summaryrefslogtreecommitdiff
path: root/qobject/qnum.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2017-06-07 20:35:58 +0400
committerMarkus Armbruster <armbru@redhat.com>2017-06-20 14:31:31 +0200
commit01b2ffcedd94ad7b42bc870e4c6936c87ad03429 (patch)
tree39bbadfbbaa229bfbda245840a256fe0132b2390 /qobject/qnum.c
parent58634047b7deeab36e4b07c4744e44d698975561 (diff)
downloadqemu-01b2ffcedd94ad7b42bc870e4c6936c87ad03429.tar.gz
qapi: merge QInt and QFloat in QNum
We would like to use a same QObject type to represent numbers, whether they are int, uint, or floats. Getters will allow some compatibility between the various types if the number fits other representations. Add a few more tests while at it. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20170607163635.17635-7-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [parse_stats_intervals() simplified a bit, comment in test_visitor_in_int_overflow() tidied up, suppress bogus warnings] Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'qobject/qnum.c')
-rw-r--r--qobject/qnum.c159
1 files changed, 159 insertions, 0 deletions
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));
+}