mirror of
https://gitee.com/zyjblog/oatpp.git
synced 2024-12-21 16:15:13 +08:00
mapping::Tree: introduce TreeChildrenOperator
This commit is contained in:
parent
0ee2e3325d
commit
a29c664581
@ -28,71 +28,6 @@
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TreeMap
|
||||
|
||||
TreeMap::TreeMap(const TreeMap& other) {
|
||||
operator=(other);
|
||||
}
|
||||
|
||||
TreeMap::TreeMap(TreeMap&& other) noexcept {
|
||||
operator=(std::forward<TreeMap>(other));
|
||||
}
|
||||
|
||||
TreeMap& TreeMap::operator = (const TreeMap& other) {
|
||||
m_map = other.m_map;
|
||||
m_order.resize(other.m_order.size());
|
||||
for(v_uint64 i = 0; i < other.m_order.size(); i ++) {
|
||||
auto& po = other.m_order[i];
|
||||
auto& pt = m_order[i];
|
||||
pt.first = po.first;
|
||||
|
||||
pt.second = &m_map.at(po.first.lock());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TreeMap& TreeMap::operator = (TreeMap&& other) noexcept {
|
||||
m_map = std::move(other.m_map);
|
||||
m_order = std::move(other.m_order);
|
||||
for(auto& p : m_order) {
|
||||
p.second = &m_map.at(p.first.lock());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& TreeMap::operator [] (const type::String& key) {
|
||||
auto it = m_map.find(key);
|
||||
if(it == m_map.end()) {
|
||||
auto& result = m_map[key];
|
||||
m_order.emplace_back(key.getPtr(), &result);
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const Tree& TreeMap::operator [] (const type::String& key) const {
|
||||
auto it = m_map.find(key);
|
||||
if(it == m_map.end()) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::TreeMap::operator[]]: const operator[] can't add items.");
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<Tree>> TreeMap::operator [] (v_uint64 index) {
|
||||
auto& item = m_order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<const Tree>> TreeMap::operator [] (v_uint64 index) const {
|
||||
auto& item = m_order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
|
||||
v_uint64 TreeMap::size() const {
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Tree::Attributes
|
||||
|
||||
@ -635,8 +570,8 @@ std::vector<std::pair<type::String, Tree>>& Tree::getPairs() {
|
||||
if(m_type == Type::UNDEFINED) {
|
||||
setPairs({});
|
||||
}
|
||||
if(m_type != Type::MAP) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::getMap()]: NOT a MAP.");
|
||||
if(m_type != Type::PAIRS) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::getMap()]: NOT a PAIRS.");
|
||||
}
|
||||
auto data = reinterpret_cast<std::vector<std::pair<type::String, Tree>>*>(m_data);
|
||||
return *data;
|
||||
@ -777,4 +712,181 @@ type::String Tree::debugPrint(v_uint32 indent0, v_uint32 indentDelta, bool first
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TreeMap
|
||||
|
||||
TreeMap::TreeMap(const TreeMap& other) {
|
||||
operator=(other);
|
||||
}
|
||||
|
||||
TreeMap::TreeMap(TreeMap&& other) noexcept {
|
||||
operator=(std::forward<TreeMap>(other));
|
||||
}
|
||||
|
||||
TreeMap& TreeMap::operator = (const TreeMap& other) {
|
||||
m_map = other.m_map;
|
||||
m_order.resize(other.m_order.size());
|
||||
for(v_uint64 i = 0; i < other.m_order.size(); i ++) {
|
||||
auto& po = other.m_order[i];
|
||||
auto& pt = m_order[i];
|
||||
pt.first = po.first;
|
||||
|
||||
pt.second = &m_map.at(po.first.lock());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TreeMap& TreeMap::operator = (TreeMap&& other) noexcept {
|
||||
m_map = std::move(other.m_map);
|
||||
m_order = std::move(other.m_order);
|
||||
for(auto& p : m_order) {
|
||||
p.second = &m_map.at(p.first.lock());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& TreeMap::operator [] (const type::String& key) {
|
||||
auto it = m_map.find(key);
|
||||
if(it == m_map.end()) {
|
||||
auto& result = m_map[key];
|
||||
m_order.emplace_back(key.getPtr(), &result);
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const Tree& TreeMap::operator [] (const type::String& key) const {
|
||||
auto it = m_map.find(key);
|
||||
if(it == m_map.end()) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::TreeMap::operator[]]: const operator[] can't add items.");
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<Tree>> TreeMap::operator [] (v_uint64 index) {
|
||||
auto& item = m_order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<const Tree>> TreeMap::operator [] (v_uint64 index) const {
|
||||
auto& item = m_order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
|
||||
v_uint64 TreeMap::size() const {
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TreeChildrenOperator
|
||||
|
||||
TreeChildrenOperator::TreeChildrenOperator(Tree& tree)
|
||||
: TreeChildrenOperator(const_cast<const Tree&>(tree))
|
||||
{
|
||||
m_const = false;
|
||||
if(tree.getType() == Tree::Type::VECTOR) {
|
||||
m_vector = std::addressof(tree.getVector());
|
||||
} else if(tree.getType() == Tree::Type::MAP) {
|
||||
m_map = std::addressof(tree.getMap());
|
||||
} else if(tree.getType() == Tree::Type::PAIRS) {
|
||||
m_pairs = std::addressof(tree.getPairs());
|
||||
}
|
||||
}
|
||||
|
||||
TreeChildrenOperator::TreeChildrenOperator(const Tree& tree)
|
||||
: m_vector(nullptr)
|
||||
, m_map(nullptr)
|
||||
, m_pairs(nullptr)
|
||||
, c_vector(nullptr)
|
||||
, c_map(nullptr)
|
||||
, c_pairs(nullptr)
|
||||
{
|
||||
m_const = true;
|
||||
if(tree.getType() == Tree::Type::VECTOR) {
|
||||
m_type = VECTOR;
|
||||
c_vector = std::addressof(tree.getVector());
|
||||
} else if(tree.getType() == Tree::Type::MAP) {
|
||||
m_type = MAP;
|
||||
c_map = std::addressof(tree.getMap());
|
||||
} else if(tree.getType() == Tree::Type::PAIRS) {
|
||||
m_type = PAIRS;
|
||||
c_pairs = std::addressof(tree.getPairs());
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::TreeChildrenOperator()]: Node type is NOT suppoerted");
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<type::String, Tree*> TreeChildrenOperator::getPair(v_uint64 index) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getPair()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
const auto& p = (*m_map)[index];
|
||||
return {p.first, std::addressof(p.second.get())};
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& p = m_pairs->at(index);
|
||||
return {p.first, &p.second};
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getPair()]: Node type doesn't support pairs");
|
||||
}
|
||||
|
||||
std::pair<type::String, const Tree*> TreeChildrenOperator::getPair(v_uint64 index) const {
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
const auto& p = (*c_map)[index];
|
||||
return {p.first, std::addressof(p.second.get())};
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& p = (*c_pairs)[index];
|
||||
return {p.first, &p.second};
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getPair()]: Node type doesn't support pairs");
|
||||
}
|
||||
|
||||
Tree* TreeChildrenOperator::getItem(v_uint64 index) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getItem()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: return std::addressof(m_vector->at(index));
|
||||
case MAP: return std::addressof((*m_map)[index].second.get());
|
||||
case PAIRS: return &m_pairs->at(index).second;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getItem()]: Invalid iterator type");
|
||||
}
|
||||
|
||||
const Tree* TreeChildrenOperator::getItem(v_uint64 index) const {
|
||||
switch (m_type) {
|
||||
case VECTOR: return std::addressof(c_vector->at(index));
|
||||
case MAP: return std::addressof((*c_map)[index].second.get());
|
||||
case PAIRS: return &c_pairs->at(index).second;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getItem()]: Invalid operator type");
|
||||
}
|
||||
|
||||
v_uint64 TreeChildrenOperator::size() const {
|
||||
switch (m_type) {
|
||||
case VECTOR: return c_vector->size();
|
||||
case MAP: return c_map->size();
|
||||
case PAIRS: return c_pairs->size();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::size()]: Invalid operator type");
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -260,6 +260,39 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class TreeChildrenOperator {
|
||||
private:
|
||||
enum IteratorType {
|
||||
VECTOR,
|
||||
MAP,
|
||||
PAIRS
|
||||
};
|
||||
private:
|
||||
std::vector<Tree>* m_vector;
|
||||
TreeMap* m_map;
|
||||
std::vector<std::pair<type::String, Tree>>* m_pairs;
|
||||
private:
|
||||
const std::vector<Tree>* c_vector;
|
||||
const TreeMap* c_map;
|
||||
const std::vector<std::pair<type::String, Tree>>* c_pairs;
|
||||
private:
|
||||
bool m_const;
|
||||
IteratorType m_type;
|
||||
public:
|
||||
|
||||
TreeChildrenOperator(Tree& tree);
|
||||
TreeChildrenOperator(const Tree& tree);
|
||||
|
||||
std::pair<type::String, Tree*> getPair(v_uint64 index);
|
||||
std::pair<type::String, const Tree*> getPair(v_uint64 index) const;
|
||||
|
||||
Tree* getItem(v_uint64 index);
|
||||
const Tree* getItem(v_uint64 index) const;
|
||||
|
||||
v_uint64 size() const;
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Tree::NodePrimitiveType
|
||||
|
||||
|
@ -201,12 +201,8 @@ oatpp::Void TreeToObjectMapper::mapEnum(const TreeToObjectMapper* mapper, State&
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapCollection(const TreeToObjectMapper* mapper, State& state, const Type* type) {
|
||||
|
||||
if(state.tree->getType() != Tree::Type::VECTOR) {
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapCollection()]: Node is NOT a VECTOR.");
|
||||
return nullptr;
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
auto dispatcher = static_cast<const data::type::__class::Collection::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
@ -214,28 +210,25 @@ oatpp::Void TreeToObjectMapper::mapCollection(const TreeToObjectMapper* mapper,
|
||||
|
||||
auto itemType = dispatcher->getItemType();
|
||||
|
||||
const auto& vector = state.tree->getVector();
|
||||
|
||||
v_int64 index = 0;
|
||||
const TreeChildrenOperator childrenOperator(*state.tree);
|
||||
v_uint64 childrenCount = childrenOperator.size();
|
||||
|
||||
State nestedState;
|
||||
nestedState.config = state.config;
|
||||
|
||||
for(const auto& node : vector) {
|
||||
for(v_uint64 index = 0; index < childrenCount; index ++) {
|
||||
|
||||
nestedState.tree = &node;
|
||||
nestedState.tree = childrenOperator.getItem(index);
|
||||
auto item = mapper->map(nestedState, itemType);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(nestedState.errorStack);
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapCollection()]: index=" + utils::Conversion::int64ToStr(index));
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapCollection()]: index=" + utils::Conversion::uint64ToStr(index));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dispatcher->addItem(collection, item);
|
||||
|
||||
index ++;
|
||||
|
||||
}
|
||||
|
||||
return collection;
|
||||
@ -244,12 +237,8 @@ oatpp::Void TreeToObjectMapper::mapCollection(const TreeToObjectMapper* mapper,
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapMap(const TreeToObjectMapper* mapper, State& state, const Type* type) {
|
||||
|
||||
if(state.tree->getType() != Tree::Type::MAP) {
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapMap()]: Node is NOT a MAP.");
|
||||
return nullptr;
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
auto dispatcher = static_cast<const data::type::__class::Map::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
@ -262,27 +251,27 @@ oatpp::Void TreeToObjectMapper::mapMap(const TreeToObjectMapper* mapper, State&
|
||||
}
|
||||
auto valueType = dispatcher->getValueType();
|
||||
|
||||
const auto& treeMap = state.tree->getMap();
|
||||
auto treeMapSize = treeMap.size();
|
||||
const TreeChildrenOperator childrenOperator(*state.tree);
|
||||
v_uint64 childrenCount = childrenOperator.size();
|
||||
|
||||
State nestedState;
|
||||
nestedState.config = state.config;
|
||||
|
||||
for(v_uint64 i = 0; i < treeMapSize; i ++) {
|
||||
for(v_uint64 i = 0; i < childrenCount; i ++) {
|
||||
|
||||
const auto& node = treeMap[i];
|
||||
const auto& pair = childrenOperator.getPair(i);
|
||||
|
||||
nestedState.tree = &node.second.get();
|
||||
nestedState.tree = pair.second;
|
||||
|
||||
auto item = mapper->map(nestedState, valueType);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(nestedState.errorStack);
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapMap()]: key='" + node.first + "'");
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapMap()]: key='" + pair.first + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dispatcher->addItem(map, node.first, item);
|
||||
dispatcher->addItem(map, pair.first, item);
|
||||
|
||||
}
|
||||
|
||||
@ -292,12 +281,8 @@ oatpp::Void TreeToObjectMapper::mapMap(const TreeToObjectMapper* mapper, State&
|
||||
|
||||
oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, State& state, const Type* type) {
|
||||
|
||||
if(state.tree->getType() != Tree::Type::MAP) {
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapObject()]: Node is NOT a MAP.");
|
||||
return nullptr;
|
||||
if(state.tree->isNull()){
|
||||
return oatpp::Void(type);
|
||||
}
|
||||
|
||||
auto dispatcher = static_cast<const oatpp::data::type::__class::AbstractObject::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
@ -306,31 +291,31 @@ oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, Stat
|
||||
|
||||
std::vector<std::pair<oatpp::BaseObject::Property*, const Tree*>> polymorphs;
|
||||
|
||||
const auto& treeMap = state.tree->getMap();
|
||||
auto treeMapSize = treeMap.size();
|
||||
const TreeChildrenOperator childrenOperator(*state.tree);
|
||||
v_uint64 childrenCount = childrenOperator.size();
|
||||
|
||||
for(v_uint64 i = 0; i < treeMapSize; i ++) {
|
||||
for(v_uint64 i = 0; i < childrenCount; i ++) {
|
||||
|
||||
const auto& node = treeMap[i];
|
||||
const auto& pair = childrenOperator.getPair(i);
|
||||
|
||||
auto fieldIterator = fieldsMap.find(node.first);
|
||||
auto fieldIterator = fieldsMap.find(pair.first);
|
||||
if(fieldIterator != fieldsMap.end()){
|
||||
|
||||
auto field = fieldIterator->second;
|
||||
|
||||
if(field->info.typeSelector && field->type == oatpp::Any::Class::getType()) {
|
||||
polymorphs.emplace_back(field, &node.second.get()); // store polymorphs for later processing.
|
||||
polymorphs.emplace_back(field, pair.second); // store polymorphs for later processing.
|
||||
} else {
|
||||
|
||||
State nestedState;
|
||||
nestedState.tree = &node.second.get();
|
||||
nestedState.tree = pair.second;
|
||||
nestedState.config = state.config;
|
||||
|
||||
auto value = mapper->map(nestedState, field->type);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(nestedState.errorStack);
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapObject()]: field='" + node.first + "'");
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapObject()]: field='" + pair.first + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -344,7 +329,7 @@ oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, Stat
|
||||
}
|
||||
|
||||
} else if (!state.config->allowUnknownFields) {
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapObject()]: Error. Unknown field '" + node.first + "'");
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapObject()]: Error. Unknown field '" + pair.first + "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -76,14 +76,17 @@ Tree::Tree(const std::shared_ptr<mapping::Tree>& node, const Type* const type)
|
||||
|
||||
Tree& Tree::operator = (std::nullptr_t) {
|
||||
m_ptr.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& Tree::operator = (const Tree& other) {
|
||||
m_ptr = other.m_ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& Tree::operator = (Tree&& other) {
|
||||
m_ptr = std::move(other.m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& Tree::operator = (const mapping::Tree& other) {
|
||||
@ -92,6 +95,7 @@ Tree& Tree::operator = (const mapping::Tree& other) {
|
||||
} else {
|
||||
m_ptr = std::make_shared<mapping::Tree>(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree& Tree::operator = (mapping::Tree&& other) {
|
||||
@ -100,6 +104,7 @@ Tree& Tree::operator = (mapping::Tree&& other) {
|
||||
} else {
|
||||
m_ptr = std::make_shared<mapping::Tree>(std::forward<mapping::Tree>(other));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Tree::operator == (std::nullptr_t) const {
|
||||
|
@ -59,6 +59,7 @@ class TestDto1 : public oatpp::DTO {
|
||||
|
||||
DTO_FIELD(Vector<oatpp::Object<TestDto1>>, vector);
|
||||
DTO_FIELD(Fields<oatpp::Object<TestDto1>>, map);
|
||||
DTO_FIELD(Fields<String>, pairs);
|
||||
|
||||
};
|
||||
|
||||
@ -100,6 +101,15 @@ void TreeToObjectMapperTest::onRun() {
|
||||
tree["map"]["nested_2"]["i32"] = 2;
|
||||
tree["map"]["nested_3"]["i32"] = 3;
|
||||
|
||||
auto& pairs = tree["pairs"].getPairs();
|
||||
pairs.push_back({"same-key", {}});
|
||||
pairs.push_back({"same-key", {}});
|
||||
pairs.push_back({"same-key", {}});
|
||||
|
||||
pairs[0].second = "value1";
|
||||
pairs[1].second = "value2";
|
||||
pairs[2].second = "value3";
|
||||
|
||||
TreeToObjectMapper::State state;
|
||||
state.config = &config;
|
||||
state.tree = &tree;
|
||||
|
Loading…
Reference in New Issue
Block a user