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 3030e702abSChristian Schoenebeck /** 3130e702abSChristian Schoenebeck * P9Array provides a mechanism to access arrays in common C-style (e.g. by 3230e702abSChristian Schoenebeck * square bracket [] operator) in conjunction with reference variables that 3330e702abSChristian Schoenebeck * perform deep auto free of the array when leaving the scope of the auto 3430e702abSChristian Schoenebeck * reference variable. That means not only is the array itself automatically 3530e702abSChristian Schoenebeck * freed, but also memory dynamically allocated by the individual array 3630e702abSChristian Schoenebeck * elements. 3730e702abSChristian Schoenebeck * 3830e702abSChristian Schoenebeck * Example: 3930e702abSChristian Schoenebeck * 4030e702abSChristian Schoenebeck * Consider the following user struct @c Foo which shall be used as scalar 4130e702abSChristian Schoenebeck * (element) type of an array: 4230e702abSChristian Schoenebeck * @code 4330e702abSChristian Schoenebeck * typedef struct Foo { 4430e702abSChristian Schoenebeck * int i; 4530e702abSChristian Schoenebeck * char *s; 4630e702abSChristian Schoenebeck * } Foo; 4730e702abSChristian Schoenebeck * @endcode 4830e702abSChristian Schoenebeck * and assume it has the following function to free memory allocated by @c Foo 4930e702abSChristian Schoenebeck * instances: 5030e702abSChristian Schoenebeck * @code 5130e702abSChristian Schoenebeck * void free_foo(Foo *foo) { 5230e702abSChristian Schoenebeck * free(foo->s); 5330e702abSChristian Schoenebeck * } 5430e702abSChristian Schoenebeck * @endcode 5530e702abSChristian Schoenebeck * Add the following to a shared header file: 5630e702abSChristian Schoenebeck * @code 5730e702abSChristian Schoenebeck * P9ARRAY_DECLARE_TYPE(Foo); 5830e702abSChristian Schoenebeck * @endcode 5930e702abSChristian Schoenebeck * and the following to a C unit file: 6030e702abSChristian Schoenebeck * @code 6130e702abSChristian Schoenebeck * P9ARRAY_DEFINE_TYPE(Foo, free_foo); 6230e702abSChristian Schoenebeck * @endcode 6330e702abSChristian Schoenebeck * Finally the array may then be used like this: 6430e702abSChristian Schoenebeck * @code 6530e702abSChristian Schoenebeck * void doSomething(size_t n) { 6630e702abSChristian Schoenebeck * P9ARRAY_REF(Foo) foos = NULL; 6730e702abSChristian Schoenebeck * P9ARRAY_NEW(Foo, foos, n); 6830e702abSChristian Schoenebeck * for (size_t i = 0; i < n; ++i) { 6930e702abSChristian Schoenebeck * foos[i].i = i; 7030e702abSChristian Schoenebeck * foos[i].s = calloc(4096, 1); 7130e702abSChristian Schoenebeck * snprintf(foos[i].s, 4096, "foo %d", i); 7230e702abSChristian Schoenebeck * if (...) { 7330e702abSChristian Schoenebeck * return; // array auto freed here 7430e702abSChristian Schoenebeck * } 7530e702abSChristian Schoenebeck * } 7630e702abSChristian Schoenebeck * // array auto freed here 7730e702abSChristian Schoenebeck * } 7830e702abSChristian Schoenebeck * @endcode 7930e702abSChristian Schoenebeck */ 8030e702abSChristian Schoenebeck 8130e702abSChristian Schoenebeck /** 82*35b64664SChristian Schoenebeck * P9ARRAY_DECLARE_TYPE() - Declares an array type for the passed @scalar_type. 83*35b64664SChristian Schoenebeck * 84*35b64664SChristian Schoenebeck * @scalar_type: type of the individual array elements 8530e702abSChristian Schoenebeck * 8630e702abSChristian Schoenebeck * This is typically used from a shared header file. 8730e702abSChristian Schoenebeck */ 8830e702abSChristian Schoenebeck #define P9ARRAY_DECLARE_TYPE(scalar_type) \ 8930e702abSChristian Schoenebeck typedef struct P9Array##scalar_type { \ 9030e702abSChristian Schoenebeck size_t len; \ 9130e702abSChristian Schoenebeck scalar_type first[]; \ 9230e702abSChristian Schoenebeck } P9Array##scalar_type; \ 9330e702abSChristian Schoenebeck \ 9430e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len); \ 9530e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var); \ 9630e702abSChristian Schoenebeck 9730e702abSChristian Schoenebeck /** 98*35b64664SChristian Schoenebeck * P9ARRAY_DEFINE_TYPE() - Defines an array type for the passed @scalar_type 99*35b64664SChristian Schoenebeck * and appropriate @scalar_cleanup_func. 100*35b64664SChristian Schoenebeck * 101*35b64664SChristian Schoenebeck * @scalar_type: type of the individual array elements 102*35b64664SChristian Schoenebeck * @scalar_cleanup_func: appropriate function to free memory dynamically 103*35b64664SChristian Schoenebeck * allocated by individual array elements before 10430e702abSChristian Schoenebeck * 10530e702abSChristian Schoenebeck * This is typically used from a C unit file. 10630e702abSChristian Schoenebeck */ 10730e702abSChristian Schoenebeck #define P9ARRAY_DEFINE_TYPE(scalar_type, scalar_cleanup_func) \ 10830e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len) \ 10930e702abSChristian Schoenebeck { \ 11030e702abSChristian Schoenebeck p9array_auto_free_##scalar_type(auto_var); \ 11130e702abSChristian Schoenebeck P9Array##scalar_type *arr = g_malloc0(sizeof(P9Array##scalar_type) + \ 11230e702abSChristian Schoenebeck len * sizeof(scalar_type)); \ 11330e702abSChristian Schoenebeck arr->len = len; \ 11430e702abSChristian Schoenebeck *auto_var = &arr->first[0]; \ 11530e702abSChristian Schoenebeck } \ 11630e702abSChristian Schoenebeck \ 11730e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var) \ 11830e702abSChristian Schoenebeck { \ 11930e702abSChristian Schoenebeck scalar_type *first = (*auto_var); \ 12030e702abSChristian Schoenebeck if (!first) { \ 12130e702abSChristian Schoenebeck return; \ 12230e702abSChristian Schoenebeck } \ 12330e702abSChristian Schoenebeck P9Array##scalar_type *arr = (P9Array##scalar_type *) ( \ 12430e702abSChristian Schoenebeck ((char *)first) - offsetof(P9Array##scalar_type, first) \ 12530e702abSChristian Schoenebeck ); \ 12630e702abSChristian Schoenebeck for (size_t i = 0; i < arr->len; ++i) { \ 12730e702abSChristian Schoenebeck scalar_cleanup_func(&arr->first[i]); \ 12830e702abSChristian Schoenebeck } \ 12930e702abSChristian Schoenebeck g_free(arr); \ 13030e702abSChristian Schoenebeck } \ 13130e702abSChristian Schoenebeck 13230e702abSChristian Schoenebeck /** 133*35b64664SChristian Schoenebeck * P9ARRAY_REF() - Declare a reference variable for an array. 134*35b64664SChristian Schoenebeck * 135*35b64664SChristian Schoenebeck * @scalar_type: type of the individual array elements 136*35b64664SChristian Schoenebeck * 13730e702abSChristian Schoenebeck * Used to declare a reference variable (unique pointer) for an array. After 13830e702abSChristian Schoenebeck * leaving the scope of the reference variable, the associated array is 13930e702abSChristian Schoenebeck * automatically freed. 14030e702abSChristian Schoenebeck */ 14130e702abSChristian Schoenebeck #define P9ARRAY_REF(scalar_type) \ 14230e702abSChristian Schoenebeck __attribute((__cleanup__(p9array_auto_free_##scalar_type))) scalar_type* 14330e702abSChristian Schoenebeck 14430e702abSChristian Schoenebeck /** 145*35b64664SChristian Schoenebeck * P9ARRAY_NEW() - Allocate a new array. 14630e702abSChristian Schoenebeck * 147*35b64664SChristian Schoenebeck * @scalar_type: type of the individual array elements 148*35b64664SChristian Schoenebeck * @auto_var: destination reference variable 149*35b64664SChristian Schoenebeck * @len: amount of array elements to be allocated immediately 150*35b64664SChristian Schoenebeck * 151*35b64664SChristian Schoenebeck * Allocates a new array of passed @scalar_type with @len number of array 152*35b64664SChristian Schoenebeck * elements and assigns the created array to the reference variable 153*35b64664SChristian Schoenebeck * @auto_var. 15430e702abSChristian Schoenebeck */ 15530e702abSChristian Schoenebeck #define P9ARRAY_NEW(scalar_type, auto_var, len) \ 156c0451f0bSChristian Schoenebeck QEMU_BUILD_BUG_MSG( \ 157c0451f0bSChristian Schoenebeck !__builtin_types_compatible_p(scalar_type, typeof(*auto_var)), \ 158c0451f0bSChristian Schoenebeck "P9Array scalar type mismatch" \ 159c0451f0bSChristian Schoenebeck ); \ 16030e702abSChristian Schoenebeck p9array_new_##scalar_type((&auto_var), len) 16130e702abSChristian Schoenebeck 16230e702abSChristian Schoenebeck #endif /* QEMU_P9ARRAY_H */ 163