log -L: fix overlapping input ranges
[gitweb.git] / line-log.c
index 30edef4bec35a9cf0a36347d80e604b8eb80f125..85c7c249f4892bf95fd108cc6baaca2b6f9097aa 100644 (file)
@@ -56,16 +56,21 @@ static void range_set_move(struct range_set *dst, struct range_set *src)
 }
 
 /* tack on a _new_ range _at the end_ */
-static void range_set_append(struct range_set *rs, long a, long b)
+static void range_set_append_unsafe(struct range_set *rs, long a, long b)
 {
        assert(a <= b);
-       assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
        range_set_grow(rs, 1);
        rs->ranges[rs->nr].start = a;
        rs->ranges[rs->nr].end = b;
        rs->nr++;
 }
 
+static void range_set_append(struct range_set *rs, long a, long b)
+{
+       assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
+       range_set_append_unsafe(rs, a, b);
+}
+
 static int range_cmp(const void *_r, const void *_s)
 {
        const struct range *r = _r;
@@ -80,10 +85,27 @@ static int range_cmp(const void *_r, const void *_s)
 }
 
 /*
- * Helper: In-place pass of sorting and merging the ranges in the
- * range set, to re-establish the invariants after another operation
- *
- * NEEDSWORK currently not needed
+ * Check that the ranges are non-empty, sorted and non-overlapping
+ */
+static void range_set_check_invariants(struct range_set *rs)
+{
+       int i;
+
+       if (!rs)
+               return;
+
+       if (rs->nr)
+               assert(rs->ranges[0].start < rs->ranges[0].end);
+
+       for (i = 1; i < rs->nr; i++) {
+               assert(rs->ranges[i-1].end < rs->ranges[i].start);
+               assert(rs->ranges[i].start < rs->ranges[i].end);
+       }
+}
+
+/*
+ * In-place pass of sorting and merging the ranges in the range set,
+ * to establish the invariants when we get the ranges from the user
  */
 static void sort_and_merge_range_set(struct range_set *rs)
 {
@@ -103,6 +125,8 @@ static void sort_and_merge_range_set(struct range_set *rs)
        }
        assert(o <= rs->nr);
        rs->nr = o;
+
+       range_set_check_invariants(rs);
 }
 
 /*
@@ -259,7 +283,7 @@ static void line_log_data_insert(struct line_log_data **list,
        struct line_log_data *p = search_line_log_data(*list, spec->path, &ip);
 
        if (p) {
-               range_set_append(&p->ranges, begin, end);
+               range_set_append_unsafe(&p->ranges, begin, end);
                sort_and_merge_range_set(&p->ranges);
                free_filespec(spec);
                return;
@@ -687,8 +711,13 @@ static struct line_log_data *lookup_line_range(struct rev_info *revs,
                                               struct commit *commit)
 {
        struct line_log_data *ret = NULL;
+       struct line_log_data *d;
 
        ret = lookup_decoration(&revs->line_log_data, &commit->object);
+
+       for (d = ret; d; d = d->next)
+               range_set_check_invariants(&d->ranges);
+
        return ret;
 }