blob: 4ce651f5c45196a39e611ef74dafeb3f36356856 [file] [log] [blame]
Simon Glass75581e42024-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#include <alist.h>
10#include <display_options.h>
11#include <malloc.h>
12#include <stdio.h>
13#include <string.h>
14
15enum {
16 ALIST_INITIAL_SIZE = 4, /* default size of unsized list */
17};
18
19bool alist_init(struct alist *lst, uint obj_size, uint start_size)
20{
21 /* Avoid realloc for the initial size to help malloc_simple */
22 memset(lst, '\0', sizeof(struct alist));
23 if (start_size) {
24 lst->data = calloc(obj_size, start_size);
25 if (!lst->data) {
26 lst->flags = ALISTF_FAIL;
27 return false;
28 }
29 lst->alloc = start_size;
30 }
31 lst->obj_size = obj_size;
32
33 return true;
34}
35
36void alist_uninit(struct alist *lst)
37{
38 free(lst->data);
39
40 /* Clear fields to avoid any confusion */
41 memset(lst, '\0', sizeof(struct alist));
42}
43
Simon Glass5bd4ead2024-10-19 09:21:46 -060044void alist_empty(struct alist *lst)
45{
46 lst->count = 0;
47}
48
Simon Glass75581e42024-07-30 08:39:37 -060049/**
50 * alist_expand_to() - Expand a list to the given size
51 *
52 * @lst: List to modify
53 * @inc_by: Amount to expand to
54 * Return: true if OK, false if out of memory
55 */
56static bool alist_expand_to(struct alist *lst, uint new_alloc)
57{
58 void *new_data;
59
60 if (lst->flags & ALISTF_FAIL)
61 return false;
62
63 /* avoid using realloc() since it increases code size */
64 new_data = malloc(lst->obj_size * new_alloc);
65 if (!new_data) {
66 lst->flags |= ALISTF_FAIL;
67 return false;
68 }
69
70 memcpy(new_data, lst->data, lst->obj_size * lst->alloc);
71 free(lst->data);
72
73 memset(new_data + lst->obj_size * lst->alloc, '\0',
74 lst->obj_size * (new_alloc - lst->alloc));
75 lst->alloc = new_alloc;
76 lst->data = new_data;
77
78 return true;
79}
80
81bool alist_expand_by(struct alist *lst, uint inc_by)
82{
83 return alist_expand_to(lst, lst->alloc + inc_by);
84}
85
86/**
87 * alist_expand_min() - Expand to at least the provided size
88 *
89 * Expands to the lowest power of two which can incorporate the new size
90 *
91 * @lst: alist to expand
92 * @min_alloc: Minimum new allocated size; if 0 then ALIST_INITIAL_SIZE is used
93 * Return: true if OK, false if out of memory
94 */
95static bool alist_expand_min(struct alist *lst, uint min_alloc)
96{
97 uint new_alloc;
98
99 for (new_alloc = lst->alloc ?: ALIST_INITIAL_SIZE;
100 new_alloc < min_alloc;)
101 new_alloc *= 2;
102
103 return alist_expand_to(lst, new_alloc);
104}
105
106const void *alist_get_ptr(const struct alist *lst, uint index)
107{
108 if (index >= lst->count)
109 return NULL;
110
111 return lst->data + index * lst->obj_size;
112}
113
Simon Glass1d49f782024-10-19 09:21:44 -0600114int alist_calc_index(const struct alist *lst, const void *ptr)
115{
116 uint index;
117
118 if (!lst->count || ptr < lst->data)
119 return -1;
120
121 index = (ptr - lst->data) / lst->obj_size;
122
123 return index;
124}
125
Simon Glass5dfc1c82024-10-19 09:21:47 -0600126void alist_update_end(struct alist *lst, const void *ptr)
127{
128 int index;
129
130 index = alist_calc_index(lst, ptr);
131 lst->count = index == -1 ? 0 : index;
132}
133
Simon Glassd785a772024-10-19 09:21:45 -0600134bool alist_chk_ptr(const struct alist *lst, const void *ptr)
135{
136 int index = alist_calc_index(lst, ptr);
137
138 return index >= 0 && index < lst->count;
139}
140
Simon Glass1d49f782024-10-19 09:21:44 -0600141const void *alist_next_ptrd(const struct alist *lst, const void *ptr)
142{
143 int index = alist_calc_index(lst, ptr);
144
145 assert(index != -1);
146
147 return alist_get_ptr(lst, index + 1);
148}
149
Simon Glass75581e42024-07-30 08:39:37 -0600150void *alist_ensure_ptr(struct alist *lst, uint index)
151{
152 uint minsize = index + 1;
153 void *ptr;
154
155 if (index >= lst->alloc && !alist_expand_min(lst, minsize))
156 return NULL;
157
158 ptr = lst->data + index * lst->obj_size;
159 if (minsize >= lst->count)
160 lst->count = minsize;
161
162 return ptr;
163}
164
165void *alist_add_placeholder(struct alist *lst)
166{
167 return alist_ensure_ptr(lst, lst->count);
168}
169
170void *alist_add_ptr(struct alist *lst, void *obj)
171{
172 void *ptr;
173
174 ptr = alist_add_placeholder(lst);
175 if (!ptr)
176 return NULL;
177 memcpy(ptr, obj, lst->obj_size);
178
179 return ptr;
180}
181
182void *alist_uninit_move_ptr(struct alist *alist, size_t *countp)
183{
184 void *ptr;
185
186 if (countp)
187 *countp = alist->count;
188 if (!alist->count) {
189 alist_uninit(alist);
190 return NULL;
191 }
192
193 ptr = alist->data;
194
195 /* Clear everything out so there is no record of the data */
196 alist_init(alist, alist->obj_size, 0);
197
198 return ptr;
199}