1*30e702abSChristian Schoenebeck /* 2*30e702abSChristian Schoenebeck * P9Array - deep auto free C-array 3*30e702abSChristian Schoenebeck * 4*30e702abSChristian Schoenebeck * Copyright (c) 2021 Crudebyte 5*30e702abSChristian Schoenebeck * 6*30e702abSChristian Schoenebeck * Authors: 7*30e702abSChristian Schoenebeck * Christian Schoenebeck <qemu_oss@crudebyte.com> 8*30e702abSChristian Schoenebeck * 9*30e702abSChristian Schoenebeck * Permission is hereby granted, free of charge, to any person obtaining a copy 10*30e702abSChristian Schoenebeck * of this software and associated documentation files (the "Software"), to deal 11*30e702abSChristian Schoenebeck * in the Software without restriction, including without limitation the rights 12*30e702abSChristian Schoenebeck * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13*30e702abSChristian Schoenebeck * copies of the Software, and to permit persons to whom the Software is 14*30e702abSChristian Schoenebeck * furnished to do so, subject to the following conditions: 15*30e702abSChristian Schoenebeck * 16*30e702abSChristian Schoenebeck * The above copyright notice and this permission notice shall be included in 17*30e702abSChristian Schoenebeck * all copies or substantial portions of the Software. 18*30e702abSChristian Schoenebeck * 19*30e702abSChristian Schoenebeck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20*30e702abSChristian Schoenebeck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21*30e702abSChristian Schoenebeck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22*30e702abSChristian Schoenebeck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23*30e702abSChristian Schoenebeck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24*30e702abSChristian Schoenebeck * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25*30e702abSChristian Schoenebeck * THE SOFTWARE. 26*30e702abSChristian Schoenebeck */ 27*30e702abSChristian Schoenebeck #ifndef QEMU_P9ARRAY_H 28*30e702abSChristian Schoenebeck #define QEMU_P9ARRAY_H 29*30e702abSChristian Schoenebeck 30*30e702abSChristian Schoenebeck /** 31*30e702abSChristian Schoenebeck * P9Array provides a mechanism to access arrays in common C-style (e.g. by 32*30e702abSChristian Schoenebeck * square bracket [] operator) in conjunction with reference variables that 33*30e702abSChristian Schoenebeck * perform deep auto free of the array when leaving the scope of the auto 34*30e702abSChristian Schoenebeck * reference variable. That means not only is the array itself automatically 35*30e702abSChristian Schoenebeck * freed, but also memory dynamically allocated by the individual array 36*30e702abSChristian Schoenebeck * elements. 37*30e702abSChristian Schoenebeck * 38*30e702abSChristian Schoenebeck * Example: 39*30e702abSChristian Schoenebeck * 40*30e702abSChristian Schoenebeck * Consider the following user struct @c Foo which shall be used as scalar 41*30e702abSChristian Schoenebeck * (element) type of an array: 42*30e702abSChristian Schoenebeck * @code 43*30e702abSChristian Schoenebeck * typedef struct Foo { 44*30e702abSChristian Schoenebeck * int i; 45*30e702abSChristian Schoenebeck * char *s; 46*30e702abSChristian Schoenebeck * } Foo; 47*30e702abSChristian Schoenebeck * @endcode 48*30e702abSChristian Schoenebeck * and assume it has the following function to free memory allocated by @c Foo 49*30e702abSChristian Schoenebeck * instances: 50*30e702abSChristian Schoenebeck * @code 51*30e702abSChristian Schoenebeck * void free_foo(Foo *foo) { 52*30e702abSChristian Schoenebeck * free(foo->s); 53*30e702abSChristian Schoenebeck * } 54*30e702abSChristian Schoenebeck * @endcode 55*30e702abSChristian Schoenebeck * Add the following to a shared header file: 56*30e702abSChristian Schoenebeck * @code 57*30e702abSChristian Schoenebeck * P9ARRAY_DECLARE_TYPE(Foo); 58*30e702abSChristian Schoenebeck * @endcode 59*30e702abSChristian Schoenebeck * and the following to a C unit file: 60*30e702abSChristian Schoenebeck * @code 61*30e702abSChristian Schoenebeck * P9ARRAY_DEFINE_TYPE(Foo, free_foo); 62*30e702abSChristian Schoenebeck * @endcode 63*30e702abSChristian Schoenebeck * Finally the array may then be used like this: 64*30e702abSChristian Schoenebeck * @code 65*30e702abSChristian Schoenebeck * void doSomething(size_t n) { 66*30e702abSChristian Schoenebeck * P9ARRAY_REF(Foo) foos = NULL; 67*30e702abSChristian Schoenebeck * P9ARRAY_NEW(Foo, foos, n); 68*30e702abSChristian Schoenebeck * for (size_t i = 0; i < n; ++i) { 69*30e702abSChristian Schoenebeck * foos[i].i = i; 70*30e702abSChristian Schoenebeck * foos[i].s = calloc(4096, 1); 71*30e702abSChristian Schoenebeck * snprintf(foos[i].s, 4096, "foo %d", i); 72*30e702abSChristian Schoenebeck * if (...) { 73*30e702abSChristian Schoenebeck * return; // array auto freed here 74*30e702abSChristian Schoenebeck * } 75*30e702abSChristian Schoenebeck * } 76*30e702abSChristian Schoenebeck * // array auto freed here 77*30e702abSChristian Schoenebeck * } 78*30e702abSChristian Schoenebeck * @endcode 79*30e702abSChristian Schoenebeck */ 80*30e702abSChristian Schoenebeck 81*30e702abSChristian Schoenebeck /** 82*30e702abSChristian Schoenebeck * Declares an array type for the passed @a scalar_type. 83*30e702abSChristian Schoenebeck * 84*30e702abSChristian Schoenebeck * This is typically used from a shared header file. 85*30e702abSChristian Schoenebeck * 86*30e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 87*30e702abSChristian Schoenebeck */ 88*30e702abSChristian Schoenebeck #define P9ARRAY_DECLARE_TYPE(scalar_type) \ 89*30e702abSChristian Schoenebeck typedef struct P9Array##scalar_type { \ 90*30e702abSChristian Schoenebeck size_t len; \ 91*30e702abSChristian Schoenebeck scalar_type first[]; \ 92*30e702abSChristian Schoenebeck } P9Array##scalar_type; \ 93*30e702abSChristian Schoenebeck \ 94*30e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len); \ 95*30e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var); \ 96*30e702abSChristian Schoenebeck 97*30e702abSChristian Schoenebeck /** 98*30e702abSChristian Schoenebeck * Defines an array type for the passed @a scalar_type and appropriate 99*30e702abSChristian Schoenebeck * @a scalar_cleanup_func. 100*30e702abSChristian Schoenebeck * 101*30e702abSChristian Schoenebeck * This is typically used from a C unit file. 102*30e702abSChristian Schoenebeck * 103*30e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 104*30e702abSChristian Schoenebeck * @param scalar_cleanup_func - appropriate function to free memory dynamically 105*30e702abSChristian Schoenebeck * allocated by individual array elements before 106*30e702abSChristian Schoenebeck */ 107*30e702abSChristian Schoenebeck #define P9ARRAY_DEFINE_TYPE(scalar_type, scalar_cleanup_func) \ 108*30e702abSChristian Schoenebeck void p9array_new_##scalar_type(scalar_type **auto_var, size_t len) \ 109*30e702abSChristian Schoenebeck { \ 110*30e702abSChristian Schoenebeck p9array_auto_free_##scalar_type(auto_var); \ 111*30e702abSChristian Schoenebeck P9Array##scalar_type *arr = g_malloc0(sizeof(P9Array##scalar_type) + \ 112*30e702abSChristian Schoenebeck len * sizeof(scalar_type)); \ 113*30e702abSChristian Schoenebeck arr->len = len; \ 114*30e702abSChristian Schoenebeck *auto_var = &arr->first[0]; \ 115*30e702abSChristian Schoenebeck } \ 116*30e702abSChristian Schoenebeck \ 117*30e702abSChristian Schoenebeck void p9array_auto_free_##scalar_type(scalar_type **auto_var) \ 118*30e702abSChristian Schoenebeck { \ 119*30e702abSChristian Schoenebeck scalar_type *first = (*auto_var); \ 120*30e702abSChristian Schoenebeck if (!first) { \ 121*30e702abSChristian Schoenebeck return; \ 122*30e702abSChristian Schoenebeck } \ 123*30e702abSChristian Schoenebeck P9Array##scalar_type *arr = (P9Array##scalar_type *) ( \ 124*30e702abSChristian Schoenebeck ((char *)first) - offsetof(P9Array##scalar_type, first) \ 125*30e702abSChristian Schoenebeck ); \ 126*30e702abSChristian Schoenebeck for (size_t i = 0; i < arr->len; ++i) { \ 127*30e702abSChristian Schoenebeck scalar_cleanup_func(&arr->first[i]); \ 128*30e702abSChristian Schoenebeck } \ 129*30e702abSChristian Schoenebeck g_free(arr); \ 130*30e702abSChristian Schoenebeck } \ 131*30e702abSChristian Schoenebeck 132*30e702abSChristian Schoenebeck /** 133*30e702abSChristian Schoenebeck * Used to declare a reference variable (unique pointer) for an array. After 134*30e702abSChristian Schoenebeck * leaving the scope of the reference variable, the associated array is 135*30e702abSChristian Schoenebeck * automatically freed. 136*30e702abSChristian Schoenebeck * 137*30e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 138*30e702abSChristian Schoenebeck */ 139*30e702abSChristian Schoenebeck #define P9ARRAY_REF(scalar_type) \ 140*30e702abSChristian Schoenebeck __attribute((__cleanup__(p9array_auto_free_##scalar_type))) scalar_type* 141*30e702abSChristian Schoenebeck 142*30e702abSChristian Schoenebeck /** 143*30e702abSChristian Schoenebeck * Allocates a new array of passed @a scalar_type with @a len number of array 144*30e702abSChristian Schoenebeck * elements and assigns the created array to the reference variable 145*30e702abSChristian Schoenebeck * @a auto_var. 146*30e702abSChristian Schoenebeck * 147*30e702abSChristian Schoenebeck * @param scalar_type - type of the individual array elements 148*30e702abSChristian Schoenebeck * @param auto_var - destination reference variable 149*30e702abSChristian Schoenebeck * @param len - amount of array elements to be allocated immediately 150*30e702abSChristian Schoenebeck */ 151*30e702abSChristian Schoenebeck #define P9ARRAY_NEW(scalar_type, auto_var, len) \ 152*30e702abSChristian Schoenebeck p9array_new_##scalar_type((&auto_var), len) 153*30e702abSChristian Schoenebeck 154*30e702abSChristian Schoenebeck #endif /* QEMU_P9ARRAY_H */ 155