diff --git a/src/common/Makefile.am b/src/common/Makefile.am index d521b0c..e5efb97 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -18,7 +18,8 @@ includedir = @includedir@/pulsecore/modules/droid include_HEADERS = include/droid/version.h \ include/droid/conversion.h \ include/droid/droid-config.h \ - include/droid/droid-util.h + include/droid/droid-util.h \ + include/droid/sllist.h pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libdroid-util.pc @@ -27,6 +28,7 @@ libdroid_util_la_SOURCES = droid-util.c \ droid-config.c \ conversion.c \ config-parser-xml.c \ + sllist.c \ droid-util-audio.h libdroid_util_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common $(SBJ_DEVICE_LDFLAGS) libdroid_util_la_LIBADD = $(AM_LIBADD) diff --git a/src/common/include/droid/sllist.h b/src/common/include/droid/sllist.h index eab6a71..0cc78cd 100644 --- a/src/common/include/droid/sllist.h +++ b/src/common/include/droid/sllist.h @@ -2,7 +2,7 @@ #define foosllistfoo /* - * Copyright (C) 2018 Jolla Ltd. + * Copyright (C) 2018-2022 Jolla Ltd. * * Contact: Juho Hämäläinen * @@ -22,6 +22,12 @@ * USA. */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + #define SLLIST_APPEND(t, head, item) \ do { \ item->next = NULL; \ @@ -46,4 +52,43 @@ i = NULL; \ } while (0) +typedef struct dm_list_entry dm_list_entry; +typedef struct dm_list dm_list; + +struct dm_list_entry { + struct dm_list_entry *next; + struct dm_list_entry *prev; + void *data; +}; + +struct dm_list { + struct dm_list_entry *head; + struct dm_list_entry *tail; + ssize_t size; +}; + +dm_list *dm_list_new(void); +void dm_list_free(dm_list *list, pa_free_cb_t free_cb); +bool dm_list_remove(dm_list *list, dm_list_entry *entry); +void dm_list_prepend(dm_list *list, void *data); +void dm_list_push_back(dm_list *list, void *data); +dm_list_entry *dm_list_last(dm_list *list); +void *dm_list_steal_first(dm_list *list); +ssize_t dm_list_size(dm_list *list); +void *dm_list_first_data(dm_list *list, void **state); +void *dm_list_next_data(dm_list *list, void **state); +/* For example + * dm_list *list; + * void *state; + * my_data *data; + * DM_LIST_FOREACH_DATA(data, list, state) { + * do_something_with_my(data); + * } + */ +#define DM_LIST_FOREACH_DATA(i, list, state) \ + for (i = dm_list_first_data(list, &(state)); state; i = dm_list_next_data(list, &(state))) +/* Access i->data */ +#define DM_LIST_FOREACH(i, list) \ + for (i = list->head; i; i = i->next) + #endif diff --git a/src/common/sllist.c b/src/common/sllist.c new file mode 100644 index 0000000..ebf343d --- /dev/null +++ b/src/common/sllist.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2022 Jolla Ltd. + * + * Contact: Juho Hämäläinen + * + * These PulseAudio Modules are free software; you can redistribute + * it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "droid/sllist.h" + +dm_list *dm_list_new(void) { + return pa_xnew0(dm_list, 1); +} + +void dm_list_free(dm_list *list, pa_free_cb_t free_cb) { + pa_assert(list); + + while (list->head) { + void *data = dm_list_steal_first(list); + + if (free_cb) + free_cb(data); + } + + pa_xfree(list); +} + +bool dm_list_remove(dm_list *list, dm_list_entry *entry) { + dm_list_entry *i; + bool removed = false; + + for (i = list->head; i; i = i->next) { + if (i == entry) { + removed = true; + if (list->head == entry) + list->head = entry->next; + if (list->tail == entry) + list->tail = entry->prev; + if (entry->next) + entry->next->prev = entry->prev; + if (entry->prev) + entry->prev->next = entry->next; + pa_xfree(entry); + break; + } + } + + return removed; +} + +void dm_list_prepend(dm_list *list, void *data) { + dm_list_entry *entry; + + pa_assert(list); + + entry = pa_xnew0(dm_list_entry, 1); + entry->data = data; + + if (!list->tail) + list->tail = entry; + + if (list->head) { + entry->next = list->head; + list->head->prev = entry; + } + + list->head = entry; + list->size++; +} + +void dm_list_push_back(dm_list *list, void *data) { + dm_list_entry *entry; + + pa_assert(list); + + entry = pa_xnew0(dm_list_entry, 1); + entry->data = data; + + if (!list->head) + list->head = entry; + + if (list->tail) { + list->tail->next = entry; + entry->prev = list->tail; + } + + list->tail = entry; + list->size++; +} + +dm_list_entry *dm_list_last(dm_list *list) { + pa_assert(list); + + return list->tail; +} + +void *dm_list_steal_first(dm_list *list) { + dm_list_entry *entry; + void *data = NULL; + + pa_assert(list); + + if (list->head) { + data = list->head->data; + entry = list->head; + if (list->head == list->tail) { + list->head = NULL; + list->tail = NULL; + } else { + list->head->next->prev = NULL; + list->head = list->head->next; + } + pa_xfree(entry); + list->size--; + } + + return data; +} + +ssize_t dm_list_size(dm_list *list) { + pa_assert(list); + + return list->size; +} + +/* For iteration */ + +void *dm_list_first_data(dm_list *list, void **state) { + pa_assert(list); + pa_assert(state); + + *state = list->head; + + if (list->head) + return list->head->data; + else + return NULL; +} + +void *dm_list_next_data(dm_list *list, void **state) { + dm_list_entry *entry; + + pa_assert(list); + pa_assert(state); + + entry = *state; + *state = entry->next; + + if (entry->next) + return entry->next->data; + else + return NULL; +}