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 <stdarg.h>
21 #include <stdint.h>
22 #include <string.h>
23
24 // Unlike standard malloc, `size` may be 0, in which case this returns an empty
25 // allocation which can still be used as a parent for other allocations.
26 void *pl_alloc(void *parent, size_t size);
27 void *pl_zalloc(void *parent, size_t size);
28 void *pl_realloc(void *parent, void *ptr, size_t size);
29
pl_calloc(void * parent,size_t count,size_t size)30 static inline void *pl_calloc(void *parent, size_t count, size_t size)
31 {
32 return pl_zalloc(parent, count * size);
33 }
34
35 #define pl_tmp(parent) pl_alloc(parent, 0)
36
37 // Variants of the above which resolve to sizeof(*ptr)
38 #define pl_alloc_ptr(parent, ptr) \
39 (__typeof__(ptr)) pl_alloc(parent, sizeof(*(ptr)))
40 #define pl_zalloc_ptr(parent, ptr) \
41 (__typeof__(ptr)) pl_zalloc(parent, sizeof(*(ptr)))
42 #define pl_calloc_ptr(parent, num, ptr) \
43 (__typeof__(ptr)) pl_calloc(parent, num, sizeof(*(ptr)))
44
45 // Helper function to allocate a struct and immediately assign it
46 #define pl_alloc_struct(parent, type, ...) \
47 (type *) pl_memdup(parent, &(type) __VA_ARGS__, sizeof(type))
48
49 // Free an allocation and its children (recursively)
50 void pl_free(void *ptr);
51 void pl_free_children(void *ptr);
52
53 #define pl_free_ptr(ptr) \
54 do { \
55 pl_free(*(ptr)); \
56 *(ptr) = NULL; \
57 } while (0)
58
59 // Get the current size of an allocation.
60 size_t pl_get_size(void *ptr);
61
62 #define pl_grow(parent, ptr, size) \
63 do { \
64 size_t _size = (size); \
65 if (_size > pl_get_size(*(ptr))) \
66 *(ptr) = pl_realloc(parent, *(ptr), _size); \
67 } while (0)
68
69 // Reparent an allocation onto a new parent
70 void *pl_steal(void *parent, void *ptr);
71
72 // Wrapper functions around common string utilities
73 void *pl_memdup(void *parent, const void *ptr, size_t size);
74 char *pl_str0dup0(void *parent, const char *str);
75 char *pl_strndup0(void *parent, const char *str, size_t size);
76
77 #define pl_memdup_ptr(parent, ptr) \
78 (__typeof__(ptr)) pl_memdup(parent, ptr, sizeof(*(ptr)))
79
80 // Helper functions for allocating public/private pairs, done by allocating
81 // `priv` at the address of `pub` + sizeof(pub), rounded up to the maximum
82 // alignment requirements.
83
84 #define pl_max_align offsetof(struct { char c; intmax_t x; }, x)
85 #define PL_ALIGN_MEM(size) \
86 (((size) + pl_max_align - 1) & ~(pl_max_align - 1))
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 // Refcounting helper
98
99 struct pl_ref;
100
101 // pl_ref_deref will free the ref and all of its children as soon as the
102 // internal refcount reaches 0
103 struct pl_ref *pl_ref_new(void *parent);
104 struct pl_ref *pl_ref_dup(struct pl_ref *ref);
105 void pl_ref_deref(struct pl_ref **ref);
106
107 // Helper functions for dealing with arrays
108
109 #define PL_ARRAY(type) struct { type *elem; int num; }
110
111 #define PL_ARRAY_RESIZE(parent, arr, len) \
112 do { \
113 size_t _new_size = (len) * sizeof((arr).elem[0]); \
114 (arr).elem = pl_realloc((void *) parent, (arr).elem, _new_size); \
115 } while (0)
116
117 #define PL_ARRAY_GROW(parent, arr) \
118 do { \
119 size_t _avail = pl_get_size((arr).elem) / sizeof((arr).elem[0]); \
120 if (_avail < 10) { \
121 PL_ARRAY_RESIZE(parent, arr, 10); \
122 } else if ((arr).num == _avail) { \
123 PL_ARRAY_RESIZE(parent, arr, (arr).num * 1.5); \
124 } else { \
125 assert((arr).elem); \
126 } \
127 } while (0)
128
129 #define PL_ARRAY_APPEND(parent, arr, ...) \
130 do { \
131 PL_ARRAY_GROW(parent, arr); \
132 (arr).elem[(arr).num++] = __VA_ARGS__; \
133 } while (0)
134
135 #define PL_ARRAY_CONCAT(parent, to, from) \
136 do { \
137 if ((from).num) { \
138 PL_ARRAY_RESIZE(parent, to, (to).num + (from).num); \
139 memmove(&(to).elem[(to).num], (from).elem, \
140 (from).num * sizeof((from).elem[0])); \
141 (to).num += (from).num; \
142 } \
143 } while (0)
144
145 #define PL_ARRAY_REMOVE_RANGE(arr, idx, count) \
146 do { \
147 size_t _idx = (idx); \
148 size_t _count = (count); \
149 assert(_idx + _count <= (arr).num); \
150 memmove(&(arr).elem[_idx], &(arr).elem[_idx + _count], \
151 ((arr).num - _idx - _count) * sizeof((arr).elem[0])); \
152 (arr).num -= _count; \
153 } while (0)
154
155 #define PL_ARRAY_REMOVE_AT(arr, idx) PL_ARRAY_REMOVE_RANGE(arr, idx, 1)
156
157 #define PL_ARRAY_INSERT_AT(parent, arr, idx, ...) \
158 do { \
159 size_t _idx = (idx); \
160 assert(_idx < (arr).num); \
161 PL_ARRAY_GROW(parent, arr); \
162 memmove(&(arr).elem[_idx + 1], &(arr).elem[_idx], \
163 ((arr).num++ - _idx) * sizeof((arr).elem[0])); \
164 (arr).elem[_idx] = __VA_ARGS__; \
165 } while (0)
166
167 // Returns whether or not there was any element to pop
168 #define PL_ARRAY_POP(arr, out) \
169 ((arr).num > 0 \
170 ? (*(out) = (arr).elem[--(arr).num], true) \
171 : false \
172 )
173
174 // Wrapper for dealing with non-PL_ARRAY arrays
175 #define PL_ARRAY_APPEND_RAW(parent, arr, idxvar, ...) \
176 do { \
177 PL_ARRAY(__typeof__((arr)[0])) _arr = { (arr), (idxvar) }; \
178 PL_ARRAY_APPEND(parent, _arr, __VA_ARGS__); \
179 (arr) = _arr.elem; \
180 (idxvar) = _arr.num; \
181 } while (0)
182