Commit b3b2aaf0 authored by Junio C Hamano's avatar Junio C Hamano

Merge branch 'nd/commit-util-to-slab'

The in-core "commit" object had an all-purpose "void *util" field,
which was tricky to use especially in library-ish part of the
code.  All of the existing uses of the field has been migrated to a
more dedicated "commit-slab" mechanism and the field is eliminated.

* nd/commit-util-to-slab:
  commit.h: delete 'util' field in struct commit
  merge: use commit-slab in merge remote desc instead of commit->util
  log: use commit-slab in prepare_bases() instead of commit->util
  show-branch: note about its object flags usage
  show-branch: use commit-slab for commit-name instead of commit->util
  name-rev: use commit-slab for rev-name instead of commit->util
  bisect.c: use commit-slab for commit weight instead of commit->util
  revision.c: use commit-slab for show_source
  sequencer.c: use commit-slab to associate todo items to commits
  sequencer.c: use commit-slab to mark seen commits
  shallow.c: use commit-slab for commit depth instead of commit->util
  describe: use commit-slab for commit names instead of commit->util
  blame: use commit-slab for blame suspects instead of commit->util
  commit-slab: support shared commit-slab
  commit-slab.h: code split
parents ea27893a 9d2c9701
......@@ -12,6 +12,7 @@
#include "bisect.h"
#include "sha1-array.h"
#include "argv-array.h"
#include "commit-slab.h"
static struct oid_array good_revs;
static struct oid_array skipped_revs;
......@@ -70,16 +71,19 @@ static void clear_distance(struct commit_list *list)
}
}
define_commit_slab(commit_weight, int *);
static struct commit_weight commit_weight;
#define DEBUG_BISECT 0
static inline int weight(struct commit_list *elem)
{
return *((int*)(elem->item->util));
return **commit_weight_at(&commit_weight, elem->item);
}
static inline void weight_set(struct commit_list *elem, int weight)
{
*((int*)(elem->item->util)) = weight;
**commit_weight_at(&commit_weight, elem->item) = weight;
}
static int count_interesting_parents(struct commit *commit)
......@@ -265,7 +269,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
struct commit *commit = p->item;
unsigned flags = commit->object.flags;
p->item->util = &weights[n++];
*commit_weight_at(&commit_weight, p->item) = &weights[n++];
switch (count_interesting_parents(commit)) {
case 0:
if (!(flags & TREESAME)) {
......@@ -372,6 +376,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
int *weights;
show_list("bisection 2 entry", 0, 0, *commit_list);
init_commit_weight(&commit_weight);
/*
* Count the number of total and tree-changing items on the
......@@ -412,6 +417,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
}
free(weights);
*commit_list = best;
clear_commit_weight(&commit_weight);
}
static int register_ref(const char *refname, const struct object_id *oid,
......
......@@ -6,6 +6,24 @@
#include "diffcore.h"
#include "tag.h"
#include "blame.h"
#include "commit-slab.h"
define_commit_slab(blame_suspects, struct blame_origin *);
static struct blame_suspects blame_suspects;
struct blame_origin *get_blame_suspects(struct commit *commit)
{
struct blame_origin **result;
result = blame_suspects_peek(&blame_suspects, commit);
return result ? *result : NULL;
}
static void set_blame_suspects(struct commit *commit, struct blame_origin *origin)
{
*blame_suspects_at(&blame_suspects, commit) = origin;
}
void blame_origin_decref(struct blame_origin *o)
{
......@@ -15,12 +33,12 @@ void blame_origin_decref(struct blame_origin *o)
blame_origin_decref(o->previous);
free(o->file.ptr);
/* Should be present exactly once in commit chain */
for (p = o->commit->util; p; l = p, p = p->next) {
for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) {
if (p == o) {
if (l)
l->next = p->next;
else
o->commit->util = p->next;
set_blame_suspects(o->commit, p->next);
free(o);
return;
}
......@@ -41,8 +59,8 @@ static struct blame_origin *make_origin(struct commit *commit, const char *path)
FLEX_ALLOC_STR(o, path, path);
o->commit = commit;
o->refcnt = 1;
o->next = commit->util;
commit->util = o;
o->next = get_blame_suspects(commit);
set_blame_suspects(commit, o);
return o;
}
......@@ -54,13 +72,13 @@ static struct blame_origin *get_origin(struct commit *commit, const char *path)
{
struct blame_origin *o, *l;
for (o = commit->util, l = NULL; o; l = o, o = o->next) {
for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) {
if (!strcmp(o->path, path)) {
/* bump to front */
if (l) {
l->next = o->next;
o->next = commit->util;
commit->util = o;
o->next = get_blame_suspects(commit);
set_blame_suspects(commit, o);
}
return blame_origin_incref(o);
}
......@@ -478,7 +496,7 @@ static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porig
porigin->suspects = blame_merge(porigin->suspects, sorted);
else {
struct blame_origin *o;
for (o = porigin->commit->util; o; o = o->next) {
for (o = get_blame_suspects(porigin->commit); o; o = o->next) {
if (o->suspects) {
porigin->suspects = sorted;
return;
......@@ -525,7 +543,7 @@ static struct blame_origin *find_origin(struct commit *parent,
const char *paths[2];
/* First check any existing origins */
for (porigin = parent->util; porigin; porigin = porigin->next)
for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next)
if (!strcmp(porigin->path, origin->path)) {
/*
* The same path between origin and its parent
......@@ -1550,7 +1568,7 @@ void assign_blame(struct blame_scoreboard *sb, int opt)
while (commit) {
struct blame_entry *ent;
struct blame_origin *suspect = commit->util;
struct blame_origin *suspect = get_blame_suspects(commit);
/* find one suspect to break down */
while (suspect && !suspect->suspects)
......@@ -1752,6 +1770,8 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
struct commit *final_commit = NULL;
enum object_type type;
init_blame_suspects(&blame_suspects);
if (sb->reverse && sb->contents_from)
die(_("--contents and --reverse do not blend well."));
......@@ -1815,7 +1835,7 @@ void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blam
}
if (is_null_oid(&sb->final->object.oid)) {
o = sb->final->util;
o = get_blame_suspects(sb->final);
sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
sb->final_buf_size = o->file.size;
}
......
......@@ -172,4 +172,6 @@ extern void setup_scoreboard(struct blame_scoreboard *sb, const char *path, stru
extern struct blame_entry *blame_entry_prepend(struct blame_entry *head, long start, long end, struct blame_origin *o);
extern struct blame_origin *get_blame_suspects(struct commit *commit);
#endif /* BLAME_H */
......@@ -543,7 +543,7 @@ static void output(struct blame_scoreboard *sb, int option)
struct commit *commit = ent->suspect->commit;
if (commit->object.flags & MORE_THAN_ONE_PATH)
continue;
for (suspect = commit->util; suspect; suspect = suspect->next) {
for (suspect = get_blame_suspects(commit); suspect; suspect = suspect->next) {
if (suspect->guilty && count++) {
commit->object.flags |= MORE_THAN_ONE_PATH;
break;
......
......@@ -15,9 +15,12 @@
#include "run-command.h"
#include "revision.h"
#include "list-objects.h"
#include "commit-slab.h"
#define MAX_TAGS (FLAG_BITS - 1)
define_commit_slab(commit_names, struct commit_name *);
static const char * const describe_usage[] = {
N_("git describe [<options>] [<commit-ish>...]"),
N_("git describe [<options>] --dirty"),
......@@ -37,6 +40,7 @@ static struct string_list patterns = STRING_LIST_INIT_NODUP;
static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
static int always;
static const char *suffix, *dirty, *broken;
static struct commit_names commit_names;
/* diff-index command arguments to check if working tree is dirty. */
static const char *diff_index_args[] = {
......@@ -321,11 +325,14 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
if (!have_util) {
struct hashmap_iter iter;
struct commit *c;
struct commit_name *n = hashmap_iter_first(&names, &iter);
struct commit_name *n;
init_commit_names(&commit_names);
n = hashmap_iter_first(&names, &iter);
for (; n; n = hashmap_iter_next(&iter)) {
c = lookup_commit_reference_gently(&n->peeled, 1);
if (c)
c->util = n;
*commit_names_at(&commit_names, c) = n;
}
have_util = 1;
}
......@@ -336,8 +343,11 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
while (list) {
struct commit *c = pop_commit(&list);
struct commit_list *parents = c->parents;
struct commit_name **slot;
seen_commits++;
n = c->util;
slot = commit_names_peek(&commit_names, c);
n = slot ? *slot : NULL;
if (n) {
if (!tags && !all && n->prio < 2) {
unannotated_cnt++;
......
......@@ -22,6 +22,7 @@
#include "quote.h"
#include "remote.h"
#include "blob.h"
#include "commit-slab.h"
static const char *fast_export_usage[] = {
N_("git fast-export [rev-list-opts]"),
......@@ -38,6 +39,7 @@ static int full_tree;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static struct revision_sources revision_sources;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
......@@ -589,7 +591,7 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
export_blob(&diff_queued_diff.queue[i]->two->oid);
refname = commit->util;
refname = *revision_sources_at(&revision_sources, commit);
if (anonymize) {
refname = anonymize_refname(refname);
anonymize_ident_line(&committer, &committer_end);
......@@ -861,10 +863,11 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
* This ref will not be updated through a commit, lets make
* sure it gets properly updated eventually.
*/
if (commit->util || commit->object.flags & SHOWN)
if (*revision_sources_at(&revision_sources, commit) ||
commit->object.flags & SHOWN)
string_list_append(&extra_refs, full_name)->util = commit;
if (!commit->util)
commit->util = full_name;
if (!*revision_sources_at(&revision_sources, commit))
*revision_sources_at(&revision_sources, commit) = full_name;
}
}
......@@ -1028,8 +1031,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
init_revisions(&revs, prefix);
init_revision_sources(&revision_sources);
revs.topo_order = 1;
revs.show_source = 1;
revs.sources = &revision_sources;
revs.rewrite_parents = 1;
argc = parse_options(argc, argv, prefix, options, fast_export_usage,
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
......
......@@ -28,6 +28,7 @@
#include "mailmap.h"
#include "gpg-interface.h"
#include "progress.h"
#include "commit-slab.h"
#define MAIL_DEFAULT_WRAP 72
......@@ -148,6 +149,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
struct decoration_filter decoration_filter = {&decorate_refs_include,
&decorate_refs_exclude};
static struct revision_sources revision_sources;
const struct option builtin_log_options[] = {
OPT__QUIET(&quiet, N_("suppress diff output")),
......@@ -194,8 +196,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
rev->diffopt.filter || rev->diffopt.flags.follow_renames)
rev->always_show_header = 0;
if (source)
rev->show_source = 1;
if (source) {
init_revision_sources(&revision_sources);
rev->sources = &revision_sources;
}
if (mailmap) {
rev->mailmap = xcalloc(1, sizeof(struct string_list));
......@@ -1337,6 +1341,8 @@ static struct commit *get_base_commit(const char *base_commit,
return base;
}
define_commit_slab(commit_base, int);
static void prepare_bases(struct base_tree_info *bases,
struct commit *base,
struct commit **list,
......@@ -1345,11 +1351,13 @@ static void prepare_bases(struct base_tree_info *bases,
struct commit *commit;
struct rev_info revs;
struct diff_options diffopt;
struct commit_base commit_base;
int i;
if (!base)
return;
init_commit_base(&commit_base);
diff_setup(&diffopt);
diffopt.flags.recursive = 1;
diff_setup_done(&diffopt);
......@@ -1362,7 +1370,7 @@ static void prepare_bases(struct base_tree_info *bases,
for (i = 0; i < total; i++) {
list[i]->object.flags &= ~UNINTERESTING;
add_pending_object(&revs, &list[i]->object, "rev_list");
list[i]->util = (void *)1;
*commit_base_at(&commit_base, list[i]) = 1;
}
base->object.flags |= UNINTERESTING;
add_pending_object(&revs, &base->object, "base");
......@@ -1376,7 +1384,7 @@ static void prepare_bases(struct base_tree_info *bases,
while ((commit = get_revision(&revs)) != NULL) {
struct object_id oid;
struct object_id *patch_id;
if (commit->util)
if (*commit_base_at(&commit_base, commit))
continue;
if (commit_patch_id(commit, &diffopt, &oid, 0))
die(_("cannot get patch id"));
......@@ -1385,6 +1393,7 @@ static void prepare_bases(struct base_tree_info *bases,
oidcpy(patch_id, &oid);
bases->nr_patch_id++;
}
clear_commit_base(&commit_base);
}
static void print_bases(struct base_tree_info *bases, FILE *file)
......
......@@ -445,6 +445,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct object_id branch_head;
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
struct merge_remote_desc *desc;
const char *ptr;
char *found_ref;
int len, early;
......@@ -517,16 +518,13 @@ static void merge_name(const char *remote, struct strbuf *msg)
strbuf_release(&truname);
}
if (remote_head->util) {
struct merge_remote_desc *desc;
desc = merge_remote_util(remote_head);
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
strbuf_addf(msg, "%s\t\t%s '%s'\n",
oid_to_hex(&desc->obj->oid),
type_name(desc->obj->type),
remote);
goto cleanup;
}
desc = merge_remote_util(remote_head);
if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
strbuf_addf(msg, "%s\t\t%s '%s'\n",
oid_to_hex(&desc->obj->oid),
type_name(desc->obj->type),
remote);
goto cleanup;
}
strbuf_addf(msg, "%s\t\tcommit '%s'\n",
......@@ -934,8 +932,11 @@ static void write_merge_heads(struct commit_list *remoteheads)
for (j = remoteheads; j; j = j->next) {
struct object_id *oid;
struct commit *c = j->item;
if (c->util && merge_remote_util(c)->obj) {
oid = &merge_remote_util(c)->obj->oid;
struct merge_remote_desc *desc;
desc = merge_remote_util(c);
if (desc && desc->obj) {
oid = &desc->obj->oid;
} else {
oid = &c->object.oid;
}
......
......@@ -6,6 +6,7 @@
#include "refs.h"
#include "parse-options.h"
#include "sha1-lookup.h"
#include "commit-slab.h"
#define CUTOFF_DATE_SLOP 86400 /* one day */
......@@ -17,11 +18,26 @@ typedef struct rev_name {
int from_tag;
} rev_name;
define_commit_slab(commit_rev_name, struct rev_name *);
static timestamp_t cutoff = TIME_MAX;
static struct commit_rev_name rev_names;
/* How many generations are maximally preferred over _one_ merge traversal? */
#define MERGE_TRAVERSAL_WEIGHT 65535
static struct rev_name *get_commit_rev_name(struct commit *commit)
{
struct rev_name **slot = commit_rev_name_peek(&rev_names, commit);
return slot ? *slot : NULL;
}
static void set_commit_rev_name(struct commit *commit, struct rev_name *name)
{
*commit_rev_name_at(&rev_names, commit) = name;
}
static int is_better_name(struct rev_name *name,
const char *tip_name,
timestamp_t taggerdate,
......@@ -65,7 +81,7 @@ static void name_rev(struct commit *commit,
int generation, int distance, int from_tag,
int deref)
{
struct rev_name *name = (struct rev_name *)commit->util;
struct rev_name *name = get_commit_rev_name(commit);
struct commit_list *parents;
int parent_number = 1;
char *to_free = NULL;
......@@ -84,7 +100,7 @@ static void name_rev(struct commit *commit,
if (name == NULL) {
name = xmalloc(sizeof(rev_name));
commit->util = name;
set_commit_rev_name(commit, name);
goto copy_data;
} else if (is_better_name(name, tip_name, taggerdate,
generation, distance, from_tag)) {
......@@ -296,7 +312,7 @@ static const char *get_rev_name(const struct object *o, struct strbuf *buf)
if (o->type != OBJ_COMMIT)
return get_exact_ref_match(o);
c = (struct commit *) o;
n = c->util;
n = get_commit_rev_name(c);
if (!n)
return NULL;
......@@ -413,6 +429,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
OPT_END(),
};
init_commit_rev_name(&rev_names);
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
if (all + transform_stdin + !!argc > 1) {
......
......@@ -7,6 +7,7 @@
#include "argv-array.h"
#include "parse-options.h"
#include "dir.h"
#include "commit-slab.h"
static const char* show_branch_usage[] = {
N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
......@@ -21,6 +22,11 @@ static int showbranch_use_color = -1;
static struct argv_array default_args = ARGV_ARRAY_INIT;
/*
* TODO: convert this use of commit->object.flags to commit-slab
* instead to store a pointer to ref name directly. Then use the same
* UNINTERESTING definition from revision.h here.
*/
#define UNINTERESTING 01
#define REV_SHIFT 2
......@@ -59,15 +65,27 @@ struct commit_name {
int generation; /* how many parents away from head_name */
};
define_commit_slab(commit_name_slab, struct commit_name *);
static struct commit_name_slab name_slab;
static struct commit_name *commit_to_name(struct commit *commit)
{
return *commit_name_slab_at(&name_slab, commit);
}
/* Name the commit as nth generation ancestor of head_name;
* we count only the first-parent relationship for naming purposes.
*/
static void name_commit(struct commit *commit, const char *head_name, int nth)
{
struct commit_name *name;
if (!commit->util)
commit->util = xmalloc(sizeof(struct commit_name));
name = commit->util;
name = *commit_name_slab_at(&name_slab, commit);
if (!name) {
name = xmalloc(sizeof(*name));
*commit_name_slab_at(&name_slab, commit) = name;
}
name->head_name = head_name;
name->generation = nth;
}
......@@ -79,8 +97,8 @@ static void name_commit(struct commit *commit, const char *head_name, int nth)
*/
static void name_parent(struct commit *commit, struct commit *parent)
{
struct commit_name *commit_name = commit->util;
struct commit_name *parent_name = parent->util;
struct commit_name *commit_name = commit_to_name(commit);
struct commit_name *parent_name = commit_to_name(parent);
if (!commit_name)
return;
if (!parent_name ||
......@@ -94,12 +112,12 @@ static int name_first_parent_chain(struct commit *c)
int i = 0;
while (c) {
struct commit *p;
if (!c->util)
if (!commit_to_name(c))
break;
if (!c->parents)
break;
p = c->parents->item;
if (!p->util) {
if (!commit_to_name(p)) {
name_parent(c, p);
i++;
}
......@@ -122,7 +140,7 @@ static void name_commits(struct commit_list *list,
/* First give names to the given heads */
for (cl = list; cl; cl = cl->next) {
c = cl->item;
if (c->util)
if (commit_to_name(c))
continue;
for (i = 0; i < num_rev; i++) {
if (rev[i] == c) {
......@@ -148,9 +166,9 @@ static void name_commits(struct commit_list *list,
struct commit_name *n;
int nth;
c = cl->item;
if (!c->util)
if (!commit_to_name(c))
continue;
n = c->util;
n = commit_to_name(c);
parents = c->parents;
nth = 0;
while (parents) {
......@@ -158,7 +176,7 @@ static void name_commits(struct commit_list *list,
struct strbuf newname = STRBUF_INIT;
parents = parents->next;
nth++;
if (p->util)
if (commit_to_name(p))
continue;
switch (n->generation) {
case 0:
......@@ -271,7 +289,7 @@ static void show_one_commit(struct commit *commit, int no_name)
{
struct strbuf pretty = STRBUF_INIT;
const char *pretty_str = "(unavailable)";
struct commit_name *name = commit->util;
struct commit_name *name = commit_to_name(commit);
if (commit->object.parsed) {
pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
......@@ -660,6 +678,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
OPT_END()
};
init_commit_name_slab(&name_slab);
git_config(git_show_branch_config, NULL);
/* If nothing is specified, try the default first */
......
#ifndef COMMIT_SLAB_HDR_H
#define COMMIT_SLAB_HDR_H
/* allocate ~512kB at once, allowing for malloc overhead */
#ifndef COMMIT_SLAB_SIZE
#define COMMIT_SLAB_SIZE (512*1024-32)
#endif
#define declare_commit_slab(slabname, elemtype) \
\
struct slabname { \
unsigned slab_size; \
unsigned stride; \
unsigned slab_count; \
elemtype **slab; \
}
/*
* 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 \
}
#define declare_commit_slab_prototypes(slabname, elemtype) \
\
void init_ ##slabname## _with_stride(struct slabname *s, unsigned stride); \
void init_ ##slabname(struct slabname *s); \
void clear_ ##slabname(struct slabname *s); \
elemtype *slabname## _at_peek(struct slabname *s, const struct commit *c, int add_if_missing); \
elemtype *slabname## _at(struct slabname *s, const struct commit *c); \
elemtype *slabname## _peek(struct slabname *s, const struct commit *c)
#define define_shared_commit_slab(slabname, elemtype) \
declare_commit_slab(slabname, elemtype); \
declare_commit_slab_prototypes(slabname, elemtype)
#endif /* COMMIT_SLAB_HDR_H */
#ifndef COMMIT_SLAB_IMPL_H
#define COMMIT_SLAB_IMPL_H
#define MAYBE_UNUSED __attribute__((__unused__))
#define implement_static_commit_slab(slabname, elemtype) \
implement_commit_slab(slabname, elemtype, static MAYBE_UNUSED)
#define implement_shared_commit_slab(slabname, elemtype) \
implement_commit_slab(slabname, elemtype, )
#define implement_commit_slab(slabname, elemtype, scope) \
\
static int stat_ ##slabname## realloc; \
\
scope 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; \
} \
\
scope void init_ ##slabname(struct slabname *s) \
{ \
init_ ##slabname## _with_stride(s, 1); \
} \
\
scope void clear_ ##slabname(struct slabname *s) \
{ \
unsigned int i; \
for (i = 0; i < s->slab_count; i++) \
free(s->slab[i]); \
s->slab_count = 0; \
FREE_AND_NULL(s->slab); \
} \
\
scope elemtype *slabname## _at_peek(struct slabname *s, \
const struct commit *c, \
int add_if_missing) \
{ \
unsigned 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) { \
unsigned 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]; \
} \
\
scope elemtype *slabname## _at(struct slabname *s, \
const struct commit *c) \
{ \
return slabname##_at_peek(s, c, 1); \
} \
\
scope 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
*
* implement_commit_slab(indegree, int, static);
*
* 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.
*/
#endif /* COMMIT_SLAB_IMPL_H */
#ifndef COMMIT_SLAB_H
#define COMMIT_SLAB_H
#include "commit-slab-decl.h"
#include "commit-slab-impl.h"
/*