1 /* 2 * QList Module 3 * 4 * Copyright (C) 2009 Red Hat Inc. 5 * 6 * Authors: 7 * Luiz Capitulino <lcapitulino@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 10 * See the COPYING.LIB file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qapi/qmp/qbool.h" 15 #include "qapi/qmp/qlist.h" 16 #include "qapi/qmp/qnull.h" 17 #include "qapi/qmp/qnum.h" 18 #include "qapi/qmp/qstring.h" 19 #include "qemu/queue.h" 20 #include "qemu-common.h" 21 22 /** 23 * qlist_new(): Create a new QList 24 * 25 * Return strong reference. 26 */ 27 QList *qlist_new(void) 28 { 29 QList *qlist; 30 31 qlist = g_malloc(sizeof(*qlist)); 32 qobject_init(QOBJECT(qlist), QTYPE_QLIST); 33 QTAILQ_INIT(&qlist->head); 34 35 return qlist; 36 } 37 38 static void qlist_copy_elem(QObject *obj, void *opaque) 39 { 40 QList *dst = opaque; 41 42 qobject_incref(obj); 43 qlist_append_obj(dst, obj); 44 } 45 46 QList *qlist_copy(QList *src) 47 { 48 QList *dst = qlist_new(); 49 50 qlist_iter(src, qlist_copy_elem, dst); 51 52 return dst; 53 } 54 55 /** 56 * qlist_append_obj(): Append an QObject into QList 57 * 58 * NOTE: ownership of 'value' is transferred to the QList 59 */ 60 void qlist_append_obj(QList *qlist, QObject *value) 61 { 62 QListEntry *entry; 63 64 entry = g_malloc(sizeof(*entry)); 65 entry->value = value; 66 67 QTAILQ_INSERT_TAIL(&qlist->head, entry, next); 68 } 69 70 void qlist_append_int(QList *qlist, int64_t value) 71 { 72 qlist_append(qlist, qnum_from_int(value)); 73 } 74 75 void qlist_append_bool(QList *qlist, bool value) 76 { 77 qlist_append(qlist, qbool_from_bool(value)); 78 } 79 80 void qlist_append_str(QList *qlist, const char *value) 81 { 82 qlist_append(qlist, qstring_from_str(value)); 83 } 84 85 void qlist_append_null(QList *qlist) 86 { 87 qlist_append(qlist, qnull()); 88 } 89 90 /** 91 * qlist_iter(): Iterate over all the list's stored values. 92 * 93 * This function allows the user to provide an iterator, which will be 94 * called for each stored value in the list. 95 */ 96 void qlist_iter(const QList *qlist, 97 void (*iter)(QObject *obj, void *opaque), void *opaque) 98 { 99 QListEntry *entry; 100 101 QTAILQ_FOREACH(entry, &qlist->head, next) 102 iter(entry->value, opaque); 103 } 104 105 QObject *qlist_pop(QList *qlist) 106 { 107 QListEntry *entry; 108 QObject *ret; 109 110 if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { 111 return NULL; 112 } 113 114 entry = QTAILQ_FIRST(&qlist->head); 115 QTAILQ_REMOVE(&qlist->head, entry, next); 116 117 ret = entry->value; 118 g_free(entry); 119 120 return ret; 121 } 122 123 QObject *qlist_peek(QList *qlist) 124 { 125 QListEntry *entry; 126 127 if (qlist == NULL || QTAILQ_EMPTY(&qlist->head)) { 128 return NULL; 129 } 130 131 entry = QTAILQ_FIRST(&qlist->head); 132 133 return entry->value; 134 } 135 136 int qlist_empty(const QList *qlist) 137 { 138 return QTAILQ_EMPTY(&qlist->head); 139 } 140 141 static void qlist_size_iter(QObject *obj, void *opaque) 142 { 143 size_t *count = opaque; 144 (*count)++; 145 } 146 147 size_t qlist_size(const QList *qlist) 148 { 149 size_t count = 0; 150 qlist_iter(qlist, qlist_size_iter, &count); 151 return count; 152 } 153 154 /** 155 * qobject_to_qlist(): Convert a QObject into a QList 156 */ 157 QList *qobject_to_qlist(const QObject *obj) 158 { 159 if (!obj || qobject_type(obj) != QTYPE_QLIST) { 160 return NULL; 161 } 162 return container_of(obj, QList, base); 163 } 164 165 /** 166 * qlist_is_equal(): Test whether the two QLists are equal 167 * 168 * In order to be considered equal, the respective two objects at each 169 * index of the two lists have to compare equal (regarding 170 * qobject_is_equal()), and both lists have to have the same number of 171 * elements. 172 * That means both lists have to contain equal objects in equal order. 173 */ 174 bool qlist_is_equal(const QObject *x, const QObject *y) 175 { 176 const QList *list_x = qobject_to_qlist(x); 177 const QList *list_y = qobject_to_qlist(y); 178 const QListEntry *entry_x, *entry_y; 179 180 entry_x = qlist_first(list_x); 181 entry_y = qlist_first(list_y); 182 183 while (entry_x && entry_y) { 184 if (!qobject_is_equal(qlist_entry_obj(entry_x), 185 qlist_entry_obj(entry_y))) 186 { 187 return false; 188 } 189 190 entry_x = qlist_next(entry_x); 191 entry_y = qlist_next(entry_y); 192 } 193 194 return !entry_x && !entry_y; 195 } 196 197 /** 198 * qlist_destroy_obj(): Free all the memory allocated by a QList 199 */ 200 void qlist_destroy_obj(QObject *obj) 201 { 202 QList *qlist; 203 QListEntry *entry, *next_entry; 204 205 assert(obj != NULL); 206 qlist = qobject_to_qlist(obj); 207 208 QTAILQ_FOREACH_SAFE(entry, &qlist->head, next, next_entry) { 209 QTAILQ_REMOVE(&qlist->head, entry, next); 210 qobject_decref(entry->value); 211 g_free(entry); 212 } 213 214 g_free(qlist); 215 } 216