summaryrefslogtreecommitdiff
path: root/commit-slab.h
blob: f84b449413d434b8145426503a98bcd4f9ad995f (plain)
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(indegee, 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);				\
}									\
									\
static int stat_ ##slabname## realloc

/*
 * Note that this seemingly redundant second 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 'static int stat_indegreerealloc;'.  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 */