1#ifndef COMMIT_SLAB_H 2#define COMMIT_SLAB_H 3 4/* 5 * define_commit_slab(slabname, elemtype) creates boilerplate code to define 6 * a new struct (struct slabname) that is used to associate a piece of data 7 * of elemtype to commits, and a few functions to use that struct. 8 * 9 * After including this header file, using: 10 * 11 * define_commit_slab(indegee, int); 12 * 13 * will let you call the following functions: 14 * 15 * - int *indegree_at(struct indegree *, struct commit *); 16 * 17 * This function locates the data associated with the given commit in 18 * the indegree slab, and returns the pointer to it. 19 * 20 * - void init_indegree(struct indegree *); 21 * void init_indegree_with_stride(struct indegree *, int); 22 * 23 * Initializes the indegree slab that associates an array of integers 24 * to each commit. 'stride' specifies how big each array is. The slab 25 * that is initialized by the variant without "_with_stride" associates 26 * each commit with an array of one integer. 27 * 28 * - void clear_indegree(struct indegree *); 29 * 30 * Empties the slab. The slab can be reused with the same stride 31 * without calling init_indegree() again or can be reconfigured to a 32 * different stride by calling init_indegree_with_stride(). 33 * 34 * Call this function before the slab falls out of scope to avoid 35 * leaking memory. 36 */ 37 38/* allocate ~512kB at once, allowing for malloc overhead */ 39#ifndef COMMIT_SLAB_SIZE 40#define COMMIT_SLAB_SIZE (512*1024-32) 41#endif 42 43#define MAYBE_UNUSED __attribute__((__unused__)) 44 45#define define_commit_slab(slabname, elemtype) \ 46 \ 47struct slabname { \ 48 unsigned slab_size; \ 49 unsigned stride; \ 50 unsigned slab_count; \ 51 elemtype **slab; \ 52}; \ 53static int stat_ ##slabname## realloc; \ 54 \ 55static MAYBE_UNUSED void init_ ##slabname## _with_stride(struct slabname *s, \ 56 unsigned stride) \ 57{ \ 58 unsigned int elem_size; \ 59 if (!stride) \ 60 stride = 1; \ 61 s->stride = stride; \ 62 elem_size = sizeof(elemtype) * stride; \ 63 s->slab_size = COMMIT_SLAB_SIZE / elem_size; \ 64 s->slab_count = 0; \ 65 s->slab = NULL; \ 66} \ 67 \ 68static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \ 69{ \ 70 init_ ##slabname## _with_stride(s, 1); \ 71} \ 72 \ 73static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \ 74{ \ 75 int i; \ 76 for (i = 0; i < s->slab_count; i++) \ 77 free(s->slab[i]); \ 78 s->slab_count = 0; \ 79 free(s->slab); \ 80 s->slab = NULL; \ 81} \ 82 \ 83static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \ 84 const struct commit *c) \ 85{ \ 86 int nth_slab, nth_slot; \ 87 \ 88 nth_slab = c->index / s->slab_size; \ 89 nth_slot = c->index % s->slab_size; \ 90 \ 91 if (s->slab_count <= nth_slab) { \ 92 int i; \ 93 s->slab = xrealloc(s->slab, \ 94 (nth_slab + 1) * sizeof(*s->slab)); \ 95 stat_ ##slabname## realloc++; \ 96 for (i = s->slab_count; i <= nth_slab; i++) \ 97 s->slab[i] = NULL; \ 98 s->slab_count = nth_slab + 1; \ 99 } \ 100 if (!s->slab[nth_slab]) \ 101 s->slab[nth_slab] = xcalloc(s->slab_size, \ 102 sizeof(**s->slab) * s->stride); \ 103 return &s->slab[nth_slab][nth_slot * s->stride]; \ 104} \ 105 \ 106static int stat_ ##slabname## realloc 107 108/* 109 * Note that this seemingly redundant second declaration is required 110 * to allow a terminating semicolon, which makes instantiations look 111 * like function declarations. I.e., the expansion of 112 * 113 * define_commit_slab(indegree, int); 114 * 115 * ends in 'static int stat_indegreerealloc;'. This would otherwise 116 * be a syntax error according (at least) to ISO C. It's hard to 117 * catch because GCC silently parses it by default. 118 */ 119 120#endif/* COMMIT_SLAB_H */