130e702abSChristian Schoenebeck /* 230e702abSChristian Schoenebeck * P9Array - deep auto free C-array 330e702abSChristian Schoenebeck * 430e702abSChristian Schoenebeck * Copyright (c) 2021 Crudebyte 530e702abSChristian Schoenebeck * 630e702abSChristian Schoenebeck * Authors: 730e702abSChristian Schoenebeck * Christian Schoenebeck <qemu_oss@crudebyte.com> 830e702abSChristian Schoenebeck * 930e702abSChristian Schoenebeck * Permission is hereby granted, free of charge, to any person obtaining a copy 1030e702abSChristian Schoenebeck * of this software and associated documentation files (the "Software"), to deal 1130e702abSChristian Schoenebeck * in the Software without restriction, including without limitation the rights 1230e702abSChristian Schoenebeck * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1330e702abSChristian Schoenebeck * copies of the Software, and to permit persons to whom the Software is 1430e702abSChristian Schoenebeck * furnished to do so, subject to the following conditions: 1530e702abSChristian Schoenebeck * 1630e702abSChristian Schoenebeck * The above copyright notice and this permission notice shall be included in 1730e702abSChristian Schoenebeck * all copies or substantial portions of the Software. 1830e702abSChristian Schoenebeck * 1930e702abSChristian Schoenebeck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2030e702abSChristian Schoenebeck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2130e702abSChristian Schoenebeck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2230e702abSChristian Schoenebeck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2330e702abSChristian Schoenebeck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2430e702abSChristian Schoenebeck * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2530e702abSChristian Schoenebeck * THE SOFTWARE. 2630e702abSChristian Schoenebeck */ 2730e702abSChristian Schoenebeck #ifndef QEMU_P9ARRAY_H 2830e702abSChristian Schoenebeck #define QEMU_P9ARRAY_H 2930e702abSChristian Schoenebeck 30*c0451f0bSChristian Schoenebeck #include "qemu/compiler.h" 31*c0451f0bSChristian Schoenebeck 3230e702abSChristian Schoenebeck /** 3330e702abSChristian Schoenebeck * P9Array provides a mechanism to access arrays in common C-style (e.g. by 3430e702abSChristian Schoenebeck * square bracket [] operator) in conjunction with reference variables that 3530e702abSChristian Schoenebeck * perform deep auto free of the array when leaving the scope of the auto 3630e702abSChristian Schoenebeck * reference variable. That means not only is the array itself automatically 3730e702abSChristian Schoenebeck * freed, but also memory dynamically allocated by the individual array 3830e702abSChristian Schoenebeck * elements. 3930e702abSChristian Schoenebeck * 4030e702abSChristian Schoenebeck * Example: 4130e702abSChristian Schoenebeck * 4230e702abSChristian Schoenebeck * Consider the following user struct @c Foo which shall be used as scalar 4330e702abSChristian Schoenebeck * (element) type of an array: 4430e702abSChristian Schoenebeck * @code 4530e702abSChristian Schoenebeck * typedef struct Foo { 4630e702abSChristian Schoenebeck * int i; 4730e702abSChristian Schoenebeck * char *s; 4830e702abSChristian Schoenebeck * } Foo; 4930e702abSChristian Schoenebeck * @endcode 5030e702abSChristian Schoenebeck * and assume it has the following function to free memory allocated by @c Foo 5130e702abSChristian Schoenebeck * instances: 5230e702abSChristian Schoenebeck * @code 5330e702abSChristian Schoenebeck * void free_foo(Foo *foo) { 5430e702abSChristian Schoenebeck * free(foo->s); 5530e702abSChristian Schoenebeck * } 5630e702abSChristian Schoenebeck * @endcode 5730e702abSChristian Schoenebeck * Add the following to a shared header file: 5830e702abSChristian Schoenebeck * @code 5930e702abSChristian Schoenebeck * P9ARRAY_DECLARE_TYPE(Foo); 6030e702abSChristian Schoenebeck * @endcode 6130e702abSChristian Schoenebeck * and the following to a C unit file: 6230e702abSChristian Schoenebeck * @code 6330e702abSChristian Schoenebeck * P9ARRAY_DEFINE_TYPE(Foo, free_foo); 6430e702abSChristian Schoenebeck * @endcode 6530e702abSChristian Schoenebeck * Finally the array may then be used like this: 6630e702abSChristian Schoenebeck * @code 6730e702abSChristian Schoenebeck * void doSomething(size_t n) { 6830e702abSChristian Schoenebeck * P9ARRAY_REF(Foo) foos = NULL; 6930e702abSChristian Schoenebeck * P9ARRAY_NEW(Foo, foos, n); 7030e702abSChristian Schoenebeck * for (size_t i = 0; i < n; ++i) { 7130e702abSChristian Schoenebeck * foos[i].i = i; 7230e702abSChristian Schoenebeck * foos[i].s = calloc(4096, 1); 7330e702abSChristian Schoenebeck * snprintf(foos[i].s, 4096, "foo %d", i); 7430e702abSChristian Schoenebeck * if (...) { 7530e702abSChristian Schoenebeck * return; // array auto freed here 7630e702abSChristian Schoenebeck * } 7730e702abSChristian Schoenebeck * } 7830e702abSChristian Schoenebeck * // array auto freed here 7930e702abSChristian Schoenebeck * } 8030e702abSChristian Schoenebeck * @endcode 8130e702abSChristian Schoenebeck */ 8230e702abSChristian Schoenebeck 8330e702abSChristian Schoenebeck /** 8430e702abSChristian Schoenebeck * Declares an array type for the passed @a scalar_type. 8530e702abSChristian Schoenebeck * 8630e702abSChristian Schoenebeck * This is typically used from a shared header file. 8730e702abSChristian Schoenebeck * 8830e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 8930e702abSChristian Schoenebeck */ 9030e702abSChristian Schoenebeck #define P9ARRAY_DECLARE_TYPE(scalar_type) \ 9130e702abSChristian Schoenebeck typedef struct P9Array##scalar_type { \ 9230e702abSChristian Schoenebeck size_t len; \ 9330e702abSChristian Schoenebeck scalar_type first[]; \ 9430e702abSChristian Schoenebeck } P9Array##scalar_type; \ 9530e702abSChristian Schoenebeck \ 9630e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len); \ 9730e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var); \ 9830e702abSChristian Schoenebeck 9930e702abSChristian Schoenebeck /** 10030e702abSChristian Schoenebeck * Defines an array type for the passed @a scalar_type and appropriate 10130e702abSChristian Schoenebeck * @a scalar_cleanup_func. 10230e702abSChristian Schoenebeck * 10330e702abSChristian Schoenebeck * This is typically used from a C unit file. 10430e702abSChristian Schoenebeck * 10530e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 10630e702abSChristian Schoenebeck * @param scalar_cleanup_func - appropriate function to free memory dynamically 10730e702abSChristian Schoenebeck * allocated by individual array elements before 10830e702abSChristian Schoenebeck */ 10930e702abSChristian Schoenebeck #define P9ARRAY_DEFINE_TYPE(scalar_type, scalar_cleanup_func) \ 11030e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len) \ 11130e702abSChristian Schoenebeck { \ 11230e702abSChristian Schoenebeck p9array_auto_free_##scalar_type(auto_var); \ 11330e702abSChristian Schoenebeck P9Array##scalar_type *arr = g_malloc0(sizeof(P9Array##scalar_type) + \ 11430e702abSChristian Schoenebeck len * sizeof(scalar_type)); \ 11530e702abSChristian Schoenebeck arr->len = len; \ 11630e702abSChristian Schoenebeck *auto_var = &arr->first[0]; \ 11730e702abSChristian Schoenebeck } \ 11830e702abSChristian Schoenebeck \ 11930e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var) \ 12030e702abSChristian Schoenebeck { \ 12130e702abSChristian Schoenebeck scalar_type *first = (*auto_var); \ 12230e702abSChristian Schoenebeck if (!first) { \ 12330e702abSChristian Schoenebeck return; \ 12430e702abSChristian Schoenebeck } \ 12530e702abSChristian Schoenebeck P9Array##scalar_type *arr = (P9Array##scalar_type *) ( \ 12630e702abSChristian Schoenebeck ((char *)first) - offsetof(P9Array##scalar_type, first) \ 12730e702abSChristian Schoenebeck ); \ 12830e702abSChristian Schoenebeck for (size_t i = 0; i < arr->len; ++i) { \ 12930e702abSChristian Schoenebeck scalar_cleanup_func(&arr->first[i]); \ 13030e702abSChristian Schoenebeck } \ 13130e702abSChristian Schoenebeck g_free(arr); \ 13230e702abSChristian Schoenebeck } \ 13330e702abSChristian Schoenebeck 13430e702abSChristian Schoenebeck /** 13530e702abSChristian Schoenebeck * Used to declare a reference variable (unique pointer) for an array. After 13630e702abSChristian Schoenebeck * leaving the scope of the reference variable, the associated array is 13730e702abSChristian Schoenebeck * automatically freed. 13830e702abSChristian Schoenebeck * 13930e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 14030e702abSChristian Schoenebeck */ 14130e702abSChristian Schoenebeck #define P9ARRAY_REF(scalar_type) \ 14230e702abSChristian Schoenebeck __attribute((__cleanup__(p9array_auto_free_##scalar_type))) scalar_type* 14330e702abSChristian Schoenebeck 14430e702abSChristian Schoenebeck /** 14530e702abSChristian Schoenebeck * Allocates a new array of passed @a scalar_type with @a len number of array 14630e702abSChristian Schoenebeck * elements and assigns the created array to the reference variable 14730e702abSChristian Schoenebeck * @a auto_var. 14830e702abSChristian Schoenebeck * 14930e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 15030e702abSChristian Schoenebeck * @param auto_var - destination reference variable 15130e702abSChristian Schoenebeck * @param len - amount of array elements to be allocated immediately 15230e702abSChristian Schoenebeck */ 15330e702abSChristian Schoenebeck #define P9ARRAY_NEW(scalar_type, auto_var, len) \ 154*c0451f0bSChristian Schoenebeck QEMU_BUILD_BUG_MSG( \ 155*c0451f0bSChristian Schoenebeck !__builtin_types_compatible_p(scalar_type, typeof(*auto_var)), \ 156*c0451f0bSChristian Schoenebeck "P9Array scalar type mismatch" \ 157*c0451f0bSChristian Schoenebeck ); \ 15830e702abSChristian Schoenebeck p9array_new_##scalar_type((&auto_var), len) 15930e702abSChristian Schoenebeck 16030e702abSChristian Schoenebeck #endif /* QEMU_P9ARRAY_H */ 161