C++: A pipeline of number filters

Build a small plug-in system: the program runs filters without knowing what any of them does.

What to build

A pipeline of filters that each change a number, built from an abstract Filter class.

Requirements

  • add k adds k, mul k multiplies by k, abs removes the sign, and clamp lo hi limits the number to that range.
  • Store the filters in a vector<Filter*>, and apply them in the order given.
  • Delete every filter at the end.

Input

The first line has f, then f lines with one filter each. Next comes q, and then a line with q numbers.

Output

One line per number: the result after all the filters.

Constraints

0 ≤ f ≤ 20, 1 ≤ q ≤ 100, and every value stays from -1000000 to 1000000.

Example

Input:

3
add 3
mul 2
clamp 0 10
3
1 4 -9

Output:

8
10
0

Why it works

Each filter only has to know its own rule, and the pipeline only has to know the interface. That separation is what lets new filters be added without touching the loop that runs them.

Examples

Example 1 · Input
3
add 3
mul 2
clamp 0 10
3
1 4 -9
Expected output
8
10
0
Example 2 · Input
1
abs
3
-5 0 7
Expected output
5
0
7

Hints

Hint 1

Make `Filter` an interface with `virtual int apply(int x) const = 0;`.

Hint 2

Write one class per kind of filter, store them as `Filter*` in a vector in the order given, and pass each number through all of them.

Hint 3

`clamp lo hi` gives `lo` for numbers below `lo` and `hi` for numbers above `hi`.

Solution

Show one correct solution (try it yourself first)
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Filter {
public:
    virtual ~Filter() {}
    virtual int apply(int x) const = 0;
};

class Add : public Filter {
    int k;
public:
    Add(int k) : k(k) {}
    int apply(int x) const override { return x + k; }
};

class Mul : public Filter {
    int k;
public:
    Mul(int k) : k(k) {}
    int apply(int x) const override { return x * k; }
};

class Abs : public Filter {
public:
    int apply(int x) const override { return x < 0 ? -x : x; }
};

class Clamp : public Filter {
    int lo, hi;
public:
    Clamp(int lo, int hi) : lo(lo), hi(hi) {}
    int apply(int x) const override {
        if (x < lo) return lo;
        if (x > hi) return hi;
        return x;
    }
};

int main() {
    int f;
    cin >> f;
    vector<Filter*> filters;
    for (int i = 0; i < f; i++) {
        string kind;
        cin >> kind;
        if (kind == "add" || kind == "mul") {
            int k;
            cin >> k;
            if (kind == "add") filters.push_back(new Add(k));
            else filters.push_back(new Mul(k));
        } else if (kind == "abs") {
            filters.push_back(new Abs());
        } else {
            int lo, hi;
            cin >> lo >> hi;
            filters.push_back(new Clamp(lo, hi));
        }
    }
    int q;
    cin >> q;
    for (int i = 0; i < q; i++) {
        int x;
        cin >> x;
        for (Filter* flt : filters) x = flt->apply(x);
        cout << x << endl;
    }
    for (Filter* flt : filters) delete flt;
    return 0;
}

Lesson: Abstract classes and interfaces →