Add a generic "object decorator" interface, and make object refs use it
[git/git.git] / object-refs.c
CommitLineData
3e4339e6
LT
1#include "cache.h"
2#include "object.h"
a59b276e 3#include "decorate.h"
3e4339e6
LT
4
5int track_object_refs = 0;
6
a59b276e 7static struct decoration ref_decorate;
3e4339e6 8
a59b276e 9struct object_refs *lookup_object_refs(struct object *base)
3e4339e6 10{
a59b276e 11 return lookup_decoration(&ref_decorate, base);
3e4339e6
LT
12}
13
a59b276e 14static void add_object_refs(struct object *obj, struct object_refs *refs)
5fdc8499 15{
a59b276e
LT
16 if (add_decoration(&ref_decorate, obj, refs))
17 die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
3e4339e6
LT
18}
19
20struct object_refs *alloc_object_refs(unsigned count)
21{
22 struct object_refs *refs;
23 size_t size = sizeof(*refs) + count*sizeof(struct object *);
24
25 refs = xcalloc(1, size);
26 refs->count = count;
27 return refs;
28}
29
30static int compare_object_pointers(const void *a, const void *b)
31{
32 const struct object * const *pa = a;
33 const struct object * const *pb = b;
34 if (*pa == *pb)
35 return 0;
36 else if (*pa < *pb)
37 return -1;
38 else
39 return 1;
40}
41
42void set_object_refs(struct object *obj, struct object_refs *refs)
43{
44 unsigned int i, j;
45
46 /* Do not install empty list of references */
47 if (refs->count < 1) {
48 free(refs);
49 return;
50 }
51
52 /* Sort the list and filter out duplicates */
53 qsort(refs->ref, refs->count, sizeof(refs->ref[0]),
54 compare_object_pointers);
55 for (i = j = 1; i < refs->count; i++) {
56 if (refs->ref[i] != refs->ref[i - 1])
57 refs->ref[j++] = refs->ref[i];
58 }
59 if (j < refs->count) {
60 /* Duplicates were found - reallocate list */
61 size_t size = sizeof(*refs) + j*sizeof(struct object *);
62 refs->count = j;
63 refs = xrealloc(refs, size);
64 }
65
66 for (i = 0; i < refs->count; i++)
67 refs->ref[i]->used = 1;
68 add_object_refs(obj, refs);
69}
70
71void mark_reachable(struct object *obj, unsigned int mask)
72{
73 const struct object_refs *refs;
74
75 if (!track_object_refs)
76 die("cannot do reachability with object refs turned off");
77 /* If we've been here already, don't bother */
78 if (obj->flags & mask)
79 return;
80 obj->flags |= mask;
81 refs = lookup_object_refs(obj);
82 if (refs) {
83 unsigned i;
84 for (i = 0; i < refs->count; i++)
85 mark_reachable(refs->ref[i], mask);
86 }
87}
88
89