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