Merge git://repo.or.cz/git-gui
[git] / object-refs.c
1 #include "cache.h"
2 #include "object.h"
3 #include "decorate.h"
4
5 int track_object_refs = 0;
6
7 static struct decoration ref_decorate;
8
9 struct object_refs *lookup_object_refs(struct object *base)
10 {
11         return lookup_decoration(&ref_decorate, base);
12 }
13
14 static void add_object_refs(struct object *obj, struct object_refs *refs)
15 {
16         if (add_decoration(&ref_decorate, obj, refs))
17                 die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
18 }
19
20 struct 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
30 static 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
42 void 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
71 void 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 }