| #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); |
| } |
| } |
| |
| |