The helper function will be useful when writing support code to deal with device slot information.
TODO: documentation is incomplete and unclear, needs to be improved. Signed-off-by: Eduardo Habkost <ehabk...@redhat.com> --- include/qapi/util.h | 39 +++++++++++++++++++++++++++++ qapi/qapi-util.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/test-qapi-util.c | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) diff --git a/include/qapi/util.h b/include/qapi/util.h index 7436ed8..d4562c4 100644 --- a/include/qapi/util.h +++ b/include/qapi/util.h @@ -11,9 +11,48 @@ #ifndef QAPI_UTIL_H #define QAPI_UTIL_H +#include "qapi/qmp/qobject.h" +#include "qapi-types.h" + int qapi_enum_parse(const char * const lookup[], const char *buf, int max, int def, Error **errp); int parse_qapi_name(const char *name, bool complete); +/** + * qobject_compare: + * + * Compare the value of @a and @b. + * + * If @a and @b have the same type and the same value (see list + * of supported types below), return 0. + * + * If @a and @b are both strings, return strcmp(a, b). + * + * If @a and @b are numbers, return a negative value if a < b, + * and a positive value if a > b. + * + * Otherwise (if @a and @b are not the same, have different types, + * are of an unsupported type, or are different), return a non-zero value. + * + * Note that this function doesn't support some types, and may + * return false if the types are unsupported, or if the types don't + * match exactly. + * + * Supported types: + * - QTYPE_QNULL + * - QTYPE_QSTRING + * - QTYPE_QBOOL + * - QTYPE_QNUM (integers only) + * - QTYPE_QLIST + * + * Unsupported (always return false): + * - QTYPE_QNUM (non-integer values) + * - QTYPE_QDICT + * + * TODO: rewrite documentation to be clearer. + * TODO: support non-integer QTYPE_NUM values and QTYPE_QDICT. + */ +int qobject_compare(QObject *a, QObject *b); + #endif diff --git a/qapi/qapi-util.c b/qapi/qapi-util.c index 46eda7d..67c5e82 100644 --- a/qapi/qapi-util.c +++ b/qapi/qapi-util.c @@ -13,6 +13,9 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qbool.h" #include "qapi/util.h" int qapi_enum_parse(const char * const lookup[], const char *buf, @@ -80,3 +83,66 @@ int parse_qapi_name(const char *str, bool complete) } return p - str; } + +static int qnum_compare(QNum *a, QNum *b) +{ + int64_t ia, ib; + bool va = qnum_get_try_int(a, &ia); + bool vb = qnum_get_try_int(b, &ib); + + if (va && vb) { + return (ia < ib) ? -1 : (ia > ib) ? 1 : 0; + } + + /*TODO: uint, double */ + return -1; +} + +static int qlist_compare(QList *a, QList *b) +{ + const QListEntry *ea, *eb; + + for (ea = qlist_first(a), eb = qlist_first(b); + ea && eb; + ea = qlist_next(ea), eb = qlist_next(eb)) { + QObject *va = qlist_entry_obj(ea); + QObject *vb = qlist_entry_obj(eb); + int c = qobject_compare(va, vb); + if (c) { + return c; + } + } + + if (eb) { + return -1; + } else if (ea) { + return 1; + } else { + return 0; + } +} + +int qobject_compare(QObject *a, QObject *b) +{ + QType ta = qobject_type(a); + QType tb = qobject_type(b); + + if (ta != tb) { + return -1; + } + + switch (ta) { + case QTYPE_QNULL: + return true; + case QTYPE_QNUM: + return qnum_compare(qobject_to_qnum(a), qobject_to_qnum(b)); + case QTYPE_QSTRING: + return strcmp(qstring_get_str(qobject_to_qstring(a)), qstring_get_str(qobject_to_qstring(b))); + case QTYPE_QBOOL: + return (int)qbool_get_bool(qobject_to_qbool(a)) - (int)qbool_get_bool(qobject_to_qbool(b)); + case QTYPE_QLIST: + return qlist_compare(qobject_to_qlist(a), qobject_to_qlist(b)); + default: + return -1; + } +} diff --git a/tests/test-qapi-util.c b/tests/test-qapi-util.c index e869757..c0cf46c 100644 --- a/tests/test-qapi-util.c +++ b/tests/test-qapi-util.c @@ -13,6 +13,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/util.h" +#include "qapi/qmp/qnum.h" +#include "qapi/qmp/qstring.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qjson.h" #include "test-qapi-types.h" static void test_qapi_enum_parse(void) @@ -75,11 +79,60 @@ static void test_parse_qapi_name(void) g_assert(ret == -1); } +static void test_qobject_compare(void) +{ + QString *a1 = qstring_from_str("abc"); + QString *a2 = qstring_from_str("abc"); + QString *b = qstring_from_str("bcd"); + QNum *i1 = qnum_from_int(100); + QNum *i2 = qnum_from_int(100); + QNum *j = qnum_from_int(200); + QList *l1 = qlist_new(); + QList *l2 = qlist_new(); + QList *m = qlist_new(); + + qlist_append_int(l1, 100); + qlist_append_int(l1, 200); + qlist_append_int(l2, 100); + qlist_append_int(l2, 200); + + qlist_append_int(m, 100); + qlist_append_int(m, 300); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(a2)), ==, 0); + g_assert_cmpint(qobject_compare(QOBJECT(i1), QOBJECT(i2)), ==, 0); + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(l2)), ==, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(b)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(b), QOBJECT(a1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(i1), QOBJECT(j)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(j), QOBJECT(i1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(m)), <, 0); + g_assert_cmpint(qobject_compare(QOBJECT(m), QOBJECT(l1)), >, 0); + + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(i1)), !=, 0); + g_assert_cmpint(qobject_compare(QOBJECT(a1), QOBJECT(l1)), !=, 0); + g_assert_cmpint(qobject_compare(QOBJECT(l1), QOBJECT(i1)), !=, 0); + + QDECREF(a1); + QDECREF(a2); + QDECREF(b); + QDECREF(i1); + QDECREF(i2); + QDECREF(j); + QDECREF(l1); + QDECREF(l2); + QDECREF(m); +} + int main(int argc, char *argv[]) { g_test_init(&argc, &argv, NULL); g_test_add_func("/qapi/util/qapi_enum_parse", test_qapi_enum_parse); g_test_add_func("/qapi/util/parse_qapi_name", test_parse_qapi_name); + g_test_add_func("/qapi/util/qobject_compare", test_qobject_compare); g_test_run(); return 0; } -- 2.9.4