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/qmp/qnum.h" 17 #include "qapi/qmp/qobject.h" 18 #include "qemu-common.h" 19 20 /** 21 * qnum_from_int(): Create a new QNum from an int64_t 22 * 23 * Return strong reference. 24 */ 25 QNum *qnum_from_int(int64_t value) 26 { 27 QNum *qn = g_new(QNum, 1); 28 29 qobject_init(QOBJECT(qn), QTYPE_QNUM); 30 qn->kind = QNUM_I64; 31 qn->u.i64 = value; 32 33 return qn; 34 } 35 36 /** 37 * qnum_from_uint(): Create a new QNum from an uint64_t 38 * 39 * Return strong reference. 40 */ 41 QNum *qnum_from_uint(uint64_t value) 42 { 43 QNum *qn = g_new(QNum, 1); 44 45 qobject_init(QOBJECT(qn), QTYPE_QNUM); 46 qn->kind = QNUM_U64; 47 qn->u.u64 = value; 48 49 return qn; 50 } 51 52 /** 53 * qnum_from_double(): Create a new QNum from a double 54 * 55 * Return strong reference. 56 */ 57 QNum *qnum_from_double(double value) 58 { 59 QNum *qn = g_new(QNum, 1); 60 61 qobject_init(QOBJECT(qn), QTYPE_QNUM); 62 qn->kind = QNUM_DOUBLE; 63 qn->u.dbl = value; 64 65 return qn; 66 } 67 68 /** 69 * qnum_get_try_int(): Get an integer representation of the number 70 * 71 * Return true on success. 72 */ 73 bool qnum_get_try_int(const QNum *qn, int64_t *val) 74 { 75 switch (qn->kind) { 76 case QNUM_I64: 77 *val = qn->u.i64; 78 return true; 79 case QNUM_U64: 80 if (qn->u.u64 > INT64_MAX) { 81 return false; 82 } 83 *val = qn->u.u64; 84 return true; 85 case QNUM_DOUBLE: 86 return false; 87 } 88 89 assert(0); 90 return false; 91 } 92 93 /** 94 * qnum_get_int(): Get an integer representation of the number 95 * 96 * assert() on failure. 97 */ 98 int64_t qnum_get_int(const QNum *qn) 99 { 100 int64_t val; 101 bool success = qnum_get_try_int(qn, &val); 102 assert(success); 103 return val; 104 } 105 106 /** 107 * qnum_get_uint(): Get an unsigned integer from the number 108 * 109 * Return true on success. 110 */ 111 bool qnum_get_try_uint(const QNum *qn, uint64_t *val) 112 { 113 switch (qn->kind) { 114 case QNUM_I64: 115 if (qn->u.i64 < 0) { 116 return false; 117 } 118 *val = qn->u.i64; 119 return true; 120 case QNUM_U64: 121 *val = qn->u.u64; 122 return true; 123 case QNUM_DOUBLE: 124 return false; 125 } 126 127 assert(0); 128 return false; 129 } 130 131 /** 132 * qnum_get_uint(): Get an unsigned integer from the number 133 * 134 * assert() on failure. 135 */ 136 uint64_t qnum_get_uint(const QNum *qn) 137 { 138 uint64_t val; 139 bool success = qnum_get_try_uint(qn, &val); 140 assert(success); 141 return val; 142 } 143 144 /** 145 * qnum_get_double(): Get a float representation of the number 146 * 147 * qnum_get_double() loses precision for integers beyond 53 bits. 148 */ 149 double qnum_get_double(QNum *qn) 150 { 151 switch (qn->kind) { 152 case QNUM_I64: 153 return qn->u.i64; 154 case QNUM_U64: 155 return qn->u.u64; 156 case QNUM_DOUBLE: 157 return qn->u.dbl; 158 } 159 160 assert(0); 161 return 0.0; 162 } 163 164 char *qnum_to_string(QNum *qn) 165 { 166 char *buffer; 167 int len; 168 169 switch (qn->kind) { 170 case QNUM_I64: 171 return g_strdup_printf("%" PRId64, qn->u.i64); 172 case QNUM_U64: 173 return g_strdup_printf("%" PRIu64, qn->u.u64); 174 case QNUM_DOUBLE: 175 /* FIXME: snprintf() is locale dependent; but JSON requires 176 * numbers to be formatted as if in the C locale. Dependence 177 * on C locale is a pervasive issue in QEMU. */ 178 /* FIXME: This risks printing Inf or NaN, which are not valid 179 * JSON values. */ 180 /* FIXME: the default precision of 6 for %f often causes 181 * rounding errors; we should be using DBL_DECIMAL_DIG (17), 182 * and only rounding to a shorter number if the result would 183 * still produce the same floating point value. */ 184 buffer = g_strdup_printf("%f" , qn->u.dbl); 185 len = strlen(buffer); 186 while (len > 0 && buffer[len - 1] == '0') { 187 len--; 188 } 189 190 if (len && buffer[len - 1] == '.') { 191 buffer[len - 1] = 0; 192 } else { 193 buffer[len] = 0; 194 } 195 196 return buffer; 197 } 198 199 assert(0); 200 return NULL; 201 } 202 203 /** 204 * qobject_to_qnum(): Convert a QObject into a QNum 205 */ 206 QNum *qobject_to_qnum(const QObject *obj) 207 { 208 if (!obj || qobject_type(obj) != QTYPE_QNUM) { 209 return NULL; 210 } 211 return container_of(obj, QNum, base); 212 } 213 214 /** 215 * qnum_is_equal(): Test whether the two QNums are equal 216 * 217 * Negative integers are never considered equal to unsigned integers, 218 * but positive integers in the range [0, INT64_MAX] are considered 219 * equal independently of whether the QNum's kind is i64 or u64. 220 * 221 * Doubles are never considered equal to integers. 222 */ 223 bool qnum_is_equal(const QObject *x, const QObject *y) 224 { 225 QNum *num_x = qobject_to_qnum(x); 226 QNum *num_y = qobject_to_qnum(y); 227 228 switch (num_x->kind) { 229 case QNUM_I64: 230 switch (num_y->kind) { 231 case QNUM_I64: 232 /* Comparison in native int64_t type */ 233 return num_x->u.i64 == num_y->u.i64; 234 case QNUM_U64: 235 /* Implicit conversion of x to uin64_t, so we have to 236 * check its sign before */ 237 return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64; 238 case QNUM_DOUBLE: 239 return false; 240 } 241 abort(); 242 case QNUM_U64: 243 switch (num_y->kind) { 244 case QNUM_I64: 245 return qnum_is_equal(y, x); 246 case QNUM_U64: 247 /* Comparison in native uint64_t type */ 248 return num_x->u.u64 == num_y->u.u64; 249 case QNUM_DOUBLE: 250 return false; 251 } 252 abort(); 253 case QNUM_DOUBLE: 254 switch (num_y->kind) { 255 case QNUM_I64: 256 case QNUM_U64: 257 return false; 258 case QNUM_DOUBLE: 259 /* Comparison in native double type */ 260 return num_x->u.dbl == num_y->u.dbl; 261 } 262 abort(); 263 } 264 265 abort(); 266 } 267 268 /** 269 * qnum_destroy_obj(): Free all memory allocated by a 270 * QNum object 271 */ 272 void qnum_destroy_obj(QObject *obj) 273 { 274 assert(obj != NULL); 275 g_free(qobject_to_qnum(obj)); 276 } 277