fix [#33305] Bevel tool crashes Blender if the number of segments exceeds 28
[blender.git] / source / blender / blenlib / BLI_array.h
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joseph Eagar.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file BLI_array.h
29  *  \ingroup bli
30  *  \brief A macro array library.
31  *
32  * this library needs to be changed to not use macros quite so heavily,
33  * and to be more of a complete array API.  The way arrays are
34  * exposed to client code as normal C arrays is very useful though, imho.
35  * it does require some use of macros, however.
36  *
37  * anyway, it's used a bit too heavily to simply rewrite as a
38  * more "correct" solution without macros entirely.  I originally wrote this
39  * to be very easy to use, without the normal pain of most array libraries.
40  * This was especially helpful when it came to the massive refactors necessary
41  * for bmesh, and really helped to speed the process up. - joeedh
42  *
43  * little array macro library.  example of usage:
44  *
45  * int *arr = NULL;
46  * BLI_array_declare(arr);
47  * int i;
48  *
49  * for (i = 0; i < 10; i++) {
50  *     BLI_array_grow_one(arr);
51  *     arr[i] = something;
52  * }
53  * BLI_array_free(arr);
54  *
55  * arrays are buffered, using double-buffering (so on each reallocation,
56  * the array size is doubled).  supposedly this should give good Big Oh
57  * behavior, though it may not be the best in practice.
58  */
59
60 #define BLI_array_declare(arr)                                                \
61         int   _##arr##_count = 0;                                                 \
62         void *_##arr##_tmp;                                                       \
63         void *_##arr##_static = NULL
64
65 /* this will use stack space, up to maxstatic array elements, before
66  * switching to dynamic heap allocation */
67 #define BLI_array_staticdeclare(arr, maxstatic)                               \
68         int   _##arr##_count = 0;                                                 \
69         void *_##arr##_tmp;                                                       \
70         char  _##arr##_static[maxstatic * sizeof(arr)]
71
72
73 /* this returns the entire size of the array, including any buffering. */
74 #define BLI_array_totalsize_dyn(arr)  (                                       \
75         ((arr) == NULL) ?                                                         \
76             0 :                                                                   \
77             MEM_allocN_len(arr) / sizeof(*arr)                                    \
78 )
79
80 #define _bli_array_totalsize_static(arr)  \
81         (sizeof(_##arr##_static) / sizeof(*arr))
82
83 #define BLI_array_totalsize(arr)  (                                           \
84         (size_t)                                                                  \
85         (((void *)(arr) == (void *)_##arr##_static && (void *)(arr) != NULL) ?    \
86             _bli_array_totalsize_static(arr) :                                    \
87             BLI_array_totalsize_dyn(arr))                                         \
88 )
89
90
91 /* this returns the logical size of the array, not including buffering. */
92 #define BLI_array_count(arr) _##arr##_count
93
94 /* Grow the array by a fixed number of items. zeroes the new elements.
95  *
96  * Allow for a large 'num' value when the new size is more then double
97  * to allocate the exact sized array. */
98
99 /* grow an array by a specified number of items */
100 #define BLI_array_grow_items(arr, num)  (                                     \
101         (((void *)(arr) == NULL) &&                                               \
102          ((void *)(_##arr##_static) != NULL) &&                                   \
103         /* dont add _##arr##_count below because it must be zero */               \
104          (_bli_array_totalsize_static(arr) >= _##arr##_count + num)) ?            \
105         /* we have an empty array and a static var big enough */                  \
106         ((arr = (void *)_##arr##_static), (_##arr##_count += (num)))              \
107             :                                                                     \
108         /* use existing static array or allocate */                               \
109         ((BLI_array_totalsize(arr) >= _##arr##_count + num) ?                     \
110             (_##arr##_count += num) :                                             \
111             (                                                                     \
112                 (void) (_##arr##_tmp = MEM_callocN(                               \
113                         sizeof(*arr) * (num < _##arr##_count ?                    \
114                                         (_##arr##_count * 2 + 2) :                \
115                                         (_##arr##_count + num)),                  \
116                         #arr " " __FILE__ ":" STRINGIFY(__LINE__)                 \
117                         )                                                         \
118                         ),                                                        \
119                 (void) (arr && memcpy(_##arr##_tmp,                               \
120                                       arr,                                        \
121                                       sizeof(*arr) * _##arr##_count)              \
122                         ),                                                        \
123                 (void) (arr && ((void *)(arr) != (void *)_##arr##_static ?        \
124                         (MEM_freeN(arr), arr) :                                   \
125                         arr)                                                      \
126                         ),                                                        \
127                 (void) (arr = _##arr##_tmp                                        \
128                         ),                                                        \
129                 (_##arr##_count += num)                                           \
130             ))                                                                    \
131 )
132
133 /* returns length of array */
134 #define BLI_array_grow_one(arr)  BLI_array_grow_items(arr, 1)
135
136
137 /* appends an item to the array. */
138 #define BLI_array_append(arr, item)  (                                        \
139         (void) BLI_array_grow_one(arr),                                           \
140         (void) (arr[_##arr##_count - 1] = item)                                   \
141 )
142
143 /* appends an item to the array and returns a pointer to the item in the array.
144  * item is not a pointer, but actual data value.*/
145 #define BLI_array_append_r(arr, item)  (                                      \
146         (void) BLI_array_grow_one(arr),                                           \
147         (void) (arr[_##arr##_count - 1] = item),                                  \
148         (&arr[_##arr##_count - 1])                                                \
149 )
150
151 #define BLI_array_reserve(arr, num)                                           \
152         BLI_array_grow_items(arr, num), (void)(_##arr##_count -= (num))
153
154
155 #define BLI_array_free(arr)                                                   \
156         if (arr && (char *)arr != _##arr##_static) {                              \
157             BLI_array_fake_user(arr);                                             \
158             MEM_freeN(arr);                                                       \
159         } (void)0
160
161 #define BLI_array_pop(arr)  (                                                 \
162         (arr && _##arr##_count) ?                                                 \
163             arr[--_##arr##_count] :                                               \
164             NULL                                                                  \
165 )
166
167 /* resets the logical size of an array to zero, but doesn't
168  * free the memory. */
169 #define BLI_array_empty(arr)                                                  \
170         _##arr##_count = 0; (void)0
171
172 /* set the count of the array, doesn't actually increase the allocated array
173  * size.  don't use this unless you know what you're doing. */
174 #define BLI_array_length_set(arr, count)                                      \
175         _##arr##_count = (count); (void)0
176
177 /* only to prevent unused warnings */
178 #define BLI_array_fake_user(arr)                                              \
179         (void)_##arr##_count,                                                     \
180         (void)_##arr##_tmp,                                                       \
181         (void)_##arr##_static
182
183
184 /* not part of the 'API' but handy funcs,
185  * same purpose as BLI_array_staticdeclare()
186  * but use when the max size is known ahead of time */
187 #define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr)      \
188         char _##arr##_static[maxstatic * sizeof(*(arr))];                         \
189         const int _##arr##_is_static = ((void *)_##arr##_static) != (             \
190             arr = ((realsize) <= maxstatic) ?                                     \
191                 (void *)_##arr##_static :                                         \
192                 MEM_mallocN(sizeof(*(arr)) * (realsize), allocstr)                \
193             )                                                                     \
194
195 #define BLI_array_fixedstack_free(arr)                                        \
196         if (_##arr##_is_static) {                                                 \
197                 MEM_freeN(arr);                                                       \
198         } (void)0