Skip to content

Commit a84b794

Browse files
committed
commit-slab: introduce a macro to define a slab for new type
Introduce a header file to define a macro that can define the struct type, initializer, accessor and cleanup functions to manage a commit slab. Update the "indegree" topological sort facility using it. To associate 32 flag bits with each commit, you can write: define_commit_slab(flag32, uint32); to declare "struct flag32" type, define an instance of it with struct flag32 flags; and initialize it by calling init_flag32(&flags); After that, a call to flag32_at() function uint32 *fp = flag32_at(&flags, commit); will return a pointer pointing at a uint32 for that commit. Once you are done with these flags, clean them up with clear_flag32(&flags); Callers that cannot hard-code how wide the data to be associated with the commit be at compile time can use the "_with_stride" variant to initialize the slab. Suppose you want to give one bit per existing ref, and paint commits down to find which refs are descendants of each commit. Saying typedef uint32 bits320[5]; define_commit_slab(flagbits, bits320); at compile time will still limit your code with hard-coded limit, because you may find that you have more than 320 refs at runtime. The code can declare a commit slab "struct flagbits" like this instead: define_commit_slab(flagbits, unsigned char); struct flagbits flags; and initialize it by: nrefs = ... count number of refs ... init_flagbits_with_stride(&flags, (nrefs + 7) / 8); so that unsigned char *fp = flagbits_at(&flags, commit); will return a pointer pointing at an array of 40 "unsigned char"s associated with the commit, once you figure out nrefs is 320 at runtime. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 66eb375 commit a84b794

File tree

2 files changed

+112
-58
lines changed

2 files changed

+112
-58
lines changed

commit-slab.h

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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 id initialied by the variant without "_with_stride" associates
26+
* each commit with an array of one integer.
27+
*/
28+
29+
/* allocate ~512kB at once, allowing for malloc overhead */
30+
#ifndef COMMIT_SLAB_SIZE
31+
#define COMMIT_SLAB_SIZE (512*1024-32)
32+
#endif
33+
34+
#define define_commit_slab(slabname, elemtype) \
35+
\
36+
struct slabname { \
37+
unsigned slab_size; \
38+
unsigned stride; \
39+
unsigned slab_count; \
40+
elemtype **slab; \
41+
}; \
42+
static int stat_ ##slabname## realloc; \
43+
\
44+
static void init_ ##slabname## _with_stride(struct slabname *s, \
45+
unsigned stride) \
46+
{ \
47+
unsigned int elem_size; \
48+
if (!stride) \
49+
stride = 1; \
50+
s->stride = stride; \
51+
elem_size = sizeof(struct slabname) * stride; \
52+
s->slab_size = COMMIT_SLAB_SIZE / elem_size; \
53+
s->slab_count = 0; \
54+
s->slab = NULL; \
55+
} \
56+
\
57+
static void init_ ##slabname(struct slabname *s) \
58+
{ \
59+
init_ ##slabname## _with_stride(s, 1); \
60+
} \
61+
\
62+
static void clear_ ##slabname(struct slabname *s) \
63+
{ \
64+
int i; \
65+
for (i = 0; i < s->slab_count; i++) \
66+
free(s->slab[i]); \
67+
s->slab_count = 0; \
68+
free(s->slab); \
69+
s->slab = NULL; \
70+
} \
71+
\
72+
static elemtype *slabname## _at(struct slabname *s, \
73+
const struct commit *c) \
74+
{ \
75+
int nth_slab, nth_slot, ix; \
76+
\
77+
ix = c->index * s->stride; \
78+
nth_slab = ix / s->slab_size; \
79+
nth_slot = ix % s->slab_size; \
80+
\
81+
if (s->slab_count <= nth_slab) { \
82+
int i; \
83+
s->slab = xrealloc(s->slab, \
84+
(nth_slab + 1) * sizeof(s->slab)); \
85+
stat_ ##slabname## realloc++; \
86+
for (i = s->slab_count; i <= nth_slab; i++) \
87+
s->slab[i] = NULL; \
88+
s->slab_count = nth_slab + 1; \
89+
} \
90+
if (!s->slab[nth_slab]) \
91+
s->slab[nth_slab] = xcalloc(s->slab_size, \
92+
sizeof(**s->slab)); \
93+
return &s->slab[nth_slab][nth_slot]; \
94+
} \
95+
\
96+
static int stat_ ##slabname## realloc
97+
98+
#endif /* COMMIT_SLAB_H */

commit.c

+14-58
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "notes.h"
99
#include "gpg-interface.h"
1010
#include "mergesort.h"
11+
#include "commit-slab.h"
1112

1213
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
1314

@@ -501,57 +502,12 @@ struct commit *pop_commit(struct commit_list **stack)
501502
return item;
502503
}
503504

504-
struct commit_slab_piece {
505-
int buf;
506-
};
507-
508-
struct commit_slab {
509-
int piece_size;
510-
int piece_count;
511-
struct commit_slab_piece **piece;
512-
};
513-
514-
static void slab_init(struct commit_slab *s)
515-
{
516-
/* allocate ~512kB at once, allowing for malloc overhead */
517-
int size = (512*1024-32) / sizeof(struct commit_slab_piece);
518-
519-
s->piece_size = size;
520-
s->piece_count = 0;
521-
s->piece = NULL;
522-
}
523-
524-
static void slab_clear(struct commit_slab *s)
525-
{
526-
int i;
527-
528-
for (i = 0; i < s->piece_count; i++)
529-
free(s->piece[i]);
530-
s->piece_count = 0;
531-
free(s->piece);
532-
s->piece = NULL;
533-
}
534-
535-
static inline struct commit_slab_piece *slab_at(struct commit_slab *s,
536-
const struct commit *c)
537-
{
538-
int nth_piece, nth_slot;
539-
540-
nth_piece = c->index / s->piece_size;
541-
nth_slot = c->index % s->piece_size;
542-
543-
if (s->piece_count <= nth_piece) {
544-
int i;
505+
/*
506+
* Topological sort support
507+
*/
545508

546-
s->piece = xrealloc(s->piece, (nth_piece + 1) * sizeof(s->piece));
547-
for (i = s->piece_count; i <= nth_piece; i++)
548-
s->piece[i] = NULL;
549-
s->piece_count = nth_piece + 1;
550-
}
551-
if (!s->piece[nth_piece])
552-
s->piece[nth_piece] = xcalloc(s->piece_size, sizeof(**s->piece));
553-
return &s->piece[nth_piece][nth_slot];
554-
}
509+
/* count number of children that have not been emitted */
510+
define_commit_slab(indegree_slab, int);
555511

556512
/*
557513
* Performs an in-place topological sort on the list supplied.
@@ -561,26 +517,26 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
561517
struct commit_list *next, *orig = *list;
562518
struct commit_list *work, **insert;
563519
struct commit_list **pptr;
564-
struct commit_slab indegree;
520+
struct indegree_slab indegree;
565521

566522
if (!orig)
567523
return;
568524
*list = NULL;
569525

570-
slab_init(&indegree);
526+
init_indegree_slab(&indegree);
571527

572528
/* Mark them and clear the indegree */
573529
for (next = orig; next; next = next->next) {
574530
struct commit *commit = next->item;
575-
slab_at(&indegree, commit)->buf = 1;
531+
*(indegree_slab_at(&indegree, commit)) = 1;
576532
}
577533

578534
/* update the indegree */
579535
for (next = orig; next; next = next->next) {
580536
struct commit_list * parents = next->item->parents;
581537
while (parents) {
582538
struct commit *parent = parents->item;
583-
int *pi = &slab_at(&indegree, parent)->buf;
539+
int *pi = indegree_slab_at(&indegree, parent);
584540

585541
if (*pi)
586542
(*pi)++;
@@ -600,7 +556,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
600556
for (next = orig; next; next = next->next) {
601557
struct commit *commit = next->item;
602558

603-
if (slab_at(&indegree, commit)->buf == 1)
559+
if (*(indegree_slab_at(&indegree, commit)) == 1)
604560
insert = &commit_list_insert(commit, insert)->next;
605561
}
606562

@@ -621,7 +577,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
621577
commit = work_item->item;
622578
for (parents = commit->parents; parents ; parents = parents->next) {
623579
struct commit *parent = parents->item;
624-
int *pi = &slab_at(&indegree, parent)->buf;
580+
int *pi = indegree_slab_at(&indegree, parent);
625581

626582
if (!*pi)
627583
continue;
@@ -642,12 +598,12 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
642598
* work_item is a commit all of whose children
643599
* have already been emitted. we can emit it now.
644600
*/
645-
slab_at(&indegree, commit)->buf = 0;
601+
*(indegree_slab_at(&indegree, commit)) = 0;
646602
*pptr = work_item;
647603
pptr = &work_item->next;
648604
}
649605

650-
slab_clear(&indegree);
606+
clear_indegree_slab(&indegree);
651607
}
652608

653609
/* merge-base stuff */

0 commit comments

Comments
 (0)