From 5bdda8409e559d1b3485639ed43d3b69e4c3fa62 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 18 Nov 2012 14:07:35 +1030 Subject: [PATCH] tal: add TAL_TAKE. TAL_TAKE provides a magic context meaning "consume my args and return a replacement". This is useful for writing convenience functions, though not so useful in the standard routines here. Signed-off-by: Rusty Russell --- ccan/tal/tal.c | 16 ++++++++++++-- ccan/tal/tal.h | 31 +++++++++++++++++++++----- ccan/tal/test/run-take.c | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 ccan/tal/test/run-take.c diff --git a/ccan/tal/tal.c b/ccan/tal/tal.c index e5751305..d7b7b4b2 100644 --- a/ccan/tal/tal.c +++ b/ccan/tal/tal.c @@ -706,7 +706,12 @@ char *tal_strndup(const tal_t *ctx, const char *p, size_t n) void *tal_memdup(const tal_t *ctx, const void *p, size_t n) { - void *ret = tal_arr(ctx, char, n); + void *ret; + + if (ctx == TAL_TAKE) + return (void *)p; + + ret = tal_arr(ctx, char, n); if (ret) memcpy(ret, p, n); return ret; @@ -727,9 +732,14 @@ char *tal_asprintf(const tal_t *ctx, const char *fmt, ...) char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap) { size_t max = strlen(fmt) * 2; - char *buf = tal_arr(ctx, char, max); + char *buf; int ret; + if (ctx == TAL_TAKE) + buf = tal_arr(tal_parent(fmt), char, max); + else + buf = tal_arr(ctx, char, max); + while (buf) { va_list ap2; @@ -741,6 +751,8 @@ char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap) break; buf = tal_resize(buf, max *= 2); } + if (ctx == TAL_TAKE) + tal_free(fmt); return buf; } diff --git a/ccan/tal/tal.h b/ccan/tal/tal.h index d511e88a..24db0864 100644 --- a/ccan/tal/tal.h +++ b/ccan/tal/tal.h @@ -17,6 +17,18 @@ */ typedef void tal_t; +/** + * TAL_TAKE - fake tal_t to indicate function will own arguments. + * + * Various functions take a context on which to allocate: if you use + * TAL_TAKE there instead, it means that the argument(s) are actually + * tal objects. The returned value will share the same parent; it may + * even be the same pointer as the arguments. The arguments themselves + * will be reused, freed, or made a child of the return value: they are + * no longer valid for external use. + */ +#define TAL_TAKE ((tal_t *)-2L) + /** * tal - basic allocator function * @ctx: NULL, or tal allocated object to be parent. @@ -146,22 +158,23 @@ tal_t *tal_parent(const tal_t *ctx); /** * tal_memdup - duplicate memory. - * @ctx: NULL, or tal allocated object to be parent. + * @ctx: NULL, or tal allocated object to be parent (or TAL_TAKE). * @p: the memory to copy * @n: the number of bytes. + * */ void *tal_memdup(const tal_t *ctx, const void *p, size_t n); /** - * tal_strdup - duplicate a string. - * @ctx: NULL, or tal allocated object to be parent. + * tal_strdup - duplicate a string + * @ctx: NULL, or tal allocated object to be parent (or TAL_TAKE). * @p: the string to copy */ char *tal_strdup(const tal_t *ctx, const char *p); /** * tal_strndup - duplicate a limited amount of a string. - * @ctx: NULL, or tal allocated object to be parent. + * @ctx: NULL, or tal allocated object to be parent (or TAL_TAKE). * @p: the string to copy * @n: the maximum length to copy. * @@ -171,16 +184,22 @@ char *tal_strndup(const tal_t *ctx, const char *p, size_t n); /** * tal_asprintf - allocate a formatted string - * @ctx: NULL, or tal allocated object to be parent. + * @ctx: NULL, or tal allocated object to be parent (or TAL_TAKE). * @fmt: the printf-style format. + * + * If @ctx is TAL_TAKE, @fmt is freed and its parent will be the parent + * of the return value. */ char *tal_asprintf(const tal_t *ctx, const char *fmt, ...) PRINTF_FMT(2,3); /** * tal_vasprintf - allocate a formatted string (va_list version) - * @ctx: NULL, or tal allocated object to be parent. + * @ctx: NULL, or tal allocated object to be parent (or TAL_TAKE). * @fmt: the printf-style format. * @va: the va_list containing the format args. + * + * If @ctx is TAL_TAKE, @fmt is freed and its parent will be the parent + * of the return value. */ char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap) PRINTF_FMT(2,0); diff --git a/ccan/tal/test/run-take.c b/ccan/tal/test/run-take.c new file mode 100644 index 00000000..dbc78a33 --- /dev/null +++ b/ccan/tal/test/run-take.c @@ -0,0 +1,47 @@ +#include +#include +#include + +int main(void) +{ + char *parent, *c; + + plan_tests(13); + + parent = tal(NULL, char); + ok1(parent); + + c = tal_strdup(parent, "hello"); + + c = tal_strdup(TAL_TAKE, c); + ok1(strcmp(c, "hello") == 0); + ok1(tal_parent(c) == parent); + + c = tal_strndup(TAL_TAKE, c, 5); + ok1(strcmp(c, "hello") == 0); + ok1(tal_parent(c) == parent); + + c = tal_strndup(TAL_TAKE, c, 3); + ok1(strcmp(c, "hel") == 0); + ok1(tal_parent(c) == parent); + + c = tal_memdup(TAL_TAKE, c, 1); + ok1(c[0] == 'h'); + ok1(tal_parent(c) == parent); + + /* No leftover allocations. */ + tal_free(c); + ok1(tal_first(parent) == NULL); + + c = tal_strdup(parent, "hello %s"); + c = tal_asprintf(TAL_TAKE, c, "there"); + ok1(strcmp(c, "hello there") == 0); + ok1(tal_parent(c) == parent); + /* No leftover allocations. */ + tal_free(c); + ok1(tal_first(parent) == NULL); + + tal_free(parent); + + return exit_status(); +} -- 2.39.2