blob: b00d9ea97d692bd59149d806f632a39328710288 [file] [log] [blame]
Simon Glasse1edadf2024-07-30 08:39:37 -06001/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Handles a contiguous list of pointers which be allocated and freed
4 *
5 * Copyright 2023 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#ifndef __ALIST_H
10#define __ALIST_H
11
12#include <stdbool.h>
13#include <linux/bitops.h>
14#include <linux/types.h>
15
16/**
17 * struct alist - object list that can be allocated and freed
18 *
19 * Holds a list of objects, each of the same size. The object is typically a
20 * C struct. The array is alloced in memory can change in size.
21 *
22 * The list rememebers the size of the list, but has a separate count of how
23 * much space is allocated, This allows it increase in size in steps as more
24 * elements are added, which is more efficient that reallocating the list every
25 * time a single item is added
26 *
27 * Two types of access are provided:
28 *
29 * alist_get...(index)
30 * gets an existing element, if its index is less that size
31 *
32 * alist_ensure(index)
33 * address an existing element, or creates a new one if not present
34 *
35 * @data: object data of size `@obj_size * @alloc`. The list can grow as
36 * needed but never shrinks
37 * @obj_size: Size of each object in bytes
38 * @count: number of objects in array
39 * @alloc: allocated length of array, to which @count can grow
40 * @flags: flags for the alist (ALISTF_...)
41 */
42struct alist {
43 void *data;
44 u16 obj_size;
45 u16 count;
46 u16 alloc;
47 u16 flags;
48};
49
50/**
51 * enum alist_flags - Flags for the alist
52 *
53 * @ALIST_FAIL: true if any allocation has failed. Once this has happened, the
54 * alist is dead and cannot grow further
55 */
56enum alist_flags {
57 ALISTF_FAIL = BIT(0),
58};
59
60/**
61 * alist_has() - Check if an index is within the list range
62 *
63 * Checks if index is within the current alist count
64 *
65 * @lst: alist to check
66 * @index: Index to check
67 * Returns: true if value, else false
68 */
69static inline bool alist_has(struct alist *lst, uint index)
70{
71 return index < lst->count;
72}
73
74/**
Simon Glass899b4cc2024-10-19 09:21:44 -060075 * alist_calc_index() - Calculate the index of an item in the list
76 *
77 * The returned element number will be -1 if the list is empty or the pointer
78 * pointers to before the list starts.
79 *
80 * If the pointer points to after the last item, the calculated element-number
81 * will be returned, even though it is greater than lst->count
82 *
83 * @lst: alist to check
84 * @ptr: pointer to check
85 * Return: element number of the pointer
86 */
87int alist_calc_index(const struct alist *lst, const void *ptr);
88
89/**
Simon Glasse1edadf2024-07-30 08:39:37 -060090 * alist_err() - Check if the alist is still valid
91 *
92 * @lst: List to check
93 * Return: false if OK, true if any previous allocation failed
94 */
95static inline bool alist_err(struct alist *lst)
96{
97 return lst->flags & ALISTF_FAIL;
98}
99
100/**
Sughosh Ganu514a5ec2024-08-26 17:29:14 +0530101 * alist_full() - Check if the alist is full
102 *
103 * @lst: List to check
104 * Return: true if full, false otherwise
105 */
106static inline bool alist_full(struct alist *lst)
107{
108 return lst->count == lst->alloc;
109}
110
111/**
Simon Glasse1edadf2024-07-30 08:39:37 -0600112 * alist_get_ptr() - Get the value of a pointer
113 *
114 * @lst: alist to check
115 * @index: Index to read from
116 * Returns: pointer, if present, else NULL
117 */
118const void *alist_get_ptr(const struct alist *lst, uint index);
119
120/**
121 * alist_getd() - Get the value of a pointer directly, with no checking
122 *
123 * This must only be called on indexes for which alist_has() returns true
124 *
125 * @lst: alist to check
126 * @index: Index to read from
127 * Returns: pointer value (may be NULL)
128 */
129static inline const void *alist_getd(struct alist *lst, uint index)
130{
131 return lst->data + index * lst->obj_size;
132}
133
Simon Glassa7498632024-10-19 09:21:43 -0600134/**
135 * alist_get() - get an entry as a constant
136 *
137 * Use as (to obtain element 2 of the list):
138 * const struct my_struct *ptr = alist_get(lst, 2, struct my_struct)
139 */
Simon Glasse1edadf2024-07-30 08:39:37 -0600140#define alist_get(_lst, _index, _struct) \
141 ((const _struct *)alist_get_ptr(_lst, _index))
142
143/** get an entry which can be written to */
144#define alist_getw(_lst, _index, _struct) \
145 ((_struct *)alist_get_ptr(_lst, _index))
146
147/**
148 * alist_ensure_ptr() - Ensure an object exists at a given index
149 *
150 * This provides read/write access to an array element. If it does not exist,
151 * it is allocated, reading for the caller to store the object into
152 *
153 * Allocates a object at the given index if needed
154 *
155 * @lst: alist to check
156 * @index: Index to address
157 * Returns: pointer where struct can be read/written, or NULL if out of memory
158 */
159void *alist_ensure_ptr(struct alist *lst, uint index);
160
161/**
162 * alist_ensure() - Address a struct, the correct object type
163 *
164 * Use as:
165 * struct my_struct *ptr = alist_ensure(&lst, 4, struct my_struct);
166 */
167#define alist_ensure(_lst, _index, _struct) \
168 ((_struct *)alist_ensure_ptr(_lst, _index))
169
170/**
171 * alist_add_placeholder() - Add a new item to the end of the list
172 *
173 * @lst: alist to add to
Simon Glass522c4332024-10-19 09:21:41 -0600174 * Return: Pointer to the newly added position, or NULL if out of memory. Note
175 * that this is not inited so the caller must copy the requested struct to the
176 * returned pointer
Simon Glasse1edadf2024-07-30 08:39:37 -0600177 */
178void *alist_add_placeholder(struct alist *lst);
179
180/**
181 * alist_add_ptr() - Ad a new object to the list
182 *
183 * @lst: alist to add to
184 * @obj: Pointer to object to copy in
185 * Returns: pointer to where the object was copied, or NULL if out of memory
186 */
187void *alist_add_ptr(struct alist *lst, void *obj);
188
189/**
190 * alist_expand_by() - Expand a list by the given amount
191 *
192 * @lst: alist to expand
193 * @inc_by: Amount to expand by
194 * Return: true if OK, false if out of memory
195 */
196bool alist_expand_by(struct alist *lst, uint inc_by);
197
198/**
199 * alist_add() - Used to add an object type with the correct type
200 *
201 * Use as:
202 * struct my_struct obj;
203 * struct my_struct *ptr = alist_add(&lst, &obj);
204 */
205#define alist_add(_lst, _obj) \
206 ((typeof(_obj) *)alist_add_ptr(_lst, &(_obj)))
207
Simon Glass899b4cc2024-10-19 09:21:44 -0600208/** get next entry as a constant */
209#define alist_next(_lst, _objp) \
210 ((const typeof(_objp))alist_next_ptrd(_lst, _objp))
211
212/** get next entry, which can be written to */
213#define alist_nextw(_lst, _objp) \
214 ((typeof(_objp))alist_next_ptrd(_lst, _objp))
215
216/**
217 * alist_next_ptrd() - Get a pointer to the next list element
218 *
219 * This returns NULL if the requested element is beyond lst->count
220 *
221 * @lst: List to check
222 * @ptr: Pointer to current element (must be valid)
223 * Return: Pointer to next element, or NULL if @ptr is the last
224 */
225const void *alist_next_ptrd(const struct alist *lst, const void *ptr);
226
Simon Glasse1edadf2024-07-30 08:39:37 -0600227/**
Simon Glassce66b8a2024-10-19 09:21:45 -0600228 * alist_chk_ptr() - Check whether a pointer is within a list
229 *
230 * Checks if the pointer points to an existing element of the list. The pointer
231 * must point to the start of an element, either in the list, or just outside of
232 * it. This function is only useful for handling for() loops
233 *
234 * Return: true if @ptr is within the list (0..count-1), else false
235 */
236bool alist_chk_ptr(const struct alist *lst, const void *ptr);
237
238/**
239 * alist_start() - Get the start of the list (first element)
240 *
241 * Note that this will always return ->data even if it is not NULL
242 *
243 * Usage:
244 * const struct my_struct *obj; # 'const' is optional
245 *
246 * alist_start(&lst, struct my_struct)
247 */
248#define alist_start(_lst, _struct) \
249 ((_struct *)(_lst)->data)
250
251/**
252 * alist_end() - Get the end of the list (just after last element)
253 *
254 * Usage:
255 * const struct my_struct *obj; # 'const' is optional
256 *
257 * alist_end(&lst, struct my_struct)
258 */
259#define alist_end(_lst, _struct) \
260 ((_struct *)(_lst)->data + (_lst)->count)
261
262/**
263 * alist_for_each() - Iterate over an alist (with constant pointer)
264 *
265 * Use as:
266 * const struct my_struct *obj; # 'const' is optional
267 *
268 * alist_for_each(obj, &lst) {
269 * obj->...
270 * }
271 */
272#define alist_for_each(_pos, _lst) \
273 for (_pos = alist_start(_lst, typeof(*(_pos))); \
274 _pos < alist_end(_lst, typeof(*(_pos))); \
275 _pos++)
276
277/**
Simon Glasse8d02102024-10-19 09:21:47 -0600278 * alist_for_each_filter() - version which sets up a 'from' pointer too
279 *
280 * This is used for filtering out information in the list. It works by iterating
281 * through the list, copying elements down over the top of elements to be
282 * deleted.
283 *
284 * In this example, 'from' iterates through the list from start to end,, 'to'
285 * also begins at the start, but only increments if the element at 'from' should
286 * be kept. This provides an O(n) filtering operation. Note that
287 * alist_update_end() must be called after the loop, to update the count.
288 *
289 * alist_for_each_filter(from, to, &lst) {
290 * if (from->val != 2)
291 * *to++ = *from;
292 * }
293 * alist_update_end(&lst, to);
294 */
295#define alist_for_each_filter(_pos, _from, _lst) \
296 for (_pos = _from = alist_start(_lst, typeof(*(_pos))); \
297 _pos < alist_end(_lst, typeof(*(_pos))); \
298 _pos++)
299
300/**
301 * alist_update_end() - Set the element count based on a given pointer
302 *
303 * Set the given element as the final one
304 */
305void alist_update_end(struct alist *lst, const void *end);
306
307/**
Simon Glass84074242024-10-19 09:21:46 -0600308 * alist_empty() - Empty an alist
309 *
310 * This removes all entries from the list, without changing the allocated size
311 */
312void alist_empty(struct alist *lst);
313
314/**
Simon Glasse1edadf2024-07-30 08:39:37 -0600315 * alist_init() - Set up a new object list
316 *
317 * Sets up a list of objects, initially empty
318 *
319 * @lst: alist to set up
320 * @obj_size: Size of each element in bytes
321 * @alloc_size: Number of items to allowed to start, before reallocation is
322 * needed (0 to start with no space)
323 * Return: true if OK, false if out of memory
324 */
325bool alist_init(struct alist *lst, uint obj_size, uint alloc_size);
326
Simon Glass1ed19522024-10-19 09:21:42 -0600327/**
328 * alist_init_struct() - Typed version of alist_init()
329 *
330 * Use as:
331 * alist_init(&lst, struct my_struct);
332 */
Simon Glasse1edadf2024-07-30 08:39:37 -0600333#define alist_init_struct(_lst, _struct) \
334 alist_init(_lst, sizeof(_struct), 0)
335
336/**
337 * alist_uninit_move_ptr() - Return the allocated contents and uninit the alist
338 *
339 * This returns the alist data to the caller, so that the caller receives data
340 * that it can be sure will hang around. The caller is responsible for freeing
341 * the data.
342 *
343 * If the alist size is 0, this returns NULL
344 *
345 * The alist is uninited as part of this.
346 *
347 * The alist must be inited before this can be called.
348 *
349 * @alist: alist to uninit
350 * @countp: if non-NULL, returns the number of objects in the returned data
351 * (which is @alist->size)
352 * Return: data contents, allocated with malloc(), or NULL if the data could not
353 * be allocated, or the data size is 0
354 */
355void *alist_uninit_move_ptr(struct alist *alist, size_t *countp);
356
357/**
358 * alist_uninit_move() - Typed version of alist_uninit_move_ptr()
359 */
360#define alist_uninit_move(_lst, _countp, _struct) \
361 (_struct *)alist_uninit_move_ptr(_lst, _countp)
362
363/**
364 * alist_uninit() - Free any memory used by an alist
365 *
366 * The alist must be inited before this can be called.
367 *
368 * @alist: alist to uninit
369 */
370void alist_uninit(struct alist *alist);
371
372#endif /* __ALIST_H */