From 0d951e3c56e8f56cb05165259e95cc8cb7b3cff2 Mon Sep 17 00:00:00 2001 From: lganzzzo Date: Sat, 25 Apr 2020 02:54:52 +0300 Subject: [PATCH] Types. Introduce Any. --- src/CMakeLists.txt | 2 + src/oatpp/core/Types.hpp | 7 + src/oatpp/core/data/mapping/type/Any.cpp | 96 ++++++++++ src/oatpp/core/data/mapping/type/Any.hpp | 110 +++++++++++ src/oatpp/core/data/mapping/type/Type.hpp | 4 +- test/CMakeLists.txt | 2 + test/oatpp/AllTestsMain.cpp | 3 + test/oatpp/core/data/mapping/type/AnyTest.cpp | 171 ++++++++++++++++++ test/oatpp/core/data/mapping/type/AnyTest.hpp | 42 +++++ 9 files changed, 435 insertions(+), 2 deletions(-) create mode 100644 src/oatpp/core/data/mapping/type/Any.cpp create mode 100644 src/oatpp/core/data/mapping/type/Any.hpp create mode 100644 test/oatpp/core/data/mapping/type/AnyTest.cpp create mode 100644 test/oatpp/core/data/mapping/type/AnyTest.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b835c280..edc26f76 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,6 +74,8 @@ add_library(oatpp oatpp/core/data/buffer/Processor.hpp oatpp/core/data/mapping/ObjectMapper.cpp 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/List.cpp oatpp/core/data/mapping/type/List.hpp oatpp/core/data/mapping/type/ListMap.cpp diff --git a/src/oatpp/core/Types.hpp b/src/oatpp/core/Types.hpp index 6b1fe88c..97a1f588 100644 --- a/src/oatpp/core/Types.hpp +++ b/src/oatpp/core/Types.hpp @@ -25,10 +25,17 @@ #ifndef oatpp_Types_hpp #define oatpp_Types_hpp +#include "oatpp/core/data/mapping/type/Any.hpp" #include "oatpp/core/data/mapping/type/Object.hpp" namespace oatpp { + /** + * `Any` - container for mapping-enabled types. + * &id:oatpp::data::mapping::type::Any; + */ + typedef oatpp::data::mapping::type::Any Any; + /** * Mapping-Enabled String type. &id:oatpp::data::mapping::type::String;
* For `oatpp::String` methods see &id:oatpp::base::StrBuffer; diff --git a/src/oatpp/core/data/mapping/type/Any.cpp b/src/oatpp/core/data/mapping/type/Any.cpp new file mode 100644 index 00000000..b0556d50 --- /dev/null +++ b/src/oatpp/core/data/mapping/type/Any.cpp @@ -0,0 +1,96 @@ +/*************************************************************************** + * + * 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 "Any.hpp" + +namespace oatpp { namespace data { namespace mapping { namespace type { + +namespace __class { + const ClassId Any::CLASS_ID("Any"); +} + +Any::Any() + : PolymorphicWrapper(__class::Any::getType()) +{} + +Any::Any(std::nullptr_t) : Any() {} + +Any::Any(const AbstractObjectWrapper& polymorph) + : PolymorphicWrapper(std::make_shared(polymorph.getPtr(), polymorph.valueType), __class::Any::getType()) +{} + +Any::Any(const Any& other) + : PolymorphicWrapper(std::make_shared(other.m_ptr->ptr, other.m_ptr->type), __class::Any::getType()) +{} + +Any::Any(Any&& other) + : PolymorphicWrapper(std::move(other.m_ptr), __class::Any::getType()) +{} + +void Any::store(const AbstractObjectWrapper& polymorph) { + m_ptr = std::make_shared(polymorph.getPtr(), polymorph.valueType); +} + +const Type* const Any::getStoredType() { + if(m_ptr) { + return m_ptr->type; + } + return nullptr; +} + +Any& Any::operator=(std::nullptr_t) { + m_ptr.reset(); + return *this; +} + +Any& Any::operator=(const AbstractObjectWrapper& other) { + m_ptr = std::make_shared(other.getPtr(), other.valueType); + return *this; +} + +Any& Any::operator=(const Any& other) { + if(other) { + m_ptr = std::make_shared(other.m_ptr->ptr, other.m_ptr->type); + } else { + m_ptr.reset(); + } + return *this; +} + +Any& Any::operator=(Any&& other) { + m_ptr = std::move(other.m_ptr); + return *this; +} + +bool Any::operator == (const Any& other) { + if(!m_ptr && !other.m_ptr) return true; + if(!m_ptr || !other.m_ptr) return false; + return m_ptr->ptr.get() == other.m_ptr->ptr.get(); +} + +bool Any::operator != (const Any& other) { + return !operator == (other); +} + +}}}} diff --git a/src/oatpp/core/data/mapping/type/Any.hpp b/src/oatpp/core/data/mapping/type/Any.hpp new file mode 100644 index 00000000..926c84e5 --- /dev/null +++ b/src/oatpp/core/data/mapping/type/Any.hpp @@ -0,0 +1,110 @@ +/*************************************************************************** + * + * 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_Any_hpp +#define oatpp_data_mapping_type_Any_hpp + +#include "./Type.hpp" + +#include "oatpp/core/collection/LinkedList.hpp" + +#include "oatpp/core/base/memory/ObjectPool.hpp" +#include "oatpp/core/base/Countable.hpp" + +namespace oatpp { namespace data { namespace mapping { namespace type { + +namespace __class { + + class Any { + public: + static const ClassId CLASS_ID; + + static Type *getType() { + static Type type(CLASS_ID, nullptr); + return &type; + } + + }; + +} + +class AnyHandle : public base::Countable { +public: + + AnyHandle(const std::shared_ptr& objPtr, const Type* const objType) + : ptr(objPtr) + , type(objType) + {} + + std::shared_ptr ptr; + const Type* const type; + +}; + +class Any : public PolymorphicWrapper{ +public: + + Any(); + + Any(std::nullptr_t); + Any(const AbstractObjectWrapper& polymorph); + + Any(const Any& other); + Any(Any&& other); + + void store(const AbstractObjectWrapper& polymorph); + + const Type* const getStoredType(); + + template + WrapperType retrieve() { + + if(m_ptr) { + + if(m_ptr->type != WrapperType::Class::getType()) { + throw std::runtime_error("[oatpp::data::mapping::type::Any::retrieve()]: Error. The value type doesn't match."); + } + + return WrapperType(std::static_pointer_cast(m_ptr->ptr), m_ptr->type); + + } + + return nullptr; + + } + + Any& operator=(std::nullptr_t); + Any& operator=(const AbstractObjectWrapper& other); + + Any& operator=(const Any& other); + Any& operator=(Any&& other); + + bool operator == (const Any& other); + bool operator != (const Any& other); + +}; + +}}}} + +#endif //oatpp_data_mapping_type_Any_hpp diff --git a/src/oatpp/core/data/mapping/type/Type.hpp b/src/oatpp/core/data/mapping/type/Type.hpp index 7ce73cb2..b5f31181 100644 --- a/src/oatpp/core/data/mapping/type/Type.hpp +++ b/src/oatpp/core/data/mapping/type/Type.hpp @@ -152,7 +152,7 @@ public: return *this; } - PolymorphicWrapper& operator=(const PolymorphicWrapper&& other){ + PolymorphicWrapper& operator=(PolymorphicWrapper&& other){ m_ptr = std::move(other.m_ptr); return *this; } @@ -258,7 +258,7 @@ public: return *this; } - ObjectWrapper& operator=(const PolymorphicWrapper&& other){ + ObjectWrapper& operator=(PolymorphicWrapper&& other){ if(this->valueType != other.valueType){ OATPP_LOGE("ObjectWrapper", "Invalid class cast"); throw std::runtime_error("[oatpp::data::mapping::type::ObjectWrapper]: Invalid class cast"); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8e536f45..b2e3391e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,6 +15,8 @@ add_executable(oatppAllTests oatpp/core/base/memory/PerfTest.hpp oatpp/core/data/buffer/ProcessorTest.cpp 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/TypeTest.cpp oatpp/core/data/mapping/type/TypeTest.hpp oatpp/core/data/share/LazyStringMapTest.cpp diff --git a/test/oatpp/AllTestsMain.cpp b/test/oatpp/AllTestsMain.cpp index 45e71d72..90637caf 100644 --- a/test/oatpp/AllTestsMain.cpp +++ b/test/oatpp/AllTestsMain.cpp @@ -39,6 +39,8 @@ #include "oatpp/core/parser/CaretTest.hpp" #include "oatpp/core/data/mapping/type/TypeTest.hpp" +#include "oatpp/core/data/mapping/type/AnyTest.hpp" + #include "oatpp/core/base/collection/LinkedListTest.hpp" #include "oatpp/core/base/memory/MemoryPoolTest.hpp" #include "oatpp/core/base/memory/PerfTest.hpp" @@ -82,6 +84,7 @@ void runTests() { OATPP_RUN_TEST(oatpp::test::core::data::stream::BufferStreamTest); 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::async::LockTest); diff --git a/test/oatpp/core/data/mapping/type/AnyTest.cpp b/test/oatpp/core/data/mapping/type/AnyTest.cpp new file mode 100644 index 00000000..e780098a --- /dev/null +++ b/test/oatpp/core/data/mapping/type/AnyTest.cpp @@ -0,0 +1,171 @@ +/*************************************************************************** + * + * 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 "AnyTest.hpp" + +#include "oatpp/core/data/mapping/type/Any.hpp" + +#include "oatpp/parser/json/mapping/ObjectMapper.hpp" +#include "oatpp/core/macro/codegen.hpp" + +namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type { + +namespace { + +#include OATPP_CODEGEN_BEGIN(DTO) + +class Dto1 : public oatpp::Object { + DTO_INIT(Dto1, Object); +}; + +class Dto2 : public oatpp::Object { + DTO_INIT(Dto2, Object); +}; + +class Test : public oatpp::Object { + + DTO_INIT(Test, Object); + + DTO_FIELD(oatpp::Any, any); + +}; + +#include OATPP_CODEGEN_END(DTO) + +} + +void AnyTest::onRun() { + + { + oatpp::Any any; + OATPP_ASSERT(!any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == nullptr); + } + + { + oatpp::Any any(nullptr); + OATPP_ASSERT(!any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == nullptr); + } + + { + oatpp::Any any(oatpp::String("Hello Any!")); + OATPP_ASSERT(any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == oatpp::data::mapping::type::__class::String::getType()); + auto str = any.retrieve(); + OATPP_ASSERT(str == "Hello Any!"); + } + + { + oatpp::Any any(oatpp::Int32(32)); + + OATPP_ASSERT(any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == oatpp::data::mapping::type::__class::Int32::getType()); + + any.store(oatpp::String("Hello Any!")); + + OATPP_ASSERT(any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == oatpp::data::mapping::type::__class::String::getType()); + + auto str = any.retrieve(); + OATPP_ASSERT(str == "Hello Any!"); + } + + { + oatpp::Any any(Dto1::createShared()); + OATPP_ASSERT(any); + OATPP_ASSERT(any.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any.getStoredType() == Dto1::ObjectWrapper::Class::getType()); + + bool wasError = false; + + try { + auto obj = any.retrieve(); // wrong object + } catch (std::runtime_error& e) { + wasError = true; + } + + OATPP_ASSERT(wasError); + } + + { + oatpp::Any any1(oatpp::String("Hello!")); + oatpp::Any any2; + + any2 = any1; + + OATPP_ASSERT(any1); + OATPP_ASSERT(any2); + + OATPP_ASSERT(any1.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any2.valueType == oatpp::data::mapping::type::__class::Any::getType()); + + OATPP_ASSERT(any1.getStoredType() == oatpp::data::mapping::type::__class::String::getType()); + OATPP_ASSERT(any2.getStoredType() == oatpp::data::mapping::type::__class::String::getType()); + + OATPP_ASSERT(any1 == any2); + OATPP_ASSERT(any1.getPtr().get() != any2.getPtr().get()); + + auto str1 = any1.retrieve(); + auto str2 = any2.retrieve(); + + OATPP_ASSERT(str1 == str2); + OATPP_ASSERT(str1.get() == str2.get() && str1 == "Hello!"); + + } + + { + oatpp::Any any1(oatpp::String("Hello!")); + oatpp::Any any2; + + any2 = std::move(any1); + + OATPP_ASSERT(!any1); + OATPP_ASSERT(any2); + + OATPP_ASSERT(any1.valueType == oatpp::data::mapping::type::__class::Any::getType()); + OATPP_ASSERT(any2.valueType == oatpp::data::mapping::type::__class::Any::getType()); + + OATPP_ASSERT(any1.getStoredType() == nullptr); + OATPP_ASSERT(any2.getStoredType() == oatpp::data::mapping::type::__class::String::getType()); + + OATPP_ASSERT(any1 != any2); + OATPP_ASSERT(any1.getPtr().get() != any2.getPtr().get()); + + auto str1 = any1.retrieve(); + auto str2 = any2.retrieve(); + + OATPP_ASSERT(str1 != str2); + OATPP_ASSERT(str2 == "Hello!"); + + } + +} + +}}}}}} \ No newline at end of file diff --git a/test/oatpp/core/data/mapping/type/AnyTest.hpp b/test/oatpp/core/data/mapping/type/AnyTest.hpp new file mode 100644 index 00000000..56cbb761 --- /dev/null +++ b/test/oatpp/core/data/mapping/type/AnyTest.hpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * + * 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_test_core_data_mapping_type_AnyTest_hpp +#define oatpp_test_core_data_mapping_type_AnyTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { namespace test { namespace core { namespace data { namespace mapping { namespace type { + +class AnyTest : public UnitTest{ +public: + + AnyTest():UnitTest("TEST[core::data::mapping::type::AnyTest]"){} + void onRun() override; + +}; + +}}}}}} + +#endif /* oatpp_test_core_data_mapping_type_AnyTest_hpp */