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