libei/src/util-object.h
Peter Hutterer b6f477fb96 util-object: split macro to generate unref into one two
One macro that also defines the cleanup function, one macro that only
defines the unref. This is required for any place where we want to
use cleanup from multiple source files - like the test suite.
2022-03-03 05:41:15 +00:00

190 lines
5.7 KiB
C

/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2020 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/**
* This is an abstraction layer for ref-counted objects with an optional
* parent. It cuts down on boilerplate by providing a bunch of macros
* that generate the various required functions.
* Limitation: the object must be the first item in the parent struct.
*/
#pragma once
#include "config.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
struct object;
/**
* Function called when the last reference is unref'd. Clean up **internal**
* state of the object, the object itself is freed by the generated
* functions.
*/
typedef void (*object_destroy_func_t)(struct object *object);
/* internal implementation, do not use directly */
struct object {
struct object *parent; /* may be NULL */
uint32_t refcount;
object_destroy_func_t destroy;
};
/* internal implementation, do not call directly */
static inline void
object_init(struct object *object,
struct object *parent,
object_destroy_func_t destroy)
{
object->refcount = 1;
object->destroy = destroy;
object->parent = parent;
}
/* internal implementation, do not call directly */
static inline void
object_destroy(struct object *object)
{
if (object->destroy)
object->destroy(object);
free(object);
}
/* internal implementation, do not call directly */
static inline void *
object_ref(struct object *object)
{
assert(object->refcount >= 1);
++object->refcount;
return object;
}
/* internal implementation, do not call directly */
static inline void *
object_unref(struct object *object)
{
assert(object->refcount >= 1);
if (--object->refcount == 0)
object_destroy(object);
return NULL;
}
/**
* For a type of "foo", generate
* struct foo *foo_ref(struct foo *f);
*/
#define OBJECT_IMPLEMENT_REF(type_) \
struct type_ * type_##_ref(struct type_ *obj) { \
object_ref(&obj->object); \
return obj; \
}
/**
* For a type of "foo", generate
* struct foo *foo_unref(struct foo *f);
* The function always returns NULL, when the last reference is removed the
* object is freed.
*/
#define OBJECT_IMPLEMENT_UNREF(type_) \
struct type_ * type_##_unref(struct type_ *obj) { \
if (!obj) return NULL; \
return object_unref(&obj->object); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* Same as OBJECT_IMPLEMENT_UNREF() but also
* also defines a unrefp function, use with
* __attribute__((cleanup(foo_unrefp))
*/
#define OBJECT_IMPLEMENT_UNREF_CLEANUP(type_) \
OBJECT_IMPLEMENT_UNREF(type_); \
__attribute__((used)) static inline void type_##_unrefp(struct type_ **p_) { \
if (*p_) type_##_unref(*p_); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* For a type for "foo", generate
* void foo_init_object(struct foo *f)
* which sets up the *object* part of the foo struct. Use this where
* allocation through foo_create isn't suitable.
*/
#define OBJECT_IMPLEMENT_INIT(type_) \
void type_##_init_object(struct type_ *t, struct object *parent) { \
assert((intptr_t)t == (intptr_t)&t->object && "field 'object' must be first one in the struct"); \
object_init(&t->object, parent, (object_destroy_func_t)type_##_destroy); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* For a type for "foo", generate
* struct foo *foo_create(struct object *parent)
* which returns an callocated and initialized foo struct.
*/
#define OBJECT_IMPLEMENT_CREATE(type_) \
struct type_ * type_##_create(struct object *parent) { \
struct type_ *t = calloc(1, sizeof *t); \
assert((intptr_t)t == (intptr_t)&t->object && "field 'object' must be first one in the struct"); \
assert(t != NULL); \
object_init(&t->object, parent, (object_destroy_func_t)type_##_destroy); \
return t; \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* For a type "foo" with parent type "bar", generate
* struct bar* foo_parent(struct foo *foo)
*/
#define OBJECT_IMPLEMENT_PARENT(type_, parent_type_) \
struct parent_type_ * type_##_parent(struct type_ *o) { \
return container_of(o->object.parent, struct parent_type_, object); \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* Generate a simple getter function for the given type, field and return
* type.
*/
#define OBJECT_IMPLEMENT_GETTER(type_, field_, rtype_) \
rtype_ type_##_get_##field_(struct type_ *obj) { \
return obj->field_; \
} \
struct __useless_struct_to_allow_trailing_semicolon__
/**
* Generate a simple setter function for the given type, field and return
* type.
*/
#define OBJECT_IMPLEMENT_SETTER(type_, field_, rtype_) \
void type_##_set_##field_(struct type_ *obj, rtype_ val_) { \
obj->field_ = (val_); \
} \
struct __useless_struct_to_allow_trailing_semicolon__