Task: Range modifications


C++: #include <algorithm>
#include <iomanip>
#include <iostream>
#include <list>

struct range {
    range(int lo, int hi) : low(lo), high(hi) {}
    int low;
    int high;
};

std::ostream& operator<<(std::ostream& out, const range& r) {
    return out << r.low << '-' << r.high;
}

class ranges {
public:
    ranges() {}
    explicit ranges(std::initializer_list<range> init) : ranges_(init) {}
    void add(int n);
    void remove(int n);
    bool empty() const { return ranges_.empty(); }
private:
    friend std::ostream& operator<<(std::ostream& out, const ranges& r);
    std::list<range> ranges_;
};

void ranges::add(int n) {
    for (auto i = ranges_.begin(); i != ranges_.end(); ++i) {
        if (n + 1 < i->low) {
            ranges_.emplace(i, n, n);
            return;
        }
        if (n > i->high + 1)
            continue;
        if (n + 1 == i->low)
            i->low = n;
        else if (n == i->high + 1)
            i->high = n;
        else
            return;
        if (i != ranges_.begin()) {
            auto prev = std::prev(i);
            if (prev->high + 1 == i->low) {
                i->low = prev->low;
                ranges_.erase(prev);
            }
        }
        auto next = std::next(i);
        if (next != ranges_.end() && next->low - 1 == i->high) {
            i->high = next->high;
            ranges_.erase(next);
        }
        return;
    }
    ranges_.emplace_back(n, n);
}

void ranges::remove(int n) {
    for (auto i = ranges_.begin(); i != ranges_.end(); ++i) {
        if (n < i->low)
            return;
        if (n == i->low) {
            if (++i->low > i->high)
                ranges_.erase(i);
            return;
        }
        if (n == i->high) {
            if (--i->high < i->low)
                ranges_.erase(i);
            return;
        }
        if (n > i->low & n < i->high) {
            int low = i->low;
            i->low = n + 1;
            ranges_.emplace(i, low, n - 1);
            return;
        }
    }
}

std::ostream& operator<<(std::ostream& out, const ranges& r) {
    if (!r.empty()) {
        auto i = r.ranges_.begin();
        out << *i++;
        for (; i != r.ranges_.end(); ++i)
            out << ',' << *i;
    }
    return out;
}

void test_add(ranges& r, int n) {
    r.add(n);
    std::cout << "       add " << std::setw(2) << n << " => " << r << '\n';
}

void test_remove(ranges& r, int n) {
    r.remove(n);
    std::cout << "    remove " << std::setw(2) << n << " => " << r << '\n';
}

void test1() {
    ranges r;
    std::cout << "Start: \"" << r << "\"\n";
    test_add(r, 77);
    test_add(r, 79);
    test_add(r, 78);
    test_remove(r, 77);
    test_remove(r, 78);
    test_remove(r, 79);
}

void test2() {
    ranges r{{1,3}, {5,5}};
    std::cout << "Start: \"" << r << "\"\n";
    test_add(r, 1);
    test_remove(r, 4);
    test_add(r, 7);
    test_add(r, 8);
    test_add(r, 6);
    test_remove(r, 7);
}

void test3() {
    ranges r{{1,5}, {10,25}, {27,30}};
    std::cout << "Start: \"" << r << "\"\n";
    test_add(r, 26);
    test_add(r, 9);
    test_add(r, 7);
    test_remove(r, 26);
    test_remove(r, 9);
    test_remove(r, 7);
}

int main() {
    test1();
    std::cout << '\n';
    test2();
    std::cout << '\n';
    test3();
    return 0;
}



Go: package main

import (
    "fmt"
    "strings"
)

type rng struct{ from, to int }

type fn func(rngs *[]rng, n int)

func (r rng) String() string { return fmt.Sprintf("%d-%d", r.from, r.to) }

func rangesAdd(rngs []rng, n int) []rng {
    if len(rngs) == 0 {
        rngs = append(rngs, rng{n, n})
        return rngs
    }
    for i, r := range rngs {
        if n < r.from-1 {
            rngs = append(rngs, rng{})
            copy(rngs[i+1:], rngs[i:])
            rngs[i] = rng{n, n}
            return rngs
        } else if n == r.from-1 {
            rngs[i] = rng{n, r.to}
            return rngs
        } else if n <= r.to {
            return rngs
        } else if n == r.to+1 {
            rngs[i] = rng{r.from, n}
            if i < len(rngs)-1 && (n == rngs[i+1].from || n+1 == rngs[i+1].from) {
                rngs[i] = rng{r.from, rngs[i+1].to}
                copy(rngs[i+1:], rngs[i+2:])
                rngs[len(rngs)-1] = rng{}
                rngs = rngs[:len(rngs)-1]
            }
            return rngs
        } else if i == len(rngs)-1 {
            rngs = append(rngs, rng{n, n})
            return rngs
        }
    }
    return rngs
}

func rangesRemove(rngs []rng, n int) []rng {
    if len(rngs) == 0 {
        return rngs
    }
    for i, r := range rngs {
        if n <= r.from-1 {
            return rngs
        } else if n == r.from && n == r.to {
            copy(rngs[i:], rngs[i+1:])
            rngs[len(rngs)-1] = rng{}
            rngs = rngs[:len(rngs)-1]
            return rngs
        } else if n == r.from {
            rngs[i] = rng{n + 1, r.to}
            return rngs
        } else if n < r.to {
            rngs[i] = rng{r.from, n - 1}
            rngs = append(rngs, rng{})
            copy(rngs[i+2:], rngs[i+1:])
            rngs[i+1] = rng{n + 1, r.to}
            return rngs
        } else if n == r.to {
            rngs[i] = rng{r.from, n - 1}
            return rngs
        }
    }
    return rngs
}

func standard(rngs []rng) string {
    if len(rngs) == 0 {
        return ""
    }
    var sb strings.Builder
    for _, r := range rngs {
        sb.WriteString(fmt.Sprintf("%s,", r))
    }
    s := sb.String()
    return s[:len(s)-1]
}

func main() {
    const add = 0
    const remove = 1
    fns := []fn{
        func(prngs *[]rng, n int) {
            *prngs = rangesAdd(*prngs, n)
            fmt.Printf("       add %2d => %s\n", n, standard(*prngs))
        },
        func(prngs *[]rng, n int) {
            *prngs = rangesRemove(*prngs, n)
            fmt.Printf("    remove %2d => %s\n", n, standard(*prngs))
        },
    }

    var rngs []rng
    ops := [][2]int{{add, 77}, {add, 79}, {add, 78}, {remove, 77}, {remove, 78}, {remove, 79}}
    fmt.Printf("Start: %q\n", standard(rngs))
    for _, op := range ops {
        fns[op[0]](&rngs, op[1])
    }

    rngs = []rng{{1, 3}, {5, 5}}
    ops = [][2]int{{add, 1}, {remove, 4}, {add, 7}, {add, 8}, {add, 6}, {remove, 7}}
    fmt.Printf("\nStart: %q\n", standard(rngs))
    for _, op := range ops {
        fns[op[0]](&rngs, op[1])
    }

    rngs = []rng{{1, 5}, {10, 25}, {27, 30}}
    ops = [][2]int{{add, 26}, {add, 9}, {add, 7}, {remove, 26}, {remove, 9}, {remove, 7}}
    fmt.Printf("\nStart: %q\n", standard(rngs))
    for _, op := range ops {
        fns[op[0]](&rngs, op[1])
    }
}