commit-slab: introduce slabname##_peek() function

There is no API to ask "Does this commit have associated data in slab?". If an application wants to (1) parse just a few commits at the beginning of a process, (2) store data for only these commits, and then (3) start processing many commits, taking into account the data stored (for a few of them) in the slab, the application would use slabname##_at() to allocate a space to store data in (2), but there is no API other than slabname##_at() to use in step (3). This allocates and wastes new space for these commits the caller is only interested in checking if they have data stored in step (2). Introduce slabname##_peek(), which is similar to slabname##_at() but returns NULL when there is no data already associated to it in such a use case. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed May 14, 2015 at 15:25 UTC 862e730ec1c13f28bfb7c8c9ecb39bcc92dd0922
2 files changed +49 -13
commit-slab.h
+29 -5
@@ -15,7 +15,13 @@
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.
18 + * the indegree slab, and returns the pointer to it. The location to
19 + * store the data is allocated as necessary.
20 + *
21 + * - int *indegree_peek(struct indegree *, struct commit *);
22 + *
23 + * This function is similar to indegree_at(), but it will return NULL
24 + * until a call to indegree_at() was made for the commit.
25 *
26 * - void init_indegree(struct indegree *);
27 * void init_indegree_with_stride(struct indegree *, int);
@@ -80,8 +86,9 @@ static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s) \
86 s->slab = NULL; \
87 } \
88 \
83 -static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
84 - const struct commit *c) \
89 +static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s, \
90 + const struct commit *c, \
91 + int add_if_missing) \
92 { \
93 int nth_slab, nth_slot; \
94 \
@@ -90,6 +97,8 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
97 \
98 if (s->slab_count <= nth_slab) { \
99 int i; \
100 + if (!add_if_missing) \
101 + return NULL; \
102 s->slab = xrealloc(s->slab, \
103 (nth_slab + 1) * sizeof(*s->slab)); \
104 stat_ ##slabname## realloc++; \
@@ -97,10 +106,25 @@ static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
106 s->slab[i] = NULL; \
107 s->slab_count = nth_slab + 1; \
108 } \
100 - if (!s->slab[nth_slab]) \
109 + if (!s->slab[nth_slab]) { \
110 + if (!add_if_missing) \
111 + return NULL; \
112 s->slab[nth_slab] = xcalloc(s->slab_size, \
113 sizeof(**s->slab) * s->stride); \
103 - return &s->slab[nth_slab][nth_slot * s->stride]; \
114 + } \
115 + return &s->slab[nth_slab][nth_slot * s->stride]; \
116 +} \
117 + \
118 +static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s, \
119 + const struct commit *c) \
120 +{ \
121 + return slabname##_at_peek(s, c, 1); \
122 +} \
123 + \
124 +static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s, \
125 + const struct commit *c) \
126 +{ \
127 + return slabname##_at_peek(s, c, 0); \
128 } \
129 \
130 static int stat_ ##slabname## realloc
commit.c
+20 -8
@@ -244,7 +244,12 @@ void set_commit_buffer(struct commit *commit, void *buffer, unsigned long size)
244
245 const void *get_cached_commit_buffer(const struct commit *commit, unsigned long *sizep)
246 {
247 - struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
247 + struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
248 + if (!v) {
249 + if (sizep)
250 + *sizep = 0;
251 + return NULL;
252 + }
253 if (sizep)
254 *sizep = v->size;
255 return v->buffer;
@@ -271,24 +276,31 @@ const void *get_commit_buffer(const struct commit *commit, unsigned long *sizep)
276
277 void unuse_commit_buffer(const struct commit *commit, const void *buffer)
278 {
274 - struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
275 - if (v->buffer != buffer)
279 + struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
280 + if (!(v && v->buffer == buffer))
281 free((void *)buffer);
282 }
283
284 void free_commit_buffer(struct commit *commit)
285 {
281 - struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
282 - free(v->buffer);
283 - v->buffer = NULL;
284 - v->size = 0;
286 + struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
287 + if (v) {
288 + free(v->buffer);
289 + v->buffer = NULL;
290 + v->size = 0;
291 + }
292 }
293
294 const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
295 {
289 - struct commit_buffer *v = buffer_slab_at(&buffer_slab, commit);
296 + struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
297 void *ret;
298
299 + if (!v) {
300 + if (sizep)
301 + *sizep = 0;
302 + return NULL;
303 + }
304 ret = v->buffer;
305 if (sizep)
306 *sizep = v->size;