mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 19:15:36 +00:00
qobject: use a QObjectBase_ struct
By moving the base fields to a QObjectBase_, QObject can be a type which also has a 'base' field. This allows writing a generic QOBJECT() macro that will work with any QObject type, including QObject itself. The container_of() macro ensures that the object to cast has a QObjectBase_ base field, giving some type safety guarantees. QObject must have no members but QObjectBase_ base, or else QOBJECT() breaks. QObjectBase_ is not a typedef and uses a trailing underscore to make it obvious it is not for normal use and to avoid potential abuse. Backports commit 3d3eacaeccaab718ea0e2ddaa578bfae9e311c59 from qemu
This commit is contained in:
parent
2ca916e106
commit
f4b3c5d0bd
|
@ -18,7 +18,7 @@
|
|||
#include "qapi/qmp/qobject.h"
|
||||
|
||||
struct QBool {
|
||||
QObject_HEAD;
|
||||
struct QObjectBase_ base;
|
||||
bool value;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef struct QDictEntry {
|
|||
} QDictEntry;
|
||||
|
||||
struct QDict {
|
||||
QObject_HEAD;
|
||||
struct QObjectBase_ base;
|
||||
size_t size;
|
||||
QLIST_HEAD(,QDictEntry) table[QDICT_BUCKET_MAX];
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ typedef struct QListEntry {
|
|||
} QListEntry;
|
||||
|
||||
struct QList {
|
||||
QObject_HEAD;
|
||||
struct QObjectBase_ base;
|
||||
QTAILQ_HEAD(,QListEntry) head;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "qapi/qmp/qobject.h"
|
||||
|
||||
struct QNull {
|
||||
QObject base;
|
||||
struct QObjectBase_ base;
|
||||
};
|
||||
|
||||
extern QNull qnull_;
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef enum {
|
|||
* convert under the hood.
|
||||
*/
|
||||
struct QNum {
|
||||
QObject base;
|
||||
struct QObjectBase_ base;
|
||||
QNumKind kind;
|
||||
union {
|
||||
int64_t i64;
|
||||
|
|
|
@ -34,17 +34,21 @@
|
|||
|
||||
#include "qapi/qapi-builtin-types.h"
|
||||
|
||||
struct QObject {
|
||||
/* Not for use outside include/qapi/qmp/ */
|
||||
struct QObjectBase_ {
|
||||
QType type;
|
||||
size_t refcnt;
|
||||
};
|
||||
|
||||
/* Objects definitions must include this */
|
||||
#define QObject_HEAD \
|
||||
QObject base
|
||||
/* this struct must have no other members than base */
|
||||
struct QObject {
|
||||
struct QObjectBase_ base;
|
||||
};
|
||||
|
||||
/* Get the 'base' part of an object */
|
||||
#define QOBJECT(obj) (&(obj)->base)
|
||||
#define QOBJECT(obj) ({ \
|
||||
typeof(obj) _obj = (obj); \
|
||||
_obj ? container_of(&(_obj)->base, QObject, base) : NULL; \
|
||||
})
|
||||
|
||||
/* High-level interface for qobject_incref() */
|
||||
#define QINCREF(obj) \
|
||||
|
@ -72,8 +76,8 @@ QEMU_BUILD_BUG_MSG(QTYPE__MAX != 7,
|
|||
static inline void qobject_init(QObject *obj, QType type)
|
||||
{
|
||||
assert(QTYPE_NONE < type && type < QTYPE__MAX);
|
||||
obj->refcnt = 1;
|
||||
obj->type = type;
|
||||
obj->base.refcnt = 1;
|
||||
obj->base.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,8 +85,9 @@ static inline void qobject_init(QObject *obj, QType type)
|
|||
*/
|
||||
static inline void qobject_incref(QObject *obj)
|
||||
{
|
||||
if (obj)
|
||||
obj->refcnt++;
|
||||
if (obj) {
|
||||
obj->base.refcnt++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,8 +110,8 @@ void qobject_destroy(QObject *obj);
|
|||
*/
|
||||
static inline void qobject_decref(QObject *obj)
|
||||
{
|
||||
assert(!obj || obj->refcnt);
|
||||
if (obj && --obj->refcnt == 0) {
|
||||
assert(!obj || obj->base.refcnt);
|
||||
if (obj && --obj->base.refcnt == 0) {
|
||||
qobject_destroy(obj);
|
||||
}
|
||||
}
|
||||
|
@ -116,8 +121,8 @@ static inline void qobject_decref(QObject *obj)
|
|||
*/
|
||||
static inline QType qobject_type(const QObject *obj)
|
||||
{
|
||||
assert(QTYPE_NONE < obj->type && obj->type < QTYPE__MAX);
|
||||
return obj->type;
|
||||
assert(QTYPE_NONE < obj->base.type && obj->base.type < QTYPE__MAX);
|
||||
return obj->base.type;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "qapi/qmp/qobject.h"
|
||||
|
||||
struct QString {
|
||||
QObject_HEAD;
|
||||
struct QObjectBase_ base;
|
||||
char *string;
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
|
|
|
@ -36,9 +36,9 @@ static void (*qdestroy[QTYPE__MAX])(QObject *) = {
|
|||
|
||||
void qobject_destroy(QObject *obj)
|
||||
{
|
||||
assert(!obj->refcnt);
|
||||
assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
|
||||
qdestroy[obj->type](obj);
|
||||
assert(!obj->base.refcnt);
|
||||
assert(QTYPE_QNULL < obj->base.type && obj->base.type < QTYPE__MAX);
|
||||
qdestroy[obj->base.type](obj);
|
||||
}
|
||||
|
||||
static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
|
||||
|
@ -60,12 +60,11 @@ bool qobject_is_equal(const QObject *x, const QObject *y)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!x || !y || x->type != y->type) {
|
||||
if (!x || !y || x->base.type != y->base.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX);
|
||||
assert(QTYPE_NONE < x->base.type && x->base.type < QTYPE__MAX);
|
||||
|
||||
return qis_equal[x->type](x, y);
|
||||
return qis_equal[x->base.type](x, y);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue