object-refs.con commit checkout: notice when the switched branch is behind or forked (79a1e6b)
   1#include "cache.h"
   2#include "object.h"
   3#include "decorate.h"
   4
   5int track_object_refs = 0;
   6
   7static struct decoration ref_decorate;
   8
   9struct object_refs *lookup_object_refs(struct object *base)
  10{
  11        return lookup_decoration(&ref_decorate, base);
  12}
  13
  14static 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
  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}