diff options
Diffstat (limited to '')
-rw-r--r-- | src/pl_alloc.h | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/pl_alloc.h b/src/pl_alloc.h new file mode 100644 index 0000000..78df08a --- /dev/null +++ b/src/pl_alloc.h @@ -0,0 +1,191 @@ +/* + * This file is part of libplacebo. + * + * libplacebo is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libplacebo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stdalign.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +// Unlike standard malloc, `size` may be 0, in which case this returns an empty +// allocation which can still be used as a parent for other allocations. +void *pl_alloc(void *parent, size_t size); +void *pl_zalloc(void *parent, size_t size); +void *pl_realloc(void *parent, void *ptr, size_t size); + +static inline void *pl_calloc(void *parent, size_t count, size_t size) +{ + return pl_zalloc(parent, count * size); +} + +#define pl_tmp(parent) pl_alloc(parent, 0) + +// Variants of the above which resolve to sizeof(*ptr) +#define pl_alloc_ptr(parent, ptr) \ + (__typeof__(ptr)) pl_alloc(parent, sizeof(*(ptr))) +#define pl_zalloc_ptr(parent, ptr) \ + (__typeof__(ptr)) pl_zalloc(parent, sizeof(*(ptr))) +#define pl_calloc_ptr(parent, num, ptr) \ + (__typeof__(ptr)) pl_calloc(parent, num, sizeof(*(ptr))) + +// Helper function to allocate a struct and immediately assign it +#define pl_alloc_struct(parent, type, ...) \ + (type *) pl_memdup(parent, &(type) __VA_ARGS__, sizeof(type)) + +// Free an allocation and its children (recursively) +void pl_free(void *ptr); +void pl_free_children(void *ptr); + +#define pl_free_ptr(ptr) \ + do { \ + pl_free(*(ptr)); \ + *(ptr) = NULL; \ + } while (0) + +// Get the current size of an allocation. +size_t pl_get_size(const void *ptr); + +#define pl_grow(parent, ptr, size) \ + do { \ + size_t _size = (size); \ + if (_size > pl_get_size(*(ptr))) \ + *(ptr) = pl_realloc(parent, *(ptr), _size); \ + } while (0) + +// Reparent an allocation onto a new parent +void *pl_steal(void *parent, void *ptr); + +// Wrapper functions around common string utilities +void *pl_memdup(void *parent, const void *ptr, size_t size); +char *pl_str0dup0(void *parent, const char *str); +char *pl_strndup0(void *parent, const char *str, size_t size); + +#define pl_memdup_ptr(parent, ptr) \ + (__typeof__(ptr)) pl_memdup(parent, ptr, sizeof(*(ptr))) + +// Helper functions for allocating public/private pairs, done by allocating +// `priv` at the address of `pub` + sizeof(pub), rounded up to the maximum +// alignment requirements. + +#define PL_ALIGN_MEM(size) PL_ALIGN2(size, alignof(max_align_t)) + +#define PL_PRIV(pub) \ + (void *) ((uintptr_t) (pub) + PL_ALIGN_MEM(sizeof(*(pub)))) + +#define pl_alloc_obj(parent, ptr, priv) \ + (__typeof__(ptr)) pl_alloc(parent, PL_ALIGN_MEM(sizeof(*(ptr))) + sizeof(priv)) + +#define pl_zalloc_obj(parent, ptr, priv) \ + (__typeof__(ptr)) pl_zalloc(parent, PL_ALIGN_MEM(sizeof(*(ptr))) + sizeof(priv)) + +// Helper functions for dealing with arrays + +#define PL_ARRAY(type) struct { type *elem; int num; } + +#define PL_ARRAY_REALLOC(parent, arr, len) \ + do { \ + size_t _new_size = (len) * sizeof((arr).elem[0]); \ + (arr).elem = pl_realloc((void *) parent, (arr).elem, _new_size); \ + } while (0) + +#define PL_ARRAY_RESIZE(parent, arr, len) \ + do { \ + size_t _avail = pl_get_size((arr).elem) / sizeof((arr).elem[0]); \ + size_t _min_len = (len); \ + if (_avail < _min_len) \ + PL_ARRAY_REALLOC(parent, arr, _min_len); \ + } while (0) + +#define PL_ARRAY_MEMDUP(parent, arr, ptr, len) \ + do { \ + size_t _len = (len); \ + PL_ARRAY_RESIZE(parent, arr, _len); \ + memcpy((arr).elem, ptr, _len * sizeof((arr).elem[0])); \ + (arr).num = _len; \ + } while (0) + +#define PL_ARRAY_GROW(parent, arr) \ + do { \ + size_t _avail = pl_get_size((arr).elem) / sizeof((arr).elem[0]); \ + if (_avail < 10) { \ + PL_ARRAY_REALLOC(parent, arr, 10); \ + } else if ((arr).num == _avail) { \ + PL_ARRAY_REALLOC(parent, arr, (arr).num * 1.5); \ + } else { \ + assert((arr).elem); \ + } \ + } while (0) + +#define PL_ARRAY_APPEND(parent, arr, ...) \ + do { \ + PL_ARRAY_GROW(parent, arr); \ + (arr).elem[(arr).num++] = __VA_ARGS__; \ + } while (0) + +#define PL_ARRAY_CONCAT(parent, to, from) \ + do { \ + if ((from).num) { \ + PL_ARRAY_RESIZE(parent, to, (to).num + (from).num); \ + memmove(&(to).elem[(to).num], (from).elem, \ + (from).num * sizeof((from).elem[0])); \ + (to).num += (from).num; \ + } \ + } while (0) + +#define PL_ARRAY_REMOVE_RANGE(arr, idx, count) \ + do { \ + ptrdiff_t _idx = (idx); \ + if (_idx < 0) \ + _idx += (arr).num; \ + size_t _count = (count); \ + assert(_idx >= 0 && _idx + _count <= (arr).num); \ + memmove(&(arr).elem[_idx], &(arr).elem[_idx + _count], \ + ((arr).num - _idx - _count) * sizeof((arr).elem[0])); \ + (arr).num -= _count; \ + } while (0) + +#define PL_ARRAY_REMOVE_AT(arr, idx) PL_ARRAY_REMOVE_RANGE(arr, idx, 1) + +#define PL_ARRAY_INSERT_AT(parent, arr, idx, ...) \ + do { \ + ptrdiff_t _idx = (idx); \ + if (_idx < 0) \ + _idx += (arr).num + 1; \ + assert(_idx >= 0 && _idx <= (arr).num); \ + PL_ARRAY_GROW(parent, arr); \ + memmove(&(arr).elem[_idx + 1], &(arr).elem[_idx], \ + ((arr).num++ - _idx) * sizeof((arr).elem[0])); \ + (arr).elem[_idx] = __VA_ARGS__; \ + } while (0) + +// Returns whether or not there was any element to pop +#define PL_ARRAY_POP(arr, out) \ + ((arr).num > 0 \ + ? (*(out) = (arr).elem[--(arr).num], true) \ + : false \ + ) + +// Wrapper for dealing with non-PL_ARRAY arrays +#define PL_ARRAY_APPEND_RAW(parent, arr, idxvar, ...) \ + do { \ + PL_ARRAY(__typeof__((arr)[0])) _arr = { (arr), (idxvar) }; \ + PL_ARRAY_APPEND(parent, _arr, __VA_ARGS__); \ + (arr) = _arr.elem; \ + (idxvar) = _arr.num; \ + } while (0) |