Blender  V2.93
BLI_memiter.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "BLI_asan.h"
44 #include "BLI_utildefines.h"
45 
46 #include "BLI_memiter.h" /* own include */
47 
48 #include "MEM_guardedalloc.h"
49 
50 #include "BLI_strict_flags.h" /* keep last */
51 
52 /* TODO: Valgrind. */
53 
54 typedef uintptr_t data_t;
56 
57 /* Write the chunk terminator on adding each element.
58  * typically we rely on the 'count' to avoid iterating past the end. */
59 // #define USE_TERMINATE_PARANOID
60 
61 /* Currently totalloc isn't used. */
62 // #define USE_TOTALLOC
63 
64 /* pad must be power of two */
65 #define PADUP(num, pad) (((num) + ((pad)-1)) & ~((pad)-1))
66 
67 typedef struct BLI_memiter_elem {
71 
72 typedef struct BLI_memiter_chunk {
82 
83 typedef struct BLI_memiter {
84  /* A pointer to 'head' is needed so we can iterate in the order allocated. */
88  /* Used unless a large element is requested.
89  * (which should be very rare!). */
92 #ifdef USE_TOTALLOC
93  uint totalloc;
94 #endif
96 
98 {
99  return (PADUP(size, (uint)sizeof(data_t))) / (uint)sizeof(data_t);
100 }
101 
103 {
105 
106  BLI_asan_unpoison(elem, sizeof(BLI_memiter_elem));
107 
108  elem->size = (offset_t)(((data_t *)mi->tail) - mi->data_curr);
109  BLI_assert(elem->size < 0);
110 }
111 
112 static void memiter_init(BLI_memiter *mi)
113 {
114  mi->head = NULL;
115  mi->tail = NULL;
116  mi->data_curr = NULL;
117  mi->data_last = NULL;
118  mi->count = 0;
119 #ifdef USE_TOTALLOC
120  mi->totalloc = 0;
121 #endif
122 }
123 
124 /* -------------------------------------------------------------------- */
138 {
139  BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
140  memiter_init(mi);
141 
142  /* Small values are used for tests to check for correctness,
143  * but otherwise not that useful. */
144  const uint slop_space = (sizeof(BLI_memiter_chunk) + MEM_SIZE_OVERHEAD);
145  if (chunk_size_min >= 1024) {
146  /* As long as the input is a power of 2, this will give efficient sizes. */
147  chunk_size_min -= slop_space;
148  }
149 
150  mi->chunk_size_in_bytes_min = chunk_size_min;
151  return mi;
152 }
153 
154 void *BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
155 {
156  const uint data_offset = data_offset_from_size(elem_size);
157  data_t *data_curr_next = mi->data_curr + (1 + data_offset);
158 
159  if (UNLIKELY(mi->data_curr == NULL) || (data_curr_next > mi->data_last)) {
160 
161 #ifndef USE_TERMINATE_PARANOID
162  if (mi->data_curr != NULL) {
164  }
165 #endif
166 
167  uint chunk_size_in_bytes = mi->chunk_size_in_bytes_min;
168  if (UNLIKELY(chunk_size_in_bytes < elem_size + (uint)sizeof(data_t[2]))) {
169  chunk_size_in_bytes = elem_size + (uint)sizeof(data_t[2]);
170  }
171  uint chunk_size = data_offset_from_size(chunk_size_in_bytes);
173  sizeof(BLI_memiter_chunk) + (chunk_size * sizeof(data_t)), "BLI_memiter_chunk");
174 
175  if (mi->head == NULL) {
176  BLI_assert(mi->tail == NULL);
177  mi->head = chunk;
178  }
179  else {
180  mi->tail->next = chunk;
181  }
182  mi->tail = chunk;
183  chunk->next = NULL;
184 
185  mi->data_curr = chunk->data;
186  mi->data_last = chunk->data + (chunk_size - 1);
187  data_curr_next = mi->data_curr + (1 + data_offset);
188 
189  BLI_asan_poison(chunk->data, chunk_size * sizeof(data_t));
190  }
191 
192  BLI_assert(data_curr_next <= mi->data_last);
193 
195 
196  BLI_asan_unpoison(elem, sizeof(BLI_memiter_elem) + elem_size);
197 
198  elem->size = (offset_t)elem_size;
199  mi->data_curr = data_curr_next;
200 
201 #ifdef USE_TERMINATE_PARANOID
203 #endif
204 
205  mi->count += 1;
206 
207 #ifdef USE_TOTALLOC
208  mi->totalloc += elem_size;
209 #endif
210 
211  return elem->data;
212 }
213 
214 void *BLI_memiter_calloc(BLI_memiter *mi, uint elem_size)
215 {
216  void *data = BLI_memiter_alloc(mi, elem_size);
217  memset(data, 0, elem_size);
218  return data;
219 }
220 
221 void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
222 {
223  void *data = BLI_memiter_alloc(mi, elem_size);
224  memcpy(data, data_from, elem_size);
225 }
226 
228 {
229  BLI_memiter_chunk *chunk = mi->head;
230  while (chunk) {
231  BLI_memiter_chunk *chunk_next = chunk->next;
232 
233  /* Unpoison memory because MEM_freeN might overwrite it. */
234  BLI_asan_unpoison(chunk, MEM_allocN_len(chunk));
235 
236  MEM_freeN(chunk);
237  chunk = chunk_next;
238  }
239 }
240 
242 {
243  memiter_free_data(mi);
244  MEM_freeN(mi);
245 }
246 
248 {
249  memiter_free_data(mi);
250  memiter_init(mi);
251 }
252 
254 {
255  return mi->count;
256 }
257 
260 /* -------------------------------------------------------------------- */
264 /* Support direct lookup for first. */
266 {
267  if (mi->head != NULL) {
268  BLI_memiter_chunk *chunk = mi->head;
269  BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
270  return elem->data;
271  }
272  return NULL;
273 }
274 
276 {
277  if (mi->head != NULL) {
278  BLI_memiter_chunk *chunk = mi->head;
279  BLI_memiter_elem *elem = (BLI_memiter_elem *)chunk->data;
280  *r_size = (uint)elem->size;
281  return elem->data;
282  }
283  return NULL;
284 }
285 
288 /* -------------------------------------------------------------------- */
300 {
301  iter->elem = mi->head ? (BLI_memiter_elem *)mi->head->data : NULL;
302  iter->elem_left = mi->count;
303 }
304 
306 {
307  return iter->elem_left != 0;
308 }
309 
311 {
312  BLI_assert(iter->elem->size < 0);
313  BLI_memiter_chunk *chunk = (BLI_memiter_chunk *)(((data_t *)iter->elem) + iter->elem->size);
314  chunk = chunk->next;
315  iter->elem = chunk ? (BLI_memiter_elem *)chunk->data : NULL;
316  BLI_assert(iter->elem == NULL || iter->elem->size >= 0);
317 }
318 
320 {
321  if (iter->elem_left != 0) {
322  iter->elem_left -= 1;
323  if (UNLIKELY(iter->elem->size < 0)) {
324  memiter_chunk_step(iter);
325  }
326  BLI_assert(iter->elem->size >= 0);
327  uint size = (uint)iter->elem->size;
328  *r_size = size; /* <-- only difference */
329  data_t *data = iter->elem->data;
331  return (void *)data;
332  }
333  return NULL;
334 }
335 
337 {
338  if (iter->elem_left != 0) {
339  iter->elem_left -= 1;
340  if (UNLIKELY(iter->elem->size < 0)) {
341  memiter_chunk_step(iter);
342  }
343  BLI_assert(iter->elem->size >= 0);
344  uint size = (uint)iter->elem->size;
345  data_t *data = iter->elem->data;
347  return (void *)data;
348  }
349  return NULL;
350 }
351 
#define BLI_asan_unpoison(addr, size)
Definition: BLI_asan.h:42
#define BLI_asan_poison(addr, size)
Definition: BLI_asan.h:37
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
static void memiter_set_rewind_offset(BLI_memiter *mi)
Definition: BLI_memiter.c:102
void * BLI_memiter_iter_step(BLI_memiter_handle *iter)
Definition: BLI_memiter.c:336
void * BLI_memiter_calloc(BLI_memiter *mi, uint elem_size)
Definition: BLI_memiter.c:214
void BLI_memiter_clear(BLI_memiter *mi)
Definition: BLI_memiter.c:247
uintptr_t data_t
Definition: BLI_memiter.c:54
struct BLI_memiter_chunk BLI_memiter_chunk
void BLI_memiter_iter_init(BLI_memiter *mi, BLI_memiter_handle *iter)
Definition: BLI_memiter.c:299
#define PADUP(num, pad)
Definition: BLI_memiter.c:65
void * BLI_memiter_iter_step_size(BLI_memiter_handle *iter, uint *r_size)
Definition: BLI_memiter.c:319
void * BLI_memiter_elem_first_size(BLI_memiter *mi, uint *r_size)
Definition: BLI_memiter.c:275
static void memiter_init(BLI_memiter *mi)
Definition: BLI_memiter.c:112
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
Definition: BLI_memiter.c:221
BLI_memiter * BLI_memiter_create(uint chunk_size_min)
Definition: BLI_memiter.c:137
uint BLI_memiter_count(const BLI_memiter *mi)
Definition: BLI_memiter.c:253
bool BLI_memiter_iter_done(const BLI_memiter_handle *iter)
Definition: BLI_memiter.c:305
struct BLI_memiter BLI_memiter
BLI_INLINE void memiter_chunk_step(BLI_memiter_handle *iter)
Definition: BLI_memiter.c:310
static void memiter_free_data(BLI_memiter *mi)
Definition: BLI_memiter.c:227
struct BLI_memiter_elem BLI_memiter_elem
void * BLI_memiter_alloc(BLI_memiter *mi, uint elem_size)
Definition: BLI_memiter.c:154
void BLI_memiter_destroy(BLI_memiter *mi)
Definition: BLI_memiter.c:241
BLI_INLINE uint data_offset_from_size(uint size)
Definition: BLI_memiter.c:97
void * BLI_memiter_elem_first(BLI_memiter *mi)
Definition: BLI_memiter.c:265
intptr_t offset_t
Definition: BLI_memiter.c:55
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_SIZE_OVERHEAD
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:40
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
_W64 unsigned int uintptr_t
Definition: stdint.h:122
_W64 int intptr_t
Definition: stdint.h:121
struct BLI_memiter_chunk * next
Definition: BLI_memiter.c:73
data_t data[0]
Definition: BLI_memiter.c:80
data_t data[0]
Definition: BLI_memiter.c:69
struct BLI_memiter_elem * elem
Definition: BLI_memiter.h:58
data_t * data_last
Definition: BLI_memiter.c:87
uint chunk_size_in_bytes_min
Definition: BLI_memiter.c:90
struct BLI_memiter_chunk * tail
Definition: BLI_memiter.c:85
data_t * data_curr
Definition: BLI_memiter.c:86
struct BLI_memiter_chunk * head
Definition: BLI_memiter.c:85