1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
/*
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
*/
#ifndef _ELI_H
#define _ELI_H
#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)
#endif // _ELI_H
|