]> git.ipfire.org Git - thirdparty/git.git/blobdiff - diff.c
OFFSETOF_VAR macro to simplify hashmap iterators
[thirdparty/git.git] / diff.c
diff --git a/diff.c b/diff.c
index 1ccd96bbfde23a0f6d42104e81f78e0953c1bc93..051de9832d3396d8c566e7bd08c5a04f4581e1ff 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -933,16 +933,18 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
 }
 
 static int moved_entry_cmp(const void *hashmap_cmp_fn_data,
-                          const void *entry,
-                          const void *entry_or_key,
+                          const struct hashmap_entry *eptr,
+                          const struct hashmap_entry *entry_or_key,
                           const void *keydata)
 {
        const struct diff_options *diffopt = hashmap_cmp_fn_data;
-       const struct moved_entry *a = entry;
-       const struct moved_entry *b = entry_or_key;
+       const struct moved_entry *a, *b;
        unsigned flags = diffopt->color_moved_ws_handling
                         & XDF_WHITESPACE_FLAGS;
 
+       a = container_of(eptr, const struct moved_entry, ent);
+       b = container_of(entry_or_key, const struct moved_entry, ent);
+
        if (diffopt->color_moved_ws_handling &
            COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE)
                /*
@@ -964,8 +966,9 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
        struct moved_entry *ret = xmalloc(sizeof(*ret));
        struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
        unsigned flags = o->color_moved_ws_handling & XDF_WHITESPACE_FLAGS;
+       unsigned int hash = xdiff_hash_string(l->line, l->len, flags);
 
-       ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
+       hashmap_entry_init(&ret->ent, hash);
        ret->es = l;
        ret->next_line = NULL;
 
@@ -1002,7 +1005,7 @@ static void add_lines_to_move_detection(struct diff_options *o,
                if (prev_line && prev_line->es->s == o->emitted_symbols->buf[n].s)
                        prev_line->next_line = key;
 
-               hashmap_add(hm, key);
+               hashmap_add(hm, &key->ent);
                prev_line = key;
        }
 }
@@ -1018,7 +1021,7 @@ static void pmb_advance_or_null(struct diff_options *o,
                struct moved_entry *prev = pmb[i].match;
                struct moved_entry *cur = (prev && prev->next_line) ?
                                prev->next_line : NULL;
-               if (cur && !hm->cmpfn(o, cur, match, NULL)) {
+               if (cur && !hm->cmpfn(o, &cur->ent, &match->ent, NULL)) {
                        pmb[i].match = cur;
                } else {
                        pmb[i].match = NULL;
@@ -1035,7 +1038,7 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,
        int i;
        char *got_match = xcalloc(1, pmb_nr);
 
-       for (; match; match = hashmap_get_next(hm, match)) {
+       hashmap_for_each_entry_from(hm, match, ent) {
                for (i = 0; i < pmb_nr; i++) {
                        struct moved_entry *prev = pmb[i].match;
                        struct moved_entry *cur = (prev && prev->next_line) ?
@@ -1143,13 +1146,15 @@ static void mark_color_as_moved(struct diff_options *o,
                case DIFF_SYMBOL_PLUS:
                        hm = del_lines;
                        key = prepare_entry(o, n);
-                       match = hashmap_get(hm, key, NULL);
+                       match = hashmap_get_entry(hm, key, NULL,
+                                               struct moved_entry, ent);
                        free(key);
                        break;
                case DIFF_SYMBOL_MINUS:
                        hm = add_lines;
                        key = prepare_entry(o, n);
-                       match = hashmap_get(hm, key, NULL);
+                       match = hashmap_get_entry(hm, key, NULL,
+                                               struct moved_entry, ent);
                        free(key);
                        break;
                default:
@@ -1188,7 +1193,7 @@ static void mark_color_as_moved(struct diff_options *o,
                         * The current line is the start of a new block.
                         * Setup the set of potential blocks.
                         */
-                       for (; match; match = hashmap_get_next(hm, match)) {
+                       hashmap_for_each_entry_from(hm, match, ent) {
                                ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
                                if (o->color_moved_ws_handling &
                                    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
@@ -1673,7 +1678,10 @@ static void emit_hunk_header(struct emit_callback *ecbdata,
        if (ecbdata->opt->flags.dual_color_diffed_diffs)
                strbuf_addstr(&msgbuf, reverse);
        strbuf_addstr(&msgbuf, frag);
-       strbuf_add(&msgbuf, line, ep - line);
+       if (ecbdata->opt->flags.suppress_hunk_header_line_count)
+               strbuf_add(&msgbuf, atat, sizeof(atat));
+       else
+               strbuf_add(&msgbuf, line, ep - line);
        strbuf_addstr(&msgbuf, reset);
 
        /*
@@ -5992,6 +6000,22 @@ static int remove_space(char *line, int len)
        return dst - line;
 }
 
+void flush_one_hunk(struct object_id *result, git_SHA_CTX *ctx)
+{
+       unsigned char hash[GIT_MAX_RAWSZ];
+       unsigned short carry = 0;
+       int i;
+
+       git_SHA1_Final(hash, ctx);
+       git_SHA1_Init(ctx);
+       /* 20-byte sum, with carry */
+       for (i = 0; i < GIT_SHA1_RAWSZ; ++i) {
+               carry += result->hash[i] + hash[i];
+               result->hash[i] = carry;
+               carry >>= 8;
+       }
+}
+
 static void patch_id_consume(void *priv, char *line, unsigned long len)
 {
        struct patch_id_t *data = priv;
@@ -6016,8 +6040,8 @@ static void patch_id_add_mode(git_SHA_CTX *ctx, unsigned mode)
        git_SHA1_Update(ctx, buf, len);
 }
 
-/* returns 0 upon success, and writes result into sha1 */
-static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
+/* returns 0 upon success, and writes result into oid */
+static int diff_get_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only, int stable)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
        int i;
@@ -6027,6 +6051,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
        git_SHA1_Init(&ctx);
        memset(&data, 0, sizeof(struct patch_id_t));
        data.ctx = &ctx;
+       oidclr(oid);
 
        for (i = 0; i < q->nr; i++) {
                xpparam_t xpp;
@@ -6102,17 +6127,22 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid
                                  patch_id_consume, &data, &xpp, &xecfg))
                        return error("unable to generate patch-id diff for %s",
                                     p->one->path);
+
+               if (stable)
+                       flush_one_hunk(oid, &ctx);
        }
 
-       git_SHA1_Final(oid->hash, &ctx);
+       if (!stable)
+               git_SHA1_Final(oid->hash, &ctx);
+
        return 0;
 }
 
-int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only)
+int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int diff_header_only, int stable)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
        int i;
-       int result = diff_get_patch_id(options, oid, diff_header_only);
+       int result = diff_get_patch_id(options, oid, diff_header_only, stable);
 
        for (i = 0; i < q->nr; i++)
                diff_free_filepair(q->queue[i]);
@@ -6205,8 +6235,10 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
                        if (o->color_moved == COLOR_MOVED_ZEBRA_DIM)
                                dim_moved_lines(o);
 
-                       hashmap_free(&add_lines, 1);
-                       hashmap_free(&del_lines, 1);
+                       hashmap_free_entries(&add_lines, struct moved_entry,
+                                               ent);
+                       hashmap_free_entries(&del_lines, struct moved_entry,
+                                               ent);
                }
 
                for (i = 0; i < esm.nr; i++)