Blender  V2.93
BLI_memblock.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  * The Original Code is Copyright (C) 2008 by Blender Foundation.
17  * All rights reserved.
18  */
19 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "atomic_ops.h"
31 
32 #include "BLI_utildefines.h"
33 
34 #include "BLI_memblock.h" /* own include */
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "BLI_strict_flags.h" /* keep last */
39 
40 #define CHUNK_LIST_SIZE 16
41 
42 struct BLI_memblock {
43  void **chunk_list;
44 
46  int elem_size;
48  int elem_next;
50  int elem_last;
60  int chunk_len;
61 };
62 
64 {
65  BLI_assert(elem_size < chunk_size);
66 
67  BLI_memblock *mblk = MEM_mallocN(sizeof(BLI_memblock), "BLI_memblock");
68  mblk->elem_size = (int)elem_size;
69  mblk->elem_next = 0;
70  mblk->elem_last = -1;
71  mblk->chunk_size = (int)chunk_size;
72  mblk->chunk_len = CHUNK_LIST_SIZE;
73  mblk->chunk_list = MEM_callocN(sizeof(void *) * (uint)mblk->chunk_len, "chunk list");
74  mblk->chunk_list[0] = MEM_mallocN_aligned((uint)mblk->chunk_size, 32, "BLI_memblock chunk");
75  memset(mblk->chunk_list[0], 0x0, (uint)mblk->chunk_size);
76  mblk->chunk_max_ofs = (mblk->chunk_size / mblk->elem_size) * mblk->elem_size;
77  mblk->elem_next_ofs = 0;
78  mblk->chunk_next = 0;
79  return mblk;
80 }
81 
83 {
84  int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
85 
86  if (free_callback) {
87  for (int i = 0; i <= mblk->elem_last; i++) {
88  int chunk_idx = i / elem_per_chunk;
89  int elem_idx = i - elem_per_chunk * chunk_idx;
90  void *val = (char *)(mblk->chunk_list[chunk_idx]) + mblk->elem_size * elem_idx;
91  free_callback(val);
92  }
93  }
94 
95  for (int i = 0; i < mblk->chunk_len; i++) {
96  MEM_SAFE_FREE(mblk->chunk_list[i]);
97  }
99  MEM_freeN(mblk);
100 }
101 
102 /* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem
103  * count. */
105 {
106  int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
107  int last_used_chunk = mblk->elem_next / elem_per_chunk;
108 
109  if (free_callback) {
110  for (int i = mblk->elem_last; i >= mblk->elem_next; i--) {
111  int chunk_idx = i / elem_per_chunk;
112  int elem_idx = i - elem_per_chunk * chunk_idx;
113  void *val = (char *)(mblk->chunk_list[chunk_idx]) + mblk->elem_size * elem_idx;
114  free_callback(val);
115  }
116  }
117 
118  for (int i = last_used_chunk + 1; i < mblk->chunk_len; i++) {
119  MEM_SAFE_FREE(mblk->chunk_list[i]);
120  }
121 
122  if (UNLIKELY(last_used_chunk + 1 < mblk->chunk_len - CHUNK_LIST_SIZE)) {
123  mblk->chunk_len -= CHUNK_LIST_SIZE;
124  mblk->chunk_list = MEM_recallocN(mblk->chunk_list, sizeof(void *) * (uint)mblk->chunk_len);
125  }
126 
127  mblk->elem_last = mblk->elem_next - 1;
128  mblk->elem_next = 0;
129  mblk->elem_next_ofs = 0;
130  mblk->chunk_next = 0;
131 }
132 
134 {
135  /* Bookkeeping. */
136  if (mblk->elem_last < mblk->elem_next) {
137  mblk->elem_last = mblk->elem_next;
138  }
139  mblk->elem_next++;
140 
141  void *ptr = (char *)(mblk->chunk_list[mblk->chunk_next]) + mblk->elem_next_ofs;
142 
143  mblk->elem_next_ofs += mblk->elem_size;
144 
145  if (mblk->elem_next_ofs == mblk->chunk_max_ofs) {
146  mblk->elem_next_ofs = 0;
147  mblk->chunk_next++;
148 
149  if (UNLIKELY(mblk->chunk_next >= mblk->chunk_len)) {
150  mblk->chunk_len += CHUNK_LIST_SIZE;
151  mblk->chunk_list = MEM_recallocN(mblk->chunk_list, sizeof(void *) * (uint)mblk->chunk_len);
152  }
153 
154  if (UNLIKELY(mblk->chunk_list[mblk->chunk_next] == NULL)) {
156  (uint)mblk->chunk_size, 32, "BLI_memblock chunk");
157  memset(mblk->chunk_list[mblk->chunk_next], 0x0, (uint)mblk->chunk_size);
158  }
159  }
160  return ptr;
161 }
162 
164 {
165  /* Small copy of the memblock used for better cache coherence. */
166  iter->chunk_list = mblk->chunk_list;
167  iter->end_index = mblk->elem_next;
168  iter->cur_index = 0;
169  iter->chunk_idx = 0;
170  iter->elem_ofs = 0;
171  iter->elem_size = mblk->elem_size;
172  iter->chunk_max_ofs = mblk->chunk_max_ofs;
173 }
174 
176 {
177  if (iter->cur_index == iter->end_index) {
178  return NULL;
179  }
180 
181  iter->cur_index++;
182 
183  void *ptr = (char *)(iter->chunk_list[iter->chunk_idx]) + iter->elem_ofs;
184 
185  iter->elem_ofs += iter->elem_size;
186 
187  if (iter->elem_ofs == iter->chunk_max_ofs) {
188  iter->elem_ofs = 0;
189  iter->chunk_idx++;
190  }
191  return ptr;
192 }
193 
194 /* Direct access. elem is element index inside the chosen chunk.
195  * Double usage: You can set chunk to 0 and set the absolute elem index.
196  * The correct chunk will be retrieve. */
197 void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
198 {
199  BLI_assert(chunk < mblk->chunk_len);
200  int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
201  chunk += elem / elem_per_chunk;
202  elem = elem % elem_per_chunk;
203  return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem;
204 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define CHUNK_LIST_SIZE
Definition: BLI_memblock.c:40
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback)
Definition: BLI_memblock.c:104
BLI_memblock * BLI_memblock_create_ex(uint elem_size, uint chunk_size)
Definition: BLI_memblock.c:63
void * BLI_memblock_iterstep(BLI_memblock_iter *iter)
Definition: BLI_memblock.c:175
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter)
Definition: BLI_memblock.c:163
void * BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
Definition: BLI_memblock.c:197
void * BLI_memblock_alloc(BLI_memblock *mblk)
Definition: BLI_memblock.c:133
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
Definition: BLI_memblock.c:82
void(* MemblockValFreeFP)(void *val)
Definition: BLI_memblock.h:37
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_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN_aligned)(size_t len, size_t alignment, const char *str)
Definition: mallocn.c:49
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
void ** chunk_list
Definition: BLI_memblock.c:43
PointerRNA * ptr
Definition: wm_files.c:3157