"Das U-Boot" Source Tree
at master 199 lines 4.0 kB view raw
1// 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 44void alist_empty(struct alist *lst) 45{ 46 lst->count = 0; 47} 48 49/** 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 114int 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 126void 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 134bool 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 141const 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 150void *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}