Introduce data::Tree::Node

This commit is contained in:
Leonid Stryzhevskyi 2024-04-24 04:24:37 +03:00
parent 14ca5e55c8
commit 5461fb2f08
8 changed files with 709 additions and 1 deletions

View File

@ -62,6 +62,8 @@ add_library(oatpp
oatpp/concurrency/Utils.hpp
oatpp/data/Bundle.cpp
oatpp/data/Bundle.hpp
oatpp/data/Tree.cpp
oatpp/data/Tree.hpp
oatpp/data/buffer/FIFOBuffer.cpp
oatpp/data/buffer/FIFOBuffer.hpp
oatpp/data/buffer/IOBuffer.cpp

287
src/oatpp/data/Tree.cpp Normal file
View File

@ -0,0 +1,287 @@
/***************************************************************************
*
* 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 "Tree.hpp"
namespace oatpp { namespace data {
Tree::Node::Node()
: m_type(Type::NULL_VALUE)
, m_data(0)
{}
Tree::Node::Node(const Node& other)
: Node()
{
setCopy(other);
}
Tree::Node::Node(Node&& other) noexcept
: m_type(other.m_type)
, m_data(other.m_data)
{
other.m_type = Type::NULL_VALUE;
other.m_data = 0;
}
Tree::Node::~Node() {
deleteValueObject();
}
Tree::Node& Tree::Node::operator = (const Node& other) {
setCopy(other);
return *this;
}
Tree::Node& Tree::Node::operator = (Node&& other) noexcept {
setMove(std::forward<Node>(other));
return *this;
}
void Tree::Node::deleteValueObject() {
switch (m_type) {
case Type::NULL_VALUE:
case Type::INTEGER:
case Type::FLOAT:
case Type::BOOL:
case Type::INT_8:
case Type::UINT_8:
case Type::INT_16:
case Type::UINT_16:
case Type::INT_32:
case Type::UINT_32:
case Type::INT_64:
case Type::UINT_64:
case Type::FLOAT_32:
case Type::FLOAT_64:
break;
case Type::STRING: {
auto data = reinterpret_cast<oatpp::String *>(m_data);
delete data;
break;
}
case Type::VECTOR: {
auto data = reinterpret_cast<std::vector<Node> *>(m_data);
delete data;
break;
}
case Type::MAP: {
auto data = reinterpret_cast<std::vector<std::pair<oatpp::String, Node>> *>(m_data);
delete data;
break;
}
default:
// DO-NOTHING
break;
}
}
Tree::Node::Type Tree::Node::getType() const {
return m_type;
}
void Tree::Node::setCopy(const Node& other) {
deleteValueObject();
m_type = other.m_type;
switch (other.m_type) {
case Type::NULL_VALUE:
break;
case Type::INTEGER:
case Type::FLOAT:
case Type::BOOL:
case Type::INT_8:
case Type::UINT_8:
case Type::INT_16:
case Type::UINT_16:
case Type::INT_32:
case Type::UINT_32:
case Type::INT_64:
case Type::UINT_64:
case Type::FLOAT_32:
case Type::FLOAT_64:
{
m_data = other.m_data;
break;
}
case Type::STRING: {
auto otherData = reinterpret_cast<oatpp::String *>(other.m_data);
if(otherData == nullptr) {
throw std::runtime_error("[oatpp::data::Tree::Node::setCopy()]: other.data is null, other.type is 'STRING'");
}
auto ptr = new oatpp::String(*otherData);
m_data = reinterpret_cast<LARGEST_TYPE>(ptr);
break;
}
case Type::VECTOR: {
auto otherData = reinterpret_cast<std::vector<Node> *>(other.m_data);
if(otherData == nullptr) {
throw std::runtime_error("[oatpp::data::Tree::Node::setCopy()]: other.data is null, other.type is 'VECTOR'");
}
auto ptr = new std::vector<Node>(*otherData);
m_data = reinterpret_cast<LARGEST_TYPE>(ptr);
break;
}
case Type::MAP: {
auto otherData = reinterpret_cast<std::vector<std::pair<oatpp::String, Node>> *>(other.m_data);
if(otherData == nullptr) {
throw std::runtime_error("[oatpp::data::Tree::Node::setCopy()]: other.data is null, other.type is 'MAP'");
}
auto ptr = new std::vector<std::pair<oatpp::String, Node>>(*otherData);
m_data = reinterpret_cast<LARGEST_TYPE>(ptr);
break;
}
default:
m_data = other.m_data;
break;
}
}
void Tree::Node::setMove(Node&& other) {
deleteValueObject();
m_type = other.m_type;
m_data = other.m_data;
other.m_type = Type::NULL_VALUE;
other.m_data = 0;
}
void Tree::Node::setNull() {
deleteValueObject();
m_type = Type::NULL_VALUE;
m_data = 0;
}
void Tree::Node::setInteger(v_int64 value) {
deleteValueObject();
m_type = Type::INTEGER;
std::memcpy (&m_data, &value, sizeof(v_int64));
}
void Tree::Node::setFloat(v_float64 value) {
deleteValueObject();
m_type = Type::FLOAT;
std::memcpy (&m_data, &value, sizeof(v_float64));
}
void Tree::Node::setString(const oatpp::String& value) {
deleteValueObject();
m_type = Type::STRING;
auto data = new oatpp::String(value);
m_data = reinterpret_cast<LARGEST_TYPE>(data);
}
void Tree::Node::setVector(const std::vector<Node>& value) {
deleteValueObject();
m_type = Type::VECTOR;
auto data = new std::vector<Node>(value);
m_data = reinterpret_cast<LARGEST_TYPE>(data);
}
void Tree::Node::setMap(const std::vector<std::pair<oatpp::String, Node>>& value) {
deleteValueObject();
m_type = Type::MAP;
auto data = new std::vector<std::pair<oatpp::String, Node>>(value);
m_data = reinterpret_cast<LARGEST_TYPE>(data);
}
bool Tree::Node::isNull() const {
return m_type == Type::NULL_VALUE;
}
v_int64 Tree::Node::getInteger() const {
if(m_type != Type::INTEGER) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT an arbitrary INTEGER.");
}
v_int64 result;
std::memcpy (&result, &m_data, sizeof(v_float64));
return result;
}
v_float64 Tree::Node::getFloat() const {
if(m_type != Type::FLOAT) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT an arbitrary FLOAT.");
}
v_float64 result;
std::memcpy (&result, &m_data, sizeof(v_float64));
return result;
}
const oatpp::String& Tree::Node::getString() const {
if(m_type != Type::STRING) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT a STRING.");
}
auto data = reinterpret_cast<const oatpp::String*>(m_data);
return *data;
}
const std::vector<Tree::Node>& Tree::Node::getVector() const {
if(m_type != Type::VECTOR) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT a VECTOR.");
}
auto data = reinterpret_cast<const std::vector<Tree::Node>*>(m_data);
return *data;
}
const std::vector<std::pair<oatpp::String, Tree::Node>>& Tree::Node::getMap() const {
if(m_type != Type::MAP) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT a MAP.");
}
auto data = reinterpret_cast<const std::vector<std::pair<oatpp::String, Tree::Node>>*>(m_data);
return *data;
}
std::vector<Tree::Node>& Tree::Node::getVector() {
if(m_type != Type::VECTOR) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT a VECTOR.");
}
auto data = reinterpret_cast<std::vector<Tree::Node>*>(m_data);
return *data;
}
std::vector<std::pair<oatpp::String, Tree::Node>>& Tree::Node::getMap() {
if(m_type != Type::MAP) {
throw std::runtime_error("[oatpp::data::Tree::Node::getInteger()]: NOT a MAP.");
}
auto data = reinterpret_cast<std::vector<std::pair<oatpp::String, Tree::Node>>*>(m_data);
return *data;
}
}}

207
src/oatpp/data/Tree.hpp Normal file
View File

@ -0,0 +1,207 @@
/***************************************************************************
*
* 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_data_Tree_hpp
#define oatpp_data_Tree_hpp
#include "oatpp/Types.hpp"
namespace oatpp { namespace data {
class Tree {
public:
class Node {
public:
enum class Type : v_int32 {
NULL_VALUE = 0,
INTEGER = 1,
FLOAT = 2,
BOOL = 3,
INT_8 = 4,
UINT_8 = 5,
INT_16 = 6,
UINT_16 = 7,
INT_32 = 8,
UINT_32 = 9,
INT_64 = 10,
UINT_64 = 11,
FLOAT_32 = 12,
FLOAT_64 = 13,
STRING = 14,
VECTOR = 15,
MAP = 16
};
template<typename T>
struct NodePrimitiveType {
};
private:
typedef v_uint64 LARGEST_TYPE;
private:
void deleteValueObject();
private:
Type m_type;
LARGEST_TYPE m_data;
public:
Node();
Node(const Node& other);
Node(Node&& other) noexcept;
~Node();
Node& operator = (const Node& other);
Node& operator = (Node&& other) noexcept;
Type getType() const;
void setCopy(const Node& other);
void setMove(Node&& other);
template <typename T>
void setValue(T value) {
deleteValueObject();
m_type = NodePrimitiveType<T>::type;
m_data = 0;
std::memcpy (&m_data, &value, sizeof(T));
}
template<typename T>
T getValue() const {
if(m_type != NodePrimitiveType<T>::type) {
throw std::runtime_error(std::string("[oatpp::data::Tree::Node::getValue()]: NOT a ") + NodePrimitiveType<T>::name);
}
T result;
std::memcpy (&result, &m_data, sizeof(T));
return result;
}
void setNull();
void setInteger(v_int64 value);
void setFloat(v_float64 value);
void setString(const oatpp::String& value);
void setVector(const std::vector<Node>& value);
void setMap(const std::vector<std::pair<oatpp::String, Node>>& value);
bool isNull() const;
v_int64 getInteger() const;
v_float64 getFloat() const;
const oatpp::String& getString() const;
const std::vector<Node>& getVector() const;
const std::vector<std::pair<oatpp::String, Node>>& getMap() const;
std::vector<Node>& getVector();
std::vector<std::pair<oatpp::String, Node>>& getMap();
};
public:
};
template<>
struct Tree::Node::NodePrimitiveType<bool> {
static constexpr Type type = Type::BOOL;
static constexpr const char* name = "BOOL";
};
template<>
struct Tree::Node::NodePrimitiveType<v_int8> {
static constexpr Type type = Type::INT_8;
static constexpr const char* name = "INT_8";
};
template<>
struct Tree::Node::NodePrimitiveType<v_uint8> {
static constexpr Type type = Type::UINT_8;
static constexpr const char* name = "UINT_8";
};
template<>
struct Tree::Node::NodePrimitiveType<v_int16> {
static constexpr Type type = Type::INT_16;
static constexpr const char* name = "INT_16";
};
template<>
struct Tree::Node::NodePrimitiveType<v_uint16> {
static constexpr Type type = Type::UINT_16;
static constexpr const char* name = "UINT_16";
};
template<>
struct Tree::Node::NodePrimitiveType<v_int32> {
static constexpr Type type = Type::INT_32;
static constexpr const char* name = "INT_32";
};
template<>
struct Tree::Node::NodePrimitiveType<v_uint32> {
static constexpr Type type = Type::UINT_32;
static constexpr const char* name = "UINT_32";
};
template<>
struct Tree::Node::NodePrimitiveType<v_int64> {
static constexpr Type type = Type::INT_64;
static constexpr const char* name = "INT_64";
};
template<>
struct Tree::Node::NodePrimitiveType<v_uint64> {
static constexpr Type type = Type::UINT_64;
static constexpr const char* name = "UINT_64";
};
template<>
struct Tree::Node::NodePrimitiveType<v_float32> {
static constexpr Type type = Type::FLOAT_32;
static constexpr const char* name = "FLOAT_32";
};
template<>
struct Tree::Node::NodePrimitiveType<v_float64> {
static constexpr Type type = Type::FLOAT_64;
static constexpr const char* name = "FLOAT_64";
};
}}
#endif //oatpp_data_Tree_hpp

View File

@ -46,6 +46,8 @@ add_executable(oatppAllTests
oatpp/data/share/StringTemplateTest.hpp
oatpp/data/stream/BufferStreamTest.cpp
oatpp/data/stream/BufferStreamTest.hpp
oatpp/data/TreeTest.cpp
oatpp/data/TreeTest.hpp
oatpp/encoding/Base64Test.cpp
oatpp/encoding/Base64Test.hpp
oatpp/encoding/UnicodeTest.cpp

View File

@ -53,6 +53,7 @@
#include "oatpp/data/resource/InMemoryDataTest.hpp"
#include "oatpp/data/stream/BufferStreamTest.hpp"
#include "oatpp/data/TreeTest.hpp"
#include "oatpp/data/share/LazyStringMapTest.hpp"
#include "oatpp/data/share/StringTemplateTest.hpp"
#include "oatpp/data/share/MemoryLabelTest.hpp"
@ -73,8 +74,12 @@ namespace {
void runTests() {
/*
oatpp::Environment::printCompilationConfig();
OATPP_LOGD("Tests", "oatpp::String size=%lu", sizeof(oatpp::String))
OATPP_LOGD("Tests", "std::string size=%lu", sizeof(std::string))
OATPP_LOGD("Tests", "coroutine handle size=%lu", sizeof(oatpp::async::CoroutineHandle))
OATPP_LOGD("Tests", "coroutine size=%lu", sizeof(oatpp::async::AbstractCoroutine))
OATPP_LOGD("Tests", "action size=%lu", sizeof(oatpp::async::Action))
@ -97,7 +102,11 @@ void runTests() {
OATPP_RUN_TEST(oatpp::data::buffer::ProcessorTest);
OATPP_RUN_TEST(oatpp::data::stream::BufferStreamTest);
*/
OATPP_RUN_TEST(oatpp::data::TreeTest);
/*
OATPP_RUN_TEST(oatpp::data::mapping::type::ObjectWrapperTest);
OATPP_RUN_TEST(oatpp::data::mapping::type::TypeTest);
@ -224,6 +233,8 @@ void runTests() {
}
*/
}
}

View File

@ -0,0 +1,159 @@
/***************************************************************************
*
* 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 "TreeTest.hpp"
#include "oatpp/data/Tree.hpp"
#include "oatpp/utils/Conversion.hpp"
#include <limits>
namespace oatpp { namespace data {
namespace {
template<typename T>
void testNodeValue(T value) {
Tree::Node node;
node.setValue<T>(value);
auto v = node.getValue<T>();
OATPP_ASSERT(v == value && "value check")
node.setValue<T>(std::numeric_limits<T>::min());
auto min = node.getValue<T>();
OATPP_ASSERT(min == std::numeric_limits<T>::min() && "min check")
node.setValue<T>(std::numeric_limits<T>::max());
auto max = node.getValue<T>();
OATPP_ASSERT(max == std::numeric_limits<T>::max() && "max check")
}
}
void TreeTest::onRun() {
testNodeValue<bool>(true);
testNodeValue<v_int8>(16);
testNodeValue<v_uint8>(16);
testNodeValue<v_int16>(16);
testNodeValue<v_uint16>(16);
testNodeValue<v_int32>(16);
testNodeValue<v_uint32>(16);
testNodeValue<v_int64>(16);
testNodeValue<v_uint64>(16);
testNodeValue<v_float32>(16);
testNodeValue<v_float64>(16);
{
Tree::Node node;
oatpp::String original = "Hello World!";
node.setString(original);
auto stored = node.getString();
OATPP_ASSERT(stored == original)
OATPP_ASSERT(stored.get() == original.get())
}
{
Tree::Node node1;
Tree::Node node2;
node1.setString("Hello World!");
node2 = node1;
OATPP_ASSERT(node1.getString() == "Hello World!")
OATPP_ASSERT(node1.getType() == Tree::Node::Type::STRING)
OATPP_ASSERT(node2.getString() == "Hello World!")
OATPP_ASSERT(node2.getType() == Tree::Node::Type::STRING)
}
{
Tree::Node node1;
Tree::Node node2;
node1.setString("Hello World!");
node2 = std::move(node1);
OATPP_ASSERT(node1.isNull())
OATPP_ASSERT(node2.getString() == "Hello World!")
OATPP_ASSERT(node2.getType() == Tree::Node::Type::STRING)
}
{
std::vector<Tree::Node> originalVector(10);
for(v_uint32 i = 0; i < 10; i ++) {
originalVector.at(i).setValue(i);
}
Tree::Node node;
node.setVector(originalVector);
auto& vector = node.getVector();
OATPP_ASSERT(vector.size() == originalVector.size())
for(v_uint32 i = 0; i < originalVector.size(); i ++) {
OATPP_ASSERT(originalVector.at(i).getValue<v_uint32>() == vector.at(i).getValue<v_uint32>())
}
originalVector.resize(5);
OATPP_ASSERT(vector.size() == 10)
vector.at(0).setString("Hello");
OATPP_ASSERT(vector.at(0).getString() == "Hello")
OATPP_ASSERT(originalVector.at(0).getValue<v_uint32>() == 0)
}
{
std::vector<std::pair<oatpp::String, Tree::Node>> originalMap(10);
for(v_uint32 i = 0; i < 10; i ++) {
originalMap.at(i).first = "node_" + utils::Conversion::int32ToStr(i);
originalMap.at(i).second.setValue(i);
}
Tree::Node node;
node.setMap(originalMap);
auto& map = node.getMap();
OATPP_ASSERT(map.size() == originalMap.size())
for(v_uint32 i = 0; i < originalMap.size(); i ++) {
OATPP_ASSERT(originalMap.at(i).first = map.at(i).first)
OATPP_ASSERT(originalMap.at(i).second.getValue<v_uint32>() == map.at(i).second.getValue<v_uint32>())
}
originalMap.resize(5);
OATPP_ASSERT(map.size() == 10)
}
}
}}

View File

@ -0,0 +1,40 @@
/***************************************************************************
*
* 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_json_TreeTest_hpp
#define oatpp_json_TreeTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace data {
class TreeTest : public oatpp::test::UnitTest {
public:
TreeTest() : UnitTest("TEST[oatpp::data::TreeTest]") {}
void onRun() override;
};
}}
#endif /* oatpp_json_TreeTest_hpp */

View File

@ -60,4 +60,4 @@ void BooleanTest::onRun() {
}
}
}}
}}