Blender V4.3
BLI_memiter.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
28#include <stdlib.h>
29#include <string.h>
30
31#include "BLI_asan.h"
32#include "BLI_utildefines.h"
33
34#include "BLI_memiter.h" /* own include */
35
36#include "MEM_guardedalloc.h"
37
38#include "BLI_strict_flags.h" /* Keep last. */
39
40/* TODO: Valgrind. */
41
44
45/* Write the chunk terminator on adding each element.
46 * typically we rely on the 'count' to avoid iterating past the end. */
47// #define USE_TERMINATE_PARANOID
48
49/* Currently totalloc isn't used. */
50// #define USE_TOTALLOC
51
52/* pad must be power of two */
53#define PADUP(num, pad) (((num) + ((pad)-1)) & ~((pad)-1))
54
59
70
71typedef struct BLI_memiter {
72 /* A pointer to 'head' is needed so we can iterate in the order allocated. */
76 /* Used unless a large element is requested.
77 * (which should be very rare!). */
80#ifdef USE_TOTALLOC
81 uint totalloc;
82#endif
84
86{
87 return PADUP(size, (uint)sizeof(data_t)) / (uint)sizeof(data_t);
88}
89
91{
93
95
96 elem->size = (offset_t)(((data_t *)mi->tail) - mi->data_curr);
97 BLI_assert(elem->size < 0);
98}
99
100static void memiter_init(BLI_memiter *mi)
101{
102 mi->head = NULL;
103 mi->tail = NULL;
104 mi->data_curr = NULL;
105 mi->data_last = NULL;
106 mi->count = 0;
107#ifdef USE_TOTALLOC
108 mi->totalloc = 0;
109#endif
110}
111
112/* -------------------------------------------------------------------- */
117{
118 BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
119 memiter_init(mi);
120
121 /* Small values are used for tests to check for correctness,
122 * but otherwise not that useful. */
123 const uint slop_space = (sizeof(BLI_memiter_chunk) + MEM_SIZE_OVERHEAD);
124 if (chunk_size_min >= 1024) {
125 /* As long as the input is a power of 2, this will give efficient sizes. */
126 chunk_size_min -= slop_space;
127 }
128
129 mi->chunk_size_in_bytes_min = chunk_size_min;
130 return mi;
131}
132
133void *BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
134{
135 const uint data_offset = data_offset_from_size(elem_size);
136 data_t *data_curr_next = LIKELY(mi->data_curr) ? mi->data_curr + (1 + data_offset) : NULL;
137
138 if (UNLIKELY(mi->data_curr == NULL) || (data_curr_next > mi->data_last)) {
139
140#ifndef USE_TERMINATE_PARANOID
141 if (mi->data_curr != NULL) {
143 }
144#endif
145
146 uint chunk_size_in_bytes = mi->chunk_size_in_bytes_min;
147 if (UNLIKELY(chunk_size_in_bytes < elem_size + (uint)sizeof(data_t[2]))) {
148 chunk_size_in_bytes = elem_size + (uint)sizeof(data_t[2]);
149 }
150 uint chunk_size = data_offset_from_size(chunk_size_in_bytes);
152 sizeof(BLI_memiter_chunk) + (chunk_size * sizeof(data_t)), "BLI_memiter_chunk");
153
154 if (mi->head == NULL) {
155 BLI_assert(mi->tail == NULL);
156 mi->head = chunk;
157 }
158 else {
159 mi->tail->next = chunk;
160 }
161 mi->tail = chunk;
162 chunk->next = NULL;
163
164 mi->data_curr = chunk->data;
165 mi->data_last = chunk->data + (chunk_size - 1);
166 data_curr_next = mi->data_curr + (1 + data_offset);
167
168 BLI_asan_poison(chunk->data, chunk_size * sizeof(data_t));
169 }
170
171 BLI_assert(data_curr_next <= mi->data_last);
172
174
175 BLI_asan_unpoison(elem, sizeof(BLI_memiter_elem) + elem_size);
176
177 elem->size = (offset_t)elem_size;
178 mi->data_curr = data_curr_next;
179
180#ifdef USE_TERMINATE_PARANOID
182#endif
183
184 mi->count += 1;
185
186#ifdef USE_TOTALLOC
187 mi->totalloc += elem_size;
188#endif
189
190 return elem->data;
191}
192
194{
195 void *data = BLI_memiter_alloc(mi, elem_size);
196 memset(data, 0, elem_size);
197 return data;
198}
199
200void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
201{
202 void *data = BLI_memiter_alloc(mi, elem_size);
203 memcpy(data, data_from, elem_size);
204}
205
207{
208 BLI_memiter_chunk *chunk = mi->head;
209 while (chunk) {
210 BLI_memiter_chunk *chunk_next = chunk->next;
211
212 /* Unpoison memory because MEM_freeN might overwrite it. */
213 BLI_asan_unpoison(chunk, MEM_allocN_len(chunk));
214
215 MEM_freeN(chunk);
216 chunk = chunk_next;
217 }
218}
219
221{
223 MEM_freeN(mi);
224}
225
227{
229 memiter_init(mi);
230}
231
233{
234 return mi->count;
235}
236
239/* -------------------------------------------------------------------- */
244{
245 if (mi->head != NULL) {
246 BLI_memiter_chunk *chunk = mi->head;
247 BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
248 return elem->data;
249 }
250 return NULL;
251}
252
254{
255 if (mi->head != NULL) {
256 BLI_memiter_chunk *chunk = mi->head;
257 BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
258 *r_size = (uint)elem->size;
259 return elem->data;
260 }
261 return NULL;
262}
263
266/* -------------------------------------------------------------------- */
278{
279 iter->elem = mi->head ? (BLI_memiter_elem *)mi->head->data : NULL;
280 iter->elem_left = mi->count;
281}
282
284{
285 return iter->elem_left != 0;
286}
287
289{
290 BLI_assert(iter->elem->size < 0);
291 BLI_memiter_chunk *chunk = (BLI_memiter_chunk *)(((data_t *)iter->elem) + iter->elem->size);
292 chunk = chunk->next;
293 iter->elem = chunk ? (BLI_memiter_elem *)chunk->data : NULL;
294 BLI_assert(iter->elem == NULL || iter->elem->size >= 0);
295}
296
298{
299 if (iter->elem_left != 0) {
300 iter->elem_left -= 1;
301 if (UNLIKELY(iter->elem->size < 0)) {
302 memiter_chunk_step(iter);
303 }
304 BLI_assert(iter->elem->size >= 0);
305 uint size = (uint)iter->elem->size;
306 *r_size = size; /* <-- only difference */
307 data_t *data = iter->elem->data;
308 iter->elem = (BLI_memiter_elem *)&data[data_offset_from_size(size)];
309 return (void *)data;
310 }
311 return NULL;
312}
313
315{
316 if (iter->elem_left != 0) {
317 iter->elem_left -= 1;
318 if (UNLIKELY(iter->elem->size < 0)) {
319 memiter_chunk_step(iter);
320 }
321 BLI_assert(iter->elem->size >= 0);
322 uint size = (uint)iter->elem->size;
323 data_t *data = iter->elem->data;
324 iter->elem = (BLI_memiter_elem *)&data[data_offset_from_size(size)];
325 return (void *)data;
326 }
327 return NULL;
328}
329
#define BLI_asan_unpoison(addr, size)
Definition BLI_asan.h:32
#define BLI_asan_poison(addr, size)
Definition BLI_asan.h:27
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
static void memiter_set_rewind_offset(BLI_memiter *mi)
Definition BLI_memiter.c:90
void BLI_memiter_clear(BLI_memiter *mi)
void * BLI_memiter_elem_first(BLI_memiter *mi)
uintptr_t data_t
Definition BLI_memiter.c:42
struct BLI_memiter_chunk BLI_memiter_chunk
void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter)
#define PADUP(num, pad)
Definition BLI_memiter.c:53
void * BLI_memiter_iter_step_size(BLI_memiter_handle *iter, uint *r_size)
static void memiter_init(BLI_memiter *mi)
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
void * BLI_memiter_elem_first_size(BLI_memiter *mi, uint *r_size)
uint BLI_memiter_count(const BLI_memiter *mi)
bool BLI_memiter_iter_done(const BLI_memiter_handle *iter)
struct BLI_memiter BLI_memiter
BLI_INLINE void memiter_chunk_step(BLI_memiter_handle *iter)
static void memiter_free_data(BLI_memiter *mi)
BLI_memiter * BLI_memiter_create(uint chunk_size_min)
void * BLI_memiter_iter_step(BLI_memiter_handle *iter)
struct BLI_memiter_elem BLI_memiter_elem
void * BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
void BLI_memiter_destroy(BLI_memiter *mi)
BLI_INLINE uint data_offset_from_size(uint size)
Definition BLI_memiter.c:85
void * BLI_memiter_calloc(BLI_memiter *mi, uint elem_size)
intptr_t offset_t
Definition BLI_memiter.c:43
unsigned int uint
#define UNLIKELY(x)
#define LIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_SIZE_OVERHEAD
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define NULL
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
size_t(* MEM_allocN_len)(const void *vmemh)
Definition mallocn.cc:36
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
_W64 unsigned int uintptr_t
Definition stdint.h:119
_W64 int intptr_t
Definition stdint.h:118
struct BLI_memiter_chunk * next
Definition BLI_memiter.c:61
struct BLI_memiter_elem * elem
Definition BLI_memiter.h:59
data_t * data_last
Definition BLI_memiter.c:75
BLI_memiter_chunk * tail
Definition BLI_memiter.c:73
uint chunk_size_in_bytes_min
Definition BLI_memiter.c:78
data_t * data_curr
Definition BLI_memiter.c:74
BLI_memiter_chunk * head
Definition BLI_memiter.c:73