From ffcff28276d615df8ceb4467ada19cea8a047284 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 11 Mar 2020 19:01:19 -0700 Subject: [PATCH] TypeDef append from vector<> --- src/pvxs/data.h | 67 +++++++++++++++++++++++++++++++++++++++++++++---- src/type.cpp | 59 ++++++++++++++++++++++--------------------- 2 files changed, 93 insertions(+), 33 deletions(-) diff --git a/src/pvxs/data.h b/src/pvxs/data.h index d378885..d3c8fab 100644 --- a/src/pvxs/data.h +++ b/src/pvxs/data.h @@ -188,6 +188,9 @@ private: std::vector children; friend class TypeDef; friend class client::detail::CommonBase; + + PVXS_API + void _validate() const; public: struct Helper; @@ -198,13 +201,29 @@ public: :Member(code, name, {}) {} //! Compound member with type ID - PVXS_API - Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list children); + Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list children) + :code(code) + ,name(name) + ,id(id) + ,children(children.begin(), children.end()) + {_validate();} + template + Member(TypeCode code, const std::string& name, const std::string& id, const Iterable& children) + :code(code) + ,name(name) + ,id(id) + ,children(children.begin(), children.end()) + {_validate();} //! Compound member without type ID inline Member(TypeCode code, const std::string& name, std::initializer_list children) :Member(code, name , std::string(), children) {} + template + inline + Member(TypeCode code, const std::string& name, const Iterable& children) + :Member(code, name , std::string(), children) + {} PVXS_API void addChild(const Member& mem); @@ -250,7 +269,11 @@ CASE(AnyA) #define CASE(TYPE) \ inline Member TYPE(const std::string& name, std::initializer_list children) { return Member(TypeCode::TYPE, name, children); } \ -inline Member TYPE(const std::string& name, const std::string& id, std::initializer_list children) { return Member(TypeCode::TYPE, name, id, children); } +template \ +inline Member TYPE(const std::string& name, const Iterable& children) { return Member(TypeCode::TYPE, name, children); } \ +inline Member TYPE(const std::string& name, const std::string& id, std::initializer_list children) { return Member(TypeCode::TYPE, name, id, children); } \ +template \ +inline Member TYPE(const std::string& name, const std::string& id, const Iterable& children) { return Member(TypeCode::TYPE, name, id, children); } CASE(Struct) CASE(Union) @@ -294,7 +317,16 @@ public: ~TypeDef(); //! new definition with id and children. code must be TypeCode::Struct or TypeCode::Union - TypeDef(TypeCode code, const std::string& id, std::initializer_list children); + template + TypeDef(TypeCode code, const std::string& id, const Iterable& children) + :TypeDef(std::make_shared(code, "", id, children)) + {} + TypeDef(TypeCode code, const std::string& id, std::initializer_list children) + :TypeDef(std::make_shared(code, "", id, children)) + {} +private: + TypeDef(std::shared_ptr&&); +public: //! new definition for a single scalar field. code must __not__ be TypeCode::Struct or TypeCode::Union TypeDef(TypeCode code) :TypeDef(code, std::string(), {}) @@ -304,8 +336,33 @@ public: :TypeDef(code, std::string(), children) {} + Member as(const std::string& name) const; + +private: + std::shared_ptr _append_start(); + static + void _append(Member& edit, const Member& mem); + void _append_finish(std::shared_ptr&& edit); +public: + //! append additional children. Only for TypeCode::Struct or TypeCode::Union - TypeDef& operator+=(std::initializer_list children); + template + TypeDef& operator+=(const Iterable& children) { + auto edit = _append_start(); + for(auto& child : children) { + _append(edit, child); + } + _append_finish(std::move(edit)); + return *this; + } + TypeDef& operator+=(std::initializer_list children) { + auto edit = _append_start(); + for(auto& child : children) { + _append(*edit, child); + } + _append_finish(std::move(edit)); + return *this; + } //! Instanciate this definition Value create() const; diff --git a/src/type.cpp b/src/type.cpp index 6ad4641..6d99839 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -22,8 +22,6 @@ struct Member::Helper { static void copy_tree(const FieldDesc* desc, Member& node); static - void append_tree(Member& node, const Member& adopt); - static void show_Node(std::ostream& strm, const std::string& name, const Member* node, unsigned level=0); }; @@ -161,14 +159,12 @@ void name_validate(const char *name) } } -Member::Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list children) - :code(code), name(name), id(id) +void Member::_validate() const { if(!name.empty()) name_validate(name.c_str()); for(auto& child : children) { Helper::node_validate(this, child.id, child.code); - this->children.push_back(child); } } @@ -233,10 +229,8 @@ void Member::Helper::build_tree(std::vector& desc, const Member& node assert(desc.size()==index+desc[index].size()); } -TypeDef::TypeDef(TypeCode code, const std::string& id, std::initializer_list children) +TypeDef::TypeDef(std::shared_ptr&& temp) { - auto temp(std::make_shared(code, "", id, children)); - auto tempdesc = std::make_shared>(); Member::Helper::build_tree(*tempdesc, *temp); @@ -278,7 +272,33 @@ TypeDef::TypeDef(const Value& val) TypeDef::~TypeDef() {} -void Member::Helper::append_tree(Member& node, const Member& adopt) +Member TypeDef::as(const std::string& name) const +{ + if(!top) + throw std::logic_error("Can't append empty TypeDef"); + + Member ret(*top); + ret.name = name; + return ret; +} + +std::shared_ptr TypeDef::_append_start() +{ + if(!top || (top->code!=TypeCode::Struct && top->code!=TypeCode::Union)) + throw std::logic_error("May only append to Struct or Union"); + + std::shared_ptr edit; + if(top.use_count()==1u) { + edit = std::const_pointer_cast(top); + top.reset(); // so we don't leave partial tree on error. + } else { + edit = std::make_shared(*top); // copy + } + + return edit; +} + +void TypeDef::_append(Member& node, const Member& adopt) { for(auto& child : node.children) { if(child.name==adopt.name) { @@ -293,7 +313,7 @@ void Member::Helper::append_tree(Member& node, const Member& adopt) child.id = adopt.id; for(auto& grandchild : adopt.children) { - append_tree(child, grandchild); + _append(child, grandchild); } return; } @@ -303,23 +323,8 @@ void Member::Helper::append_tree(Member& node, const Member& adopt) node.children.push_back(adopt); } -TypeDef& TypeDef::operator+=(std::initializer_list children) +void TypeDef::_append_finish(std::shared_ptr&& edit) { - if(!top || (top->code!=TypeCode::Struct && top->code!=TypeCode::Union)) - throw std::logic_error("May only append to Struct or Union"); - - std::shared_ptr edit; - if(top.use_count()==1u) { - edit = std::const_pointer_cast(top); - top.reset(); // so we don't leave partial tree on error. - } else { - edit = std::make_shared(*top); // copy - } - - for(auto& child : children) { - Member::Helper::append_tree(*edit, child); - } - auto temp = std::make_shared>(); Member::Helper::build_tree(*temp, *edit); @@ -327,8 +332,6 @@ TypeDef& TypeDef::operator+=(std::initializer_list children) top = std::move(edit); desc = std::move(type); - - return *this; } Value TypeDef::create() const