qemu/qobject/qnum.c
<<
>>
Prefs
   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 */
  26QNum *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 */
  42QNum *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 */
  58QNum *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 */
  74bool 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 */
  99int64_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 */
 112bool 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 */
 137uint64_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 */
 150double 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
 165char *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 */
 207QNum *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_is_equal(): Test whether the two QNums are equal
 217 *
 218 * Negative integers are never considered equal to unsigned integers,
 219 * but positive integers in the range [0, INT64_MAX] are considered
 220 * equal independently of whether the QNum's kind is i64 or u64.
 221 *
 222 * Doubles are never considered equal to integers.
 223 */
 224bool qnum_is_equal(const QObject *x, const QObject *y)
 225{
 226    QNum *num_x = qobject_to_qnum(x);
 227    QNum *num_y = qobject_to_qnum(y);
 228
 229    switch (num_x->kind) {
 230    case QNUM_I64:
 231        switch (num_y->kind) {
 232        case QNUM_I64:
 233            /* Comparison in native int64_t type */
 234            return num_x->u.i64 == num_y->u.i64;
 235        case QNUM_U64:
 236            /* Implicit conversion of x to uin64_t, so we have to
 237             * check its sign before */
 238            return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64;
 239        case QNUM_DOUBLE:
 240            return false;
 241        }
 242        abort();
 243    case QNUM_U64:
 244        switch (num_y->kind) {
 245        case QNUM_I64:
 246            return qnum_is_equal(y, x);
 247        case QNUM_U64:
 248            /* Comparison in native uint64_t type */
 249            return num_x->u.u64 == num_y->u.u64;
 250        case QNUM_DOUBLE:
 251            return false;
 252        }
 253        abort();
 254    case QNUM_DOUBLE:
 255        switch (num_y->kind) {
 256        case QNUM_I64:
 257        case QNUM_U64:
 258            return false;
 259        case QNUM_DOUBLE:
 260            /* Comparison in native double type */
 261            return num_x->u.dbl == num_y->u.dbl;
 262        }
 263        abort();
 264    }
 265
 266    abort();
 267}
 268
 269/**
 270 * qnum_destroy_obj(): Free all memory allocated by a
 271 * QNum object
 272 */
 273void qnum_destroy_obj(QObject *obj)
 274{
 275    assert(obj != NULL);
 276    g_free(qobject_to_qnum(obj));
 277}
 278