CoriEngine
Loading...
Searching...
No Matches
Function.hpp
Go to the documentation of this file.
1#pragma once
2#include <exprtk.hpp>
3
4namespace Cori {
5 namespace Math {
9 template<typename T>
10 concept IsNumber = std::is_arithmetic_v<T>;
11
23 template<IsNumber NumericType, uint8_t ArgumentAmount>
24 class Function {
25 public:
27 m_Data = std::make_unique<Data>();
28 NumericType e = static_cast<NumericType>(std::numbers::e);
29 m_Data->m_SymbolTable.add_constant("e", e);
30 m_Data->m_SymbolTable.add_constants();
31 }
32
33 ~Function() = default;
34
35 Function(Function&& other) noexcept = default;
36 Function& operator=(Function&& other) noexcept = default;
37
38 Function(const Function&) = delete;
39 Function& operator=(const Function&) = delete;
40
46 void RegisterValues(const std::vector<std::string>& argNames) {
47 if (!m_ValuesRegistered) {
48 if (argNames.size() != ArgumentAmount) {
49 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Size of vector argNames should match the specified argument amount '{}'.", argNames.size(), ArgumentAmount);
50 return;
51 }
52
53 m_Data->m_ArgNames = argNames;
54
55 for (uint8_t i = 0; i < ArgumentAmount; ++i) {
56 m_Data->m_SymbolTable.add_variable(argNames[i], m_Data->m_ArgValues[i]);
57 }
58 m_ValuesRegistered = true;
59 }
60 }
61
68 bool AddConstant(const std::string& alias, const NumericType value) {
69 return m_Data->m_SymbolTable.add_constant(alias, value);
70 }
71
77 void AddAlias(const std::string& aliasName, const std::string& aliasExpression) {
78 auto aliasFunc = typename exprtk::function_compositor<NumericType>::function(aliasName);
79
80 for (const auto& argName : m_Data->m_ArgNames) {
81 aliasFunc.var(argName);
82 }
83
84 aliasFunc.expression(aliasExpression);
85
86 if (!m_Data->m_Compositor.add(aliasFunc)) {
87 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Failed to create alias '{}'", aliasExpression);
88 for (std::size_t i = 0; i < m_Data->m_Compositor.error_count(); ++i) {
89 exprtk::parser_error::type error = m_Data->m_Compositor.get_error(i);
91 }
92 m_Valid = false;
93 }
94 }
95
100 void Parse(const std::string& expression) {
101 if (!m_Valid) {
102 m_Data->m_Expression.register_symbol_table(m_Data->m_SymbolTable);
103
104 static exprtk::parser<double> parser;
105 if (parser.compile(expression, m_Data->m_Expression)) {
106 m_Valid = true;
107 } else {
108 m_Valid = false;
109 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Failed to parse main expression '{}'", expression);
110 for (std::size_t i = 0; i < parser.error_count(); ++i) {
111 exprtk::parser_error::type error = parser.get_error(i);
113 }
114 }
115 }
116 }
117
130 NumericType operator()(const IsNumber auto&... args) {
131 if (!m_Valid) {
132 CORI_CORE_WARN_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Calling an invalid math function that failed to parse, 1 returned.");
133 return 1;
134 }
135
136 if (!m_ValuesRegistered) {
137 CORI_CORE_WARN_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Calling an math function that doest have any values registered, you forgot to call RegisterValues, 1 returned.");
138 return 1;
139 }
140
141 if (sizeof...(args) != ArgumentAmount) {
142 CORI_CORE_ERROR_TAGGED({ Logger::Tags::Math::Self, Logger::Tags::Math::Function }, "Amount of arguments '{}' provided to the () operator should be the same as the specified argument amount '{}'.", sizeof...(args), ArgumentAmount);
143 return 1;
144 }
145
146 uint8_t index = 0;
147
148 ([&](const auto& arg) {
149 m_Data->m_ArgValues[index++] = static_cast<NumericType>(arg);
150 }(args), ...);
151
152 NumericType result = m_Data->m_Expression.value();
153 return result;
154 }
155
156 [[nodiscard]] bool Success() const {
157 return m_Valid;
158 }
159
160 private:
161 struct Data {
162 std::array<NumericType, ArgumentAmount> m_ArgValues;
163 std::vector<std::string> m_ArgNames;
164 exprtk::symbol_table<NumericType> m_SymbolTable{};
165 exprtk::expression<NumericType> m_Expression;
166 exprtk::function_compositor<NumericType> m_Compositor;
167 uint8_t m_ArgAmount = ArgumentAmount;
168
169 Data() : m_Compositor(m_SymbolTable) {}
170 };
171
172 std::unique_ptr<Data> m_Data{ nullptr };
173 bool m_Valid{ false };
174 bool m_ValuesRegistered{ false };
175
176 };
177 }
178}
#define CORI_CORE_ERROR_TAGGED(...)
Definition Logger.hpp:1039
#define CORI_CORE_WARN_TAGGED(...)
Definition Logger.hpp:1038
void Parse(const std::string &expression)
Parses the main mathematical expression. Can use any aliases created with AddAlias.
Definition Function.hpp:100
void RegisterValues(const std::vector< std::string > &argNames)
Registers the names of the arguments for the function. This must be called before AddAlias or Parse.
Definition Function.hpp:46
Function & operator=(const Function &)=delete
Function & operator=(Function &&other) noexcept=default
void AddAlias(const std::string &aliasName, const std::string &aliasExpression)
Creates a parameterized alias (a composited function). The alias will accept the same parameters as r...
Definition Function.hpp:77
bool AddConstant(const std::string &alias, const NumericType value)
Ads a constant to the registered values.
Definition Function.hpp:68
Function(const Function &)=delete
NumericType operator()(const IsNumber auto &... args)
Makes function object a callable. Calculates the main expression result based on the passed values....
Definition Function.hpp:130
Function(Function &&other) noexcept=default
bool Success() const
Definition Function.hpp:156
Checks if T is a number.
Definition Function.hpp:10
Anything custom connected to math is in this namespace.
Definition Function.hpp:5
Global engine namespace.
static constexpr char Function[]
Definition Logger.hpp:115
static constexpr char Self[]
Definition Logger.hpp:113