Blender V5.0
stack.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib> /* abort() */
10#include <cstring>
11
12#include "BLI_utildefines.h"
13#include "MEM_guardedalloc.h"
14
15#include "BLI_stack.h" /* own include */
16
17#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
18
19#define USE_TOTELEM
20
21#define CHUNK_EMPTY size_t(-1)
22/* target chunks size: 64kb */
23#define CHUNK_SIZE_DEFAULT (1 << 16)
24/* ensure we get at least this many elems per chunk */
25#define CHUNK_ELEM_MIN 32
26
27struct StackChunk {
29 char data[0];
30};
31
32struct BLI_Stack {
33 StackChunk *chunk_curr; /* currently active chunk */
34 StackChunk *chunk_free; /* free chunks */
35 size_t chunk_index; /* index into 'chunk_curr' */
36 size_t chunk_elem_max; /* number of elements per chunk */
37 size_t elem_size;
38#ifdef USE_TOTELEM
39 size_t elem_num;
40#endif
41};
42
43static void *stack_get_last_elem(BLI_Stack *stack)
44{
45 return ((char *)(stack)->chunk_curr->data) + ((stack)->elem_size * (stack)->chunk_index);
46}
47
51static size_t stack_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
52{
53 /* get at least this number of elems per chunk */
54 const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN;
55
56 BLI_assert((elem_size != 0) && (chunk_size != 0));
57
58 while (UNLIKELY(chunk_size <= elem_size_min)) {
59 chunk_size <<= 1;
60 }
61
62 /* account for slop-space */
63 chunk_size -= (sizeof(StackChunk) + MEM_SIZE_OVERHEAD);
64
65 return chunk_size / elem_size;
66}
67
68BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
69 const char *description,
70 const size_t chunk_size)
71{
72 BLI_Stack *stack = MEM_callocN<BLI_Stack>(description);
73
74 stack->chunk_elem_max = stack_chunk_elem_max_calc(elem_size, chunk_size);
75 stack->elem_size = elem_size;
76 /* force init */
77 stack->chunk_index = stack->chunk_elem_max - 1;
78
79 return stack;
80}
81
82BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description)
83{
84 return BLI_stack_new_ex(elem_size, description, CHUNK_SIZE_DEFAULT);
85}
86
88{
89 while (data) {
90 StackChunk *data_next = data->next;
92 data = data_next;
93 }
94}
95
97{
100 MEM_freeN(stack);
101}
102
104{
105 stack->chunk_index++;
106
107 if (UNLIKELY(stack->chunk_index == stack->chunk_elem_max)) {
108 StackChunk *chunk;
109 if (stack->chunk_free) {
110 chunk = stack->chunk_free;
111 stack->chunk_free = chunk->next;
112 }
113 else {
114 chunk = static_cast<StackChunk *>(
115 MEM_mallocN(sizeof(*chunk) + (stack->elem_size * stack->chunk_elem_max), __func__));
116 }
117 chunk->next = stack->chunk_curr;
118 stack->chunk_curr = chunk;
119 stack->chunk_index = 0;
120 }
121
122 BLI_assert(stack->chunk_index < stack->chunk_elem_max);
123
124#ifdef USE_TOTELEM
125 stack->elem_num++;
126#endif
127
128 /* Return end of stack */
129 return stack_get_last_elem(stack);
130}
131
132void BLI_stack_push(BLI_Stack *stack, const void *src)
133{
134 void *dst = BLI_stack_push_r(stack);
135 memcpy(dst, src, stack->elem_size);
136}
137
138void BLI_stack_pop(BLI_Stack *stack, void *dst)
139{
140 BLI_assert(BLI_stack_is_empty(stack) == false);
141
142 memcpy(dst, stack_get_last_elem(stack), stack->elem_size);
143
144 BLI_stack_discard(stack);
145}
146
147void BLI_stack_pop_n(BLI_Stack *stack, void *dst, uint n)
148{
149 BLI_assert(n <= BLI_stack_count(stack));
150
151 while (n--) {
152 BLI_stack_pop(stack, dst);
153 dst = (void *)((char *)dst + stack->elem_size);
154 }
155}
156
157void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, uint n)
158{
159 BLI_assert(n <= BLI_stack_count(stack));
160
161 dst = (void *)((char *)dst + (stack->elem_size * n));
162
163 while (n--) {
164 dst = (void *)((char *)dst - stack->elem_size);
165 BLI_stack_pop(stack, dst);
166 }
167}
168
170{
171 BLI_assert(BLI_stack_is_empty(stack) == false);
172
173 return stack_get_last_elem(stack);
174}
175
177{
178 BLI_assert(BLI_stack_is_empty(stack) == false);
179
180#ifdef USE_TOTELEM
181 stack->elem_num--;
182#endif
183 if (UNLIKELY(--stack->chunk_index == CHUNK_EMPTY)) {
184 StackChunk *chunk_free;
185
186 chunk_free = stack->chunk_curr;
187 stack->chunk_curr = stack->chunk_curr->next;
188
189 chunk_free->next = stack->chunk_free;
190 stack->chunk_free = chunk_free;
191
192 stack->chunk_index = stack->chunk_elem_max - 1;
193 }
194}
195
197{
198#ifdef USE_TOTELEM
199 if (UNLIKELY(stack->elem_num == 0)) {
200 return;
201 }
202 stack->elem_num = 0;
203#else
204 if (UNLIKELY(stack->chunk_curr == nullptr)) {
205 return;
206 }
207#endif
208
209 stack->chunk_index = stack->chunk_elem_max - 1;
210
211 if (stack->chunk_free) {
212 if (stack->chunk_curr) {
213 /* move all used chunks into tail of free list */
214 StackChunk *chunk_free_last = stack->chunk_free;
215 while (chunk_free_last->next) {
216 chunk_free_last = chunk_free_last->next;
217 }
218 chunk_free_last->next = stack->chunk_curr;
219 stack->chunk_curr = nullptr;
220 }
221 }
222 else {
223 stack->chunk_free = stack->chunk_curr;
224 stack->chunk_curr = nullptr;
225 }
226}
227
228size_t BLI_stack_count(const BLI_Stack *stack)
229{
230#ifdef USE_TOTELEM
231 return stack->elem_num;
232#else
233 StackChunk *data = stack->chunk_curr;
234 size_t elem_num = stack->chunk_index + 1;
235 size_t i;
236 if (elem_num != stack->chunk_elem_max) {
237 data = data->next;
238 }
239 else {
240 elem_num = 0;
241 }
242 for (i = 0; data; data = data->next) {
243 i++;
244 }
245 elem_num += stack->chunk_elem_max * i;
246 return elem_num;
247#endif
248}
249
251{
252#ifdef USE_TOTELEM
253 BLI_assert((stack->chunk_curr == nullptr) == (stack->elem_num == 0));
254#endif
255 return (stack->chunk_curr == nullptr);
256}
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_stack_new(esize, descr)
unsigned int uint
#define UNLIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_SIZE_OVERHEAD
BMesh const char void * data
#define CHUNK_ELEM_MIN
Definition gsqueue.cc:24
#define CHUNK_SIZE_DEFAULT
Definition gsqueue.cc:22
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void BLI_stack_clear(BLI_Stack *stack)
Definition stack.cc:196
static void * stack_get_last_elem(BLI_Stack *stack)
Definition stack.cc:43
#define CHUNK_EMPTY
Definition stack.cc:21
BLI_Stack * BLI_stack_new_ex(const size_t elem_size, const char *description, const size_t chunk_size)
Definition stack.cc:68
static size_t stack_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
Definition stack.cc:51
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, uint n)
Definition stack.cc:157
static void stack_free_chunks(StackChunk *data)
Definition stack.cc:87
void BLI_stack_free(BLI_Stack *stack)
Definition stack.cc:96
void BLI_stack_discard(BLI_Stack *stack)
Definition stack.cc:176
void * BLI_stack_push_r(BLI_Stack *stack)
Definition stack.cc:103
size_t BLI_stack_count(const BLI_Stack *stack)
Definition stack.cc:228
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, uint n)
Definition stack.cc:147
void BLI_stack_pop(BLI_Stack *stack, void *dst)
Definition stack.cc:138
void BLI_stack_push(BLI_Stack *stack, const void *src)
Definition stack.cc:132
bool BLI_stack_is_empty(const BLI_Stack *stack)
Definition stack.cc:250
void * BLI_stack_peek(BLI_Stack *stack)
Definition stack.cc:169
StackChunk * chunk_free
Definition stack.cc:34
size_t elem_size
Definition stack.cc:37
size_t elem_num
Definition stack.cc:39
StackChunk * chunk_curr
Definition stack.cc:33
size_t chunk_elem_max
Definition stack.cc:36
size_t chunk_index
Definition stack.cc:35
StackChunk * next
Definition stack.cc:28
char data[0]
Definition stack.cc:29
i
Definition text_draw.cc:230