Files
calculator-challenge/Calculator.cpp
T
2024-03-15 00:53:14 +00:00

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);
}