Merge branch 'ew/svn-rev-db'
[git/trast.git] / object-refs.c
blob5345671569e9500ad31124dacf9525739687d9be
1 #include "cache.h"
2 #include "object.h"
3 #include "decorate.h"
5 int track_object_refs = 0;
7 static struct decoration ref_decorate;
9 struct object_refs *lookup_object_refs(struct object *base)
11 return lookup_decoration(&ref_decorate, base);
14 static void add_object_refs(struct object *obj, struct object_refs *refs)
16 if (add_decoration(&ref_decorate, obj, refs))
17 die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1));
20 struct object_refs *alloc_object_refs(unsigned count)
22 struct object_refs *refs;
23 size_t size = sizeof(*refs) + count*sizeof(struct object *);
25 refs = xcalloc(1, size);
26 refs->count = count;
27 return refs;
30 static int compare_object_pointers(const void *a, const void *b)
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;
42 void set_object_refs(struct object *obj, struct object_refs *refs)
44 unsigned int i, j;
46 /* Do not install empty list of references */
47 if (refs->count < 1) {
48 free(refs);
49 return;
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];
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);
66 for (i = 0; i < refs->count; i++)
67 refs->ref[i]->used = 1;
68 add_object_refs(obj, refs);
71 void mark_reachable(struct object *obj, unsigned int mask)
73 const struct object_refs *refs;
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);