8950c6b5bc91f1c9ed374bb0f60497597efaa019
[ccan] / ccan / take / take.h
1 /* CC0 (Public domain) - see LICENSE file for details */
2 #ifndef CCAN_TAKE_H
3 #define CCAN_TAKE_H
4 #include "config.h"
5 #include <stdbool.h>
6 #include <ccan/str/str.h>
7
8 #ifdef CCAN_TAKE_DEBUG
9 #define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p)
10 #else
11 #define TAKE_LABEL(p) NULL
12 #endif
13
14 /**
15  * TAKES - annotate a formal parameter as being take()-able
16  *
17  * This doesn't do anything, but useful for documentation.
18  *
19  * Example:
20  *      void print_string(const char *str TAKES);
21  *      
22  */
23 #define TAKES
24
25 /**
26  * take - record a pointer to be consumed by the function its handed to.
27  * @p: the pointer to mark, or NULL.
28  *
29  * This marks a pointer object to be freed by the called function,
30  * which is extremely useful for chaining functions.  It works on
31  * NULL, for pass-through error handling.
32  */
33 #define take(p) (take_typeof(p) take_((p), TAKE_LABEL(p)))
34
35 /**
36  * taken - check (and un-take) a pointer was passed with take()
37  * @p: the pointer to check.
38  *
39  * A function which accepts take() arguments uses this to see if it
40  * should own the pointer; it will be removed from the take list, so
41  * this only returns true once.
42  *
43  * Example:
44  *      // Silly routine to add 1
45  *      static int *add_one(const int *num TAKES)
46  *      {
47  *              int *ret;
48  *              if (taken(num))
49  *                      ret = (int *)num;
50  *              else
51  *                      ret = malloc(sizeof(int));
52  *              if (ret)
53  *                      *ret = (*num) + 1;
54  *              return ret;
55  *      }
56  */
57 bool taken(const void *p);
58
59 /**
60  * is_taken - check if a pointer was passed with take()
61  * @p: the pointer to check.
62  *
63  * This is like the above, but doesn't remove it from the taken list.
64  *
65  * Example:
66  *      // Silly routine to add 1: doesn't handle taken args!
67  *      static int *add_one_notake(const int *num)
68  *      {
69  *              int *ret = malloc(sizeof(int));
70  *              assert(!is_taken(num));
71  *              if (ret)
72  *                      *ret = (*num) + 1;
73  *              return ret;
74  *      }
75  */
76 bool is_taken(const void *p);
77
78 /**
79  * taken_any - are there any taken pointers?
80  *
81  * Mainly useful for debugging take() leaks.  With CCAN_TAKE_DEBUG, returns
82  * the label where the pointer was passed to take(), otherwise returns
83  * a static char buffer with the pointer value in it.  NULL if none are taken.
84  *
85  * Example:
86  *      static void cleanup(void)
87  *      {
88  *              assert(!taken_any());
89  *      }
90  */
91 const char *taken_any(void);
92
93 /**
94  * take_cleanup - remove all taken pointers from list.
95  *
96  * This is useful in atexit() handlers for valgrind-style leak detection.
97  *
98  * Example:
99  *      static void cleanup2(void)
100  *      {
101  *              take_cleanup();
102  *      }
103  */
104 void take_cleanup(void);
105
106 /**
107  * take_allocfail - set function to call if we can't reallocated taken array.
108  * @fn: the function.
109  *
110  * If this is not set, then if the array reallocation fails, the
111  * pointer won't be marked taken().  If @fn returns, it is expected to
112  * free the pointer; we return NULL from take() and the function handles
113  * it like any allocation failure.
114  *
115  * Example:
116  *      static void free_on_fail(const void *p)
117  *      {
118  *              free((void *)p);
119  *      }
120  *
121  *      static void init(void)
122  *      {
123  *              take_allocfail(free_on_fail);
124  *      }
125  */
126 void take_allocfail(void (*fn)(const void *p));
127
128 /* Private functions */
129 #if HAVE_TYPEOF
130 #define take_typeof(ptr) (__typeof__(ptr))
131 #else
132 #define take_typeof(ptr)
133 #endif
134
135 void *take_(const void *p, const char *label);
136 #endif /* CCAN_TAKE_H */