/*
* 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 .
*/
#pragma once
#include
#include
#include
#include
#include
// 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)