@@ -44,16 +44,35 @@ typedef enum {
* in range: qnum_get_try_int() / qnum_get_try_uint() check range and
* convert under the hood.
*/
-struct QNum {
- struct QObjectBase_ base;
+
+/**
+ * struct QNumValue: the value of a QNum
+ *
+ * QNumValue literals can be constructed using the `QNUM_VAL_INT`,
+ * `QNUM_VAL_UINT`, and `QNUM_VAL_DOUBLE` macros.
+ */
+typedef struct QNumValue {
QNumKind kind;
union {
int64_t i64;
uint64_t u64;
double dbl;
} u;
+} QNumValue;
+
+#define QNUM_VAL_INT(value) \
+ { .kind = QNUM_I64, .u.i64 = value }
+#define QNUM_VAL_UINT(value) \
+ { .kind = QNUM_U64, .u.u64 = value }
+#define QNUM_VAL_DOUBLE(value) \
+ { .kind = QNUM_DOUBLE, .u.dbl = value }
+
+struct QNum {
+ struct QObjectBase_ base;
+ QNumValue value;
};
+QNum *qnum_from_value(QNumValue value);
QNum *qnum_from_int(int64_t value);
QNum *qnum_from_uint(uint64_t value);
QNum *qnum_from_double(double value);
@@ -16,21 +16,29 @@
#include "qapi/qmp/qnum.h"
/**
- * qnum_from_int(): Create a new QNum from an int64_t
+ * qnum_from_value(): Create a new QNum from a QNumValue
*
* Return strong reference.
*/
-QNum *qnum_from_int(int64_t value)
+QNum *qnum_from_value(QNumValue value)
{
QNum *qn = g_new(QNum, 1);
qobject_init(QOBJECT(qn), QTYPE_QNUM);
- qn->kind = QNUM_I64;
- qn->u.i64 = value;
-
+ qn->value = value;
return qn;
}
+/**
+ * qnum_from_int(): Create a new QNum from an int64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_int(int64_t value)
+{
+ return qnum_from_value((QNumValue)QNUM_VAL_INT(value));
+}
+
/**
* qnum_from_uint(): Create a new QNum from an uint64_t
*
@@ -38,13 +46,7 @@ QNum *qnum_from_int(int64_t value)
*/
QNum *qnum_from_uint(uint64_t value)
{
- QNum *qn = g_new(QNum, 1);
-
- qobject_init(QOBJECT(qn), QTYPE_QNUM);
- qn->kind = QNUM_U64;
- qn->u.u64 = value;
-
- return qn;
+ return qnum_from_value((QNumValue)QNUM_VAL_UINT(value));
}
/**
@@ -54,13 +56,7 @@ QNum *qnum_from_uint(uint64_t value)
*/
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;
+ return qnum_from_value((QNumValue)QNUM_VAL_DOUBLE(value));
}
/**
@@ -70,15 +66,17 @@ QNum *qnum_from_double(double value)
*/
bool qnum_get_try_int(const QNum *qn, int64_t *val)
{
- switch (qn->kind) {
+ const QNumValue *qv = &qn->value;
+
+ switch (qv->kind) {
case QNUM_I64:
- *val = qn->u.i64;
+ *val = qv->u.i64;
return true;
case QNUM_U64:
- if (qn->u.u64 > INT64_MAX) {
+ if (qv->u.u64 > INT64_MAX) {
return false;
}
- *val = qn->u.u64;
+ *val = qv->u.u64;
return true;
case QNUM_DOUBLE:
return false;
@@ -108,15 +106,17 @@ int64_t qnum_get_int(const QNum *qn)
*/
bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
{
- switch (qn->kind) {
+ const QNumValue *qv = &qn->value;
+
+ switch (qv->kind) {
case QNUM_I64:
- if (qn->u.i64 < 0) {
+ if (qv->u.i64 < 0) {
return false;
}
- *val = qn->u.i64;
+ *val = qv->u.i64;
return true;
case QNUM_U64:
- *val = qn->u.u64;
+ *val = qv->u.u64;
return true;
case QNUM_DOUBLE:
return false;
@@ -146,13 +146,15 @@ uint64_t qnum_get_uint(const QNum *qn)
*/
double qnum_get_double(const QNum *qn)
{
- switch (qn->kind) {
+ const QNumValue *qv = &qn->value;
+
+ switch (qv->kind) {
case QNUM_I64:
- return qn->u.i64;
+ return qv->u.i64;
case QNUM_U64:
- return qn->u.u64;
+ return qv->u.u64;
case QNUM_DOUBLE:
- return qn->u.dbl;
+ return qv->u.dbl;
}
assert(0);
@@ -161,14 +163,15 @@ double qnum_get_double(const QNum *qn)
char *qnum_to_string(QNum *qn)
{
+ const QNumValue *qv = &qn->value;
char *buffer;
int len;
- switch (qn->kind) {
+ switch (qv->kind) {
case QNUM_I64:
- return g_strdup_printf("%" PRId64, qn->u.i64);
+ return g_strdup_printf("%" PRId64, qv->u.i64);
case QNUM_U64:
- return g_strdup_printf("%" PRIu64, qn->u.u64);
+ return g_strdup_printf("%" PRIu64, qv->u.u64);
case QNUM_DOUBLE:
/* FIXME: snprintf() is locale dependent; but JSON requires
* numbers to be formatted as if in the C locale. Dependence
@@ -179,7 +182,7 @@ char *qnum_to_string(QNum *qn)
* 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);
+ buffer = g_strdup_printf("%f" , qv->u.dbl);
len = strlen(buffer);
while (len > 0 && buffer[len - 1] == '0') {
len--;
@@ -211,40 +214,42 @@ bool qnum_is_equal(const QObject *x, const QObject *y)
{
const QNum *num_x = qobject_to(QNum, x);
const QNum *num_y = qobject_to(QNum, y);
+ const QNumValue *val_x = &num_x->value;
+ const QNumValue *val_y = &num_y->value;
- switch (num_x->kind) {
+ switch (val_x->kind) {
case QNUM_I64:
- switch (num_y->kind) {
+ switch (val_y->kind) {
case QNUM_I64:
/* Comparison in native int64_t type */
- return num_x->u.i64 == num_y->u.i64;
+ return val_x->u.i64 == val_y->u.i64;
case QNUM_U64:
/* Implicit conversion of x to uin64_t, so we have to
* check its sign before */
- return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
+ return val_x->u.i64 >= 0 && val_x->u.i64 == val_y->u.u64;
case QNUM_DOUBLE:
return false;
}
abort();
case QNUM_U64:
- switch (num_y->kind) {
+ switch (val_y->kind) {
case QNUM_I64:
return qnum_is_equal(y, x);
case QNUM_U64:
/* Comparison in native uint64_t type */
- return num_x->u.u64 == num_y->u.u64;
+ return val_x->u.u64 == val_y->u.u64;
case QNUM_DOUBLE:
return false;
}
abort();
case QNUM_DOUBLE:
- switch (num_y->kind) {
+ switch (val_y->kind) {
case QNUM_I64:
case QNUM_U64:
return false;
case QNUM_DOUBLE:
/* Comparison in native double type */
- return num_x->u.dbl == num_y->u.dbl;
+ return val_x->u.dbl == val_y->u.dbl;
}
abort();
}
@@ -30,8 +30,8 @@ static void qnum_from_int_test(void)
qn = qnum_from_int(value);
g_assert(qn != NULL);
- g_assert_cmpint(qn->kind, ==, QNUM_I64);
- g_assert_cmpint(qn->u.i64, ==, value);
+ g_assert_cmpint(qn->value.kind, ==, QNUM_I64);
+ g_assert_cmpint(qn->value.u.i64, ==, value);
g_assert_cmpint(qn->base.refcnt, ==, 1);
g_assert_cmpint(qobject_type(QOBJECT(qn)), ==, QTYPE_QNUM);
@@ -45,8 +45,8 @@ static void qnum_from_uint_test(void)
qn = qnum_from_uint(value);
g_assert(qn != NULL);
- g_assert_cmpint(qn->kind, ==, QNUM_U64);
- g_assert(qn->u.u64 == value);
+ g_assert_cmpint(qn->value.kind, ==, QNUM_U64);
+ g_assert(qn->value.u.u64 == value);
g_assert(qn->base.refcnt == 1);
g_assert(qobject_type(QOBJECT(qn)) == QTYPE_QNUM);
@@ -60,8 +60,8 @@ static void qnum_from_double_test(void)
qn = qnum_from_double(value);
g_assert(qn != NULL);
- g_assert_cmpint(qn->kind, ==, QNUM_DOUBLE);
- g_assert_cmpfloat(qn->u.dbl, ==, value);
+ g_assert_cmpint(qn->value.kind, ==, QNUM_DOUBLE);
+ g_assert_cmpfloat(qn->value.u.dbl, ==, value);
g_assert_cmpint(qn->base.refcnt, ==, 1);
g_assert_cmpint(qobject_type(QOBJECT(qn)), ==, QTYPE_QNUM);
@@ -74,7 +74,7 @@ static void qnum_from_int64_test(void)
const int64_t value = 0x1234567890abcdefLL;
qn = qnum_from_int(value);
- g_assert_cmpint((int64_t) qn->u.i64, ==, value);
+ g_assert_cmpint((int64_t) qn->value.u.i64, ==, value);
qobject_unref(qn);
}
Provide a separate QNumValue type that can be used for QNum value literals without the referencing counting and memory allocation features provided by QObject. Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- Changes v2 -> v3: * Fixed copy-pasta at qnum_from_value() documentation * Removed qnum_get_value() function * Moved doc comment of qnum_from_value() to .c file, for consistency with other functions. * Removed "private:" doc comment at QNumValue. * Removed unnecessary kernel-doc noise (obvious parameter descriptions). * Removed space after type cast in qnum_from_*(). * qnum_is_equal() variable const-ness & renames: * Renamed new QNumValue variables to val_x/val_y. * Keep existing QNum num_x/num_y variable names. * const-ness change of num_x/num_y was moved to a separate patch. Changes v1 -> v2: * Fix "make check" failure, by updating check-qnum unit test to use the new struct fields --- include/qapi/qmp/qnum.h | 23 ++++++++++- qobject/qnum.c | 91 ++++++++++++++++++++++------------------- tests/check-qnum.c | 14 +++---- 3 files changed, 76 insertions(+), 52 deletions(-)