* [Qemu-devel] [PATCH 04/29] Introduce QDict
@ 2015-09-12 0:22 Programmingkid
2015-09-12 4:10 ` Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Programmingkid @ 2015-09-12 0:22 UTC (permalink / raw)
To: lcapitulino; +Cc: qemu-devel qemu-devel, qemu-discuss
Could you make a tutorial on how to use the QDict type?
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH v3 00/29] QMonitor
@ 2009-08-28 18:27 Luiz Capitulino
2009-08-28 18:27 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-28 18:27 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
Hi there,
Another respin, the most important change being a rebase against
latest push bomb.
Please review, as it's easy to make mistakes on conflict fixes.
Changelog, description and diffstat follows.
changelog
---------
V2 -> V3
- Rebase against latest master
- Updated configure changes to new style (Juan's advice)
V1 -> V2
- Renamed some macros to be more OOP-like
- New refcounts terminology by Paulo Bonzini
- QDict:
o use sys-queue for the linked list
o replace qdict_add() by qdict_put()
o rename qdict_exists() to qdict_haskey()
o add qdict_get_try_int() and qdict_get_try_str()
- QInt
o drop 'export' functions
o rename qint_from_int64() to qint_from_int()
- Other small changes
V0 -> V1
- Make QType structs const
- New macros: QOBJECT_INIT(), QDECREF()/QINCREF(), QType_HEAD
- qobject_to_*() should return NULL if type doesn't match
description
------------
Basically, this series introduces high-level data types (QInt, QString,
QDict) and port all Monitor command handlers to use them to receive
arguments.
The following points should be observed:
o Object life cycle management: I'm using refcouting for this
o QString's get: QString exports a function called qstring_get_str(), this
function returns a *pointer* to the stored string. A better API would
return a copy instead, but it would be too much work and error-prone to go
over all handlers and put a qemu_free() in the right place.
Handlers only want quick and read-only access to strings anyway, so
returning a pointer makes handlers' code a lot simpler.
o unit-testing: I have written unit-tests for all the new code and have an
off-tree suite for the Monitor's parsing code. I was in doubt if I should
submit this work... I did, but it's in the end of the series, if people
don't like this it can be easily dropped.
Monitor's suite is not in the series because I couldn't make it build
"in tree".
While reviewing the series is important to bear in mind that all my
design decisions were based on the need of the current and most important
users of the API: monitor command handlers.
Thanks for reading this all! :)
Makefile | 5 +
check-qdict.c | 365 ++++
check-qint.c | 110 ++
check-qstring.c | 100 +
configure | 31 +
console.h | 3 +-
hw/pci-hotplug.c | 15 +-
migration.c | 12 +-
migration.h | 9 +-
monitor.c | 457 +++---
monitor.h | 1 +
net.c | 25 +-
net.h | 13 +-
qdict-test-data.txt | 4999 +++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.c | 297 +++
qdict.h | 42 +
qemu-monitor.hx | 109 +-
qint.c | 66 +
qint.h | 16 +
qobject.h | 109 ++
qstring.c | 73 +
qstring.h | 15 +
savevm.c | 6 +-
sysemu.h | 15 +-
vl.c | 11 +-
25 files changed, 6578 insertions(+), 326 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-28 18:27 [Qemu-devel] [PATCH v3 00/29] QMonitor Luiz Capitulino
@ 2009-08-28 18:27 ` Luiz Capitulino
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-28 18:27 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
QDict is a high-level dictionary data type that can be used to store a
collection of QObjects. A unique key is associated with only one
QObject.
The following functions are available:
- qdict_new() Create a new QDict
- qdict_put() Add a new 'key:object' pair
- qdict_get() Get the QObject of a given key
- qdict_del() Delete a 'key:object' pair
- qdict_size() Return the size of the dictionary
- qdict_haskey() Check if a given 'key' exists
Some high-level helpers to operate on QStrings and QInts objects
are also provided.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
Makefile | 2 +-
qdict.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.h | 42 +++++++++
qobject.h | 1 +
4 files changed, 341 insertions(+), 1 deletions(-)
create mode 100644 qdict.c
create mode 100644 qdict.h
diff --git a/Makefile b/Makefile
index d7618ba..983fe39 100644
--- a/Makefile
+++ b/Makefile
@@ -91,7 +91,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
obj-y += qemu-char.o aio.o net-checksum.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o ssi.o
-obj-y += qint.o qstring.o
+obj-y += qint.o qstring.o qdict.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qdict.c b/qdict.c
new file mode 100644
index 0000000..cffd23d
--- /dev/null
+++ b/qdict.c
@@ -0,0 +1,297 @@
+/*
+ * QDict data type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qint.h"
+#include "qdict.h"
+#include "qstring.h"
+#include "qobject.h"
+#include "sys-queue.h"
+#include "qemu-common.h"
+
+static const QType qdict_type;
+
+/**
+ * qdict_new(): Create a new QDict
+ *
+ * Return strong reference.
+ */
+QDict *qdict_new(void)
+{
+ QDict *qdict;
+
+ qdict = qemu_mallocz(sizeof(*qdict));
+ QOBJECT_INIT(qdict, &qdict_type);
+
+ return qdict;
+}
+
+/**
+ * qobject_to_qdict(): Convert a QObject into a QDict
+ */
+QDict *qobject_to_qdict(const QObject *obj)
+{
+ if (qobject_type(obj) != QTYPE_QDICT)
+ return NULL;
+
+ return container_of(obj, QDict, base);
+}
+
+/**
+ * tdb_hash(): based on the hash agorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+ value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value)
+{
+ QDictEntry *entry;
+
+ entry = qemu_mallocz(sizeof(*entry));
+ entry->key = qemu_strdup(key);
+ entry->value = value;
+
+ return entry;
+}
+
+/**
+ * qdict_find(): List lookup function
+ */
+static QDictEntry *qdict_find(const QDict *qdict,
+ const char *key, unsigned int hash)
+{
+ QDictEntry *entry;
+
+ LIST_FOREACH(entry, &qdict->table[hash], next)
+ if (!strcmp(entry->key, key))
+ return entry;
+
+ return NULL;
+}
+
+/**
+ * qdict_put_obj(): Put a new QObject into the dictionary
+ *
+ * Insert the pair 'key:value' into 'qdict', if 'key' already exists
+ * its 'value' will be replaced.
+ *
+ * This is done by freeing the reference to the stored QObject and
+ * storing the new one in the same entry.
+ *
+ * NOTE: ownership of 'value' is transferred to the QDict
+ */
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
+{
+ unsigned int hash;
+ QDictEntry *entry;
+
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ entry = qdict_find(qdict, key, hash);
+ if (entry) {
+ /* replace key's value */
+ qobject_decref(entry->value);
+ entry->value = value;
+ } else {
+ /* allocate a new entry */
+ entry = alloc_entry(key, value);
+ LIST_INSERT_HEAD(&qdict->table[hash], entry, next);
+ }
+
+ qdict->size++;
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return a weak reference to the QObject associated with 'key' if
+ * 'key' is present in the dictionary, NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+ return (entry == NULL ? NULL : entry->value);
+}
+
+/**
+ * qdict_haskey(): Check if 'key' exists
+ *
+ * Return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_haskey(const QDict *qdict, const char *key)
+{
+ unsigned int hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ return (qdict_find(qdict, key, hash) == NULL ? 0 : 1);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+ return qdict->size;
+}
+
+/**
+ * qdict_get_obj(): Get a QObject of a specific type
+ */
+static QObject *qdict_get_obj(const QDict *qdict, const char *key,
+ qtype_code type)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ assert(obj != NULL);
+ assert(qobject_type(obj) == type);
+
+ return obj;
+}
+
+/**
+ * qdict_get_int(): Get an integer mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ *
+ * Return integer mapped by 'key'.
+ */
+int64_t qdict_get_int(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QString object.
+ *
+ * Return pointer to the string mapped by 'key'.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING);
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_get_try_int(): Try to get integer mapped by 'key'
+ *
+ * Return integer mapped by 'key', if it is not present in
+ * the dictionary or if the stored object is not of QInt type
+ * 'err_value' will be returned.
+ */
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+ int64_t err_value)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj || qobject_type(obj) != QTYPE_QINT)
+ return err_value;
+
+ return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_try_str(): Try to get a pointer to the stored string
+ * mapped by 'key'
+ *
+ * Return a pointer to the string mapped by 'key', if it is not present
+ * in the dictionary or if the stored object is not of QString type
+ * NULL will be returned.
+ */
+const char *qdict_get_try_str(const QDict *qdict, const char *key)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj || qobject_type(obj) != QTYPE_QSTRING)
+ return NULL;
+
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+ assert(e != NULL);
+ assert(e->key != NULL);
+ assert(e->value != NULL);
+
+ qobject_decref(e->value);
+ qemu_free(e->key);
+ qemu_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+ if (entry) {
+ LIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ qdict->size--;
+ }
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+static void qdict_destroy_obj(QObject *obj)
+{
+ int i;
+ QDict *qdict;
+
+ assert(obj != NULL);
+ qdict = qobject_to_qdict(obj);
+
+ for (i = 0; i < QDICT_HASH_SIZE; i++) {
+ QDictEntry *entry = LIST_FIRST(&qdict->table[i]);
+ while (entry) {
+ QDictEntry *tmp = LIST_NEXT(entry, next);
+ LIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ entry = tmp;
+ }
+ }
+
+ qemu_free(qdict);
+}
+
+static const QType qdict_type = {
+ .code = QTYPE_QDICT,
+ .destroy = qdict_destroy_obj,
+};
diff --git a/qdict.h b/qdict.h
new file mode 100644
index 0000000..613d163
--- /dev/null
+++ b/qdict.h
@@ -0,0 +1,42 @@
+#ifndef QDICT_H
+#define QDICT_H
+
+#include "qobject.h"
+#include "sys-queue.h"
+#include <stdint.h>
+
+#define QDICT_HASH_SIZE 512
+
+typedef struct QDictEntry {
+ char *key;
+ QObject *value;
+ LIST_ENTRY(QDictEntry) next;
+} QDictEntry;
+
+typedef struct QDict {
+ QObject_HEAD;
+ size_t size;
+ LIST_HEAD(,QDictEntry) table[QDICT_HASH_SIZE];
+} QDict;
+
+/* Object API */
+QDict *qdict_new(void);
+size_t qdict_size(const QDict *qdict);
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value);
+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);
+
+/* Helper to qdict_put_obj(), accepts any object */
+#define qdict_put(qdict, key, obj) \
+ qdict_put_obj(qdict, key, QOBJECT(obj))
+
+/* High level helpers */
+int64_t qdict_get_int(const QDict *qdict, const char *key);
+const char *qdict_get_str(const QDict *qdict, const char *key);
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+ int64_t err_value);
+const char *qdict_get_try_str(const QDict *qdict, const char *key);
+
+#endif /* QDICT_H */
diff --git a/qobject.h b/qobject.h
index d4eeb3f..39b8649 100644
--- a/qobject.h
+++ b/qobject.h
@@ -39,6 +39,7 @@ typedef enum {
QTYPE_NONE,
QTYPE_QINT,
QTYPE_QSTRING,
+ QTYPE_QDICT,
} qtype_code;
struct QObject;
--
1.6.4.1.184.g2e117
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH v2 00/29] QMonitor
@ 2009-08-26 17:05 Luiz Capitulino
2009-08-26 17:05 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-26 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
Hi there,
This new version of the QMonitor series has more simplifications,
renames and improvements.
Most changes are because of simplifications on QInt, please review
carefully its implementation and usage.
Changelog, description and diffstat follows.
changelog
---------
V1 -> V2
- Renamed some macros to be more OOP-like
- New refcounts terminology by Paulo Bonzini
- QDict:
o use sys-queue for the linked list
o replace qdict_add() by qdict_put()
o rename qdict_exists() to qdict_haskey()
o add qdict_get_try_int() and qdict_get_try_str()
- QInt
o drop 'export' functions
o rename qint_from_int64() to qint_from_int()
- Other small changes
V0 -> V1
- Make QType structs const
- New macros: QOBJECT_INIT(), QDECREF()/QINCREF(), QType_HEAD
- qobject_to_*() should return NULL if type doesn't match
description
------------
Basically, this series introduces high-level data types (QInt, QString,
QDict) and port all Monitor command handlers to use them to receive
arguments.
The following points should be observed:
o Object life cycle management: I'm using refcouting for this
o QString's get: QString exports a function called qstring_get_str(), this
function returns a *pointer* to the stored string. A better API would
return a copy instead, but it would be too much work and error-prone to go
over all handlers and put a qemu_free() in the right place.
Handlers only want quick and read-only access to strings anyway, so
returning a pointer makes handlers' code a lot simpler.
o unit-testing: I have written unit-tests for all the new code and have an
off-tree suite for the Monitor's parsing code. I was in doubt if I should
submit this work... I did, but it's in the end of the series, if people
don't like this it can be easily dropped.
Monitor's suite is not in the series because I couldn't make it build
"in tree".
While reviewing the series is important to bear in mind that all my
design decisions were based on the need of the current and most important
users of the API: monitor command handlers.
Thanks for reading this all! :)
Makefile | 8 +
check-qdict.c | 365 ++++
check-qint.c | 110 ++
check-qstring.c | 100 +
configure | 32 +
console.h | 3 +-
hw/pci-hotplug.c | 15 +-
migration.c | 12 +-
migration.h | 9 +-
monitor.c | 448 +++---
monitor.h | 1 +
net.c | 25 +-
net.h | 13 +-
qdict-test-data.txt | 4999 +++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.c | 297 +++
qdict.h | 42 +
qemu-monitor.hx | 109 +-
qint.c | 66 +
qint.h | 16 +
qobject.h | 111 ++
qstring.c | 73 +
qstring.h | 15 +
savevm.c | 13 +-
sysemu.h | 18 +-
vl.c | 13 +-
25 files changed, 6587 insertions(+), 326 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-26 17:05 [Qemu-devel] [PATCH v2 00/29] QMonitor Luiz Capitulino
@ 2009-08-26 17:05 ` Luiz Capitulino
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-26 17:05 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
QDict is a high-level dictionary data type that can be used to store a
collection of QObjects. A unique key is associated with only one
QObject.
The following functions are available:
- qdict_new() Create a new QDict
- qdict_put() Add a new 'key:object' pair
- qdict_get() Get the QObject of a given key
- qdict_del() Delete a 'key:object' pair
- qdict_size() Return the size of the dictionary
- qdict_haskey() Check if a given 'key' exists
Some high-level helpers to operate on QStrings and QInts objects
are also provided.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
Makefile | 2 +-
qdict.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.h | 42 +++++++++
qobject.h | 1 +
4 files changed, 341 insertions(+), 1 deletions(-)
create mode 100644 qdict.c
create mode 100644 qdict.h
diff --git a/Makefile b/Makefile
index 6307278..bdb6b39 100644
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
obj-y += qemu-char.o aio.o net-checksum.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o ssi.o
-obj-y += qint.o qstring.o
+obj-y += qint.o qstring.o qdict.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qdict.c b/qdict.c
new file mode 100644
index 0000000..cffd23d
--- /dev/null
+++ b/qdict.c
@@ -0,0 +1,297 @@
+/*
+ * QDict data type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qint.h"
+#include "qdict.h"
+#include "qstring.h"
+#include "qobject.h"
+#include "sys-queue.h"
+#include "qemu-common.h"
+
+static const QType qdict_type;
+
+/**
+ * qdict_new(): Create a new QDict
+ *
+ * Return strong reference.
+ */
+QDict *qdict_new(void)
+{
+ QDict *qdict;
+
+ qdict = qemu_mallocz(sizeof(*qdict));
+ QOBJECT_INIT(qdict, &qdict_type);
+
+ return qdict;
+}
+
+/**
+ * qobject_to_qdict(): Convert a QObject into a QDict
+ */
+QDict *qobject_to_qdict(const QObject *obj)
+{
+ if (qobject_type(obj) != QTYPE_QDICT)
+ return NULL;
+
+ return container_of(obj, QDict, base);
+}
+
+/**
+ * tdb_hash(): based on the hash agorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+ value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value)
+{
+ QDictEntry *entry;
+
+ entry = qemu_mallocz(sizeof(*entry));
+ entry->key = qemu_strdup(key);
+ entry->value = value;
+
+ return entry;
+}
+
+/**
+ * qdict_find(): List lookup function
+ */
+static QDictEntry *qdict_find(const QDict *qdict,
+ const char *key, unsigned int hash)
+{
+ QDictEntry *entry;
+
+ LIST_FOREACH(entry, &qdict->table[hash], next)
+ if (!strcmp(entry->key, key))
+ return entry;
+
+ return NULL;
+}
+
+/**
+ * qdict_put_obj(): Put a new QObject into the dictionary
+ *
+ * Insert the pair 'key:value' into 'qdict', if 'key' already exists
+ * its 'value' will be replaced.
+ *
+ * This is done by freeing the reference to the stored QObject and
+ * storing the new one in the same entry.
+ *
+ * NOTE: ownership of 'value' is transferred to the QDict
+ */
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
+{
+ unsigned int hash;
+ QDictEntry *entry;
+
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ entry = qdict_find(qdict, key, hash);
+ if (entry) {
+ /* replace key's value */
+ qobject_decref(entry->value);
+ entry->value = value;
+ } else {
+ /* allocate a new entry */
+ entry = alloc_entry(key, value);
+ LIST_INSERT_HEAD(&qdict->table[hash], entry, next);
+ }
+
+ qdict->size++;
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return a weak reference to the QObject associated with 'key' if
+ * 'key' is present in the dictionary, NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+ return (entry == NULL ? NULL : entry->value);
+}
+
+/**
+ * qdict_haskey(): Check if 'key' exists
+ *
+ * Return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_haskey(const QDict *qdict, const char *key)
+{
+ unsigned int hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ return (qdict_find(qdict, key, hash) == NULL ? 0 : 1);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+ return qdict->size;
+}
+
+/**
+ * qdict_get_obj(): Get a QObject of a specific type
+ */
+static QObject *qdict_get_obj(const QDict *qdict, const char *key,
+ qtype_code type)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ assert(obj != NULL);
+ assert(qobject_type(obj) == type);
+
+ return obj;
+}
+
+/**
+ * qdict_get_int(): Get an integer mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ *
+ * Return integer mapped by 'key'.
+ */
+int64_t qdict_get_int(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QString object.
+ *
+ * Return pointer to the string mapped by 'key'.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING);
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_get_try_int(): Try to get integer mapped by 'key'
+ *
+ * Return integer mapped by 'key', if it is not present in
+ * the dictionary or if the stored object is not of QInt type
+ * 'err_value' will be returned.
+ */
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+ int64_t err_value)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj || qobject_type(obj) != QTYPE_QINT)
+ return err_value;
+
+ return qint_get_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_try_str(): Try to get a pointer to the stored string
+ * mapped by 'key'
+ *
+ * Return a pointer to the string mapped by 'key', if it is not present
+ * in the dictionary or if the stored object is not of QString type
+ * NULL will be returned.
+ */
+const char *qdict_get_try_str(const QDict *qdict, const char *key)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj || qobject_type(obj) != QTYPE_QSTRING)
+ return NULL;
+
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+ assert(e != NULL);
+ assert(e->key != NULL);
+ assert(e->value != NULL);
+
+ qobject_decref(e->value);
+ qemu_free(e->key);
+ qemu_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+ QDictEntry *entry;
+
+ entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+ if (entry) {
+ LIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ qdict->size--;
+ }
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+static void qdict_destroy_obj(QObject *obj)
+{
+ int i;
+ QDict *qdict;
+
+ assert(obj != NULL);
+ qdict = qobject_to_qdict(obj);
+
+ for (i = 0; i < QDICT_HASH_SIZE; i++) {
+ QDictEntry *entry = LIST_FIRST(&qdict->table[i]);
+ while (entry) {
+ QDictEntry *tmp = LIST_NEXT(entry, next);
+ LIST_REMOVE(entry, next);
+ qentry_destroy(entry);
+ entry = tmp;
+ }
+ }
+
+ qemu_free(qdict);
+}
+
+static const QType qdict_type = {
+ .code = QTYPE_QDICT,
+ .destroy = qdict_destroy_obj,
+};
diff --git a/qdict.h b/qdict.h
new file mode 100644
index 0000000..613d163
--- /dev/null
+++ b/qdict.h
@@ -0,0 +1,42 @@
+#ifndef QDICT_H
+#define QDICT_H
+
+#include "qobject.h"
+#include "sys-queue.h"
+#include <stdint.h>
+
+#define QDICT_HASH_SIZE 512
+
+typedef struct QDictEntry {
+ char *key;
+ QObject *value;
+ LIST_ENTRY(QDictEntry) next;
+} QDictEntry;
+
+typedef struct QDict {
+ QObject_HEAD;
+ size_t size;
+ LIST_HEAD(,QDictEntry) table[QDICT_HASH_SIZE];
+} QDict;
+
+/* Object API */
+QDict *qdict_new(void);
+size_t qdict_size(const QDict *qdict);
+void qdict_put_obj(QDict *qdict, const char *key, QObject *value);
+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);
+
+/* Helper to qdict_put_obj(), accepts any object */
+#define qdict_put(qdict, key, obj) \
+ qdict_put_obj(qdict, key, QOBJECT(obj))
+
+/* High level helpers */
+int64_t qdict_get_int(const QDict *qdict, const char *key);
+const char *qdict_get_str(const QDict *qdict, const char *key);
+int64_t qdict_get_try_int(const QDict *qdict, const char *key,
+ int64_t err_value);
+const char *qdict_get_try_str(const QDict *qdict, const char *key);
+
+#endif /* QDICT_H */
diff --git a/qobject.h b/qobject.h
index 4f84cec..f17397e 100644
--- a/qobject.h
+++ b/qobject.h
@@ -41,6 +41,7 @@ typedef enum {
QTYPE_NONE,
QTYPE_QINT,
QTYPE_QSTRING,
+ QTYPE_QDICT,
} qtype_code;
struct QObject;
--
1.6.4.1.184.g2e117
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH v1 00/29] QMonitor
@ 2009-08-19 23:07 Luiz Capitulino
2009-08-19 23:07 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-19 23:07 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
Hi there,
This is a new version of my QMonitor series, it has some simplifications
and changes suggested by Avi.
Changelog and full introduction follow.
changelog
---------
V0 -> V1
- Make QType structs const
- New macros: QOBJECT_INIT(), QDECREF()/QINCREF(), QType_HEAD
- qobject_to_*() should return NULL if type doesn't match
introduction
------------
Basically, this series introduces high-level data types (QInt, QString,
QDict) and port all Monitor command handlers to use them to receive
arguments.
The following points should be observed:
o Object life cycle management: I'm using refcouting and have adopted Python's
approach, this means that you only do refcount when needed, more info here:
http://docs.python.org/c-api/intro.html#objects-types-and-reference-counts
This approach makes command handlers code simpler.
o QString's get: QString exports a function called qstring_get_str(), this
function returns a *pointer* to the stored string. A better API would
return a copy instead, but it would be too much work and error-prone to go
over all handlers and put a qemu_free() in the right place.
Handlers only want quick and read-only access to strings anyway, so
returning a pointer makes handlers' code a lot simpler.
o unit-testing: I have written unit-tests for all the new code and have an
off-tree suite for the Monitor's parsing code. I was in doubt if I should
submit this work... I did, but it's in the end of the series, if people
don't like this it can be easily dropped.
Monitor's suite is not in the series because I couldn't make it build
"in tree".
While reviewing the series is important to bear in mind that all my
design decisions were based on the need of the current and most important
users of the API: monitor command handlers.
Thanks for reading this all. :)
Makefile | 8 +
check-qdict.c | 347 ++++
check-qint.c | 124 ++
check-qstring.c | 100 +
configure | 32 +
console.h | 3 +-
hw/pci-hotplug.c | 15 +-
migration.c | 12 +-
migration.h | 9 +-
monitor.c | 463 +++---
monitor.h | 1 +
net.c | 25 +-
net.h | 13 +-
qdict-test-data.txt | 4999 +++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.c | 311 ++++
qdict.h | 40 +
qemu-monitor.hx | 109 +-
qint.c | 92 +
qint.h | 20 +
qobject.h | 113 ++
qstring.c | 73 +
qstring.h | 16 +
savevm.c | 13 +-
sysemu.h | 18 +-
vl.c | 13 +-
25 files changed, 6643 insertions(+), 326 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-19 23:07 [Qemu-devel] [PATCH v1 00/29] QMonitor Luiz Capitulino
@ 2009-08-19 23:07 ` Luiz Capitulino
2009-08-24 15:40 ` Markus Armbruster
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-19 23:07 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
QDict is a high-level dictionary data type that can be used to store a
collection of QObjects. A unique key is associated with only one
QObject.
The following functions are available:
- qdict_new() Create a new dictionary
- qdict_add() Add a new 'key:object' pair
- qdict_get() Get the QObject of a given key
- qdict_del() Delete a 'key:object' pair
- qdict_size() Return the size of the dictionary
- qdict_exists() Check if a given 'key' exists
Some high-level helpers to operate on QStrings and QInts objects
are also provided.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
Makefile | 2 +-
qdict.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.h | 40 ++++++++
qobject.h | 1 +
4 files changed, 353 insertions(+), 1 deletions(-)
create mode 100644 qdict.c
create mode 100644 qdict.h
diff --git a/Makefile b/Makefile
index 6100b35..40fe1b7 100644
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
obj-y += qemu-char.o aio.o net-checksum.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o ssi.o
-obj-y += qint.o qstring.o
+obj-y += qint.o qstring.o qdict.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qdict.c b/qdict.c
new file mode 100644
index 0000000..3901c48
--- /dev/null
+++ b/qdict.c
@@ -0,0 +1,311 @@
+/*
+ * QDict data type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qdict.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static const QType qdict_type;
+
+/**
+ * qdict_new(): Create a new dictionary data-type
+ *
+ * Return new reference.
+ */
+QDict *qdict_new(void)
+{
+ QDict *qdict;
+
+ qdict = qemu_mallocz(sizeof(*qdict));
+ QOBJECT_INIT(qdict, &qdict_type);
+
+ return qdict;
+}
+
+/**
+ * qobject_to_qdict(): Convert a QObject into a QDict
+ */
+QDict *qobject_to_qdict(const QObject *obj)
+{
+ if (qobject_type(obj) != QTYPE_QDICT)
+ return NULL;
+
+ return container_of(obj, QDict, base);
+}
+
+/**
+ * tdb_hash(): based on the hash agorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+ value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value,
+ QDictEntry *next)
+{
+ QDictEntry *entry;
+
+ entry = qemu_malloc(sizeof(*entry));
+ entry->key = qemu_strdup(key);
+ entry->value = value;
+ entry->next = next;
+
+ return entry;
+}
+
+/**
+ * qdict_find(): Low-level lookup function
+ */
+static void *qdict_find(const QDict *qdict,
+ const char *key, unsigned int hash)
+{
+ QDictEntry *e;
+
+ for (e = qdict->table[hash]; e; e = e->next)
+ if (!strcmp(e->key, key))
+ return e->value;
+ return NULL;
+}
+
+/**
+ * qdict_add(): Add a new object into the dictionary
+ *
+ * Add the pair 'key:value' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'value'
+ */
+void qdict_add(QDict *qdict, const char *key, QObject *value)
+{
+ unsigned int hash;
+ QDictEntry *entry;
+
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ if (qdict_find(qdict, key, hash)) {
+ /* Don't add again if it's already there */
+ return;
+ }
+
+ entry = alloc_entry(key, value, qdict->table[hash]);
+ qdict->table[hash] = entry;
+ qdict->size++;
+}
+
+/**
+ * qdict_add_qint(): Add a new QInt into the dictionary
+ *
+ * Add the pair 'key:qint' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'qi'
+ */
+void qdict_add_qint(QDict *qdict, const char *key, QInt *qi)
+{
+ qdict_add(qdict, key, QOBJECT(qi));
+}
+
+/**
+ * qdict_add_qstring(): Add a new QString into the dictionary
+ *
+ * Add the pair 'key:qstring' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'qs'
+ */
+void qdict_add_qstring(QDict *qdict, const char *key, QString *qs)
+{
+ qdict_add(qdict, key, QOBJECT(qs));
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return borrowed reference to QObject if 'key' exists,
+ * NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+ return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+ return qdict->size;
+}
+
+/**
+ * qdict_get_obj(): Get a QObject of a specific type.
+ */
+static QObject *qdict_get_obj(const QDict *qdict, const char *key,
+ qtype_code type)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ assert(obj != NULL);
+ assert(qobject_type(obj) == type);
+
+ return obj;
+}
+
+/**
+ * qdict_get_int(): Get an int value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+int qdict_get_int(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_uint32(): Get an uint32_t value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+uint32_t qdict_get_uint32(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_uint32(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_uint64(): Get an uint64_t value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+uint64_t qdict_get_uint64(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_uint64(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * return the string pointer on success, NULL if 'key' doesn't
+ * exist.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj)
+ return NULL;
+
+ assert(qobject_type(obj) == QTYPE_QSTRING);
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_exists(): Check if 'key' exists
+ *
+ * return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_exists(const QDict *qdict, const char *key)
+{
+ QDictEntry *e;
+
+ for (e = qdict->table[tdb_hash(key) % QDICT_HASH_SIZE]; e; e = e->next)
+ if (!strcmp(e->key, key))
+ return 1;
+ return 0;
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+ assert(e != NULL);
+ assert(e->key != NULL);
+ assert(e->value != NULL);
+
+ qobject_decref(e->value);
+ qemu_free(e->key);
+ qemu_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+ unsigned int hash;
+ QDictEntry *e, *prev;
+
+ prev = NULL;
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ for (e = qdict->table[hash]; e; e = e->next) {
+ if (!strcmp(e->key, key)) {
+ if (!prev)
+ qdict->table[hash] = e->next;
+ else
+ prev->next = e->next;
+ qentry_destroy(e);
+ qdict->size--;
+ return;
+ }
+ prev = e;
+ }
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+static void qdict_destroy_obj(QObject *obj)
+{
+ int i;
+ QDict *qdict;
+
+ assert(obj != NULL);
+ qdict = qobject_to_qdict(obj);
+
+ for (i = 0; i < QDICT_HASH_SIZE; i++) {
+ QDictEntry *e = qdict->table[i];
+ while (e) {
+ QDictEntry *tmp = e->next;
+ qentry_destroy(e);
+ e = tmp;
+ }
+ }
+
+ qemu_free(qdict);
+}
+
+static const QType qdict_type = {
+ .code = QTYPE_QDICT,
+ .destroy = qdict_destroy_obj,
+};
diff --git a/qdict.h b/qdict.h
new file mode 100644
index 0000000..911117f
--- /dev/null
+++ b/qdict.h
@@ -0,0 +1,40 @@
+#ifndef QDICT_H
+#define QDICT_H
+
+#include "qint.h"
+#include "qstring.h"
+#include "qobject.h"
+#include <stddef.h>
+
+#define QDICT_HASH_SIZE 512
+
+typedef struct QDictEntry {
+ char *key;
+ QObject *value;
+ struct QDictEntry *next;
+} QDictEntry;
+
+typedef struct QDict {
+ QType_HEAD
+ size_t size;
+ QDictEntry *table[QDICT_HASH_SIZE];
+} QDict;
+
+/* Object API */
+QDict *qdict_new(void);
+size_t qdict_size(const QDict *qdict);
+void qdict_add(QDict *qdict, const char *key, QObject *value);
+void qdict_del(QDict *qdict, const char *key);
+int qdict_exists(const QDict *qdict, const char *key);
+QObject *qdict_get(const QDict *qdict, const char *key);
+QDict *qobject_to_qdict(const QObject *obj);
+
+/* High level helpers */
+int qdict_get_int(const QDict *qdict, const char *key);
+uint32_t qdict_get_uint32(const QDict *qdict, const char *key);
+uint64_t qdict_get_uint64(const QDict *qdict, const char *key);
+const char *qdict_get_str(const QDict *qdict, const char *key);
+void qdict_add_qint(QDict *qdict, const char *key, QInt *qi);
+void qdict_add_qstring(QDict *qdict, const char *key, QString *qs);
+
+#endif /* QDICT_H */
diff --git a/qobject.h b/qobject.h
index 61cd4a3..0835a28 100644
--- a/qobject.h
+++ b/qobject.h
@@ -43,6 +43,7 @@ typedef enum {
QTYPE_NONE,
QTYPE_QINT,
QTYPE_QSTRING,
+ QTYPE_QDICT,
} qtype_code;
struct QObject;
--
1.6.4.67.gea5b1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-19 23:07 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
@ 2009-08-24 15:40 ` Markus Armbruster
2009-08-24 16:11 ` Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Markus Armbruster @ 2009-08-24 15:40 UTC (permalink / raw)
To: Luiz Capitulino; +Cc: aliguori, qemu-devel, avi
Luiz Capitulino <lcapitulino@redhat.com> writes:
> QDict is a high-level dictionary data type that can be used to store a
> collection of QObjects. A unique key is associated with only one
> QObject.
>
> The following functions are available:
>
> - qdict_new() Create a new dictionary
> - qdict_add() Add a new 'key:object' pair
> - qdict_get() Get the QObject of a given key
> - qdict_del() Delete a 'key:object' pair
> - qdict_size() Return the size of the dictionary
> - qdict_exists() Check if a given 'key' exists
>
> Some high-level helpers to operate on QStrings and QInts objects
> are also provided.
>
> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> ---
> Makefile | 2 +-
> qdict.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> qdict.h | 40 ++++++++
> qobject.h | 1 +
> 4 files changed, 353 insertions(+), 1 deletions(-)
> create mode 100644 qdict.c
> create mode 100644 qdict.h
>
> diff --git a/Makefile b/Makefile
[...]
> diff --git a/qdict.c b/qdict.c
> new file mode 100644
> index 0000000..3901c48
> --- /dev/null
> +++ b/qdict.c
> @@ -0,0 +1,311 @@
> +/*
> + * QDict data type.
> + *
> + * Copyright (C) 2009 Red Hat Inc.
> + *
> + * Authors:
> + * Luiz Capitulino <lcapitulino@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#include "qdict.h"
> +#include "qobject.h"
> +#include "qemu-common.h"
> +
> +static const QType qdict_type;
> +
> +/**
> + * qdict_new(): Create a new dictionary data-type
> + *
> + * Return new reference.
> + */
> +QDict *qdict_new(void)
> +{
> + QDict *qdict;
> +
> + qdict = qemu_mallocz(sizeof(*qdict));
> + QOBJECT_INIT(qdict, &qdict_type);
> +
> + return qdict;
> +}
> +
> +/**
> + * qobject_to_qdict(): Convert a QObject into a QDict
> + */
> +QDict *qobject_to_qdict(const QObject *obj)
> +{
> + if (qobject_type(obj) != QTYPE_QDICT)
> + return NULL;
> +
> + return container_of(obj, QDict, base);
> +}
> +
> +/**
> + * tdb_hash(): based on the hash agorithm from gdbm, via tdb
> + * (from module-init-tools)
> + */
> +static unsigned int tdb_hash(const char *name)
> +{
> + unsigned value; /* Used to compute the hash value. */
> + unsigned i; /* Used to cycle through random values. */
> +
> + /* Set the initial value from the key size. */
> + for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
> + value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
> +
> + return (1103515243 * value + 12345);
> +}
> +
> +/**
> + * alloc_entry(): allocate a new QDictEntry
> + */
> +static QDictEntry *alloc_entry(const char *key, QObject *value,
> + QDictEntry *next)
> +{
> + QDictEntry *entry;
> +
> + entry = qemu_malloc(sizeof(*entry));
> + entry->key = qemu_strdup(key);
> + entry->value = value;
> + entry->next = next;
> +
> + return entry;
> +}
> +
> +/**
> + * qdict_find(): Low-level lookup function
> + */
> +static void *qdict_find(const QDict *qdict,
> + const char *key, unsigned int hash)
> +{
> + QDictEntry *e;
> +
> + for (e = qdict->table[hash]; e; e = e->next)
> + if (!strcmp(e->key, key))
> + return e->value;
> + return NULL;
> +}
> +
> +/**
> + * qdict_add(): Add a new object into the dictionary
> + *
> + * Add the pair 'key:value' into qdict. Does nothing if 'key' already
> + * exist.
> + *
> + * NOTE: this function 'steals' a reference to 'value'
> + */
> +void qdict_add(QDict *qdict, const char *key, QObject *value)
So this steals unless KEY already exists. Callers who need to know
whether they still own VALUE afterwards have to check whether KEY exists
before. Hmm. What about returning whether the reference was stolen?
Or just steal unconditionally.
Same for the qdict_add_FOO().
Is it okay to add a null value?
> +{
> + unsigned int hash;
> + QDictEntry *entry;
> +
> + hash = tdb_hash(key) % QDICT_HASH_SIZE;
> + if (qdict_find(qdict, key, hash)) {
> + /* Don't add again if it's already there */
> + return;
> + }
> +
> + entry = alloc_entry(key, value, qdict->table[hash]);
> + qdict->table[hash] = entry;
> + qdict->size++;
> +}
> +
> +/**
> + * qdict_add_qint(): Add a new QInt into the dictionary
> + *
> + * Add the pair 'key:qint' into qdict. Does nothing if 'key' already
> + * exist.
> + *
> + * NOTE: this function 'steals' a reference to 'qi'
> + */
> +void qdict_add_qint(QDict *qdict, const char *key, QInt *qi)
> +{
> + qdict_add(qdict, key, QOBJECT(qi));
> +}
> +
> +/**
> + * qdict_add_qstring(): Add a new QString into the dictionary
> + *
> + * Add the pair 'key:qstring' into qdict. Does nothing if 'key' already
> + * exist.
> + *
> + * NOTE: this function 'steals' a reference to 'qs'
> + */
> +void qdict_add_qstring(QDict *qdict, const char *key, QString *qs)
> +{
> + qdict_add(qdict, key, QOBJECT(qs));
> +}
> +
> +/**
> + * qdict_get(): Lookup for a given 'key'
> + *
> + * Return borrowed reference to QObject if 'key' exists,
> + * NULL otherwise.
> + */
> +QObject *qdict_get(const QDict *qdict, const char *key)
> +{
> + return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
> +}
> +
> +/**
> + * qdict_size(): Return the size of the dictionary
> + */
> +size_t qdict_size(const QDict *qdict)
> +{
> + return qdict->size;
> +}
> +
> +/**
> + * qdict_get_obj(): Get a QObject of a specific type.
> + */
> +static QObject *qdict_get_obj(const QDict *qdict, const char *key,
> + qtype_code type)
> +{
> + QObject *obj;
> +
> + obj = qdict_get(qdict, key);
> + assert(obj != NULL);
> + assert(qobject_type(obj) == type);
> +
> + return obj;
> +}
> +
> +/**
> + * qdict_get_int(): Get an int value mapped by 'key'
> + *
> + * This function assumes that 'key' exists and it stores a
> + * QInt object.
> + */
> +int qdict_get_int(const QDict *qdict, const char *key)
> +{
> + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> + return qint_to_int(qobject_to_qint(obj));
> +}
> +
> +/**
> + * qdict_get_uint32(): Get an uint32_t value mapped by 'key'
> + *
> + * This function assumes that 'key' exists and it stores a
> + * QInt object.
> + */
> +uint32_t qdict_get_uint32(const QDict *qdict, const char *key)
> +{
> + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> + return qint_to_uint32(qobject_to_qint(obj));
> +}
> +
> +/**
> + * qdict_get_uint64(): Get an uint64_t value mapped by 'key'
> + *
> + * This function assumes that 'key' exists and it stores a
> + * QInt object.
> + */
> +uint64_t qdict_get_uint64(const QDict *qdict, const char *key)
> +{
> + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> + return qint_to_uint64(qobject_to_qint(obj));
> +}
> +
> +/**
> + * qdict_get_str(): Get a pointer to the stored string mapped
> + * by 'key'
> + *
> + * return the string pointer on success, NULL if 'key' doesn't
> + * exist.
> + */
> +const char *qdict_get_str(const QDict *qdict, const char *key)
> +{
> + QObject *obj;
> +
> + obj = qdict_get(qdict, key);
> + if (!obj)
> + return NULL;
> +
> + assert(qobject_type(obj) == QTYPE_QSTRING);
> + return qstring_get_str(qobject_to_qstring(obj));
> +}
> +
> +/**
> + * qdict_exists(): Check if 'key' exists
> + *
> + * return 1 if 'key' exists in the dict, 0 otherwise
> + */
> +int qdict_exists(const QDict *qdict, const char *key)
> +{
> + QDictEntry *e;
> +
> + for (e = qdict->table[tdb_hash(key) % QDICT_HASH_SIZE]; e; e = e->next)
> + if (!strcmp(e->key, key))
> + return 1;
> + return 0;
> +}
Duplicates the loop from qdict_find().
What about
return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE) != NULL
Doesn't work if qdict can contain (key, value) pairs with null values.
Not a problem if qdict_find() returned e (of type QDictEntry *) instead
of e->value (of type void *).
> +
> +/**
> + * qentry_destroy(): Free all the memory allocated by a QDictEntry
> + */
> +static void qentry_destroy(QDictEntry *e)
> +{
> + assert(e != NULL);
> + assert(e->key != NULL);
> + assert(e->value != NULL);
> +
> + qobject_decref(e->value);
> + qemu_free(e->key);
> + qemu_free(e);
> +}
> +
> +/**
> + * qdict_del(): Delete a 'key:value' pair from the dictionary
> + *
> + * This will destroy all data allocated by this entry.
> + */
> +void qdict_del(QDict *qdict, const char *key)
> +{
> + unsigned int hash;
> + QDictEntry *e, *prev;
> +
> + prev = NULL;
> + hash = tdb_hash(key) % QDICT_HASH_SIZE;
> + for (e = qdict->table[hash]; e; e = e->next) {
> + if (!strcmp(e->key, key)) {
> + if (!prev)
> + qdict->table[hash] = e->next;
> + else
> + prev->next = e->next;
> + qentry_destroy(e);
> + qdict->size--;
> + return;
> + }
> + prev = e;
> + }
> +}
Duplicates the loop from qdict_find(). I figure it could quse
qdict_find() if it returned e instead of e->value.
> +
> +/**
> + * qdict_destroy_obj(): Free all the memory allocated by a QDict
> + */
> +static void qdict_destroy_obj(QObject *obj)
> +{
> + int i;
> + QDict *qdict;
> +
> + assert(obj != NULL);
> + qdict = qobject_to_qdict(obj);
> +
> + for (i = 0; i < QDICT_HASH_SIZE; i++) {
> + QDictEntry *e = qdict->table[i];
> + while (e) {
> + QDictEntry *tmp = e->next;
> + qentry_destroy(e);
> + e = tmp;
> + }
> + }
> +
> + qemu_free(qdict);
> +}
> +
> +static const QType qdict_type = {
> + .code = QTYPE_QDICT,
> + .destroy = qdict_destroy_obj,
> +};
> diff --git a/qdict.h b/qdict.h
[...]
> diff --git a/qobject.h b/qobject.h
[...]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-24 15:40 ` Markus Armbruster
@ 2009-08-24 16:11 ` Luiz Capitulino
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-24 16:11 UTC (permalink / raw)
To: Markus Armbruster; +Cc: aliguori, qemu-devel, avi
On Mon, 24 Aug 2009 17:40:44 +0200
Markus Armbruster <armbru@redhat.com> wrote:
> Luiz Capitulino <lcapitulino@redhat.com> writes:
>
> > QDict is a high-level dictionary data type that can be used to store a
> > collection of QObjects. A unique key is associated with only one
> > QObject.
> >
> > The following functions are available:
> >
> > - qdict_new() Create a new dictionary
> > - qdict_add() Add a new 'key:object' pair
> > - qdict_get() Get the QObject of a given key
> > - qdict_del() Delete a 'key:object' pair
> > - qdict_size() Return the size of the dictionary
> > - qdict_exists() Check if a given 'key' exists
> >
> > Some high-level helpers to operate on QStrings and QInts objects
> > are also provided.
> >
> > Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
> > ---
> > Makefile | 2 +-
> > qdict.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > qdict.h | 40 ++++++++
> > qobject.h | 1 +
> > 4 files changed, 353 insertions(+), 1 deletions(-)
> > create mode 100644 qdict.c
> > create mode 100644 qdict.h
> >
> > diff --git a/Makefile b/Makefile
> [...]
> > diff --git a/qdict.c b/qdict.c
> > new file mode 100644
> > index 0000000..3901c48
> > --- /dev/null
> > +++ b/qdict.c
> > @@ -0,0 +1,311 @@
> > +/*
> > + * QDict data type.
> > + *
> > + * Copyright (C) 2009 Red Hat Inc.
> > + *
> > + * Authors:
> > + * Luiz Capitulino <lcapitulino@redhat.com>
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2. See
> > + * the COPYING file in the top-level directory.
> > + */
> > +
> > +#include "qdict.h"
> > +#include "qobject.h"
> > +#include "qemu-common.h"
> > +
> > +static const QType qdict_type;
> > +
> > +/**
> > + * qdict_new(): Create a new dictionary data-type
> > + *
> > + * Return new reference.
> > + */
> > +QDict *qdict_new(void)
> > +{
> > + QDict *qdict;
> > +
> > + qdict = qemu_mallocz(sizeof(*qdict));
> > + QOBJECT_INIT(qdict, &qdict_type);
> > +
> > + return qdict;
> > +}
> > +
> > +/**
> > + * qobject_to_qdict(): Convert a QObject into a QDict
> > + */
> > +QDict *qobject_to_qdict(const QObject *obj)
> > +{
> > + if (qobject_type(obj) != QTYPE_QDICT)
> > + return NULL;
> > +
> > + return container_of(obj, QDict, base);
> > +}
> > +
> > +/**
> > + * tdb_hash(): based on the hash agorithm from gdbm, via tdb
> > + * (from module-init-tools)
> > + */
> > +static unsigned int tdb_hash(const char *name)
> > +{
> > + unsigned value; /* Used to compute the hash value. */
> > + unsigned i; /* Used to cycle through random values. */
> > +
> > + /* Set the initial value from the key size. */
> > + for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
> > + value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
> > +
> > + return (1103515243 * value + 12345);
> > +}
> > +
> > +/**
> > + * alloc_entry(): allocate a new QDictEntry
> > + */
> > +static QDictEntry *alloc_entry(const char *key, QObject *value,
> > + QDictEntry *next)
> > +{
> > + QDictEntry *entry;
> > +
> > + entry = qemu_malloc(sizeof(*entry));
> > + entry->key = qemu_strdup(key);
> > + entry->value = value;
> > + entry->next = next;
> > +
> > + return entry;
> > +}
> > +
> > +/**
> > + * qdict_find(): Low-level lookup function
> > + */
> > +static void *qdict_find(const QDict *qdict,
> > + const char *key, unsigned int hash)
> > +{
> > + QDictEntry *e;
> > +
> > + for (e = qdict->table[hash]; e; e = e->next)
> > + if (!strcmp(e->key, key))
> > + return e->value;
> > + return NULL;
> > +}
> > +
> > +/**
> > + * qdict_add(): Add a new object into the dictionary
> > + *
> > + * Add the pair 'key:value' into qdict. Does nothing if 'key' already
> > + * exist.
> > + *
> > + * NOTE: this function 'steals' a reference to 'value'
> > + */
> > +void qdict_add(QDict *qdict, const char *key, QObject *value)
>
> So this steals unless KEY already exists. Callers who need to know
> whether they still own VALUE afterwards have to check whether KEY exists
> before. Hmm. What about returning whether the reference was stolen?
>
> Or just steal unconditionally.
Avi has suggested having a qdict_put() with that semantics, I'm
already working on this.
> Same for the qdict_add_FOO().
>
> Is it okay to add a null value?
No, although this is not enforced at insertion time. I'll fix
in new qdict_put().
Note that supporting this is just a matter of checking if
a certain struct member if null at destroy time, but I don't
see uses for it as we have agreed the dict will only store
QObjects.
> > +{
> > + unsigned int hash;
> > + QDictEntry *entry;
> > +
> > + hash = tdb_hash(key) % QDICT_HASH_SIZE;
> > + if (qdict_find(qdict, key, hash)) {
> > + /* Don't add again if it's already there */
> > + return;
> > + }
> > +
> > + entry = alloc_entry(key, value, qdict->table[hash]);
> > + qdict->table[hash] = entry;
> > + qdict->size++;
> > +}
> > +
> > +/**
> > + * qdict_add_qint(): Add a new QInt into the dictionary
> > + *
> > + * Add the pair 'key:qint' into qdict. Does nothing if 'key' already
> > + * exist.
> > + *
> > + * NOTE: this function 'steals' a reference to 'qi'
> > + */
> > +void qdict_add_qint(QDict *qdict, const char *key, QInt *qi)
> > +{
> > + qdict_add(qdict, key, QOBJECT(qi));
> > +}
> > +
> > +/**
> > + * qdict_add_qstring(): Add a new QString into the dictionary
> > + *
> > + * Add the pair 'key:qstring' into qdict. Does nothing if 'key' already
> > + * exist.
> > + *
> > + * NOTE: this function 'steals' a reference to 'qs'
> > + */
> > +void qdict_add_qstring(QDict *qdict, const char *key, QString *qs)
> > +{
> > + qdict_add(qdict, key, QOBJECT(qs));
> > +}
> > +
> > +/**
> > + * qdict_get(): Lookup for a given 'key'
> > + *
> > + * Return borrowed reference to QObject if 'key' exists,
> > + * NULL otherwise.
> > + */
> > +QObject *qdict_get(const QDict *qdict, const char *key)
> > +{
> > + return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
> > +}
> > +
> > +/**
> > + * qdict_size(): Return the size of the dictionary
> > + */
> > +size_t qdict_size(const QDict *qdict)
> > +{
> > + return qdict->size;
> > +}
> > +
> > +/**
> > + * qdict_get_obj(): Get a QObject of a specific type.
> > + */
> > +static QObject *qdict_get_obj(const QDict *qdict, const char *key,
> > + qtype_code type)
> > +{
> > + QObject *obj;
> > +
> > + obj = qdict_get(qdict, key);
> > + assert(obj != NULL);
> > + assert(qobject_type(obj) == type);
> > +
> > + return obj;
> > +}
> > +
> > +/**
> > + * qdict_get_int(): Get an int value mapped by 'key'
> > + *
> > + * This function assumes that 'key' exists and it stores a
> > + * QInt object.
> > + */
> > +int qdict_get_int(const QDict *qdict, const char *key)
> > +{
> > + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> > + return qint_to_int(qobject_to_qint(obj));
> > +}
> > +
> > +/**
> > + * qdict_get_uint32(): Get an uint32_t value mapped by 'key'
> > + *
> > + * This function assumes that 'key' exists and it stores a
> > + * QInt object.
> > + */
> > +uint32_t qdict_get_uint32(const QDict *qdict, const char *key)
> > +{
> > + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> > + return qint_to_uint32(qobject_to_qint(obj));
> > +}
> > +
> > +/**
> > + * qdict_get_uint64(): Get an uint64_t value mapped by 'key'
> > + *
> > + * This function assumes that 'key' exists and it stores a
> > + * QInt object.
> > + */
> > +uint64_t qdict_get_uint64(const QDict *qdict, const char *key)
> > +{
> > + QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
> > + return qint_to_uint64(qobject_to_qint(obj));
> > +}
> > +
> > +/**
> > + * qdict_get_str(): Get a pointer to the stored string mapped
> > + * by 'key'
> > + *
> > + * return the string pointer on success, NULL if 'key' doesn't
> > + * exist.
> > + */
> > +const char *qdict_get_str(const QDict *qdict, const char *key)
> > +{
> > + QObject *obj;
> > +
> > + obj = qdict_get(qdict, key);
> > + if (!obj)
> > + return NULL;
> > +
> > + assert(qobject_type(obj) == QTYPE_QSTRING);
> > + return qstring_get_str(qobject_to_qstring(obj));
> > +}
> > +
> > +/**
> > + * qdict_exists(): Check if 'key' exists
> > + *
> > + * return 1 if 'key' exists in the dict, 0 otherwise
> > + */
> > +int qdict_exists(const QDict *qdict, const char *key)
> > +{
> > + QDictEntry *e;
> > +
> > + for (e = qdict->table[tdb_hash(key) % QDICT_HASH_SIZE]; e; e = e->next)
> > + if (!strcmp(e->key, key))
> > + return 1;
> > + return 0;
> > +}
>
> Duplicates the loop from qdict_find().
>
> What about
>
> return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE) != NULL
>
> Doesn't work if qdict can contain (key, value) pairs with null values.
> Not a problem if qdict_find() returned e (of type QDictEntry *) instead
> of e->value (of type void *).
This code is somewhat different now and the duplication is already
gone, as I have ported QDict to use list functions from "sys-queue.h".
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH v0 00/29] QMonitor
@ 2009-08-13 13:49 Luiz Capitulino
2009-08-13 13:50 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
0 siblings, 1 reply; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-13 13:49 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
Hi there,
This is a new version of the 'monitor handlers new structure' work.
As the series is very different from my last submission I've renamed it
to QMonitor.
Basically, this series introduces high-level data types (QInt, QString,
QDict) and port all Monitor command handlers to use them to receive
arguments.
The following points should be observed:
o Object life cycle management: I'm using refcouting and have adopted Python's
approach, this means that you only do refcount when needed, more info here:
http://docs.python.org/c-api/intro.html#objects-types-and-reference-counts
This approach makes command handlers code simpler.
o QString's get: QString exports a function called qstring_get_str(), this
function returns a *pointer* to the stored string. A better API would
return a copy instead, but it would be too much work and error-prone to go
over all handlers and put a qemu_free() in the right place.
Handlers only want quick and read-only access to strings anyway, so
returning a pointer makes handlers' code a lot simpler.
o unit-testing: I have written unit-tests for all the new code and have an
off-tree suite for the Monitor's parsing code. I was in doubt if I should
submit this work... I did, but it's in the end of the series, if people
don't like this it can be easily dropped.
Monitor's suite is not in the series because I couldn't make it build
"in tree".
While reviewing the series is important to bear in mind that all my
design decisions were based on the need of the current and most important
users of the API: monitor command handlers.
Thanks for reading this all. :)
---
Makefile | 8 +
check-qdict.c | 347 ++++
check-qint.c | 124 ++
check-qstring.c | 100 +
configure | 32 +
console.h | 3 +-
hw/pci-hotplug.c | 15 +-
migration.c | 12 +-
migration.h | 9 +-
monitor.c | 463 +++---
monitor.h | 1 +
net.c | 25 +-
net.h | 13 +-
qdict-test-data.txt | 4999 +++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.c | 300 +++
qdict.h | 47 +
qemu-monitor.hx | 109 +-
qint.c | 81 +
qint.h | 27 +
qobject.h | 98 +
qstring.c | 62 +
qstring.h | 23 +
savevm.c | 13 +-
sysemu.h | 18 +-
vl.c | 13 +-
25 files changed, 6616 insertions(+), 326 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [PATCH 04/29] Introduce QDict
2009-08-13 13:49 [Qemu-devel] [PATCH v0 00/29] QMonitor Luiz Capitulino
@ 2009-08-13 13:50 ` Luiz Capitulino
0 siblings, 0 replies; 9+ messages in thread
From: Luiz Capitulino @ 2009-08-13 13:50 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, avi
QDict is a high-level dictionary data type that can be used to store a
collection of QObjects. A unique key is associated with only one
QObject.
The following functions are available:
- qdict_new() Create a new dictionary
- qdict_add() Add a new 'key:object' pair
- qdict_get() Get the QObject of a given key
- qdict_del() Delete a 'key:object' pair
- qdict_size() Return the size of the dictionary
- qdict_exists() Check if a given 'key' exists
Some high-level helpers to operate on QStrings and QInts objects
are also provided.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
Makefile | 2 +-
qdict.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
qdict.h | 47 ++++++++++
qobject.h | 1 +
4 files changed, 349 insertions(+), 1 deletions(-)
create mode 100644 qdict.c
create mode 100644 qdict.h
diff --git a/Makefile b/Makefile
index 47cc532..2310a31 100644
--- a/Makefile
+++ b/Makefile
@@ -90,7 +90,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
obj-y += qemu-char.o aio.o net-checksum.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o ssi.o
-obj-y += qint.o qstring.o
+obj-y += qint.o qstring.o qdict.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
diff --git a/qdict.c b/qdict.c
new file mode 100644
index 0000000..9a75e3c
--- /dev/null
+++ b/qdict.c
@@ -0,0 +1,300 @@
+/*
+ * QDict data type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qdict.h"
+#include "qobject.h"
+#include "qemu-common.h"
+
+static QType qdict_type;
+
+/**
+ * qdict_new(): Create a new dictionary data-type
+ *
+ * Return new reference.
+ */
+QDict *qdict_new(void)
+{
+ QDict *qdict;
+
+ qdict = qemu_mallocz(sizeof(*qdict));
+ qobject_init(QOBJECT(qdict), &qdict_type);
+
+ return qdict;
+}
+
+/**
+ * tdb_hash(): based on the hash agorithm from gdbm, via tdb
+ * (from module-init-tools)
+ */
+static unsigned int tdb_hash(const char *name)
+{
+ unsigned value; /* Used to compute the hash value. */
+ unsigned i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
+ value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/**
+ * alloc_entry(): allocate a new QDictEntry
+ */
+static QDictEntry *alloc_entry(const char *key, QObject *value,
+ QDictEntry *next)
+{
+ QDictEntry *entry;
+
+ entry = qemu_malloc(sizeof(*entry));
+ entry->key = qemu_strdup(key);
+ entry->value = value;
+ entry->next = next;
+
+ return entry;
+}
+
+/**
+ * qdict_find(): Low-level lookup function
+ */
+static void *qdict_find(const QDict *qdict,
+ const char *key, unsigned int hash)
+{
+ QDictEntry *e;
+
+ for (e = qdict->table[hash]; e; e = e->next)
+ if (!strcmp(e->key, key))
+ return e->value;
+ return NULL;
+}
+
+/**
+ * qdict_add(): Add a new object into the dictionary
+ *
+ * Add the pair 'key:value' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'value'
+ */
+void qdict_add(QDict *qdict, const char *key, QObject *value)
+{
+ unsigned int hash;
+ QDictEntry *entry;
+
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ if (qdict_find(qdict, key, hash)) {
+ /* Don't add again if it's already there */
+ return;
+ }
+
+ entry = alloc_entry(key, value, qdict->table[hash]);
+ qdict->table[hash] = entry;
+ qdict->size++;
+}
+
+/**
+ * qdict_add_qint(): Add a new QInt into the dictionary
+ *
+ * Add the pair 'key:qint' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'qi'
+ */
+void qdict_add_qint(QDict *qdict, const char *key, QInt *qi)
+{
+ qdict_add(qdict, key, QOBJECT(qi));
+}
+
+/**
+ * qdict_add_qstring(): Add a new QString into the dictionary
+ *
+ * Add the pair 'key:qstring' into qdict. Does nothing if 'key' already
+ * exist.
+ *
+ * NOTE: this function 'steals' a reference to 'qs'
+ */
+void qdict_add_qstring(QDict *qdict, const char *key, QString *qs)
+{
+ qdict_add(qdict, key, QOBJECT(qs));
+}
+
+/**
+ * qdict_get(): Lookup for a given 'key'
+ *
+ * Return borrowed reference to QObject if 'key' exists,
+ * NULL otherwise.
+ */
+QObject *qdict_get(const QDict *qdict, const char *key)
+{
+ return qdict_find(qdict, key, tdb_hash(key) % QDICT_HASH_SIZE);
+}
+
+/**
+ * qdict_size(): Return the size of the dictionary
+ */
+size_t qdict_size(const QDict *qdict)
+{
+ return qdict->size;
+}
+
+/**
+ * qdict_get_obj(): Get a QObject of a specific type.
+ */
+static QObject *qdict_get_obj(const QDict *qdict, const char *key,
+ qtype_code type)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ assert(obj != NULL);
+ assert(qobject_type(obj) == type);
+
+ return obj;
+}
+
+/**
+ * qdict_get_int(): Get an int value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+int qdict_get_int(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_int(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_uint32(): Get an uint32_t value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+uint32_t qdict_get_uint32(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_uint32(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_uint64(): Get an uint64_t value mapped by 'key'
+ *
+ * This function assumes that 'key' exists and it stores a
+ * QInt object.
+ */
+uint64_t qdict_get_uint64(const QDict *qdict, const char *key)
+{
+ QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
+ return qint_to_uint64(qobject_to_qint(obj));
+}
+
+/**
+ * qdict_get_str(): Get a pointer to the stored string mapped
+ * by 'key'
+ *
+ * return the string pointer on success, NULL if 'key' doesn't
+ * exist.
+ */
+const char *qdict_get_str(const QDict *qdict, const char *key)
+{
+ QObject *obj;
+
+ obj = qdict_get(qdict, key);
+ if (!obj)
+ return NULL;
+
+ assert(qobject_type(obj) == QTYPE_QSTRING);
+ return qstring_get_str(qobject_to_qstring(obj));
+}
+
+/**
+ * qdict_exists(): Check if 'key' exists
+ *
+ * return 1 if 'key' exists in the dict, 0 otherwise
+ */
+int qdict_exists(const QDict *qdict, const char *key)
+{
+ QDictEntry *e;
+
+ for (e = qdict->table[tdb_hash(key) % QDICT_HASH_SIZE]; e; e = e->next)
+ if (!strcmp(e->key, key))
+ return 1;
+ return 0;
+}
+
+/**
+ * qentry_destroy(): Free all the memory allocated by a QDictEntry
+ */
+static void qentry_destroy(QDictEntry *e)
+{
+ assert(e != NULL);
+ assert(e->key != NULL);
+ assert(e->value != NULL);
+
+ qobject_decref(e->value);
+ qemu_free(e->key);
+ qemu_free(e);
+}
+
+/**
+ * qdict_del(): Delete a 'key:value' pair from the dictionary
+ *
+ * This will destroy all data allocated by this entry.
+ */
+void qdict_del(QDict *qdict, const char *key)
+{
+ unsigned int hash;
+ QDictEntry *e, *prev;
+
+ prev = NULL;
+ hash = tdb_hash(key) % QDICT_HASH_SIZE;
+ for (e = qdict->table[hash]; e; e = e->next) {
+ if (!strcmp(e->key, key)) {
+ if (!prev)
+ qdict->table[hash] = e->next;
+ else
+ prev->next = e->next;
+ qentry_destroy(e);
+ qdict->size--;
+ return;
+ }
+ prev = e;
+ }
+}
+
+/**
+ * qdict_destroy_obj(): Free all the memory allocated by a QDict
+ */
+static void qdict_destroy_obj(QObject *obj)
+{
+ int i;
+ QDict *qdict;
+
+ assert(obj != NULL);
+ qdict = qobject_to_qdict(obj);
+
+ for (i = 0; i < QDICT_HASH_SIZE; i++) {
+ QDictEntry *e = qdict->table[i];
+ while (e) {
+ QDictEntry *tmp = e->next;
+ qentry_destroy(e);
+ e = tmp;
+ }
+ }
+
+ qemu_free(qdict);
+}
+
+static QType qdict_type = {
+ .code = QTYPE_QDICT,
+ .destroy = qdict_destroy_obj,
+};
diff --git a/qdict.h b/qdict.h
new file mode 100644
index 0000000..1500b8c
--- /dev/null
+++ b/qdict.h
@@ -0,0 +1,47 @@
+#ifndef QDICT_H
+#define QDICT_H
+
+#include "qint.h"
+#include "qstring.h"
+#include "qobject.h"
+#include <stddef.h>
+
+#define QDICT_HASH_SIZE 512
+
+typedef struct QDictEntry {
+ char *key;
+ QObject *value;
+ struct QDictEntry *next;
+} QDictEntry;
+
+typedef struct QDict {
+ QObject base;
+ size_t size;
+ QDictEntry *table[QDICT_HASH_SIZE];
+} QDict;
+
+/* Object API */
+QDict *qdict_new(void);
+size_t qdict_size(const QDict *qdict);
+void qdict_add(QDict *qdict, const char *key, QObject *value);
+void qdict_del(QDict *qdict, const char *key);
+int qdict_exists(const QDict *qdict, const char *key);
+QObject *qdict_get(const QDict *qdict, const char *key);
+
+/* High level helpers */
+int qdict_get_int(const QDict *qdict, const char *key);
+uint32_t qdict_get_uint32(const QDict *qdict, const char *key);
+uint64_t qdict_get_uint64(const QDict *qdict, const char *key);
+const char *qdict_get_str(const QDict *qdict, const char *key);
+void qdict_add_qint(QDict *qdict, const char *key, QInt *qi);
+void qdict_add_qstring(QDict *qdict, const char *key, QString *qs);
+
+/**
+ * qobject_to_qdict(): Convert a QObject into a QDict
+ */
+static inline QDict *qobject_to_qdict(const QObject *obj)
+{
+ return container_of(obj, QDict, base);
+}
+
+#endif /* QDICT_H */
diff --git a/qobject.h b/qobject.h
index c1bdae7..52df5ff 100644
--- a/qobject.h
+++ b/qobject.h
@@ -42,6 +42,7 @@ typedef enum {
QTYPE_NONE,
QTYPE_QINT,
QTYPE_QSTRING,
+ QTYPE_QDICT,
} qtype_code;
struct QObject;
--
1.6.4.67.gea5b1
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-09-12 12:08 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-12 0:22 [Qemu-devel] [PATCH 04/29] Introduce QDict Programmingkid
2015-09-12 4:10 ` Luiz Capitulino
2015-09-12 12:08 ` Programmingkid
-- strict thread matches above, loose matches on Subject: below --
2009-08-28 18:27 [Qemu-devel] [PATCH v3 00/29] QMonitor Luiz Capitulino
2009-08-28 18:27 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
2009-08-26 17:05 [Qemu-devel] [PATCH v2 00/29] QMonitor Luiz Capitulino
2009-08-26 17:05 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
2009-08-19 23:07 [Qemu-devel] [PATCH v1 00/29] QMonitor Luiz Capitulino
2009-08-19 23:07 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
2009-08-24 15:40 ` Markus Armbruster
2009-08-24 16:11 ` Luiz Capitulino
2009-08-13 13:49 [Qemu-devel] [PATCH v0 00/29] QMonitor Luiz Capitulino
2009-08-13 13:50 ` [Qemu-devel] [PATCH 04/29] Introduce QDict Luiz Capitulino
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).