|  | /* | 
|  | * QList Module | 
|  | * | 
|  | * Copyright (C) 2009 Red Hat Inc. | 
|  | * | 
|  | * Authors: | 
|  | *  Luiz Capitulino <lcapitulino@redhat.com> | 
|  | * | 
|  | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | 
|  | * See the COPYING.LIB file in the top-level directory. | 
|  | */ | 
|  |  | 
|  | #include "qlist.h" | 
|  | #include "qobject.h" | 
|  | #include "qemu-queue.h" | 
|  | #include "qemu-common.h" | 
|  |  | 
|  | static void qlist_destroy_obj(QObject *obj); | 
|  |  | 
|  | static const QType qlist_type = { | 
|  | .code = QTYPE_QLIST, | 
|  | .destroy = qlist_destroy_obj, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * qlist_new(): Create a new QList | 
|  | * | 
|  | * Return strong reference. | 
|  | */ | 
|  | QList *qlist_new(void) | 
|  | { | 
|  | QList *qlist; | 
|  |  | 
|  | qlist = g_malloc(sizeof(*qlist)); | 
|  | QTAILQ_INIT(&qlist->head); | 
|  | QOBJECT_INIT(qlist, &qlist_type); | 
|  |  | 
|  | return qlist; | 
|  | } | 
|  |  | 
|  | static void qlist_copy_elem(QObject *obj, void *opaque) | 
|  | { | 
|  | QList *dst = opaque; | 
|  |  | 
|  | qobject_incref(obj); | 
|  | qlist_append_obj(dst, obj); | 
|  | } | 
|  |  | 
|  | QList *qlist_copy(QList *src) | 
|  | { | 
|  | QList *dst = qlist_new(); | 
|  |  | 
|  | qlist_iter(src, qlist_copy_elem, dst); | 
|  |  | 
|  | return dst; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * qlist_append_obj(): Append an QObject into QList | 
|  | * | 
|  | * NOTE: ownership of 'value' is transferred to the QList | 
|  | */ | 
|  | void qlist_append_obj(QList *qlist, QObject *value) | 
|  | { | 
|  | QListEntry *entry; | 
|  |  | 
|  | entry = g_malloc(sizeof(*entry)); | 
|  | entry->value = value; | 
|  |  | 
|  | QTAILQ_INSERT_TAIL(&qlist->head, entry, next); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * qlist_iter(): Iterate over all the list's stored values. | 
|  | * | 
|  | * This function allows the user to provide an iterator, which will be | 
|  | * called for each stored value in the list. | 
|  | */ | 
|  | void qlist_iter(const QList *qlist, | 
|  | void (*iter)(QObject *obj, void *opaque), void *opaque) | 
|  | { | 
|  | QListEntry *entry; | 
|  |  | 
|  | QTAILQ_FOREACH(entry, &qlist->head, next) | 
|  | iter(entry->value, opaque); | 
|  | } | 
|  |  | 
|  | QObject *qlist_pop(QList *qlist) | 
|  | { | 
|  | QListEntry *entry; | 
|  | QObject *ret; | 
|  |  | 
|  | if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | entry = QTAILQ_FIRST(&qlist->head); | 
|  | QTAILQ_REMOVE(&qlist->head, entry, next); | 
|  |  | 
|  | ret = entry->value; | 
|  | g_free(entry); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | QObject *qlist_peek(QList *qlist) | 
|  | { | 
|  | QListEntry *entry; | 
|  | QObject *ret; | 
|  |  | 
|  | if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | entry = QTAILQ_FIRST(&qlist->head); | 
|  |  | 
|  | ret = entry->value; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int qlist_empty(const QList *qlist) | 
|  | { | 
|  | return QTAILQ_EMPTY(&qlist->head); | 
|  | } | 
|  |  | 
|  | static void qlist_size_iter(QObject *obj, void *opaque) | 
|  | { | 
|  | size_t *count = opaque; | 
|  | (*count)++; | 
|  | } | 
|  |  | 
|  | size_t qlist_size(const QList *qlist) | 
|  | { | 
|  | size_t count = 0; | 
|  | qlist_iter(qlist, qlist_size_iter, &count); | 
|  | return count; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * qobject_to_qlist(): Convert a QObject into a QList | 
|  | */ | 
|  | QList *qobject_to_qlist(const QObject *obj) | 
|  | { | 
|  | if (qobject_type(obj) != QTYPE_QLIST) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return container_of(obj, QList, base); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * qlist_destroy_obj(): Free all the memory allocated by a QList | 
|  | */ | 
|  | static void qlist_destroy_obj(QObject *obj) | 
|  | { | 
|  | QList *qlist; | 
|  | QListEntry *entry, *next_entry; | 
|  |  | 
|  | assert(obj != NULL); | 
|  | qlist = qobject_to_qlist(obj); | 
|  |  | 
|  | QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) { | 
|  | QTAILQ_REMOVE(&qlist->head, entry, next); | 
|  | qobject_decref(entry->value); | 
|  | g_free(entry); | 
|  | } | 
|  |  | 
|  | g_free(qlist); | 
|  | } |