aboutsummaryrefslogtreecommitdiff
path: root/src/range_set.cpp
blob: fd0076191b1fcee34e917fd2adf2a0acc92e645b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "range_set.hpp"

AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node) {
    for (size_t i = 0; i < rs->src_range_list.length; i += 1) {
        RangeWithSrc *range_with_src = &rs->src_range_list.at(i);
        Range *range = &range_with_src->range;
        if ((bigint_cmp(first, &range->first) == CmpLT && bigint_cmp(last, &range->first) == CmpLT) ||
            (bigint_cmp(first, &range->last) == CmpGT && bigint_cmp(last, &range->last) == CmpGT))
        {
            // first...last is completely before/after `range`
        }
        else
        {
            return range_with_src->source_node;
        }
    }
    rs->src_range_list.append({{*first, *last}, source_node});

    return nullptr;

}

static int compare_rangeset(const void *a, const void *b) {
    const Range *r1 = &static_cast<const RangeWithSrc*>(a)->range;
    const Range *r2 = &static_cast<const RangeWithSrc*>(b)->range;
    // Assume no two ranges overlap
    switch (bigint_cmp(&r1->first, &r2->first)) {
        case CmpLT: return -1;
        case CmpGT: return  1;
        case CmpEQ: return  0;
    }
    zig_unreachable();
}

void rangeset_sort(RangeSet *rs) {
    if (rs->src_range_list.length > 1) {
        qsort(rs->src_range_list.items, rs->src_range_list.length,
              sizeof(RangeWithSrc), compare_rangeset);
    }
}

bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) {
    rangeset_sort(rs);

    const Range *first_range = &rs->src_range_list.at(0).range;
    if (bigint_cmp(&first_range->first, first) != CmpEQ)
        return false;

    const Range *last_range = &rs->src_range_list.last().range;
    if (bigint_cmp(&last_range->last, last) != CmpEQ)
        return false;

    BigInt one;
    bigint_init_unsigned(&one, 1);

    // Make sure there are no holes in the first...last range
    for (size_t i = 1; i < rs->src_range_list.length; i++) {
        const Range *range = &rs->src_range_list.at(i).range;
        const Range *prev_range = &rs->src_range_list.at(i - 1).range;

        assert(bigint_cmp(&prev_range->last, &range->first) == CmpLT);

        BigInt last_plus_one;
        bigint_add(&last_plus_one, &prev_range->last, &one);

        if (bigint_cmp(&last_plus_one, &range->first) != CmpEQ)
            return false;
    }

    return true;
}