Merge branch 'master' into blender2.8
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #ifndef __BLI_ARRAY_H__
29 #define __BLI_ARRAY_H__
30
31 /** \file BLI_array.h
32  *  \ingroup bli
33  *  \brief A (mainly) macro array library.
34  */
35
36 /* -------------------------------------------------------------------- */
37 /** \name Internal defines
38  * \{ */
39
40 /** this returns the entire size of the array, including any buffering. */
41 #define _bli_array_totalsize_dynamic(arr)  (                                  \
42         ((arr) == NULL) ?                                                         \
43             0 :                                                                   \
44             MEM_allocN_len(arr) / sizeof(*(arr))                                  \
45 )
46
47 #define _bli_array_totalsize_static(arr)  \
48         (sizeof(_##arr##_static) / sizeof(*(arr)))
49
50 #define _bli_array_totalsize(arr)  (                                          \
51         (size_t)                                                                  \
52         (((void *)(arr) == (void *)_##arr##_static && (void *)(arr) != NULL) ?    \
53             _bli_array_totalsize_static(arr) :                                    \
54             _bli_array_totalsize_dynamic(arr))                                    \
55 )
56
57 /** \} */
58
59
60 /** BLI_array.c
61  *
62  * Doing the realloc in a macro isn't so simple,
63  * so use a function the macros can use.
64  */
65 void _bli_array_grow_func(void **arr_p, const void *arr_static,
66                           const int sizeof_arr_p, const int arr_count, const int num,
67                           const char *alloc_str);
68
69
70 /* -------------------------------------------------------------------- */
71
72 /** \name Public defines
73  * \{ */
74
75 /** use ``sizeof(*(arr))`` to ensure the array exists and is an array */
76 #define BLI_array_declare(arr)                                                \
77         int   _##arr##_count = ((void)(sizeof(*(arr))), 0);                       \
78         void *_##arr##_static = NULL
79
80 /**
81  * this will use stack space, up to maxstatic array elements, before
82  * switching to dynamic heap allocation */
83 #define BLI_array_staticdeclare(arr, maxstatic)                               \
84         int   _##arr##_count = 0;                                                 \
85         char  _##arr##_static[maxstatic * sizeof(*(arr))]
86
87 /** returns the logical size of the array, not including buffering. */
88 #define BLI_array_count(arr) ((void)0, _##arr##_count)
89
90 /**
91  * Grow the array by a fixed number of items.
92  *
93  * Allow for a large 'num' value when the new size is more than double
94  * to allocate the exact sized array. */
95 #define BLI_array_reserve(arr, num)  (void)(                                  \
96         (((void *)(arr) == NULL) &&                                               \
97          ((void *)(_##arr##_static) != NULL) &&                                   \
98         /* don't add _##arr##_count below because it must be zero */              \
99          (_bli_array_totalsize_static(arr) >= _##arr##_count + (num))) ?          \
100         /* we have an empty array and a static var big enough */                  \
101         (void)(arr = (void *)_##arr##_static)                                     \
102             :                                                                     \
103         /* use existing static array or allocate */                               \
104         (LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + (num)) ?            \
105          (void)0 /* do nothing */ :                                               \
106          _bli_array_grow_func((void **)&(arr), _##arr##_static,                   \
107                                sizeof(*(arr)), _##arr##_count, num,               \
108                                "BLI_array." #arr))                                \
109         )
110
111
112 /** returns length of array */
113 #define BLI_array_grow_items(arr, num) \
114         (BLI_array_reserve(arr, num), (_##arr##_count += num))
115
116 #define BLI_array_grow_one(arr) \
117         BLI_array_grow_items(arr, 1)
118
119 /** appends an item to the array. */
120 #define BLI_array_append(arr, item)  (                                        \
121         (void) BLI_array_grow_one(arr),                                           \
122         (void) (arr[_##arr##_count - 1] = item)                                   \
123 )
124
125 /**
126  * appends an item to the array and returns a pointer to the item in the array.
127  * item is not a pointer, but actual data value.*/
128 #define BLI_array_append_r(arr, item)  (                                      \
129         (void) BLI_array_grow_one(arr),                                           \
130         (void) (arr[_##arr##_count - 1] = item),                                  \
131         (&arr[_##arr##_count - 1])                                                \
132 )
133
134 /** appends (grows) & returns a pointer to the uninitialized memory */
135 #define BLI_array_append_ret(arr) \
136         (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)])
137
138 #define BLI_array_free(arr)                                                   \
139         if (arr && (char *)arr != _##arr##_static) {                              \
140                 BLI_array_fake_user(arr);                                             \
141                 MEM_freeN(arr);                                                       \
142         } (void)0
143
144 #define BLI_array_pop(arr)  (                                                 \
145         (arr && _##arr##_count) ?                                                 \
146             arr[--_##arr##_count] :                                               \
147             NULL                                                                  \
148 )
149
150 /**
151  * resets the logical size of an array to zero, but doesn't
152  * free the memory. */
153 #define BLI_array_empty(arr)                                                  \
154         { _##arr##_count = 0; } (void)0
155
156 /**
157  * set the count of the array, doesn't actually increase the allocated array
158  * size.  don't use this unless you know what you're doing. */
159 #define BLI_array_count_set(arr, count)                                      \
160         { _##arr##_count = (count); }(void)0
161
162 /** only to prevent unused warnings */
163 #define BLI_array_fake_user(arr)                                              \
164         ((void)_##arr##_count,                                                    \
165          (void)_##arr##_static)
166
167 /** \} */
168
169
170 /* -------------------------------------------------------------------- */
171
172 /** \name Generic Array Utils
173  * other useful defines
174  * (unrelated to the main array macros)
175  *
176  * \{ */
177
178 /**
179  * not part of the 'API' but handy funcs,
180  * same purpose as #BLI_array_staticdeclare()
181  * but use when the max size is known ahead of time */
182 #define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr)      \
183         char _##arr##_static[maxstatic * sizeof(*(arr))];                         \
184         const bool _##arr##_is_static = ((void *)_##arr##_static) != (            \
185             arr = ((realsize) <= maxstatic) ?                                     \
186                 (void *)_##arr##_static :                                         \
187                 MEM_mallocN(sizeof(*(arr)) * (realsize), allocstr)                \
188             )                                                                     \
189
190 #define BLI_array_fixedstack_free(arr)                                        \
191         if (_##arr##_is_static) {                                                 \
192                 MEM_freeN(arr);                                                       \
193         } (void)0
194
195 /** \} */
196
197 #endif  /* __BLI_ARRAY_H__ */