| /* |
| * Copyright (C) Tildeslash Ltd. All rights reserved. |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU Affero General Public License version 3. |
| * |
| * This program 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 Affero General Public License for more details. |
| * |
| * You should have received a copy of the GNU Affero General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| * |
| * In addition, as a special exception, the copyright holders give |
| * permission to link the code of portions of this program with the |
| * OpenSSL library under certain conditions as described in each |
| * individual source file, and distribute linked combinations |
| * including the two. |
| * |
| * You must obey the GNU Affero General Public License in all respects |
| * for all of the code used other than OpenSSL. |
| */ |
| |
| |
| #include "Config.h" |
| |
| #include <stdio.h> |
| #include <strings.h> |
| #include <stdarg.h> |
| |
| #include "Str.h" |
| #include "List.h" |
| |
| |
| /** |
| * Implementation of the List interface. A freelist is used to retain |
| * deleted nodes for reuse. |
| * |
| * @see http://www.mmonit.com/ |
| * @file |
| */ |
| |
| |
| /* ----------------------------------------------------------- Definitions */ |
| |
| |
| #define T List_T |
| |
| |
| /* --------------------------------------------------------------- Private */ |
| |
| |
| static inline list_t new_node(T L, void *e, list_t next) { |
| list_t p; |
| if (L->freelist) { |
| p = L->freelist; |
| L->freelist = p->next; |
| } else |
| p = ALLOC(sizeof *(p)); |
| p->e = e; |
| p->next = next; |
| return p; |
| } |
| |
| |
| /* ---------------------------------------------------------------- Public */ |
| |
| |
| T List_new(void) { |
| T L; |
| NEW(L); |
| return L; |
| } |
| |
| |
| void List_free(T *L) { |
| list_t p, q; |
| assert(L && *L); |
| for (p = (*L)->head; p; p = q) { |
| q = p->next; |
| FREE(p); |
| } |
| for (p = (*L)->freelist; p; p = q) { |
| q = p->next; |
| FREE(p); |
| } |
| FREE(*L); |
| } |
| |
| |
| void List_push(T L, void *e) { |
| assert(L); |
| list_t p = new_node(L, e, L->head); |
| if (L->head == NULL) |
| L->tail = p; |
| L->head = p; |
| L->length++; |
| L->timestamp++; |
| } |
| |
| |
| void *List_pop(T L) { |
| assert(L); |
| if (L->head) { |
| list_t p = L->head; |
| L->head = L->head->next; |
| L->length--; |
| L->timestamp++; |
| p->next = L->freelist; |
| L->freelist = p; |
| return p->e; |
| } |
| return NULL; |
| } |
| |
| |
| void List_append(T L, void *e) { |
| list_t p; |
| assert(L); |
| p = new_node(L, e, NULL); |
| if (L->head == NULL) |
| L->head = p; |
| else |
| L->tail->next = p; |
| L->tail = p; |
| L->length++; |
| L->timestamp++; |
| } |
| |
| |
| void *List_remove(T L, void *e) { |
| assert(L); |
| if (e && L->head) { |
| list_t p, q; |
| if (L->head->e == e) |
| return List_pop(L); |
| for (p = L->head; p; p = q) { |
| q = p->next; |
| if (q && (q->e == e)) { |
| p->next = q->next; |
| if (q == L->tail) |
| L->tail = p; |
| p = q; |
| L->length--; |
| L->timestamp++; |
| p->next = L->freelist; |
| L->freelist = p; |
| return p->e; |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| |
| void List_cat(T L, T list) { |
| assert(L); |
| assert(list); |
| if (L != list) |
| for (list_t p = list->head; p; p = p->next) |
| List_append(L, p->e); |
| } |
| |
| |
| void List_reverse(T L) { |
| list_t head, next, list; |
| assert(L); |
| head = NULL; |
| list = L->head; |
| L->tail = L->head; |
| for (; list; list = next) { |
| next = list->next; |
| list->next = head; |
| head = list; |
| } |
| L->head = head; |
| } |
| |
| |
| int List_length(T L) { |
| assert(L); |
| return L->length; |
| } |
| |
| |
| void List_clear(T L) { |
| assert(L); |
| if (L->tail) { |
| L->tail->next = L->freelist; |
| L->freelist = L->head; |
| } |
| L->tail = L->head = NULL; |
| L->length = 0; |
| } |
| |
| |
| void List_map(T L, void (*apply)(void *e, void *ap), void *ap) { |
| int stamp; |
| list_t p; |
| assert(L); |
| stamp = L->timestamp; |
| assert(apply); |
| for (p = L->head; p; p = p->next) { |
| apply(p->e, ap); |
| assert(L->timestamp == stamp); |
| } |
| } |
| |
| |
| void **List_toArray(T L) { |
| assert(L); |
| int i = 0; |
| void **array = ALLOC((L->length + 1) * sizeof *(array)); |
| for (list_t p = L->head; p; p = p->next, i++) |
| array[i] = p->e; |
| array[i] = NULL; |
| return array; |
| } |
| |
| |