apply: refactor code to drop `line_allocated`

The `struct image` has two members `line` and `line_allocated`. The former member is the one that should be used throughout the code, whereas the latter one is used to track whether the lines have been allocated or not. In practice, the array of lines is always allocated. The reason why we have `line_allocated` is that `remove_first_line()` will advance the array pointer to drop the first entry, and thus it points into the array instead of to the array header. Refactor the function to use memmove(3P) instead, which allows us to get rid of this double bookkeeping. This is less efficient, but I doubt that this matters much in practice. If this judgement call is found to be wrong at a later point in time we can likely refactor the surrounding loop such that we first calculate the number of leading context lines to remove and then remove them in a single call to memmove(3P). Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Sep 17, 2024 at 12:08 UTC 6eff8b8f406f53ad3301263300016813f1d73c63
1 file changed +14 -19
apply.c
+14 -19
@@ -281,7 +281,6 @@ struct image {
281 size_t len;
282 size_t nr;
283 size_t alloc;
284 - struct line *line_allocated;
284 struct line *line;
285 };
286 #define IMAGE_INIT { 0 }
@@ -295,7 +294,7 @@ static void image_init(struct image *image)
294 static void image_clear(struct image *image)
295 {
296 free(image->buf);
298 - free(image->line_allocated);
297 + free(image->line);
298 image_init(image);
299 }
300
@@ -313,10 +312,10 @@ static uint32_t hash_line(const char *cp, size_t len)
312
313 static void image_add_line(struct image *img, const char *bol, size_t len, unsigned flag)
314 {
316 - ALLOC_GROW(img->line_allocated, img->nr + 1, img->alloc);
317 - img->line_allocated[img->nr].len = len;
318 - img->line_allocated[img->nr].hash = hash_line(bol, len);
319 - img->line_allocated[img->nr].flag = flag;
315 + ALLOC_GROW(img->line, img->nr + 1, img->alloc);
316 + img->line[img->nr].len = len;
317 + img->line[img->nr].hash = hash_line(bol, len);
318 + img->line[img->nr].flag = flag;
319 img->nr++;
320 }
321
@@ -348,15 +347,15 @@ static void image_prepare(struct image *image, char *buf, size_t len,
347 image_add_line(image, cp, next - cp, 0);
348 cp = next;
349 }
351 - image->line = image->line_allocated;
350 }
351
352 static void image_remove_first_line(struct image *img)
353 {
354 img->buf += img->line[0].len;
355 img->len -= img->line[0].len;
358 - img->line++;
356 img->nr--;
357 + if (img->nr)
358 + MOVE_ARRAY(img->line, img->line + 1, img->nr);
359 }
360
361 static void image_remove_last_line(struct image *img)
@@ -2335,7 +2334,7 @@ static void update_pre_post_images(struct image *preimage,
2334 : fixed_preimage.nr <= preimage->nr);
2335 for (i = 0; i < fixed_preimage.nr; i++)
2336 fixed_preimage.line[i].flag = preimage->line[i].flag;
2338 - free(preimage->line_allocated);
2337 + free(preimage->line);
2338 *preimage = fixed_preimage;
2339
2340 /*
@@ -2879,14 +2878,12 @@ static void update_image(struct apply_state *state,
2878
2879 /* Adjust the line table */
2880 nr = img->nr + postimage->nr - preimage_limit;
2882 - if (preimage_limit < postimage->nr) {
2881 + if (preimage_limit < postimage->nr)
2882 /*
2883 * NOTE: this knows that we never call image_remove_first_line()
2884 * on anything other than pre/post image.
2885 */
2886 REALLOC_ARRAY(img->line, nr);
2888 - img->line_allocated = img->line;
2889 - }
2887 if (preimage_limit != postimage->nr)
2888 MOVE_ARRAY(img->line + applied_pos + postimage->nr,
2889 img->line + applied_pos + preimage_limit,
@@ -3027,8 +3024,8 @@ static int apply_one_fragment(struct apply_state *state,
3024 newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
3025 old--;
3026 strbuf_setlen(&newlines, newlines.len - 1);
3030 - preimage.line_allocated[preimage.nr - 1].len--;
3031 - postimage.line_allocated[postimage.nr - 1].len--;
3027 + preimage.line[preimage.nr - 1].len--;
3028 + postimage.line[postimage.nr - 1].len--;
3029 }
3030
3031 leading = frag->leading;
@@ -3062,8 +3059,6 @@ static int apply_one_fragment(struct apply_state *state,
3059 preimage.len = old - oldlines;
3060 postimage.buf = newlines.buf;
3061 postimage.len = newlines.len;
3065 - preimage.line = preimage.line_allocated;
3066 - postimage.line = postimage.line_allocated;
3062
3063 for (;;) {
3064
@@ -3151,8 +3146,8 @@ static int apply_one_fragment(struct apply_state *state,
3146 out:
3147 free(oldlines);
3148 strbuf_release(&newlines);
3154 - free(preimage.line_allocated);
3155 - free(postimage.line_allocated);
3149 + free(preimage.line);
3150 + free(postimage.line);
3151
3152 return (applied_pos < 0);
3153 }
@@ -3752,7 +3747,7 @@ static int apply_data(struct apply_state *state, struct patch *patch,
3747 patch->result = image.buf;
3748 patch->resultsize = image.len;
3749 add_to_fn_table(state, patch);
3755 - free(image.line_allocated);
3750 + free(image.line);
3751
3752 if (0 < patch->is_delete && patch->resultsize)
3753 return error(_("removal patch leaves file contents"));