xref: /qemu/fsdev/p9array.h (revision bfe7bf85)
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