xref: /qemu/qobject/qnum.c (revision 890000dd3bd13c7421a2895c7300f410940eb0f0)
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"
1780d71121SMarkus 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 
88*890000ddSPierrick Bouvier     g_assert_not_reached();
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 
126*890000ddSPierrick Bouvier     g_assert_not_reached();
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 
159*890000ddSPierrick Bouvier     g_assert_not_reached();
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         /* 17 digits suffice for IEEE double */
172f917eed3SMarkus Armbruster         return g_strdup_printf("%.17g", qn->u.dbl);
17301b2ffceSMarc-André Lureau     }
17401b2ffceSMarc-André Lureau 
175*890000ddSPierrick Bouvier     g_assert_not_reached();
17601b2ffceSMarc-André Lureau     return NULL;
17701b2ffceSMarc-André Lureau }
17801b2ffceSMarc-André Lureau 
17901b2ffceSMarc-André Lureau /**
180b38dd678SMax Reitz  * qnum_is_equal(): Test whether the two QNums are equal
181b38dd678SMax Reitz  *
182b38dd678SMax Reitz  * Negative integers are never considered equal to unsigned integers,
183b38dd678SMax Reitz  * but positive integers in the range [0, INT64_MAX] are considered
184b38dd678SMax Reitz  * equal independently of whether the QNum's kind is i64 or u64.
185b38dd678SMax Reitz  *
186b38dd678SMax Reitz  * Doubles are never considered equal to integers.
187b38dd678SMax Reitz  */
188b38dd678SMax Reitz bool qnum_is_equal(const QObject *x, const QObject *y)
189b38dd678SMax Reitz {
1907dc847ebSMax Reitz     QNum *num_x = qobject_to(QNum, x);
1917dc847ebSMax Reitz     QNum *num_y = qobject_to(QNum, y);
192b38dd678SMax Reitz 
193b38dd678SMax Reitz     switch (num_x->kind) {
194b38dd678SMax Reitz     case QNUM_I64:
195b38dd678SMax Reitz         switch (num_y->kind) {
196b38dd678SMax Reitz         case QNUM_I64:
197b38dd678SMax Reitz             /* Comparison in native int64_t type */
198b38dd678SMax Reitz             return num_x->u.i64 == num_y->u.i64;
199b38dd678SMax Reitz         case QNUM_U64:
200b38dd678SMax Reitz             /* Implicit conversion of x to uin64_t, so we have to
201b38dd678SMax Reitz              * check its sign before */
202b38dd678SMax Reitz             return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
203b38dd678SMax Reitz         case QNUM_DOUBLE:
204b38dd678SMax Reitz             return false;
205b38dd678SMax Reitz         }
206b38dd678SMax Reitz         abort();
207b38dd678SMax Reitz     case QNUM_U64:
208b38dd678SMax Reitz         switch (num_y->kind) {
209b38dd678SMax Reitz         case QNUM_I64:
210b38dd678SMax Reitz             return qnum_is_equal(y, x);
211b38dd678SMax Reitz         case QNUM_U64:
212b38dd678SMax Reitz             /* Comparison in native uint64_t type */
213b38dd678SMax Reitz             return num_x->u.u64 == num_y->u.u64;
214b38dd678SMax Reitz         case QNUM_DOUBLE:
215b38dd678SMax Reitz             return false;
216b38dd678SMax Reitz         }
217b38dd678SMax Reitz         abort();
218b38dd678SMax Reitz     case QNUM_DOUBLE:
219b38dd678SMax Reitz         switch (num_y->kind) {
220b38dd678SMax Reitz         case QNUM_I64:
221b38dd678SMax Reitz         case QNUM_U64:
222b38dd678SMax Reitz             return false;
223b38dd678SMax Reitz         case QNUM_DOUBLE:
224b38dd678SMax Reitz             /* Comparison in native double type */
225b38dd678SMax Reitz             return num_x->u.dbl == num_y->u.dbl;
226b38dd678SMax Reitz         }
227b38dd678SMax Reitz         abort();
228b38dd678SMax Reitz     }
229b38dd678SMax Reitz 
230b38dd678SMax Reitz     abort();
231b38dd678SMax Reitz }
232b38dd678SMax Reitz 
233b38dd678SMax Reitz /**
23401b2ffceSMarc-André Lureau  * qnum_destroy_obj(): Free all memory allocated by a
23501b2ffceSMarc-André Lureau  * QNum object
23601b2ffceSMarc-André Lureau  */
23701b2ffceSMarc-André Lureau void qnum_destroy_obj(QObject *obj)
23801b2ffceSMarc-André Lureau {
23901b2ffceSMarc-André Lureau     assert(obj != NULL);
2407dc847ebSMax Reitz     g_free(qobject_to(QNum, obj));
24101b2ffceSMarc-André Lureau }
242d709bbf3SMarc-André Lureau 
243d709bbf3SMarc-André Lureau void qnum_unref(QNum *q)
244d709bbf3SMarc-André Lureau {
245d709bbf3SMarc-André Lureau     qobject_unref(q);
246d709bbf3SMarc-André Lureau }
247