On Sonntag, 22. August 2021 15:16:46 CEST Christian Schoenebeck wrote: > Implements deep auto free of arrays while retaining common C-style > squared bracket access. > > Signed-off-by: Christian Schoenebeck <qemu_...@crudebyte.com> > --- > include/qemu/qarray.h | 150 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 150 insertions(+) > create mode 100644 include/qemu/qarray.h > > diff --git a/include/qemu/qarray.h b/include/qemu/qarray.h > new file mode 100644 > index 0000000000..9885e5e9ed > --- /dev/null > +++ b/include/qemu/qarray.h > @@ -0,0 +1,150 @@ > +/* > + * QArray - deep auto free C-array > + * > + * Copyright (c) 2021 Crudebyte > + * > + * Authors: > + * Christian Schoenebeck <qemu_...@crudebyte.com> > + * > + * 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 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. > + */ > +#ifndef QEMU_QARRAY_H > +#define QEMU_QARRAY_H > + > +/** > + * QArray provides a mechanism to access arrays in common C-style (e.g. by > + * square bracket [] operator) in conjunction with reference variables that > + * perform deep auto free of the array when leaving the scope of the auto > + * reference variable. That means not only is the array itself > automatically + * freed, but also memory dynamically allocated by the > individual array + * elements. > + * > + * Example: > + * > + * Consider the following user struct @c Foo which shall be used as scalar > + * (element) type of an array: > + * @code > + * typedef struct Foo { > + * int i; > + * char *s; > + * } Foo; > + * @endcode > + * and assume it has the following function to free memory allocated by @c > Foo + * instances: > + * @code > + * void free_foo(Foo *foo) { > + * free(foo->s); > + * } > + * @endcode > + * Add the following to a shared header file: > + * @code > + * DECLARE_QARRAY_TYPE(Foo); > + * @endcode > + * and the following to a C unit file: > + * @code > + * DEFINE_QARRAY_TYPE(Foo, free_foo); > + * @endcode > + * Finally the array may then be used like this: > + * @code > + * void doSomething(int n) { > + * QArrayRef(Foo) foos = NULL; > + * QARRAY_CREATE(Foo, foos, n); > + * for (size_t i = 0; i < n; ++i) { > + * foos[i].i = i; > + * foos[i].s = calloc(4096, 1); > + * snprintf(foos[i].s, 4096, "foo %d", i); > + * } > + * } > + * @endcode
Or should that probably be changed to upper case QArrayRef() -> QARRAY_REF(), because ... > + */ > + > +/** > + * Declares an array type for the passed @a scalar_type. > + * > + * This is typically used from a shared header file. > + * > + * @param scalar_type - type of the individual array elements > + */ > +#define DECLARE_QARRAY_TYPE(scalar_type) \ > + typedef struct QArray##scalar_type { \ > + size_t len; \ > + scalar_type first[]; \ > + } QArray##scalar_type; \ > + \ > + void qarray_create_##scalar_type(scalar_type **auto_var, size_t len); \ > + void qarray_auto_free_##scalar_type(scalar_type **auto_var); \ + > +/** > + * Defines an array type for the passed @a scalar_type and appropriate > + * @a scalar_cleanup_func. > + * > + * This is typically used from a C unit file. > + * > + * @param scalar_type - type of the individual array elements > + * @param scalar_cleanup_func - appropriate function to free memory > dynamically + * allocated by individual array > elements before + */ > +#define DEFINE_QARRAY_TYPE(scalar_type, scalar_cleanup_func) \ > + void qarray_create_##scalar_type(scalar_type **auto_var, size_t len) \ > + { \ > + qarray_auto_free_##scalar_type(auto_var); \ > + QArray##scalar_type *arr = g_malloc0(sizeof(QArray##scalar_type) + > \ + len * sizeof(scalar_type)); \ > + arr->len = len; \ > + *auto_var = &arr->first[0]; \ > + } \ > + \ > + void qarray_auto_free_##scalar_type(scalar_type **auto_var) \ > + { \ > + scalar_type *first = (*auto_var); \ > + if (!first) { \ > + return; \ > + } \ > + QArray##scalar_type *arr = (QArray##scalar_type *) ( \ > + ((char *)first) - offsetof(QArray##scalar_type, first) \ > + ); \ > + for (size_t i = 0; i < arr->len; ++i) { \ > + scalar_cleanup_func(&arr->first[i]); \ > + } \ > + g_free(arr); \ > + } \ > + > +/** > + * Used to declare a reference variable (unique pointer) for an array. > After + * leaving the scope of the reference variable, the associated array > is + * automatically freed. > + * > + * @param scalar_type - type of the individual array elements > + */ > +#define QArrayRef(scalar_type) \ > + __attribute((__cleanup__(qarray_auto_free_##scalar_type))) scalar_type* > + ... it is actually a macro? > +/** > + * Allocates a new array of passed @a scalar_type with @a len number of > array + * elements and assigns the created array to the reference variable > + * @a auto_var. > + * > + * @param scalar_type - type of the individual array elements > + * @param auto_var - destination reference variable > + * @param len - amount of array elements to be allocated immediately > + */ > +#define QARRAY_CREATE(scalar_type, auto_var, len) \ > + qarray_create_##scalar_type((&auto_var), len) > + > +#endif /* QEMU_QARRAY_H */ Best regards, Christian Schoenebeck