diff --git a/Foundation/include/Poco/Dynamic/VarHolder.h b/Foundation/include/Poco/Dynamic/VarHolder.h index 2cab44d540..61a51b42bc 100644 --- a/Foundation/include/Poco/Dynamic/VarHolder.h +++ b/Foundation/include/Poco/Dynamic/VarHolder.h @@ -416,6 +416,42 @@ class Foundation_API VarHolder checkUpperLimit(from); to = static_cast(from); } + + template ::value && std::is_signed::value && (sizeof(F) <= sizeof(T))>* = nullptr> + void convertToSigned(const F& from, T& to) const + { + to = static_cast(from); + } + + template ::value && std::is_signed::value && (sizeof(F) > sizeof(T))>* = nullptr> + void convertToSigned(const F& from, T& to) const + { + convertToSmaller(from, to); + } + + template ::value && std::is_signed::value>* = nullptr> + void convertToSigned(const F& from, T& to) const + { + convertUnsignedToSigned(from, to); + } + + template ::value && !std::is_signed::value && (sizeof(F) <= sizeof(T))>* = nullptr> + void convertToUnsigned(const F& from, T& to) const + { + to = static_cast(from); + } + + template ::value && !std::is_signed::value && (sizeof(F) > sizeof(T))>* = nullptr> + void convertToUnsigned(const F& from, T& to) const + { + convertToSmallerUnsigned(from, to); + } + + template ::value && !std::is_signed::value>* = nullptr> + void convertToUnsigned(const F& from, T& to) const + { + convertSignedToUnsigned(from, to); + } template ::value, bool> = true, @@ -787,6 +823,287 @@ class VarHolderImpl: public VarHolder return typeid(T); } + void convert(Int8& val) const + { + if constexpr (std::is_enum::value) + { + convertToSigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(Int16& val) const + { + if constexpr (std::is_enum::value) + { + convertToSigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(Int32& val) const + { + if constexpr (std::is_enum::value) + { + convertToSigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(Int64& val) const + { + if constexpr (std::is_enum::value) + { + convertToSigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(UInt8& val) const + { + if constexpr (std::is_enum::value) + { + convertToUnsigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(UInt16& val) const + { + if constexpr (std::is_enum::value) + { + convertToUnsigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(UInt32& val) const + { + if constexpr (std::is_enum::value) + { + convertToUnsigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(UInt64& val) const + { + if constexpr (std::is_enum::value) + { + convertToUnsigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + +#ifdef POCO_INT64_IS_LONG + + void convert(long long& val) const + { + if constexpr (std::is_enum::value) + { + convertToSigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(unsigned long long& val) const + { + if constexpr (std::is_enum::value) + { + convertToUnsigned(std::underlying_type_t(_val), val); + } + else + { + VarHolder::convert(val); + } + } + +#endif + + void convert(bool& val) const + { + if constexpr (std::is_enum::value) + { + val = (std::underlying_type_t(_val) != 0); + } + else + { + VarHolder::convert(val); + } + } + + void convert(float& val) const + { + if constexpr (std::is_enum::value) + { + val = static_cast(_val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(double& val) const + { + if constexpr (std::is_enum::value) + { + val = static_cast(_val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(char& val) const + { + if constexpr (std::is_enum::value) + { + val = static_cast(_val); + } + else + { + VarHolder::convert(val); + } + } + + void convert(std::string& val) const + { + if constexpr (std::is_enum::value) + { + val = NumberFormatter::format(std::underlying_type_t(_val)); + } + else + { + VarHolder::convert(val); + } + } + + void convert(Poco::UTF16String& val) const + { + if constexpr (std::is_enum::value) + { + std::string str = NumberFormatter::format(std::underlying_type_t(_val)); + Poco::UnicodeConverter::convert(str, val); + } + else + { + VarHolder::convert(val); + } + } + + bool isArray() const + { + if constexpr (std::is_enum::value) + { + return false; + } + else + { + return VarHolder::isArray(); + } + } + + bool isStruct() const + { + if constexpr (std::is_enum::value) + { + return false; + } + else + { + return VarHolder::isStruct(); + } + } + + bool isInteger() const + { + if constexpr (std::is_enum::value) + { + return std::numeric_limits>::is_integer; + } + else + { + return VarHolder::isInteger(); + } + } + + bool isSigned() const + { + if constexpr (std::is_enum::value) + { + return std::numeric_limits>::is_signed; + } + else + { + return VarHolder::isSigned(); + } + } + + bool isNumeric() const + { + if constexpr (std::is_enum::value) + { + return std::numeric_limits>::is_specialized; + } + else + { + return VarHolder::isNumeric(); + } + } + + bool isBoolean() const + { + if constexpr (std::is_enum::value) + { + return false; + } + else + { + return VarHolder::isBoolean(); + } + } + + bool isString() const + { + if constexpr (std::is_enum::value) + { + return false; + } + else + { + return VarHolder::isString(); + } + } + VarHolder* clone(Placeholder* pVarHolder = 0) const { return cloneHolder(pVarHolder, _val); diff --git a/Foundation/testsuite/src/VarTest.cpp b/Foundation/testsuite/src/VarTest.cpp index b9616f94c1..916824ad43 100644 --- a/Foundation/testsuite/src/VarTest.cpp +++ b/Foundation/testsuite/src/VarTest.cpp @@ -1644,6 +1644,103 @@ void VarTest::testULongLong() } +void VarTest::testEnumType() +{ + enum class src { + value = 32 + }; + + Var a1 = src::value; + + assertTrue (a1.type() == typeid(src)); + + std::string s1; + Poco::Int8 s2; + Poco::Int16 s3; + Poco::Int32 s4; + Poco::Int64 s5; + Poco::UInt8 s6; + Poco::UInt16 s7; + Poco::UInt32 s8; + Poco::UInt64 s9; + float s10; + double s11; + bool s12; + char s13; + a1.convert(s1); + a1.convert(s2); + a1.convert(s3); + a1.convert(s4); + a1.convert(s5); + a1.convert(s6); + a1.convert(s7); + a1.convert(s8); + a1.convert(s9); + a1.convert(s10); + a1.convert(s11); + a1.convert(s12); + a1.convert(s13); + long s14; + unsigned long s15; + long long s16; + unsigned long long s17; + a1.convert(s14); + a1.convert(s15); + a1.convert(s16); + a1.convert(s17); + assertTrue (s14 == 32); + assertTrue (s15 == 32); + assertTrue (s16 == 32); + assertTrue (s17 == 32); + assertTrue (s1 == "32"); + assertTrue (s2 == 32); + assertTrue (s3 == 32); + assertTrue (s4 == 32); + assertTrue (s5 == 32); + assertTrue (s6 == 32); + assertTrue (s7 == 32); + assertTrue (s8 == 32); + assertTrue (s9 == 32); + assertTrue (s10 == 32.0f); + assertTrue (s11 == 32.0); + assertTrue (s12); + assertTrue (s13 == ' '); + Var a2(a1); + std::string t2; + a2.convert(t2); + assertTrue (s1 == t2); + + src value = a1.extract(); + assertTrue (value == src::value); + + try + { + POCO_UNUSED Int16 value2; value2 = a1.extract(); + fail("bad cast - must throw"); + } + catch (Poco::BadCastException&) + { + } + + Var a3 = a1 + 1; + assertTrue (a3 == 33); + a3 = a1 - 1; + assertTrue (a3 == 31); + a3 += 1; + assertTrue (a3 == 32); + a3 -= 1; + assertTrue (a3 == 31); + a3 = a1 / 2; + assertTrue (a3 == 16); + a3 = a1 * 2; + assertTrue (a3 == 64); + a3 /= 2; + assertTrue (a3 == 32); + a3 *= 2; + assertTrue (a3 == 64); +} + + void VarTest::testUDT() { Dummy d0; @@ -3375,6 +3472,7 @@ CppUnit::Test* VarTest::suite() CppUnit_addTest(pSuite, VarTest, testEmpty); CppUnit_addTest(pSuite, VarTest, testIterator); CppUnit_addTest(pSuite, VarTest, testVarVisitor); + CppUnit_addTest(pSuite, VarTest, testEnumType); return pSuite; } diff --git a/Foundation/testsuite/src/VarTest.h b/Foundation/testsuite/src/VarTest.h index e71dd0e92e..06940b04d0 100644 --- a/Foundation/testsuite/src/VarTest.h +++ b/Foundation/testsuite/src/VarTest.h @@ -42,6 +42,7 @@ class VarTest: public CppUnit::TestCase void testULong(); void testLongLong(); void testULongLong(); + void testEnumType(); void testString(); void testUDT(); void testConversionOperator(); diff --git a/JSON/testsuite/src/JSONTest.cpp b/JSON/testsuite/src/JSONTest.cpp index 7e0b56d4d7..dec1e7a97c 100644 --- a/JSON/testsuite/src/JSONTest.cpp +++ b/JSON/testsuite/src/JSONTest.cpp @@ -2369,7 +2369,178 @@ void JSONTest::testRemove() assertTrue(nl[1] == "baz"); } - +void JSONTest::testEnum() +{ + enum SAMPLE_ENUM + { + SE_VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_I8: Poco::Int8 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_I16: Poco::Int16 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_I32: Poco::Int32 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_I64: Poco::Int64 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_UI8: Poco::UInt8 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_UI16: Poco::UInt16 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_UI32: Poco::UInt32 + { + VALUE = 42 + }; + + enum class SAMPLE_ENUM_CLASS_UI64: Poco::UInt64 + { + VALUE = 42 + }; + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("simple_enum", SE_VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"simple_enum\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM se = obj->get("simple_enum").extract(); + assertTrue(se == SE_VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class", SAMPLE_ENUM_CLASS::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS se = obj->get("enum_class").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_i8", SAMPLE_ENUM_CLASS_I8::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_i8\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_I8 se = obj->get("enum_class_i8").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_I8::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_i16", SAMPLE_ENUM_CLASS_I16::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_i16\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_I16 se = obj->get("enum_class_i16").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_I16::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_i32", SAMPLE_ENUM_CLASS_I32::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_i32\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_I32 se = obj->get("enum_class_i32").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_I32::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_i64", SAMPLE_ENUM_CLASS_I64::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_i64\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_I64 se = obj->get("enum_class_i64").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_I64::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_ui8", SAMPLE_ENUM_CLASS_UI8::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_ui8\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_UI8 se = obj->get("enum_class_ui8").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_UI8::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_ui16", SAMPLE_ENUM_CLASS_UI16::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_ui16\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_UI16 se = obj->get("enum_class_ui16").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_UI16::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_ui32", SAMPLE_ENUM_CLASS_UI32::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_ui32\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_UI32 se = obj->get("enum_class_ui32").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_UI32::VALUE); + } + + { + Poco::JSON::Object::Ptr obj = new Poco::JSON::Object(); + obj->set("enum_class_ui64", SAMPLE_ENUM_CLASS_UI64::VALUE); + Poco::Dynamic::Var var(obj); + std::string expected = "{\"enum_class_ui64\":42}"; + std::string result = var.convert(); + assertEquals(expected, result); + + SAMPLE_ENUM_CLASS_UI64 se = obj->get("enum_class_ui64").extract(); + assertTrue(se == SAMPLE_ENUM_CLASS_UI64::VALUE); + } +} CppUnit::Test* JSONTest::suite() { @@ -2424,6 +2595,7 @@ CppUnit::Test* JSONTest::suite() CppUnit_addTest(pSuite, JSONTest, testCopy); CppUnit_addTest(pSuite, JSONTest, testMove); CppUnit_addTest(pSuite, JSONTest, testRemove); + CppUnit_addTest(pSuite, JSONTest, testEnum); return pSuite; } diff --git a/JSON/testsuite/src/JSONTest.h b/JSON/testsuite/src/JSONTest.h index 40bf81a1ae..c431a761d1 100644 --- a/JSON/testsuite/src/JSONTest.h +++ b/JSON/testsuite/src/JSONTest.h @@ -86,6 +86,8 @@ class JSONTest: public CppUnit::TestCase void testMove(); void testRemove(); + void testEnum(); + void setUp(); void tearDown();