qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

p9array.h (5557B)


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