2
0

qnum.c 5.8 KB

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