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 | \
|
---|
47 | struct slabname { \
|
---|
48 | unsigned slab_size; \
|
---|
49 | unsigned stride; \
|
---|
50 | unsigned slab_count; \
|
---|
51 | elemtype **slab; \
|
---|
52 | }; \
|
---|
53 | static int stat_ ##slabname## realloc; \
|
---|
54 | \
|
---|
55 | static 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 | \
|
---|
68 | static MAYBE_UNUSED void init_ ##slabname(struct slabname *s) \
|
---|
69 | { \
|
---|
70 | init_ ##slabname## _with_stride(s, 1); \
|
---|
71 | } \
|
---|
72 | \
|
---|
73 | static 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 | \
|
---|
83 | static 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 | \
|
---|
106 | static 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 */
|
---|