From 171ccdbf1c40068fcea2cc36ff7eef1a49155928 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Thu, 4 Nov 2021 12:23:05 -0400 Subject: [PATCH] util: add ptralloc many times it will be the case that an allocation for a block of data needs to be done in one alloc() call such that the members of a struct as well as some extra trailing data are all in the same allocation like ``` struct Test { unsigned a[4]; unsigned c; }; unsigned *b; //ptr to uint[8] ``` should be allocated as a single block of (13 * sizeof(unsigned)) memory using C pointer offsets to allocate the memory as ``` | Test | b | ``` with something like ``` struct Test *t = malloc(sizeof(struct Test) + (8 * sizeof(unsigned))); ``` and then set `b` with ``` t->b = ((uint8_t*)t) + sizeof(struct Test); ``` this is annoying, awful to read, and (at least for dum-dums like me) prone to errors, however, so having some utility functions which can deliver the same functionality with better readability helps out this case by transforming it to ``` unsigned *b; void **ptrs[] = {(void*)&b}; size_t sizes[] = {8 * sizeof(unsigned)); struct Test *t = ptralloc(sizeof(struct Test), 1, sizes, ptrs); ``` where `b` is now set to the appropriate offset in memory Acked-by: Dave Airlie Part-of: --- src/util/meson.build | 1 + src/util/ptralloc.h | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 src/util/ptralloc.h diff --git a/src/util/meson.build b/src/util/meson.build index fe46352ce16..6e77a2f0364 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -78,6 +78,7 @@ files_mesa_util = files( 'os_misc.h', 'os_socket.c', 'os_socket.h', + 'ptralloc.h', 'perf/u_trace.h', 'perf/u_trace.c', 'perf/u_trace_priv.h', diff --git a/src/util/ptralloc.h b/src/util/ptralloc.h new file mode 100644 index 00000000000..019bc7b8e12 --- /dev/null +++ b/src/util/ptralloc.h @@ -0,0 +1,79 @@ +/* + * Copyright © 2021 Valve Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Mike Blumenkrantz + */ + +#pragma once + +#include +#include +#include +#include "c99_compat.h" +#include "macros.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void * +ptralloc(size_t base_size, unsigned member_count, size_t *member_sizes, void ***members) +{ + size_t size = base_size; + for (unsigned i = 0; i < member_count; i++) + size += member_sizes[i]; + + uint8_t *ptr = (uint8_t*)malloc(size); + if (!ptr) + return NULL; + + size_t accum = base_size; + for (unsigned i = 0; i < member_count; i++) { + *members[i] = (void*)(ptr + accum); + accum += member_sizes[i]; + } + return (void*)ptr; +} + +static inline void * +ptrzalloc(size_t base_size, unsigned member_count, size_t *member_sizes, void ***members) +{ + size_t size = base_size; + for (unsigned i = 0; i < member_count; i++) + size += member_sizes[i]; + + uint8_t *ptr = (uint8_t*)calloc(1, size); + if (!ptr) + return NULL; + + size_t accum = base_size; + for (unsigned i = 0; i < member_count; i++) { + *members[i] = (void*)(ptr + accum); + accum += member_sizes[i]; + } + return (void*)ptr; +} + +#ifdef __cplusplus +} +#endif