diff options
author | Paweł Redman <pawel.redman@gmail.com> | 2019-07-14 13:31:08 +0200 |
---|---|---|
committer | Paweł Redman <pawel.redman@gmail.com> | 2019-07-14 13:31:08 +0200 |
commit | dcf3c8f677ed0d864604ba0a43d3b971510962e6 (patch) | |
tree | a9180fe261ff2c69e449156bd9663e246d52d0af /src/eli.h | |
parent | ac855a7e9d9970e4f1b658b679c05c893d991be7 (diff) |
Add eli
Diffstat (limited to 'src/eli.h')
-rw-r--r-- | src/eli.h | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/eli.h b/src/eli.h new file mode 100644 index 0000000..8cd75a6 --- /dev/null +++ b/src/eli.h @@ -0,0 +1,84 @@ +/* +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 <stddef.h> // 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) |