xref: /qemu/qobject/qnum.c (revision 01b2ffcedd94ad7b42bc870e4c6936c87ad03429)
1*01b2ffceSMarc-André Lureau /*
2*01b2ffceSMarc-André Lureau  * QNum Module
3*01b2ffceSMarc-André Lureau  *
4*01b2ffceSMarc-André Lureau  * Copyright (C) 2009 Red Hat Inc.
5*01b2ffceSMarc-André Lureau  *
6*01b2ffceSMarc-André Lureau  * Authors:
7*01b2ffceSMarc-André Lureau  *  Luiz Capitulino <lcapitulino@redhat.com>
8*01b2ffceSMarc-André Lureau  *  Anthony Liguori <aliguori@us.ibm.com>
9*01b2ffceSMarc-André Lureau  *  Marc-André Lureau <marcandre.lureau@redhat.com>
10*01b2ffceSMarc-André Lureau  *
11*01b2ffceSMarc-André Lureau  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
12*01b2ffceSMarc-André Lureau  * See the COPYING.LIB file in the top-level directory.
13*01b2ffceSMarc-André Lureau  */
14*01b2ffceSMarc-André Lureau 
15*01b2ffceSMarc-André Lureau #include "qemu/osdep.h"
16*01b2ffceSMarc-André Lureau #include "qapi/error.h"
17*01b2ffceSMarc-André Lureau #include "qapi/qmp/qnum.h"
18*01b2ffceSMarc-André Lureau #include "qapi/qmp/qobject.h"
19*01b2ffceSMarc-André Lureau #include "qemu-common.h"
20*01b2ffceSMarc-André Lureau 
21*01b2ffceSMarc-André Lureau /**
22*01b2ffceSMarc-André Lureau  * qnum_from_int(): Create a new QNum from an int64_t
23*01b2ffceSMarc-André Lureau  *
24*01b2ffceSMarc-André Lureau  * Return strong reference.
25*01b2ffceSMarc-André Lureau  */
26*01b2ffceSMarc-André Lureau QNum *qnum_from_int(int64_t value)
27*01b2ffceSMarc-André Lureau {
28*01b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
29*01b2ffceSMarc-André Lureau 
30*01b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
31*01b2ffceSMarc-André Lureau     qn->kind = QNUM_I64;
32*01b2ffceSMarc-André Lureau     qn->u.i64 = value;
33*01b2ffceSMarc-André Lureau 
34*01b2ffceSMarc-André Lureau     return qn;
35*01b2ffceSMarc-André Lureau }
36*01b2ffceSMarc-André Lureau 
37*01b2ffceSMarc-André Lureau /**
38*01b2ffceSMarc-André Lureau  * qnum_from_double(): Create a new QNum from a double
39*01b2ffceSMarc-André Lureau  *
40*01b2ffceSMarc-André Lureau  * Return strong reference.
41*01b2ffceSMarc-André Lureau  */
42*01b2ffceSMarc-André Lureau QNum *qnum_from_double(double value)
43*01b2ffceSMarc-André Lureau {
44*01b2ffceSMarc-André Lureau     QNum *qn = g_new(QNum, 1);
45*01b2ffceSMarc-André Lureau 
46*01b2ffceSMarc-André Lureau     qobject_init(QOBJECT(qn), QTYPE_QNUM);
47*01b2ffceSMarc-André Lureau     qn->kind = QNUM_DOUBLE;
48*01b2ffceSMarc-André Lureau     qn->u.dbl = value;
49*01b2ffceSMarc-André Lureau 
50*01b2ffceSMarc-André Lureau     return qn;
51*01b2ffceSMarc-André Lureau }
52*01b2ffceSMarc-André Lureau 
53*01b2ffceSMarc-André Lureau /**
54*01b2ffceSMarc-André Lureau  * qnum_get_try_int(): Get an integer representation of the number
55*01b2ffceSMarc-André Lureau  *
56*01b2ffceSMarc-André Lureau  * Return true on success.
57*01b2ffceSMarc-André Lureau  */
58*01b2ffceSMarc-André Lureau bool qnum_get_try_int(const QNum *qn, int64_t *val)
59*01b2ffceSMarc-André Lureau {
60*01b2ffceSMarc-André Lureau     switch (qn->kind) {
61*01b2ffceSMarc-André Lureau     case QNUM_I64:
62*01b2ffceSMarc-André Lureau         *val = qn->u.i64;
63*01b2ffceSMarc-André Lureau         return true;
64*01b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
65*01b2ffceSMarc-André Lureau         return false;
66*01b2ffceSMarc-André Lureau     }
67*01b2ffceSMarc-André Lureau 
68*01b2ffceSMarc-André Lureau     assert(0);
69*01b2ffceSMarc-André Lureau     return false;
70*01b2ffceSMarc-André Lureau }
71*01b2ffceSMarc-André Lureau 
72*01b2ffceSMarc-André Lureau /**
73*01b2ffceSMarc-André Lureau  * qnum_get_int(): Get an integer representation of the number
74*01b2ffceSMarc-André Lureau  *
75*01b2ffceSMarc-André Lureau  * assert() on failure.
76*01b2ffceSMarc-André Lureau  */
77*01b2ffceSMarc-André Lureau int64_t qnum_get_int(const QNum *qn)
78*01b2ffceSMarc-André Lureau {
79*01b2ffceSMarc-André Lureau     int64_t val;
80*01b2ffceSMarc-André Lureau     bool success = qnum_get_try_int(qn, &val);
81*01b2ffceSMarc-André Lureau     assert(success);
82*01b2ffceSMarc-André Lureau     return val;
83*01b2ffceSMarc-André Lureau }
84*01b2ffceSMarc-André Lureau 
85*01b2ffceSMarc-André Lureau /**
86*01b2ffceSMarc-André Lureau  * qnum_get_double(): Get a float representation of the number
87*01b2ffceSMarc-André Lureau  *
88*01b2ffceSMarc-André Lureau  * qnum_get_double() loses precision for integers beyond 53 bits.
89*01b2ffceSMarc-André Lureau  */
90*01b2ffceSMarc-André Lureau double qnum_get_double(QNum *qn)
91*01b2ffceSMarc-André Lureau {
92*01b2ffceSMarc-André Lureau     switch (qn->kind) {
93*01b2ffceSMarc-André Lureau     case QNUM_I64:
94*01b2ffceSMarc-André Lureau         return qn->u.i64;
95*01b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
96*01b2ffceSMarc-André Lureau         return qn->u.dbl;
97*01b2ffceSMarc-André Lureau     }
98*01b2ffceSMarc-André Lureau 
99*01b2ffceSMarc-André Lureau     assert(0);
100*01b2ffceSMarc-André Lureau     return 0.0;
101*01b2ffceSMarc-André Lureau }
102*01b2ffceSMarc-André Lureau 
103*01b2ffceSMarc-André Lureau char *qnum_to_string(QNum *qn)
104*01b2ffceSMarc-André Lureau {
105*01b2ffceSMarc-André Lureau     char *buffer;
106*01b2ffceSMarc-André Lureau     int len;
107*01b2ffceSMarc-André Lureau 
108*01b2ffceSMarc-André Lureau     switch (qn->kind) {
109*01b2ffceSMarc-André Lureau     case QNUM_I64:
110*01b2ffceSMarc-André Lureau         return g_strdup_printf("%" PRId64, qn->u.i64);
111*01b2ffceSMarc-André Lureau     case QNUM_DOUBLE:
112*01b2ffceSMarc-André Lureau         /* FIXME: snprintf() is locale dependent; but JSON requires
113*01b2ffceSMarc-André Lureau          * numbers to be formatted as if in the C locale. Dependence
114*01b2ffceSMarc-André Lureau          * on C locale is a pervasive issue in QEMU. */
115*01b2ffceSMarc-André Lureau         /* FIXME: This risks printing Inf or NaN, which are not valid
116*01b2ffceSMarc-André Lureau          * JSON values. */
117*01b2ffceSMarc-André Lureau         /* FIXME: the default precision of 6 for %f often causes
118*01b2ffceSMarc-André Lureau          * rounding errors; we should be using DBL_DECIMAL_DIG (17),
119*01b2ffceSMarc-André Lureau          * and only rounding to a shorter number if the result would
120*01b2ffceSMarc-André Lureau          * still produce the same floating point value.  */
121*01b2ffceSMarc-André Lureau         buffer = g_strdup_printf("%f" , qn->u.dbl);
122*01b2ffceSMarc-André Lureau         len = strlen(buffer);
123*01b2ffceSMarc-André Lureau         while (len > 0 && buffer[len - 1] == '0') {
124*01b2ffceSMarc-André Lureau             len--;
125*01b2ffceSMarc-André Lureau         }
126*01b2ffceSMarc-André Lureau 
127*01b2ffceSMarc-André Lureau         if (len && buffer[len - 1] == '.') {
128*01b2ffceSMarc-André Lureau             buffer[len - 1] = 0;
129*01b2ffceSMarc-André Lureau         } else {
130*01b2ffceSMarc-André Lureau             buffer[len] = 0;
131*01b2ffceSMarc-André Lureau         }
132*01b2ffceSMarc-André Lureau 
133*01b2ffceSMarc-André Lureau         return buffer;
134*01b2ffceSMarc-André Lureau     }
135*01b2ffceSMarc-André Lureau 
136*01b2ffceSMarc-André Lureau     assert(0);
137*01b2ffceSMarc-André Lureau     return NULL;
138*01b2ffceSMarc-André Lureau }
139*01b2ffceSMarc-André Lureau 
140*01b2ffceSMarc-André Lureau /**
141*01b2ffceSMarc-André Lureau  * qobject_to_qnum(): Convert a QObject into a QNum
142*01b2ffceSMarc-André Lureau  */
143*01b2ffceSMarc-André Lureau QNum *qobject_to_qnum(const QObject *obj)
144*01b2ffceSMarc-André Lureau {
145*01b2ffceSMarc-André Lureau     if (!obj || qobject_type(obj) != QTYPE_QNUM) {
146*01b2ffceSMarc-André Lureau         return NULL;
147*01b2ffceSMarc-André Lureau     }
148*01b2ffceSMarc-André Lureau     return container_of(obj, QNum, base);
149*01b2ffceSMarc-André Lureau }
150*01b2ffceSMarc-André Lureau 
151*01b2ffceSMarc-André Lureau /**
152*01b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
153*01b2ffceSMarc-André Lureau  * QNum object
154*01b2ffceSMarc-André Lureau  */
155*01b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
156*01b2ffceSMarc-André Lureau {
157*01b2ffceSMarc-André Lureau     assert(obj != NULL);
158*01b2ffceSMarc-André Lureau     g_free(qobject_to_qnum(obj));
159*01b2ffceSMarc-André Lureau }
160