feat: add challenge code
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
#include "Calculator.hpp"
|
||||
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user