take.c (3051B)
1 /* CC0 (Public domain) - see LICENSE file for details */ 2 #include "take.h" 3 #include "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 }