xref: /qemu/qobject/qnum.c (revision 80d71121b719c610c7f6e05c932c35ded4cc92d4)
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"
17*80d71121SMarkus Armbruster #include "qobject-internal.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     switch (qn->kind) {
16601b2ffceSMarc-André Lureau     case QNUM_I64:
16701b2ffceSMarc-André Lureau         return g_strdup_printf("%" PRId64, qn->u.i64);
16861a8f418SMarc-André Lureau     case QNUM_U64:
16961a8f418SMarc-André Lureau         return g_strdup_printf("%" PRIu64, qn->u.u64);
17001b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
171f917eed3SMarkus Armbruster         /* FIXME: g_strdup_printf() is locale dependent; but JSON requires
17201b2ffceSMarc-André Lureau          * numbers to be formatted as if in the C locale. Dependence
17301b2ffceSMarc-André Lureau          * on C locale is a pervasive issue in QEMU. */
17401b2ffceSMarc-André Lureau         /* FIXME: This risks printing Inf or NaN, which are not valid
17501b2ffceSMarc-André Lureau          * JSON values. */
176f917eed3SMarkus Armbruster         /* 17 digits suffice for IEEE double */
177f917eed3SMarkus Armbruster         return g_strdup_printf("%.17g", qn->u.dbl);
17801b2ffceSMarc-André Lureau     }
17901b2ffceSMarc-André Lureau 
18001b2ffceSMarc-André Lureau     assert(0);
18101b2ffceSMarc-André Lureau     return NULL;
18201b2ffceSMarc-André Lureau }
18301b2ffceSMarc-André Lureau 
18401b2ffceSMarc-André Lureau /**
185b38dd678SMax Reitz  * qnum_is_equal(): Test whether the two QNums are equal
186b38dd678SMax Reitz  *
187b38dd678SMax Reitz  * Negative integers are never considered equal to unsigned integers,
188b38dd678SMax Reitz  * but positive integers in the range [0, INT64_MAX] are considered
189b38dd678SMax Reitz  * equal independently of whether the QNum's kind is i64 or u64.
190b38dd678SMax Reitz  *
191b38dd678SMax Reitz  * Doubles are never considered equal to integers.
192b38dd678SMax Reitz  */
193b38dd678SMax Reitz bool qnum_is_equal(const QObject *x, const QObject *y)
194b38dd678SMax Reitz {
1957dc847ebSMax Reitz     QNum *num_x = qobject_to(QNum, x);
1967dc847ebSMax Reitz     QNum *num_y = qobject_to(QNum, y);
197b38dd678SMax Reitz 
198b38dd678SMax Reitz     switch (num_x->kind) {
199b38dd678SMax Reitz     case QNUM_I64:
200b38dd678SMax Reitz         switch (num_y->kind) {
201b38dd678SMax Reitz         case QNUM_I64:
202b38dd678SMax Reitz             /* Comparison in native int64_t type */
203b38dd678SMax Reitz             return num_x->u.i64 == num_y->u.i64;
204b38dd678SMax Reitz         case QNUM_U64:
205b38dd678SMax Reitz             /* Implicit conversion of x to uin64_t, so we have to
206b38dd678SMax Reitz              * check its sign before */
207b38dd678SMax Reitz             return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
208b38dd678SMax Reitz         case QNUM_DOUBLE:
209b38dd678SMax Reitz             return false;
210b38dd678SMax Reitz         }
211b38dd678SMax Reitz         abort();
212b38dd678SMax Reitz     case QNUM_U64:
213b38dd678SMax Reitz         switch (num_y->kind) {
214b38dd678SMax Reitz         case QNUM_I64:
215b38dd678SMax Reitz             return qnum_is_equal(y, x);
216b38dd678SMax Reitz         case QNUM_U64:
217b38dd678SMax Reitz             /* Comparison in native uint64_t type */
218b38dd678SMax Reitz             return num_x->u.u64 == num_y->u.u64;
219b38dd678SMax Reitz         case QNUM_DOUBLE:
220b38dd678SMax Reitz             return false;
221b38dd678SMax Reitz         }
222b38dd678SMax Reitz         abort();
223b38dd678SMax Reitz     case QNUM_DOUBLE:
224b38dd678SMax Reitz         switch (num_y->kind) {
225b38dd678SMax Reitz         case QNUM_I64:
226b38dd678SMax Reitz         case QNUM_U64:
227b38dd678SMax Reitz             return false;
228b38dd678SMax Reitz         case QNUM_DOUBLE:
229b38dd678SMax Reitz             /* Comparison in native double type */
230b38dd678SMax Reitz             return num_x->u.dbl == num_y->u.dbl;
231b38dd678SMax Reitz         }
232b38dd678SMax Reitz         abort();
233b38dd678SMax Reitz     }
234b38dd678SMax Reitz 
235b38dd678SMax Reitz     abort();
236b38dd678SMax Reitz }
237b38dd678SMax Reitz 
238b38dd678SMax Reitz /**
23901b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
24001b2ffceSMarc-André Lureau  * QNum object
24101b2ffceSMarc-André Lureau  */
24201b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
24301b2ffceSMarc-André Lureau {
24401b2ffceSMarc-André Lureau     assert(obj != NULL);
2457dc847ebSMax Reitz     g_free(qobject_to(QNum, obj));
24601b2ffceSMarc-André Lureau }
247