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