Message ID | 20170614153102.9077-3-mreitz@redhat.com |
---|---|
State | New |
Headers | show |
Am 14.06.2017 um 17:31 hat Max Reitz geschrieben: > This generic function (along with its implementations for different > types) determines whether two QObjects are equal. > > Signed-off-by: Max Reitz <mreitz@redhat.com> > diff --git a/qobject/qdict.c b/qobject/qdict.c > index 88e2ecd..2ed57ca 100644 > --- a/qobject/qdict.c > +++ b/qobject/qdict.c > @@ -410,6 +410,30 @@ void qdict_del(QDict *qdict, const char *key) > } > > /** > + * qdict_is_equal(): Tests whether the two QDicts are equal This should specify what equality means for QDicts: Do their entries have to point to the same objects, or is it enough if the objects compare equal? It seems you're trying to implement the lattter. > + */ > +bool qdict_is_equal(const QObject *x, const QObject *y) > +{ > + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y); > + const QDictEntry *e; > + > + if (qdict_size(dict_x) != qdict_size(dict_y)) { > + return false; > + } > + > + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) { > + const QObject *obj_x = qdict_entry_value(e); > + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e)); > + > + if (!qobject_is_equal(obj_x, obj_y)) { > + return false; > + } > + } > + > + return true; > +} If I'm not mistaken, this doesn't actually check equality, but that the entries of x are a subset of the entries of y. > +/** > * qdict_destroy_obj(): Free all the memory allocated by a QDict > */ > void qdict_destroy_obj(QObject *obj) > diff --git a/qobject/qlist.c b/qobject/qlist.c > index 86b60cb..b3033c6 100644 > --- a/qobject/qlist.c > +++ b/qobject/qlist.c > @@ -140,6 +140,31 @@ QList *qobject_to_qlist(const QObject *obj) > } > > /** > + * qlist_is_equal(): Tests whether the two QLists are equal Like for QDict, this isn't a complete description. Your implementation seems to check that both lists contain objects that compare equal at each index (i.e. order matters). > + */ > +bool qlist_is_equal(const QObject *x, const QObject *y) > +{ > + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y); > + const QListEntry *entry_x, *entry_y; > + > + entry_x = qlist_first(list_x); > + entry_y = qlist_first(list_y); > + > + while (entry_x && entry_y) { > + if (!qobject_is_equal(qlist_entry_obj(entry_x), > + qlist_entry_obj(entry_y))) > + { > + return false; > + } > + > + entry_x = qlist_next(entry_x); > + entry_y = qlist_next(entry_y); > + } > + > + return !entry_x && !entry_y; > +} > + > +/** > * qlist_destroy_obj(): Free all the memory allocated by a QList > */ Kevin
On 2017-06-19 15:55, Kevin Wolf wrote: > Am 14.06.2017 um 17:31 hat Max Reitz geschrieben: >> This generic function (along with its implementations for different >> types) determines whether two QObjects are equal. >> >> Signed-off-by: Max Reitz <mreitz@redhat.com> > >> diff --git a/qobject/qdict.c b/qobject/qdict.c >> index 88e2ecd..2ed57ca 100644 >> --- a/qobject/qdict.c >> +++ b/qobject/qdict.c >> @@ -410,6 +410,30 @@ void qdict_del(QDict *qdict, const char *key) >> } >> >> /** >> + * qdict_is_equal(): Tests whether the two QDicts are equal > > This should specify what equality means for QDicts: Do their entries > have to point to the same objects, or is it enough if the objects > compare equal? It seems you're trying to implement the lattter. Yes, I'll add a comment. >> + */ >> +bool qdict_is_equal(const QObject *x, const QObject *y) >> +{ >> + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y); >> + const QDictEntry *e; >> + >> + if (qdict_size(dict_x) != qdict_size(dict_y)) { >> + return false; >> + } >> + >> + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) { >> + const QObject *obj_x = qdict_entry_value(e); >> + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e)); >> + >> + if (!qobject_is_equal(obj_x, obj_y)) { >> + return false; >> + } >> + } >> + >> + return true; >> +} > > If I'm not mistaken, this doesn't actually check equality, but that the > entries of x are a subset of the entries of y. That's why I'm checking that x and y have the same size before. >> +/** >> * qdict_destroy_obj(): Free all the memory allocated by a QDict >> */ >> void qdict_destroy_obj(QObject *obj) >> diff --git a/qobject/qlist.c b/qobject/qlist.c >> index 86b60cb..b3033c6 100644 >> --- a/qobject/qlist.c >> +++ b/qobject/qlist.c >> @@ -140,6 +140,31 @@ QList *qobject_to_qlist(const QObject *obj) >> } >> >> /** >> + * qlist_is_equal(): Tests whether the two QLists are equal > > Like for QDict, this isn't a complete description. Yes, I'll add a comment here, too. > Your implementation seems to check that both lists contain objects that > compare equal at each index (i.e. order matters). Of course it does because lists are not sets but arrays (in contrast to dicts). Max >> + */ >> +bool qlist_is_equal(const QObject *x, const QObject *y) >> +{ >> + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y); >> + const QListEntry *entry_x, *entry_y; >> + >> + entry_x = qlist_first(list_x); >> + entry_y = qlist_first(list_y); >> + >> + while (entry_x && entry_y) { >> + if (!qobject_is_equal(qlist_entry_obj(entry_x), >> + qlist_entry_obj(entry_y))) >> + { >> + return false; >> + } >> + >> + entry_x = qlist_next(entry_x); >> + entry_y = qlist_next(entry_y); >> + } >> + >> + return !entry_x && !entry_y; >> +} >> + >> +/** >> * qlist_destroy_obj(): Free all the memory allocated by a QList >> */ > > Kevin >
diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h index a41111c..f77ea86 100644 --- a/include/qapi/qmp/qbool.h +++ b/include/qapi/qmp/qbool.h @@ -24,6 +24,7 @@ typedef struct QBool { QBool *qbool_from_bool(bool value); bool qbool_get_bool(const QBool *qb); QBool *qobject_to_qbool(const QObject *obj); +bool qbool_is_equal(const QObject *x, const QObject *y); void qbool_destroy_obj(QObject *obj); #endif /* QBOOL_H */ diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 188440a..134a526 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -41,6 +41,7 @@ void qdict_del(QDict *qdict, const char *key); int qdict_haskey(const QDict *qdict, const char *key); QObject *qdict_get(const QDict *qdict, const char *key); QDict *qobject_to_qdict(const QObject *obj); +bool qdict_is_equal(const QObject *x, const QObject *y); void qdict_iter(const QDict *qdict, void (*iter)(const char *key, QObject *obj, void *opaque), void *opaque); diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h index b5d1583..318e91e 100644 --- a/include/qapi/qmp/qfloat.h +++ b/include/qapi/qmp/qfloat.h @@ -24,6 +24,7 @@ typedef struct QFloat { QFloat *qfloat_from_double(double value); double qfloat_get_double(const QFloat *qi); QFloat *qobject_to_qfloat(const QObject *obj); +bool qfloat_is_equal(const QObject *x, const QObject *y); void qfloat_destroy_obj(QObject *obj); #endif /* QFLOAT_H */ diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h index 3aaff76..20975da 100644 --- a/include/qapi/qmp/qint.h +++ b/include/qapi/qmp/qint.h @@ -23,6 +23,7 @@ typedef struct QInt { QInt *qint_from_int(int64_t value); int64_t qint_get_int(const QInt *qi); QInt *qobject_to_qint(const QObject *obj); +bool qint_is_equal(const QObject *x, const QObject *y); void qint_destroy_obj(QObject *obj); #endif /* QINT_H */ diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h index 5dc4ed9..4380a5b 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -57,6 +57,7 @@ QObject *qlist_peek(QList *qlist); int qlist_empty(const QList *qlist); size_t qlist_size(const QList *qlist); QList *qobject_to_qlist(const QObject *obj); +bool qlist_is_equal(const QObject *x, const QObject *y); void qlist_destroy_obj(QObject *obj); static inline const QListEntry *qlist_first(const QList *qlist) diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h index 69555ac..9299683 100644 --- a/include/qapi/qmp/qnull.h +++ b/include/qapi/qmp/qnull.h @@ -23,4 +23,6 @@ static inline QObject *qnull(void) return &qnull_; } +bool qnull_is_equal(const QObject *x, const QObject *y); + #endif /* QNULL_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index ef1d1a9..cac72e3 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj) } /** + * qobject_is_equal(): Returns whether the two objects are equal. + * + * Any of the pointers may be NULL; will return true if both are. Will always + * return false if only one is (therefore a QNull object is not considered equal + * to a NULL pointer). + */ +bool qobject_is_equal(const QObject *x, const QObject *y); + +/** * qobject_destroy(): Free resources used by the object */ void qobject_destroy(QObject *obj); diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 10076b7..65c05a9 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); void qstring_append_chr(QString *qstring, int c); QString *qobject_to_qstring(const QObject *obj); +bool qstring_is_equal(const QObject *x, const QObject *y); void qstring_destroy_obj(QObject *obj); #endif /* QSTRING_H */ diff --git a/qobject/qbool.c b/qobject/qbool.c index 0606bbd..f1d1719 100644 --- a/qobject/qbool.c +++ b/qobject/qbool.c @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj) } /** + * qbool_is_equal(): Tests whether the two QBools are equal + */ +bool qbool_is_equal(const QObject *x, const QObject *y) +{ + return qobject_to_qbool(x)->value == qobject_to_qbool(y)->value; +} + +/** * qbool_destroy_obj(): Free all memory allocated by a * QBool object */ diff --git a/qobject/qdict.c b/qobject/qdict.c index 88e2ecd..2ed57ca 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -410,6 +410,30 @@ void qdict_del(QDict *qdict, const char *key) } /** + * qdict_is_equal(): Tests whether the two QDicts are equal + */ +bool qdict_is_equal(const QObject *x, const QObject *y) +{ + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y); + const QDictEntry *e; + + if (qdict_size(dict_x) != qdict_size(dict_y)) { + return false; + } + + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) { + const QObject *obj_x = qdict_entry_value(e); + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e)); + + if (!qobject_is_equal(obj_x, obj_y)) { + return false; + } + } + + return true; +} + +/** * qdict_destroy_obj(): Free all the memory allocated by a QDict */ void qdict_destroy_obj(QObject *obj) diff --git a/qobject/qfloat.c b/qobject/qfloat.c index d5da847..291ecc4 100644 --- a/qobject/qfloat.c +++ b/qobject/qfloat.c @@ -52,6 +52,14 @@ QFloat *qobject_to_qfloat(const QObject *obj) } /** + * qfloat_is_equal(): Tests whether the two QFloats are equal + */ +bool qfloat_is_equal(const QObject *x, const QObject *y) +{ + return qobject_to_qfloat(x)->value == qobject_to_qfloat(y)->value; +} + +/** * qfloat_destroy_obj(): Free all memory allocated by a * QFloat object */ diff --git a/qobject/qint.c b/qobject/qint.c index d7d1b30..f638cb7 100644 --- a/qobject/qint.c +++ b/qobject/qint.c @@ -51,6 +51,14 @@ QInt *qobject_to_qint(const QObject *obj) } /** + * qint_is_equal(): Tests whether the two QInts are equal + */ +bool qint_is_equal(const QObject *x, const QObject *y) +{ + return qobject_to_qint(x)->value == qobject_to_qint(y)->value; +} + +/** * qint_destroy_obj(): Free all memory allocated by a * QInt object */ diff --git a/qobject/qlist.c b/qobject/qlist.c index 86b60cb..b3033c6 100644 --- a/qobject/qlist.c +++ b/qobject/qlist.c @@ -140,6 +140,31 @@ QList *qobject_to_qlist(const QObject *obj) } /** + * qlist_is_equal(): Tests whether the two QLists are equal + */ +bool qlist_is_equal(const QObject *x, const QObject *y) +{ + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y); + const QListEntry *entry_x, *entry_y; + + entry_x = qlist_first(list_x); + entry_y = qlist_first(list_y); + + while (entry_x && entry_y) { + if (!qobject_is_equal(qlist_entry_obj(entry_x), + qlist_entry_obj(entry_y))) + { + return false; + } + + entry_x = qlist_next(entry_x); + entry_y = qlist_next(entry_y); + } + + return !entry_x && !entry_y; +} + +/** * qlist_destroy_obj(): Free all the memory allocated by a QList */ void qlist_destroy_obj(QObject *obj) diff --git a/qobject/qnull.c b/qobject/qnull.c index b3cc85e..af5453d 100644 --- a/qobject/qnull.c +++ b/qobject/qnull.c @@ -19,3 +19,8 @@ QObject qnull_ = { .type = QTYPE_QNULL, .refcnt = 1, }; + +bool qnull_is_equal(const QObject *x, const QObject *y) +{ + return true; +} diff --git a/qobject/qobject.c b/qobject/qobject.c index fe4fa10..af2869a 100644 --- a/qobject/qobject.c +++ b/qobject/qobject.c @@ -28,3 +28,33 @@ void qobject_destroy(QObject *obj) assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX); qdestroy[obj->type](obj); } + + +static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = { + [QTYPE_NONE] = NULL, /* No such object exists */ + [QTYPE_QNULL] = qnull_is_equal, + [QTYPE_QINT] = qint_is_equal, + [QTYPE_QSTRING] = qstring_is_equal, + [QTYPE_QDICT] = qdict_is_equal, + [QTYPE_QLIST] = qlist_is_equal, + [QTYPE_QFLOAT] = qfloat_is_equal, + [QTYPE_QBOOL] = qbool_is_equal, +}; + +bool qobject_is_equal(const QObject *x, const QObject *y) +{ + /* We cannot test x == y because an object does not need to be equal to + * itself (e.g. NaN floats are not). */ + + if (!x && !y) { + return true; + } + + if (!x || !y || x->type != y->type) { + return false; + } + + assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX); + + return qis_equal[x->type](x, y); +} diff --git a/qobject/qstring.c b/qobject/qstring.c index 5da7b5f..a2b51fa 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring) } /** + * qstring_is_equal(): Tests whether the two QStrings are equal + */ +bool qstring_is_equal(const QObject *x, const QObject *y) +{ + return !strcmp(qobject_to_qstring(x)->string, + qobject_to_qstring(y)->string); +} + +/** * qstring_destroy_obj(): Free all memory allocated by a QString * object */
This generic function (along with its implementations for different types) determines whether two QObjects are equal. Signed-off-by: Max Reitz <mreitz@redhat.com> --- include/qapi/qmp/qbool.h | 1 + include/qapi/qmp/qdict.h | 1 + include/qapi/qmp/qfloat.h | 1 + include/qapi/qmp/qint.h | 1 + include/qapi/qmp/qlist.h | 1 + include/qapi/qmp/qnull.h | 2 ++ include/qapi/qmp/qobject.h | 9 +++++++++ include/qapi/qmp/qstring.h | 1 + qobject/qbool.c | 8 ++++++++ qobject/qdict.c | 24 ++++++++++++++++++++++++ qobject/qfloat.c | 8 ++++++++ qobject/qint.c | 8 ++++++++ qobject/qlist.c | 25 +++++++++++++++++++++++++ qobject/qnull.c | 5 +++++ qobject/qobject.c | 30 ++++++++++++++++++++++++++++++ qobject/qstring.c | 9 +++++++++ 16 files changed, 134 insertions(+)