|  | #include "cache.h" | 
|  | #include "object.h" | 
|  | #include "decorate.h" | 
|  |  | 
|  | int track_object_refs = 0; | 
|  |  | 
|  | static struct decoration ref_decorate; | 
|  |  | 
|  | struct object_refs *lookup_object_refs(struct object *base) | 
|  | { | 
|  | return lookup_decoration(&ref_decorate, base); | 
|  | } | 
|  |  | 
|  | static void add_object_refs(struct object *obj, struct object_refs *refs) | 
|  | { | 
|  | if (add_decoration(&ref_decorate, obj, refs)) | 
|  | die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1)); | 
|  | } | 
|  |  | 
|  | struct object_refs *alloc_object_refs(unsigned count) | 
|  | { | 
|  | struct object_refs *refs; | 
|  | size_t size = sizeof(*refs) + count*sizeof(struct object *); | 
|  |  | 
|  | refs = xcalloc(1, size); | 
|  | refs->count = count; | 
|  | return refs; | 
|  | } | 
|  |  | 
|  | static int compare_object_pointers(const void *a, const void *b) | 
|  | { | 
|  | const struct object * const *pa = a; | 
|  | const struct object * const *pb = b; | 
|  | if (*pa == *pb) | 
|  | return 0; | 
|  | else if (*pa < *pb) | 
|  | return -1; | 
|  | else | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void set_object_refs(struct object *obj, struct object_refs *refs) | 
|  | { | 
|  | unsigned int i, j; | 
|  |  | 
|  | /* Do not install empty list of references */ | 
|  | if (refs->count < 1) { | 
|  | free(refs); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Sort the list and filter out duplicates */ | 
|  | qsort(refs->ref, refs->count, sizeof(refs->ref[0]), | 
|  | compare_object_pointers); | 
|  | for (i = j = 1; i < refs->count; i++) { | 
|  | if (refs->ref[i] != refs->ref[i - 1]) | 
|  | refs->ref[j++] = refs->ref[i]; | 
|  | } | 
|  | if (j < refs->count) { | 
|  | /* Duplicates were found - reallocate list */ | 
|  | size_t size = sizeof(*refs) + j*sizeof(struct object *); | 
|  | refs->count = j; | 
|  | refs = xrealloc(refs, size); | 
|  | } | 
|  |  | 
|  | for (i = 0; i < refs->count; i++) | 
|  | refs->ref[i]->used = 1; | 
|  | add_object_refs(obj, refs); | 
|  | } | 
|  |  | 
|  | void mark_reachable(struct object *obj, unsigned int mask) | 
|  | { | 
|  | const struct object_refs *refs; | 
|  |  | 
|  | if (!track_object_refs) | 
|  | die("cannot do reachability with object refs turned off"); | 
|  | /* If we've been here already, don't bother */ | 
|  | if (obj->flags & mask) | 
|  | return; | 
|  | obj->flags |= mask; | 
|  | refs = lookup_object_refs(obj); | 
|  | if (refs) { | 
|  | unsigned i; | 
|  | for (i = 0; i < refs->count; i++) | 
|  | mark_reachable(refs->ref[i], mask); | 
|  | } | 
|  | } |