Skip to content

Instantly share code, notes, and snippets.

@mpusz
Created December 14, 2012 11:43

Revisions

  1. mpusz revised this gist Dec 15, 2012. 1 changed file with 27 additions and 22 deletions.
    49 changes: 27 additions & 22 deletions spreadsheetInterpreter.cpp
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,6 @@
    #include <array>
    #include <iostream>
    #include <cassert>
    #include <boost/noncopyable.hpp>


    // -------------------- TOOLS ---------------------
    @@ -18,6 +17,12 @@ inline std::unique_ptr<T> make_unique(Args&&... args)
    return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
    }

    class CNonCopyable {
    public:
    CNonCopyable() = default;
    CNonCopyable(const CNonCopyable &) = delete;
    CNonCopyable &operator=(const CNonCopyable &) = delete;
    };


    // -------------------- FRAMEWORK ---------------------
    @@ -34,16 +39,16 @@ namespace spreadsheet {
    {
    _cells.at(row).at(col) = std::move(expr);
    }

    const CExpression<T> &Expression(std::size_t row, std::size_t col) const
    {
    auto &cell = _cells.at(row).at(col);
    if(!cell)
    throw std::runtime_error("No expression in cell(row: " + std::to_string(row) + ", " + std::to_string(col) + ")");
    return *cell;
    }

    T Value(std::size_t row, std::size_t col) const
    T operator()(std::size_t row, std::size_t col) const
    {
    return Expression(row, col).Value();
    }
    @@ -52,7 +57,7 @@ namespace spreadsheet {


    template<typename T>
    class CExpression : boost::noncopyable {
    class CExpression : CNonCopyable {
    public:
    virtual ~CExpression() = default;
    virtual T Value() const = 0;
    @@ -76,15 +81,15 @@ namespace spreadsheet {
    public:
    CExpressionBinary(std::unique_ptr<CExpression<T> > left, std::unique_ptr<CExpression<T> > right):
    _left(move(left)), _right(move(right)) {}
    T Value() const override { return EXPR()(_left->Value(), _right->Value()); }
    T Value() const override { return EXPR<T>()(_left->Value(), _right->Value()); }
    };

    template<typename T> using CExpressionAdd = CExpressionBinary<T, std::plus>;
    template<typename T> using CExpressionSubtract = CExpressionBinary<T, std::minus>;
    template<typename T> using CExpressionMultiply = CExpressionBinary<T, std::multiplies>;
    template<typename T> using CExpressionDivide = CExpressionBinary<T, std::divides>;


    template<typename T, std::size_t ROWS, std::size_t COLS>
    class CExpressionCell : public CExpression<T> {
    const CSpreadsheet<T, ROWS, COLS> &_spreadsheet;
    @@ -93,7 +98,7 @@ namespace spreadsheet {
    public:
    CExpressionCell(const CSpreadsheet<T, ROWS, COLS> &spreadsheet, std::size_t row, std::size_t col):
    _spreadsheet(spreadsheet), _row(row), _col(col) {}
    T Value() const override { return _spreadsheet.Value(_row, _col); }
    T Value() const override { return _spreadsheet(_row, _col); }
    };

    }
    @@ -118,31 +123,31 @@ int main()
    {
    try {
    CSpreadsheet sheet;
    // sheet.Value(ROWS, COLS); // should throw
    // sheet.Value(1, 1); // should throw

    // sheet(ROWS, COLS); // should throw
    // sheet(1, 1); // should throw
    sheet.Expression(0, 0, make_unique<CExpressionConstant>(5.0));
    assert(sheet.Value(0, 0) == 5);

    assert(sheet(0, 0) == 5);
    sheet.Expression(0, 1, make_unique<CExpressionAdd>(make_unique<CExpressionConstant>(10.0),
    make_unique<CExpressionCell>(sheet, 0, 0)));
    assert(sheet.Value(0, 1) == 15);
    assert(sheet(0, 1) == 15);

    sheet.Expression(0, 2, make_unique<CExpressionDivide>(make_unique<CExpressionCell>(sheet, 0, 1),
    make_unique<CExpressionCell>(sheet, 0, 0)));
    assert(sheet.Value(0, 2) == 3);

    assert(sheet(0, 2) == 3);
    // override last cell and set an expression for not filled one
    sheet.Expression(0, 2, make_unique<CExpressionCell>(sheet, 0, 3));
    // sheet.Value(0, 2); // should throw
    // sheet(0, 2); // should throw

    sheet.Expression(0, 3, make_unique<CExpressionMultiply>(make_unique<CExpressionConstant>(2.0),
    make_unique<CExpressionSubtract>(make_unique<CExpressionCell>(sheet, 0, 1),
    make_unique<CExpressionCell>(sheet, 0, 0))));
    assert(sheet.Value(0, 3) == 20);

    assert(sheet(0, 3) == 20);
    // check now
    assert(sheet.Value(0, 2) == sheet.Value(0, 3));
    assert(sheet(0, 2) == sheet(0, 3));
    }
    catch(const std::exception &ex) {
    std::cerr << "ERROR: " << ex.what() << "\n";
  2. mpusz renamed this gist Dec 15, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. mpusz created this gist Dec 14, 2012.
    150 changes: 150 additions & 0 deletions spreadsheet.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,150 @@
    //
    // author: Mateusz Pusz
    //

    #include <functional>
    #include <memory>
    #include <array>
    #include <iostream>
    #include <cassert>
    #include <boost/noncopyable.hpp>


    // -------------------- TOOLS ---------------------

    template<typename T, typename ...Args>
    inline std::unique_ptr<T> make_unique(Args&&... args)
    {
    return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
    }



    // -------------------- FRAMEWORK ---------------------

    namespace spreadsheet {

    template<typename T> class CExpression;

    template<typename T, std::size_t ROWS, std::size_t COLS>
    class CSpreadsheet {
    std::array<std::array<std::unique_ptr<CExpression<T> >, COLS>, ROWS> _cells;
    public:
    void Expression(std::size_t row, std::size_t col, std::unique_ptr<CExpression<T> > expr)
    {
    _cells.at(row).at(col) = std::move(expr);
    }

    const CExpression<T> &Expression(std::size_t row, std::size_t col) const
    {
    auto &cell = _cells.at(row).at(col);
    if(!cell)
    throw std::runtime_error("No expression in cell(row: " + std::to_string(row) + ", " + std::to_string(col) + ")");
    return *cell;
    }

    T Value(std::size_t row, std::size_t col) const
    {
    return Expression(row, col).Value();
    }
    };



    template<typename T>
    class CExpression : boost::noncopyable {
    public:
    virtual ~CExpression() = default;
    virtual T Value() const = 0;
    };


    template<typename T>
    class CExpressionConstant : public CExpression<T> {
    T _value;
    public:
    CExpressionConstant(T value): _value(std::move(value)) {}
    T Value() const override { return _value; }
    };


    // note: template template used here :-)
    template<typename T, template<class> class EXPR>
    class CExpressionBinary : public CExpression<T> {
    std::unique_ptr<CExpression<T> > _left;
    std::unique_ptr<CExpression<T> > _right;
    public:
    CExpressionBinary(std::unique_ptr<CExpression<T> > left, std::unique_ptr<CExpression<T> > right):
    _left(move(left)), _right(move(right)) {}
    T Value() const override { return EXPR()(_left->Value(), _right->Value()); }
    };

    template<typename T> using CExpressionAdd = CExpressionBinary<T, std::plus>;
    template<typename T> using CExpressionSubtract = CExpressionBinary<T, std::minus>;
    template<typename T> using CExpressionMultiply = CExpressionBinary<T, std::multiplies>;
    template<typename T> using CExpressionDivide = CExpressionBinary<T, std::divides>;


    template<typename T, std::size_t ROWS, std::size_t COLS>
    class CExpressionCell : public CExpression<T> {
    const CSpreadsheet<T, ROWS, COLS> &_spreadsheet;
    const std::size_t _row;
    const std::size_t _col;
    public:
    CExpressionCell(const CSpreadsheet<T, ROWS, COLS> &spreadsheet, std::size_t row, std::size_t col):
    _spreadsheet(spreadsheet), _row(row), _col(col) {}
    T Value() const override { return _spreadsheet.Value(_row, _col); }
    };

    }


    // -------------------- USAGE ---------------------

    using Value = double;
    constexpr std::size_t ROWS = 10;
    constexpr std::size_t COLS = 10;

    using CSpreadsheet = spreadsheet::CSpreadsheet<Value, ROWS, COLS>;
    using CExpressionConstant = spreadsheet::CExpressionConstant<Value>;
    using CExpressionAdd = spreadsheet::CExpressionAdd<Value>;
    using CExpressionSubtract = spreadsheet::CExpressionSubtract<Value>;
    using CExpressionMultiply = spreadsheet::CExpressionMultiply<Value>;
    using CExpressionDivide = spreadsheet::CExpressionDivide<Value>;
    using CExpressionCell = spreadsheet::CExpressionCell<Value, ROWS, COLS>;


    int main()
    {
    try {
    CSpreadsheet sheet;
    // sheet.Value(ROWS, COLS); // should throw
    // sheet.Value(1, 1); // should throw

    sheet.Expression(0, 0, make_unique<CExpressionConstant>(5.0));
    assert(sheet.Value(0, 0) == 5);

    sheet.Expression(0, 1, make_unique<CExpressionAdd>(make_unique<CExpressionConstant>(10.0),
    make_unique<CExpressionCell>(sheet, 0, 0)));
    assert(sheet.Value(0, 1) == 15);

    sheet.Expression(0, 2, make_unique<CExpressionDivide>(make_unique<CExpressionCell>(sheet, 0, 1),
    make_unique<CExpressionCell>(sheet, 0, 0)));
    assert(sheet.Value(0, 2) == 3);

    // override last cell and set an expression for not filled one
    sheet.Expression(0, 2, make_unique<CExpressionCell>(sheet, 0, 3));
    // sheet.Value(0, 2); // should throw

    sheet.Expression(0, 3, make_unique<CExpressionMultiply>(make_unique<CExpressionConstant>(2.0),
    make_unique<CExpressionSubtract>(make_unique<CExpressionCell>(sheet, 0, 1),
    make_unique<CExpressionCell>(sheet, 0, 0))));
    assert(sheet.Value(0, 3) == 20);

    // check now
    assert(sheet.Value(0, 2) == sheet.Value(0, 3));
    }
    catch(const std::exception &ex) {
    std::cerr << "ERROR: " << ex.what() << "\n";
    }
    }