dto::Enum. Enum interpreters POC.

This commit is contained in:
lganzzzo 2020-05-06 03:41:18 +03:00
parent 66d34683f7
commit bfcb159b48
7 changed files with 271 additions and 36 deletions

View File

@ -48,7 +48,7 @@ namespace __class {
};
template<class T>
template<class T, class Interpreter>
class Enum;
}
@ -63,19 +63,24 @@ struct EnumValueInfo {
template<typename T>
struct EnumInfo {
public:
const char* nameQualifier;
const char* nameQualifier = nullptr;
std::unordered_map<data::share::StringKeyLabel, EnumValueInfo<T>> byName;
std::unordered_map<v_uint64, EnumValueInfo<T>> byValue;
std::vector<EnumValueInfo<T>> byIndex;
};
template<class T>
class Enum; // FWD
template<class T, class Interpreter>
class EnumObjectWrapper; // FWD
template<class T>
class EnumMeta {
friend __class::Enum<T>;
friend Enum<T>;
template<class Type, class Interpreter>
friend class __class::Enum;
template<class Type, class Interpreter>
friend class EnumObjectWrapper;
public:
typedef T EnumType;
protected:
@ -85,10 +90,40 @@ protected:
template<class T>
EnumInfo<T> EnumMeta<T>::__info;
template<class T>
class Enum : public ObjectWrapper<T, __class::Enum<T>>{
template<class T, bool nullable>
class EnumInterpreterAsString {
public:
template <bool N>
using InterpreterType = EnumInterpreterAsString<T, N>;
public:
constexpr static bool isNullable = nullable;
public:
static Void toInterpretation(T value);
static T fromInterpretation(const Void& value);
};
template<class T, bool nullable>
class EnumInterpreterAsInteger {
public:
template <bool N>
using InterpreterType = EnumInterpreterAsInteger<T, N>;
public:
constexpr static bool isNullable = nullable;
public:
static Void toInterpretation(T value);
static T fromInterpretation(const Void& value);
};
template<class T, class EnumInterpreter>
class EnumObjectWrapper : public ObjectWrapper<T, __class::Enum<T, EnumInterpreter>>{
public:
typedef typename std::underlying_type<T>::type UnderlyingType;
typedef __class::Enum<T, EnumInterpreter> EnumObjectClass;
typedef EnumInterpreter Interpreter;
public:
typedef EnumObjectWrapper<T, EnumInterpreterAsString<T, true>> AsString;
typedef EnumObjectWrapper<T, EnumInterpreterAsInteger<T, true>> AsInteger;
typedef EnumObjectWrapper<T, typename EnumInterpreter::template InterpreterType<false>> NotNull;
public:
static EnumValueInfo<T> getEntryByName(const String& name) {
@ -128,9 +163,49 @@ public:
};
template <class T>
using Enum = EnumObjectWrapper<T, EnumInterpreterAsString<T, true>>;
template<class T, bool nullable>
Void EnumInterpreterAsString<T, nullable>::toInterpretation(T value) {
const auto& entry = EnumObjectWrapper<T, EnumInterpreterAsString<T, nullable>>::getEntryByValue(value);
return entry.name.toString();
}
template<class T, bool nullable>
T EnumInterpreterAsString<T, nullable>::fromInterpretation(const Void& value) {
if(value.valueType != String::Class::getType()) {
throw std::runtime_error("[oatpp::data::mapping::type::EnumInterpreterAsString::fromInterpretation()]: Error. Interpretation must be a String.");
}
const auto& entry = EnumObjectWrapper<T, EnumInterpreterAsString<T, nullable>>::getEntryByName(value.staticCast<String>());
return entry.value;
}
template<class T, bool nullable>
Void EnumInterpreterAsInteger<T, nullable>::toInterpretation(T value) {
const auto& entry = EnumObjectWrapper<T, EnumInterpreterAsString<T, nullable>>::getEntryByValue(value);
typedef typename std::underlying_type<T>::type EnumUT;
typedef typename ObjectWrapperByUnderlyingType<EnumUT>::ObjectWrapper OW;
OW result(static_cast<EnumUT>(value));
return result;
}
template<class T, bool nullable>
T EnumInterpreterAsInteger<T, nullable>::fromInterpretation(const Void& value) {
typedef typename std::underlying_type<T>::type EnumUT;
typedef typename ObjectWrapperByUnderlyingType<EnumUT>::ObjectWrapper OW;
if(value.valueType != OW::Class::getType()) {
throw std::runtime_error("[oatpp::data::mapping::type::EnumInterpreterAsInteger::fromInterpretation()]: Error. Interpretation value type doesn't match.");
}
const auto& entry = EnumObjectWrapper<T, EnumInterpreterAsString<T, nullable>>::getEntryByUnderlyingValue(value.staticCast<OW>());
return entry.value;
}
namespace __class {
template<class T>
template<class T, class Interpreter>
class Enum : public AbstractEnum {
private:

View File

@ -166,6 +166,8 @@ String operator + (const String& a, const String& b);
*/
template<typename TValueType, class Clazz>
class Primitive : public type::ObjectWrapper<TValueType, Clazz> {
public:
typedef TValueType UnderlyingType;
public:
OATPP_DEFINE_OBJECT_WRAPPER_DEFAULTS(Primitive, TValueType, Clazz)
@ -239,6 +241,8 @@ public:
* ObjectWrapper for Boolean.
*/
class Boolean : public type::ObjectWrapper<bool, __class::Boolean> {
public:
typedef bool UnderlyingType;
public:
OATPP_DEFINE_OBJECT_WRAPPER_DEFAULTS(Boolean, bool, __class::Boolean)
@ -354,6 +358,52 @@ typedef Primitive<v_float32, __class::Float32> Float32;
* Float64 is an ObjectWrapper over `v_float64` and __class::Float64.
*/
typedef Primitive<v_float64, __class::Float64> Float64;
template<>
struct ObjectWrapperByUnderlyingType <v_int8> {
typedef Int8 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_uint8> {
typedef UInt8 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_int16> {
typedef Int16 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_uint16> {
typedef UInt16 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_int32> {
typedef Int32 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_uint32> {
typedef UInt32 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_int64> {
typedef Int64 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <v_uint64> {
typedef UInt64 ObjectWrapper;
};
template<>
struct ObjectWrapperByUnderlyingType <bool> {
typedef Boolean ObjectWrapper;
};
namespace __class {

View File

@ -219,6 +219,9 @@ public:
typedef ObjectWrapper<void, __class::Void> Void;
template <typename T>
struct ObjectWrapperByUnderlyingType {};
/**
* Object type data.
*/

View File

@ -15,6 +15,8 @@ add_executable(oatppAllTests
oatpp/core/data/buffer/ProcessorTest.hpp
oatpp/core/data/mapping/type/AnyTest.cpp
oatpp/core/data/mapping/type/AnyTest.hpp
oatpp/core/data/mapping/type/EnumTest.cpp
oatpp/core/data/mapping/type/EnumTest.hpp
oatpp/core/data/mapping/type/ListTest.cpp
oatpp/core/data/mapping/type/ListTest.hpp
oatpp/core/data/mapping/type/ObjectWrapperTest.cpp

View File

@ -47,6 +47,7 @@
#include "oatpp/core/data/mapping/type/ObjectWrapperTest.hpp"
#include "oatpp/core/data/mapping/type/TypeTest.hpp"
#include "oatpp/core/data/mapping/type/AnyTest.hpp"
#include "oatpp/core/data/mapping/type/EnumTest.hpp"
#include "oatpp/core/base/collection/LinkedListTest.hpp"
#include "oatpp/core/base/memory/MemoryPoolTest.hpp"
@ -91,31 +92,6 @@ void runTests() {
OATPP_LOGD("aaa", "coroutine size=%d", sizeof(oatpp::async::AbstractCoroutine));
OATPP_LOGD("aaa", "action size=%d", sizeof(oatpp::async::Action));
v_uint16 v = static_cast<v_uint16>(MyEnum1::CODE_3);
OATPP_LOGD("AAA", "name='%s'", oatpp::Enum<MyEnum1>::Class::getType()->nameQualifier);
OATPP_LOGD("AAA", "name='%s'", oatpp::Enum<MyEnum2>::Class::getType()->nameQualifier);
{
auto entry = oatpp::Enum<MyEnum1>::getEntryByName("Error - code 1");
OATPP_LOGD("Entry", "name='%s', value=%d, index=%d", entry.name.toString()->getData(), entry.value, entry.index);
}
{
auto entry = oatpp::Enum<MyEnum1>::getEntryByValue(MyEnum1::CODE_3);
OATPP_LOGD("Entry", "name='%s', value=%d, index=%d", entry.name.toString()->getData(), entry.value, entry.index);
}
{
auto entry = oatpp::Enum<MyEnum1>::getEntryByIndex(2);
OATPP_LOGD("Entry", "name='%s', value=%d, index=%d", entry.name.toString()->getData(), entry.value, entry.index);
}
{
auto entry = oatpp::Enum<MyEnum1>::getEntryByUnderlyingValue(1003);
OATPP_LOGD("Entry", "name='%s', value=%d, index=%d", entry.name.toString()->getData(), entry.value, entry.index);
}
/*
OATPP_RUN_TEST(oatpp::test::base::CommandLineArgumentsTest);
@ -135,14 +111,16 @@ void runTests() {
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::ObjectWrapperTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::TypeTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::AnyTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::StringTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::PrimitiveTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::ListTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::VectorTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::PairListTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::UnorderedMapTest);
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::AnyTest);
*/
OATPP_RUN_TEST(oatpp::test::core::data::mapping::type::EnumTest);
/*
OATPP_RUN_TEST(oatpp::test::async::LockTest);
OATPP_RUN_TEST(oatpp::test::parser::CaretTest);

View File

@ -0,0 +1,85 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#include "EnumTest.hpp"
#include "oatpp/core/Types.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type {
#include OATPP_CODEGEN_BEGIN(DTO)
ENUM(Enum1, v_int32,
VALUE(NAME_1, 1, "name-1"),
VALUE(NAME_2, 2, "name-2"),
VALUE(NAME_3, 3, "name-3")
)
#include OATPP_CODEGEN_END(DTO)
void EnumTest::onRun() {
{
OATPP_LOGI(TAG, "Declaration...");
OATPP_ASSERT(oatpp::Enum<Enum1>::Interpreter::isNullable == true);
OATPP_ASSERT(oatpp::Enum<Enum1>::NotNull::Interpreter::isNullable == false);
OATPP_ASSERT(oatpp::Enum<Enum1>::AsString::Interpreter::isNullable == true);
OATPP_ASSERT(oatpp::Enum<Enum1>::AsString::NotNull::Interpreter::isNullable == false);
OATPP_ASSERT(oatpp::Enum<Enum1>::AsInteger::Interpreter::isNullable == true);
OATPP_ASSERT(oatpp::Enum<Enum1>::AsInteger::NotNull::Interpreter::isNullable == false);
OATPP_LOGI(TAG, "OK");
}
{
OATPP_LOGI(TAG, "Test Interpreter AsString...");
auto inter = oatpp::Enum<Enum1>::AsString::Interpreter::toInterpretation(Enum1::NAME_1);
OATPP_ASSERT(inter.valueType == oatpp::String::Class::getType());
auto interValue = inter.staticCast<oatpp::String>();
OATPP_ASSERT(interValue == "name-1");
Enum1 value = oatpp::Enum<Enum1>::AsString::Interpreter::fromInterpretation(interValue);
OATPP_ASSERT(value == Enum1::NAME_1);
OATPP_LOGI(TAG, "OK");
}
{
OATPP_LOGI(TAG, "Test Interpreter AsInteger...");
auto inter = oatpp::Enum<Enum1>::AsInteger::Interpreter::toInterpretation(Enum1::NAME_1);
OATPP_ASSERT(inter.valueType == oatpp::Int32::Class::getType());
auto interValue = inter.staticCast<oatpp::Int32>();
OATPP_ASSERT(interValue == static_cast<v_int32>(Enum1::NAME_1));
Enum1 value = oatpp::Enum<Enum1>::AsInteger::Interpreter::fromInterpretation(interValue);
OATPP_ASSERT(value == Enum1::NAME_1);
OATPP_LOGI(TAG, "OK");
}
}
}}}}}}

View File

@ -0,0 +1,42 @@
/***************************************************************************
*
* Project _____ __ ____ _ _
* ( _ ) /__\ (_ _)_| |_ _| |_
* )(_)( /(__)\ )( (_ _)(_ _)
* (_____)(__)(__)(__) |_| |_|
*
*
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/
#ifndef oatpp_test_core_data_mapping_type_EnumTest_hpp
#define oatpp_test_core_data_mapping_type_EnumTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type {
class EnumTest : public UnitTest{
public:
EnumTest():UnitTest("TEST[core::data::mapping::type::EnumTest]"){}
void onRun() override;
};
}}}}}}
#endif /* oatpp_test_core_data_mapping_type_EnumTest_hpp */