patch-ids.con commit t7508: add test for "git status" refreshing the index (4c926b3)
   1#include "cache.h"
   2#include "diff.h"
   3#include "commit.h"
   4#include "sha1-lookup.h"
   5#include "patch-ids.h"
   6
   7static int commit_patch_id(struct commit *commit, struct diff_options *options,
   8                    unsigned char *sha1)
   9{
  10        if (commit->parents)
  11                diff_tree_sha1(commit->parents->item->object.sha1,
  12                               commit->object.sha1, "", options);
  13        else
  14                diff_root_tree_sha1(commit->object.sha1, "", options);
  15        diffcore_std(options);
  16        return diff_flush_patch_id(options, sha1);
  17}
  18
  19static const unsigned char *patch_id_access(size_t index, void *table)
  20{
  21        struct patch_id **id_table = table;
  22        return id_table[index]->patch_id;
  23}
  24
  25static int patch_pos(struct patch_id **table, int nr, const unsigned char *id)
  26{
  27        return sha1_pos(id, table, nr, patch_id_access);
  28}
  29
  30#define BUCKET_SIZE 190 /* 190 * 21 = 3990, with slop close enough to 4K */
  31struct patch_id_bucket {
  32        struct patch_id_bucket *next;
  33        int nr;
  34        struct patch_id bucket[BUCKET_SIZE];
  35};
  36
  37int init_patch_ids(struct patch_ids *ids)
  38{
  39        memset(ids, 0, sizeof(*ids));
  40        diff_setup(&ids->diffopts);
  41        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
  42        if (diff_setup_done(&ids->diffopts) < 0)
  43                return error("diff_setup_done failed");
  44        return 0;
  45}
  46
  47int free_patch_ids(struct patch_ids *ids)
  48{
  49        struct patch_id_bucket *next, *patches;
  50
  51        free(ids->table);
  52        for (patches = ids->patches; patches; patches = next) {
  53                next = patches->next;
  54                free(patches);
  55        }
  56        return 0;
  57}
  58
  59static struct patch_id *add_commit(struct commit *commit,
  60                                   struct patch_ids *ids,
  61                                   int no_add)
  62{
  63        struct patch_id_bucket *bucket;
  64        struct patch_id *ent;
  65        unsigned char sha1[20];
  66        int pos;
  67
  68        if (commit_patch_id(commit, &ids->diffopts, sha1))
  69                return NULL;
  70        pos = patch_pos(ids->table, ids->nr, sha1);
  71        if (0 <= pos)
  72                return ids->table[pos];
  73        if (no_add)
  74                return NULL;
  75
  76        pos = -1 - pos;
  77
  78        bucket = ids->patches;
  79        if (!bucket || (BUCKET_SIZE <= bucket->nr)) {
  80                bucket = xcalloc(1, sizeof(*bucket));
  81                bucket->next = ids->patches;
  82                ids->patches = bucket;
  83        }
  84        ent = &bucket->bucket[bucket->nr++];
  85        hashcpy(ent->patch_id, sha1);
  86
  87        if (ids->alloc <= ids->nr) {
  88                ids->alloc = alloc_nr(ids->nr);
  89                ids->table = xrealloc(ids->table, sizeof(ent) * ids->alloc);
  90        }
  91        if (pos < ids->nr)
  92                memmove(ids->table + pos + 1, ids->table + pos,
  93                        sizeof(ent) * (ids->nr - pos));
  94        ids->nr++;
  95        ids->table[pos] = ent;
  96        return ids->table[pos];
  97}
  98
  99struct patch_id *has_commit_patch_id(struct commit *commit,
 100                                     struct patch_ids *ids)
 101{
 102        return add_commit(commit, ids, 1);
 103}
 104
 105struct patch_id *add_commit_patch_id(struct commit *commit,
 106                                     struct patch_ids *ids)
 107{
 108        return add_commit(commit, ids, 0);
 109}