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