#include "Calculator.hpp" #include #include #include #include "Operand.hpp" namespace { using Workspace = std::unordered_map; class Visitor; auto compute(Visitor& visitor, const Operation& binary_operation) noexcept -> std::optional; class Visitor { public: Visitor(std::span operations, Workspace& variables) noexcept : _operations{operations}, _variables{variables} {} auto operator()(const IntegerOperand& operand) noexcept -> std::optional { return operand.get(); } auto operator()(const VariableOperand& operand) noexcept -> std::optional { auto name = operand.get(); auto found_variable = _variables.get().find(name); if (found_variable != _variables.get().end()) return found_variable->second; auto found_operation = std::ranges::find(_operations, name, &Operation::variable); if (found_operation == _operations.end()) return std::nullopt; return compute(*this, *found_operation); } private: std::span _operations; std::reference_wrapper _variables; }; auto compute(Visitor& visitor, const Operation& operation) noexcept -> std::optional { auto lhs = std::visit(visitor, operation.lhs); if (!lhs.has_value()) return std::nullopt; auto rhs = std::visit(visitor, operation.rhs); if (!rhs.has_value()) return std::nullopt; return operation.binary_op(lhs.value(), rhs.value()); } } // namespace void Calculator::addOperation(Operation operation) noexcept { _operations.push_back(std::move(operation)); } void Calculator::addOperation(std::string result, Operand lhs, Operand rhs, Operator binary_operator) noexcept { addOperation(Operation{std::move(result), std::move(lhs), std::move(rhs), std::move(binary_operator)}); } void Calculator::undoOperation(std::size_t count) noexcept { count = std::min(_operations.size(), count); _operations.erase(_operations.end() - static_cast(count), _operations.end()); } auto Calculator::computeLast() noexcept -> std::pair> { Workspace workspace; Visitor visitor{_operations, workspace}; for (auto& operation : std::views::reverse(_operations)) { auto result = compute(visitor, operation); if (result.has_value()) return std::make_pair(operation.variable, result.value()); } return std::make_pair("na", std::nullopt); } auto Calculator::computeLastValue() noexcept -> double { auto [_, result] = computeLast(); return result.value_or(0.0); }