#ifndef CONSTVARIANT_INL #define CONSTVARIANT_INL #include "exception.h" #include "constvariant.h" #include #include template inline CConstVariant& CConstVariant::operator=(const TType& rtValue) { m_varValue = rtValue; return *this; } #ifdef _WIN32 template <> inline CConstVariant& CConstVariant::operator=(const long int& rtValue) { m_varValue = static_cast(rtValue); return *this; } template <> inline CConstVariant& CConstVariant::operator=(const unsigned long int& rtValue) { m_varValue = static_cast(rtValue); return *this; } #endif #if defined( __GNUC__) && !defined(_WIN32) template <> inline CConstVariant& CConstVariant::operator=(const long long int& rtValue) { m_varValue = static_cast(rtValue); return *this; } template <> inline CConstVariant& CConstVariant::operator=(const unsigned long long int& rtValue) { m_varValue = static_cast(rtValue); return *this; } #endif template inline TTargetType CConstVariant::Get() const { switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return InternalGet(); case ETypeMapping::type_uint8_t: return InternalGet(); case ETypeMapping::type_uint16_t: return InternalGet(); case ETypeMapping::type_uint32_t: return InternalGet(); case ETypeMapping::type_uint64_t: return InternalGet(); case ETypeMapping::type_int8_t: return InternalGet(); case ETypeMapping::type_int16_t: return InternalGet(); case ETypeMapping::type_int32_t: return InternalGet(); case ETypeMapping::type_int64_t: return InternalGet(); case ETypeMapping::type_fixed: return InternalGet(); case ETypeMapping::type_float: return InternalGet(); case ETypeMapping::type_double: return InternalGet(); case ETypeMapping::type_long_double: return InternalGet(); case ETypeMapping::type_string: return InternalGet(); case ETypeMapping::type_u16string: return InternalGet(); case ETypeMapping::type_u32string: return InternalGet(); case ETypeMapping::type_wstring: return InternalGet(); default: throw CCompileException("Conversion to target data type is not supported."); } } inline std::string CConstVariant::GetAsString() const { // TODO: Add conversion for the missing types switch (static_cast(m_varValue.index())) { case ETypeMapping::type_bool: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_uint8_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_uint16_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_uint32_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_uint64_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_int8_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_int16_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_int32_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_int64_t: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_fixed: return "fixed"; case ETypeMapping::type_float: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_double: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_long_double: return std::to_string(std::get(m_varValue)); case ETypeMapping::type_string: return std::get(m_varValue); case ETypeMapping::type_u16string: return "UTF-16 string"; case ETypeMapping::type_u32string: return "UTF-32string"; case ETypeMapping::type_wstring: return "wstring"; default: throw CCompileException("Creating a string from value is not possible."); } } template inline bool CConstVariant::IsSame() const { return std::holds_alternative(m_varValue); } template inline void CConstVariant::Convert() { // Conversion needed? if (IsSame()) return; if constexpr (std::is_integral_v) { if constexpr (std::is_signed_v) { // Singed integer // NOTE: 'if' is used instead of switch to allow the use of constexpr. if constexpr (sizeof(TType) == sizeof(int8_t)) Convert(ETypeMapping::type_int8_t); else if constexpr (sizeof(TType) == sizeof(int16_t)) Convert(ETypeMapping::type_int16_t); else if constexpr (sizeof(TType) == sizeof(int32_t)) Convert(ETypeMapping::type_int32_t); else Convert(ETypeMapping::type_int64_t); } else { // Unsigned integer // NOTE: 'if' is used instead of switch to allow the use of constexpr. if constexpr (sizeof(TType) == sizeof(uint8_t)) { if constexpr (std::is_same_v) Convert(ETypeMapping::type_bool); else Convert(ETypeMapping::type_uint8_t); } else if constexpr (sizeof(TType) == sizeof(uint16_t)) Convert(ETypeMapping::type_uint16_t); else if constexpr (sizeof(TType) == sizeof(uint32_t)) Convert(ETypeMapping::type_uint32_t); else Convert(ETypeMapping::type_uint64_t); } // Done! return; } else if constexpr (std::is_floating_point_v) { // NOTE: 'if' is used instead of switch to allow the use of constexpr. if constexpr (std::is_same_v) Convert(ETypeMapping::type_fixed); else if constexpr (sizeof(TType) == sizeof(float)) Convert(ETypeMapping::type_float); else if constexpr (sizeof(TType) == sizeof(double)) Convert(ETypeMapping::type_double); else Convert(ETypeMapping::type_long_double); // Done! return; } else { // Conversion is only possible between arithmetic types. throw CCompileException("Internal error: incompatible data type conversion."); } } template inline CConstVariant CConstVariant::UnaryOperation(const CConstVariant& rvarOperand, TFunction tOperation) { // Based on the operand type, execute the provided function switch (static_cast(rvarOperand.Ranking())) { case ETypeMapping::type_bool: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint8_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint16_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint32_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint64_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int8_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int16_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int32_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int64_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_fixed: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_float: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_double: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_long_double: return tOperation(rvarOperand.Get()); break; default: throw CCompileException("Internal error: incompatible data type conversion."); } } template inline CConstVariant CConstVariant::UnaryOperationIntegral(const CConstVariant& rvarOperand, TFunction tOperation) { // Based on the operand type, execute the provided function switch (static_cast(rvarOperand.Ranking())) { case ETypeMapping::type_bool: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint8_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint16_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint32_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_uint64_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int8_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int16_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int32_t: return tOperation(rvarOperand.Get()); break; case ETypeMapping::type_int64_t: return tOperation(rvarOperand.Get()); break; default: throw CCompileException("Internal error: incompatible data type conversion."); } } template inline CConstVariant CConstVariant::BinaryOperation(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2, TFunction tOperation) { // Equalize the operands CConstVariant varOperand1 = rvarOperand1; CConstVariant varOperand2 = rvarOperand2; Equalize(varOperand1, varOperand2); // Based on the operand type, execute the provided function switch (static_cast(varOperand1.Ranking())) { // NOTE: Arithmetic operations on "bool" can cause warnings. Use uint8_t instead. case ETypeMapping::type_bool: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint8_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint16_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint32_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint64_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int8_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int16_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int32_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int64_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_fixed: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_float: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_double: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_long_double: return tOperation(varOperand1.Get(), varOperand2.Get()); break; default: throw CCompileException("Internal error: incompatible data type conversion."); } } template inline CConstVariant CConstVariant::BinaryOperationIntegral(const CConstVariant& rvarOperand1, const CConstVariant& rvarOperand2, TFunction tOperation) { // Equalize the operands CConstVariant varOperand1 = rvarOperand1; CConstVariant varOperand2 = rvarOperand2; Equalize(varOperand1, varOperand2); // Based on the operand type, execute the provided function switch (static_cast(varOperand1.Ranking())) { case ETypeMapping::type_uint8_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint16_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint32_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_uint64_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int8_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int16_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int32_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; case ETypeMapping::type_int64_t: return tOperation(varOperand1.Get(), varOperand2.Get()); break; default: throw CCompileException("Internal error: incompatible data type conversion."); } } template inline TTargetType CConstVariant::InternalGet() const { if constexpr (std::is_same_v) return std::get(m_varValue); else if constexpr (std::is_floating_point_v && std::is_arithmetic_v) { TVariantType tValue = std::get(m_varValue); if (static_cast(tValue) > static_cast(std::numeric_limits::max())) throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type."); if (static_cast(tValue) < static_cast(std::numeric_limits::lowest())) throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type."); if constexpr (std::is_floating_point_v) { int iExpValue = 0, iExpMin = 0; long double ldDigitsValue = std::fabs(std::frexp(static_cast(tValue), &iExpValue)); long double ldDigitsMin = std::frexp(static_cast(std::numeric_limits::min()), &iExpMin); if ((iExpValue < iExpMin) || ((iExpValue == iExpMin) && ldDigitsValue < ldDigitsMin)) throw CCompileException("Cannot cast to type, the value precision is below the smallest possible" " precision of the target type."); } return static_cast(tValue); } else if constexpr (std::is_integral_v && std::is_integral_v && !std::is_same_v) { if constexpr (std::is_signed_v && std::is_signed_v) { TVariantType tValue = std::get(m_varValue); if (static_cast(tValue) > static_cast(std::numeric_limits::max())) throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type."); if (static_cast(tValue) < static_cast(std::numeric_limits::min())) throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type."); return static_cast(tValue); } if constexpr (std::is_unsigned_v && std::is_unsigned_v) { TVariantType tValue = std::get(m_varValue); if (static_cast(tValue) > static_cast(std::numeric_limits::max())) throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type."); if (static_cast(tValue) < static_cast(std::numeric_limits::min())) throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the target type."); return static_cast(tValue); } if constexpr (std::is_signed_v && std::is_unsigned_v) { TVariantType tValue = std::get(m_varValue); if (static_cast(tValue) > static_cast(std::numeric_limits::max())) throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type."); return static_cast(tValue); } if constexpr (std::is_unsigned_v && std::is_signed_v) { TVariantType tValue = std::get(m_varValue); if (tValue > 0 && static_cast(tValue) > static_cast(std::numeric_limits::max())) throw CCompileException("Cannot cast to type, the value exceeds the maximum possible value of the target type."); else if (tValue < 0 && static_cast(tValue) < static_cast(std::numeric_limits>::min())) throw CCompileException("Cannot cast to type, the value is below the minumum possible value of the signed version" " of the target type."); return static_cast(tValue); } } else if constexpr (std::is_same_v && std::is_arithmetic_v) return std::get(m_varValue) != static_cast(0) ? true : false; else { // Conversion not possible throw CCompileException("Cannot cast to target type, the types are incompatible."); } } #endif // !defined(CONSTVARIANT_INL)