Commit 97ac5832 authored by Rusty Russell's avatar Rusty Russell

tal/autoptr: new module.

Helps with the common case of wanting to NULL out a pointer when the object
freed.  We could also track it if resized, but that's TODO.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 58277ab6
../../../licenses/BSD-MIT
\ No newline at end of file
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* tal/autoptr - automatic updates of pointers to tal objects.
*
* This code updates pointers when the pointed-to object is freed.
*
* Maintainer: Rusty Russell <rusty@rustcorp.com.au>
* License: BSD-MIT
* Example:
* #include <ccan/tal/autoptr/autoptr.h>
* #include <assert.h>
*
* static void *p;
*
* int main(void)
* {
* char *c = tal(NULL, char);
*
* // Sets p to point to c.
* autonull_set_ptr(NULL, &p, c);
* assert(p == c);
*
* // Automatically clears p.
* tal_free(c);
* assert(p == NULL);
* return 0;
* }
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/tal\n");
return 0;
}
return 1;
}
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/tal/autoptr/autoptr.h>
struct autonull {
void **pp;
};
static void autonull_remove(struct autonull *a);
static void autonull_null_out(tal_t *p UNNEEDED, struct autonull *a)
{
void **pp = a->pp;
tal_del_destructor(a, autonull_remove);
tal_free(a);
*pp = NULL;
}
static void autonull_remove(struct autonull *a)
{
/* Don't NULL us out now. */
tal_del_destructor2(*a->pp, autonull_null_out, a);
}
struct autonull *autonull_set_ptr_(const tal_t *ctx, void *pp, const tal_t *p)
{
struct autonull *a = tal(ctx, struct autonull);
a->pp = (void **)pp;
*a->pp = (void *)p;
/* If p is freed, NULL out a->pp */
tal_add_destructor2(*a->pp, autonull_null_out, a);
/* If they free autonull, it removes other destructor. */
tal_add_destructor(a, autonull_remove);
return a;
}
/* MIT (BSD) license - see LICENSE file for details */
#ifndef CCAN_TAL_AUTOPTR_H
#define CCAN_TAL_AUTOPTR_H
#include <ccan/tal/tal.h>
struct autonull;
/**
* autonull_set_ptr - set a pointer, NULL it when pointer tal_free'd.
* @ctx: the tal context which owns this autonull.
* @pp: pointer to tal pointer
* @p: the tal pointer to set *@pp to.
*
* *@pp is set to @p. When @p is tal_free'd directly or indirectly, *@pp will
* be set to NULL. Or, if the returned object is freed, the callback is
* deactivated.
*
* Example:
* struct parent {
* struct child *c;
* };
* struct child {
* const char *name;
* };
*
* int main(void)
* {
* struct parent *p = tal(NULL, struct parent);
* struct child *c = tal(p, struct child);
* c->name = "Child";
*
* autonull_set_ptr(p, &p->c, c);
* assert(p->c == c);
*
* // Automatically clears p->c.
* tal_free(c);
* assert(p->c == NULL);
* return 0;
* }
*
*/
#define autonull_set_ptr(ctx, pp, p) \
autonull_set_ptr_((ctx), (pp) + 0*sizeof(*(pp) = (p)), (p))
struct autonull *autonull_set_ptr_(const tal_t *ctx, void *pp, const tal_t *p);
#endif /* CCAN_TAL_AUTOPTR_H */
#include <ccan/tal/autoptr/autoptr.h>
/* Include the C files directly. */
#include <ccan/tal/autoptr/autoptr.c>
#include <ccan/tap/tap.h>
int main(void)
{
char *p1, *p2, *p3;
struct autonull *a;
/* This is how many tests you plan to run */
plan_tests(8);
p1 = tal(NULL, char);
// Sets p1 to point to p2.
autonull_set_ptr(NULL, &p2, p1);
ok1(p2 == p1);
tal_free(p1);
ok1(p2 == NULL);
// Using p1 as the parent is the same. */
p1 = tal(NULL, char);
autonull_set_ptr(p1, &p2, p1);
ok1(p2 == p1);
tal_free(p1);
ok1(p2 == NULL);
// Freeing autodata deactivates it.
p1 = tal(NULL, char);
a = autonull_set_ptr(NULL, &p2, p1);
ok1(p2 == p1);
tal_free(a);
tal_free(p1);
ok1(p2 == p1);
// Making p3 the parent means freeing p3 deactivates it.
p3 = tal(NULL, char);
p1 = tal(NULL, char);
autonull_set_ptr(p3, &p2, p1);
ok1(p2 == p1);
tal_free(p3);
tal_free(p1);
ok1(p2 == p1);
/* This exits depending on whether all tests passed */
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment