]> git.ozlabs.org Git - ccan/blob - ccan/take/take.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / take / take.c
1 /* CC0 (Public domain) - see LICENSE file for details */
2 #include <ccan/take/take.h>
3 #include <ccan/likely/likely.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 static const void **takenarr;
9 static const char **labelarr;
10 static size_t max_taken, num_taken;
11 static size_t allocfail;
12 static void (*allocfailfn)(const void *p);
13
14 void *take_(const void *p, const char *label)
15 {
16         /* Overallocate: it's better than risking calloc returning NULL! */
17         if (unlikely(label && !labelarr))
18                 labelarr = calloc(max_taken+1, sizeof(*labelarr));
19
20         if (unlikely(num_taken == max_taken)) {
21                 const void **new;
22
23                 new = realloc(takenarr, sizeof(*takenarr) * (max_taken+1));
24                 if (unlikely(!new)) {
25                         if (allocfailfn) {
26                                 allocfail++;
27                                 allocfailfn(p);
28                                 return NULL;
29                         }
30                         /* Otherwise we leak p. */
31                         return (void *)p;
32                 }
33                 takenarr = new;
34                 /* Once labelarr is set, we maintain it. */
35                 if (labelarr) {
36                         const char **labelarr_new;
37                         labelarr_new = realloc(labelarr,
38                                                sizeof(*labelarr) * (max_taken+1));
39                         if (labelarr_new) {
40                                 labelarr = labelarr_new;
41                         } else {
42                                 /* num_taken will be out of sync with the size of
43                                  * labelarr after realloc failure.
44                                  * Just pretend that we never had labelarr allocated. */
45                                 free(labelarr);
46                                 labelarr = NULL;
47                         }
48                 }
49                 max_taken++;
50         }
51         if (unlikely(labelarr))
52                 labelarr[num_taken] = label;
53         takenarr[num_taken++] = p;
54
55         return (void *)p;
56 }
57
58 static size_t find_taken(const void *p)
59 {
60         size_t i;
61
62         for (i = 0; i < num_taken; i++) {
63                 if (takenarr[i] == p)
64                         return i+1;
65         }
66         return 0;
67 }
68
69 bool taken(const void *p)
70 {
71         size_t i;
72
73         if (!p && unlikely(allocfail)) {
74                 allocfail--;
75                 return true;
76         }
77
78         i = find_taken(p);
79         if (!i)
80                 return false;
81
82         memmove(&takenarr[i-1], &takenarr[i],
83                 (--num_taken - (i - 1))*sizeof(takenarr[0]));
84         return true;
85 }
86
87 bool is_taken(const void *p)
88 {
89         if (!p && unlikely(allocfail))
90                 return true;
91
92         return find_taken(p) > 0;
93 }
94
95 const char *taken_any(void)
96 {
97         static char pointer_buf[32];
98
99         if (num_taken == 0)
100                 return NULL;
101
102         /* We're *allowed* to have some with labels, some without. */
103         if (labelarr) {
104                 size_t i;
105                 for (i = 0; i < num_taken; i++)
106                         if (labelarr[i])
107                                 return labelarr[i];
108         }
109
110         sprintf(pointer_buf, "%p", takenarr[0]);
111         return pointer_buf;
112 }
113
114 void take_cleanup(void)
115 {
116         max_taken = num_taken = 0;
117         free(takenarr);
118         takenarr = NULL;
119         free(labelarr);
120         labelarr = NULL;
121 }
122
123 void take_allocfail(void (*fn)(const void *p))
124 {
125         allocfailfn = fn;
126 }