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