xref: /qemu/qobject/qnum.c (revision b38dd678a21582e03ecd2dec76ccf8290455628a)
101b2ffceSMarc-André Lureau /*
201b2ffceSMarc-André Lureau  * QNum Module
301b2ffceSMarc-André Lureau  *
401b2ffceSMarc-André Lureau  * Copyright (C) 2009 Red Hat Inc.
501b2ffceSMarc-André Lureau  *
601b2ffceSMarc-André Lureau  * Authors:
701b2ffceSMarc-André Lureau  *  Luiz Capitulino <lcapitulino@redhat.com>
801b2ffceSMarc-André Lureau  *  Anthony Liguori <aliguori@us.ibm.com>
901b2ffceSMarc-André Lureau  *  Marc-André Lureau <marcandre.lureau@redhat.com>
1001b2ffceSMarc-André Lureau  *
1101b2ffceSMarc-André Lureau  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
1201b2ffceSMarc-André Lureau  * See the COPYING.LIB file in the top-level directory.
1301b2ffceSMarc-André Lureau  */
1401b2ffceSMarc-André Lureau 
1501b2ffceSMarc-André Lureau #include "qemu/osdep.h"
1601b2ffceSMarc-André Lureau #include "qapi/error.h"
1701b2ffceSMarc-André Lureau #include "qapi/qmp/qnum.h"
1801b2ffceSMarc-André Lureau #include "qapi/qmp/qobject.h"
1901b2ffceSMarc-André Lureau #include "qemu-common.h"
2001b2ffceSMarc-André Lureau 
2101b2ffceSMarc-André Lureau /**
2201b2ffceSMarc-André Lureau  * qnum_from_int(): Create a new QNum from an int64_t
2301b2ffceSMarc-André Lureau  *
2401b2ffceSMarc-André Lureau  * Return strong reference.
2501b2ffceSMarc-André Lureau  */
2601b2ffceSMarc-André Lureau QNum *qnum_from_int(int64_t value)
2701b2ffceSMarc-André Lureau {
2801b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
2901b2ffceSMarc-André Lureau 
3001b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
3101b2ffceSMarc-André Lureau     qn->kind = QNUM_I64;
3201b2ffceSMarc-André Lureau     qn->u.i64 = value;
3301b2ffceSMarc-André Lureau 
3401b2ffceSMarc-André Lureau     return qn;
3501b2ffceSMarc-André Lureau }
3601b2ffceSMarc-André Lureau 
3701b2ffceSMarc-André Lureau /**
3861a8f418SMarc-André Lureau  * qnum_from_uint(): Create a new QNum from an uint64_t
3961a8f418SMarc-André Lureau  *
4061a8f418SMarc-André Lureau  * Return strong reference.
4161a8f418SMarc-André Lureau  */
4261a8f418SMarc-André Lureau QNum *qnum_from_uint(uint64_t value)
4361a8f418SMarc-André Lureau {
4461a8f418SMarc-André Lureau     QNum *qn = g_new(QNum, 1);
4561a8f418SMarc-André Lureau 
4661a8f418SMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
4761a8f418SMarc-André Lureau     qn->kind = QNUM_U64;
4861a8f418SMarc-André Lureau     qn->u.u64 = value;
4961a8f418SMarc-André Lureau 
5061a8f418SMarc-André Lureau     return qn;
5161a8f418SMarc-André Lureau }
5261a8f418SMarc-André Lureau 
5361a8f418SMarc-André Lureau /**
5401b2ffceSMarc-André Lureau  * qnum_from_double(): Create a new QNum from a double
5501b2ffceSMarc-André Lureau  *
5601b2ffceSMarc-André Lureau  * Return strong reference.
5701b2ffceSMarc-André Lureau  */
5801b2ffceSMarc-André Lureau QNum *qnum_from_double(double value)
5901b2ffceSMarc-André Lureau {
6001b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
6101b2ffceSMarc-André Lureau 
6201b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
6301b2ffceSMarc-André Lureau     qn->kind = QNUM_DOUBLE;
6401b2ffceSMarc-André Lureau     qn->u.dbl = value;
6501b2ffceSMarc-André Lureau 
6601b2ffceSMarc-André Lureau     return qn;
6701b2ffceSMarc-André Lureau }
6801b2ffceSMarc-André Lureau 
6901b2ffceSMarc-André Lureau /**
7001b2ffceSMarc-André Lureau  * qnum_get_try_int(): Get an integer representation of the number
7101b2ffceSMarc-André Lureau  *
7201b2ffceSMarc-André Lureau  * Return true on success.
7301b2ffceSMarc-André Lureau  */
7401b2ffceSMarc-André Lureau bool qnum_get_try_int(const QNum *qn, int64_t *val)
7501b2ffceSMarc-André Lureau {
7601b2ffceSMarc-André Lureau     switch (qn->kind) {
7701b2ffceSMarc-André Lureau     case QNUM_I64:
7801b2ffceSMarc-André Lureau         *val = qn->u.i64;
7901b2ffceSMarc-André Lureau         return true;
8061a8f418SMarc-André Lureau     case QNUM_U64:
8161a8f418SMarc-André Lureau         if (qn->u.u64 > INT64_MAX) {
8261a8f418SMarc-André Lureau             return false;
8361a8f418SMarc-André Lureau         }
8461a8f418SMarc-André Lureau         *val = qn->u.u64;
8561a8f418SMarc-André Lureau         return true;
8601b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
8701b2ffceSMarc-André Lureau         return false;
8801b2ffceSMarc-André Lureau     }
8901b2ffceSMarc-André Lureau 
9001b2ffceSMarc-André Lureau     assert(0);
9101b2ffceSMarc-André Lureau     return false;
9201b2ffceSMarc-André Lureau }
9301b2ffceSMarc-André Lureau 
9401b2ffceSMarc-André Lureau /**
9501b2ffceSMarc-André Lureau  * qnum_get_int(): Get an integer representation of the number
9601b2ffceSMarc-André Lureau  *
9701b2ffceSMarc-André Lureau  * assert() on failure.
9801b2ffceSMarc-André Lureau  */
9901b2ffceSMarc-André Lureau int64_t qnum_get_int(const QNum *qn)
10001b2ffceSMarc-André Lureau {
10101b2ffceSMarc-André Lureau     int64_t val;
10201b2ffceSMarc-André Lureau     bool success = qnum_get_try_int(qn, &val);
10301b2ffceSMarc-André Lureau     assert(success);
10401b2ffceSMarc-André Lureau     return val;
10501b2ffceSMarc-André Lureau }
10601b2ffceSMarc-André Lureau 
10701b2ffceSMarc-André Lureau /**
10861a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
10961a8f418SMarc-André Lureau  *
11061a8f418SMarc-André Lureau  * Return true on success.
11161a8f418SMarc-André Lureau  */
11261a8f418SMarc-André Lureau bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
11361a8f418SMarc-André Lureau {
11461a8f418SMarc-André Lureau     switch (qn->kind) {
11561a8f418SMarc-André Lureau     case QNUM_I64:
11661a8f418SMarc-André Lureau         if (qn->u.i64 < 0) {
11761a8f418SMarc-André Lureau             return false;
11861a8f418SMarc-André Lureau         }
11961a8f418SMarc-André Lureau         *val = qn->u.i64;
12061a8f418SMarc-André Lureau         return true;
12161a8f418SMarc-André Lureau     case QNUM_U64:
12261a8f418SMarc-André Lureau         *val = qn->u.u64;
12361a8f418SMarc-André Lureau         return true;
12461a8f418SMarc-André Lureau     case QNUM_DOUBLE:
12561a8f418SMarc-André Lureau         return false;
12661a8f418SMarc-André Lureau     }
12761a8f418SMarc-André Lureau 
12861a8f418SMarc-André Lureau     assert(0);
12961a8f418SMarc-André Lureau     return false;
13061a8f418SMarc-André Lureau }
13161a8f418SMarc-André Lureau 
13261a8f418SMarc-André Lureau /**
13361a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
13461a8f418SMarc-André Lureau  *
13561a8f418SMarc-André Lureau  * assert() on failure.
13661a8f418SMarc-André Lureau  */
13761a8f418SMarc-André Lureau uint64_t qnum_get_uint(const QNum *qn)
13861a8f418SMarc-André Lureau {
13961a8f418SMarc-André Lureau     uint64_t val;
14061a8f418SMarc-André Lureau     bool success = qnum_get_try_uint(qn, &val);
14161a8f418SMarc-André Lureau     assert(success);
14261a8f418SMarc-André Lureau     return val;
14361a8f418SMarc-André Lureau }
14461a8f418SMarc-André Lureau 
14561a8f418SMarc-André Lureau /**
14601b2ffceSMarc-André Lureau  * qnum_get_double(): Get a float representation of the number
14701b2ffceSMarc-André Lureau  *
14801b2ffceSMarc-André Lureau  * qnum_get_double() loses precision for integers beyond 53 bits.
14901b2ffceSMarc-André Lureau  */
15001b2ffceSMarc-André Lureau double qnum_get_double(QNum *qn)
15101b2ffceSMarc-André Lureau {
15201b2ffceSMarc-André Lureau     switch (qn->kind) {
15301b2ffceSMarc-André Lureau     case QNUM_I64:
15401b2ffceSMarc-André Lureau         return qn->u.i64;
15561a8f418SMarc-André Lureau     case QNUM_U64:
15661a8f418SMarc-André Lureau         return qn->u.u64;
15701b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
15801b2ffceSMarc-André Lureau         return qn->u.dbl;
15901b2ffceSMarc-André Lureau     }
16001b2ffceSMarc-André Lureau 
16101b2ffceSMarc-André Lureau     assert(0);
16201b2ffceSMarc-André Lureau     return 0.0;
16301b2ffceSMarc-André Lureau }
16401b2ffceSMarc-André Lureau 
16501b2ffceSMarc-André Lureau char *qnum_to_string(QNum *qn)
16601b2ffceSMarc-André Lureau {
16701b2ffceSMarc-André Lureau     char *buffer;
16801b2ffceSMarc-André Lureau     int len;
16901b2ffceSMarc-André Lureau 
17001b2ffceSMarc-André Lureau     switch (qn->kind) {
17101b2ffceSMarc-André Lureau     case QNUM_I64:
17201b2ffceSMarc-André Lureau         return g_strdup_printf("%" PRId64, qn->u.i64);
17361a8f418SMarc-André Lureau     case QNUM_U64:
17461a8f418SMarc-André Lureau         return g_strdup_printf("%" PRIu64, qn->u.u64);
17501b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
17601b2ffceSMarc-André Lureau         /* FIXME: snprintf() is locale dependent; but JSON requires
17701b2ffceSMarc-André Lureau          * numbers to be formatted as if in the C locale. Dependence
17801b2ffceSMarc-André Lureau          * on C locale is a pervasive issue in QEMU. */
17901b2ffceSMarc-André Lureau         /* FIXME: This risks printing Inf or NaN, which are not valid
18001b2ffceSMarc-André Lureau          * JSON values. */
18101b2ffceSMarc-André Lureau         /* FIXME: the default precision of 6 for %f often causes
18201b2ffceSMarc-André Lureau          * rounding errors; we should be using DBL_DECIMAL_DIG (17),
18301b2ffceSMarc-André Lureau          * and only rounding to a shorter number if the result would
18401b2ffceSMarc-André Lureau          * still produce the same floating point value.  */
18501b2ffceSMarc-André Lureau         buffer = g_strdup_printf("%f" , qn->u.dbl);
18601b2ffceSMarc-André Lureau         len = strlen(buffer);
18701b2ffceSMarc-André Lureau         while (len > 0 && buffer[len - 1] == '0') {
18801b2ffceSMarc-André Lureau             len--;
18901b2ffceSMarc-André Lureau         }
19001b2ffceSMarc-André Lureau 
19101b2ffceSMarc-André Lureau         if (len && buffer[len - 1] == '.') {
19201b2ffceSMarc-André Lureau             buffer[len - 1] = 0;
19301b2ffceSMarc-André Lureau         } else {
19401b2ffceSMarc-André Lureau             buffer[len] = 0;
19501b2ffceSMarc-André Lureau         }
19601b2ffceSMarc-André Lureau 
19701b2ffceSMarc-André Lureau         return buffer;
19801b2ffceSMarc-André Lureau     }
19901b2ffceSMarc-André Lureau 
20001b2ffceSMarc-André Lureau     assert(0);
20101b2ffceSMarc-André Lureau     return NULL;
20201b2ffceSMarc-André Lureau }
20301b2ffceSMarc-André Lureau 
20401b2ffceSMarc-André Lureau /**
20501b2ffceSMarc-André Lureau  * qobject_to_qnum(): Convert a QObject into a QNum
20601b2ffceSMarc-André Lureau  */
20701b2ffceSMarc-André Lureau QNum *qobject_to_qnum(const QObject *obj)
20801b2ffceSMarc-André Lureau {
20901b2ffceSMarc-André Lureau     if (!obj || qobject_type(obj) != QTYPE_QNUM) {
21001b2ffceSMarc-André Lureau         return NULL;
21101b2ffceSMarc-André Lureau     }
21201b2ffceSMarc-André Lureau     return container_of(obj, QNum, base);
21301b2ffceSMarc-André Lureau }
21401b2ffceSMarc-André Lureau 
21501b2ffceSMarc-André Lureau /**
216*b38dd678SMax Reitz  * qnum_is_equal(): Test whether the two QNums are equal
217*b38dd678SMax Reitz  *
218*b38dd678SMax Reitz  * Negative integers are never considered equal to unsigned integers,
219*b38dd678SMax Reitz  * but positive integers in the range [0, INT64_MAX] are considered
220*b38dd678SMax Reitz  * equal independently of whether the QNum's kind is i64 or u64.
221*b38dd678SMax Reitz  *
222*b38dd678SMax Reitz  * Doubles are never considered equal to integers.
223*b38dd678SMax Reitz  */
224*b38dd678SMax Reitz bool qnum_is_equal(const QObject *x, const QObject *y)
225*b38dd678SMax Reitz {
226*b38dd678SMax Reitz     QNum *num_x = qobject_to_qnum(x);
227*b38dd678SMax Reitz     QNum *num_y = qobject_to_qnum(y);
228*b38dd678SMax Reitz 
229*b38dd678SMax Reitz     switch (num_x->kind) {
230*b38dd678SMax Reitz     case QNUM_I64:
231*b38dd678SMax Reitz         switch (num_y->kind) {
232*b38dd678SMax Reitz         case QNUM_I64:
233*b38dd678SMax Reitz             /* Comparison in native int64_t type */
234*b38dd678SMax Reitz             return num_x->u.i64 == num_y->u.i64;
235*b38dd678SMax Reitz         case QNUM_U64:
236*b38dd678SMax Reitz             /* Implicit conversion of x to uin64_t, so we have to
237*b38dd678SMax Reitz              * check its sign before */
238*b38dd678SMax Reitz             return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
239*b38dd678SMax Reitz         case QNUM_DOUBLE:
240*b38dd678SMax Reitz             return false;
241*b38dd678SMax Reitz         }
242*b38dd678SMax Reitz         abort();
243*b38dd678SMax Reitz     case QNUM_U64:
244*b38dd678SMax Reitz         switch (num_y->kind) {
245*b38dd678SMax Reitz         case QNUM_I64:
246*b38dd678SMax Reitz             return qnum_is_equal(y, x);
247*b38dd678SMax Reitz         case QNUM_U64:
248*b38dd678SMax Reitz             /* Comparison in native uint64_t type */
249*b38dd678SMax Reitz             return num_x->u.u64 == num_y->u.u64;
250*b38dd678SMax Reitz         case QNUM_DOUBLE:
251*b38dd678SMax Reitz             return false;
252*b38dd678SMax Reitz         }
253*b38dd678SMax Reitz         abort();
254*b38dd678SMax Reitz     case QNUM_DOUBLE:
255*b38dd678SMax Reitz         switch (num_y->kind) {
256*b38dd678SMax Reitz         case QNUM_I64:
257*b38dd678SMax Reitz         case QNUM_U64:
258*b38dd678SMax Reitz             return false;
259*b38dd678SMax Reitz         case QNUM_DOUBLE:
260*b38dd678SMax Reitz             /* Comparison in native double type */
261*b38dd678SMax Reitz             return num_x->u.dbl == num_y->u.dbl;
262*b38dd678SMax Reitz         }
263*b38dd678SMax Reitz         abort();
264*b38dd678SMax Reitz     }
265*b38dd678SMax Reitz 
266*b38dd678SMax Reitz     abort();
267*b38dd678SMax Reitz }
268*b38dd678SMax Reitz 
269*b38dd678SMax Reitz /**
27001b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
27101b2ffceSMarc-André Lureau  * QNum object
27201b2ffceSMarc-André Lureau  */
27301b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
27401b2ffceSMarc-André Lureau {
27501b2ffceSMarc-André Lureau     assert(obj != NULL);
27601b2ffceSMarc-André Lureau     g_free(qobject_to_qnum(obj));
27701b2ffceSMarc-André Lureau }
278