87 lines
2.6 KiB
C++
87 lines
2.6 KiB
C++
#include "Calculator.hpp"
|
|
|
|
#include <cstdint>
|
|
#include <ranges>
|
|
#include <unordered_map>
|
|
|
|
#include "Operand.hpp"
|
|
|
|
namespace {
|
|
using Workspace = std::unordered_map<std::string, double>;
|
|
|
|
class Visitor;
|
|
|
|
auto compute(Visitor& visitor, const Operation& binary_operation) noexcept -> std::optional<double>;
|
|
|
|
class Visitor
|
|
{
|
|
public:
|
|
Visitor(std::span<const Operation> operations, Workspace& variables) noexcept :
|
|
_operations{operations}, _variables{variables}
|
|
{}
|
|
|
|
auto operator()(const IntegerOperand& operand) noexcept -> std::optional<double> { return operand.get(); }
|
|
|
|
auto operator()(const VariableOperand& operand) noexcept -> std::optional<double>
|
|
{
|
|
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<const Operation> _operations;
|
|
std::reference_wrapper<Workspace> _variables;
|
|
};
|
|
|
|
auto compute(Visitor& visitor, const Operation& operation) noexcept -> std::optional<double>
|
|
{
|
|
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<std::int64_t>(count), _operations.end());
|
|
}
|
|
|
|
auto Calculator::computeLast() noexcept -> std::pair<std::string, std::optional<double>>
|
|
{
|
|
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);
|
|
}
|