qemu/fsdev/p9array.h
<<
>>
Prefs
   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 * Declares an array type for the passed @a scalar_type.
  85 *
  86 * This is typically used from a shared header file.
  87 *
  88 * @param scalar_type - type of the individual array elements
  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 * Defines an array type for the passed @a scalar_type and appropriate
 101 * @a scalar_cleanup_func.
 102 *
 103 * This is typically used from a C unit file.
 104 *
 105 * @param scalar_type - type of the individual array elements
 106 * @param scalar_cleanup_func - appropriate function to free memory dynamically
 107 *                              allocated by individual array elements before
 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 * Used to declare a reference variable (unique pointer) for an array. After
 136 * leaving the scope of the reference variable, the associated array is
 137 * automatically freed.
 138 *
 139 * @param scalar_type - type of the individual array elements
 140 */
 141#define P9ARRAY_REF(scalar_type) \
 142    __attribute((__cleanup__(p9array_auto_free_##scalar_type))) scalar_type*
 143
 144/**
 145 * Allocates a new array of passed @a scalar_type with @a len number of array
 146 * elements and assigns the created array to the reference variable
 147 * @a auto_var.
 148 *
 149 * @param scalar_type - type of the individual array elements
 150 * @param auto_var - destination reference variable
 151 * @param len - amount of array elements to be allocated immediately
 152 */
 153#define P9ARRAY_NEW(scalar_type, auto_var, len) \
 154    QEMU_BUILD_BUG_MSG( \
 155        !__builtin_types_compatible_p(scalar_type, typeof(*auto_var)), \
 156        "P9Array scalar type mismatch" \
 157    ); \
 158    p9array_new_##scalar_type((&auto_var), len)
 159
 160#endif /* QEMU_P9ARRAY_H */
 161