diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02b42a86..8b3a81ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,6 +80,8 @@ add_library(oatpp oatpp/core/data/mapping/ObjectMapper.hpp oatpp/core/data/mapping/type/Any.cpp oatpp/core/data/mapping/type/Any.hpp + oatpp/core/data/mapping/type/Enum.cpp + oatpp/core/data/mapping/type/Enum.hpp oatpp/core/data/mapping/type/List.cpp oatpp/core/data/mapping/type/List.hpp oatpp/core/data/mapping/type/PairList.cpp diff --git a/src/oatpp/codegen/dto/enum_define.hpp b/src/oatpp/codegen/dto/enum_define.hpp index 8e987eab..67102ec2 100644 --- a/src/oatpp/codegen/dto/enum_define.hpp +++ b/src/oatpp/codegen/dto/enum_define.hpp @@ -43,10 +43,20 @@ OATPP_MACRO_EXPAND(OATPP_MACRO_MACRO_SELECTOR(MACRO, (__VA_ARGS__)) (NAME, __VA_ // VALUE MACRO #define OATPP_MACRO_DTO_ENUM_VALUE_1(NAME, VAL) \ -IMPL{ NAME = VAL } +{ \ + oatpp::data::mapping::type::EnumValueInfo entry = {EnumType::NAME, index ++, #NAME}; \ + info.byName.insert({#NAME, entry}); \ + info.byValue.insert({static_cast(EnumType::NAME), entry}); \ + info.byIndex.push_back(entry); \ +} #define OATPP_MACRO_DTO_ENUM_VALUE_2(NAME, VAL, QUALIFIER) \ -IMPL{ NAME (QUALIFIER) = VAL } +{ \ + oatpp::data::mapping::type::EnumValueInfo entry = {EnumType::NAME, index ++, QUALIFIER}; \ + info.byName.insert({QUALIFIER, entry}); \ + info.byValue.insert({static_cast(EnumType::NAME), entry}); \ + info.byIndex.push_back(entry); \ +} #define OATPP_MACRO_DTO_ENUM_VALUE(NAME, PARAM_LIST) \ OATPP_MACRO_DTO_ENUM_MACRO_SELECTOR(OATPP_MACRO_DTO_ENUM_VALUE_, NAME, OATPP_MACRO_UNFOLD_VA_ARGS PARAM_LIST) @@ -60,31 +70,30 @@ OATPP_MACRO_DTO_ENUM_PARAM_NAME X = OATPP_MACRO_DTO_ENUM_PARAM_VALUE X , OATPP_MACRO_DTO_ENUM_PARAM_NAME X = OATPP_MACRO_DTO_ENUM_PARAM_VALUE X #define OATPP_MACRO_DTO_ENUM_PARAM_PUT(INDEX, COUNT, X) \ -{ \ - "name": OATPP_MACRO_DTO_ENUM_PARAM_NAME X; \ - "value": OATPP_MACRO_DTO_ENUM_PARAM_VALUE X; \ - "name-str": OATPP_MACRO_DTO_ENUM_PARAM_NAME_STR X; \ - "value-str": OATPP_MACRO_DTO_ENUM_PARAM_VALUE_STR X; \ - "body": { \ - OATPP_MACRO_DTO_ENUM_PARAM_MACRO X \ - } \ -} +OATPP_MACRO_DTO_ENUM_PARAM_MACRO X // ENUM MACRO #define OATPP_ENUM_0(NAME, ORDINAL_TYPE) \ -enum NAME : ORDINAL_TYPE {}; \ +enum class NAME : ORDINAL_TYPE {}; \ \ -template<> \ -struct EnumInfo { \ -public: \ - typedef ORDINAL_TYPE ValueType; \ -public: \ - static constexpr const char* name = #NAME; \ -}; +class Z__OATPP_ENUM_META_##NAME : public oatpp::data::mapping::type::EnumMeta { \ +private: \ +\ + static bool init() { \ + auto& info = EnumMeta::__info; \ + info.nameQualifier = #NAME; \ + return true; \ + } \ +\ +private: \ + static bool initialized; \ +}; \ +\ +bool Z__OATPP_ENUM_META_##NAME::initialized = Z__OATPP_ENUM_META_##NAME::init(); #define OATPP_ENUM_1(NAME, ORDINAL_TYPE, ...) \ -enum NAME : ORDINAL_TYPE { \ +enum class NAME : ORDINAL_TYPE { \ OATPP_MACRO_FOREACH_FIRST_AND_REST( \ OATPP_MACRO_DTO_ENUM_PARAM_DECL_FIRST, \ OATPP_MACRO_DTO_ENUM_PARAM_DECL_REST, \ @@ -92,16 +101,22 @@ enum NAME : ORDINAL_TYPE { \ ) \ }; \ \ -template<> \ -struct EnumInfo { \ -public: \ - typedef ORDINAL_TYPE ValueType; \ -public: \ - static constexpr const char* name = #NAME; \ - \ - OATPP_MACRO_FOREACH(OATPP_MACRO_DTO_ENUM_PARAM_PUT, __VA_ARGS__) \ - \ -}; +class Z__OATPP_ENUM_META_##NAME : public oatpp::data::mapping::type::EnumMeta { \ +private: \ +\ + static bool init() { \ + auto& info = EnumMeta::__info; \ + v_int32 index = 0; \ + info.nameQualifier = #NAME; \ + OATPP_MACRO_FOREACH(OATPP_MACRO_DTO_ENUM_PARAM_PUT, __VA_ARGS__) \ + return true; \ + } \ +\ +private: \ + static bool initialized; \ +}; \ +\ +bool Z__OATPP_ENUM_META_##NAME::initialized = Z__OATPP_ENUM_META_##NAME::init(); // Chooser diff --git a/src/oatpp/core/Types.hpp b/src/oatpp/core/Types.hpp index ef077185..51a24c41 100644 --- a/src/oatpp/core/Types.hpp +++ b/src/oatpp/core/Types.hpp @@ -106,6 +106,12 @@ namespace oatpp { */ typedef oatpp::data::mapping::type::Object Object; + /* + * Mapping-Enabled Enum. &id:oatpp::data::mapping::type::Enum; + */ + template + using Enum = oatpp::data::mapping::type::Enum; + /* * Mapping-Enabled List. &id:oatpp::data::mapping::type::Vector; */ diff --git a/src/oatpp/core/data/mapping/type/Enum.cpp b/src/oatpp/core/data/mapping/type/Enum.cpp new file mode 100644 index 00000000..b44842f7 --- /dev/null +++ b/src/oatpp/core/data/mapping/type/Enum.cpp @@ -0,0 +1,33 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * 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 "Enum.hpp" + +namespace oatpp { namespace data { namespace mapping { namespace type { + +namespace __class { + const ClassId AbstractEnum::CLASS_ID("Enum"); +} + +}}}} diff --git a/src/oatpp/core/data/mapping/type/Enum.hpp b/src/oatpp/core/data/mapping/type/Enum.hpp new file mode 100644 index 00000000..81d7e974 --- /dev/null +++ b/src/oatpp/core/data/mapping/type/Enum.hpp @@ -0,0 +1,166 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * 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_data_mapping_type_Enum_hpp +#define oatpp_data_mapping_type_Enum_hpp + +#include "./Primitive.hpp" +#include "oatpp/core/data/share/MemoryLabel.hpp" + +#include +#include +#include + +namespace oatpp { namespace data { namespace mapping { namespace type { + +namespace __class { + + class AbstractEnum { + public: + static const ClassId CLASS_ID; + public: + + class AbstractPolymorphicDispatcher { + public: + + }; + + }; + + template + class Enum; + +} + +template +struct EnumValueInfo { + const T value; + const v_int32 index; + const data::share::StringKeyLabel name; +}; + +template +struct EnumInfo { +public: + const char* nameQualifier; + std::unordered_map> byName; + std::unordered_map> byValue; + std::vector> byIndex; +}; + +template +class Enum; // FWD + +template +class EnumMeta { + friend __class::Enum; + friend Enum; +public: + typedef T EnumType; +protected: + static EnumInfo __info; +}; + +template +EnumInfo EnumMeta::__info; + +template +class Enum : public ObjectWrapper>{ +public: + typedef typename std::underlying_type::type UnderlyingType; +public: + + static EnumValueInfo getEntryByName(const String& name) { + auto it = EnumMeta::__info.byName.find(name); + if(it != EnumMeta::__info.byName.end()) { + return it->second; + } + throw std::runtime_error("[oatpp::data::mapping::type::Enum::getEntryByName()]: Error. Entry not found."); + } + + static EnumValueInfo getEntryByValue(T value) { + auto it = EnumMeta::__info.byValue.find(static_cast(value)); + if(it != EnumMeta::__info.byValue.end()) { + return it->second; + } + throw std::runtime_error("[oatpp::data::mapping::type::Enum::getEntryByValue()]: Error. Entry not found."); + } + + static EnumValueInfo getEntryByUnderlyingValue(UnderlyingType value) { + auto it = EnumMeta::__info.byValue.find(static_cast(value)); + if(it != EnumMeta::__info.byValue.end()) { + return it->second; + } + throw std::runtime_error("[oatpp::data::mapping::type::Enum::getEntryByUnderlyingValue()]: Error. Entry not found."); + } + + static EnumValueInfo getEntryByIndex(v_int32 index) { + if(index >= 0 && index < EnumMeta::__info.byIndex.size()) { + return EnumMeta::__info.byIndex[index]; + } + throw std::runtime_error("[oatpp::data::mapping::type::Enum::getEntryByIndex()]: Error. Entry not found."); + } + + static const std::vector>& getEntries() { + return EnumMeta::__info.byIndex; + } + +}; + +namespace __class { + + template + class Enum : public AbstractEnum { + private: + + class PolymorphicDispatcher : public AbstractPolymorphicDispatcher { + public: + + }; + + private: + + static type::Void creator() { + return type::Void(std::make_shared(), getType()); + } + + static Type createType() { + Type type(__class::AbstractEnum::CLASS_ID, type::EnumMeta::__info.nameQualifier, &creator, nullptr, new PolymorphicDispatcher()); + return type; + } + + public: + + static Type* getType() { + static Type type = createType(); + return &type; + } + + }; + +} + +}}}} + +#endif // oatpp_data_mapping_type_Enum_hpp diff --git a/src/oatpp/core/data/mapping/type/Object.hpp b/src/oatpp/core/data/mapping/type/Object.hpp index 8d8de222..8540a986 100644 --- a/src/oatpp/core/data/mapping/type/Object.hpp +++ b/src/oatpp/core/data/mapping/type/Object.hpp @@ -29,6 +29,7 @@ #include "./Any.hpp" #include "./Primitive.hpp" +#include "./Enum.hpp" #include "./UnorderedMap.hpp" #include "./PairList.hpp" #include "./List.hpp" diff --git a/src/oatpp/core/data/share/LazyStringMap.hpp b/src/oatpp/core/data/share/LazyStringMap.hpp index dc5ccb4d..53ed6e11 100644 --- a/src/oatpp/core/data/share/LazyStringMap.hpp +++ b/src/oatpp/core/data/share/LazyStringMap.hpp @@ -39,6 +39,8 @@ namespace oatpp { namespace data { namespace share { */ template class LazyStringMap { +public: + typedef oatpp::data::mapping::type::String String; private: mutable concurrency::SpinLock m_lock; mutable bool m_fullyInitialized; @@ -181,7 +183,7 @@ public: * @param key * @return */ - oatpp::String get(const Key& key) const { + String get(const Key& key) const { std::lock_guard lock(m_lock); diff --git a/src/oatpp/core/data/share/MemoryLabel.cpp b/src/oatpp/core/data/share/MemoryLabel.cpp index 2b4ed91c..120bfa6b 100644 --- a/src/oatpp/core/data/share/MemoryLabel.cpp +++ b/src/oatpp/core/data/share/MemoryLabel.cpp @@ -42,7 +42,7 @@ StringKeyLabel::StringKeyLabel(const char* constText) : oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText)) {} -StringKeyLabel::StringKeyLabel(const oatpp::String& str) +StringKeyLabel::StringKeyLabel(const String& str) : oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize()) {} @@ -54,7 +54,7 @@ StringKeyLabelCI::StringKeyLabelCI(const char* constText) : oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText)) {} -StringKeyLabelCI::StringKeyLabelCI(const oatpp::String& str) +StringKeyLabelCI::StringKeyLabelCI(const String& str) : oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize()) {} @@ -66,7 +66,7 @@ StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const char* constText) : oatpp::data::share::MemoryLabel(nullptr, (p_char8)constText, std::strlen(constText)) {} -StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const oatpp::String& str) +StringKeyLabelCI_FAST::StringKeyLabelCI_FAST(const String& str) : oatpp::data::share::MemoryLabel(str.getPtr(), str->getData(), str->getSize()) {} diff --git a/src/oatpp/core/data/share/MemoryLabel.hpp b/src/oatpp/core/data/share/MemoryLabel.hpp index 6e11d274..8bb2013b 100644 --- a/src/oatpp/core/data/share/MemoryLabel.hpp +++ b/src/oatpp/core/data/share/MemoryLabel.hpp @@ -26,7 +26,7 @@ #define oatpp_data_share_MemoryLabel_hpp #include "oatpp/core/base/StrBuffer.hpp" -#include "oatpp/core/Types.hpp" +#include "oatpp/core/data/mapping/type/Primitive.hpp" namespace oatpp { namespace data { namespace share { @@ -36,6 +36,8 @@ namespace oatpp { namespace data { namespace share { * You may allocate separate buffer for data copy later once you need it. */ class MemoryLabel { +public: + typedef oatpp::data::mapping::type::String String; protected: mutable std::shared_ptr m_memoryHandle; mutable p_char8 m_data; @@ -134,8 +136,8 @@ public: * Create oatpp::String from memory label * @return oatpp::String(data, size) */ - oatpp::String toString() const { - return oatpp::String((const char*) m_data, m_size, true); + String toString() const { + return String((const char*) m_data, m_size, true); } /** @@ -164,7 +166,7 @@ public: StringKeyLabel(const std::shared_ptr& memHandle, p_char8 data, v_buff_size size); StringKeyLabel(const char* constText); - StringKeyLabel(const oatpp::String& str); + StringKeyLabel(const String& str); bool operator==(const StringKeyLabel &other) const { return m_size == other.m_size && base::StrBuffer::equals(m_data, other.m_data, m_size); @@ -188,7 +190,7 @@ public: StringKeyLabelCI(const std::shared_ptr& memHandle, p_char8 data, v_buff_size size); StringKeyLabelCI(const char* constText); - StringKeyLabelCI(const oatpp::String& str); + StringKeyLabelCI(const String& str); bool operator==(const StringKeyLabelCI &other) const { return m_size == other.m_size && base::StrBuffer::equalsCI(m_data, other.m_data, m_size); @@ -212,7 +214,7 @@ public: StringKeyLabelCI_FAST(const std::shared_ptr& memHandle, p_char8 data, v_buff_size size); StringKeyLabelCI_FAST(const char* constText); - StringKeyLabelCI_FAST(const oatpp::String& str); + StringKeyLabelCI_FAST(const String& str); bool operator==(const StringKeyLabelCI_FAST &other) const { return m_size == other.m_size && base::StrBuffer::equalsCI_FAST(m_data, other.m_data, m_size); diff --git a/test/oatpp/AllTestsMain.cpp b/test/oatpp/AllTestsMain.cpp index 17ceaa5b..5667d534 100644 --- a/test/oatpp/AllTestsMain.cpp +++ b/test/oatpp/AllTestsMain.cpp @@ -55,6 +55,7 @@ #include "oatpp/core/async/Coroutine.hpp" #include "oatpp/core/Types.hpp" +#include "oatpp/core/data/mapping/type/Enum.hpp" #include "oatpp/core/concurrency/SpinLock.hpp" #include "oatpp/core/base/Environment.hpp" @@ -63,42 +64,25 @@ #include #ifdef OATPP_ENABLE_ALL_TESTS_MAIN + namespace { -// -//#include OATPP_CODEGEN_BEGIN(DTO) -// -//ENUM(MyEnum0, v_int32) -// -//ENUM(MyEnum1, v_int32, -// VALUE(CODE_1, 1001, "Error - code 1"), -// VALUE(CODE_2, 1002) -//) -// -//#include OATPP_CODEGEN_END(DTO) -// -//enum MyE : v_int32 { -// -//}; -// -//enum MyE1 : v_int32 { -// -//}; -// -//template -//struct EnumInfo { -// typedef T Enum; -// static constexpr const char* name = "Unknown"; -//}; -// -//template<> -//struct EnumInfo { -// static constexpr const char* name = "MyE"; -//}; -// -//template<> -//struct EnumInfo : public oatpp::String { -// static constexpr const char* name = "MyE1"; -//}; + +#include OATPP_CODEGEN_BEGIN(DTO) + +ENUM(MyEnum0, v_int32) + +ENUM(MyEnum1, v_int32, + VALUE(CODE_1, 1001, "Error - code 1"), + VALUE(CODE_2, 1002), + VALUE(CODE_3, -1) +) + +ENUM(MyEnum2, v_uint64, + VALUE(CODE_1, 1001, "Error - code 1"), + VALUE(CODE_2, 1002) +) + +#include OATPP_CODEGEN_END(DTO) void runTests() { @@ -107,9 +91,32 @@ void runTests() { OATPP_LOGD("aaa", "coroutine size=%d", sizeof(oatpp::async::AbstractCoroutine)); OATPP_LOGD("aaa", "action size=%d", sizeof(oatpp::async::Action)); - //OATPP_LOGD("AAA", "e-name='%s'", EnumInfo::name); + v_uint16 v = static_cast(MyEnum1::CODE_3); + OATPP_LOGD("AAA", "name='%s'", oatpp::Enum::Class::getType()->nameQualifier); + OATPP_LOGD("AAA", "name='%s'", oatpp::Enum::Class::getType()->nameQualifier); + { + auto entry = oatpp::Enum::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::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::getEntryByIndex(2); + OATPP_LOGD("Entry", "name='%s', value=%d, index=%d", entry.name.toString()->getData(), entry.value, entry.index); + } + + { + auto entry = oatpp::Enum::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); OATPP_RUN_TEST(oatpp::test::memory::MemoryPoolTest); @@ -222,7 +229,7 @@ void runTests() { test_port.run(); } - +*/ } } diff --git a/test/oatpp/core/data/share/LazyStringMapTest.cpp b/test/oatpp/core/data/share/LazyStringMapTest.cpp index 0caac5a0..48faf47e 100644 --- a/test/oatpp/core/data/share/LazyStringMapTest.cpp +++ b/test/oatpp/core/data/share/LazyStringMapTest.cpp @@ -25,6 +25,7 @@ #include "LazyStringMapTest.hpp" #include "oatpp/core/data/share/LazyStringMap.hpp" +#include "oatpp/core/Types.hpp" namespace oatpp { namespace test { namespace core { namespace data { namespace share {