LordAro
LordAro

Reputation: 1289

Pattern matching on C++ vector

I have several functions approximately of the form

struct ins;
enum class op_t {
    // ...
};

std::vector<ins> optimise_addone(std::vector<ins> prog)
{
    for (size_t i = 0; i < prog.size() - 1; i++) {
        auto &a = prog[i];
        auto &b = prog[i + 1];
        if (a.code == op_t::SET && a.op.which() == 1 && boost::get<uint16_t>(a.op) == 1 && b.code == op_t::ADD) {
            a = make_ins(op_t::INC);
            prog.erase(prog.begin() + i + 1);
            i += 1;
        }
    }
    return prog;
}

std::vector<ins> optimise_storeload(std::vector<ins> prog)
{
    for (size_t i = 0; i < prog.size() - 3; i++) {
        auto &a = prog[i];
        auto &b = prog[i + 1];
        auto &c = prog[i + 2];
        auto &d = prog[i + 3];
        if (a.code == op_t::SET && c.code == op_t::SET && b.code == op_t::STORE && d.code == op_t::LOAD && a.op == c.op) {
            a = make_ins(op_t::DUP);
            b = make_ins(op_t::SET, c.op);
            c = make_ins(op_t::STORE);
            prog.erase(prog.begin() + i + 3);
            i += 3;
        }
    }
    return prog;
}

They each take in a vector, find a patching subsection of it (of size N), and modify it in some arbitrary way

It seems to me that there should be a way of generalising this, using templates or function objects or similar, but I can't see it myself.

What's the best way to go about this?

Upvotes: 0

Views: 587

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93324

Higher-order functions solve your issue nicely. Below is a C++14 solution.

Here's how the final interface will look:

std::vector<int> v{1, 2, 3, 4, 5};
patchVector<2>(v, [](auto& a, auto& b){
    std::cout << a + b << " ";
});

Prints:

3 5 7 9


template <typename Vector, typename F, std::size_t... Is>
auto callWithSlice(std::size_t i, Vector& v, F&& f, std::index_sequence<Is...>)
{
    return f(v[i + Is]...);
}

template <std::size_t N, typename Vector, typename F>
auto patchVector(Vector v, F&& f)
{
    for(std::size_t i = 0; i < v.size() - N + 1; ++i)
    {
        callWithSlice(i, v, std::forward<F>(f), std::make_index_sequence<N>{});
    }
}

live wandbox example

Upvotes: 1

Related Questions