qnum: add uint type
authorMarc-André Lureau <marcandre.lureau@redhat.com>
Wed, 7 Jun 2017 16:36:01 +0000 (20:36 +0400)
committerMarkus Armbruster <armbru@redhat.com>
Tue, 20 Jun 2017 12:31:31 +0000 (14:31 +0200)
In order to store integer values between INT64_MAX and UINT64_MAX, add
a uint64_t internal representation.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20170607163635.17635-10-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
include/qapi/qmp/qnum.h
qobject/qnum.c
tests/check-qnum.c

index e42b13614103464e8a18b126c5488ee22a489446..09d745c490ceeb474bc69e0d00a6828da5def0b4 100644 (file)
@@ -19,6 +19,7 @@
 
 typedef enum {
     QNUM_I64,
+    QNUM_U64,
     QNUM_DOUBLE
 } QNumKind;
 
@@ -27,15 +28,21 @@ typedef struct QNum {
     QNumKind kind;
     union {
         int64_t i64;
+        uint64_t u64;
         double dbl;
     } u;
 } QNum;
 
 QNum *qnum_from_int(int64_t value);
+QNum *qnum_from_uint(uint64_t value);
 QNum *qnum_from_double(double value);
 
 bool qnum_get_try_int(const QNum *qn, int64_t *val);
 int64_t qnum_get_int(const QNum *qn);
+
+bool qnum_get_try_uint(const QNum *qn, uint64_t *val);
+uint64_t qnum_get_uint(const QNum *qn);
+
 double qnum_get_double(QNum *qn);
 
 char *qnum_to_string(QNum *qn);
index 7bb90067635dc6fd5367528e3593e9cdc1d3277b..476e81c93b37f35c3ac131ba5c5396357826fc7e 100644 (file)
@@ -34,6 +34,22 @@ QNum *qnum_from_int(int64_t value)
     return qn;
 }
 
+/**
+ * qnum_from_uint(): Create a new QNum from an uint64_t
+ *
+ * Return strong reference.
+ */
+QNum *qnum_from_uint(uint64_t value)
+{
+    QNum *qn = g_new(QNum, 1);
+
+    qobject_init(QOBJECT(qn), QTYPE_QNUM);
+    qn->kind = QNUM_U64;
+    qn->u.u64 = value;
+
+    return qn;
+}
+
 /**
  * qnum_from_double(): Create a new QNum from a double
  *
@@ -61,6 +77,12 @@ bool qnum_get_try_int(const QNum *qn, int64_t *val)
     case QNUM_I64:
         *val = qn->u.i64;
         return true;
+    case QNUM_U64:
+        if (qn->u.u64 > INT64_MAX) {
+            return false;
+        }
+        *val = qn->u.u64;
+        return true;
     case QNUM_DOUBLE:
         return false;
     }
@@ -82,6 +104,44 @@ int64_t qnum_get_int(const QNum *qn)
     return val;
 }
 
+/**
+ * qnum_get_uint(): Get an unsigned integer from the number
+ *
+ * Return true on success.
+ */
+bool qnum_get_try_uint(const QNum *qn, uint64_t *val)
+{
+    switch (qn->kind) {
+    case QNUM_I64:
+        if (qn->u.i64 < 0) {
+            return false;
+        }
+        *val = qn->u.i64;
+        return true;
+    case QNUM_U64:
+        *val = qn->u.u64;
+        return true;
+    case QNUM_DOUBLE:
+        return false;
+    }
+
+    assert(0);
+    return false;
+}
+
+/**
+ * qnum_get_uint(): Get an unsigned integer from the number
+ *
+ * assert() on failure.
+ */
+uint64_t qnum_get_uint(const QNum *qn)
+{
+    uint64_t val;
+    bool success = qnum_get_try_uint(qn, &val);
+    assert(success);
+    return val;
+}
+
 /**
  * qnum_get_double(): Get a float representation of the number
  *
@@ -92,6 +152,8 @@ double qnum_get_double(QNum *qn)
     switch (qn->kind) {
     case QNUM_I64:
         return qn->u.i64;
+    case QNUM_U64:
+        return qn->u.u64;
     case QNUM_DOUBLE:
         return qn->u.dbl;
     }
@@ -108,6 +170,8 @@ char *qnum_to_string(QNum *qn)
     switch (qn->kind) {
     case QNUM_I64:
         return g_strdup_printf("%" PRId64, qn->u.i64);
+    case QNUM_U64:
+        return g_strdup_printf("%" PRIu64, qn->u.u64);
     case QNUM_DOUBLE:
         /* FIXME: snprintf() is locale dependent; but JSON requires
          * numbers to be formatted as if in the C locale. Dependence
index da7e0b0a9a23691ae70a7dd05d6866c2f61ac212..d702d5da9c63d98d8fdc50b1ee1d339ad05f7e17 100644 (file)
@@ -39,6 +39,21 @@ static void qnum_from_int_test(void)
     QDECREF(qn);
 }
 
+static void qnum_from_uint_test(void)
+{
+    QNum *qn;
+    const uint64_t value = UINT64_MAX;
+
+    qn = qnum_from_uint(value);
+    g_assert(qn != NULL);
+    g_assert_cmpint(qn->kind, ==, QNUM_U64);
+    g_assert(qn->u.u64 == value);
+    g_assert(qn->base.refcnt == 1);
+    g_assert(qobject_type(QOBJECT(qn)) == QTYPE_QNUM);
+
+    QDECREF(qn);
+}
+
 static void qnum_from_double_test(void)
 {
     QNum *qn;
@@ -76,6 +91,37 @@ static void qnum_get_int_test(void)
     QDECREF(qn);
 }
 
+static void qnum_get_uint_test(void)
+{
+    QNum *qn;
+    const int value = 123456;
+    uint64_t val;
+    int64_t ival;
+
+    qn = qnum_from_uint(value);
+    g_assert(qnum_get_try_uint(qn, &val));
+    g_assert_cmpuint(val, ==, value);
+    QDECREF(qn);
+
+    qn = qnum_from_int(value);
+    g_assert(qnum_get_try_uint(qn, &val));
+    g_assert_cmpuint(val, ==, value);
+    QDECREF(qn);
+
+    /* invalid cases */
+    qn = qnum_from_int(-1);
+    g_assert(!qnum_get_try_uint(qn, &val));
+    QDECREF(qn);
+
+    qn = qnum_from_uint(-1ULL);
+    g_assert(!qnum_get_try_int(qn, &ival));
+    QDECREF(qn);
+
+    qn = qnum_from_double(0.42);
+    g_assert(!qnum_get_try_uint(qn, &val));
+    QDECREF(qn);
+}
+
 static void qobject_to_qnum_test(void)
 {
     QNum *qn;
@@ -112,9 +158,11 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     g_test_add_func("/qnum/from_int", qnum_from_int_test);
+    g_test_add_func("/qnum/from_uint", qnum_from_uint_test);
     g_test_add_func("/qnum/from_double", qnum_from_double_test);
     g_test_add_func("/qnum/from_int64", qnum_from_int64_test);
     g_test_add_func("/qnum/get_int", qnum_get_int_test);
+    g_test_add_func("/qnum/get_uint", qnum_get_uint_test);
     g_test_add_func("/qnum/to_qnum", qobject_to_qnum_test);
     g_test_add_func("/qnum/to_string", qnum_to_string_test);