1 /*
2 ** cdecl -- C gibberish translator
3 ** src/slist.h
4 **
5 ** Copyright (C) 2017-2021 Paul J. Lucas
6 **
7 ** This program is free software: you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation, either version 3 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifndef cdecl_slist_H
22 #define cdecl_slist_H
23
24 /**
25 * @file
26 * Declares a singly-linked-list data structure and functions to manipulate it.
27 */
28
29 // local
30 #include "pjl_config.h" /* must go first */
31 #include "util.h"
32
33 /// @cond DOXYGEN_IGNORE
34
35 // standard
36 #include <stdbool.h>
37 #include <stddef.h> /* for NULL, size_t */
38
39 _GL_INLINE_HEADER_BEGIN
40 #ifndef SLIST_INLINE
41 # define SLIST_INLINE _GL_INLINE
42 #endif /* SLIST_INLINE */
43
44 /// @endcond
45
46 /**
47 * @defgroup slist-group Singly-Linked List
48 * Types and functions for manipulating singly-linked lists.
49 * @{
50 */
51
52 /**
53 * Convenience macro for iterating over all the nodes of \a SLIST.
54 *
55 * @param VAR The slist_node loop variable.
56 * @param SLIST A pointer to the \ref slist to iterate over.
57 *
58 * @sa #FOREACH_SLIST_NODE_UNTIL()
59 */
60 #define FOREACH_SLIST_NODE(VAR,SLIST) \
61 FOREACH_SLIST_NODE_UNTIL( VAR, SLIST, /*END=*/NULL )
62
63 /**
64 * Convenience macro for iterating over the nodes of \a SLIST up to but not
65 * including \a END.
66 *
67 * @param VAR The slist_node loop variable.
68 * @param SLIST A pointer to the \ref slist to iterate over.
69 * @param END A pointer to the node to end before; may be NULL.
70 *
71 * @sa #FOREACH_SLIST_NODE()
72 */
73 #define FOREACH_SLIST_NODE_UNTIL(VAR,SLIST,END) \
74 for ( slist_node_t *VAR = CONST_CAST( slist_t*, SLIST )->head; VAR != (END); VAR = VAR->next )
75
76 /**
77 * Creates a single-node \ref slist on the stack with \a NODE_DATA.
78 *
79 * @param VAR The name for the \ref slist variable.
80 * @param NODE_DATA A pointer to the node data.
81 */
82 #define SLIST_VAR_INIT(VAR,NODE_DATA) \
83 slist_node_t VAR##_node = { NULL, CONST_CAST(void*, (NODE_DATA)) }; \
84 slist_t const VAR = { &VAR##_node, &VAR##_node, 1 }
85
86 ///////////////////////////////////////////////////////////////////////////////
87
88 typedef struct slist slist_t;
89 typedef struct slist_node slist_node_t;
90
91 /**
92 * The signature for a function passed to slist_cmp() used to compare data
93 * associated with each node (if necessary).
94 *
95 * @param i_data A pointer to the first data to compare.
96 * @param j_data A pointer to the second data to compare.
97 * @return Returns a number less than 0, 0, or greater than 0 if \a i_data is
98 * less than, equal to, or greater than \a j_data, respectively.
99 */
100 typedef int (*slist_cmp_fn_t)( void const *i_data, void const *j_data );
101
102 /**
103 * The signature for a function passed to slist_dup() used to duplicate data
104 * associated with each node (if necessary).
105 *
106 * @param data A pointer to the data to duplicate.
107 * @return Returns a duplicate of \a data.
108 */
109 typedef void* (*slist_dup_fn_t)( void const *data );
110
111 /**
112 * The signature for a function passed to slist_cleanup() used to free data
113 * associated with each node (if necessary).
114 *
115 * @param data A pointer to the data to free.
116 */
117 typedef void (*slist_free_fn_t)( void *data );
118
119 /**
120 * The signature for a function passed to slist_free_if() used to determine
121 * whether a node should be freed.
122 *
123 * @param data A pointer to the data to check.
124 * @return Returns `true` only if the node should be freed.
125 */
126 typedef bool (*slist_pred_fn_t)( void *data );
127
128 ///////////////////////////////////////////////////////////////////////////////
129
130 /**
131 * Singly-linked list.
132 */
133 struct slist {
134 slist_node_t *head; ///< Pointer to list head.
135 slist_node_t *tail; ///< Pointer to list tail.
136 size_t len; ///< Length of list.
137 };
138
139 /**
140 * Singly-linked-list node.
141 */
142 struct slist_node {
143 slist_node_t *next; ///< Pointer to next node or NULL.
144 void *data; ///< Pointer to user data.
145 };
146
147 ////////// extern functions ///////////////////////////////////////////////////
148
149 /**
150 * Cleans-up all memory associated with \a list but _not_ \a list itself.
151 *
152 * @param list A pointer to the list to clean up. If NULL, does nothing;
153 * otherwise, reinitializes \a list upon completion.
154 * @param free_fn A pointer to a function to use to free the data at each node
155 * of \a list or NULL if none is required.
156 *
157 * @sa slist_free_if()
158 * @sa slist_init()
159 */
160 void slist_cleanup( slist_t *list, slist_free_fn_t free_fn );
161
162 /**
163 * Compares two lists.
164 *
165 * @param i_list The first list.
166 * @param j_list The second list.
167 * @param cmp_fn A pointer to a function to use to compare data at each node of
168 * \a i_list and \a j_list or NULL if none is required (hence the data will be
169 * compared directly as signed integers).
170 * @return Returns a number less than 0, 0, or greater than 0 if \a i_list is
171 * less than, equal to, or greater than \a j_list, respectively.
172 */
173 PJL_WARN_UNUSED_RESULT
174 int slist_cmp( slist_t const *i_list, slist_t const *j_list,
175 slist_cmp_fn_t cmp_fn );
176
177 /**
178 * Duplicates \a src_list and all of its nodes.
179 *
180 * @param src_list The \ref slist to duplicate; may ne NULL.
181 * @param n The number of nodes to duplicate; -1 is equivalent to slist_len().
182 * @param dup_fn A pointer to a function to use to duplicate the data at each
183 * node of \a src_list or NULL if none is required (hence a shallow copy will
184 * be done).
185 * @return Returns a duplicate of \a src_list. The caller is responsible for
186 * calling slist_cleanup() on it.
187 *
188 * @sa slist_cleanup()
189 */
190 PJL_WARN_UNUSED_RESULT
191 slist_t slist_dup( slist_t const *src_list, ssize_t n, slist_dup_fn_t dup_fn );
192
193 /**
194 * Gets whether \a list is empty.
195 *
196 * @param list A pointer to the \ref slist to check.
197 * @return Returns `true` only if \a list is empty.
198 *
199 * @note This is an O(1) operation.
200 *
201 * @sa slist_len()
202 */
203 SLIST_INLINE PJL_WARN_UNUSED_RESULT
slist_empty(slist_t const * list)204 bool slist_empty( slist_t const *list ) {
205 return list->head == NULL;
206 }
207
208 /**
209 * Frees select nodes from \a list for which \a pred_fn returns `true`.
210 *
211 * @param list A pointer to the list to possibly free nodes from.
212 * @param pred_fn The predicate function to use.
213 *
214 * @note This function _only_ frees matching nodes from \a list and _not_ the
215 * data at each node. If the data at each node needs to be freed, \a pred_fn
216 * can do that before returning `true`.
217 * @note This is an O(n) operation.
218 *
219 * @sa slist_cleanup()
220 */
221 void slist_free_if( slist_t *list, slist_pred_fn_t pred_fn );
222
223 /**
224 * Initializes \a list. This is not necessary for either global or `static`
225 * lists.
226 *
227 * @param list A pointer to the \ref slist to initialize.
228 *
229 * @sa slist_cleanup()
230 */
231 SLIST_INLINE
slist_init(slist_t * list)232 void slist_init( slist_t *list ) {
233 MEM_ZERO( list );
234 }
235
236 /**
237 * Gets the length of \a list.
238 *
239 * @param list A pointer to the \ref slist to get the length of.
240 * @return Returns said length.
241 *
242 * @note This is an O(1) operation.
243 *
244 * @sa slist_empty()
245 */
246 SLIST_INLINE PJL_WARN_UNUSED_RESULT
slist_len(slist_t const * list)247 size_t slist_len( slist_t const *list ) {
248 return list->len;
249 }
250
251 /**
252 * Peeks at the data at \a offset of \a list.
253 *
254 * @param list A pointer to the \ref slist.
255 * @param offset The offset (starting at 0) of the data to get.
256 * @return Returns the data from the node at \a offset or NULL if \a offset
257 * ≥ slist_len().
258 *
259 * @note This is an O(n) operation.
260 *
261 * @sa slist_peek_atr()
262 * @sa slist_peek_head()
263 * @sa slist_peek_tail()
264 */
265 PJL_WARN_UNUSED_RESULT
266 void* slist_peek_at( slist_t const *list, size_t offset );
267
268 /**
269 * Peeks at the data at \a roffset from the tail of \a list.
270 *
271 * @param list A pointer to the \ref slist.
272 * @param roffset The reverse offset (starting at 0) of the data to get.
273 * @return Returns the data from the node at \a roffset or NULL if \a roffset
274 * ≥ slist_len().
275 *
276 * @note This is an O(n) operation.
277 *
278 * @sa slist_peek_at()
279 * @sa slist_peek_head()
280 * @sa slist_peek_tail()
281 */
282 SLIST_INLINE PJL_WARN_UNUSED_RESULT
slist_peek_atr(slist_t const * list,size_t roffset)283 void* slist_peek_atr( slist_t const *list, size_t roffset ) {
284 return roffset < list->len ?
285 slist_peek_at( list, list->len - (roffset + 1) ) : NULL;
286 }
287
288 /**
289 * Peeks at the data at the head of \a list.
290 *
291 * @param list A pointer to the \ref slist.
292 * @return Returns the data from the node at the head of \a list or NULL if \a
293 * list is empty.
294 *
295 * @note This is an O(1) operation.
296 *
297 * @sa slist_peek_at()
298 * @sa slist_peek_atr()
299 * @sa slist_peek_tail()
300 */
301 SLIST_INLINE PJL_WARN_UNUSED_RESULT
slist_peek_head(slist_t const * list)302 void* slist_peek_head( slist_t const *list ) {
303 return list->head != NULL ? list->head->data : NULL;
304 }
305
306 /**
307 * Peeks at the data at the tail of \a list.
308 *
309 * @param list A pointer to the \ref slist.
310 * @return Returns the data from the node at the tail of \a list or NULL if \a
311 * list is empty.
312 *
313 * @note This is an O(1) operation.
314 *
315 * @sa slist_peek_at()
316 * @sa slist_peek_atr()
317 * @sa slist_peek_head()
318 */
319 SLIST_INLINE PJL_WARN_UNUSED_RESULT
slist_peek_tail(slist_t const * list)320 void* slist_peek_tail( slist_t const *list ) {
321 return list->tail != NULL ? list->tail->data : NULL;
322 }
323
324 /**
325 * Pops data from the head of \a list.
326 *
327 * @param list The pointer to the \ref slist.
328 * @return Returns the data from the head of \a list. The caller is
329 * responsible for freeing it (if necessary).
330 *
331 * @note This is an O(1) operation.
332 */
333 PJL_WARN_UNUSED_RESULT
334 void* slist_pop_head( slist_t *list );
335
336 /**
337 * Pushes a node onto the head of \a list.
338 *
339 * @param list A pointer to the \ref slist.
340 * @param data The pointer to the data to add.
341 *
342 * @note This is an O(1) operation.
343 *
344 * @sa slist_push_list_head()
345 * @sa slist_push_tail()
346 */
347 void slist_push_head( slist_t *list, void *data );
348
349 /**
350 * Pushes \a src_list onto the head of \a dst_list.
351 *
352 * @param dst_list The \ref slist to push onto.
353 * @param src_list The \ref slist to push. It is made empty.
354 *
355 * @note This is an O(1) operation.
356 *
357 * @sa slist_push_head()
358 * @sa slist_push_list_tail()
359 */
360 void slist_push_list_head( slist_t *dst_list, slist_t *src_list );
361
362 /**
363 * Pushes \a src_list onto the tail of \a dst_list.
364 *
365 * @param dst_list The \ref slist to push onto.
366 * @param src_list The \ref slist to push. It is made empty.
367 *
368 * @note This is an O(1) operation.
369 *
370 * @sa slist_push_list_head()
371 * @sa slist_push_tail()
372 */
373 void slist_push_list_tail( slist_t *dst_list, slist_t *src_list );
374
375 /**
376 * Appends \a data onto the tail of \a list.
377 *
378 * @param list The \ref slist to push onto.
379 * @param data The data to pushed.
380 *
381 * @note This is an O(1) operation.
382 *
383 * @sa slist_push_head()
384 * @sa slist_push_list_tail()
385 */
386 void slist_push_tail( slist_t *list, void *data );
387
388 ///////////////////////////////////////////////////////////////////////////////
389
390 /** @} */
391
392 _GL_INLINE_HEADER_END
393
394 #endif /* cdecl_slist_H */
395 /* vim:set et sw=2 ts=2: */
396