xref: /qemu/qobject/qnum.c (revision 61a8f418b26a2d974e38e4ae55020aca8d402d88)
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 /**
38*61a8f418SMarc-André Lureau  * qnum_from_uint(): Create a new QNum from an uint64_t
39*61a8f418SMarc-André Lureau  *
40*61a8f418SMarc-André Lureau  * Return strong reference.
41*61a8f418SMarc-André Lureau  */
42*61a8f418SMarc-André Lureau QNum *qnum_from_uint(uint64_t value)
43*61a8f418SMarc-André Lureau {
44*61a8f418SMarc-André Lureau     QNum *qn = g_new(QNum, 1);
45*61a8f418SMarc-André Lureau 
46*61a8f418SMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
47*61a8f418SMarc-André Lureau     qn->kind = QNUM_U64;
48*61a8f418SMarc-André Lureau     qn->u.u64 = value;
49*61a8f418SMarc-André Lureau 
50*61a8f418SMarc-André Lureau     return qn;
51*61a8f418SMarc-André Lureau }
52*61a8f418SMarc-André Lureau 
53*61a8f418SMarc-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;
80*61a8f418SMarc-André Lureau     case QNUM_U64:
81*61a8f418SMarc-André Lureau         if (qn->u.u64 > INT64_MAX) {
82*61a8f418SMarc-André Lureau             return false;
83*61a8f418SMarc-André Lureau         }
84*61a8f418SMarc-André Lureau         *val = qn->u.u64;
85*61a8f418SMarc-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 /**
108*61a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
109*61a8f418SMarc-André Lureau  *
110*61a8f418SMarc-André Lureau  * Return true on success.
111*61a8f418SMarc-André Lureau  */
112*61a8f418SMarc-André Lureau bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
113*61a8f418SMarc-André Lureau {
114*61a8f418SMarc-André Lureau     switch (qn->kind) {
115*61a8f418SMarc-André Lureau     case QNUM_I64:
116*61a8f418SMarc-André Lureau         if (qn->u.i64 < 0) {
117*61a8f418SMarc-André Lureau             return false;
118*61a8f418SMarc-André Lureau         }
119*61a8f418SMarc-André Lureau         *val = qn->u.i64;
120*61a8f418SMarc-André Lureau         return true;
121*61a8f418SMarc-André Lureau     case QNUM_U64:
122*61a8f418SMarc-André Lureau         *val = qn->u.u64;
123*61a8f418SMarc-André Lureau         return true;
124*61a8f418SMarc-André Lureau     case QNUM_DOUBLE:
125*61a8f418SMarc-André Lureau         return false;
126*61a8f418SMarc-André Lureau     }
127*61a8f418SMarc-André Lureau 
128*61a8f418SMarc-André Lureau     assert(0);
129*61a8f418SMarc-André Lureau     return false;
130*61a8f418SMarc-André Lureau }
131*61a8f418SMarc-André Lureau 
132*61a8f418SMarc-André Lureau /**
133*61a8f418SMarc-André Lureau  * qnum_get_uint(): Get an unsigned integer from the number
134*61a8f418SMarc-André Lureau  *
135*61a8f418SMarc-André Lureau  * assert() on failure.
136*61a8f418SMarc-André Lureau  */
137*61a8f418SMarc-André Lureau uint64_t qnum_get_uint(const QNum *qn)
138*61a8f418SMarc-André Lureau {
139*61a8f418SMarc-André Lureau     uint64_t val;
140*61a8f418SMarc-André Lureau     bool success = qnum_get_try_uint(qn, &val);
141*61a8f418SMarc-André Lureau     assert(success);
142*61a8f418SMarc-André Lureau     return val;
143*61a8f418SMarc-André Lureau }
144*61a8f418SMarc-André Lureau 
145*61a8f418SMarc-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;
155*61a8f418SMarc-André Lureau     case QNUM_U64:
156*61a8f418SMarc-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);
173*61a8f418SMarc-André Lureau     case QNUM_U64:
174*61a8f418SMarc-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 /**
21601b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
21701b2ffceSMarc-André Lureau  * QNum object
21801b2ffceSMarc-André Lureau  */
21901b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
22001b2ffceSMarc-André Lureau {
22101b2ffceSMarc-André Lureau     assert(obj != NULL);
22201b2ffceSMarc-André Lureau     g_free(qobject_to_qnum(obj));
22301b2ffceSMarc-André Lureau }
224