Coverage Report

Created: 2025-07-11 06:34

/src/libwebsockets/build/include/libwebsockets/lws-dll2.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 */
24
25
/** \defgroup ll linked-lists
26
* ##Linked list apis
27
*
28
* simple single and doubly-linked lists
29
*/
30
///@{
31
32
/**
33
 * lws_start_foreach_ll(): linkedlist iterator helper start
34
 *
35
 * \param type: type of iteration, eg, struct xyz *
36
 * \param it: iterator var name to create
37
 * \param start: start of list
38
 *
39
 * This helper creates an iterator and starts a while (it) {
40
 * loop.  The iterator runs through the linked list starting at start and
41
 * ends when it gets a NULL.
42
 * The while loop should be terminated using lws_start_foreach_ll().
43
 */
44
#define lws_start_foreach_ll(type, it, start)\
45
{ \
46
  type it = start; \
47
  while (it) {
48
49
/**
50
 * lws_end_foreach_ll(): linkedlist iterator helper end
51
 *
52
 * \param it: same iterator var name given when starting
53
 * \param nxt: member name in the iterator pointing to next list element
54
 *
55
 * This helper is the partner for lws_start_foreach_ll() that ends the
56
 * while loop.
57
 */
58
59
#define lws_end_foreach_ll(it, nxt) \
60
    it = it->nxt; \
61
  } \
62
}
63
64
/**
65
 * lws_start_foreach_ll_safe(): linkedlist iterator helper start safe against delete
66
 *
67
 * \param type: type of iteration, eg, struct xyz *
68
 * \param it: iterator var name to create
69
 * \param start: start of list
70
 * \param nxt: member name in the iterator pointing to next list element
71
 *
72
 * This helper creates an iterator and starts a while (it) {
73
 * loop.  The iterator runs through the linked list starting at start and
74
 * ends when it gets a NULL.
75
 * The while loop should be terminated using lws_end_foreach_ll_safe().
76
 * Performs storage of next increment for situations where iterator can become invalidated
77
 * during iteration.
78
 */
79
#define lws_start_foreach_ll_safe(type, it, start, nxt)\
80
{ \
81
  type it = start; \
82
  while (it) { \
83
    type next_##it = it->nxt;
84
85
/**
86
 * lws_end_foreach_ll_safe(): linkedlist iterator helper end (pre increment storage)
87
 *
88
 * \param it: same iterator var name given when starting
89
 *
90
 * This helper is the partner for lws_start_foreach_ll_safe() that ends the
91
 * while loop. It uses the precreated next_ variable already stored during
92
 * start.
93
 */
94
95
#define lws_end_foreach_ll_safe(it) \
96
    it = next_##it; \
97
  } \
98
}
99
100
/**
101
 * lws_start_foreach_llp(): linkedlist pointer iterator helper start
102
 *
103
 * \param type: type of iteration, eg, struct xyz **
104
 * \param it: iterator var name to create
105
 * \param start: start of list
106
 *
107
 * This helper creates an iterator and starts a while (it) {
108
 * loop.  The iterator runs through the linked list starting at the
109
 * address of start and ends when it gets a NULL.
110
 * The while loop should be terminated using lws_start_foreach_llp().
111
 *
112
 * This helper variant iterates using a pointer to the previous linked-list
113
 * element.  That allows you to easily delete list members by rewriting the
114
 * previous pointer to the element's next pointer.
115
 */
116
#define lws_start_foreach_llp(type, it, start)\
117
{ \
118
  type it = &(start); \
119
  while (*(it)) {
120
121
#define lws_start_foreach_llp_safe(type, it, start, nxt)\
122
{ \
123
  type it = &(start); \
124
  type next; \
125
  while (*(it)) { \
126
    next = &((*(it))->nxt); \
127
128
/**
129
 * lws_end_foreach_llp(): linkedlist pointer iterator helper end
130
 *
131
 * \param it: same iterator var name given when starting
132
 * \param nxt: member name in the iterator pointing to next list element
133
 *
134
 * This helper is the partner for lws_start_foreach_llp() that ends the
135
 * while loop.
136
 */
137
138
#define lws_end_foreach_llp(it, nxt) \
139
    it = &(*(it))->nxt; \
140
  } \
141
}
142
143
#define lws_end_foreach_llp_safe(it) \
144
    it = next; \
145
  } \
146
}
147
148
#define lws_ll_fwd_insert(\
149
  ___new_object,  /* pointer to new object */ \
150
  ___m_list,  /* member for next list object ptr */ \
151
  ___list_head  /* list head */ \
152
    ) {\
153
    ___new_object->___m_list = ___list_head; \
154
    ___list_head = ___new_object; \
155
  }
156
157
#define lws_ll_fwd_remove(\
158
  ___type,  /* type of listed object */ \
159
  ___m_list,  /* member for next list object ptr */ \
160
  ___target,  /* object to remove from list */ \
161
  ___list_head  /* list head */ \
162
  ) { \
163
                lws_start_foreach_llp(___type **, ___ppss, ___list_head) { \
164
                        if (*___ppss == ___target) { \
165
                                *___ppss = ___target->___m_list; \
166
                                break; \
167
                        } \
168
                } lws_end_foreach_llp(___ppss, ___m_list); \
169
  }
170
171
172
/*
173
 * doubly linked-list
174
 */
175
176
/*
177
 * lws_dll2_owner / lws_dll2 : more capable version of lws_dll.  Differences:
178
 *
179
 *  - there's an explicit lws_dll2_owner struct which holds head, tail and
180
 *    count of members.
181
 *
182
 *  - list members all hold a pointer to their owner.  So user code does not
183
 *    have to track anything about exactly what lws_dll2_owner list the object
184
 *    is a member of.
185
 *
186
 *  - you can use lws_dll unless you want the member count or the ability to
187
 *    not track exactly which list it's on.
188
 *
189
 *  - layout is compatible with lws_dll (but lws_dll apis will not update the
190
 *    new stuff)
191
 */
192
193
194
struct lws_dll2;
195
struct lws_dll2_owner;
196
197
typedef struct lws_dll2 {
198
  struct lws_dll2   *prev;
199
  struct lws_dll2   *next;
200
  struct lws_dll2_owner *owner;
201
} lws_dll2_t;
202
203
typedef struct lws_dll2_owner {
204
  struct lws_dll2   *tail;
205
  struct lws_dll2   *head;
206
207
  uint32_t    count;
208
} lws_dll2_owner_t;
209
210
LWS_VISIBLE LWS_EXTERN int
211
lws_dll2_is_detached(const struct lws_dll2 *d);
212
213
static LWS_INLINE const struct lws_dll2_owner *
214
0
lws_dll2_owner(const struct lws_dll2 *d) { return d->owner; }
215
216
static LWS_INLINE struct lws_dll2 *
217
0
lws_dll2_get_head(struct lws_dll2_owner *owner) { return owner->head; }
218
219
static LWS_INLINE struct lws_dll2 *
220
0
lws_dll2_get_tail(struct lws_dll2_owner *owner) { return owner->tail; }
221
222
LWS_VISIBLE LWS_EXTERN void
223
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner);
224
225
LWS_VISIBLE LWS_EXTERN void
226
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner);
227
228
LWS_VISIBLE LWS_EXTERN void
229
lws_dll2_remove(struct lws_dll2 *d);
230
231
typedef int (*lws_dll2_foreach_cb_t)(struct lws_dll2 *d, void *user);
232
233
LWS_VISIBLE LWS_EXTERN int
234
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
235
          lws_dll2_foreach_cb_t cb);
236
237
LWS_VISIBLE LWS_EXTERN void
238
lws_dll2_clear(struct lws_dll2 *d);
239
240
LWS_VISIBLE LWS_EXTERN void
241
lws_dll2_owner_clear(struct lws_dll2_owner *d);
242
243
LWS_VISIBLE LWS_EXTERN void
244
lws_dll2_add_before(struct lws_dll2 *d, struct lws_dll2 *after);
245
246
LWS_VISIBLE LWS_EXTERN void
247
lws_dll2_add_insert(struct lws_dll2 *d, struct lws_dll2 *prev);
248
249
LWS_VISIBLE LWS_EXTERN void
250
lws_dll2_add_sorted(lws_dll2_t *d, lws_dll2_owner_t *own,
251
        int (*compare)(const lws_dll2_t *d, const lws_dll2_t *i));
252
253
LWS_VISIBLE LWS_EXTERN void
254
lws_dll2_add_sorted_priv(lws_dll2_t *d, lws_dll2_owner_t *own, void *priv,
255
       int (*compare3)(void *priv, const lws_dll2_t *d,
256
           const lws_dll2_t *i));
257
258
LWS_VISIBLE LWS_EXTERN void *
259
_lws_dll2_search_sz_pl(lws_dll2_owner_t *own, const char *name, size_t namelen,
260
          size_t dll2_ofs, size_t ptr_ofs);
261
262
/*
263
 * Searches objects in an owner list linearly and returns one with a given
264
 * member C-string matching a supplied length-provided string if it exists, else
265
 * NULL.
266
 */
267
268
#define lws_dll2_search_sz_pl(own, name, namelen, type, membd2list, membptr) \
269
    ((type *)_lws_dll2_search_sz_pl(own, name, namelen, \
270
               offsetof(type, membd2list), \
271
               offsetof(type, membptr)))
272
273
#if defined(_DEBUG)
274
void
275
lws_dll2_describe(struct lws_dll2_owner *owner, const char *desc);
276
#else
277
#define lws_dll2_describe(x, y)
278
#endif
279
280
/*
281
 * these are safe against the current container object getting deleted,
282
 * since the hold his next in a temp and go to that next.  ___tmp is
283
 * the temp.
284
 */
285
286
#define lws_start_foreach_dll_safe(___type, ___it, ___tmp, ___start) \
287
{ \
288
  ___type ___it = ___start; \
289
  while (___it) { \
290
    ___type ___tmp = (___it)->next;
291
292
#define lws_end_foreach_dll_safe(___it, ___tmp) \
293
    ___it = ___tmp; \
294
  } \
295
}
296
297
#define lws_start_foreach_dll(___type, ___it, ___start) \
298
{ \
299
  ___type ___it = ___start; \
300
  while (___it) {
301
302
#define lws_end_foreach_dll(___it) \
303
    ___it = (___it)->next; \
304
  } \
305
}
306
307
///@}
308