xref: /qemu/qobject/qnum.c (revision 7dc847ebba953db90853d15f140c20eef74d4fb2)
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/qmp/qnum.h"
1701b2ffceSMarc-André Lureau #include "qemu-common.h"
1801b2ffceSMarc-André Lureau 
1901b2ffceSMarc-André Lureau /**
2001b2ffceSMarc-André Lureau  * qnum_from_int(): Create a new QNum from an int64_t
2101b2ffceSMarc-André Lureau  *
2201b2ffceSMarc-André Lureau  * Return strong reference.
2301b2ffceSMarc-André Lureau  */
2401b2ffceSMarc-André Lureau QNum *qnum_from_int(int64_t value)
2501b2ffceSMarc-André Lureau {
2601b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
2701b2ffceSMarc-André Lureau 
2801b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
2901b2ffceSMarc-André Lureau     qn->kind = QNUM_I64;
3001b2ffceSMarc-André Lureau     qn->u.i64 = value;
3101b2ffceSMarc-André Lureau 
3201b2ffceSMarc-André Lureau     return qn;
3301b2ffceSMarc-André Lureau }
3401b2ffceSMarc-André Lureau 
3501b2ffceSMarc-André Lureau /**
3661a8f418SMarc-André Lureau  * qnum_from_uint(): Create a new QNum from an uint64_t
3761a8f418SMarc-André Lureau  *
3861a8f418SMarc-André Lureau  * Return strong reference.
3961a8f418SMarc-André Lureau  */
4061a8f418SMarc-André Lureau QNum *qnum_from_uint(uint64_t value)
4161a8f418SMarc-André Lureau {
4261a8f418SMarc-André Lureau     QNum *qn = g_new(QNum, 1);
4361a8f418SMarc-André Lureau 
4461a8f418SMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
4561a8f418SMarc-André Lureau     qn->kind = QNUM_U64;
4661a8f418SMarc-André Lureau     qn->u.u64 = value;
4761a8f418SMarc-André Lureau 
4861a8f418SMarc-André Lureau     return qn;
4961a8f418SMarc-André Lureau }
5061a8f418SMarc-André Lureau 
5161a8f418SMarc-André Lureau /**
5201b2ffceSMarc-André Lureau  * qnum_from_double(): Create a new QNum from a double
5301b2ffceSMarc-André Lureau  *
5401b2ffceSMarc-André Lureau  * Return strong reference.
5501b2ffceSMarc-André Lureau  */
5601b2ffceSMarc-André Lureau QNum *qnum_from_double(double value)
5701b2ffceSMarc-André Lureau {
5801b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
5901b2ffceSMarc-André Lureau 
6001b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
6101b2ffceSMarc-André Lureau     qn->kind = QNUM_DOUBLE;
6201b2ffceSMarc-André Lureau     qn->u.dbl = value;
6301b2ffceSMarc-André Lureau 
6401b2ffceSMarc-André Lureau     return qn;
6501b2ffceSMarc-André Lureau }
6601b2ffceSMarc-André Lureau 
6701b2ffceSMarc-André Lureau /**
6801b2ffceSMarc-André Lureau  * qnum_get_try_int(): Get an integer representation of the number
6901b2ffceSMarc-André Lureau  *
7001b2ffceSMarc-André Lureau  * Return true on success.
7101b2ffceSMarc-André Lureau  */
7201b2ffceSMarc-André Lureau bool qnum_get_try_int(const QNum *qn, int64_t *val)
7301b2ffceSMarc-André Lureau {
7401b2ffceSMarc-André Lureau     switch (qn->kind) {
7501b2ffceSMarc-André Lureau     case QNUM_I64:
7601b2ffceSMarc-André Lureau         *val = qn->u.i64;
7701b2ffceSMarc-André Lureau         return true;
7861a8f418SMarc-André Lureau     case QNUM_U64:
7961a8f418SMarc-André Lureau         if (qn->u.u64 > INT64_MAX) {
8061a8f418SMarc-André Lureau             return false;
8161a8f418SMarc-André Lureau         }
8261a8f418SMarc-André Lureau         *val = qn->u.u64;
8361a8f418SMarc-André Lureau         return true;
8401b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
8501b2ffceSMarc-André Lureau         return false;
8601b2ffceSMarc-André Lureau     }
8701b2ffceSMarc-André Lureau 
8801b2ffceSMarc-André Lureau     assert(0);
8901b2ffceSMarc-André Lureau     return false;
9001b2ffceSMarc-André Lureau }
9101b2ffceSMarc-André Lureau 
9201b2ffceSMarc-André Lureau /**
9301b2ffceSMarc-André Lureau  * qnum_get_int(): Get an integer representation of the number
9401b2ffceSMarc-André Lureau  *
9501b2ffceSMarc-André Lureau  * assert() on failure.
9601b2ffceSMarc-André Lureau  */
9701b2ffceSMarc-André Lureau int64_t qnum_get_int(const QNum *qn)
9801b2ffceSMarc-André Lureau {
9901b2ffceSMarc-André Lureau     int64_t val;
10001b2ffceSMarc-André Lureau     bool success = qnum_get_try_int(qn, &val);
10101b2ffceSMarc-André Lureau     assert(success);
10201b2ffceSMarc-André Lureau     return val;
10301b2ffceSMarc-André Lureau }
10401b2ffceSMarc-André Lureau 
10501b2ffceSMarc-André Lureau /**
10661a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
10761a8f418SMarc-André Lureau  *
10861a8f418SMarc-André Lureau  * Return true on success.
10961a8f418SMarc-André Lureau  */
11061a8f418SMarc-André Lureau bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
11161a8f418SMarc-André Lureau {
11261a8f418SMarc-André Lureau     switch (qn->kind) {
11361a8f418SMarc-André Lureau     case QNUM_I64:
11461a8f418SMarc-André Lureau         if (qn->u.i64 < 0) {
11561a8f418SMarc-André Lureau             return false;
11661a8f418SMarc-André Lureau         }
11761a8f418SMarc-André Lureau         *val = qn->u.i64;
11861a8f418SMarc-André Lureau         return true;
11961a8f418SMarc-André Lureau     case QNUM_U64:
12061a8f418SMarc-André Lureau         *val = qn->u.u64;
12161a8f418SMarc-André Lureau         return true;
12261a8f418SMarc-André Lureau     case QNUM_DOUBLE:
12361a8f418SMarc-André Lureau         return false;
12461a8f418SMarc-André Lureau     }
12561a8f418SMarc-André Lureau 
12661a8f418SMarc-André Lureau     assert(0);
12761a8f418SMarc-André Lureau     return false;
12861a8f418SMarc-André Lureau }
12961a8f418SMarc-André Lureau 
13061a8f418SMarc-André Lureau /**
13161a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
13261a8f418SMarc-André Lureau  *
13361a8f418SMarc-André Lureau  * assert() on failure.
13461a8f418SMarc-André Lureau  */
13561a8f418SMarc-André Lureau uint64_t qnum_get_uint(const QNum *qn)
13661a8f418SMarc-André Lureau {
13761a8f418SMarc-André Lureau     uint64_t val;
13861a8f418SMarc-André Lureau     bool success = qnum_get_try_uint(qn, &val);
13961a8f418SMarc-André Lureau     assert(success);
14061a8f418SMarc-André Lureau     return val;
14161a8f418SMarc-André Lureau }
14261a8f418SMarc-André Lureau 
14361a8f418SMarc-André Lureau /**
14401b2ffceSMarc-André Lureau  * qnum_get_double(): Get a float representation of the number
14501b2ffceSMarc-André Lureau  *
14601b2ffceSMarc-André Lureau  * qnum_get_double() loses precision for integers beyond 53 bits.
14701b2ffceSMarc-André Lureau  */
14801b2ffceSMarc-André Lureau double qnum_get_double(QNum *qn)
14901b2ffceSMarc-André Lureau {
15001b2ffceSMarc-André Lureau     switch (qn->kind) {
15101b2ffceSMarc-André Lureau     case QNUM_I64:
15201b2ffceSMarc-André Lureau         return qn->u.i64;
15361a8f418SMarc-André Lureau     case QNUM_U64:
15461a8f418SMarc-André Lureau         return qn->u.u64;
15501b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
15601b2ffceSMarc-André Lureau         return qn->u.dbl;
15701b2ffceSMarc-André Lureau     }
15801b2ffceSMarc-André Lureau 
15901b2ffceSMarc-André Lureau     assert(0);
16001b2ffceSMarc-André Lureau     return 0.0;
16101b2ffceSMarc-André Lureau }
16201b2ffceSMarc-André Lureau 
16301b2ffceSMarc-André Lureau char *qnum_to_string(QNum *qn)
16401b2ffceSMarc-André Lureau {
16501b2ffceSMarc-André Lureau     char *buffer;
16601b2ffceSMarc-André Lureau     int len;
16701b2ffceSMarc-André Lureau 
16801b2ffceSMarc-André Lureau     switch (qn->kind) {
16901b2ffceSMarc-André Lureau     case QNUM_I64:
17001b2ffceSMarc-André Lureau         return g_strdup_printf("%" PRId64, qn->u.i64);
17161a8f418SMarc-André Lureau     case QNUM_U64:
17261a8f418SMarc-André Lureau         return g_strdup_printf("%" PRIu64, qn->u.u64);
17301b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
17401b2ffceSMarc-André Lureau         /* FIXME: snprintf() is locale dependent; but JSON requires
17501b2ffceSMarc-André Lureau          * numbers to be formatted as if in the C locale. Dependence
17601b2ffceSMarc-André Lureau          * on C locale is a pervasive issue in QEMU. */
17701b2ffceSMarc-André Lureau         /* FIXME: This risks printing Inf or NaN, which are not valid
17801b2ffceSMarc-André Lureau          * JSON values. */
17901b2ffceSMarc-André Lureau         /* FIXME: the default precision of 6 for %f often causes
18001b2ffceSMarc-André Lureau          * rounding errors; we should be using DBL_DECIMAL_DIG (17),
18101b2ffceSMarc-André Lureau          * and only rounding to a shorter number if the result would
18201b2ffceSMarc-André Lureau          * still produce the same floating point value.  */
18301b2ffceSMarc-André Lureau         buffer = g_strdup_printf("%f" , qn->u.dbl);
18401b2ffceSMarc-André Lureau         len = strlen(buffer);
18501b2ffceSMarc-André Lureau         while (len > 0 && buffer[len - 1] == '0') {
18601b2ffceSMarc-André Lureau             len--;
18701b2ffceSMarc-André Lureau         }
18801b2ffceSMarc-André Lureau 
18901b2ffceSMarc-André Lureau         if (len && buffer[len - 1] == '.') {
19001b2ffceSMarc-André Lureau             buffer[len - 1] = 0;
19101b2ffceSMarc-André Lureau         } else {
19201b2ffceSMarc-André Lureau             buffer[len] = 0;
19301b2ffceSMarc-André Lureau         }
19401b2ffceSMarc-André Lureau 
19501b2ffceSMarc-André Lureau         return buffer;
19601b2ffceSMarc-André Lureau     }
19701b2ffceSMarc-André Lureau 
19801b2ffceSMarc-André Lureau     assert(0);
19901b2ffceSMarc-André Lureau     return NULL;
20001b2ffceSMarc-André Lureau }
20101b2ffceSMarc-André Lureau 
20201b2ffceSMarc-André Lureau /**
20301b2ffceSMarc-André Lureau  * qobject_to_qnum(): Convert a QObject into a QNum
20401b2ffceSMarc-André Lureau  */
20501b2ffceSMarc-André Lureau QNum *qobject_to_qnum(const QObject *obj)
20601b2ffceSMarc-André Lureau {
20701b2ffceSMarc-André Lureau     if (!obj || qobject_type(obj) != QTYPE_QNUM) {
20801b2ffceSMarc-André Lureau         return NULL;
20901b2ffceSMarc-André Lureau     }
21001b2ffceSMarc-André Lureau     return container_of(obj, QNum, base);
21101b2ffceSMarc-André Lureau }
21201b2ffceSMarc-André Lureau 
21301b2ffceSMarc-André Lureau /**
214b38dd678SMax Reitz  * qnum_is_equal(): Test whether the two QNums are equal
215b38dd678SMax Reitz  *
216b38dd678SMax Reitz  * Negative integers are never considered equal to unsigned integers,
217b38dd678SMax Reitz  * but positive integers in the range [0, INT64_MAX] are considered
218b38dd678SMax Reitz  * equal independently of whether the QNum's kind is i64 or u64.
219b38dd678SMax Reitz  *
220b38dd678SMax Reitz  * Doubles are never considered equal to integers.
221b38dd678SMax Reitz  */
222b38dd678SMax Reitz bool qnum_is_equal(const QObject *x, const QObject *y)
223b38dd678SMax Reitz {
224*7dc847ebSMax Reitz     QNum *num_x = qobject_to(QNum, x);
225*7dc847ebSMax Reitz     QNum *num_y = qobject_to(QNum, y);
226b38dd678SMax Reitz 
227b38dd678SMax Reitz     switch (num_x->kind) {
228b38dd678SMax Reitz     case QNUM_I64:
229b38dd678SMax Reitz         switch (num_y->kind) {
230b38dd678SMax Reitz         case QNUM_I64:
231b38dd678SMax Reitz             /* Comparison in native int64_t type */
232b38dd678SMax Reitz             return num_x->u.i64 == num_y->u.i64;
233b38dd678SMax Reitz         case QNUM_U64:
234b38dd678SMax Reitz             /* Implicit conversion of x to uin64_t, so we have to
235b38dd678SMax Reitz              * check its sign before */
236b38dd678SMax Reitz             return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
237b38dd678SMax Reitz         case QNUM_DOUBLE:
238b38dd678SMax Reitz             return false;
239b38dd678SMax Reitz         }
240b38dd678SMax Reitz         abort();
241b38dd678SMax Reitz     case QNUM_U64:
242b38dd678SMax Reitz         switch (num_y->kind) {
243b38dd678SMax Reitz         case QNUM_I64:
244b38dd678SMax Reitz             return qnum_is_equal(y, x);
245b38dd678SMax Reitz         case QNUM_U64:
246b38dd678SMax Reitz             /* Comparison in native uint64_t type */
247b38dd678SMax Reitz             return num_x->u.u64 == num_y->u.u64;
248b38dd678SMax Reitz         case QNUM_DOUBLE:
249b38dd678SMax Reitz             return false;
250b38dd678SMax Reitz         }
251b38dd678SMax Reitz         abort();
252b38dd678SMax Reitz     case QNUM_DOUBLE:
253b38dd678SMax Reitz         switch (num_y->kind) {
254b38dd678SMax Reitz         case QNUM_I64:
255b38dd678SMax Reitz         case QNUM_U64:
256b38dd678SMax Reitz             return false;
257b38dd678SMax Reitz         case QNUM_DOUBLE:
258b38dd678SMax Reitz             /* Comparison in native double type */
259b38dd678SMax Reitz             return num_x->u.dbl == num_y->u.dbl;
260b38dd678SMax Reitz         }
261b38dd678SMax Reitz         abort();
262b38dd678SMax Reitz     }
263b38dd678SMax Reitz 
264b38dd678SMax Reitz     abort();
265b38dd678SMax Reitz }
266b38dd678SMax Reitz 
267b38dd678SMax Reitz /**
26801b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
26901b2ffceSMarc-André Lureau  * QNum object
27001b2ffceSMarc-André Lureau  */
27101b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
27201b2ffceSMarc-André Lureau {
27301b2ffceSMarc-André Lureau     assert(obj != NULL);
274*7dc847ebSMax Reitz     g_free(qobject_to(QNum, obj));
27501b2ffceSMarc-André Lureau }
276