/* Copyright (C) 2017 Paweł Redman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include // size_t #define eli_rebase(x, xm, y) \ ((void*)((char*)(y) + ((char*)(xm) - (char*)(x)))) typedef struct { void *prev, *next; } eli_header; // Link an element to the end of a list. static inline void eli_append_real(void **head, void *entry, eli_header *head_h, eli_header *entry_h) { eli_header *last_h; // Empty list. if (__builtin_expect(!*head, 0)) { *head = entry; entry_h->prev = entry; entry_h->next = NULL; return; } entry_h->prev = head_h->prev; entry_h->next = NULL; last_h = eli_rebase(entry, entry_h, head_h->prev); last_h->next = entry; head_h->prev = entry; } #define eli_append(pphead, entry, member) \ eli_append_real((void**)(pphead), (entry), &((*(pphead))->member), &((entry)->member)) // Unlink an element (from anywhere in a list). static inline void eli_unlink_real(void **head, void *entry, eli_header *head_h, eli_header *entry_h) { if (entry_h->prev && *head != entry) { eli_header *prev_h; prev_h = eli_rebase(entry, entry_h, head_h->prev); prev_h->next = entry_h->next; } if (entry_h->next) { eli_header *next_h; next_h = eli_rebase(entry, entry_h, head_h->next); next_h->prev = entry_h->prev; } else { head_h->prev = entry_h->prev; } if (*head == entry) *head = entry_h->next; } #define eli_unlink(pphead, entry, member) \ eli_unlink_real((void**)(pphead), (entry), &((*(pphead))->member), &((entry)->member)) // Loop over a list #define eli_for(i, head, member) \ for ((i) = (head); (i); (i) = (i)->member.next)