#include "constvariant.h" #include "constvariant.inl" CConstVariant::CConstVariant(const CConstVariant& rvar) : m_varValue(rvar.m_varValue) {} CConstVariant::CConstVariant(CConstVariant&& rvar) noexcept : m_varValue(std::move(rvar.m_varValue)) {} CConstVariant::CConstVariant(bool bValue) : m_varValue(bValue) {} CConstVariant::CConstVariant(int8_t iValue) : m_varValue(iValue) {} CConstVariant::CConstVariant(uint8_t uiValue) : m_varValue(uiValue) {} CConstVariant::CConstVariant(int16_t iValue) : m_varValue(iValue) {} CConstVariant::CConstVariant(uint16_t uiValue) : m_varValue(uiValue) {} #ifdef _WIN32 CConstVariant::CConstVariant(long int iValue) : m_varValue(static_cast(iValue)) {} CConstVariant::CConstVariant(unsigned long int uiValue) : m_varValue(static_cast(uiValue)) {} #endif CConstVariant::CConstVariant(int32_t iValue) : m_varValue(iValue) {} CConstVariant::CConstVariant(uint32_t uiValue) : m_varValue(uiValue) {} CConstVariant::CConstVariant(int64_t iValue) : m_varValue(iValue) {} CConstVariant::CConstVariant(uint64_t uiValue) : m_varValue(uiValue) {} #if defined(__GNUC__) && !defined(_WIN32) CConstVariant::CConstVariant(long long int iValue) : CConstVariant(static_cast(iValue)) {} CConstVariant::CConstVariant(unsigned long long int uiValue) : CConstVariant(static_cast(uiValue)) {} #endif CConstVariant::CConstVariant(fixed fixValue) : m_varValue(fixValue) {} CConstVariant::CConstVariant(float fValue) : m_varValue(fValue) {} CConstVariant::CConstVariant(double dValue) : m_varValue(dValue) {} CConstVariant::CConstVariant(long double ldValue) : m_varValue(ldValue) {} CConstVariant::CConstVariant(const std::string& rssValue) : m_varValue(rssValue) {} CConstVariant::CConstVariant(const std::u16string& rssValue) : m_varValue(rssValue) {} CConstVariant::CConstVariant(const std::u32string& rssValue) : m_varValue(rssValue) {} CConstVariant::CConstVariant(const std::wstring& rssValue) : m_varValue(rssValue) {} CConstVariant& CConstVariant::operator=(const CConstVariant& rvar) { m_varValue = rvar.m_varValue; return *this; } CConstVariant& CConstVariant::operator=(CConstVariant&& rvar) noexcept { m_varValue = std::move(rvar.m_varValue); return *this; } bool CConstVariant::IsArithmetic() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::is_arithmetic_v; case ETypeMapping::type_uint8_t: return std::is_arithmetic_v; case ETypeMapping::type_uint16_t: return std::is_arithmetic_v; case ETypeMapping::type_uint32_t: return std::is_arithmetic_v; case ETypeMapping::type_uint64_t: return std::is_arithmetic_v; case ETypeMapping::type_int8_t: return std::is_arithmetic_v; case ETypeMapping::type_int16_t: return std::is_arithmetic_v; case ETypeMapping::type_int32_t: return std::is_arithmetic_v; case ETypeMapping::type_int64_t: return std::is_arithmetic_v; case ETypeMapping::type_fixed: return std::is_arithmetic_v; case ETypeMapping::type_float: return std::is_arithmetic_v; case ETypeMapping::type_double: return std::is_arithmetic_v; case ETypeMapping::type_long_double: return std::is_arithmetic_v; case ETypeMapping::type_string: return std::is_arithmetic_v; case ETypeMapping::type_u16string: return std::is_arithmetic_v; case ETypeMapping::type_u32string: return std::is_arithmetic_v; case ETypeMapping::type_wstring: return std::is_arithmetic_v; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } bool CConstVariant::IsIntegral() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::is_integral_v; case ETypeMapping::type_uint8_t: return std::is_integral_v; case ETypeMapping::type_uint16_t: return std::is_integral_v; case ETypeMapping::type_uint32_t: return std::is_integral_v; case ETypeMapping::type_uint64_t: return std::is_integral_v; case ETypeMapping::type_int8_t: return std::is_integral_v; case ETypeMapping::type_int16_t: return std::is_integral_v; case ETypeMapping::type_int32_t: return std::is_integral_v; case ETypeMapping::type_int64_t: return std::is_integral_v; case ETypeMapping::type_fixed: return std::is_integral_v; case ETypeMapping::type_float: return std::is_integral_v; case ETypeMapping::type_double: return std::is_integral_v; case ETypeMapping::type_long_double: return std::is_integral_v; case ETypeMapping::type_string: return std::is_integral_v; case ETypeMapping::type_u16string: return std::is_integral_v; case ETypeMapping::type_u32string: return std::is_integral_v; case ETypeMapping::type_wstring: return std::is_integral_v; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } bool CConstVariant::IsFloatingPoint() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::is_floating_point_v; case ETypeMapping::type_uint8_t: return std::is_floating_point_v; case ETypeMapping::type_uint16_t: return std::is_floating_point_v; case ETypeMapping::type_uint32_t: return std::is_floating_point_v; case ETypeMapping::type_uint64_t: return std::is_floating_point_v; case ETypeMapping::type_int8_t: return std::is_floating_point_v; case ETypeMapping::type_int16_t: return std::is_floating_point_v; case ETypeMapping::type_int32_t: return std::is_floating_point_v; case ETypeMapping::type_int64_t: return std::is_floating_point_v; case ETypeMapping::type_fixed: return std::is_floating_point_v; case ETypeMapping::type_float: return std::is_floating_point_v; case ETypeMapping::type_double: return std::is_floating_point_v; case ETypeMapping::type_long_double: return std::is_floating_point_v; case ETypeMapping::type_string: return std::is_floating_point_v; case ETypeMapping::type_u16string: return std::is_floating_point_v; case ETypeMapping::type_u32string: return std::is_floating_point_v; case ETypeMapping::type_wstring: return std::is_floating_point_v; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } bool CConstVariant::IsBoolean() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return true; case ETypeMapping::type_uint8_t: return false; case ETypeMapping::type_uint16_t: return false; case ETypeMapping::type_uint32_t: return false; case ETypeMapping::type_uint64_t: return false; case ETypeMapping::type_int8_t: return false; case ETypeMapping::type_int16_t: return false; case ETypeMapping::type_int32_t: return false; case ETypeMapping::type_int64_t: return false; case ETypeMapping::type_fixed: return false; case ETypeMapping::type_float: return false; case ETypeMapping::type_double: return false; case ETypeMapping::type_long_double: return false; case ETypeMapping::type_string: return false; case ETypeMapping::type_u16string: return false; case ETypeMapping::type_u32string: return false; case ETypeMapping::type_wstring: return false; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } bool CConstVariant::IsSigned() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::is_signed_v; case ETypeMapping::type_uint8_t: return std::is_signed_v; case ETypeMapping::type_uint16_t: return std::is_signed_v; case ETypeMapping::type_uint32_t: return std::is_signed_v; case ETypeMapping::type_uint64_t: return std::is_signed_v; case ETypeMapping::type_int8_t: return std::is_signed_v; case ETypeMapping::type_int16_t: return std::is_signed_v; case ETypeMapping::type_int32_t: return std::is_signed_v; case ETypeMapping::type_int64_t: return std::is_signed_v; case ETypeMapping::type_fixed: return std::is_signed_v; case ETypeMapping::type_float: return std::is_signed_v; case ETypeMapping::type_double: return std::is_signed_v; case ETypeMapping::type_long_double: return std::is_signed_v; case ETypeMapping::type_string: return std::is_signed_v; case ETypeMapping::type_u16string: return std::is_signed_v; case ETypeMapping::type_u32string: return std::is_signed_v; case ETypeMapping::type_wstring: return std::is_signed_v; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } bool CConstVariant::IsUnsigned() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::is_unsigned_v; case ETypeMapping::type_uint8_t: return std::is_unsigned_v; case ETypeMapping::type_uint16_t: return std::is_unsigned_v; case ETypeMapping::type_uint32_t: return std::is_unsigned_v; case ETypeMapping::type_uint64_t: return std::is_unsigned_v; case ETypeMapping::type_int8_t: return std::is_unsigned_v; case ETypeMapping::type_int16_t: return std::is_unsigned_v; case ETypeMapping::type_int32_t: return std::is_unsigned_v; case ETypeMapping::type_int64_t: return std::is_unsigned_v; case ETypeMapping::type_fixed: return std::is_unsigned_v; case ETypeMapping::type_float: return std::is_unsigned_v; case ETypeMapping::type_double: return std::is_unsigned_v; case ETypeMapping::type_long_double: return std::is_unsigned_v; case ETypeMapping::type_string: return std::is_unsigned_v; case ETypeMapping::type_u16string: return std::is_unsigned_v; case ETypeMapping::type_u32string: return std::is_unsigned_v; case ETypeMapping::type_wstring: return std::is_unsigned_v; default: throw CCompileException("Internal error: the variant doesn't contain any valid data type."); } } size_t CConstVariant::Ranking() const { // The ranking is provided through the index. return m_varValue.index(); } void CConstVariant::Convert(size_t nRank) { if (nRank == Ranking()) return; switch (static_cast(nRank)) { case ETypeMapping::type_bool: m_varValue = Get(); break; case ETypeMapping::type_uint8_t: m_varValue = Get(); break; case ETypeMapping::type_uint16_t: m_varValue = Get(); break; case ETypeMapping::type_uint32_t: m_varValue = Get(); break; case ETypeMapping::type_uint64_t: m_varValue = Get(); break; case ETypeMapping::type_int8_t: m_varValue = Get(); break; case ETypeMapping::type_int16_t: m_varValue = Get(); break; case ETypeMapping::type_int32_t: m_varValue = Get(); break; case ETypeMapping::type_int64_t: m_varValue = Get(); break; case ETypeMapping::type_fixed: m_varValue = Get(); break; case ETypeMapping::type_float: m_varValue = Get(); break; case ETypeMapping::type_double: m_varValue = Get(); break; case ETypeMapping::type_long_double: m_varValue = Get(); break; default: throw CCompileException("Internal error: incompatible data type conversion."); } } CConstVariant CConstVariant::operator!() const { return UnaryOperationIntegral(*this, [](auto tOperand) {return !tOperand;}); } CConstVariant CConstVariant::operator~() const { return UnaryOperationIntegral(*this, [](auto tOperand) -> CConstVariant { if constexpr (!std::is_same_v) return ~tOperand; else throw CCompileException("Cannot execute bitwise operations on a boolean."); }); } CConstVariant CConstVariant::operator+() const { return UnaryOperation(*this, [](auto tOperand) {return tOperand;}); } CConstVariant CConstVariant::operator-() const { return CConstVariant::UnaryOperation(*this, [](auto tOperand) -> CConstVariant { if constexpr (!std::is_same_v) { if constexpr (std::is_signed_v) return -tOperand; else if constexpr (std::is_integral_v) { // Two's complement plus 1. return ~tOperand + 1; } else throw CCompileException("Internal error: cannot execute unary arithmic operation on the type."); } else throw CCompileException("Cannot execute unary arithmic operations on a boolean."); }); } void Equalize(CConstVariant& rvar1, CConstVariant& rvar2) { // Are the types of both variant the same? if (rvar1.Ranking() == rvar2.Ranking()) return; // Equalization only works if both types are arithmetic. if (!rvar1.IsArithmetic() || !rvar2.IsArithmetic()) throw CCompileException("The types of both operands are not compatible."); // Check for highest ranking and adapt the lowest. if (rvar1.Ranking() > rvar2.Ranking()) rvar2.Convert(rvar1.Ranking()); else rvar1.Convert(rvar2.Ranking()); } CConstVariant operator*(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 * tOperand2;}); } CConstVariant operator/(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #endif return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) -> CConstVariant { if constexpr (!std::is_same_v) { if (!tOperand2) throw CCompileException("Division by zero."); return tOperand1 / tOperand2; } else throw CCompileException("Cannot divide a boolean."); }); #ifdef __GNUC__ #pragma GCC diagnostic pop #endif } CConstVariant operator+(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 + tOperand2;}); } CConstVariant operator-(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 - tOperand2;}); } CConstVariant operator<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 < tOperand2;}); } CConstVariant operator<=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 <= tOperand2;}); } CConstVariant operator>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 > tOperand2;}); } CConstVariant operator>=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 >= tOperand2;}); } CConstVariant operator==(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 == tOperand2;}); } CConstVariant operator!=(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 != tOperand2;}); } CConstVariant operator%(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #endif return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) -> CConstVariant { if constexpr (std::is_integral_v && !std::is_same_v) { if (!tOperand2) throw CCompileException("Division by zero."); return tOperand1 % tOperand2; } else throw CCompileException("Cannot divide a boolean."); }); #ifdef __GNUC__ #pragma GCC diagnostic pop #endif } CConstVariant operator<<(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 << tOperand2;}); } CConstVariant operator>>(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 >> tOperand2;}); } CConstVariant operator&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 & tOperand2;}); } CConstVariant operator^(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 ^ tOperand2;}); } CConstVariant operator|(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperationIntegral(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) {return tOperand1 | tOperand2;}); } CConstVariant operator&&(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) { if constexpr (std::is_integral_v && std::is_integral_v) return tOperand1 && tOperand2; else return false; }); } CConstVariant operator||(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2) { return CConstVariant::BinaryOperation(rvarOperand1, rvarOperand2, [](auto tOperand1, auto tOperand2) { if constexpr (std::is_integral_v && std::is_integral_v) return tOperand1 || tOperand2; else return false; }); }