damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

take.c (2734B)


      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 }