Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo 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 Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #pragma once
19 : :
20 : : #include <stdalign.h>
21 : : #include <stdarg.h>
22 : : #include <stddef.h>
23 : : #include <stdint.h>
24 : : #include <string.h>
25 : :
26 : : // Unlike standard malloc, `size` may be 0, in which case this returns an empty
27 : : // allocation which can still be used as a parent for other allocations.
28 : : void *pl_alloc(void *parent, size_t size);
29 : : void *pl_zalloc(void *parent, size_t size);
30 : : void *pl_realloc(void *parent, void *ptr, size_t size);
31 : :
32 : : static inline void *pl_calloc(void *parent, size_t count, size_t size)
33 : : {
34 : 7079 : return pl_zalloc(parent, count * size);
35 : : }
36 : :
37 : : #define pl_tmp(parent) pl_alloc(parent, 0)
38 : :
39 : : // Variants of the above which resolve to sizeof(*ptr)
40 : : #define pl_alloc_ptr(parent, ptr) \
41 : : (__typeof__(ptr)) pl_alloc(parent, sizeof(*(ptr)))
42 : : #define pl_zalloc_ptr(parent, ptr) \
43 : : (__typeof__(ptr)) pl_zalloc(parent, sizeof(*(ptr)))
44 : : #define pl_calloc_ptr(parent, num, ptr) \
45 : : (__typeof__(ptr)) pl_calloc(parent, num, sizeof(*(ptr)))
46 : :
47 : : // Helper function to allocate a struct and immediately assign it
48 : : #define pl_alloc_struct(parent, type, ...) \
49 : : (type *) pl_memdup(parent, &(type) __VA_ARGS__, sizeof(type))
50 : :
51 : : // Free an allocation and its children (recursively)
52 : : void pl_free(void *ptr);
53 : : void pl_free_children(void *ptr);
54 : :
55 : : #define pl_free_ptr(ptr) \
56 : : do { \
57 : : pl_free(*(ptr)); \
58 : : *(ptr) = NULL; \
59 : : } while (0)
60 : :
61 : : // Get the current size of an allocation.
62 : : size_t pl_get_size(const void *ptr);
63 : :
64 : : #define pl_grow(parent, ptr, size) \
65 : : do { \
66 : : size_t _size = (size); \
67 : : if (_size > pl_get_size(*(ptr))) \
68 : : *(ptr) = pl_realloc(parent, *(ptr), _size); \
69 : : } while (0)
70 : :
71 : : // Reparent an allocation onto a new parent
72 : : void *pl_steal(void *parent, void *ptr);
73 : :
74 : : // Wrapper functions around common string utilities
75 : : void *pl_memdup(void *parent, const void *ptr, size_t size);
76 : : char *pl_str0dup0(void *parent, const char *str);
77 : : char *pl_strndup0(void *parent, const char *str, size_t size);
78 : :
79 : : #define pl_memdup_ptr(parent, ptr) \
80 : : (__typeof__(ptr)) pl_memdup(parent, ptr, sizeof(*(ptr)))
81 : :
82 : : // Helper functions for allocating public/private pairs, done by allocating
83 : : // `priv` at the address of `pub` + sizeof(pub), rounded up to the maximum
84 : : // alignment requirements.
85 : :
86 : : #define PL_ALIGN_MEM(size) PL_ALIGN2(size, alignof(max_align_t))
87 : :
88 : : #define PL_PRIV(pub) \
89 : : (void *) ((uintptr_t) (pub) + PL_ALIGN_MEM(sizeof(*(pub))))
90 : :
91 : : #define pl_alloc_obj(parent, ptr, priv) \
92 : : (__typeof__(ptr)) pl_alloc(parent, PL_ALIGN_MEM(sizeof(*(ptr))) + sizeof(priv))
93 : :
94 : : #define pl_zalloc_obj(parent, ptr, priv) \
95 : : (__typeof__(ptr)) pl_zalloc(parent, PL_ALIGN_MEM(sizeof(*(ptr))) + sizeof(priv))
96 : :
97 : : // Helper functions for dealing with arrays
98 : :
99 : : #define PL_ARRAY(type) struct { type *elem; int num; }
100 : :
101 : : #define PL_ARRAY_REALLOC(parent, arr, len) \
102 : : do { \
103 : : size_t _new_size = (len) * sizeof((arr).elem[0]); \
104 : : (arr).elem = pl_realloc((void *) parent, (arr).elem, _new_size); \
105 : : } while (0)
106 : :
107 : : #define PL_ARRAY_RESIZE(parent, arr, len) \
108 : : do { \
109 : : size_t _avail = pl_get_size((arr).elem) / sizeof((arr).elem[0]); \
110 : : size_t _min_len = (len); \
111 : : if (_avail < _min_len) \
112 : : PL_ARRAY_REALLOC(parent, arr, _min_len); \
113 : : } while (0)
114 : :
115 : : #define PL_ARRAY_MEMDUP(parent, arr, ptr, len) \
116 : : do { \
117 : : size_t _len = (len); \
118 : : PL_ARRAY_RESIZE(parent, arr, _len); \
119 : : memcpy((arr).elem, ptr, _len * sizeof((arr).elem[0])); \
120 : : (arr).num = _len; \
121 : : } while (0)
122 : :
123 : : #define PL_ARRAY_GROW(parent, arr) \
124 : : do { \
125 : : size_t _avail = pl_get_size((arr).elem) / sizeof((arr).elem[0]); \
126 : : if (_avail < 10) { \
127 : : PL_ARRAY_REALLOC(parent, arr, 10); \
128 : : } else if ((arr).num == _avail) { \
129 : : PL_ARRAY_REALLOC(parent, arr, (arr).num * 1.5); \
130 : : } else { \
131 : : assert((arr).elem); \
132 : : } \
133 : : } while (0)
134 : :
135 : : #define PL_ARRAY_APPEND(parent, arr, ...) \
136 : : do { \
137 : : PL_ARRAY_GROW(parent, arr); \
138 : : (arr).elem[(arr).num++] = __VA_ARGS__; \
139 : : } while (0)
140 : :
141 : : #define PL_ARRAY_CONCAT(parent, to, from) \
142 : : do { \
143 : : if ((from).num) { \
144 : : PL_ARRAY_RESIZE(parent, to, (to).num + (from).num); \
145 : : memmove(&(to).elem[(to).num], (from).elem, \
146 : : (from).num * sizeof((from).elem[0])); \
147 : : (to).num += (from).num; \
148 : : } \
149 : : } while (0)
150 : :
151 : : #define PL_ARRAY_REMOVE_RANGE(arr, idx, count) \
152 : : do { \
153 : : ptrdiff_t _idx = (idx); \
154 : : if (_idx < 0) \
155 : : _idx += (arr).num; \
156 : : size_t _count = (count); \
157 : : assert(_idx >= 0 && _idx + _count <= (arr).num); \
158 : : memmove(&(arr).elem[_idx], &(arr).elem[_idx + _count], \
159 : : ((arr).num - _idx - _count) * sizeof((arr).elem[0])); \
160 : : (arr).num -= _count; \
161 : : } while (0)
162 : :
163 : : #define PL_ARRAY_REMOVE_AT(arr, idx) PL_ARRAY_REMOVE_RANGE(arr, idx, 1)
164 : :
165 : : #define PL_ARRAY_INSERT_AT(parent, arr, idx, ...) \
166 : : do { \
167 : : ptrdiff_t _idx = (idx); \
168 : : if (_idx < 0) \
169 : : _idx += (arr).num + 1; \
170 : : assert(_idx >= 0 && _idx <= (arr).num); \
171 : : PL_ARRAY_GROW(parent, arr); \
172 : : memmove(&(arr).elem[_idx + 1], &(arr).elem[_idx], \
173 : : ((arr).num++ - _idx) * sizeof((arr).elem[0])); \
174 : : (arr).elem[_idx] = __VA_ARGS__; \
175 : : } while (0)
176 : :
177 : : // Returns whether or not there was any element to pop
178 : : #define PL_ARRAY_POP(arr, out) \
179 : : ((arr).num > 0 \
180 : : ? (*(out) = (arr).elem[--(arr).num], true) \
181 : : : false \
182 : : )
183 : :
184 : : // Wrapper for dealing with non-PL_ARRAY arrays
185 : : #define PL_ARRAY_APPEND_RAW(parent, arr, idxvar, ...) \
186 : : do { \
187 : : PL_ARRAY(__typeof__((arr)[0])) _arr = { (arr), (idxvar) }; \
188 : : PL_ARRAY_APPEND(parent, _arr, __VA_ARGS__); \
189 : : (arr) = _arr.elem; \
190 : : (idxvar) = _arr.num; \
191 : : } while (0)
|